[sasview] 01/08: New upstream version 4.2.0~git20171031
Stuart Prescott
stuart at debian.org
Tue Oct 31 14:52:39 UTC 2017
This is an automated email from the git hooks/post-receive script.
stuart pushed a commit to branch master
in repository sasview.
commit f9a9fcb49b6b627dd1d544bb5f82480fdc5941a7
Author: Stuart Prescott <stuart at debian.org>
Date: Tue Oct 31 21:30:26 2017 +1100
New upstream version 4.2.0~git20171031
---
.gitattributes | 6 +-
.gitignore | 120 +-
.pydevproject | 2 +-
.travis.yml | 80 +-
README.md | 2 +-
Vagrantfile | 10 +-
Vagrantprovision.sh | 2 +-
build_tools/conda/periodictable/meta.yaml | 8 +-
build_tools/deploy.bat | 2 +-
build_tools/jenkins_linux_build.sh | 8 +-
build_tools/jenkins_osx_build.sh | 4 +-
build_tools/jenkins_rhel6_build.sh | 4 +-
build_tools/jenkins_win64_build.bat | 6 +-
build_tools/jenkins_win_build.bat | 4 +-
build_tools/requirements.txt | 2 +-
build_tools/travis_build.sh | 7 +-
check_packages.py | 128 +-
docs/pandoc-docs/Makefile | 2 +
docs/pandoc-docs/build_pandoc.py | 14 +
docs/pandoc-docs/source/README.txt | 1 +
docs/sasview/Tutorial.pptx | Bin 2557784 -> 2561760 bytes
.../sasview/{Tutorial_Old.pdf => Tutorial_SV2.pdf} | Bin
.../{Tutorial_Old.pptx => Tutorial_SV2.pptx} | Bin
.../Tutorial.pdf => docs/sasview/Tutorial_SV3.pdf | Bin 2282706 -> 2246876 bytes
docs/sasview/{Tutorial.pptx => Tutorial_SV3.pptx} | Bin
docs/sphinx-docs/Makefile | 4 +-
docs/sphinx-docs/build_sphinx.py | 443 +-
docs/sphinx-docs/convertKaTex.js | 87 +
docs/sphinx-docs/convertMathJax.js | 168 +
docs/sphinx-docs/source/_extensions/mathjax.py | 117 +
docs/sphinx-docs/source/_static/rendermath.js | 4 +
docs/sphinx-docs/source/conf.py | 604 +-
docs/sphinx-docs/source/dev/dev.rst | 40 +-
docs/sphinx-docs/source/rst_prolog | 49 -
docs/sphinx-docs/source/user/analysis.rst | 34 +-
docs/sphinx-docs/source/user/marketplace.rst | 42 +-
docs/sphinx-docs/source/user/menu_bar.rst | 170 +-
docs/sphinx-docs/source/user/tools.rst | 58 +-
docs/sphinx-docs/source/user/tutorial.rst | 4 +-
docs/sphinx-docs/source/user/user.rst | 34 +-
docs/sphinx-docs/source/user/working.rst | 21 +-
{sasview => installers}/MANIFEST.IN | 0
{sasview => installers}/README-next-release.txt | 0
{sasview => installers}/README.txt | 0
{sasview => installers}/installer_generator.py | 745 +-
{sasview => installers}/license.txt | 0
installers/macholib_patch.py | 27 +
{sasview => installers}/sasview.spec | 0
installers/sasview_console.py | 2 +
installers/sasview_gui.py | 8 +
{sasview => installers}/setup.cfg | 0
{sasview => installers}/setup_exe.py | 277 +-
installers/setup_mac.py | 200 +
{sasview => installers}/version.txt | 0
mac_setup_homebrew.sh | 7 +
run.py | 98 +-
sasview/__init__.py | 18 -
sasview/sasview.py | 213 -
sasview/setup_mac.py | 158 -
sasview/test/2d_data/Dec07031.ASC | 16403 ---------
sasview/test/2d_data/HiResSAN14.ASC | 36883 -------------------
sasview/test/2d_data/MAR07262.ASC | 16403 ---------
sasview/test/2d_data/SILIC009.ASC | 16403 ---------
sasview/test/sesans_data/sphere2micron.ses | 51 -
setup.py | 316 +-
src/examples/data_generator/test_transfo.py | 100 +-
src/examples/data_generator/testdata_generator.py | 194 +-
src/examples/test_chisq_panel.py | 234 +-
src/examples/test_copy_print.py | 234 +-
src/examples/test_panel.py | 20 +-
src/examples/test_panel2D.py | 18 +-
src/examples/test_text_panel.py | 210 +-
src/sas/__init__.py | 57 +
src/sas/_config.py | 119 +
src/sas/logger_config.py | 84 +
src/sas/logging.ini | 73 +
src/sas/sascalc/calculator/BaseComponent.py | 26 +-
.../calculator/c_extensions/sld2i_module.cpp | 70 +-
src/sas/sascalc/calculator/instrument.py | 24 +-
src/sas/sascalc/calculator/kiessig_calculator.py | 2 +-
.../sascalc/calculator/resolution_calculator.py | 92 +-
src/sas/sascalc/calculator/sas_gen.py | 363 +-
src/sas/sascalc/corfunc/corfunc_calculator.py | 27 +-
src/sas/sascalc/corfunc/transform_thread.py | 68 +-
src/sas/sascalc/data_util/calcthread.py | 42 +-
src/sas/sascalc/data_util/err1d.py | 8 +-
src/sas/sascalc/data_util/formatnum.py | 36 +-
src/sas/sascalc/data_util/nxsunit.py | 39 +-
src/sas/sascalc/data_util/odict.py | 108 +-
src/sas/sascalc/data_util/registry.py | 106 +-
src/sas/sascalc/data_util/uncertainty.py | 53 +-
src/sas/sascalc/dataloader/__init__.py | 6 +-
src/sas/sascalc/dataloader/data_info.py | 2410 +-
.../sascalc/dataloader/file_reader_base_class.py | 347 +
src/sas/sascalc/dataloader/loader.py | 119 +-
src/sas/sascalc/dataloader/loader_exceptions.py | 41 +
src/sas/sascalc/dataloader/manipulations.py | 2312 +-
src/sas/sascalc/dataloader/readers/IgorReader.py | 304 -
src/sas/sascalc/dataloader/readers/__init__.py | 15 +-
src/sas/sascalc/dataloader/readers/abs_reader.py | 477 +-
.../dataloader/readers/anton_paar_saxs_reader.py | 129 +-
src/sas/sascalc/dataloader/readers/ascii_reader.py | 409 +-
src/sas/sascalc/dataloader/readers/associations.py | 165 +-
.../sascalc/dataloader/readers/cansas_constants.py | 1 +
.../sascalc/dataloader/readers/cansas_reader.py | 691 +-
.../dataloader/readers/cansas_reader_HDF5.py | 133 +-
src/sas/sascalc/dataloader/readers/danse_reader.py | 491 +-
src/sas/sascalc/dataloader/readers/defaults.json | 50 -
.../sascalc/dataloader/readers/hfir1d_reader.py | 129 -
src/sas/sascalc/dataloader/readers/nexus_reader.py | 96 -
src/sas/sascalc/dataloader/readers/red2d_reader.py | 693 +-
.../sascalc/dataloader/readers/sesans_reader.py | 290 +-
src/sas/sascalc/dataloader/readers/tiff_reader.py | 214 +-
src/sas/sascalc/dataloader/readers/xml_reader.py | 32 +-
src/sas/sascalc/file_converter/ascii2d_loader.py | 150 +
src/sas/sascalc/file_converter/c_ext/__init__.py | 3 +
src/sas/sascalc/file_converter/c_ext/bsl_loader.c | 72 +-
src/sas/sascalc/file_converter/cansas_writer.py | 12 +-
src/sas/sascalc/file_converter/nxcansas_writer.py | 2 +-
src/sas/sascalc/fit/AbstractFitEngine.py | 179 +-
src/sas/sascalc/fit/BumpsFitting.py | 85 +-
src/sas/sascalc/fit/Loader.py | 173 +-
src/sas/sascalc/fit/MultiplicationModel.py | 24 +-
src/sas/sascalc/fit/expression.py | 51 +-
src/sas/sascalc/fit/models.py | 336 +
.../fitting => sascalc/fit}/pagestate.py | 2828 +-
src/sas/sascalc/fit/pluginmodel.py | 4 +-
src/sas/sascalc/{data_util => fit}/qsmearing.py | 37 +-
src/sas/sascalc/invariant/invariant.py | 1924 +-
src/sas/sascalc/invariant/invariant_mapper.py | 96 +-
src/sas/sascalc/pr/__init__.py | 212 +-
src/sas/sascalc/pr/c_extensions/Cinvertor.c | 2303 +-
src/sas/sascalc/pr/c_extensions/__init__.py | 6 +-
src/sas/sascalc/pr/c_extensions/invertor.c | 629 +-
src/sas/sascalc/pr/c_extensions/invertor.h | 118 +-
src/sas/sascalc/pr/distance_explorer.py | 214 +-
src/sas/sascalc/pr/fit/AbstractFitEngine.py | 179 +-
src/sas/sascalc/pr/fit/BumpsFitting.py | 28 +-
src/sas/sascalc/pr/fit/Loader.py | 173 +-
src/sas/sascalc/pr/fit/expression.py | 51 +-
src/sas/sascalc/pr/invertor.py | 109 +-
src/sas/sascalc/pr/num_term.py | 398 +-
src/sas/sascalc/realspace/VolumeCanvas.py | 1595 +-
src/sas/sascalc/realspace/__init__.py | 159 +-
.../sascalc/simulation/analmodelpy/tests/signon.py | 20 +-
.../simulation/analmodelpy/tests/testanal_model.py | 16 +-
.../simulation/geoshapespy/libgeoshapespy/minmax.h | 44 +-
.../simulation/geoshapespy/tests/testshapes.py | 12 +-
src/sas/sascalc/simulation/iqPy/tests/signon.py | 20 +-
src/sas/sascalc/simulation/iqPy/tests/testiq.py | 2 +-
.../simulation/pointsmodelpy/tests/signon.py | 22 +-
.../simulation/pointsmodelpy/tests/test2dui.py | 241 +-
.../pointsmodelpy/tests/testcomplexmodel.py | 241 +-
.../simulation/pointsmodelpy/tests/testlores.py | 129 +-
.../simulation/pointsmodelpy/tests/testlores2d.py | 233 +-
.../pointsmodelpy/tests/testnegativepr.py | 32 +-
src/sas/sasgui/guiframe/CategoryInstaller.py | 350 +-
src/sas/sasgui/guiframe/CategoryManager.py | 4 +-
src/sas/sasgui/guiframe/__init__.py | 142 +-
src/sas/sasgui/guiframe/aboutbox.py | 901 +-
src/sas/sasgui/guiframe/acknowledgebox.py | 19 +-
src/sas/sasgui/guiframe/config.py | 24 +-
src/sas/sasgui/guiframe/custom_pstats.py | 236 +-
src/sas/sasgui/guiframe/customdir.py | 68 -
src/sas/sasgui/guiframe/dataFitting.py | 1020 +-
src/sas/sasgui/guiframe/data_manager.py | 608 +-
src/sas/sasgui/guiframe/data_panel.py | 3006 +-
src/sas/sasgui/guiframe/data_processor.py | 54 +-
src/sas/sasgui/guiframe/data_state.py | 214 +-
src/sas/sasgui/guiframe/documentation_window.py | 238 +-
src/sas/sasgui/guiframe/dummyapp.py | 254 +-
src/sas/sasgui/guiframe/events.py | 74 +-
src/sas/sasgui/guiframe/gui_manager.py | 200 +-
src/sas/sasgui/guiframe/gui_statusbar.py | 6 +-
src/sas/sasgui/guiframe/gui_style.py | 182 +-
src/sas/sasgui/guiframe/gui_toolbar.py | 558 +-
src/sas/sasgui/guiframe/images/angles.png | Bin 5138 -> 0 bytes
src/sas/sasgui/guiframe/images/angles_flat.png | Bin 3462 -> 0 bytes
src/sas/sasgui/guiframe/images/ansto_logo.png | Bin 6508 -> 0 bytes
src/sas/sasgui/guiframe/images/danse_logo.png | Bin 7299 -> 0 bytes
src/sas/sasgui/guiframe/images/ess_logo.png | Bin 4681 -> 0 bytes
src/sas/sasgui/guiframe/images/ill_logo.png | Bin 3906 -> 0 bytes
src/sas/sasgui/guiframe/images/isis_logo.png | Bin 11382 -> 0 bytes
src/sas/sasgui/guiframe/images/nist_logo.png | Bin 2887 -> 0 bytes
src/sas/sasgui/guiframe/images/nsf_logo.png | Bin 3985 -> 0 bytes
src/sas/sasgui/guiframe/images/ornl_logo.png | Bin 8831 -> 0 bytes
src/sas/sasgui/guiframe/images/sns_logo.png | Bin 8337 -> 0 bytes
src/sas/sasgui/guiframe/images/tudelft_logo.png | Bin 2934 -> 0 bytes
src/sas/sasgui/guiframe/images/umd_logo.png | Bin 4273 -> 0 bytes
src/sas/sasgui/guiframe/images/utlogo.gif | Bin 277 -> 0 bytes
src/sas/sasgui/guiframe/images/utlogo.png | Bin 0 -> 403 bytes
.../local_perspectives/data_loader/__init__.py | 4 +-
.../local_perspectives/data_loader/data_loader.py | 107 +-
.../local_perspectives/data_loader/load_thread.py | 162 +-
.../local_perspectives/plotting/AnnulusSlicer.py | 8 +-
.../guiframe/local_perspectives/plotting/Arc.py | 322 +-
.../local_perspectives/plotting/BaseInteractor.py | 360 +-
.../guiframe/local_perspectives/plotting/Edge.py | 256 +-
.../local_perspectives/plotting/Plotter1D.py | 1781 +-
.../local_perspectives/plotting/Plotter2D.py | 1600 +-
.../local_perspectives/plotting/SectorSlicer.py | 1197 +-
.../local_perspectives/plotting/SimplePlot.py | 654 +-
.../plotting/SlicerParameters.py | 146 -
.../local_perspectives/plotting/__init__.py | 4 +-
.../guiframe/local_perspectives/plotting/binder.py | 4 +-
.../local_perspectives/plotting/boxMask.py | 482 +-
.../local_perspectives/plotting/boxSlicer.py | 1080 +-
.../guiframe/local_perspectives/plotting/boxSum.py | 32 +-
.../local_perspectives/plotting/detector_dialog.py | 564 +-
.../local_perspectives/plotting/masking.py | 1482 +-
.../{slicerpanel.py => parameters_panel_boxsum.py} | 102 +-
.../plotting/parameters_panel_slicer.py | 536 +
.../local_perspectives/plotting/plotting.py | 680 +-
.../local_perspectives/plotting/profile_dialog.py | 632 +-
.../local_perspectives/plotting/sector_mask.py | 432 +-
src/sas/sasgui/guiframe/media/M_angles_pic.bmp | Bin 870118 -> 0 bytes
src/sas/sasgui/guiframe/media/M_angles_pic.png | Bin 0 -> 116924 bytes
.../sasgui/guiframe/media/data_formats_help.rst | 193 +-
src/sas/sasgui/guiframe/media/graph_help.rst | 36 +-
src/sas/sasgui/guiframe/panel_base.py | 898 +-
src/sas/sasgui/guiframe/pdfview.py | 338 +-
src/sas/sasgui/guiframe/plugin_base.py | 8 +-
src/sas/sasgui/guiframe/proxy.py | 35 +-
src/sas/sasgui/guiframe/report_dialog.py | 32 +-
src/sas/sasgui/guiframe/startup_configuration.py | 420 +-
src/sas/sasgui/guiframe/utils.py | 426 +-
src/sas/sasgui/perspectives/calculator/__init__.py | 92 +-
.../perspectives/calculator/aperture_editor.py | 756 +-
.../sasgui/perspectives/calculator/calculator.py | 468 +-
.../perspectives/calculator/calculator_widgets.py | 194 +-
.../perspectives/calculator/collimation_editor.py | 1094 +-
src/sas/sasgui/perspectives/calculator/console.py | 132 +-
.../sasgui/perspectives/calculator/data_editor.py | 1304 +-
.../perspectives/calculator/data_operator.py | 1992 +-
.../perspectives/calculator/density_panel.py | 920 +-
.../perspectives/calculator/detector_editor.py | 1719 +-
.../perspectives/calculator/gen_scatter_panel.py | 4121 +--
.../sasgui/perspectives/calculator/image_viewer.py | 894 +-
.../calculator/kiessig_calculator_panel.py | 496 +-
.../sasgui/perspectives/calculator/load_thread.py | 178 +-
.../sasgui/perspectives/calculator/media/.DS_Store | Bin 0 -> 6148 bytes
.../calculator/media/density_calculator_help.rst | 2 +-
.../calculator/media/density_tutor.gif | Bin 77205 -> 0 bytes
.../calculator/media/density_tutor.png | Bin 0 -> 199869 bytes
.../sasgui/perspectives/calculator/media/dm_eq.gif | Bin 1140 -> 0 bytes
.../sasgui/perspectives/calculator/media/dm_eq.png | Bin 0 -> 2115 bytes
.../perspectives/calculator/media/gen_debye_eq.gif | Bin 2290 -> 0 bytes
.../perspectives/calculator/media/gen_debye_eq.png | Bin 0 -> 4852 bytes
.../perspectives/calculator/media/gen_gui_help.bmp | Bin 1471342 -> 0 bytes
.../perspectives/calculator/media/gen_gui_help.png | Bin 0 -> 245543 bytes
.../sasgui/perspectives/calculator/media/gen_i.gif | Bin 1675 -> 0 bytes
.../sasgui/perspectives/calculator/media/gen_i.png | Bin 0 -> 3439 bytes
.../perspectives/calculator/media/gen_mag_pic.bmp | Bin 870118 -> 0 bytes
.../perspectives/calculator/media/gen_mag_pic.png | Bin 0 -> 113814 bytes
.../calculator/media/gen_sas_help.html | 28 +-
.../calculator/media/image_viewer_help.rst | 6 +-
.../calculator/media/kiessig_calculator_help.rst | 20 +-
.../perspectives/calculator/media/load_image.bmp | Bin 895030 -> 0 bytes
.../perspectives/calculator/media/load_image.png | Bin 0 -> 410760 bytes
.../perspectives/calculator/media/mag_vector.bmp | Bin 1097766 -> 0 bytes
.../perspectives/calculator/media/mag_vector.png | Bin 0 -> 39047 bytes
.../sasgui/perspectives/calculator/media/mqx.gif | Bin 1189 -> 0 bytes
.../sasgui/perspectives/calculator/media/mqx.png | Bin 0 -> 1881 bytes
.../sasgui/perspectives/calculator/media/mqy.gif | Bin 1221 -> 0 bytes
.../sasgui/perspectives/calculator/media/mqy.png | Bin 0 -> 1902 bytes
.../sasgui/perspectives/calculator/media/mxp.gif | Bin 1132 -> 0 bytes
.../sasgui/perspectives/calculator/media/mxp.png | Bin 0 -> 1857 bytes
.../sasgui/perspectives/calculator/media/myp.gif | Bin 1117 -> 0 bytes
.../sasgui/perspectives/calculator/media/myp.png | Bin 0 -> 1752 bytes
.../sasgui/perspectives/calculator/media/mzp.gif | Bin 474 -> 0 bytes
.../sasgui/perspectives/calculator/media/mzp.png | Bin 0 -> 741 bytes
.../perspectives/calculator/media/pic_convert.bmp | Bin 300054 -> 0 bytes
.../perspectives/calculator/media/pic_convert.png | Bin 0 -> 5959 bytes
.../perspectives/calculator/media/pic_plot.bmp | Bin 765462 -> 0 bytes
.../perspectives/calculator/media/pic_plot.png | Bin 0 -> 359560 bytes
src/sas/sasgui/perspectives/calculator/media/q.gif | Bin 13760 -> 0 bytes
src/sas/sasgui/perspectives/calculator/media/q.png | Bin 0 -> 36307 bytes
.../media/resolution_calculator_help.rst | 68 +-
.../calculator/media/resolution_tutor.gif | Bin 67849 -> 0 bytes
.../calculator/media/resolution_tutor.png | Bin 0 -> 117904 bytes
.../calculator/media/sas_calculator_help.rst | 106 +-
.../perspectives/calculator/media/sigma_q.gif | Bin 33328 -> 0 bytes
.../perspectives/calculator/media/sigma_q.png | Bin 0 -> 87297 bytes
.../perspectives/calculator/media/sigma_table.gif | Bin 26563 -> 0 bytes
.../perspectives/calculator/media/sigma_table.png | Bin 0 -> 62442 bytes
.../sasgui/perspectives/calculator/media/sld1.gif | Bin 754 -> 0 bytes
.../sasgui/perspectives/calculator/media/sld1.png | Bin 0 -> 1366 bytes
.../sasgui/perspectives/calculator/media/sld2.gif | Bin 940 -> 0 bytes
.../sasgui/perspectives/calculator/media/sld2.png | Bin 0 -> 1744 bytes
.../calculator/media/sld_calculator_help.rst | 24 +-
.../calculator/media/slit_calculator_help.rst | 11 +-
.../sasgui/perspectives/calculator/media/v_j.gif | Bin 582 -> 0 bytes
.../sasgui/perspectives/calculator/model_editor.py | 2767 +-
.../sasgui/perspectives/calculator/pyconsole.py | 21 +-
.../perspectives/calculator/resolcal_thread.py | 106 +-
.../calculator/resolution_calculator_panel.py | 2718 +-
.../perspectives/calculator/sample_editor.py | 1104 +-
.../sasgui/perspectives/calculator/sld_panel.py | 1098 +-
.../calculator/slit_length_calculator_panel.py | 4 +-
.../perspectives/calculator/source_editor.py | 1080 +-
src/sas/sasgui/perspectives/corfunc/corfunc.py | 12 +-
.../sasgui/perspectives/corfunc/corfunc_panel.py | 34 +-
.../sasgui/perspectives/corfunc/corfunc_state.py | 15 +-
.../perspectives/corfunc/media/corfunc_help.rst | 219 +-
.../sasgui/perspectives/corfunc/media/fdr-pdfs.rst | 20 +-
src/sas/sasgui/perspectives/corfunc/media/fig1.gif | Bin 1680 -> 0 bytes
src/sas/sasgui/perspectives/corfunc/media/fig1.png | Bin 0 -> 4585 bytes
src/sas/sasgui/perspectives/corfunc/media/fig2.gif | Bin 3600 -> 0 bytes
src/sas/sasgui/perspectives/corfunc/media/fig2.png | Bin 0 -> 11033 bytes
.../perspectives/corfunc/media/tutorial1.png | Bin 92564 -> 193137 bytes
.../perspectives/corfunc/media/tutorial2.png | Bin 101777 -> 207333 bytes
.../perspectives/corfunc/media/tutorial3.png | Bin 116773 -> 247082 bytes
.../perspectives/corfunc/media/tutorial4.png | Bin 0 -> 252365 bytes
src/sas/sasgui/perspectives/corfunc/plot_labels.py | 7 +-
.../perspectives/file_converter/converter_panel.py | 69 +-
.../perspectives/file_converter/file_converter.py | 6 +-
.../file_converter/media/file_converter_help.rst | 13 +-
src/sas/sasgui/perspectives/fitting/__init__.py | 93 +-
src/sas/sasgui/perspectives/fitting/basepage.py | 510 +-
.../sasgui/perspectives/fitting/batchfitpage.py | 187 +-
src/sas/sasgui/perspectives/fitting/console.py | 366 +-
src/sas/sasgui/perspectives/fitting/fit_thread.py | 212 +-
src/sas/sasgui/perspectives/fitting/fitpage.py | 180 +-
src/sas/sasgui/perspectives/fitting/fitpanel.py | 39 +-
src/sas/sasgui/perspectives/fitting/fitproblem.py | 1337 +-
src/sas/sasgui/perspectives/fitting/fitting.py | 552 +-
.../sasgui/perspectives/fitting/fitting_widgets.py | 376 +-
src/sas/sasgui/perspectives/fitting/gpu_options.py | 2 +-
.../sasgui/perspectives/fitting/hint_fitpage.py | 110 +-
.../perspectives/fitting/media/M_angles_pic.bmp | Bin 870118 -> 0 bytes
.../fitting/media/batch_button_area.bmp | Bin 408258 -> 0 bytes
.../fitting/media/batch_button_area.png | Bin 0 -> 25256 bytes
.../sasgui/perspectives/fitting/media/cat_fig0.bmp | Bin 805558 -> 0 bytes
.../sasgui/perspectives/fitting/media/cat_fig0.png | Bin 0 -> 53971 bytes
.../sasgui/perspectives/fitting/media/cat_fig1.bmp | Bin 786014 -> 0 bytes
.../sasgui/perspectives/fitting/media/cat_fig1.png | Bin 0 -> 66355 bytes
.../sasgui/perspectives/fitting/media/cat_fig2.bmp | Bin 642374 -> 0 bytes
.../sasgui/perspectives/fitting/media/cat_fig2.png | Bin 0 -> 40656 bytes
.../fitting/media/combine_batch_grid.png | Bin 0 -> 541489 bytes
.../fitting/media/combine_batch_page.png | Bin 0 -> 374798 bytes
.../fitting/media/combine_batch_plot.png | Bin 0 -> 146675 bytes
.../sasgui/perspectives/fitting/media/dm_eq.gif | Bin 1140 -> 0 bytes
.../perspectives/fitting/media/edit_menu.bmp | Bin 486150 -> 0 bytes
.../perspectives/fitting/media/edit_menu.png | Bin 0 -> 30852 bytes
.../perspectives/fitting/media/file_menu.bmp | Bin 121806 -> 0 bytes
.../perspectives/fitting/media/file_menu.png | Bin 0 -> 10710 bytes
.../sasgui/perspectives/fitting/media/fitting.rst | 35 +-
.../perspectives/fitting/media/fitting_help.rst | 204 +-
.../sasgui/perspectives/fitting/media/m0x_eq.gif | Bin 861 -> 0 bytes
.../sasgui/perspectives/fitting/media/m0y_eq.gif | Bin 702 -> 0 bytes
.../sasgui/perspectives/fitting/media/m0z_eq.gif | Bin 887 -> 0 bytes
.../sasgui/perspectives/fitting/media/mag_help.rst | 107 -
.../perspectives/fitting/media/mag_vector.bmp | Bin 1097766 -> 0 bytes
src/sas/sasgui/perspectives/fitting/media/mqx.gif | Bin 1189 -> 0 bytes
src/sas/sasgui/perspectives/fitting/media/mqy.gif | Bin 1221 -> 0 bytes
src/sas/sasgui/perspectives/fitting/media/mxp.gif | Bin 1132 -> 0 bytes
src/sas/sasgui/perspectives/fitting/media/myp.gif | Bin 1117 -> 0 bytes
src/sas/sasgui/perspectives/fitting/media/mzp.gif | Bin 474 -> 0 bytes
.../perspectives/fitting/media/new_model.bmp | Bin 1703334 -> 0 bytes
.../perspectives/fitting/media/new_model.png | Bin 0 -> 73358 bytes
.../sasgui/perspectives/fitting/media/pd_help.rst | 194 -
.../perspectives/fitting/media/pd_image001.png | Bin 2535 -> 0 bytes
.../perspectives/fitting/media/pd_image002.png | Bin 736 -> 0 bytes
.../perspectives/fitting/media/pd_image003.png | Bin 898 -> 0 bytes
.../perspectives/fitting/media/pd_image004.jpg | Bin 16313 -> 0 bytes
.../perspectives/fitting/media/pd_image005.png | Bin 2433 -> 0 bytes
.../perspectives/fitting/media/pd_image006.jpg | Bin 16860 -> 0 bytes
.../perspectives/fitting/media/pd_image007.png | Bin 2436 -> 0 bytes
.../perspectives/fitting/media/pd_image008.png | Bin 585 -> 0 bytes
.../perspectives/fitting/media/pd_image009.png | Bin 777 -> 0 bytes
.../perspectives/fitting/media/pd_image010.jpg | Bin 13357 -> 0 bytes
.../perspectives/fitting/media/pd_image011.png | Bin 3005 -> 0 bytes
.../perspectives/fitting/media/pd_image012.png | Bin 793 -> 0 bytes
.../perspectives/fitting/media/pd_image013.jpg | Bin 12845 -> 0 bytes
.../perspectives/fitting/media/plot_button.bmp | Bin 1203230 -> 0 bytes
.../perspectives/fitting/media/plot_button.png | Bin 0 -> 68751 bytes
.../sasgui/perspectives/fitting/media/plugin.rst | 1012 -
.../perspectives/fitting/media/residuals_help.rst | 65 +-
.../fitting/media/restore_batch_window.bmp | Bin 134454 -> 0 bytes
.../fitting/media/restore_batch_window.png | Bin 0 -> 14019 bytes
src/sas/sasgui/perspectives/fitting/media/sld1.gif | Bin 754 -> 0 bytes
src/sas/sasgui/perspectives/fitting/media/sld2.gif | Bin 940 -> 0 bytes
.../sasgui/perspectives/fitting/media/sm_help.rst | 235 -
.../perspectives/fitting/media/sm_image002.gif | Bin 2278 -> 0 bytes
.../perspectives/fitting/media/sm_image003.gif | Bin 1215 -> 0 bytes
.../perspectives/fitting/media/sm_image004.gif | Bin 374 -> 0 bytes
.../perspectives/fitting/media/sm_image005.gif | Bin 379 -> 0 bytes
.../perspectives/fitting/media/sm_image006.gif | Bin 832 -> 0 bytes
.../perspectives/fitting/media/sm_image007.gif | Bin 854 -> 0 bytes
.../perspectives/fitting/media/sm_image008.gif | Bin 304 -> 0 bytes
.../perspectives/fitting/media/sm_image009.gif | Bin 417 -> 0 bytes
.../perspectives/fitting/media/sm_image010.gif | Bin 241 -> 0 bytes
.../perspectives/fitting/media/sm_image011.gif | Bin 220 -> 0 bytes
.../perspectives/fitting/media/sm_image012.gif | Bin 217 -> 0 bytes
.../perspectives/fitting/media/sm_image013.gif | Bin 2021 -> 0 bytes
.../perspectives/fitting/media/sm_image016.gif | Bin 2068 -> 0 bytes
.../perspectives/fitting/media/sm_image017.gif | Bin 2473 -> 0 bytes
.../perspectives/fitting/media/sm_image018.gif | Bin 285 -> 0 bytes
.../perspectives/fitting/media/sm_image019.gif | Bin 1961 -> 0 bytes
.../perspectives/fitting/media/sm_image020.gif | Bin 4151 -> 0 bytes
.../perspectives/fitting/media/sm_image021.gif | Bin 2355 -> 0 bytes
.../perspectives/fitting/media/sm_image022.gif | Bin 7724 -> 0 bytes
.../perspectives/fitting/media/sm_image023.gif | Bin 5875 -> 0 bytes
.../perspectives/fitting/media/sm_image024.gif | Bin 6240 -> 0 bytes
.../perspectives/fitting/media/sm_image025.gif | Bin 2083 -> 0 bytes
.../perspectives/fitting/media/sm_image026.gif | Bin 2177 -> 0 bytes
.../perspectives/fitting/media/sm_image027.gif | Bin 1304 -> 0 bytes
.../perspectives/fitting/media/sm_image028.gif | Bin 1989 -> 0 bytes
.../perspectives/fitting/media/sum_model.bmp | Bin 444582 -> 0 bytes
.../perspectives/fitting/media/sum_model.png | Bin 0 -> 29841 bytes
.../perspectives/fitting/media/view_button.bmp | Bin 1224174 -> 0 bytes
.../perspectives/fitting/media/view_button.png | Bin 0 -> 69736 bytes
.../perspectives/fitting/media/view_data_model.bmp | Bin 675078 -> 0 bytes
.../perspectives/fitting/media/view_data_model.png | Bin 0 -> 34547 bytes
.../sasgui/perspectives/fitting/model_thread.py | 122 +-
src/sas/sasgui/perspectives/fitting/models.py | 455 -
.../perspectives/fitting/plugin_models/__init__.py | 6 +
.../sasgui/perspectives/fitting/report_dialog.py | 287 +-
src/sas/sasgui/perspectives/fitting/resultpanel.py | 198 +-
src/sas/sasgui/perspectives/fitting/simfitpage.py | 2206 +-
src/sas/sasgui/perspectives/fitting/utils.py | 56 +-
src/sas/sasgui/perspectives/invariant/__init__.py | 86 +-
src/sas/sasgui/perspectives/invariant/invariant.py | 716 +-
.../perspectives/invariant/invariant_details.py | 1084 +-
.../perspectives/invariant/invariant_panel.py | 3932 +-
.../perspectives/invariant/invariant_state.py | 18 +-
.../perspectives/invariant/invariant_widgets.py | 330 +-
.../perspectives/invariant/media/image001.gif | Bin 343 -> 0 bytes
.../perspectives/invariant/media/image002.gif | Bin 429 -> 0 bytes
.../perspectives/invariant/media/image003.gif | Bin 295 -> 0 bytes
.../perspectives/invariant/media/image004.gif | Bin 492 -> 0 bytes
.../perspectives/invariant/media/image005.gif | Bin 46101 -> 0 bytes
.../perspectives/invariant/media/image005.png | Bin 0 -> 89273 bytes
.../invariant/media/invariant_help.rst | 91 +-
.../sasgui/perspectives/invariant/report_dialog.py | 250 +-
src/sas/sasgui/perspectives/pr/__init__.py | 2 +-
src/sas/sasgui/perspectives/pr/explore_dialog.py | 852 +-
src/sas/sasgui/perspectives/pr/inversion_panel.py | 117 +-
src/sas/sasgui/perspectives/pr/inversion_state.py | 1067 +-
src/sas/sasgui/perspectives/pr/media/pr_help.rst | 6 +-
src/sas/sasgui/perspectives/pr/pr.py | 2640 +-
src/sas/sasgui/perspectives/pr/pr_thread.py | 226 +-
src/sas/sasgui/perspectives/pr/pr_widgets.py | 446 +-
.../sasgui/perspectives/simulation/ShapeAdapter.py | 266 +-
.../perspectives/simulation/ShapeParameters.py | 12 +-
.../sasgui/perspectives/simulation/SimCanvas.py | 1320 +-
src/sas/sasgui/perspectives/simulation/__init__.py | 2 +-
.../sasgui/perspectives/simulation/simulation.py | 666 +-
src/sas/sasgui/plottools/BaseInteractor.py | 358 +-
src/sas/sasgui/plottools/LabelDialog.py | 86 +-
src/sas/sasgui/plottools/LineModel.py | 216 +-
src/sas/sasgui/plottools/PlotPanel.py | 4086 +-
src/sas/sasgui/plottools/PropertyDialog.py | 232 +-
src/sas/sasgui/plottools/SizeDialog.py | 76 +-
src/sas/sasgui/plottools/TextDialog.py | 614 +-
src/sas/sasgui/plottools/__init__.py | 1 -
src/sas/sasgui/plottools/arrow3d.py | 134 +-
src/sas/sasgui/plottools/binder.py | 8 +-
src/sas/sasgui/plottools/canvas.py | 8 +-
src/sas/sasgui/plottools/config.py | 2 +-
src/sas/sasgui/plottools/convert_units.py | 158 +-
src/sas/sasgui/plottools/fitDialog.py | 1540 +-
src/sas/sasgui/plottools/fittings.py | 220 +-
src/sas/sasgui/plottools/plottable_interactor.py | 465 +-
src/sas/sasgui/plottools/plottables.py | 87 +-
src/sas/sasgui/plottools/toolbar.py | 346 +-
src/sas/sasgui/plottools/transform.py | 826 +-
src/sas/sasview/__init__.py | 2 +
{sasview => src/sas/sasview}/custom_config.py | 34 +-
{sasview => src/sas/sasview}/images/SVwelcome.png | Bin
.../sas/sasview}/images/SVwelcome_mini.png | Bin
{sasview => src/sas/sasview}/images/angles.png | Bin
.../sas/sasview}/images/angles_flat.png | Bin
{sasview => src/sas/sasview}/images/ansto_logo.png | Bin
{sasview => src/sas/sasview}/images/ball.icns | Bin
{sasview => src/sas/sasview}/images/ball.ico | Bin
{sasview => src/sas/sasview}/images/danse_logo.png | Bin
src/sas/sasview/images/dls_logo.png | Bin 0 -> 7713 bytes
{sasview => src/sas/sasview}/images/ess_logo.png | Bin
{sasview => src/sas/sasview}/images/ill_logo.png | Bin
{sasview => src/sas/sasview}/images/isis_logo.png | Bin
{sasview => src/sas/sasview}/images/nist_logo.png | Bin
{sasview => src/sas/sasview}/images/nsf_logo.png | Bin
{sasview => src/sas/sasview}/images/ornl_logo.png | Bin
{sasview => src/sas/sasview}/images/sns_logo.png | Bin
.../sas/sasview}/images/tudelft_logo.png | Bin
{sasview => src/sas/sasview}/images/umd_logo.png | Bin
{sasview => src/sas/sasview}/images/utlogo.gif | Bin
{sasview => src/sas/sasview}/local_config.py | 23 +-
{sasview => src/sas/sasview}/media/README.txt | 0
{sasview => src/sas/sasview}/media/Tutorial.pdf | Bin
.../media/getting_started_with_sasview.pdf | Bin
src/sas/sasview/sasview.py | 254 +
.../sas/sasview}/test/1d_data/ testdata_line1.txt | 0
.../sas/sasview}/test/1d_data/1000A_sphere_dsm.xml | 0
.../test/1d_data/10wtAOT_Reline_120_reduced.pdh | 0
.../1d_data/33837rear_1D_1.75_16.5_CanSAS1D.xml | 0
.../1d_data/33837rear_1D_1.75_16.5_NXcanSAS.h5 | Bin
.../1d_data/33837rear_1D_1.75_16.5_NXcanSAS_v3.h5 | Bin
.../1d_data/AOT_Microemulsion-Core_Contrast.xml | 0
.../1d_data/AOT_Microemulsion-Drop_Contrast.xml | 0
.../1d_data/AOT_Microemulsion-Shell_Contrast.xml | 0
.../sas/sasview}/test/1d_data/APS_DND-CAT.TXT | 0
.../sas/sasview}/test/1d_data/Anton-Paar.pdh | 0
.../sas/sasview}/test/1d_data/CoreXY_ShellZ.txt | 0
.../sas/sasview}/test/1d_data/ISIS_83404.TXT | 0
.../sas/sasview}/test/1d_data/ISIS_98929.TXT | 0
.../test/1d_data/ISIS_Polymer_Blend_TK49.xml | 0
.../sasview}/test/1d_data/P123_D2O_10_percent.xml | 0
.../sasview}/test/1d_data/P123_D2O_30_percent.xml | 0
.../sasview}/test/1d_data/P123_D2O_40_percent.xml | 0
.../sas/sasview}/test/1d_data/PolySpheres.txt | 0
.../sas/sasview}/test/1d_data/beam profile.DAT | 0
.../sas/sasview}/test/1d_data/circular_test.txt | 0
.../sas/sasview}/test/1d_data/cyl_400_20.txt | 0
.../sas/sasview}/test/1d_data/cyl_400_40.txt | 0
.../sas/sasview}/test/1d_data/cyl_testdata.txt | 0
.../sas/sasview}/test/1d_data/cyl_testdata1.txt | 0
.../sas/sasview}/test/1d_data/cyl_testdata2.txt | 0
.../sasview}/test/1d_data/hSDS_D2O_0p5_percent.xml | 0
.../sasview}/test/1d_data/hSDS_D2O_2p0_percent.xml | 0
.../1d_data/hSDS_D2O_2p0_percent_0p2M_NaCl.xml | 0
.../sas/sasview}/test/1d_data/latex_smeared.xml | 0
.../sas/sasview}/test/1d_data/rpa_igor.txt | 0
.../sas/sasview}/test/1d_data/saxess_example.pdh | 0
.../sas/sasview}/test/1d_data/sphere_60_q0_2.txt | 0
.../sas/sasview}/test/1d_data/sphere_80.txt | 0
.../sas/sasview}/test/1d_data/testdata_line.txt | 0
.../sas/sasview}/test/1d_data/testdata_line3.txt | 0
.../test/2d_data/14250_2D_NoDetInfo_NXcanSAS_v3.h5 | Bin
.../sas/sasview}/test/2d_data/2P_New.sans | 0
.../test/2d_data/33837rear_2D_1.75_16.5_NIST.dat | 0
.../2d_data/33837rear_2D_1.75_16.5_NXcanSAS.h5 | Bin
.../2d_data/33837rear_2D_1.75_16.5_NXcanSAS_v3.h5 | Bin
.../sasview}/test/2d_data/P123_D2O_10_percent.dat | 0
.../sasview}/test/2d_data/P123_D2O_30_percent.dat | 0
.../sasview}/test/2d_data/P123_D2O_40_percent.dat | 0
.../sas/sasview}/test/2d_data/P_New.sans | 0
.../sas/sasview}/test/2d_data/SILIC010.DAT | 0
.../sasview}/test/2d_data/SILIC010_noheader.DAT | 0
.../test/2d_data/SILIC010_noheader_3col.DAT | 0
.../sasview}/test/2d_data/exp18_14_igor_2dqxqy.dat | 0
{sasview => src/sas/sasview}/test/README.txt | 0
.../sas/sasview}/test/convertible_files/APS_X.TXT | 0
.../sas/sasview}/test/convertible_files/APS_Y.TXT | 0
.../sasview}/test/convertible_files/FIT2D_I.TXT | 0
.../sasview}/test/convertible_files/FIT2D_Q.TXT | 0
.../SANS2D_100254_merged_ISIS2D.txt | 2536 ++
.../test/convertible_files/YBCO_12685__ISIS2D.txt | 1184 +
.../sas/sasview}/test/convertible_files/Z83000.I1D | 0
.../sas/sasview}/test/convertible_files/Z83000.QAX | 0
.../sas/sasview}/test/convertible_files/Z83001.I1D | 0
.../sas/sasview}/test/convertible_files/Z83001.QAX | Bin
.../sas/sasview}/test/convertible_files/Z83002.I1D | 0
.../sas/sasview}/test/convertible_files/Z98000.I1D | 0
.../sas/sasview}/test/convertible_files/Z98000.QAX | 0
.../sas/sasview}/test/convertible_files/Z98001.I1D | Bin
.../sas/sasview}/test/convertible_files/Z98001.QAX | Bin
.../sas/sasview}/test/convertible_files/Z98002.I1D | Bin
.../test/coordinate_data/A_Raw_Example-1.omf | 0
.../sas/sasview}/test/coordinate_data/diamond.pdb | 0
.../sas/sasview}/test/coordinate_data/dna.pdb | 0
.../sas/sasview}/test/coordinate_data/sld_file.sld | 0
.../test/image_data/ISIS_98940_greyscale_bmp.bmp | Bin
.../test/image_data/ISIS_98940_greyscale_gif.gif | Bin
.../test/image_data/ISIS_98940_greyscale_jpg.jpg | Bin
.../test/image_data/ISIS_98940_greyscale_png.png | Bin
.../test/image_data/ISIS_98940_greyscale_tif.tif | Bin
.../sas/sasview}/test/media/testdata_help.rst | 0
src/sas/sasview/test/nr_data/NR_Ni_down_state.txt | 270 +
src/sas/sasview/test/nr_data/NR_Ni_up_state.txt | 271 +
.../test/other_files/dist _THETA_weights.txt | 0
.../sas/sasview}/test/other_files/phi_weights.txt | 0
.../sas/sasview}/test/other_files/radius_dist.txt | 0
.../sasview}/test/other_files/theta_weights.txt | 0
.../test/save_states/constrained_fit_project.svs | 0
.../save_states/fit_pr_and_invariant_project.svs | 0
.../sas/sasview}/test/save_states/fitstate.fitv | 0
.../project_multiplicative_constraint.svs | 0
.../sas/sasview}/test/save_states/prstate.prv | 0
.../sas/sasview}/test/save_states/test.inv | 0
.../sas/sasview}/test/save_states/test002.inv | 0
src/sas/sasview/test/sesans_data/sphere2micron.ses | 60 +
src/sas/sasview/test/sesans_data/sphere_isis.ses | 73 +
.../test/upcoming_formats/1000A_sphere_sm.xml | 0
{sasview => src/sas/sasview}/welcome_panel.py | 364 +-
{sasview => src/sas/sasview}/wxcruft.py | 4 +-
test/README.rst | 32 +-
{src/sas => test/calculatorview}/__init__.py | 0
{src/sas => test/calculatorview/test}/__init__.py | 0
test/calculatorview/test/utest_gui_sld.py | 382 +-
{src/sas => test/corfunc}/__init__.py | 0
{src/sas => test/corfunc/test}/__init__.py | 0
test/corfunc/test/gamma1_out.txt | 1816 +
test/corfunc/test/gamma3_out.txt | 1816 +
test/corfunc/test/idf_out.txt | 1816 +
test/corfunc/test/utest_corfunc.py | 58 +-
{src/sas => test/fileconverter}/__init__.py | 0
{src/sas => test/fileconverter/test}/__init__.py | 0
test/fileconverter/test/cansas1d.xml | 26 +-
test/fileconverter/test/export2d.h5 | Bin 1199296 -> 0 bytes
test/fileconverter/test/utest_nxcansas_writer.py | 18 +-
test/logging.ini | 48 +
{src/sas => test/pr_inversion}/__init__.py | 0
{src/sas => test/pr_inversion/test}/__init__.py | 0
test/pr_inversion/test/utest_explorer.py | 68 +-
test/pr_inversion/test/utest_invertor.py | 1210 +-
test/run_one.py | 14 +-
{src/sas => test/sascalculator}/__init__.py | 0
{src/sas => test/sascalculator/test}/__init__.py | 0
.../test/utest_resolution_calculator.py | 76 +-
test/sascalculator/test/utest_sas_gen.py | 108 +-
.../test/utest_sld.py | 296 +-
.../test/utest_slit_length_calculator.py | 68 +-
{src/sas => test/sasdataloader}/__init__.py | 0
.../sas => test/sasdataloader/plugins}/__init__.py | 0
test/sasdataloader/plugins/test_reader.py | 129 +-
test/sasdataloader/test/AR07232_rest.ASC | 16403 ---------
test/sasdataloader/test/MAR07232_rest.ASC | 16403 ---------
test/sasdataloader/test/MAR07232_rest.h5 | Bin 0 -> 545568 bytes
{src/sas => test/sasdataloader/test}/__init__.py | 0
test/sasdataloader/test/error_conditions.py | 62 +-
test/sasdataloader/test/isis_1_0_write_test.xml | 0
test/sasdataloader/test/isis_1_1_write_test.xml | 0
test/sasdataloader/test/sequence_tests.py | 64 +-
.../test/sesans_examples/next_gen.ses | 73 +
.../test/sesans_examples/no_spin_echo_unit.ses | 72 +
.../test/sesans_examples/no_wavelength.ses | 73 +
.../test/sesans_examples/sesans_no_data.ses | 15 +
.../test/sesans_examples/sphere2micron.ses | 60 +
.../test/sesans_examples/sphere_isis.ses | 73 +
.../test/sesans_examples/too_many_headers.ses | 73 +
test/sasdataloader/test/testLoad.py | 171 -
test/sasdataloader/test/testplugings.py | 67 -
test/sasdataloader/test/utest_abs_reader.py | 289 +-
test/sasdataloader/test/utest_ascii.py | 211 +-
test/sasdataloader/test/utest_averaging.py | 236 +-
test/sasdataloader/test/utest_cansas.py | 635 +-
.../sasdataloader/test/utest_extension_registry.py | 78 +
.../test/utest_generic_file_reader_class.py | 52 +
test/sasdataloader/test/utest_red2d_reader.py | 69 +-
test/sasdataloader/test/utest_sesans.py | 97 +
.../sasdataloader/test/valid_cansas_xml.xml | 0
test/sasdataloader/test/write_test.xml | 0
{src/sas => test/sasguiframe}/__init__.py | 0
{src/sas => test/sasguiframe/test}/__init__.py | 0
test/sasguiframe/test/utest_manipulations.py | 754 +-
{src/sas => test/sasinvariant}/__init__.py | 0
{src/sas => test/sasinvariant/test}/__init__.py | 0
test/sasinvariant/test/utest_data_handling.py | 41 +-
test/sasinvariant/test/utest_use_cases.py | 753 +-
{src/sas => test/sasrealspace}/__init__.py | 0
{src/sas => test/sasrealspace/test}/__init__.py | 0
test/sasrealspace/test/early_test.py | 589 +-
test/sasrealspace/test/sim_validation.py | 690 +-
test/sasrealspace/test/utest_oriented.py | 971 +-
test/sasrealspace/test/utest_realspace.py | 747 +-
test/utest_sasview.py | 215 +-
658 files changed, 69579 insertions(+), 178966 deletions(-)
diff --git a/.gitattributes b/.gitattributes
index 015b154..e5c3e2a 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -2,4 +2,8 @@
*.asc linguist-language=Other
Make.mm linguist-language=Makefile
sasview/test/* linguist-language=Other
-* test=auto
+*.py text eol=lf
+*.c text eol=lf
+*.h text eol=lf
+*.cpp text eol=lf
+*.rst text eol=lf
diff --git a/.gitignore b/.gitignore
index 0cc7956..0cccfd0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,61 +1,59 @@
-# It is actually possible to list all the old svn ignore properties:
-#
-# svn pg -R svn:ignore .
-#
-# But there's a whole load of useless stuff in there that is no longer used.
-# Instead I did a clean build including the docs, ran the tests, and then ran
-# sasview for a bit and then did a git status to see what extra stuff was being
-# generated.
-#
-# Feel free to add more stuff to this as and when it becomes an issue.
-
-.project
-.pydevproject
-.vagrant
-.idea
-.settings/
-build
-dist
-sasview.egg-info
-sasview.egg-info
-
-.mplconfig
-doctrees
-html
-build
-
-/setup.cfg
-
-/dist
-**/build
-sasview.egg-info
-sasview-install
-**/test/logs
-*.pyc
-*.so
-default_categories.json
-
-/src/sas/models/*.py
-/src/sas/models/c_extension/c_models/c_models.cpp
-/src/sas/models/c_extension/python_wrapper/generated/
-/src/sas/models/media/.idea/
-
-/docs/sphinx-docs/build
-/docs/sphinx-docs/source-temp
-/docs/sphinx-docs/source/dev/api
-/docs/sphinx-docs/source/user/guiframe
-/docs/sphinx-docs/source/user/models
-/docs/sphinx-docs/source/user/perspectives
-/docs/sphinx-docs/source/user/sasgui
-
-
-# test outputs
-/test/pr_inversion/test/test_output.txt
-/test/sasdataloader/test/plugins.zip
-/test/sasdataloader/test/test_log.txt
-/test/sasdataloader/test/isis_1_0_write_test.xml
-/test/sasdataloader/test/isis_1_1_write_test.xml
-/test/sasdataloader/test/write_test.xml
-
-# autogenerated scripts
-/sasview/installer.iss
+# It is actually possible to list all the old svn ignore properties:
+#
+# svn pg -R svn:ignore .
+#
+# But there's a whole load of useless stuff in there that is no longer used.
+# Instead I did a clean build including the docs, ran the tests, and then ran
+# sasview for a bit and then did a git status to see what extra stuff was being
+# generated.
+#
+# Feel free to add more stuff to this as and when it becomes an issue.
+
+# Editor files
+.DS_Store
+/.settings
+/.vscode
+/.project
+/.pydevproject
+/.idea
+
+# Build and run files
+**/__pycache__
+*.pyc
+*.so
+/.vagrant
+/build
+/dist
+sasview.egg-info
+.mplconfig
+default_categories.json
+/setup.cfg
+
+# doc build
+/docs/sphinx-docs/build
+/docs/sphinx-docs/source-temp
+/docs/sphinx-docs/source/dev/api
+/docs/sphinx-docs/source/user/guiframe
+/docs/sphinx-docs/source/user/models
+/docs/sphinx-docs/source/user/sasview
+/docs/sphinx-docs/source/user/perspectives
+/docs/sphinx-docs/katex*.zip
+/docs/sphinx-docs/node_modules
+/docs/sphinx-docs/node-package.json
+
+# test outputs
+/test/pr_inversion/test/test_output.txt
+/test/sasdataloader/test/plugins.zip
+/test/sasdataloader/test/test_log.txt
+/test/sasdataloader/test/isis_1_0_write_test.xml
+/test/sasdataloader/test/isis_1_1_write_test.xml
+/test/sasdataloader/test/write_test.xml
+/test/fileconverter/test/export2d.h5
+**/test/logs
+tests.log
+
+# Installer files
+/sasview-install
+/installers/installer.iss
+/installers/build
+/installers/dist
diff --git a/.pydevproject b/.pydevproject
index c6fb8f6..0fac5fc 100644
--- a/.pydevproject
+++ b/.pydevproject
@@ -3,6 +3,6 @@
<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.7</pydev_property>
<pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH">
-<path>/sasview4/src</path>
+<path>/sasview/src</path>
</pydev_pathproperty>
</pydev_project>
diff --git a/.travis.yml b/.travis.yml
index 183004d..d808193 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,38 +1,54 @@
-# Test Travis CL
-
language: python
-python:
- - "2.7"
-# whitelist
+matrix:
+ include:
+ - os: linux
+ env:
+ - PY=2.7
+ - NUMPYSPEC=numpy
+ - os: osx
+ language: generic
+ env:
+ - PY=2.7
+ - NUMPYSPEC=numpy
branches:
only:
- - master
-# command to install dependencies
-virtualenv:
- system_site_packages: true
+ - master
+addons:
+ apt:
+ packages:
+ - opencl-headers
+ - fglrx
+ - libblas-dev
+ - libatlas-dev
+ - libatlas-base-dev
+ - liblapack-dev
+ - gfortran
+ - libhdf5-serial-dev
before_install:
- - 'if [ $TRAVIS_PYTHON_VERSION == "2.7" ]; then sudo apt-get update;sudo apt-get install python-matplotlib libhdf5-serial-dev python-h5py fglrx opencl-headers python-pyopencl gfortran libblas-dev liblapack-dev libatlas-dev; fi'
-
+- echo $TRAVIS_OS_NAME
+- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh
+ -O miniconda.sh; sudo apt-get update; sudo apt-get install python-pyopencl; elif
+ [[ "$TRAVIS_OS_NAME" == "osx" ]]; then wget https://repo.continuum.io/miniconda/Miniconda3-latest-MacOSX-x86_64.sh
+ -O miniconda.sh; fi
+- bash miniconda.sh -b -p $HOME/miniconda
+- export PATH="$HOME/miniconda/bin:$PATH"
+- hash -r
+- conda update --yes conda
+- conda info -a
+- conda install --yes python=$PY $NUMPYSPEC scipy cython pylint wxpython
install:
- - pip install -r build_tools/requirements.txt
-
-before_script:
- - "export DISPLAY=:99.0"
- - "sh -e /etc/init.d/xvfb start"
- - sleep 3 # give xvfb some time to start
-
+- pip install -r build_tools/requirements.txt
+- pip install matplotlib
script:
- - export WORKSPACE=/home/travis/build/SasView/
- - cd $WORKSPACE
- - git clone --depth=50 --branch=master https://github.com/SasView/sasmodels.git sasmodels
- - export PYTHONPATH=$WORKSPACE/sasview-install:$WORKSPACE/utils:$PYTHONPATH
- - cd $WORKSPACE
- - ls -ltr
- - if [ ! -d "utils" ]; then mkdir utils; fi
- - /bin/sh -xe sasview/build_tools/travis_build.sh
-# - /bin/sh -xe sasview/build_tools/jenkins_linux_test.sh
- - export LC_ALL=en_US.UTF-8
- - export LANG=en_US.UTF-8
-# - python setup.py docs; echo 0
-# - python setup.py bdist_egg --skip-build
-
+- cd ..
+- export WORKSPACE=$(pwd)
+- git clone --depth=50 --branch=master https://github.com/SasView/sasmodels.git sasmodels
+- git clone --depth=50 --branch=master https://github.com/bumps/bumps.git
+- ls -ltr
+- if [ ! -d "utils" ]; then mkdir utils; fi
+- /bin/sh -xe sasview/build_tools/travis_build.sh
+- export LC_ALL=en_US.UTF-8
+- export LANG=en_US.UTF-8
+notifications:
+ slack:
+ secure: TlsEpZiMLmOOgnmdG0I/oB4tq3bbQYeBBQi6S5qLlkYE9EjUTbbfg7oz0JYUsQ56FAsdFR8zswpBsX7PebZerzrq0ZmvfHSiJhOFIdBfY5Nb7bmLW8/9pUNWV57ON/8Gw2fE5ytc7FgvCGR64yb2QISI/150SIUwvdL5HXTxRWI=
diff --git a/README.md b/README.md
index 0e8aafb..155bbf0 100644
--- a/README.md
+++ b/README.md
@@ -5,4 +5,4 @@ This project was initiated by the NSF funded DANSE project, DMR-0520547, SANS su
[SasView website](http://www.sasview.org)
[![Travis-CI Build Status](https://travis-ci.org/SasView/sasview.svg?branch=master)](https://travis-ci.org/SasView/sasview)
-
+[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.438138.svg)](https://doi.org/10.5281/zenodo.438138)
diff --git a/Vagrantfile b/Vagrantfile
index 4e88c02..108c18a 100644
--- a/Vagrantfile
+++ b/Vagrantfile
@@ -1,10 +1,10 @@
# -*- mode: ruby -*-
# vi: set ft=ruby :
-# This allows you to build sasview using vagrant
+# This allows you to build sasview using vagrant
# for the moment you can build Ubuntu on any platform supported by vagrant
# (Linux, Mac, Windows)
-# You will need VirtualBox as well.
+# You will need VirtualBox as well.
# Download pages:
# http://www.vagrantup.com/downloads
# https://www.virtualbox.org/wiki/Downloads
@@ -20,7 +20,7 @@ Vagrant.configure(2) do |config|
# Every Vagrant development environment requires a box. You can search for
# boxes at https://atlas.hashicorp.com/search.
- config.vm.box = "ubuntu/trusty64"
+ config.vm.box = "ubuntu/xenial64"
#config.vm.box = "fedora19"
#config.vm.box_url = "https://dl.dropboxusercontent.com/u/86066173/fedora-19.box"
#config.vm.box = "fedora20"
@@ -39,5 +39,9 @@ Vagrant.configure(2) do |config|
vb.cpus = "1"
end
#
+ config.vm.synced_folder ".", "/vagrant", disabled: true
+ config.vm.synced_folder ".", "/sasview-docs-test/sasview", disabled: false
+ config.vm.synced_folder "../sasmodels", "/sasview-docs-test/sasmodels", disabled: false
+
config.vm.provision :shell, :path => "Vagrantprovision.sh"
end
diff --git a/Vagrantprovision.sh b/Vagrantprovision.sh
index f9c319c..6e7577a 100644
--- a/Vagrantprovision.sh
+++ b/Vagrantprovision.sh
@@ -6,7 +6,7 @@ apt-get update
apt-get install -y xvfb git python-pip pkg-config libfreetype6-dev libpng-dev python-dev python-wxtools pylint python-matplotlib python-numpy python-sphinx python-xmlrunner python-pisa python-setuptools python-scipy python-pyparsing python-html5lib python-reportlab python-lxml python-pil
pip install bumps comtypes periodictable
-cat >> ~vagrant/.bashrc <<EOF
+cat >> ~/.bashrc <<EOF
export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8
export LC_CTYPE=en_US.UTF-8
diff --git a/build_tools/conda/periodictable/meta.yaml b/build_tools/conda/periodictable/meta.yaml
index 4ef686b..0062b2d 100644
--- a/build_tools/conda/periodictable/meta.yaml
+++ b/build_tools/conda/periodictable/meta.yaml
@@ -1,11 +1,11 @@
package:
name: periodictable
- version: !!str 1.4.1
+ version: !!str 1.5.0
source:
- fn: periodictable-1.4.1.tar.gz
- url: https://pypi.python.org/packages/source/p/periodictable/periodictable-1.4.1.tar.gz
- md5: 7246b63cc0b6b1be6e86b6616f9e866e
+ fn: periodictable-1.5.0.tar.gz
+ url: https://pypi.python.org/packages/source/p/periodictable/periodictable-1.5.0.tar.gz
+ md5: f7e0d8199b0fe829868d24a0a734398e
# patches:
# List any patch files here
# - fix.patch
diff --git a/build_tools/deploy.bat b/build_tools/deploy.bat
index bcb34bd..b204efe 100755
--- a/build_tools/deploy.bat
+++ b/build_tools/deploy.bat
@@ -2,7 +2,7 @@
cd "c:\program files\putty"
rem Copy new installer to the temp directory on the test server
-pscp -scp -v -i sasview.ppk C:\jenkins\workspace\SasView_Win7\sasview\sasview\Output\setupSasView.exe sasview at 192.168.1.18:AppData\Local\Temp\
+pscp -scp -v -i sasview.ppk C:\jenkins\workspace\SasView_Win7\sasview\installers\Output\setupSasView.exe sasview at 192.168.1.18:AppData\Local\Temp\
rem Execute the test on the remote server
plink -i sasview.ppk -ssh sasview at 192.168.1.18 c:\\jenkins\\test_deployment.bat
diff --git a/build_tools/jenkins_linux_build.sh b/build_tools/jenkins_linux_build.sh
index 65506e3..34ea2b9 100755
--- a/build_tools/jenkins_linux_build.sh
+++ b/build_tools/jenkins_linux_build.sh
@@ -13,7 +13,7 @@ cd $WORKSPACE
# SET SASVIEW GITHASH
cd $WORKSPACE
-cd sasview/sasview
+cd sasview/src/sas/sasview
githash=$( git rev-parse HEAD )
sed -i.bak s/GIT_COMMIT/$githash/g __init__.py
@@ -62,6 +62,10 @@ cd sasview
$PYTHON setup.py clean
$PYTHON setup.py build docs bdist_egg
+# CREATE PDF FROM LATEX
+#cd $WORKSPACE
+#cd sasview/docs/sphinx-docs/build/latex
+#pdflatex SasView.tex
# INSTALL SASVIEW
cd $WORKSPACE
@@ -80,5 +84,3 @@ $PYTHON utest_sasview.py
#cd $WORKSPACE
#cd sasview
#$PYLINT --rcfile "build_tools/pylint.rc" -f parseable sasview-install/sasview*.egg/sas sasview | tee test/sasview.txt
-
-
diff --git a/build_tools/jenkins_osx_build.sh b/build_tools/jenkins_osx_build.sh
index 43e2f82..c0c34f7 100755
--- a/build_tools/jenkins_osx_build.sh
+++ b/build_tools/jenkins_osx_build.sh
@@ -16,7 +16,7 @@ cd $WORKSPACE
# SET SASVIEW GITHASH
cd $WORKSPACE
-cd sasview/sasview
+cd sasview/src/sas/sasview
githash=$( git rev-parse HEAD )
sed -i.bak s/GIT_COMMIT/$githash/g __init__.py
@@ -87,6 +87,6 @@ $PYLINT --rcfile "build_tools/pylint.rc" -f parseable sasview-install/sasview*.e
# BUILD APP
cd $WORKSPACE
-cd sasview/sasview
+cd sasview/installers
$PYTHON setup_mac.py py2app
diff --git a/build_tools/jenkins_rhel6_build.sh b/build_tools/jenkins_rhel6_build.sh
index 4232074..1c88918 100755
--- a/build_tools/jenkins_rhel6_build.sh
+++ b/build_tools/jenkins_rhel6_build.sh
@@ -28,7 +28,7 @@ export PYTHONPATH=$PYTHONPATH:$WORKSPACE/utils
"$EASY_INSTALL" -d "$WORKSPACE/utils" lxml
"$EASY_INSTALL" -d "$WORKSPACE/utils" pyparsing==1.5.5
"$EASY_INSTALL" -d "$WORKSPACE/utils" bumps==0.7.5.9
-"$EASY_INSTALL" -d "$WORKSPACE/utils" periodictable==1.3.0
+"$EASY_INSTALL" -d "$WORKSPACE/utils" periodictable==1.5.0
python deps.py
# Set up working directories
@@ -43,7 +43,7 @@ rm -rf build
# Build SasView ###########################################################
export PYTHONPATH=$PYTHONPATH:$WORKSPACE/$SASVIEW_INSTALL:$WORKSPACE/utils
-python setup.py bdist_egg
+python setup.py bdist_egg
# Run tests ###############################################################
diff --git a/build_tools/jenkins_win64_build.bat b/build_tools/jenkins_win64_build.bat
index fb85470..a411ad7 100644
--- a/build_tools/jenkins_win64_build.bat
+++ b/build_tools/jenkins_win64_build.bat
@@ -1,6 +1,6 @@
set PYTHON=python.exe
set EASY_INSTALL=easy_install.exe
-set PYLINT= pylint.exe
+set PYLINT=pylint.exe
set INNO="C:\util\inno\ISCC.exe"
set GIT_SED=C:\"Program Files"\Git\bin\sed.exe
set SAS_COMPILER=tinycc
@@ -14,7 +14,7 @@ echo %WORKSPACE%
:: SET SASVIEW GITHASH ################################################
cd %WORKSPACE%
-cd sasview\sasview
+cd sasview\src\sas\sasview
git rev-parse HEAD > tmpFile_githash
SET /p githash= < tmpFile_githash
DEL tmpFile_githash
@@ -80,7 +80,7 @@ echo F | xcopy sasview-*.egg sasview.egg /Y
:: SASVIEW INSTALLER ##################################################
cd %WORKSPACE%
cd sasview
-cd sasview
+cd installers
%PYTHON% setup_exe.py py2exe
%PYTHON% installer_generator.py
%INNO% installer.iss
diff --git a/build_tools/jenkins_win_build.bat b/build_tools/jenkins_win_build.bat
index 8d12640..bdf3f95 100644
--- a/build_tools/jenkins_win_build.bat
+++ b/build_tools/jenkins_win_build.bat
@@ -16,7 +16,7 @@ echo %WORKSPACE%
:: SET SASVIEW GITHASH ################################################
cd %WORKSPACE%
-cd sasview\sasview
+cd sasview\src\sas\sasview
git rev-parse HEAD > tmpFile_githash
SET /p githash= < tmpFile_githash
DEL tmpFile_githash
@@ -88,7 +88,7 @@ xcopy /S build\lib\* %WORKSPACE%\sasview\utils\
:: SASVIEW INSTALLER ##################################################
cd %WORKSPACE%
cd sasview
-cd sasview
+cd installers
%PYTHON% setup_exe.py py2exe
%PYTHON% installer_generator.py
%INNO% installer.iss
diff --git a/build_tools/requirements.txt b/build_tools/requirements.txt
index f75744a..b659be1 100644
--- a/build_tools/requirements.txt
+++ b/build_tools/requirements.txt
@@ -7,7 +7,7 @@ html5lib==0.95
reportlab==2.5
lxml==2.3
#PIL==1.1.7
-periodictable==1.3.0
+periodictable==1.5.0
bumps==0.7.5.9
numpy>=1.7.1
scipy>=0.18.0
diff --git a/build_tools/travis_build.sh b/build_tools/travis_build.sh
index a5d0538..f7270c3 100644
--- a/build_tools/travis_build.sh
+++ b/build_tools/travis_build.sh
@@ -1,4 +1,4 @@
-# Simplified build for Travic CI
+# Simplified build for Travis CI
# No documentation is built
export PATH=$PATH:/usr/local/bin/
@@ -9,7 +9,7 @@ export PYTHONPATH=$PYTHONPATH:$WORKSPACE/sasview/utils
export PYTHONPATH=$PYTHONPATH:$WORKSPACE/sasview/sasview-install
# SET SASVIEW GITHASH
-cd $WORKSPACE/sasview/sasview
+cd $WORKSPACE/sasview/src/sas/sasview
githash=$( git rev-parse HEAD )
sed -i.bak s/GIT_COMMIT/$githash/g __init__.py
@@ -37,7 +37,8 @@ $EASY_INSTALL -d $WORKSPACE/sasview/utils sasmodels*.egg
# BUILD SASVIEW
cd $WORKSPACE/sasview
$PYTHON setup.py clean
-$PYTHON setup.py build docs bdist_egg
+# $PYTHON setup.py build docs bdist_egg
+$PYTHON setup.py bdist_egg
# INSTALL SASVIEW
cd $WORKSPACE/sasview/dist
diff --git a/check_packages.py b/check_packages.py
index a80a658..fff8bb9 100644
--- a/check_packages.py
+++ b/check_packages.py
@@ -1,7 +1,8 @@
"""
Checking and reinstalling the external packages
"""
-import os
+from __future__ import print_function
+
import sys
# Fix for error: hash-collision-3-both-1-and-1/
@@ -13,92 +14,89 @@ except ImportError:
else:
sys.modules['Image'] = PIL.Image
+if sys.version_info[0] > 2:
+ print("To use the sasview GUI you must use Python 2\n")
common_required_package_list = {
- 'setuptools':{'version':'0.6c11','import_name':'setuptools','test':'__version__'},
- 'pyparsing':{'version':'1.5.5','import_name':'pyparsing','test':'__version__'},
- 'html5lib':{'version':'0.95','import_name':'html5lib','test':'__version__'},
- 'reportlab':{'version':'2.5','import_name':'reportlab','test':'Version'},
- 'h5py':{'version':'2.5','import_name':'h5py','test':'__version__'},
- 'lxml':{'version':'2.3','import_name':'lxml.etree','test':'LXML_VERSION'},
- 'PIL':{'version':'1.1.7','import_name':'Image','test':'VERSION'},
- 'pylint':{'version':None,'import_name':'pylint','test':None},
- 'periodictable':{'version':'1.3.0','import_name':'periodictable','test':'__version__'},
- 'bumps':{'version':'0.7.5.9','import_name':'bumps','test':'__version__'},
- 'numpy':{'version':'1.7.1','import_name':'numpy','test':'__version__'},
- 'scipy':{'version':'0.18.0','import_name':'scipy','test':'__version__'},
- 'wx':{'version':'2.8.12.1','import_name':'wx','test':'__version__'},
- 'matplotlib':{'version':'1.1.0','import_name':'matplotlib','test':'__version__'},
- 'xhtml2pdf':{'version':'3.0.33','import_name':'xhtml2pdf','test':'__version__'},
- 'sphinx':{'version':'1.2.1','import_name':'sphinx','test':'__version__'},
- 'unittest-xml-reporting':{'version':'1.10.0','import_name':'xmlrunner','test':'__version__'},
- 'pyopencl':{'version':'2015.1','import_name':'pyopencl','test':'VERSION_TEXT'},
+ 'setuptools': {'version': '0.6c11', 'import_name': 'setuptools', 'test': '__version__'},
+ 'pyparsing': {'version': '1.5.5', 'import_name': 'pyparsing', 'test': '__version__'},
+ 'html5lib': {'version': '0.95', 'import_name': 'html5lib', 'test': '__version__'},
+ 'reportlab': {'version': '2.5', 'import_name': 'reportlab', 'test': 'Version'},
+ 'h5py': {'version': '2.5', 'import_name': 'h5py', 'test': '__version__'},
+ 'lxml': {'version': '2.3', 'import_name': 'lxml.etree', 'test': 'LXML_VERSION'},
+ 'PIL': {'version': '1.1.7', 'import_name': 'Image', 'test': 'VERSION'},
+ 'pylint': {'version': None, 'import_name': 'pylint', 'test': None},
+ 'periodictable': {'version': '1.5.0', 'import_name': 'periodictable', 'test': '__version__'},
+ 'bumps': {'version': '0.7.5.9', 'import_name': 'bumps', 'test': '__version__'},
+ 'numpy': {'version': '1.7.1', 'import_name': 'numpy', 'test': '__version__'},
+ 'scipy': {'version': '0.18.0', 'import_name': 'scipy', 'test': '__version__'},
+ 'wx': {'version': '2.8.12.1', 'import_name': 'wx', 'test': '__version__'},
+ 'matplotlib': {'version': '1.1.0', 'import_name': 'matplotlib', 'test': '__version__'},
+ 'xhtml2pdf': {'version': '3.0.33', 'import_name': 'xhtml2pdf', 'test': '__version__'},
+ 'sphinx': {'version': '1.2.1', 'import_name': 'sphinx', 'test': '__version__'},
+ 'unittest-xml-reporting': {'version': '1.10.0', 'import_name': 'xmlrunner', 'test': '__version__'},
+ 'pyopencl': {'version': '2015.1', 'import_name': 'pyopencl', 'test': 'VERSION_TEXT'},
}
win_required_package_list = {
- 'comtypes':{'version':'0.6.2','import_name':'comtypes','test':'__version__'},
- 'pywin':{'version':'217','import_name':'pywin','test':'__version__'},
- 'py2exe':{'version':'0.6.9','import_name':'py2exe','test':'__version__'},
+ 'comtypes': {'version': '0.6.2', 'import_name': 'comtypes', 'test': '__version__'},
+ 'pywin': {'version': '217', 'import_name': 'pywin', 'test': '__version__'},
+ 'py2exe': {'version': '0.6.9', 'import_name': 'py2exe', 'test': '__version__'},
}
mac_required_package_list = {
- 'py2app':{'version':None,'import_name':'py2app','test':'__version__'},
+ 'py2app': {'version': None, 'import_name': 'py2app', 'test': '__version__'},
}
deprecated_package_list = {
- 'pyPdf':{'version':'1.13','import_name':'pyPdf','test':'__version__'},
+ 'pyPdf': {'version': '1.13', 'import_name': 'pyPdf', 'test': '__version__'},
}
-print "Checking Required Package Versions...."
-print
-print "Common Packages"
-for package_name,test_vals in common_required_package_list.iteritems():
+print("Checking Required Package Versions....\n")
+print("Common Packages")
+
+for package_name, test_vals in common_required_package_list.items():
try:
- i = __import__(test_vals['import_name'],fromlist=[''])
- if test_vals['test'] == None:
- print "%s Installed (Unknown version)" % package_name
+ i = __import__(test_vals['import_name'], fromlist=[''])
+ if test_vals['test'] is None:
+ print("%s Installed (Unknown version)" % package_name)
elif package_name == 'lxml':
- verstring = str(getattr(i,'LXML_VERSION'))
- print "%s Version Installed: %s"% (package_name,verstring.replace(', ','.').lstrip('(').rstrip(')'))
+ verstring = str(getattr(i, 'LXML_VERSION'))
+ print("%s Version Installed: %s"% (package_name, verstring.replace(', ', '.').lstrip('(').rstrip(')')))
else:
- print "%s Version Installed: %s"% (package_name,getattr(i,test_vals['test']))
- except:
- print '%s NOT INSTALLED'% package_name
+ print("%s Version Installed: %s"% (package_name, getattr(i, test_vals['test'])))
+ except ImportError:
+ print('%s NOT INSTALLED'% package_name)
if sys.platform == 'win32':
- print
- print "Windows Specific Packages:"
- for package_name,test_vals in win_required_package_list.iteritems():
+ print("")
+ print("Windows Specific Packages:")
+ for package_name, test_vals in win_required_package_list.items():
try:
- if package_name == "pywin":
- import win32api
- fixed_file_info = win32api.GetFileVersionInfo(win32api.__file__,'\\')
- print "%s Version Installed: %s"% (package_name,fixed_file_info['FileVersionLS'] >> 16)
- else:
- i = __import__(test_vals['import_name'],fromlist=[''])
- print "%s Version Installed: %s"% (package_name,getattr(i,test_vals['test']))
- except:
- print '%s NOT INSTALLED'% package_name
+ i = __import__(test_vals['import_name'], fromlist=[''])
+ print("%s Version Installed: %s"% (package_name, getattr(i, test_vals['test'], "unknown")))
+ except ImportError:
+ print('%s NOT INSTALLED'% package_name)
if sys.platform == 'darwin':
- print
- print "MacOS Specific Packages:"
- for package_name,test_vals in mac_required_package_list.iteritems():
+ print("")
+ print("MacOS Specific Packages:")
+ for package_name, test_vals in mac_required_package_list.items():
try:
- i = __import__(test_vals['import_name'],fromlist=[''])
- print "%s Version Installed: %s"% (package_name,getattr(i,test_vals['test']))
- except:
- print '%s NOT INSTALLED'% package_name
+ i = __import__(test_vals['import_name'], fromlist=[''])
+ print("%s Version Installed: %s"% (package_name, getattr(i, test_vals['test'])))
+ except ImportError:
+ print('%s NOT INSTALLED'% package_name)
-print
-print "Deprecated Packages"
-print "You can remove these unless you need them for other reasons!"
-for package_name,test_vals in deprecated_package_list.iteritems():
+print("")
+print("Deprecated Packages")
+print("You can remove these unless you need them for other reasons!")
+for package_name, test_vals in deprecated_package_list.items():
try:
- i = __import__(test_vals['import_name'],fromlist=[''])
+ i = __import__(test_vals['import_name'], fromlist=[''])
if package_name == 'pyPdf':
- #pyPdf doesn't have the version number internally
- print 'pyPDF Installed (Version unknown)'
+ # pyPdf doesn't have the version number internally
+ print('pyPDF Installed (Version unknown)')
else:
- print "%s Version Installed: %s"% (package_name,getattr(i,test_vals['test']))
- except:
- print '%s NOT INSTALLED'% package_name
+ print("%s Version Installed: %s"% (package_name, getattr(i, test_vals['test'])))
+ except ImportError:
+ print('%s NOT INSTALLED'% package_name)
diff --git a/docs/pandoc-docs/Makefile b/docs/pandoc-docs/Makefile
new file mode 100644
index 0000000..db025e8
--- /dev/null
+++ b/docs/pandoc-docs/Makefile
@@ -0,0 +1,2 @@
+# Makefile for PanDoc documentation
+#
diff --git a/docs/pandoc-docs/build_pandoc.py b/docs/pandoc-docs/build_pandoc.py
new file mode 100644
index 0000000..2f7a6e9
--- /dev/null
+++ b/docs/pandoc-docs/build_pandoc.py
@@ -0,0 +1,14 @@
+#!/usr/bin/env python
+"""
+Functions for building tutorial docs from
+Libre Office .fodt files using PanDoc
+
+Required formats are:
+html
+pdf
+(eBook)
+
+pdf will need to be generated by Sphinx
+via LaTeX intermediate
+
+"""
\ No newline at end of file
diff --git a/docs/pandoc-docs/source/README.txt b/docs/pandoc-docs/source/README.txt
new file mode 100644
index 0000000..8f7d1f5
--- /dev/null
+++ b/docs/pandoc-docs/source/README.txt
@@ -0,0 +1 @@
+Need to slurp all tutorial .fodt files from https://github.com/SasView/tutorials/ to this folder
\ No newline at end of file
diff --git a/docs/sasview/Tutorial.pptx b/docs/sasview/Tutorial.pptx
index f8107c5..c69d619 100644
Binary files a/docs/sasview/Tutorial.pptx and b/docs/sasview/Tutorial.pptx differ
diff --git a/docs/sasview/Tutorial_Old.pdf b/docs/sasview/Tutorial_SV2.pdf
similarity index 100%
rename from docs/sasview/Tutorial_Old.pdf
rename to docs/sasview/Tutorial_SV2.pdf
diff --git a/docs/sasview/Tutorial_Old.pptx b/docs/sasview/Tutorial_SV2.pptx
similarity index 100%
rename from docs/sasview/Tutorial_Old.pptx
rename to docs/sasview/Tutorial_SV2.pptx
diff --git a/sasview/media/Tutorial.pdf b/docs/sasview/Tutorial_SV3.pdf
similarity index 73%
copy from sasview/media/Tutorial.pdf
copy to docs/sasview/Tutorial_SV3.pdf
index 0ef7362..6f56404 100644
Binary files a/sasview/media/Tutorial.pdf and b/docs/sasview/Tutorial_SV3.pdf differ
diff --git a/docs/sasview/Tutorial.pptx b/docs/sasview/Tutorial_SV3.pptx
similarity index 100%
copy from docs/sasview/Tutorial.pptx
copy to docs/sasview/Tutorial_SV3.pptx
diff --git a/docs/sphinx-docs/Makefile b/docs/sphinx-docs/Makefile
index 8d41d06..647d3ca 100644
--- a/docs/sphinx-docs/Makefile
+++ b/docs/sphinx-docs/Makefile
@@ -15,7 +15,7 @@ endif
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
-ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
+ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source-temp
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
@@ -52,7 +52,7 @@ clean:
stubs:
rm -rf source/dev/api
sphinx-apidoc -o source/dev/api -d 8 ../../src
-
+
html: stubs
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
diff --git a/docs/sphinx-docs/build_sphinx.py b/docs/sphinx-docs/build_sphinx.py
index 2b45615..0653e9e 100755
--- a/docs/sphinx-docs/build_sphinx.py
+++ b/docs/sphinx-docs/build_sphinx.py
@@ -5,124 +5,98 @@ Functions for building sphinx docs.
For more information on the invocation of sphinx see:
http://sphinx-doc.org/invocation.html
"""
+from __future__ import print_function
+
import subprocess
import os
+from os.path import join as joinpath, abspath, dirname, isdir, exists, relpath
import sys
import fnmatch
import shutil
import imp
-from glob import glob
+from glob import glob
from distutils.dir_util import copy_tree
from distutils.util import get_platform
+from distutils.spawn import find_executable
+
from shutil import copy
from os import listdir
platform = '.%s-%s'%(get_platform(),sys.version[:3])
-CURRENT_SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
-
-run = imp.load_source('run', os.path.join(CURRENT_SCRIPT_DIR, '..', '..', 'run.py'))
+# sphinx paths
+SPHINX_ROOT = dirname(abspath(__file__))
+SPHINX_BUILD = joinpath(SPHINX_ROOT, "build")
+SPHINX_SOURCE = joinpath(SPHINX_ROOT, "source-temp")
+SPHINX_PERSPECTIVES = joinpath(SPHINX_SOURCE, "user", "sasgui", "perspectives")
+
+# sasview paths
+SASVIEW_ROOT = joinpath(SPHINX_ROOT, '..', '..')
+SASVIEW_DOCS = joinpath(SPHINX_ROOT, "source")
+SASVIEW_BUILD = abspath(joinpath(SASVIEW_ROOT, "build", "lib"+platform))
+SASVIEW_MEDIA_SOURCE = joinpath(SASVIEW_ROOT, "src", "sas")
+SASVIEW_DOC_TARGET = joinpath(SASVIEW_BUILD, "doc")
+SASVIEW_API_TARGET = joinpath(SPHINX_SOURCE, "dev", "sasview-api")
+
+# sasmodels paths
+SASMODELS_ROOT = joinpath(SASVIEW_ROOT, "..", "sasmodels")
+SASMODELS_DOCS = joinpath(SASMODELS_ROOT, "doc")
+SASMODELS_BUILD = joinpath(SASMODELS_ROOT, "build", "lib")
+SASMODELS_MODEL_SOURCE = joinpath(SASMODELS_DOCS, "model")
+SASMODELS_MODEL_TARGET = joinpath(SPHINX_SOURCE, "user", "models")
+#SASMODELS_API_SOURCE = joinpath(SASMODELS_DOCS, "api")
+SASMODELS_API_TARGET = joinpath(SPHINX_SOURCE, "dev", "sasmodels-api")
+SASMODELS_DEV_SOURCE = joinpath(SASMODELS_DOCS, "developer")
+SASMODELS_DEV_TARGET = joinpath(SPHINX_SOURCE, "dev", "sasmodels-dev")
+SASMODELS_GUIDE_SOURCE = joinpath(SASMODELS_DOCS, "guide")
+SASMODELS_GUIDE_TARGET = joinpath(SPHINX_PERSPECTIVES, "fitting")
+SASMODELS_GUIDE_EXCLUDE = [
+ "index.rst", "install.rst", "intro.rst",
+]
+
+# bumps paths
+BUMPS_DOCS = joinpath(SASVIEW_ROOT, "..", "bumps", "doc")
+BUMPS_SOURCE = joinpath(BUMPS_DOCS, "guide")
+BUMPS_TARGET = joinpath(SPHINX_PERSPECTIVES, "fitting")
+
+run = imp.load_source('run', joinpath(SASVIEW_ROOT, 'run.py'))
run.prepare()
-SASVIEW_SRC = os.path.join(CURRENT_SCRIPT_DIR, "..", "..", "src")
-SASVIEW_BUILD = os.path.abspath(os.path.join(CURRENT_SCRIPT_DIR, "..", "..", "build", "lib"+platform))
-SASVIEW_DOCS = os.path.join(SASVIEW_BUILD, "doc")
-SASVIEW_TEST = os.path.join(SASVIEW_SRC, "..", "sasview", "test", "media")
-SASVIEW_TOC_SOURCE = os.path.join(CURRENT_SCRIPT_DIR, "source")
-
-# Need to slurp in the new sasmodels model definitions to replace the old model_functions.rst
-# We are currently here:
-#/sasview-local-trunk/docs/sphinx-docs/build_sphinx.py
-SASMODELS_SOURCE_PROLOG = os.path.join(CURRENT_SCRIPT_DIR, "..", "..", "..", "sasmodels", "doc")
-SASMODELS_SOURCE_GPU = os.path.join(CURRENT_SCRIPT_DIR, "..", "..", "..", "sasmodels", "doc", "ref", "gpu")
-SASMODELS_SOURCE_SESANS = os.path.join(CURRENT_SCRIPT_DIR, "..", "..", "..", "sasmodels", "doc", "ref", "sesans")
-SASMODELS_SOURCE_SESANSIMG = os.path.join(CURRENT_SCRIPT_DIR, "..", "..", "..", "sasmodels", "doc", "ref", "sesans", "sesans_img")
-SASMODELS_SOURCE_MAGNETISM = os.path.join(CURRENT_SCRIPT_DIR, "..", "..", "..", "sasmodels", "doc", "ref", "magnetism")
-SASMODELS_SOURCE_MAGIMG = os.path.join(CURRENT_SCRIPT_DIR, "..", "..", "..", "sasmodels", "doc", "ref", "magnetism", "mag_img")
-SASMODELS_SOURCE_REF_MODELS = os.path.join(CURRENT_SCRIPT_DIR, "..", "..", "..", "sasmodels", "doc", "ref", "models")
-SASMODELS_SOURCE_MODELS = os.path.join(CURRENT_SCRIPT_DIR, "..", "..", "..", "sasmodels", "doc", "model")
-SASMODELS_SOURCE_IMG = os.path.join(CURRENT_SCRIPT_DIR, "..", "..", "..", "sasmodels", "doc", "model", "img")
-SASMODELS_SOURCE_AUTOIMG = os.path.join(CURRENT_SCRIPT_DIR, "..", "..", "..", "sasmodels", "doc", "_build", "html","_images")
-## Don't do assemble-in-place
-## Assemble the docs in a temporary folder
-SASMODELS_DEST_PROLOG = os.path.join(CURRENT_SCRIPT_DIR, "source-temp")
-SASMODELS_DEST_REF_MODELS = os.path.join(SASMODELS_DEST_PROLOG, "user")
-SASMODELS_DEST_MODELS = os.path.join(SASMODELS_DEST_PROLOG, "user", "models")
-SASMODELS_DEST_IMG = os.path.join(SASMODELS_DEST_PROLOG, "user", "model-imgs", "new-models")
-SASMODELS_DEST_MAGIMG = os.path.join(SASMODELS_DEST_PROLOG, "user", "mag_img")
-SASMODELS_DEST_SESANSIMG = os.path.join(SASMODELS_DEST_PROLOG, "user", "sesans_img")
-SASMODELS_DEST_BUILDIMG = os.path.join(SASMODELS_DEST_PROLOG, "user", "models", "img")
-
-#if os.path.exists(SASMODELS_SOURCE_PROLOG):
-# print "Found models prolog folder at ", SASMODELS_SOURCE_PROLOG
-#if os.path.exists(SASMODELS_SOURCE_REF_MODELS):
-# print "Found models ref folder at ", SASMODELS_SOURCE_REF_MODELS
-#if os.path.exists(SASMODELS_SOURCE_MODELS):
-# print "Found models folder at ", SASMODELS_SOURCE_MODELS
-#if os.path.exists(SASMODELS_SOURCE_IMG):
-# print "Found img folder at ", SASMODELS_SOURCE_IMG
-#if os.path.exists(SASMODELS_DEST_REF_MODELS):
-# print "Found models ref folder at ", SASMODELS_DEST_REF_MODELS
-#if os.path.exists(SASMODELS_DEST_MODELS):
-# print "Found models folder at ", SASMODELS_DEST_MODELS
-#if os.path.exists(SASMODELS_DEST_IMG):
-# print "Found img folder at ", SASMODELS_DEST_IMG
-#sys.exit()
-
-SPHINX_BUILD = os.path.join(CURRENT_SCRIPT_DIR, "build")
-SPHINX_SOURCE = os.path.join(CURRENT_SCRIPT_DIR, "source-temp")
-SPHINX_SOURCE_API = os.path.join(SPHINX_SOURCE, "dev", "api")
-SPHINX_SOURCE_GUIFRAME = os.path.join(SPHINX_SOURCE, "user", "sasgui", "guiframe")
-SPHINX_SOURCE_MODELS = os.path.join(SPHINX_SOURCE, "user", "models")
-SPHINX_SOURCE_PERSPECTIVES = os.path.join(SPHINX_SOURCE, "user", "sasgui", "perspectives")
-SPHINX_SOURCE_TEST = os.path.join(SPHINX_SOURCE, "test")
-SPHINX_SOURCE_USER = os.path.join(SPHINX_SOURCE, "user")
-
-BUMPS_DOCS = os.path.join(CURRENT_SCRIPT_DIR, "..", "..", "..",
- "bumps", "doc", "guide")
-BUMPS_TARGET = os.path.join(SPHINX_SOURCE_PERSPECTIVES, "fitting")
-
def inplace_change(filename, old_string, new_string):
# Thanks to http://stackoverflow.com/questions/4128144/replace-string-within-file-contents
s=open(filename).read()
if old_string in s:
- print 'Changing "{old_string}" to "{new_string}"'.format(**locals())
+ print('Changing "{old_string}" to "{new_string}"'.format(**locals()))
s=s.replace(old_string, new_string)
f=open(filename, 'w')
f.write(s)
f.flush()
f.close()
else:
- print 'No occurences of "{old_string}" found.'.format(**locals())
+ print('No occurences of "{old_string}" found.'.format(**locals()))
def _remove_dir(dir_path):
"""Removes the given directory."""
- if os.path.isdir(dir_path):
- print "Removing \"%s\"... " % dir_path
+ if isdir(dir_path):
+ print("Removing \"%s\"... " % dir_path)
shutil.rmtree(dir_path)
def clean():
"""
Clean the sphinx build directory.
"""
- print "=== Cleaning Sphinx Build ==="
- _remove_dir(SASVIEW_DOCS)
+ print("=== Cleaning Sphinx Build ===")
+ _remove_dir(SASVIEW_DOC_TARGET)
_remove_dir(SPHINX_BUILD)
_remove_dir(SPHINX_SOURCE)
- #_remove_dir(SPHINX_SOURCE_GUIFRAME)
- #_remove_dir(SPHINX_SOURCE_MODELS)
- #_remove_dir(SPHINX_SOURCE_PERSPECTIVES)
- #_remove_dir(SPHINX_SOURCE_TEST)
def setup_source_temp():
"""
Copy the source toctrees to new folder for assembling the sphinx-docs
"""
- print "=== Copying Source toctrees ==="
- if os.path.exists(SASVIEW_TOC_SOURCE):
- print "Found docs folder at ", SASVIEW_TOC_SOURCE
- shutil.copytree(SASVIEW_TOC_SOURCE, SPHINX_SOURCE)
+ print("=== Copying Source toctrees ===")
+ shutil.copytree(SASVIEW_DOCS, SPHINX_SOURCE)
def retrieve_user_docs():
"""
@@ -140,247 +114,162 @@ def retrieve_user_docs():
so that Sphinx may pick it up when generating the documentation.
"""
- print "=== Retrieve User Docs ==="
-
- # Copy documentation files from their "source" to their "destination".
- for root, dirnames, _ in os.walk(SASVIEW_SRC):
- for dirname in fnmatch.filter(dirnames, 'media'):
-
- docs = os.path.abspath(os.path.join(root, dirname))
- print "Found docs folder at \"%s\"." % docs
-
- dest_dir_part = os.path.dirname(os.path.relpath(docs, SASVIEW_SRC))
- if os.sep in dest_dir_part:
- dest_dir_part = dest_dir_part[dest_dir_part.index(os.sep) + 1:]
- dest_dir = os.path.join(SPHINX_SOURCE, "user", dest_dir_part)
-
- copy_tree(docs, dest_dir)
-
- # Now pickup testdata_help.rst
-# print os.path.abspath(SASVIEW_TEST)
-# print os.path.abspath(SPHINX_SOURCE_TEST)
- print "=== Including Test Data Docs ==="
- if os.path.exists(SASVIEW_TEST):
- print "Found docs folder at ", SASVIEW_TEST
- shutil.copytree(SASVIEW_TEST, SPHINX_SOURCE_TEST)
-
- print "=== And the Sasmodels Docs ==="
- # Make sure we have the relevant images for the new sasmodels documentation
- # First(!) we'll make a local reference copy for SasView (/new-models will be cleaned each build)
- if os.path.exists(SASMODELS_SOURCE_IMG):
- print "Found img folder SASMODELS_SOURCE_IMG at ", SASMODELS_SOURCE_IMG
- if not os.path.exists(SASMODELS_DEST_IMG):
- print "Missing docs folder SASMODELS_DEST_IMG at ", SASMODELS_DEST_IMG
- os.makedirs(SASMODELS_DEST_IMG)
- print "created SASMODELS_DEST_BUILDIMG at ", SASMODELS_DEST_BUILDIMG
- else: print "Found img folder SASMODELS_DEST_IMG at ", SASMODELS_DEST_IMG
- print "Copying sasmodels model image files..."
- for files in os.listdir(SASMODELS_SOURCE_IMG):
- fromhere=os.path.join(SASMODELS_SOURCE_IMG,files)
- tohere=os.path.join(SASMODELS_DEST_IMG,files)
- shutil.copy(fromhere,tohere)
- else: print "cannot find SASMODELS_SOURCE_IMG", SASMODELS_SOURCE_IMG
-
- if os.path.exists(SASMODELS_SOURCE_AUTOIMG):
- print "Found img folder SASMODELS_SOURCE_AUTOIMG at ", SASMODELS_SOURCE_AUTOIMG
- if not os.path.exists(SASMODELS_DEST_IMG):
- print "Missing docs folder SASMODELS_DEST_IMG at ", SASMODELS_DEST_IMG
- os.makedirs(SASMODELS_DEST_BUILDIMG)
- print "created SASMODELS_DEST_BUILDIMG at ", SASMODELS_DEST_BUILDIMG
- print "Copying sasmodels model auto-generated image files..."
- for files in os.listdir(SASMODELS_SOURCE_AUTOIMG):
- fromhere=os.path.join(SASMODELS_SOURCE_AUTOIMG,files)
- tohere=os.path.join(SASMODELS_DEST_IMG,files)
- shutil.copy(fromhere,tohere)
- else: print "no source directory",SASMODELS_SOURCE_AUTOIMG ,"was found"
-
- # And the rst prolog with the unit substitutions
- if os.path.exists(SASMODELS_SOURCE_PROLOG):
- print "Found prolog folder SASMODELS_SOURCE_PROLOG at ", SASMODELS_SOURCE_PROLOG
- if os.path.exists(SASMODELS_DEST_PROLOG):
- print "Found docs folder SASMODELS_DEST_PROLOG at ", SASMODELS_DEST_PROLOG
- print "Copying sasmodels rst_prolog file..."
- for files in os.listdir(SASMODELS_SOURCE_PROLOG):
- if files.startswith("rst"):
- fromhere=os.path.join(SASMODELS_SOURCE_PROLOG,files)
- tohere=os.path.join(SASMODELS_DEST_PROLOG,files)
- shutil.copy(fromhere,tohere)
-
- if os.path.exists(SASMODELS_SOURCE_GPU):
- print "Found docs folder SASMODELS_SOURCE_GPU at ", SASMODELS_SOURCE_GPU
- if os.path.exists(SPHINX_SOURCE_USER):
- print "Found docs folder SPHINX_SOURCE_USER at ", SPHINX_SOURCE_USER
- print "Copying sasmodels gpu files..."
- for files in os.listdir(SASMODELS_SOURCE_GPU):
- if files.endswith(".rst"):
- fromhere=os.path.join(SASMODELS_SOURCE_GPU,files)
- tohere=os.path.join(SPHINX_SOURCE_USER,files)
- shutil.copy(fromhere,tohere)
-
- if os.path.exists(SASMODELS_SOURCE_SESANS):
- print "Found docs folder SASMODELS_SOURCE_SESANS at ", SASMODELS_SOURCE_SESANS
- if os.path.exists(SPHINX_SOURCE_USER):
- print "Found docs folder SPHINX_SOURCE_USER at ", SPHINX_SOURCE_USER
- print "Copying sasmodels sesans files..."
- for files in os.listdir(SASMODELS_SOURCE_SESANS):
- if files.endswith(".rst"):
- fromhere=os.path.join(SASMODELS_SOURCE_SESANS,files)
- tohere=os.path.join(SPHINX_SOURCE_USER,files)
- shutil.copy(fromhere,tohere)
-
- if os.path.exists(SASMODELS_SOURCE_MAGNETISM):
- print "Found docs folder SASMODELS_SOURCE_MAGNETISM at ", SASMODELS_SOURCE_MAGNETISM
- if os.path.exists(SASMODELS_DEST_REF_MODELS):
- print "Found docs folder SASMODELS_DEST_REF_MODELS at ", SASMODELS_DEST_REF_MODELS
- print "Copying sasmodels model toctree files..."
- for files in os.listdir(SASMODELS_SOURCE_MAGNETISM):
- if files.endswith(".rst"):
- fromhere=os.path.join(SASMODELS_SOURCE_MAGNETISM,files)
- tohere=os.path.join(SASMODELS_DEST_REF_MODELS,files)
- shutil.copy(fromhere,tohere)
-
- if os.path.exists(SASMODELS_SOURCE_MAGIMG):
- print "Found img folder SASMODELS_SOURCE_MAGIMG at ", SASMODELS_SOURCE_MAGIMG
- if not os.path.exists(SASMODELS_DEST_MAGIMG):
- print "Missing img folder SASMODELS_DEST_MAGIMG at ", SASMODELS_DEST_MAGIMG
- os.makedirs(SASMODELS_DEST_MAGIMG)
- print "created SASMODELS_DEST_MAGIMG at ", SASMODELS_DEST_MAGIMG
- print "Copying sasmodels mag image files..."
- for files in os.listdir(SASMODELS_SOURCE_MAGIMG):
- fromhere=os.path.join(SASMODELS_SOURCE_MAGIMG,files)
- tohere=os.path.join(SASMODELS_DEST_MAGIMG,files)
- shutil.copy(fromhere,tohere)
- else: print "no source directory",SASMODELS_SOURCE_MAGIMG ,"was found"
-
- if os.path.exists(SASMODELS_SOURCE_SESANSIMG):
- print "Found img folder SASMODELS_SOURCE_SESANSIMG at ", SASMODELS_SOURCE_SESANSIMG
- if not os.path.exists(SASMODELS_DEST_SESANSIMG):
- print "Missing img folder SASMODELS_DEST_SESANSIMG at ", SASMODELS_DEST_SESANSIMG
- os.makedirs(SASMODELS_DEST_SESANSIMG)
- print "created SASMODELS_DEST_SESANSIMG at ", SASMODELS_DEST_SESANSIMG
- print "Copying sasmodels sesans image files..."
- for files in os.listdir(SASMODELS_SOURCE_SESANSIMG):
- fromhere=os.path.join(SASMODELS_SOURCE_SESANSIMG,files)
- tohere=os.path.join(SASMODELS_DEST_SESANSIMG,files)
- shutil.copy(fromhere,tohere)
- else: print "no source directory",SASMODELS_SOURCE_SESANSIMG ,"was found"
-
- if os.path.exists(SASMODELS_SOURCE_REF_MODELS):
- print "Found docs folder SASMODELS_SOURCE_REF_MODELS at ", SASMODELS_SOURCE_REF_MODELS
- if os.path.exists(SASMODELS_DEST_REF_MODELS):
- print "Found docs folder SASMODELS_DEST_REF_MODELS at ", SASMODELS_DEST_REF_MODELS
- print "Copying sasmodels model toctree files..."
- for files in os.listdir(SASMODELS_SOURCE_REF_MODELS):
- if files.endswith(".rst"):
- fromhere=os.path.join(SASMODELS_SOURCE_REF_MODELS,files)
- tohere=os.path.join(SASMODELS_DEST_REF_MODELS,files)
- shutil.copy(fromhere,tohere)
- # But need to change the path to the model docs in the tocs
- for files in os.listdir(SASMODELS_DEST_REF_MODELS):
-# print files
- if files.startswith("shape"):
- print "Changing toc paths in", files
- inplace_change(os.path.join(SASMODELS_DEST_REF_MODELS,files), "../../model/", "models/")
- if files.startswith("sphere"):
- print "Changing toc paths in", files
- inplace_change(os.path.join(SASMODELS_DEST_REF_MODELS,files), "../../model/", "models/")
- if files.startswith("custom"):
- print "Changing toc paths in", files
- inplace_change(os.path.join(SASMODELS_DEST_REF_MODELS,files), "../../model/", "models/")
- if files.startswith("structure"):
- print "Changing toc paths in", files
- inplace_change(os.path.join(SASMODELS_DEST_REF_MODELS,files), "../../model/", "models/")
-
- if os.path.exists(SASMODELS_SOURCE_MODELS):
- print "Found docs folder SASMODELS_SOURCE_MODELS at ", SASMODELS_SOURCE_MODELS
- if os.path.exists(SASMODELS_DEST_MODELS):
- print "Found docs folder SASMODELS_DEST_MODELS at ", SASMODELS_DEST_MODELS
- print "Copying sasmodels model files..."
- for files in os.listdir(SASMODELS_SOURCE_MODELS):
- if files.endswith(".rst"):
- fromhere=os.path.join(SASMODELS_SOURCE_MODELS,files)
- tohere=os.path.join(SASMODELS_DEST_MODELS,files)
- shutil.copy(fromhere,tohere)
- else:
- print "Missing docs folder SASMODELS_DEST_MODELS at ", SASMODELS_DEST_MODELS
- os.makedirs(SASMODELS_DEST_MODELS)
- if not os.path.exists(SASMODELS_DEST_BUILDIMG):
- os.makedirs(SASMODELS_DEST_BUILDIMG)
- print "Created docs folder SASMODELS_DEST_MODELS at ", SASMODELS_DEST_MODELS
- print "Copying model files for build..."
- for files in os.listdir(SASMODELS_SOURCE_MODELS):
- if files.endswith(".rst"):
- fromhere=os.path.join(SASMODELS_SOURCE_MODELS,files)
- tohere=os.path.join(SASMODELS_DEST_MODELS,files)
- shutil.copy(fromhere,tohere)
- # No choice but to do this because model files are all coded for images in /models/img
- print "Copying image files for build..."
- for files in os.listdir(SASMODELS_DEST_IMG):
- fromhere=os.path.join(SASMODELS_DEST_IMG,files)
- tohere=os.path.join(SASMODELS_DEST_BUILDIMG,files)
- shutil.copy(fromhere,tohere)
+ print("=== Retrieve User Docs ===")
+
+ # Copy documentation files from sas/.../media to the sphinx directory
+ for root, dirs, _ in os.walk(SASVIEW_MEDIA_SOURCE):
+ if 'media' in dirs:
+ source_dir = abspath(joinpath(root, "media"))
+ relative = dirname(relpath(source_dir, SASVIEW_MEDIA_SOURCE))
+ dest_dir = joinpath(SPHINX_SOURCE, "user", relative)
+
+ print("Found sasview docs folder at \"%s\"." % relative)
+ copy_tree(source_dir, dest_dir)
+
+ print("=== Sasmodels Docs ===")
+ shutil.copy(joinpath(SASMODELS_DOCS, "rst_prolog"), SPHINX_SOURCE)
+ copy_tree(SASMODELS_MODEL_SOURCE, SASMODELS_MODEL_TARGET)
+ #copy_tree(SASMODELS_API_SOURCE, SASMODELS_API_TARGET)
+ copy_tree(SASMODELS_DEV_SOURCE, SASMODELS_DEV_TARGET)
+ copy_tree(SASMODELS_GUIDE_SOURCE, SASMODELS_GUIDE_TARGET)
+ for filename in SASMODELS_GUIDE_EXCLUDE:
+ os.unlink(joinpath(SASMODELS_GUIDE_TARGET, filename))
+
+ # Model category files reference the model as ../../model/name.rst. Since
+ # we are rearranging the tree, we need to update each of these links.
+ catdir = joinpath(SASMODELS_GUIDE_TARGET, "models")
+ for filename in os.listdir(catdir):
+ inplace_change(joinpath(catdir, filename), "../../model/", "/user/models/")
def retrieve_bumps_docs():
"""
Copies select files from the bumps documentation into fitting perspective
"""
- if os.path.exists(BUMPS_DOCS):
- print "=== Retrieve BUMPS Docs ==="
- filenames = [os.path.join(BUMPS_DOCS, "optimizer.rst")]
- filenames += glob(os.path.join(BUMPS_DOCS, "dream-*.png"))
- filenames += glob(os.path.join(BUMPS_DOCS, "fit-*.png"))
+ if exists(BUMPS_SOURCE):
+ print("=== Retrieve BUMPS Docs ===")
+ filenames = [joinpath(BUMPS_SOURCE, "optimizer.rst")]
+ filenames += glob(joinpath(BUMPS_SOURCE, "dream-*.png"))
+ filenames += glob(joinpath(BUMPS_SOURCE, "fit-*.png"))
for f in filenames:
- print "Copying file", f
+ print("Copying file", f)
shutil.copy(f, BUMPS_TARGET)
else:
- print """
-*** Error *** missing directory %s
+ print("""
+======= Error =======
+missing directory %s
The documentation will not include the optimizer selection section.
Checkout the bumps source tree and rebuild the docs.
-
-
-""" % BUMPS_DOCS
+""" % BUMPS_DOCS)
def apidoc():
"""
Runs sphinx-apidoc to generate .rst files from the docstrings in .py files
in the SasView build directory.
"""
- print "=== Generate API Rest Files ==="
+ print("=== Generate API Rest Files ===")
# Clean directory before generating a new version.
- _remove_dir(SPHINX_SOURCE_API)
+ #_remove_dir(SASVIEW_API_TARGET)
subprocess.call(["sphinx-apidoc",
- "-o", SPHINX_SOURCE_API, # Output dir.
+ "-o", SASVIEW_API_TARGET, # Output dir.
"-d", "8", # Max depth of TOC.
+ "-H", "SasView", # Package header
SASVIEW_BUILD])
+ subprocess.call(["sphinx-apidoc",
+ "-o", SASMODELS_API_TARGET, # Output dir.
+ "-d", "8", # Max depth of TOC.
+ "-H", "sasmodels", # Package header
+ SASMODELS_BUILD,
+ joinpath(SASMODELS_BUILD, "sasmodels", "models"), # exclude
+ ])
+
+def build_pdf():
+ """
+ Runs sphinx-build for pdf. Reads in all .rst files and spits out the final html.
+ """
+ print("=== Build PDF Docs from ReST Files ===")
+ subprocess.call(["sphinx-build",
+ "-b", "latex", # Builder name. TODO: accept as arg to setup.py.
+ "-d", joinpath(SPHINX_BUILD, "doctrees"),
+ SPHINX_SOURCE,
+ joinpath(SPHINX_BUILD, "latex")])
+
+ LATEXDIR = joinpath(SPHINX_BUILD, "latex")
+ #TODO: Does it need to be done so many time?
+ def pdflatex():
+ subprocess.call(["pdflatex", "SasView.tex"], cwd=LATEXDIR)
+ pdflatex()
+ pdflatex()
+ pdflatex()
+ subprocess.call(["makeindex", "-s", "python.ist", "SasView.idx"], cwd=LATEXDIR)
+ pdflatex()
+ pdflatex()
+
+ print("=== Copy PDF to HTML Directory ===")
+ source = joinpath(LATEXDIR, "SasView.pdf")
+ target = joinpath(SASVIEW_DOC_TARGET, "SasView.pdf")
+ shutil.copyfile(source, target)
+
def build():
"""
Runs sphinx-build. Reads in all .rst files and spits out the final html.
"""
- print "=== Build HTML Docs from Rest Files ==="
+ print("=== Build HTML Docs from ReST Files ===")
subprocess.call(["sphinx-build",
"-b", "html", # Builder name. TODO: accept as arg to setup.py.
- "-d", os.path.join(SPHINX_BUILD, "doctrees"),
+ "-d", joinpath(SPHINX_BUILD, "doctrees"),
SPHINX_SOURCE,
- os.path.join(SPHINX_BUILD, "html")])
-
- print "=== Copy HTML Docs to Build Directory ==="
- html = os.path.join(SPHINX_BUILD, "html")
- copy_tree(html, SASVIEW_DOCS)
+ joinpath(SPHINX_BUILD, "html")])
+
+ print("=== Copy HTML Docs to Build Directory ===")
+ html = joinpath(SPHINX_BUILD, "html")
+ copy_tree(html, SASVIEW_DOC_TARGET)
+
+def fetch_katex(version, destination="_static"):
+ from zipfile import ZipFile
+ import urllib2
+ url = "https://github.com/Khan/KaTeX/releases/download/%s/katex.zip" % version
+ cache_path = "katex_%s.zip" % version
+ if not exists(cache_path):
+ try:
+ fd_in = urllib2.urlopen(url)
+ with open(cache_path, "wb") as fd_out:
+ fd_out.write(fd_in.read())
+ finally:
+ fd_in.close()
+ with ZipFile(cache_path) as zip:
+ zip.extractall(destination)
+
+def convert_katex():
+ print("=== Preprocess HTML, converting latex to html ===")
+ subprocess.call(["node", "convertKaTex.js", SASVIEW_DOC_TARGET])
+
+def convert_mathjax():
+ print("=== Preprocess HTML, converting latex to html ===")
+ subprocess.call(["node", "convertMathJax.js", SASVIEW_DOC_TARGET])
+
+def fetch_mathjax():
+ subprocess.call(["npm", "install", "mathjax-node-page"])
+ # TODO: copy fonts from node_modules/mathjax/fonts/HTML-CSS/Tex into static
def rebuild():
clean()
setup_source_temp()
retrieve_user_docs()
retrieve_bumps_docs()
+ #fetch_katex(version=KATEX_VERSION, destination=KATEX_PARENT)
+ #fetch_mathjax()
apidoc()
build()
+ if find_executable('latex'):
+ build_pdf()
+ #convert_katex()
+ #convert_mathjax()
- print "=== Done ==="
+ print("=== Done ===")
if __name__ == "__main__":
rebuild()
diff --git a/docs/sphinx-docs/convertKaTex.js b/docs/sphinx-docs/convertKaTex.js
new file mode 100755
index 0000000..597643c
--- /dev/null
+++ b/docs/sphinx-docs/convertKaTex.js
@@ -0,0 +1,87 @@
+#!/usr/bin/env node
+// Usage:
+// npm install jsdom
+// node convertTree.js build/html
+/* eslint no-console:0 */
+/* global katex */
+"use strict";
+
+/**
+ * Set a global variables name to value.
+ */
+function setGlobal(name, value) {
+ (function(globals) { globals[name] = value; }((1, eval)('this')));
+}
+
+const fs = require("fs"); // standard node
+const jsdom = require("jsdom"); // npm install jsdom
+const { JSDOM } = jsdom;
+
+// Need a fake document in order to initialize katex, and it needs to be strict
+const DTD = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">';
+const empty_dom = new JSDOM(DTD+'\n<html><body></body></html>');
+setGlobal('document', empty_dom.window.document);
+
+const path = require("path");
+setGlobal('katex', require(path.resolve("./build/html/_static/katex/katex.min")));
+const renderMathInElement = require(path.resolve("./build/html/_static/katex/contrib/auto-render.min"));
+//setGlobal('katex', require("../../katex.js"));
+//const renderMathInElement = require("../auto-render/auto-render");
+
+function isDir(path) {
+ const stat = fs.statSync(path);
+ return (stat && stat.isDirectory());
+}
+
+/**
+ * Walk a directory tree, yielding a list of matching filenames
+ *
+ * @param {path} dir - root of the tree which is walked
+ * @param {regex} [pattern] - regular expression match for the full path
+ */
+function* walkit(dir, pattern = /./) {
+ const _walk = function* (dir) {
+ const entries = fs.readdirSync(dir);
+ for (const entry of entries) {
+ const path = dir + "/" + entry;
+ if (isDir(path)) {
+ //console.log('walking '+path);
+ yield* _walk(path);
+ } else if (pattern.test(path)) {
+ //console.log('yielding '+path);
+ yield path;
+ }
+ }
+ };
+ yield* _walk(dir);
+}
+
+function processHtml(path) {
+ JSDOM.fromFile(path).then(dom => {
+ console.log("====> processing", path);
+ //console.log(dom.serialize());
+ setGlobal('document', dom.window.document);
+ //console.log(document.compatMode);
+ renderMathInElement(dom.window.document.body);
+ //console.log(dom.serialize());
+ fs.writeFileSync(path, dom.serialize());
+ }).catch(console.log.bind(console));
+}
+
+function processTree(dir) {
+ //console.log(process.argv.slice(2));
+ for (const path of walkit(dir, /\.html$/)) {
+ processHtml(path);
+ }
+}
+
+if (typeof require !== 'undefined' && require.main === module) {
+ //console.log(process.argv.slice(2));
+ for (const arg of process.argv.slice(2)) {
+ if (isDir(arg)) {
+ processTree(arg);
+ } else if (/\.html$/.test(arg)) {
+ processHtml(arg);
+ }
+ }
+}
diff --git a/docs/sphinx-docs/convertMathJax.js b/docs/sphinx-docs/convertMathJax.js
new file mode 100755
index 0000000..43e97bf
--- /dev/null
+++ b/docs/sphinx-docs/convertMathJax.js
@@ -0,0 +1,168 @@
+#!/usr/bin/env node
+// Usage:
+// npm install jsdom
+// node convertTree.js build/html
+/* eslint no-console:0 */
+/* global katex */
+"use strict";
+
+/**
+ * Set a global variables name to value.
+ */
+function setGlobal(name, value) {
+ (function(globals) { globals[name] = value; }((1, eval)('this')));
+}
+
+const fs = require("fs");
+//const await = require("await");
+const mjpage = require('mathjax-node-page').mjpage;
+
+function isDir(path) {
+ const stat = fs.statSync(path);
+ return (stat && stat.isDirectory());
+}
+
+/**
+ * Walk a directory tree, yielding a list of matching filenames
+ *
+ * @param {path} dir - root of the tree which is walked
+ * @param {regex} [pattern] - regular expression match for the full path
+ */
+function* walkit(dir, pattern = /./) {
+ const _walk = function* (dir) {
+ const entries = fs.readdirSync(dir);
+ for (const entry of entries) {
+ const path = dir + "/" + entry;
+ if (isDir(path)) {
+ //console.log('walking '+path);
+ yield* _walk(path);
+ } else if (pattern.test(path)) {
+ //console.log('yielding '+path);
+ yield path;
+ }
+ }
+ };
+ yield* _walk(dir);
+}
+
+function readFileAsync(path) {
+ return new Promise((resolve, reject) =>
+ fs.readFile(path, (err, data) => {
+ if (err) { reject(err); } else { resolve(data); }
+ }));
+}
+
+function writeFileAsync(path, data) {
+ return new Promise((resolve, reject) =>
+ fs.writeFile(path, data, (err) => {
+ if (err) { reject(err); } else { resolve(data); }
+ }));
+}
+
+const pageConfig = {
+ format: ["TeX"],
+ //output: 'html',
+ output: 'svg',
+ fontURL: 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js/fonts/HTML-CSS',
+ MathJax: {
+ //config: ["MMLorHTML.js"],
+ //jax: ["input/TeX","input/MathML","output/HTML-CSS",
+ // "output/NativeMML", "output/PreviewHTML"],
+ jax: ["input/TeX", "output/HTML-CSS"],
+ //extensions: ["tex2jax.js","mml2jax.js","MathMenu.js",
+ // "MathZoom.js", "fast-preview.js",
+ // "AssistiveMML.js", "a11y/accessibility-menu.js"
+ // ],
+ extensions: ["tex2jax.js"],
+ TeX: {
+ extensions: ["AMSmath.js","AMSsymbols.js",
+ "noErrors.js","noUndefined.js"]
+ }
+ }
+}
+const mjnodeConfig = {
+ ex: 6, // ex-size in pixels
+ width: 100, // width of math container (in ex) for linebreaking and tags
+ fragment: false,
+ useFontCache: true, // use <defs> and <use> in svg output?
+ useGlobalCache: false, // use common <defs> for all equations?
+ //state: mjstate, // track global state
+ linebreaks: false, // do linebreaking?
+ equationNumbers: "none", // or "AMS" or "all"
+ //math: "", // the math to typeset
+ html: true, // generate HTML output?
+ css: true, // generate CSS for HTML output?
+ //mml: false, // generate mml output?
+ //svg: false, // generate svg output?
+ //speakText: true, // add spoken annotations to output?
+ //timeout: 10 * 1000, // 10 second timeout before restarting MathJax
+}
+function mjpageAsync(input, pageConfig, mjnodeConfig) {
+ return new Promise((resolve, reject) =>
+ mjpage(input, pageConfig, mjnodeConfig, output => resolve(output))
+ );
+}
+async function updateHtmlAsync(path) {
+ try {
+ console.log("====> processing", path);
+ const input = await readFileAsync(path);
+ const output = await mjpageAsync(input, pageConfig, mjnodeConfig);
+ return await writeFileAsync(path, output);
+ } catch (err) {
+ console.log(err);
+ }
+}
+
+async function processTreeAsync(dir) {
+ //console.log(dir);
+ for (const path of walkit(dir, /\.html$/)) {
+ await updateHtmlAsync(path);
+ }
+}
+
+async function mainAsync(args) {
+ //console.log(process.argv.slice(2));
+ for (const arg of args) {
+ if (isDir(arg)) {
+ processTreeAsync(arg);
+ } else if (/\.html$/.test(arg)) {
+ updateHtmlAsync(arg);
+ }
+ }
+}
+
+
+function updateHtmlSortOfSync(path) {
+ console.log("====> loading", path);
+ const input = fs.readFileSync(path);
+ //const pageConfig = {format: ['TeX']}
+ //const mjnodeConfig = {html: true}
+ mjpage(input, pageConfig, mjnodeConfig,
+ //output => console.log(output));
+ output => {
+ console.log("====> processed", path);
+ fs.writeFileSync(path, output)
+ });
+}
+
+function processTreeSortOfSync(dir) {
+ //console.log(dir);
+ for (const path of walkit(dir, /\.html$/)) {
+ updateHtmlSortOfSync(path);
+ }
+}
+
+function mainSortOfSync(args) {
+ //console.log(process.argv.slice(2));
+ for (const arg of args) {
+ if (isDir(arg)) {
+ processTreeSortOfSync(arg);
+ } else if (/\.html$/.test(arg)) {
+ updateHtmlSortOfSync(arg);
+ }
+ }
+}
+
+if (typeof require !== 'undefined' && require.main === module) {
+ console.log(mainAsync(process.argv.slice(2)));
+}
diff --git a/docs/sphinx-docs/source/_extensions/mathjax.py b/docs/sphinx-docs/source/_extensions/mathjax.py
new file mode 100644
index 0000000..4565a21
--- /dev/null
+++ b/docs/sphinx-docs/source/_extensions/mathjax.py
@@ -0,0 +1,117 @@
+# -*- coding: utf-8 -*-
+"""
+ sphinx.ext.mathjax
+ ~~~~~~~~~~~~~~~~~~
+
+ Allow `MathJax <http://mathjax.org/>`_ to be used to display math in
+ Sphinx's HTML writer -- requires the MathJax JavaScript library on your
+ webserver/computer.
+
+ :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+
+ sample lines in conf.py to use this::
+
+ mathjax_path = ['https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.6.0/katex.min.js',
+ 'http://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.6.0/contrib/auto-render.min.js',
+ 'rendermath.js']
+ mathjax_css = 'https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.6.0/katex.min.css'
+
+ with rendermath.js containing::
+
+ document.addEventListener("DOMContentLoaded", function(event) {
+ renderMathInElement(document.body);
+ });
+
+ 2016-08-09 Jason Sachs
+ * allow list of URLS for mathjax_path, which permits use of katex.js
+"""
+
+from docutils import nodes
+
+import sphinx
+from sphinx.locale import _
+from sphinx.errors import ExtensionError
+from sphinx.ext.mathbase import setup_math as mathbase_setup
+
+
+def html_visit_math(self, node):
+ self.body.append(self.starttag(node, 'span', '', CLASS='math'))
+ self.body.append(self.builder.config.mathjax_inline[0] +
+ self.encode(node['latex']) +
+ self.builder.config.mathjax_inline[1] + '</span>')
+ raise nodes.SkipNode
+
+
+def html_visit_displaymath(self, node):
+ self.body.append(self.starttag(node, 'div', CLASS='math'))
+ if node['nowrap']:
+ self.body.append(self.encode(node['latex']))
+ self.body.append('</div>')
+ raise nodes.SkipNode
+
+ # necessary to e.g. set the id property correctly
+ if node['number']:
+ self.body.append('<span class="eqno">(%s)' % node['number'])
+ self.add_permalink_ref(node, _('Permalink to this equation'))
+ self.body.append('</span>')
+ self.body.append(self.builder.config.mathjax_display[0])
+ parts = [prt for prt in node['latex'].split('\n\n') if prt.strip()]
+ if len(parts) > 1: # Add alignment if there are more than 1 equation
+ self.body.append(r' \begin{align}\begin{aligned}')
+ for i, part in enumerate(parts):
+ part = self.encode(part)
+ if r'\\' in part:
+ self.body.append(r'\begin{split}' + part + r'\end{split}')
+ else:
+ self.body.append(part)
+ if i < len(parts) - 1: # append new line if not the last equation
+ self.body.append(r'\\')
+ if len(parts) > 1: # Add alignment if there are more than 1 equation
+ self.body.append(r'\end{aligned}\end{align} ')
+ self.body.append(self.builder.config.mathjax_display[1])
+ self.body.append('</div>\n')
+ raise nodes.SkipNode
+
+try:
+ basestring
+except:
+ basestring = str
+
+def builder_inited(app):
+ jaxpath = app.config.mathjax_path
+ if not jaxpath:
+ raise ExtensionError('mathjax_path config value must be set for the '
+ 'mathjax extension to work')
+
+ # app.config.mathjax_path can be a string or a list of strings
+ if isinstance(jaxpath, basestring):
+ app.add_javascript(jaxpath)
+ else:
+ for p in jaxpath:
+ app.add_javascript(p)
+
+ if app.config.mathjax_css:
+ app.add_stylesheet(app.config.mathjax_css)
+
+
+def setup(app):
+ try:
+ mathbase_setup(app, (html_visit_math, None), (html_visit_displaymath, None))
+ except ExtensionError:
+ raise ExtensionError('sphinx.ext.mathjax: other math package is already loaded')
+
+ # more information for mathjax secure url is here:
+ # http://docs.mathjax.org/en/latest/start.html#secure-access-to-the-cdn
+ app.add_config_value('mathjax_path',
+ 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?'
+ 'config=TeX-MML-AM_CHTML',
+ #'config=TeX-AMS-MML_HTMLorMML',
+ False)
+ app.add_config_value('mathjax_css', None, 'html')
+ app.add_config_value('mathjax_use_katex', False, 'html')
+ app.add_config_value('mathjax_inline', [r'\(', r'\)'], 'html')
+ app.add_config_value('mathjax_display', [r'\[', r'\]'], 'html')
+ app.connect('builder-inited', builder_inited)
+
+ return {'version': sphinx.__display_version__, 'parallel_read_safe': True}
diff --git a/docs/sphinx-docs/source/_static/rendermath.js b/docs/sphinx-docs/source/_static/rendermath.js
new file mode 100644
index 0000000..b7e062f
--- /dev/null
+++ b/docs/sphinx-docs/source/_static/rendermath.js
@@ -0,0 +1,4 @@
+// Render katex on page.
+document.addEventListener("DOMContentLoaded", function(event) {
+ renderMathInElement(document.body);
+});
diff --git a/docs/sphinx-docs/source/conf.py b/docs/sphinx-docs/source/conf.py
index a88a4ee..cbb3586 100644
--- a/docs/sphinx-docs/source/conf.py
+++ b/docs/sphinx-docs/source/conf.py
@@ -1,293 +1,311 @@
-# -*- coding: utf-8 -*-
-#
-# SasView documentation build configuration file, created by
-# sphinx-quickstart on Wed Aug 28 14:59:44 2013.
-#
-# This file is execfile()d with the current directory set to its containing dir.
-#
-# Note that not all possible configuration values are present in this
-# autogenerated file.
-#
-# All configuration values have a default; values that are commented out
-# serve to show the default.
-
-import sys, os, collections
-
-# If extensions (or modules to document with autodoc) are in another directory,
-# add these directories to sys.path here. If the directory is relative to the
-# documentation root, use os.path.abspath to make it absolute, like shown here.
-from distutils.util import get_platform
-platform = '.%s-%s'%(get_platform(),sys.version[:3])
-build_lib = os.path.abspath('../../../build/lib'+platform)
-sys.path.insert(0, build_lib)
-sys.path.insert(0, os.path.abspath('_extensions')) # for sphinx extensions
-print "-- path --"
-print "\n".join(sys.path)
-
-# -- General configuration -----------------------------------------------------
-
-# If your documentation needs a minimal Sphinx version, state it here.
-#needs_sphinx = '1.0'
-
-# Add any Sphinx extension module names here, as strings. They can be extensions
-# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
-extensions = ['sphinx.ext.autodoc',
- 'sphinx.ext.todo',
- 'sphinx.ext.coverage',
- 'sphinx.ext.mathjax',
- 'dollarmath',
- 'sphinx.ext.viewcode']
-
-#set mathjax path
-mathjax_path="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-MML-AM_CHTML"
-
-# Add any paths that contain templates here, relative to this directory.
-templates_path = ['_templates']
-
-# The suffix of source filenames.
-source_suffix = '.rst'
-
-# The encoding of source files.
-#source_encoding = 'utf-8-sig'
-
-# The master toctree document.
-master_doc = 'index'
-
-# General information about the project.
-project = u'SasView'
-copyright = u'2017, The SasView Project'
-
-# The version info for the project you're documenting, acts as replacement for
-# |version| and |release|, also used in various other places throughout the
-# built documents.
-#
-# The short X.Y version.
-version = '4.1'
-# The full version, including alpha/beta/rc tags.
-release = '4.1.2'
-
-# The language for content autogenerated by Sphinx. Refer to documentation
-# for a list of supported languages.
-#language = None
-
-# There are two options for replacing |today|: either, you set today to some
-# non-false value, then it is used:
-#today = ''
-# Else, today_fmt is used as the format for a strftime call.
-#today_fmt = '%B %d, %Y'
-
-# List of patterns, relative to source directory, that match files and
-# directories to ignore when looking for source files.
-#
-# PGP 2014/04/03: We have some code which doesn't get carried over to
-# the build directory. Exclude the appropriate *.rst files here so
-# that we don't get various "ImportError: No module named ___" when
-# running Sphinx.
-exclude_patterns = ["*sas.sasgui.perspectives.simulation.rst",
- "*sas.sascalc.pr.c_extensions.rst",
- "*sas.sascalc.realspace.rst",
- "*sas.sascalc.simulation.rst",
- "*sas.sasview.setup_exe.rst",
- "*sas.sasview.setup_mac.rst",
- "*sas.sasgui.guiframe.custom_pstats.rst", # pstats not in standard library on Ubuntu out of the box
- ]
-
-# The reST default role (used for this markup: `text`) to use for all documents.
-#default_role = None
-
-# If true, '()' will be appended to :func: etc. cross-reference text.
-#add_function_parentheses = True
-
-# If true, the current module name will be prepended to all description
-# unit titles (such as .. function::).
-#add_module_names = True
-
-# If true, sectionauthor and moduleauthor directives will be shown in the
-# output. They are ignored by default.
-#show_authors = False
-
-# The name of the Pygments (syntax highlighting) style to use.
-pygments_style = 'sphinx'
-
-# A list of ignored prefixes for module index sorting.
-#modindex_common_prefix = []
-
-# If true, keep warnings as "system message" paragraphs in the built documents.
-#keep_warnings = False
-
-
-# -- Options for HTML output ---------------------------------------------------
-
-# The theme to use for HTML and HTML Help pages. See the documentation for
-# a list of builtin themes.
-html_theme = 'default'
-
-# Theme options are theme-specific and customize the look and feel of a theme
-# further. For a list of options available for each theme, see the
-# documentation.
-#html_theme_options = {}
-
-# Add any paths that contain custom themes here, relative to this directory.
-#html_theme_path = []
-
-# The name for this set of Sphinx documents. If None, it defaults to
-# "<project> v<release> documentation".
-#html_title = None
-
-# A shorter title for the navigation bar. Default is the same as html_title.
-#html_short_title = None
-
-# The name of an image file (relative to this directory) to place at the top
-# of the sidebar.
-#html_logo = None
-
-# The name of an image file (within the static path) to use as favicon of the
-# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
-# pixels large.
-#html_favicon = None
-
-# Add any paths that contain custom static files (such as style sheets) here,
-# relative to this directory. They are copied after the builtin static files,
-# so a file named "default.css" will overwrite the builtin "default.css".
-html_static_path = ['_static']
-
-# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
-# using the given strftime format.
-#html_last_updated_fmt = '%b %d, %Y'
-
-# If true, SmartyPants will be used to convert quotes and dashes to
-# typographically correct entities.
-#html_use_smartypants = True
-
-# Custom sidebar templates, maps document names to template names.
-#html_sidebars = {}
-
-# Additional templates that should be rendered to pages, maps page names to
-# template names.
-#html_additional_pages = {}
-
-# If false, no module index is generated.
-#html_domain_indices = True
-
-# If false, no index is generated.
-#html_use_index = True
-
-# If true, the index is split into individual pages for each letter.
-#html_split_index = False
-
-# If true, links to the reST sources are added to the pages.
-#html_show_sourcelink = True
-
-# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
-#html_show_sphinx = True
-
-# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
-#html_show_copyright = True
-
-# If true, an OpenSearch description file will be output, and all pages will
-# contain a <link> tag referring to it. The value of this option must be the
-# base URL from which the finished HTML is served.
-#html_use_opensearch = ''
-
-# This is the file name suffix for HTML files (e.g. ".xhtml").
-#html_file_suffix = None
-
-# Output file base name for HTML help builder.
-htmlhelp_basename = 'SasViewdoc'
-
-# Turn off permalinks, which are a nice feature for the docs when viewed in a
-# browser, but which look weird (and cannot be "right-click->copy url") in
-# the SasView help.
-html_add_permalinks = ""
-
-
-# -- Options for LaTeX output --------------------------------------------------
-
-LATEX_PREAMBLE=r"""
-\renewcommand{\AA}{\text{\r{A}}} % Allow \AA in math mode
-\usepackage[utf8]{inputenc} % Allow unicode symbols in text
-\DeclareUnicodeCharacter {00B7} {\ensuremath{\cdot}} % cdot
-\DeclareUnicodeCharacter {00B0} {\ensuremath{^\circ}} % degrees
-\DeclareUnicodeCharacter {212B} {\AA} % Angstrom
-"""
-latex_elements = {
-# The paper size ('letterpaper' or 'a4paper').
-'papersize': 'a4paper',
-
-# The font size ('10pt', '11pt' or '12pt').
-#'pointsize': '10pt',
-
-# Additional stuff for the LaTeX preamble.
-'preamble': LATEX_PREAMBLE
-
-}
-
-# Grouping the document tree into LaTeX files. List of tuples
-# (source start file, target name, title, author, documentclass [howto/manual]).
-latex_documents = [
- ('index', 'SasView.tex', u'SasView Documentation',
- u'The SasView Project', 'manual'),
-]
-
-# The name of an image file (relative to this directory) to place at the top of
-# the title page.
-#latex_logo = None
-
-# For "manual" documents, if this is true, then toplevel headings are parts,
-# not chapters.
-#latex_use_parts = False
-
-# If true, show page references after internal links.
-#latex_show_pagerefs = False
-
-# If true, show URL addresses after external links.
-#latex_show_urls = False
-
-# Documents to append as an appendix to all manuals.
-#latex_appendices = []
-
-# If false, no module index is generated.
-#latex_domain_indices = True
-
-
-# -- Options for manual page output --------------------------------------------
-
-# One entry per manual page. List of tuples
-# (source start file, name, description, authors, manual section).
-man_pages = [
- ('index', 'sasview', u'SasView Documentation',
- [u'The SasView Project'], 1)
-]
-
-# If true, show URL addresses after external links.
-#man_show_urls = False
-
-
-# -- Options for Texinfo output ------------------------------------------------
-
-# Grouping the document tree into Texinfo files. List of tuples
-# (source start file, target name, title, author,
-# dir menu entry, description, category)
-texinfo_documents = [
- ('index', 'SasView', u'SasView Documentation',
- u'The SasView Project', 'SasView', 'One line description of project.',
- 'Miscellaneous'),
-]
-
-# Documents to append as an appendix to all manuals.
-#texinfo_appendices = []
-
-# If false, no module index is generated.
-#texinfo_domain_indices = True
-
-# How to display URL addresses: 'footnote', 'no', or 'inline'.
-#texinfo_show_urls = 'footnote'
-
-# If true, do not generate a @detailmenu in the "Top" node's menu.
-#texinfo_no_detailmenu = False
-
-if os.path.exists('rst_prolog'):
- with open('rst_prolog') as fid:
- rst_prolog = fid.read()
-
-numfig = True
+# -*- coding: utf-8 -*-
+#
+# SasView documentation build configuration file, created by
+# sphinx-quickstart on Wed Aug 28 14:59:44 2013.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys, os, collections
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+from distutils.util import get_platform
+platform = '.%s-%s'%(get_platform(),sys.version[:3])
+build_lib = os.path.abspath('../../../build/lib'+platform)
+sys.path.insert(0, build_lib)
+sys.path.insert(0, os.path.abspath('_extensions')) # for sphinx extensions
+print "-- path --"
+print "\n".join(sys.path)
+
+# -- General configuration -----------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = ['sphinx.ext.autodoc',
+ 'sphinx.ext.todo',
+ 'sphinx.ext.coverage',
+ 'sphinx.ext.mathjax',
+ #'mathjax', # replacement mathjax that allows a list of paths
+ 'dollarmath',
+ 'sphinx.ext.viewcode']
+
+mathjax_path = (
+ 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?'
+ 'config=TeX-MML-AM_CHTML')
+
+# For katex uncomment the following
+"""
+#STATIC_PATH = '../../_static/'
+STATIC_PATH = ''
+mathjax_path = [
+ STATIC_PATH + 'katex/katex.min.js',
+ STATIC_PATH + 'katex/contrib/auto-render.min.js',
+ STATIC_PATH + 'rendermath.js'
+]
+mathjax_css = STATIC_PATH + 'katex/katex.min.css'
+"""
+
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'SasView'
+copyright = u'2017, The SasView Project'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '4.2'
+# The full version, including alpha/beta/rc tags.
+release = '4.2.0'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+#
+# PGP 2014/04/03: We have some code which doesn't get carried over to
+# the build directory. Exclude the appropriate *.rst files here so
+# that we don't get various "ImportError: No module named ___" when
+# running Sphinx.
+exclude_patterns = ["*sas.sasgui.perspectives.simulation.rst",
+ "*sas.sascalc.pr.c_extensions.rst",
+ "*sas.sascalc.realspace.rst",
+ "*sas.sascalc.simulation.rst",
+ "*sas.sasview.setup_exe.rst",
+ "*sas.sasview.setup_mac.rst",
+ "*sas.sasgui.guiframe.custom_pstats.rst", # pstats not in standard library on Ubuntu out of the box
+ ]
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+# If true, keep warnings as "system message" paragraphs in the built documents.
+#keep_warnings = False
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+html_theme = 'default'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'SasViewdoc'
+
+# Turn off permalinks, which are a nice feature for the docs when viewed in a
+# browser, but which look weird (and cannot be "right-click->copy url") in
+# the SasView help.
+html_add_permalinks = ""
+
+
+# -- Options for LaTeX output --------------------------------------------------
+
+# TODO: seems like angstroms is defined twice.
+LATEX_PREAMBLE=r"""
+\usepackage[utf8]{inputenc} % Allow unicode symbols in text
+\newcommand{\lt}{<} % HTML needs \lt rather than <
+\newcommand{\gt}{>} % HTML needs \gt rather than >
+\renewcommand{\AA}{\text{\r{A}}} % Allow \AA in math mode
+\DeclareUnicodeCharacter {212B} {\AA} % Angstrom
+\DeclareUnicodeCharacter {00B7} {\ensuremath{\cdot}} % cdot
+\DeclareUnicodeCharacter {00B0} {\ensuremath{^\circ}} % degrees
+"""
+latex_elements = {
+# The paper size ('letterpaper' or 'a4paper').
+'papersize': 'a4paper',
+
+# The font size ('10pt', '11pt' or '12pt').
+#'pointsize': '10pt',
+
+# Additional stuff for the LaTeX preamble.
+'preamble': LATEX_PREAMBLE
+
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+ ('index', 'SasView.tex', u'SasView Documentation',
+ u'The SasView Project', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output --------------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+ ('index', 'sasview', u'SasView Documentation',
+ [u'The SasView Project'], 1)
+]
+
+# If true, show URL addresses after external links.
+#man_show_urls = False
+
+
+# -- Options for Texinfo output ------------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+# dir menu entry, description, category)
+texinfo_documents = [
+ ('index', 'SasView', u'SasView Documentation',
+ u'The SasView Project', 'SasView', 'One line description of project.',
+ 'Miscellaneous'),
+]
+
+# Documents to append as an appendix to all manuals.
+#texinfo_appendices = []
+
+# If false, no module index is generated.
+#texinfo_domain_indices = True
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#texinfo_show_urls = 'footnote'
+
+# If true, do not generate a @detailmenu in the "Top" node's menu.
+#texinfo_no_detailmenu = False
+
+if os.path.exists('rst_prolog'):
+ with open('rst_prolog') as fid:
+ rst_prolog = fid.read()
+
+numfig = True
\ No newline at end of file
diff --git a/docs/sphinx-docs/source/dev/dev.rst b/docs/sphinx-docs/source/dev/dev.rst
index dea7c32..3f6ded9 100644
--- a/docs/sphinx-docs/source/dev/dev.rst
+++ b/docs/sphinx-docs/source/dev/dev.rst
@@ -1,19 +1,21 @@
-Developer Documentation
-=======================
-
-.. note:: In Windows use [Alt]-[Cursor left] to return to the previous page
-
-Contents
---------
-
-.. toctree::
- :maxdepth: 1
-
- SasView API <api/modules>
-
-Indices and Search
-------------------
-
-* :ref:`genindex`
-* :ref:`modindex`
-* :ref:`search`
+Developer Documentation
+=======================
+
+.. note:: In Windows use [Alt]-[Cursor left] to return to the previous page
+
+Contents
+--------
+
+.. toctree::
+ :maxdepth: 1
+
+ SasView API <sasview-api/modules>
+ sasmodels overview <sasmodels-dev/index>
+ sasmodels API <sasmodels-api/modules>
+
+Indices and Search
+------------------
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
diff --git a/docs/sphinx-docs/source/rst_prolog b/docs/sphinx-docs/source/rst_prolog
index 098e6b0..f6e7abd 100644
--- a/docs/sphinx-docs/source/rst_prolog
+++ b/docs/sphinx-docs/source/rst_prolog
@@ -1,46 +1,5 @@
.. Set up some substitutions to make life easier...
-.. Remove |biggamma|, etc. when they are no longer needed.
-
-.. |alpha| unicode:: U+03B1
-.. |beta| unicode:: U+03B2
-.. |gamma| unicode:: U+03B3
-.. |delta| unicode:: U+03B4
-.. |epsilon| unicode:: U+03B5
-.. |zeta| unicode:: U+03B6
-.. |eta| unicode:: U+03B7
-.. |theta| unicode:: U+03B8
-.. |iota| unicode:: U+03B9
-.. |kappa| unicode:: U+03BA
-.. |lambda| unicode:: U+03BB
-.. |mu| unicode:: U+03BC
-.. |nu| unicode:: U+03BD
-.. |xi| unicode:: U+03BE
-.. |omicron| unicode:: U+03BF
-.. |pi| unicode:: U+03C0
-.. |rho| unicode:: U+03C1
-.. |sigma| unicode:: U+03C3
-.. |tau| unicode:: U+03C4
-.. |upsilon| unicode:: U+03C5
-.. |phi| unicode:: U+03C6
-.. |chi| unicode:: U+03C7
-.. |psi| unicode:: U+03C8
-.. |omega| unicode:: U+03C9
-
-
-.. |biggamma| unicode:: U+0393
-.. |bigdelta| unicode:: U+0394
-.. |bigzeta| unicode:: U+039E
-.. |bigpsi| unicode:: U+03A8
-.. |bigphi| unicode:: U+03A6
-.. |bigsigma| unicode:: U+03A3
-.. |Gamma| unicode:: U+0393
-.. |Delta| unicode:: U+0394
-.. |Zeta| unicode:: U+039E
-.. |Psi| unicode:: U+03A8
-
-
-.. |drho| replace:: |Delta|\ |rho|
.. |Ang| unicode:: U+212B
.. |Ang^-1| replace:: |Ang|\ :sup:`-1`
.. |Ang^2| replace:: |Ang|\ :sup:`2`
@@ -56,14 +15,6 @@
.. |1e15cm^3| replace:: 10\ :sup:`15`\ cm\ :sup:`3`
.. |cm^-3| replace:: cm\ :sup:`-3`
.. |sr^-1| replace:: sr\ :sup:`-1`
-.. |P0| replace:: P\ :sub:`0`\
-.. |A2| replace:: A\ :sub:`2`\
-
-
-.. |equiv| unicode:: U+2261
-.. |noteql| unicode:: U+2260
-.. |TM| unicode:: U+2122
-
.. |cdot| unicode:: U+00B7
.. |deg| unicode:: U+00B0
diff --git a/docs/sphinx-docs/source/user/analysis.rst b/docs/sphinx-docs/source/user/analysis.rst
index ce368cb..e8eaf49 100644
--- a/docs/sphinx-docs/source/user/analysis.rst
+++ b/docs/sphinx-docs/source/user/analysis.rst
@@ -1,17 +1,17 @@
-.. _analysis:
-
-Fitting & Other Analyses
-========================
-
-.. note:: In Windows use [Alt]-[Cursor left] to return to the previous page
-
-.. toctree::
- :maxdepth: 1
-
- Model Fitting <sasgui/perspectives/fitting/fitting>
-
- P(r) Inversion <sasgui/perspectives/pr/pr_help>
-
- Invariant Calculation <sasgui/perspectives/invariant/invariant_help>
-
- Correlation Function <sasgui/perspectives/corfunc/corfunc_help>
+.. _analysis:
+
+Fitting & Other Analyses
+========================
+
+.. note:: In Windows use [Alt]-[Cursor left] to return to the previous page
+
+.. toctree::
+ :maxdepth: 1
+
+ Model Fitting <sasgui/perspectives/fitting/fitting>
+
+ P(r) Inversion <sasgui/perspectives/pr/pr_help>
+
+ Invariant Calculation <sasgui/perspectives/invariant/invariant_help>
+
+ Correlation Function <sasgui/perspectives/corfunc/corfunc_help>
diff --git a/docs/sphinx-docs/source/user/marketplace.rst b/docs/sphinx-docs/source/user/marketplace.rst
index 6f7a5ba..81bff29 100644
--- a/docs/sphinx-docs/source/user/marketplace.rst
+++ b/docs/sphinx-docs/source/user/marketplace.rst
@@ -1,15 +1,27 @@
-.. _marketplace:
-
-Model Marketplace
-=================
-The Model Marketplace allows members of the SAS Community to contribute plug-in fitting models for *SasView* for all to use.
-
-.. note:: These plug-in models require SasView version 4.0 or later.
-
-Contributed models should be written in Python (only version 2.7.x is currently supported) or, if computational speed is an issue, in a combination of Python and C. You only need to upload the .py/.c source code files to the Marketplace!
-
-For guidance on how to write a plugin model see :ref:`Writing_a_Plugin` . It may also be helpful to examine the library models in the */sasmodels-data/models* sub-folder of your SasView installation directory.
-
-The Marketplace also provides the option to upload a SasView text file of the scattering function data computed by your model. If you do this a graph of the scattering function will appear under the Marketplace entry for your model.
-
-.. note:: The SasView Development Team regret to say that they do not have the resources to fix the bugs or polish the code in every model contributed to the Marketplace!
\ No newline at end of file
+.. _marketplace:
+
+Model Marketplace
+=================
+The Model Marketplace allows members of the SAS Community to contribute
+plug-in fitting models for *SasView* for all to use.
+
+.. note:: These plug-in models require SasView version 4.0 or later.
+
+Contributed models should be written in Python (only version 2.7.x is
+currently supported) or, if computational speed is an issue, in a
+combination of Python and C. You only need to upload the .py/.c source
+code files to the Marketplace!
+
+For guidance on how to write a plugin model see :ref:`Writing_a_Plugin` . It
+may also be helpful to examine the library models in
+the */sasmodels-data/models* sub-folder of your SasView installation directory.
+
+The Marketplace also provides the option to upload a SasView text file of
+the scattering function data computed by your model. If you do this a graph
+of the scattering function will appear under the Marketplace entry for
+your model.
+
+.. note::
+ The SasView Development Team regret to say that they do not have the
+ resources to fix the bugs or polish the code in every model contributed
+ to the Marketplace!
diff --git a/docs/sphinx-docs/source/user/menu_bar.rst b/docs/sphinx-docs/source/user/menu_bar.rst
index f9ceda3..12c2af1 100644
--- a/docs/sphinx-docs/source/user/menu_bar.rst
+++ b/docs/sphinx-docs/source/user/menu_bar.rst
@@ -1,85 +1,85 @@
-.. _menu_bar:
-
-Menu Bar
-========
-The menu bar at the top of the *SasView* window gives you access to additional features of the program:
-
-File
-----
-The File option allows you load data into *SasView* for analysis, or to save the work you have been doing.
-
-Data can be loaded one file at a time, or by selecting multiple files, or by loading an entire folder of
-files (in which case *SasView* will attempt to make an intelligent guess as to what to load based on the
-file formats it recognises in the folder!).
-
-A *SasView* session can also be saved and reloaded as an 'Analysis' (an individual model fit or invariant
-calculation, etc), or as a 'Project' (everything you have done since starting your *SasView* session).
-
-Edit
-----
-The Edit option allows you to:
-
-- undo/redo your recent changes;
-- copy and paste parameters between *SasView* analysis windows;
-- copy parameters from a *SasView* analysis window to the Clipboard as either tab-delimited text (compatible with Microsoft Excel) or LaTex-wrapped text;
-- generate a summary 'Report' of the most recent analysis performed;
-- reset parameter values in the P(r) Inversion analysis page.
-
-View
-----
-The View option allows you to:
-
-- show the Batch Fitting Results Panel if it has been closed;
-- show/hide the Data Explorer Panel;
-- show/hide the Toolbar of icons below the Menu Bar;
-- select the default location that *SasView* looks in for data to analyse (the *SasView* installation directory, the initial default, or a custom folder). NB: any change only takes effect when *SasView* is restarted;
-- change the default assignment of categories (*Shapes*\, *Shape-independent*\, *Structure Factor*\) for fitting model functions.
-
-Tools
------
-The Tools option provides access to a comprehensive range of tools and utilities. See :ref:`tools` for more information.
-
-Window
-------
-The Window option allows you to select which *SasView* windows are visible.
-
-Analysis
---------
-The Analysis option provides access to the key functionality of *SasView*:
-
-- Model Fitting;
-- P(r) Inversion;
-- Invariant Analysis;
-- Correlation Function Analysis (*SasView* 4.1 and later)
-
-See :ref:`analysis` for more information.
-
-Fitting
--------
-The Fitting option allows you to:
-
-- create a new FitPage;
-- change optimiser (under Fit Options);
-- view fit parameter correlations, distributions, and convergence traces (under Fit Results);
-- create/edit a Plugin Model.
-
-Additional functionality is available under this menu option during particular types of model fitting, including:
-
-- setting up a Constrained or Simultaneous Fit;
-- combining a Batch Fit (an obscure capability);
-- setting up Chain Fitting.
-
-Help
-----
-The Help option provides access to:
-
-- this help documentation;
-- a :ref:`tutorial` on using *SasView* (in pdf format);
-- information on how to acknowledge *SasView* in publications;
-- information about the version of *SasView* you are using;
-- the :ref:`marketplace`\ ;
-- a check to see if there is a more recent version of *SasView*.
-
-.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
-
-.. note:: This help document was last changed by Steve King, 10Oct2016
+.. _menu_bar:
+
+Menu Bar
+========
+The menu bar at the top of the *SasView* window gives you access to additional features of the program:
+
+File
+----
+The File option allows you load data into *SasView* for analysis, or to save the work you have been doing.
+
+Data can be loaded one file at a time, or by selecting multiple files, or by loading an entire folder of
+files (in which case *SasView* will attempt to make an intelligent guess as to what to load based on the
+file formats it recognises in the folder!).
+
+A *SasView* session can also be saved and reloaded as an 'Analysis' (an individual model fit or invariant
+calculation, etc), or as a 'Project' (everything you have done since starting your *SasView* session).
+
+Edit
+----
+The Edit option allows you to:
+
+- undo/redo your recent changes;
+- copy and paste parameters between *SasView* analysis windows;
+- copy parameters from a *SasView* analysis window to the Clipboard as either tab-delimited text (compatible with Microsoft Excel) or LaTex-wrapped text;
+- generate a summary 'Report' of the most recent analysis performed;
+- reset parameter values in the P(r) Inversion analysis page.
+
+View
+----
+The View option allows you to:
+
+- show the Batch Fitting Results Panel if it has been closed;
+- show/hide the Data Explorer Panel;
+- show/hide the Toolbar of icons below the Menu Bar;
+- select the default location that *SasView* looks in for data to analyse (the *SasView* installation directory, the initial default, or a custom folder). NB: any change only takes effect when *SasView* is restarted;
+- change the default assignment of categories (*Shapes*\, *Shape-independent*\, *Structure Factor*\) for fitting model functions.
+
+Tools
+-----
+The Tools option provides access to a comprehensive range of tools and utilities. See :ref:`tools` for more information.
+
+Window
+------
+The Window option allows you to select which *SasView* windows are visible.
+
+Analysis
+--------
+The Analysis option provides access to the key functionality of *SasView*:
+
+- Model Fitting;
+- P(r) Inversion;
+- Invariant Analysis;
+- Correlation Function Analysis (*SasView* 4.1 and later)
+
+See :ref:`analysis` for more information.
+
+Fitting
+-------
+The Fitting option allows you to:
+
+- create a new FitPage;
+- change optimiser (under Fit Options);
+- view fit parameter correlations, distributions, and convergence traces (under Fit Results);
+- create/edit a Plugin Model.
+
+Additional functionality is available under this menu option during particular types of model fitting, including:
+
+- setting up a Constrained or Simultaneous Fit;
+- combining a Batch Fit (an obscure capability);
+- setting up Chain Fitting.
+
+Help
+----
+The Help option provides access to:
+
+- this help documentation;
+- a :ref:`tutorial` on using *SasView* (in pdf format);
+- information on how to acknowledge *SasView* in publications;
+- information about the version of *SasView* you are using;
+- the :ref:`marketplace`\ ;
+- a check to see if there is a more recent version of *SasView*.
+
+.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
+
+.. note:: This help document was last changed by Steve King, 10Oct2016
diff --git a/docs/sphinx-docs/source/user/tools.rst b/docs/sphinx-docs/source/user/tools.rst
index 5424a3d..a983c36 100644
--- a/docs/sphinx-docs/source/user/tools.rst
+++ b/docs/sphinx-docs/source/user/tools.rst
@@ -1,30 +1,30 @@
-.. _tools:
-
-Tools & Utilities
-=================
-
-.. note:: In Windows use [Alt]-[Cursor left] to return to the previous page
-
-.. toctree::
- :maxdepth: 1
-
- Data Operations Utility <sasgui/perspectives/calculator/data_operator_help>
-
- SLD Calculator <sasgui/perspectives/calculator/sld_calculator_help>
-
- Density/Volume Calculator <sasgui/perspectives/calculator/density_calculator_help>
-
- Slit Size Calculator <sasgui/perspectives/calculator/slit_calculator_help>
-
- Kiessig Thickness Calculator <sasgui/perspectives/calculator/kiessig_calculator_help>
-
- Q Resolution Estimator <sasgui/perspectives/calculator/resolution_calculator_help>
-
- Generic SANS Calculator <sasgui/perspectives/calculator/sas_calculator_help>
-
- Python Shell <sasgui/perspectives/calculator/python_shell_help>
-
- Image Viewer <sasgui/perspectives/calculator/image_viewer_help>
-
- File Converter <sasgui/perspectives/file_converter/file_converter_help>
+.. _tools:
+
+Tools & Utilities
+=================
+
+.. note:: In Windows use [Alt]-[Cursor left] to return to the previous page
+
+.. toctree::
+ :maxdepth: 1
+
+ Data Operations Utility <sasgui/perspectives/calculator/data_operator_help>
+
+ SLD Calculator <sasgui/perspectives/calculator/sld_calculator_help>
+
+ Density/Volume Calculator <sasgui/perspectives/calculator/density_calculator_help>
+
+ Slit Size Calculator <sasgui/perspectives/calculator/slit_calculator_help>
+
+ Kiessig Thickness Calculator <sasgui/perspectives/calculator/kiessig_calculator_help>
+
+ Q Resolution Estimator <sasgui/perspectives/calculator/resolution_calculator_help>
+
+ Generic SANS Calculator <sasgui/perspectives/calculator/sas_calculator_help>
+
+ Python Shell <sasgui/perspectives/calculator/python_shell_help>
+
+ Image Viewer <sasgui/perspectives/calculator/image_viewer_help>
+
+ File Converter <sasgui/perspectives/file_converter/file_converter_help>
\ No newline at end of file
diff --git a/docs/sphinx-docs/source/user/tutorial.rst b/docs/sphinx-docs/source/user/tutorial.rst
index fafa3a6..3046bc1 100644
--- a/docs/sphinx-docs/source/user/tutorial.rst
+++ b/docs/sphinx-docs/source/user/tutorial.rst
@@ -7,6 +7,6 @@ Tutorials
.. note:: In Windows use [Alt]-[Cursor left] to return to the previous page
-:download:`Getting Started with Sasview <../../../../sasview/media/getting_started_with_sasview.pdf>`
+:download:`Getting Started with Sasview <sasview/getting_started_with_sasview.pdf>`
-:download:`Old Tutorial <../../../../sasview/media/Tutorial.pdf>`
+:download:`Old Tutorial <sasview/Tutorial.pdf>`
diff --git a/docs/sphinx-docs/source/user/user.rst b/docs/sphinx-docs/source/user/user.rst
index eab9e5c..dea35cb 100644
--- a/docs/sphinx-docs/source/user/user.rst
+++ b/docs/sphinx-docs/source/user/user.rst
@@ -1,17 +1,17 @@
-SasView User Documentation
-==========================
-
-.. note:: In Windows use [Alt]-[Cursor left] to return to the previous page
-
-.. toctree::
- :maxdepth: 1
-
- Model Documentation <index>
-
- Menu Bar <menu_bar>
-
- Fitting & Other Analyses <analysis>
-
- Tools & Utilities <tools>
-
- Working with SasView <working>
+SasView User Documentation
+==========================
+
+.. note:: In Windows use [Alt]-[Cursor left] to return to the previous page
+
+.. toctree::
+ :maxdepth: 1
+
+ Model Documentation <sasgui/perspectives/fitting/models/index>
+
+ Menu Bar <menu_bar>
+
+ Fitting & Other Analyses <analysis>
+
+ Tools & Utilities <tools>
+
+ Working with SasView <working>
diff --git a/docs/sphinx-docs/source/user/working.rst b/docs/sphinx-docs/source/user/working.rst
index aa06224..5723ed3 100644
--- a/docs/sphinx-docs/source/user/working.rst
+++ b/docs/sphinx-docs/source/user/working.rst
@@ -7,16 +7,15 @@ Working with SasView
:maxdepth: 1
Data Formats <sasgui/guiframe/data_formats_help>
-
+
Loading Data <sasgui/guiframe/data_explorer_help>
-
+
Plotting Data/Models <sasgui/guiframe/graph_help>
-
- Test Data <../test/testdata_help.rst>
-
- Tutorials <tutorial.rst>
-
- Writing a Plugin Model <sasgui/perspectives/fitting/plugin.rst>
-
- Computations with a GPU <gpu_computations>
-
\ No newline at end of file
+
+ Test Data <sasview/test/testdata_help>
+
+ Tutorials <tutorial>
+
+ Writing a Plugin Model <sasgui/perspectives/fitting/plugin>
+
+ Model marketplace <marketplace>
\ No newline at end of file
diff --git a/sasview/MANIFEST.IN b/installers/MANIFEST.IN
similarity index 100%
rename from sasview/MANIFEST.IN
rename to installers/MANIFEST.IN
diff --git a/sasview/README-next-release.txt b/installers/README-next-release.txt
similarity index 100%
rename from sasview/README-next-release.txt
rename to installers/README-next-release.txt
diff --git a/sasview/README.txt b/installers/README.txt
similarity index 100%
rename from sasview/README.txt
rename to installers/README.txt
diff --git a/sasview/installer_generator.py b/installers/installer_generator.py
similarity index 85%
rename from sasview/installer_generator.py
rename to installers/installer_generator.py
index c1ad99a..fb88943 100644
--- a/sasview/installer_generator.py
+++ b/installers/installer_generator.py
@@ -1,370 +1,375 @@
-"""
-This module generates .iss file according to the local config of
-the current application. Please make sure a file named "local_config.py"
-exists in the current directory. Edit local_config.py according to your needs.
-"""
-import local_config
-import os
-import string
-
-REG_PROGRAM = """{app}\MYPROG.EXE"" ""%1"""
-APPLICATION = str(local_config.__appname__ )+ '.exe'
-AppName = str(local_config.__appname__ )
-AppVerName = str(local_config.__appname__ )+'-'+ str(local_config.__version__)
-Dev = ''
-if AppVerName.lower().count('dev') > 0:
- Dev = '-Dev'
-AppPublisher = local_config._copyright
-AppPublisherURL = local_config._homepage
-AppSupportURL = local_config._homepage
-AppUpdatesURL = local_config._homepage
-ChangesEnvironment = 'true'
-DefaultDirName = os.path.join("{pf}" , AppName+Dev)
-DefaultGroupName = os.path.join(local_config.DefaultGroupName, AppVerName)
-
-OutputBaseFilename = local_config.OutputBaseFilename
-SetupIconFile = "images\\ball.ico"
-LicenseFile = 'license.txt'
-DisableProgramGroupPage = 'yes'
-Compression = 'lzma'
-SolidCompression = 'yes'
-PrivilegesRequired = 'none'
-INSTALLER_FILE = 'installer'
-
-icon_path = local_config.icon_path
-media_path = local_config.media_path
-test_path = local_config.test_path
-
-def find_extension():
- """
- Describe the extensions that can be read by the current application
- """
- list_data = []
- list_app =[]
- try:
-
- #(ext, type, name, flags)
- from sas.sascalc.dataloader.loader import Loader
- wild_cards = Loader().get_wildcards()
- for item in wild_cards:
- #['All (*.*)|*.*']
- file_type, ext = string.split(item, "|*", 1)
- if ext.strip() not in ['.*', ''] and ext.strip() not in list_data:
- list_data.append((ext, 'string', file_type))
- except:
- pass
- try:
- file_type, ext = string.split(local_config.APPLICATION_WLIST, "|*", 1)
- if ext.strip() not in ['.', ''] and ext.strip() not in list_app:
- list_app.append((ext, 'string', file_type))
- except:
- pass
- try:
- for item in local_config.PLUGINS_WLIST:
- file_type, ext = string.split(item, "|*", 1)
- if ext.strip() not in ['.', ''] and ext.strip() not in list_app:
- list_app.append((ext, 'string', file_type))
- except:
- pass
- return list_data, list_app
-DATA_EXTENSION, APP_EXTENSION = find_extension()
-
-def write_registry(data_extension=None, app_extension=None):
- """
- create file association for windows.
- Allow open file on double click
- """
- msg = ""
- if data_extension is not None and data_extension:
- openwithlist = "OpenWithList\%s" % str(APPLICATION)
- msg = "\n\n[Registry]\n"
- for (ext, type, _) in data_extension:
- list = os.path.join(ext, openwithlist)
- msg += """Root: HKCR;\tSubkey: "%s";\t""" % str(list)
- msg += """ Flags: %s""" % str('uninsdeletekey noerror')
- msg += "\n"
- #list the file on right-click
- msg += """Root: HKCR; Subkey: "applications\%s\shell\open\command";\t"""\
- % str(APPLICATION)
- msg += """ValueType: %s; """ % str('string')
- msg += """ValueName: "%s";\t""" %str('')
- msg += """ValueData: \"""{app}\%s"" ""%s1\"""; \t"""% (str(APPLICATION),
- str('%'))
- msg += """ Flags: %s""" % str('uninsdeletevalue noerror')
- msg += "\n"
- user_list = "Software\Classes"
- for (ext, type, _) in data_extension:
- list = os.path.join(user_list, ext, openwithlist)
- msg += """Root: HKCU;\tSubkey: "%s";\t""" % str(list)
- msg += """ Flags: %s""" % str('uninsdeletekey noerror')
- msg += "\n"
- #list the file on right-click
- user_list = os.path.join("Software", "Classes", "applications")
- msg += """Root: HKCU; Subkey: "%s\%s\shell\open\command";\t"""\
- % (str(user_list), str(APPLICATION))
- msg += """ValueType: %s; """ % str('string')
- msg += """ValueName: "%s";\t""" %str('')
- msg += """ValueData: \"""{app}\%s"" ""%s1\"""; \t"""% (str(APPLICATION),
- str('%'))
- msg += """ Flags: %s""" % str('uninsdeletevalue noerror')
- msg += "\n"
- if app_extension is not None and app_extension:
- for (ext, type, _) in app_extension:
- msg += """Root: HKCR;\tSubkey: "%s";\t""" % str(ext)
- msg += """ValueType: %s;\t""" % str(type)
- #file type empty set the current application as the default
- #reader for this file. change the value of file_type to another
- #string modify the default reader
- file_type = ''
- msg += """ValueName: "%s";\t""" % str('')
- msg += """ValueData: "{app}\%s";\t""" % str(APPLICATION)
- msg += """ Flags: %s""" % str('uninsdeletevalue noerror')
- msg += "\n"
- msg += """Root: HKCR; Subkey: "{app}\%s";\t""" % str(APPLICATION)
- msg += """ValueType: %s; """ % str('string')
- msg += """ValueName: "%s";\t""" % str('')
- msg += """ValueData: "{app}\%s";\t""" % str("SasView File")
- msg += """ Flags: %s \t""" % str("uninsdeletekey noerror")
- msg += "\n"
-
- #execute the file on double-click
- msg += """Root: HKCR; Subkey: "{app}\%s\shell\open\command";\t""" % str(APPLICATION)
- msg += """ValueType: %s; """ % str('string')
- msg += """ValueName: "%s";\t""" %str('')
- msg += """ValueData: \"""{app}\%s"" ""%s1\""";\t"""% (str(APPLICATION),
- str('%'))
- msg += """ Flags: %s \t""" % str("uninsdeletevalue noerror")
- msg += "\n"
- #create default icon
- msg += """Root: HKCR; Subkey: "{app}\%s";\t""" % str(SetupIconFile)
- msg += """ValueType: %s; """ % str('string')
- msg += """ValueName: "%s";\t""" % str('')
- msg += """ValueData: "{app}\%s,0";\t""" % str(APPLICATION)
- msg += """ Flags: %s \t""" % str("uninsdeletevalue noerror")
- msg += "\n"
-
-
- #SASVIEWPATH
- msg += """Root: HKLM; Subkey: "%s";\t""" % str('SYSTEM\CurrentControlSet\Control\Session Manager\Environment')
- msg += """ValueType: %s; """ % str('expandsz')
- msg += """ValueName: "%s";\t""" % str('SASVIEWPATH')
- msg += """ValueData: "{app}";\t"""
- msg += """ Flags: %s""" % str('uninsdeletevalue noerror')
- msg += "\n"
-
- #PATH
- msg += """; Write to PATH (below) is disabled; need more tests\n"""
- msg += """;Root: HKCU; Subkey: "%s";\t""" % str('Environment')
- msg += """ValueType: %s; """ % str('expandsz')
- msg += """ValueName: "%s";\t""" % str('PATH')
- msg += """ValueData: "%s;{olddata}";\t""" % str('%SASVIEWPATH%')
- msg += """ Check: %s""" % str('NeedsAddPath()')
- msg += "\n"
-
- return msg
-
-def write_language(language=['english'], msfile="compiler:Default.isl"):
- """
- define the language of the application
- """
- msg = ''
- if language:
- msg = "\n\n[Languages]\n"
- for lang in language:
- msg += """Name: "%s";\tMessagesFile: "%s"\n""" % (str(lang),
- str(msfile))
- return msg
-
-def write_tasks():
- """
- create desktop icon
- """
- msg = """\n\n[Tasks]\n"""
- msg += """Name: "desktopicon";\tDescription: "{cm:CreateDesktopIcon}";\t"""
- msg += """GroupDescription: "{cm:AdditionalIcons}";\tFlags: unchecked\n"""
- msg += """Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}";\t"""
- msg += """GroupDescription: "{cm:AdditionalIcons}";\n"""
- return msg
-
-dist_path = "dist"
-def write_file():
- """
- copy some data files
- """
- msg = "\n\n[Files]\n"
- msg += """Source: "%s\%s";\t""" % (dist_path, str(APPLICATION))
- msg += """DestDir: "{app}";\tFlags: ignoreversion\n"""
- msg += """Source: "dist\*";\tDestDir: "{app}";\t"""
- msg += """Flags: ignoreversion recursesubdirs createallsubdirs\n"""
- msg += """Source: "dist\plugin_models\*";\tDestDir: "{userdesktop}\..\.sasview\plugin_models";\t"""
- msg += """Flags: recursesubdirs createallsubdirs\n"""
- msg += """Source: "dist\compiled_models\*";\tDestDir: "{userdesktop}\..\.sasmodels\compiled_models";\t"""
- msg += """Flags: recursesubdirs createallsubdirs\n"""
- msg += """Source: "dist\config\custom_config.py";\tDestDir: "{userdesktop}\..\.sasview\config";\t"""
- msg += """Flags: recursesubdirs createallsubdirs\n"""
- #msg += """Source: "dist\default_categories.json"; DestDir: "{userdesktop}\..\.sasview";\t"""
- #msg += """DestName: "categories.json";\n"""
- msg += """;\tNOTE: Don't use "Flags: ignoreversion" on any shared system files"""
- return msg
-
-def write_icon():
- """
- Create application icon
- """
- msg = """\n\n[Icons]\n"""
- msg += """Name: "{group}\%s";\t""" % str(AppName)
- msg += """Filename: "{app}\%s";\t""" % str(APPLICATION)
- msg += """WorkingDir: "{app}"; IconFilename: "{app}\images\\ball.ico" \n"""
- msg += """Name: "{group}\{cm:UninstallProgram, %s}";\t""" % str(AppName)
- msg += """ Filename: "{uninstallexe}" \n"""
- msg += """Name: "{commondesktop}\%s";\t""" % str(AppVerName)
- msg += """Filename: "{app}\%s";\t""" % str(APPLICATION)
- msg += """Tasks: desktopicon; WorkingDir: "{app}" ; IconFilename: "{app}\images\\ball.ico" \n"""
- msg += """Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\%s";\t""" % str(AppVerName)
- msg += """Filename: "{app}\%s";\t""" % str(APPLICATION)
- msg += """Tasks: quicklaunchicon; WorkingDir: "{app}"; IconFilename: "{app}\images\\ball.ico" \n"""
- return msg
-
-def write_run():
- """
- execute some file
- """
- msg = """\n\n[Run]\n"""
- msg += """Filename: "{app}\%s";\t""" % str(APPLICATION)
- msg += """Description: "{cm:LaunchProgram, %s}";\t""" %str(AppName)
- msg += """Flags: nowait postinstall skipifsilent\n"""
- msg += """; Install the Microsoft C++ DLL redistributable package if it is """
- msg += """provided and the DLLs are not present on the target system.\n"""
- msg += """; Note that the redistributable package is included if the app was """
- msg += """built using Python 2.6 or 2.7, but not with 2.5.\n"""
- msg += """; Parameter options:\n"""
- msg += """; - for silent install use: "/q"\n"""
- msg += """; - for silent install with progress bar use: "/qb"\n"""
- msg += """; - for silent install with progress bar but disallow """
- msg += """cancellation of operation use: "/qb!"\n"""
- msg += """; Note that we do not use the postinstall flag as this would """
- msg += """display a checkbox and thus require the user to decide what to do.\n"""
- msg += """;Filename: "{app}\\vcredist_x86.exe"; Parameters: "/qb!"; """
- msg += """WorkingDir: "{tmp}"; StatusMsg: "Installing Microsoft Visual """
- msg += """C++ 2008 Redistributable Package ..."; Check: InstallVC90CRT(); """
- msg += """Flags: skipifdoesntexist waituntilterminated\n"""
- return msg
-
-def write_dirs():
- """
- Define Dir permission
- """
- msg = """\n\n[Dirs]\n"""
- msg += """Name: "{app}\%s";\t""" % str('')
- msg += """Permissions: everyone-modify\t"""
- msg += """\n"""
- return msg
-
-def write_code():
- """
- Code that checks the existing path and snaviewpath
- in the environmental viriables/PATH
- """
- msg = """\n\n[Code]\n"""
- msg += """function InstallVC90CRT(): Boolean;\n"""
- msg += """begin\n"""
- msg += """ Result := not DirExists('C:\WINDOWS\WinSxS\\x86_Microsoft.VC90."""
- msg += """CRT_1fc8b3b9a1e18e3b_9.0.21022.8_x-ww_d08d0375');\n"""
- msg += """end;\n\n"""
- msg += """function NeedsAddPath(): boolean;\n"""
- msg += """var\n"""
- msg += """ oldpath: string;\n"""
- msg += """ newpath: string;\n"""
- msg += """ pathArr: TArrayOfString;\n"""
- msg += """ i: Integer;\n"""
- msg += """begin\n"""
- msg += """ RegQueryStringValue(HKEY_CURRENT_USER,'Environment',"""
- msg += """'PATH', oldpath)\n"""
- msg += """ oldpath := oldpath + ';';\n"""
- msg += """ newpath := '%SASVIEWPATH%';\n"""
- msg += """ i := 0;\n"""
- msg += """ while (Pos(';', oldpath) > 0) do begin\n"""
- msg += """ SetArrayLength(pathArr, i+1);\n"""
- msg += """ pathArr[i] := Copy(oldpath, 0, Pos(';', oldpath)-1);\n"""
- msg += """ oldpath := Copy(oldpath, Pos(';', oldpath)+1,"""
- msg += """ Length(oldpath));\n"""
- msg += """ i := i + 1;\n"""
- msg += """ // Check if current directory matches app dir\n"""
- msg += """ if newpath = pathArr[i-1] \n"""
- msg += """ then begin\n"""
- msg += """ Result := False;\n"""
- msg += """ exit;\n"""
- msg += """ end;\n"""
- msg += """ end;\n"""
- msg += """ Result := True;\n"""
- msg += """end;\n"""
- msg += """\n"""
- return msg
-
-def write_uninstalldelete():
- """
- Define uninstalldelete
- """
- msg = """\n[UninstallDelete]\n"""
- msg += """; Delete directories and files that are dynamically created by """
- msg += """the application (i.e. at runtime).\n"""
- msg += """Type: filesandordirs; Name: "{app}\.matplotlib"\n"""
- msg += """Type: files; Name: "{app}\*.*"\n"""
- msg += """; The following is a workaround for the case where the """
- msg += """application is installed and uninstalled but the\n"""
- msg += """;{app} directory is not deleted because it has user files. """
- msg += """Then the application is installed into the\n"""
- msg += """; existing directory, user files are deleted, and the """
- msg += """application is un-installed again. Without the\n"""
- msg += """; directive below, {app} will not be deleted because Inno Setup """
- msg += """did not create it during the previous\n"""
- msg += """; installation.\n"""
- msg += """Type: dirifempty; Name: "{app}"\n"""
- msg += """\n"""
- return msg
-
-def generate_installer():
- """
- """
- TEMPLATE = "\n; Script generated by the Inno Setup Script Wizard\n"
- TEMPLATE += "\n; and local_config.py located in this directory.\n "
- TEMPLATE += "; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!"
- TEMPLATE += "\n[Setup]\n\n"
- TEMPLATE += "ChangesAssociations=%s\n" %str('yes')
- TEMPLATE += "AppName=%s\n" % str(AppName)
- TEMPLATE += "AppVerName=%s\n" % str(AppVerName)
- TEMPLATE += "AppPublisher=%s\n" % str(AppPublisher)
- TEMPLATE += "AppPublisherURL=%s\n" % str(AppPublisherURL)
- TEMPLATE += "AppSupportURL=%s\n" % str(AppSupportURL)
- TEMPLATE += "AppUpdatesURL=%s \n" % str(AppUpdatesURL)
- TEMPLATE += "ChangesEnvironment=%s \n" % str(ChangesEnvironment)
- TEMPLATE += "DefaultDirName=%s\n" % str(DefaultDirName)
- TEMPLATE += "DefaultGroupName=%s\n" % str(DefaultGroupName)
- TEMPLATE += "DisableProgramGroupPage=%s\n" % str(DisableProgramGroupPage)
- TEMPLATE += "LicenseFile=%s\n" % str(LicenseFile)
- TEMPLATE += "OutputBaseFilename=%s\n" % str(OutputBaseFilename)
- TEMPLATE += "SetupIconFile=%s\n" % str(SetupIconFile)
- TEMPLATE += "Compression=%s\n" % str(Compression)
- TEMPLATE += "SolidCompression=%s\n" % str(SolidCompression)
- TEMPLATE += "PrivilegesRequired=%s\n" % str(PrivilegesRequired)
- TEMPLATE += "UsePreviousAppDir=no\n"
-
- TEMPLATE += write_registry(data_extension=DATA_EXTENSION,
- app_extension=APP_EXTENSION)
- TEMPLATE += write_language()
- TEMPLATE += write_tasks()
- TEMPLATE += write_file()
- TEMPLATE += write_icon()
- TEMPLATE += write_run()
- TEMPLATE += write_dirs()
- TEMPLATE += write_code()
- TEMPLATE += write_uninstalldelete()
- path = '%s.iss' % str(INSTALLER_FILE)
- f = open(path,'w')
- f.write(TEMPLATE)
- f.close()
- print "Generate Inno setup installer script complete"
- print "A new file %s.iss should be created.Please refresh your directory" % str(INSTALLER_FILE)
-
-if __name__ == "__main__":
- generate_installer()
+"""
+This module generates .iss file according to the local config of
+the current application. Please make sure a file named "local_config.py"
+exists in the current directory. Edit local_config.py according to your needs.
+"""
+from __future__ import print_function
+
+import os
+import sys
+import string
+
+root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+sys.path.insert(0, os.path.join(root, 'sasview-install', 'Lib', 'site-packages'))
+from sas.sasview import local_config
+
+#REG_PROGRAM = """{app}\MYPROG.EXE"" ""%1"""
+APPLICATION = str(local_config.__appname__ )+ '.exe'
+AppName = str(local_config.__appname__ )
+AppVerName = str(local_config.__appname__ )+'-'+ str(local_config.__version__)
+Dev = ''
+if AppVerName.lower().count('dev') > 0:
+ Dev = '-Dev'
+AppPublisher = local_config._copyright
+AppPublisherURL = local_config._homepage
+AppSupportURL = local_config._homepage
+AppUpdatesURL = local_config._homepage
+ChangesEnvironment = 'true'
+DefaultDirName = os.path.join("{pf}" , AppName+Dev)
+DefaultGroupName = os.path.join(local_config.DefaultGroupName, AppVerName)
+
+OutputBaseFilename = local_config.OutputBaseFilename
+SetupIconFile = local_config.SetupIconFile_win
+LicenseFile = 'license.txt'
+DisableProgramGroupPage = 'yes'
+Compression = 'lzma'
+SolidCompression = 'yes'
+PrivilegesRequired = 'none'
+INSTALLER_FILE = 'installer'
+
+icon_path = local_config.icon_path
+media_path = local_config.media_path
+test_path = local_config.test_path
+
+def find_extension():
+ """
+ Describe the extensions that can be read by the current application
+ """
+ list_data = []
+ list_app =[]
+ try:
+
+ #(ext, type, name, flags)
+ from sas.sascalc.dataloader.loader import Loader
+ wild_cards = Loader().get_wildcards()
+ for item in wild_cards:
+ #['All (*.*)|*.*']
+ file_type, ext = string.split(item, "|*", 1)
+ if ext.strip() not in ['.*', ''] and ext.strip() not in list_data:
+ list_data.append((ext, 'string', file_type))
+ except Exception:
+ pass
+ try:
+ file_type, ext = string.split(local_config.APPLICATION_WLIST, "|*", 1)
+ if ext.strip() not in ['.', ''] and ext.strip() not in list_app:
+ list_app.append((ext, 'string', file_type))
+ except Exception:
+ pass
+ try:
+ for item in local_config.PLUGINS_WLIST:
+ file_type, ext = string.split(item, "|*", 1)
+ if ext.strip() not in ['.', ''] and ext.strip() not in list_app:
+ list_app.append((ext, 'string', file_type))
+ except Exception:
+ pass
+ return list_data, list_app
+DATA_EXTENSION, APP_EXTENSION = find_extension()
+
+def write_registry(data_extension=None, app_extension=None):
+ """
+ create file association for windows.
+ Allow open file on double click
+ """
+ msg = ""
+ if data_extension is not None and data_extension:
+ openwithlist = "OpenWithList\%s" % str(APPLICATION)
+ msg = "\n\n[Registry]\n"
+ for (ext, type, _) in data_extension:
+ list = os.path.join(ext, openwithlist)
+ msg += """Root: HKCR;\tSubkey: "%s";\t""" % str(list)
+ msg += """ Flags: %s""" % str('uninsdeletekey noerror')
+ msg += "\n"
+ #list the file on right-click
+ msg += """Root: HKCR; Subkey: "applications\%s\shell\open\command";\t"""\
+ % str(APPLICATION)
+ msg += """ValueType: %s; """ % str('string')
+ msg += """ValueName: "%s";\t""" %str('')
+ msg += """ValueData: \"""{app}\%s"" ""%s1\"""; \t"""% (str(APPLICATION),
+ str('%'))
+ msg += """ Flags: %s""" % str('uninsdeletevalue noerror')
+ msg += "\n"
+ user_list = "Software\Classes"
+ for (ext, type, _) in data_extension:
+ list = os.path.join(user_list, ext, openwithlist)
+ msg += """Root: HKCU;\tSubkey: "%s";\t""" % str(list)
+ msg += """ Flags: %s""" % str('uninsdeletekey noerror')
+ msg += "\n"
+ #list the file on right-click
+ user_list = os.path.join("Software", "Classes", "applications")
+ msg += """Root: HKCU; Subkey: "%s\%s\shell\open\command";\t"""\
+ % (str(user_list), str(APPLICATION))
+ msg += """ValueType: %s; """ % str('string')
+ msg += """ValueName: "%s";\t""" %str('')
+ msg += """ValueData: \"""{app}\%s"" ""%s1\"""; \t"""% (str(APPLICATION),
+ str('%'))
+ msg += """ Flags: %s""" % str('uninsdeletevalue noerror')
+ msg += "\n"
+ if app_extension is not None and app_extension:
+ for (ext, type, _) in app_extension:
+ msg += """Root: HKCR;\tSubkey: "%s";\t""" % str(ext)
+ msg += """ValueType: %s;\t""" % str(type)
+ #file type empty set the current application as the default
+ #reader for this file. change the value of file_type to another
+ #string modify the default reader
+ file_type = ''
+ msg += """ValueName: "%s";\t""" % str('')
+ msg += """ValueData: "{app}\%s";\t""" % str(APPLICATION)
+ msg += """ Flags: %s""" % str('uninsdeletevalue noerror')
+ msg += "\n"
+ msg += """Root: HKCR; Subkey: "{app}\%s";\t""" % str(APPLICATION)
+ msg += """ValueType: %s; """ % str('string')
+ msg += """ValueName: "%s";\t""" % str('')
+ msg += """ValueData: "{app}\%s";\t""" % str("SasView File")
+ msg += """ Flags: %s \t""" % str("uninsdeletekey noerror")
+ msg += "\n"
+
+ #execute the file on double-click
+ msg += """Root: HKCR; Subkey: "{app}\%s\shell\open\command";\t""" % str(APPLICATION)
+ msg += """ValueType: %s; """ % str('string')
+ msg += """ValueName: "%s";\t""" %str('')
+ msg += """ValueData: \"""{app}\%s"" ""%s1\""";\t"""% (str(APPLICATION),
+ str('%'))
+ msg += """ Flags: %s \t""" % str("uninsdeletevalue noerror")
+ msg += "\n"
+ #create default icon
+ msg += """Root: HKCR; Subkey: "{app}\%s";\t""" % str(SetupIconFile)
+ msg += """ValueType: %s; """ % str('string')
+ msg += """ValueName: "%s";\t""" % str('')
+ msg += """ValueData: "{app}\%s,0";\t""" % str(APPLICATION)
+ msg += """ Flags: %s \t""" % str("uninsdeletevalue noerror")
+ msg += "\n"
+
+
+ #SASVIEWPATH
+ msg += """Root: HKLM; Subkey: "%s";\t""" % str('SYSTEM\CurrentControlSet\Control\Session Manager\Environment')
+ msg += """ValueType: %s; """ % str('expandsz')
+ msg += """ValueName: "%s";\t""" % str('SASVIEWPATH')
+ msg += """ValueData: "{app}";\t"""
+ msg += """ Flags: %s""" % str('uninsdeletevalue noerror')
+ msg += "\n"
+
+ #PATH
+ msg += """; Write to PATH (below) is disabled; need more tests\n"""
+ msg += """;Root: HKCU; Subkey: "%s";\t""" % str('Environment')
+ msg += """ValueType: %s; """ % str('expandsz')
+ msg += """ValueName: "%s";\t""" % str('PATH')
+ msg += """ValueData: "%s;{olddata}";\t""" % str('%SASVIEWPATH%')
+ msg += """ Check: %s""" % str('NeedsAddPath()')
+ msg += "\n"
+
+ return msg
+
+def write_languages(languages=('english',), msfile="compiler:Default.isl"):
+ """
+ define the language of the application
+ """
+ msg = ''
+ if languages:
+ msg = "\n\n[Languages]\n"
+ for lang in languages:
+ msg += """Name: "%s";\tMessagesFile: "%s"\n""" % (str(lang), str(msfile))
+ return msg
+
+def write_tasks():
+ """
+ create desktop icon
+ """
+ msg = """\n\n[Tasks]\n"""
+ msg += """Name: "desktopicon";\tDescription: "{cm:CreateDesktopIcon}";\t"""
+ msg += """GroupDescription: "{cm:AdditionalIcons}";\tFlags: unchecked\n"""
+ msg += """Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}";\t"""
+ msg += """GroupDescription: "{cm:AdditionalIcons}";\n"""
+ return msg
+
+dist_path = "dist"
+def write_file():
+ """
+ copy some data files
+ """
+ msg = "\n\n[Files]\n"
+ msg += """Source: "%s\%s";\t""" % (dist_path, str(APPLICATION))
+ msg += """DestDir: "{app}";\tFlags: ignoreversion\n"""
+ msg += """Source: "dist\*";\tDestDir: "{app}";\t"""
+ msg += """Flags: ignoreversion recursesubdirs createallsubdirs\n"""
+ msg += """Source: "dist\plugin_models\*";\tDestDir: "{userdesktop}\..\.sasview\plugin_models";\t"""
+ msg += """Flags: recursesubdirs createallsubdirs\n"""
+ msg += """Source: "dist\compiled_models\*";\tDestDir: "{userdesktop}\..\.sasmodels\compiled_models";\t"""
+ msg += """Flags: recursesubdirs createallsubdirs\n"""
+ msg += """Source: "dist\config\custom_config.py";\tDestDir: "{userdesktop}\..\.sasview\config";\t"""
+ msg += """Flags: recursesubdirs createallsubdirs\n"""
+ #msg += """Source: "dist\default_categories.json"; DestDir: "{userdesktop}\..\.sasview";\t"""
+ #msg += """DestName: "categories.json";\n"""
+ msg += """;\tNOTE: Don't use "Flags: ignoreversion" on any shared system files"""
+ return msg
+
+def write_icon():
+ """
+ Create application icon
+ """
+ msg = """\n\n[Icons]\n"""
+ msg += """Name: "{group}\%s";\t""" % str(AppName)
+ msg += """Filename: "{app}\%s";\t""" % str(APPLICATION)
+ msg += """WorkingDir: "{app}"; IconFilename: "{app}\images\\ball.ico" \n"""
+ msg += """Name: "{group}\{cm:UninstallProgram, %s}";\t""" % str(AppName)
+ msg += """ Filename: "{uninstallexe}" \n"""
+ msg += """Name: "{commondesktop}\%s";\t""" % str(AppVerName)
+ msg += """Filename: "{app}\%s";\t""" % str(APPLICATION)
+ msg += """Tasks: desktopicon; WorkingDir: "{app}" ; IconFilename: "{app}\images\\ball.ico" \n"""
+ msg += """Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\%s";\t""" % str(AppVerName)
+ msg += """Filename: "{app}\%s";\t""" % str(APPLICATION)
+ msg += """Tasks: quicklaunchicon; WorkingDir: "{app}"; IconFilename: "{app}\images\\ball.ico" \n"""
+ return msg
+
+def write_run():
+ """
+ execute some file
+ """
+ msg = """\n\n[Run]\n"""
+ msg += """Filename: "{app}\%s";\t""" % str(APPLICATION)
+ msg += """Description: "{cm:LaunchProgram, %s}";\t""" %str(AppName)
+ msg += """Flags: nowait postinstall skipifsilent\n"""
+ msg += """; Install the Microsoft C++ DLL redistributable package if it is """
+ msg += """provided and the DLLs are not present on the target system.\n"""
+ msg += """; Note that the redistributable package is included if the app was """
+ msg += """built using Python 2.6 or 2.7, but not with 2.5.\n"""
+ msg += """; Parameter options:\n"""
+ msg += """; - for silent install use: "/q"\n"""
+ msg += """; - for silent install with progress bar use: "/qb"\n"""
+ msg += """; - for silent install with progress bar but disallow """
+ msg += """cancellation of operation use: "/qb!"\n"""
+ msg += """; Note that we do not use the postinstall flag as this would """
+ msg += """display a checkbox and thus require the user to decide what to do.\n"""
+ msg += """;Filename: "{app}\\vcredist_x86.exe"; Parameters: "/qb!"; """
+ msg += """WorkingDir: "{tmp}"; StatusMsg: "Installing Microsoft Visual """
+ msg += """C++ 2008 Redistributable Package ..."; Check: InstallVC90CRT(); """
+ msg += """Flags: skipifdoesntexist waituntilterminated\n"""
+ return msg
+
+def write_dirs():
+ """
+ Define Dir permission
+ """
+ msg = """\n\n[Dirs]\n"""
+ msg += """Name: "{app}\%s";\t""" % str('')
+ msg += """Permissions: everyone-modify\t"""
+ msg += """\n"""
+ return msg
+
+def write_code():
+ """
+ Code that checks the existing path and snaviewpath
+ in the environmental viriables/PATH
+ """
+ msg = """\n\n[Code]\n"""
+ msg += """function InstallVC90CRT(): Boolean;\n"""
+ msg += """begin\n"""
+ msg += """ Result := not DirExists('C:\WINDOWS\WinSxS\\x86_Microsoft.VC90."""
+ msg += """CRT_1fc8b3b9a1e18e3b_9.0.21022.8_x-ww_d08d0375');\n"""
+ msg += """end;\n\n"""
+ msg += """function NeedsAddPath(): boolean;\n"""
+ msg += """var\n"""
+ msg += """ oldpath: string;\n"""
+ msg += """ newpath: string;\n"""
+ msg += """ pathArr: TArrayOfString;\n"""
+ msg += """ i: Integer;\n"""
+ msg += """begin\n"""
+ msg += """ RegQueryStringValue(HKEY_CURRENT_USER,'Environment',"""
+ msg += """'PATH', oldpath)\n"""
+ msg += """ oldpath := oldpath + ';';\n"""
+ msg += """ newpath := '%SASVIEWPATH%';\n"""
+ msg += """ i := 0;\n"""
+ msg += """ while (Pos(';', oldpath) > 0) do begin\n"""
+ msg += """ SetArrayLength(pathArr, i+1);\n"""
+ msg += """ pathArr[i] := Copy(oldpath, 0, Pos(';', oldpath)-1);\n"""
+ msg += """ oldpath := Copy(oldpath, Pos(';', oldpath)+1,"""
+ msg += """ Length(oldpath));\n"""
+ msg += """ i := i + 1;\n"""
+ msg += """ // Check if current directory matches app dir\n"""
+ msg += """ if newpath = pathArr[i-1] \n"""
+ msg += """ then begin\n"""
+ msg += """ Result := False;\n"""
+ msg += """ exit;\n"""
+ msg += """ end;\n"""
+ msg += """ end;\n"""
+ msg += """ Result := True;\n"""
+ msg += """end;\n"""
+ msg += """\n"""
+ return msg
+
+def write_uninstalldelete():
+ """
+ Define uninstalldelete
+ """
+ msg = """\n[UninstallDelete]\n"""
+ msg += """; Delete directories and files that are dynamically created by """
+ msg += """the application (i.e. at runtime).\n"""
+ msg += """Type: filesandordirs; Name: "{app}\.matplotlib"\n"""
+ msg += """Type: files; Name: "{app}\*.*"\n"""
+ msg += """; The following is a workaround for the case where the """
+ msg += """application is installed and uninstalled but the\n"""
+ msg += """;{app} directory is not deleted because it has user files. """
+ msg += """Then the application is installed into the\n"""
+ msg += """; existing directory, user files are deleted, and the """
+ msg += """application is un-installed again. Without the\n"""
+ msg += """; directive below, {app} will not be deleted because Inno Setup """
+ msg += """did not create it during the previous\n"""
+ msg += """; installation.\n"""
+ msg += """Type: dirifempty; Name: "{app}"\n"""
+ msg += """\n"""
+ return msg
+
+def generate_installer():
+ """
+ """
+ TEMPLATE = "\n; Script generated by the Inno Setup Script Wizard\n"
+ TEMPLATE += "\n; and local_config.py located in this directory.\n "
+ TEMPLATE += "; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!"
+ TEMPLATE += "\n[Setup]\n\n"
+ TEMPLATE += "ChangesAssociations=%s\n" %str('yes')
+ TEMPLATE += "AppName=%s\n" % str(AppName)
+ TEMPLATE += "AppVerName=%s\n" % str(AppVerName)
+ TEMPLATE += "AppPublisher=%s\n" % str(AppPublisher)
+ TEMPLATE += "AppPublisherURL=%s\n" % str(AppPublisherURL)
+ TEMPLATE += "AppSupportURL=%s\n" % str(AppSupportURL)
+ TEMPLATE += "AppUpdatesURL=%s \n" % str(AppUpdatesURL)
+ TEMPLATE += "ChangesEnvironment=%s \n" % str(ChangesEnvironment)
+ TEMPLATE += "DefaultDirName=%s\n" % str(DefaultDirName)
+ TEMPLATE += "DefaultGroupName=%s\n" % str(DefaultGroupName)
+ TEMPLATE += "DisableProgramGroupPage=%s\n" % str(DisableProgramGroupPage)
+ TEMPLATE += "LicenseFile=%s\n" % str(LicenseFile)
+ TEMPLATE += "OutputBaseFilename=%s\n" % str(OutputBaseFilename)
+ TEMPLATE += "SetupIconFile=%s\n" % str(SetupIconFile)
+ TEMPLATE += "Compression=%s\n" % str(Compression)
+ TEMPLATE += "SolidCompression=%s\n" % str(SolidCompression)
+ TEMPLATE += "PrivilegesRequired=%s\n" % str(PrivilegesRequired)
+ TEMPLATE += "UsePreviousAppDir=no\n"
+
+ TEMPLATE += write_registry(data_extension=DATA_EXTENSION,
+ app_extension=APP_EXTENSION)
+ TEMPLATE += write_languages()
+ TEMPLATE += write_tasks()
+ TEMPLATE += write_file()
+ TEMPLATE += write_icon()
+ TEMPLATE += write_run()
+ TEMPLATE += write_dirs()
+ TEMPLATE += write_code()
+ TEMPLATE += write_uninstalldelete()
+ path = '%s.iss' % str(INSTALLER_FILE)
+ f = open(path,'w')
+ f.write(TEMPLATE)
+ f.close()
+ print("Generate Inno setup installer script complete")
+ print("A new file %s.iss should be created.Please refresh your directory" % str(INSTALLER_FILE))
+
+if __name__ == "__main__":
+ generate_installer()
diff --git a/sasview/license.txt b/installers/license.txt
similarity index 100%
rename from sasview/license.txt
rename to installers/license.txt
diff --git a/installers/macholib_patch.py b/installers/macholib_patch.py
new file mode 100644
index 0000000..4398aff
--- /dev/null
+++ b/installers/macholib_patch.py
@@ -0,0 +1,27 @@
+"""
+MachOlib fix
+============
+
+Monkey-patch macholib to get around error in v1.7 and earlier, which
+gives::
+
+ TypeError: dyld_find() got an unexpected keyword argument 'loader'
+
+Add the following to the top of your setup_py2app to work around this::
+
+ import macholib_patch
+"""
+
+import macholib
+#print("~"*60 + "macholib verion: "+macholib.__version__)
+if macholib.__version__ <= "1.7":
+ print("Applying macholib patch...")
+ import macholib.dyld
+ import macholib.MachOGraph
+ dyld_find_1_7 = macholib.dyld.dyld_find
+ def dyld_find(name, loader=None, **kwargs):
+ #print("~"*60 + "calling alternate dyld_find")
+ if loader is not None:
+ kwargs['loader_path'] = loader
+ return dyld_find_1_7(name, **kwargs)
+ macholib.MachOGraph.dyld_find = dyld_find
diff --git a/sasview/sasview.spec b/installers/sasview.spec
similarity index 100%
rename from sasview/sasview.spec
rename to installers/sasview.spec
diff --git a/installers/sasview_console.py b/installers/sasview_console.py
new file mode 100644
index 0000000..472a665
--- /dev/null
+++ b/installers/sasview_console.py
@@ -0,0 +1,2 @@
+from sas.sasview.sasview import run_cli
+run_cli()
diff --git a/installers/sasview_gui.py b/installers/sasview_gui.py
new file mode 100644
index 0000000..05f6915
--- /dev/null
+++ b/installers/sasview_gui.py
@@ -0,0 +1,8 @@
+from sas.sasview.sasview import run_gui
+# force inclusion of readers in the distribution
+from sas.sascalc.dataloader.readers import (
+ abs_reader, anton_paar_saxs_reader, ascii_reader, cansas_reader_HDF5,
+ cansas_reader, danse_reader, red2d_reader, sesans_reader, tiff_reader,
+ xml_reader,
+)
+run_gui()
\ No newline at end of file
diff --git a/sasview/setup.cfg b/installers/setup.cfg
similarity index 100%
rename from sasview/setup.cfg
rename to installers/setup.cfg
diff --git a/sasview/setup_exe.py b/installers/setup_exe.py
old mode 100644
new mode 100755
similarity index 65%
rename from sasview/setup_exe.py
rename to installers/setup_exe.py
index 4b2f4d9..b40a1c4
--- a/sasview/setup_exe.py
+++ b/installers/setup_exe.py
@@ -2,41 +2,49 @@
#
# The setup to create a Windows executable.
-# Inno Setup can then be used with the installer.iss file
-# in the top source directory to create an installer.
+# Inno Setup can then be used with the installer.iss file
+# in the top source directory to create an installer.
#
# Setuptools clashes with py2exe 0.6.8 (and probably later too).
# For that reason, most of the code needs to have direct imports
-# that are not going through pkg_resources.
+# that are not going through pkg_resources.
#
# Attention should be paid to dynamic imports. Data files can
# be added to the distribution directory for that purpose.
# See for example the 'images' directory below.
+from __future__ import print_function
import os
import sys
-import warnings
from glob import glob
+import warnings
import shutil
from distutils.util import get_platform
from distutils.core import setup
from distutils.filelist import findall
from distutils.sysconfig import get_python_lib
-import py2exe
#from idlelib.PyShell import warning_stream
-# put the build directory at the front of the path
+# Need the installer dir on the python path to find helper modules
+installer_dir = os.path.abspath(os.path.dirname(__file__))
+if installer_dir != os.path.abspath(os.getcwd()):
+ raise RuntimeError("Must run setup_exe from the installers directory")
+sys.path.append(installer_dir)
+
+# Need the installer dir on the python path to find helper modules
if os.path.abspath(os.path.dirname(__file__)) != os.path.abspath(os.getcwd()):
- raise RuntimeError("Must run setup_exe from the sasview directory")
+ raise RuntimeError("Must run setup_exe from the installers directory")
+sys.path.append(installer_dir)
+
+# put the build directory at the front of the path
root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
platform = '%s-%s'%(get_platform(), sys.version[:3])
-build_path = os.path.join(root, 'build', 'lib.'+platform)
-#build_path = os.path.join(root, 'sasview-install', 'Lib', 'site-packages')
+doc_path = os.path.join(root, 'build', 'lib.'+platform, 'doc')
+build_path = os.path.join(root, 'sasview-install', 'Lib', 'site-packages')
sys.path.insert(0, build_path)
-import local_config
from installer_generator import generate_installer
import matplotlib
@@ -60,10 +68,12 @@ try:
sys.path.insert(0, extra_path)
del sys.argv[path_flag_idx+1]
sys.argv.remove('--extrapath')
-except:
- print "Error processing extra python path needed to build SasView\n %s" % \
- sys.exc_value
+except Exception:
+ print("Error processing extra python path needed to build SasView\n %s" %
+ sys.exc_value)
+from sas import get_local_config
+local_config = get_local_config()
# Solution taken from here: http://www.py2exe.org/index.cgi/win32com.shell
# ModuleFinder can't handle runtime changes to __path__, but win32com uses them
@@ -82,14 +92,13 @@ try:
for p in win32com.__path__[1:]:
modulefinder.AddPackagePath(win32_folder, p)
for extra in ["win32com.shell", "win32com.adsi", "win32com.axcontrol",
- "win32com.axscript", "win32com.bits", "win32com.ifilter",
- "win32com.internet", "win32com.mapi", "win32com.propsys",
- "win32com.taskscheduler"]:
-
- __import__(extra)
- m = sys.modules[extra]
- for p in m.__path__[1:]:
- modulefinder.AddPackagePath(extra, p)
+ "win32com.axscript", "win32com.bits", "win32com.ifilter",
+ "win32com.internet", "win32com.mapi", "win32com.propsys",
+ "win32com.taskscheduler"]:
+ __import__(extra)
+ m = sys.modules[extra]
+ for p in m.__path__[1:]:
+ modulefinder.AddPackagePath(extra, p)
except ImportError:
# no build path setup, no worries.
@@ -148,16 +157,6 @@ manifest = """
</assembly>
"""%{'arch': arch}
-if is_64bits:
- msvcrtdll = glob(r"C:\Program Files\Microsoft Visual Studio 9.0\VC\redist\x86\Microsoft.VC90.CRT\*.*")
-else:
- msvcrtdll = glob(r"C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\redist\x86\Microsoft.VC90.CRT\*.*")
-if msvcrtdll:
- msvcrtdll_data_files = ("Microsoft.VC90.CRT", msvcrtdll)
-else:
- msvcrtdll_data_files = None
-
-
class Target:
def __init__(self, **kw):
self.__dict__.update(kw)
@@ -166,51 +165,28 @@ class Target:
self.company_name = "SasView.org"
self.copyright = "copyright 2009 - 2016"
self.name = "SasView"
-
-#
-# Adapted from http://www.py2exe.org/index.cgi/MatPlotLib
-# to use the MatPlotLib.
-#
-path = os.getcwd()
-
-media_dir = os.path.join(path, "media")
-images_dir = os.path.join(path, "images")
-test_dir = os.path.join(path, "test")
-test_1d_dir = os.path.join(path, "test\\1d_data")
-test_2d_dir = os.path.join(path, "test\\2d_data")
-test_sesans_dir = os.path.join(path, "test\\sesans_data")
-test_convertible_dir = os.path.join(path, "test\\convertible_files")
-test_save_dir = os.path.join(path, "test\\save_states")
-test_coord_dir = os.path.join(path, "test\\coordinate_data")
-test_image_dir = os.path.join(path, "test\\image_data")
-test_other_dir = os.path.join(path, "test\\other_files")
-
-matplotlibdatadir = matplotlib.get_data_path()
-matplotlibdata = findall(matplotlibdatadir)
-
-site_loc = get_python_lib()
-opencl_include_dir = os.path.join(site_loc, "pyopencl", "cl")
data_files = []
if tinycc:
data_files += tinycc.data_files()
-# Copying SLD data
+# Include data for supporting packages
import periodictable
data_files += periodictable.data_files()
-import sas.sasgui.perspectives.fitting as fitting
-data_files += fitting.data_files()
-
-import sas.sasgui.perspectives.calculator as calculator
-data_files += calculator.data_files()
-
-import sas.sasgui.perspectives.invariant as invariant
-data_files += invariant.data_files()
+#
+# Adapted from http://www.py2exe.org/index.cgi/MatPlotLib
+# to use the MatPlotLib.
+#
+mpl_dir = matplotlib.get_data_path()
+for dirpath, dirnames, filenames in os.walk(mpl_dir):
+ target_dir = os.path.join("mpl-data", os.path.relpath(dirpath, mpl_dir))
+ source_files = [os.path.join(dirpath, f) for f in filenames]
+ data_files.append((target_dir, source_files))
-import sas.sasgui.guiframe as guiframe
-data_files += guiframe.data_files()
+import sasmodels
+data_files += sasmodels.data_files()
# precompile sas models into the sasview build path; doesn't matter too much
# where it is so long as it is a place that will get cleaned up afterwards.
@@ -222,97 +198,85 @@ compiled_dlls = sasmodels.core.precompile_dlls(dll_path, dtype='double')
# data with installer_generator.py
data_files.append(('compiled_models', compiled_dlls))
-import sasmodels
-data_files += sasmodels.data_files()
+# Data files for the different perspectives
+from sas.sasgui.perspectives import fitting
+data_files += fitting.data_files()
-for f in matplotlibdata:
- dirname = os.path.join('mpl-data', f[len(matplotlibdatadir)+1:])
- data_files.append((os.path.split(dirname)[0], [f]))
-
-# Copy the settings file for the sas.dataloader file extension associations
-import sas.sascalc.dataloader.readers
-f = os.path.join(sas.sascalc.dataloader.readers.get_data_path(), 'defaults.json')
-if os.path.isfile(f):
- data_files.append(('.', [f]))
-f = 'custom_config.py'
-if os.path.isfile(f):
- data_files.append(('.', [f]))
- data_files.append(('config', [f]))
-f = 'local_config.py'
-if os.path.isfile(f):
- data_files.append(('.', [f]))
-
-#f = 'default_categories.json'
-#if os.path.isfile(f):
-# data_files.append(('.', [f]))
-
-# numerical libraries
-def dll_check(dll_path, dlls):
- dll_includes = [os.path.join(dll_path, dll+'.dll') for dll in dlls]
- return [dll for dll in dll_includes if os.path.exists(dll)]
+from sas.sasgui.perspectives import calculator
+data_files += calculator.data_files()
-python_root = os.path.dirname(os.path.abspath(sys.executable))
-# Check for ATLAS
-dll_path = os.path.join(python_root, 'lib', 'site-packages', 'numpy', 'core')
-dlls = ['numpy-atlas']
-atlas_dlls = dll_check(dll_path, dlls)
+from sas.sasgui.perspectives import invariant
+data_files += invariant.data_files()
-# Check for MKL
-dll_path = os.path.join(python_root, 'Library', 'bin')
-dlls = ['mkl_core', 'mkl_def', 'libiomp5md']
-mkl_dlls = dll_check(dll_path, dlls)
+from sas.sasgui import guiframe
+data_files += guiframe.data_files()
-if atlas_dlls:
- data_files.append(('.', atlas_dlls))
-elif mkl_dlls:
- data_files.append(('.', mkl_dlls))
+# Copy the config files
+sasview_path = os.path.join('..', 'src', 'sas', 'sasview')
+data_files.append(('.', [os.path.join(sasview_path, 'custom_config.py')]))
+data_files.append(('config', [os.path.join(sasview_path, 'custom_config.py')]))
+data_files.append(('.', [os.path.join(sasview_path, 'local_config.py')]))
+
+# Copy the logging config
+sas_path = os.path.join('..', 'src', 'sas')
+data_files.append(('.', [os.path.join(sas_path, 'logging.ini')]))
if os.path.isfile("BUILD_NUMBER"):
data_files.append(('.', ["BUILD_NUMBER"]))
# Copying the images directory to the distribution directory.
-for f in findall(images_dir):
- data_files.append(("images", [f]))
+data_files.append(("images", findall(local_config.icon_path)))
# Copying the HTML help docs
-for f in findall(media_dir):
- data_files.append(("media", [f]))
+data_files.append(("media", findall(local_config.media_path)))
# Copying the sample data user data
-for f in findall(test_1d_dir):
- data_files.append(("test\\1d_data", [f]))
-for f in findall(test_2d_dir):
- data_files.append(("test\\2d_data", [f]))
-for f in findall(test_save_dir):
- data_files.append(("test\\save_states", [f]))
-for f in findall(test_sesans_dir):
- data_files.append(("test\\sesans_data", [f]))
-for f in findall(test_convertible_dir):
- data_files.append(("test\\convertible_files", [f]))
-for f in findall(test_coord_dir):
- data_files.append(("test\\coordinate_data", [f]))
-for f in findall(test_image_dir):
- data_files.append(("test\\image_data", [f]))
-for f in findall(test_other_dir):
- data_files.append(("test\\other_files", [f]))
-
-# Copying opencl include files
-for f in findall(opencl_include_dir):
- data_files.append(("includes\\pyopencl",[f]))
+test_dir = local_config.test_path
+for dirpath, dirnames, filenames in os.walk(test_dir):
+ target_dir = os.path.join("test", os.path.relpath(dirpath, test_dir))
+ source_files = [os.path.join(dirpath, f) for f in filenames]
+ data_files.append((target_dir, source_files))
# See if the documentation has been built, and if so include it.
-doc_path = os.path.join(build_path, "doc")
if os.path.exists(doc_path):
for dirpath, dirnames, filenames in os.walk(doc_path):
- for filename in filenames:
- sub_dir = os.path.join("doc", os.path.relpath(dirpath, doc_path))
- data_files.append((sub_dir, [os.path.join(dirpath, filename)]))
+ target_dir = os.path.join("doc", os.path.relpath(dirpath, doc_path))
+ source_files = [os.path.join(dirpath, f) for f in filenames]
+ data_files.append((target_dir, source_files))
else:
raise Exception("You must first build the documentation before creating an installer.")
-if msvcrtdll_data_files is not None:
+# Copying opencl include files
+opencl_source = os.path.join(get_python_lib(), "pyopencl", "cl")
+opencl_target = os.path.join("includes", "pyopencl")
+data_files.append((opencl_target, findall(opencl_source)))
+
+# Numerical libraries
+python_root = os.path.dirname(os.path.abspath(sys.executable))
+def dll_check(dll_path, dlls):
+ dll_includes = [os.path.join(dll_path, dll+'.dll') for dll in dlls]
+ return [dll for dll in dll_includes if os.path.exists(dll)]
+
+# Check for ATLAS
+numpy_path = os.path.join(python_root, 'lib', 'site-packages', 'numpy', 'core')
+atlas_dlls = dll_check(numpy_path, ['numpy-atlas'])
+
+# Check for MKL
+mkl_path = os.path.join(python_root, 'Library', 'bin')
+mkl_dlls = dll_check(mkl_path, ['mkl_core', 'mkl_def', 'libiomp5md'])
+
+if mkl_dlls:
+ data_files.append(('.', mkl_dlls))
+if atlas_dlls:
+ data_files.append(('.', atlas_dlls))
+
+if is_64bits:
+ msvcrtdll = glob(r"C:\Program Files\Microsoft Visual Studio 9.0\VC\redist\x86\Microsoft.VC90.CRT\*.*")
+else:
+ msvcrtdll = glob(r"C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\redist\x86\Microsoft.VC90.CRT\*.*")
+if msvcrtdll:
# install the MSVC 9 runtime dll's into the application folder
- data_files.append(msvcrtdll_data_files)
+ data_files.append(("Microsoft.VC90.CRT", msvcrtdll))
# NOTE:
# need an empty __init__.py in site-packages/numpy/distutils/tests and site-packages/mpl_toolkits
@@ -321,7 +285,7 @@ if msvcrtdll_data_files is not None:
#
packages = [
'matplotlib', 'scipy', 'encodings', 'comtypes', 'h5py',
- 'win32com', 'xhtml2pdf', 'bumps','sasmodels', 'sas',
+ 'win32com', 'xhtml2pdf', 'bumps', 'sasmodels', 'sas',
]
packages.extend([
'reportlab',
@@ -336,7 +300,11 @@ packages.extend([
'reportlab.platypus',
])
packages.append('periodictable.core') # not found automatically
-#packages.append('IPython')
+
+# For the interactive interpreter SasViewCom make sure ipython is available
+#packages.extend(['IPython', 'pyreadline', 'pyreadline.unicode_helper'])
+
+# individual models
includes = ['site', 'lxml._elementpath', 'lxml.etree']
if tinycc:
@@ -345,12 +313,12 @@ if tinycc:
# Exclude packages that are not needed but are often found on build systems
excludes = ['Tkinter', 'PyQt4', '_tkagg', 'sip', 'pytz', 'sympy']
-
dll_excludes = [
# Various matplotlib backends we are not using
'libgdk_pixbuf-2.0-0.dll', 'libgobject-2.0-0.dll', 'libgdk-win32-2.0-0.dll',
'tcl84.dll', 'tk84.dll', 'QtGui4.dll', 'QtCore4.dll',
# numpy 1.8 openmp bindings (still seems to use all the cores without them)
+ # ... but we seem to need them when building from anaconda, so don't exclude ...
#'libiomp5md.dll', 'libifcoremd.dll', 'libmmd.dll', 'svml_dispmd.dll','libifportMD.dll',
'numpy-atlas.dll',
# microsoft C runtime (not allowed to ship with the app; need to ship vcredist
@@ -364,25 +332,34 @@ dll_excludes = [
]
target_wx_client = Target(
- description = 'SasView',
- script = 'sasview.py',
- icon_resources = [(1, os.path.join(images_dir, "ball.ico"))],
- other_resources = [(24, 1, manifest)],
- dest_base = "SasView"
- )
-
-# bundle_option = 2
+ description='SasView',
+ script='sasview_gui.py',
+ icon_resources=[(1, local_config.SetupIconFile_win)],
+ other_resources=[(24, 1, manifest)],
+ dest_base="SasView"
+)
+
+target_console_client = Target(
+ description='SasView console',
+ script='sasview_console.py',
+ icon_resources=[(1, local_config.SetupIconFile_win)],
+ other_resources=[(24, 1, manifest)],
+ dest_base="SasViewCom"
+)
+
+#bundle_option = 3 if is_64bits else 2
bundle_option = 3
-if is_64bits:
- bundle_option = 3
generate_installer()
#initialize category stuff
#from sas.sasgui.guiframe.CategoryInstaller import CategoryInstaller
#CategoryInstaller.check_install(s)
+#import pprint; pprint.pprint(data_files); sys.exit()
+
+import py2exe
setup(
windows=[target_wx_client],
- console=[],
+ console=[target_console_client],
options={
'py2exe': {
'dll_excludes': dll_excludes,
diff --git a/installers/setup_mac.py b/installers/setup_mac.py
new file mode 100644
index 0000000..3adb354
--- /dev/null
+++ b/installers/setup_mac.py
@@ -0,0 +1,200 @@
+"""
+This is a setup.py script partly generated by py2applet
+
+Usage:
+ python setup.py py2app
+
+
+NOTES:
+ 12/01/2011: When seeing an error related to pytz.zoneinfo not being found,
+ change the following line in py2app/recipes/matplotlib.py
+ mf.import_hook('pytz.tzinfo', m, ['UTC'])
+ 12/05/2011: Needs macholib >= 1.4.3 and py2app >= 0.6.4 to create a 64-bit app
+"""
+from __future__ import print_function
+
+import os
+import sys
+import string
+
+from distutils.util import get_platform
+from distutils.filelist import findall
+from distutils.sysconfig import get_python_lib
+
+from setuptools import setup
+
+# Need the installer dir on the python path to find helper modules
+installer_dir = os.path.abspath(os.path.dirname(__file__))
+if installer_dir != os.path.abspath(os.getcwd()):
+ raise RuntimeError("Must run setup_exe from the installers directory")
+sys.path.append(installer_dir)
+
+# put the build directory at the front of the path
+root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+platform = '%s-%s'%(get_platform(), sys.version[:3])
+doc_path = os.path.join(root, 'build', 'lib.'+platform, 'doc')
+build_path = os.path.join(root, 'sasview-install', 'lib', 'python2.7', 'site-packages')
+#sys.path.insert(0, build_path)
+
+#Extending recursion limit
+sys.setrecursionlimit(10000)
+
+if len(sys.argv) == 1:
+ sys.argv.append('py2app')
+
+import macholib_patch
+
+from sas import get_local_config
+local_config = get_local_config()
+
+ICON = local_config.SetupIconFile_mac
+data_files = []
+
+# Include data for supporting packages
+import periodictable
+data_files += periodictable.data_files()
+
+import sasmodels
+data_files += sasmodels.data_files()
+
+# Data files for the different perspectives
+from sas.sasgui.perspectives import fitting
+data_files += fitting.data_files()
+
+from sas.sasgui.perspectives import calculator
+data_files += calculator.data_files()
+
+from sas.sasgui.perspectives import invariant
+data_files += invariant.data_files()
+
+from sas.sasgui import guiframe
+data_files += guiframe.data_files()
+
+# Copy the config files
+sasview_path = os.path.join('..', 'src', 'sas', 'sasview')
+data_files.append(('.', [os.path.join(sasview_path, 'custom_config.py')]))
+data_files.append(('config', [os.path.join(sasview_path, 'custom_config.py')]))
+data_files.append(('.', [os.path.join(sasview_path, 'local_config.py')]))
+
+# Copy the logging config
+sas_path = os.path.join('..', 'src', 'sas')
+data_files.append(('.', [os.path.join(sas_path, 'logging.ini')]))
+
+if os.path.isfile("BUILD_NUMBER"):
+ data_files.append(('.', ["BUILD_NUMBER"]))
+
+# Copying the images directory to the distribution directory.
+data_files.append(("images", findall(local_config.icon_path)))
+
+# Copying the HTML help docs
+data_files.append(("media", findall(local_config.media_path)))
+
+# Copying the sample data user data
+test_dir = local_config.test_path
+for dirpath, dirnames, filenames in os.walk(test_dir):
+ target_dir = os.path.join("test", os.path.relpath(dirpath, test_dir))
+ source_files = [os.path.join(dirpath, f) for f in filenames]
+ data_files.append((target_dir, source_files))
+
+# See if the documentation has been built, and if so include it.
+if os.path.exists(doc_path):
+ for dirpath, dirnames, filenames in os.walk(doc_path):
+ target_dir = os.path.join("doc", os.path.relpath(dirpath, doc_path))
+ source_files = [os.path.join(dirpath, f) for f in filenames]
+ data_files.append((target_dir, source_files))
+else:
+ raise Exception("You must first build the documentation before creating an installer.")
+
+# Copying opencl include files
+opencl_source = os.path.join(get_python_lib(), "pyopencl", "cl")
+opencl_target = os.path.join("includes", "pyopencl")
+data_files.append((opencl_target, findall(opencl_source)))
+
+# Locate libxml2 library
+lib_locs = ['/usr/local/lib', '/usr/lib']
+libxml_path = None
+for item in lib_locs:
+ libxml_path_test = '%s/libxml2.2.dylib' % item
+ if os.path.isfile(libxml_path_test):
+ libxml_path = libxml_path_test
+if libxml_path is None:
+ raise RuntimeError("Could not find libxml2 on the system")
+
+# locate file extensions
+def find_extension():
+ """
+ Describe the extensions that can be read by the current application
+ """
+ try:
+ extensions = []
+ EXCEPTION_LIST = ['*', '.', '']
+ from sas.sascalc.dataloader.loader import Loader
+ wild_cards = Loader().get_wildcards()
+ for item in wild_cards:
+ #['All (*.*)|*.*']
+ file_type, ext = string.split(item, "|*.", 1)
+ if ext.strip() not in EXCEPTION_LIST and ext.strip() not in extensions:
+ extensions.append(ext)
+ except Exception:
+ pass
+ try:
+ file_type, ext = string.split(local_config.APPLICATION_WLIST, "|*.", 1)
+ if ext.strip() not in EXCEPTION_LIST and ext.strip() not in extensions:
+ extensions.append(ext)
+ except Exception:
+ pass
+ try:
+ for item in local_config.PLUGINS_WLIST:
+ file_type, ext = string.split(item, "|*.", 1)
+ if ext.strip() not in EXCEPTION_LIST and ext.strip() not in extensions:
+ extensions.append(ext)
+ except Exception:
+ pass
+
+ return extensions
+
+EXTENSIONS_LIST = find_extension()
+
+plist = dict(CFBundleDocumentTypes=[dict(CFBundleTypeExtensions=EXTENSIONS_LIST,
+ CFBundleTypeIconFile=ICON,
+ CFBundleTypeName="sasview file",
+ CFBundleTypeRole="Shell")],)
+
+#Get version - NB nasty hack. Need to find correct way to give path to installed sasview (AJJ)
+#h5py has been added to packages. It requires hdf5 to be installed separetly
+#
+
+from sas.sasview import __version__ as VERSION
+APPNAME = "SasView "+VERSION
+DMGNAME = "SasView-"+VERSION+"-MacOSX"
+APP = ['sasview_gui.py']
+
+EXCLUDES = ['PyQt4', 'sip', 'QtGui']
+
+OPTIONS = {'argv_emulation': True,
+ 'packages': ['lxml', 'numpy', 'scipy', 'pytz', 'encodings',
+ 'encodings', 'matplotlib', 'periodictable',
+ 'reportlab', 'sasmodels', 'pyopencl', 'h5py',
+ ],
+ 'iconfile': ICON,
+ 'frameworks': [libxml_path],
+ 'plist': plist,
+ 'excludes' : EXCLUDES,
+ }
+
+#import pprint; pprint.pprint(data_files); sys.exit()
+setup(
+ name=APPNAME,
+ app=APP,
+ data_files=data_files,
+ include_package_data=True,
+ options={'py2app': OPTIONS},
+ setup_requires=['py2app'],
+)
+
+#Build dmg
+DMG = "dist/%s.dmg"%DMGNAME
+if os.path.exists(DMG):
+ os.unlink(DMG)
+os.system('cd dist && ../../build_tools/dmgpack.sh "%s" "%s.app"'%(DMGNAME, APPNAME))
+os.system('chmod a+r "%s"'%DMG)
diff --git a/sasview/version.txt b/installers/version.txt
similarity index 100%
rename from sasview/version.txt
rename to installers/version.txt
diff --git a/mac_setup_homebrew.sh b/mac_setup_homebrew.sh
new file mode 100644
index 0000000..c656ae1
--- /dev/null
+++ b/mac_setup_homebrew.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+sudo pip install Pillow
+brew tap homebrew/science
+brew install hdf5
+sudo pip install h5py
+xcode-select --install
+sudo python setup.py install
diff --git a/run.py b/run.py
index 641c718..fad3adc 100755
--- a/run.py
+++ b/run.py
@@ -1,4 +1,5 @@
#!/usr/bin/env python
+# -*- coding: utf-8 -*-
"""
Run sasview in place. This allows sasview to use the python
files in the source tree without having to call setup.py install
@@ -12,13 +13,14 @@ Usage:
Without arguments run.py runs sasview. With arguments, run.py will run
the given module or script.
"""
+from __future__ import print_function
+import imp
import os
import sys
-import imp
from contextlib import contextmanager
-from os.path import abspath, dirname, join as joinpath
-
+from os.path import join as joinpath
+from os.path import abspath, dirname
def addpath(path):
"""
@@ -33,6 +35,7 @@ def addpath(path):
os.environ['PYTHONPATH'] = PYTHONPATH
sys.path.insert(0, path)
+
@contextmanager
def cd(path):
"""
@@ -43,22 +46,26 @@ def cd(path):
yield
os.chdir(old_dir)
+
def import_package(modname, path):
"""Import a package into a particular point in the python namespace"""
- mod = imp.load_source(modname, abspath(joinpath(path,'__init__.py')))
+ #logger.debug("Dynamicly importing: %s", path)
+ mod = imp.load_source(modname, abspath(joinpath(path, '__init__.py')))
sys.modules[modname] = mod
mod.__path__ = [abspath(path)]
return mod
+
def import_dll(modname, build_path):
"""Import a DLL from the build directory"""
import sysconfig
ext = sysconfig.get_config_var('SO')
# build_path comes from context
- path = joinpath(build_path, *modname.split('.'))+ext
- #print "importing", modname, "from", path
+ path = joinpath(build_path, *modname.split('.')) + ext
+ # print "importing", modname, "from", path
return imp.load_dynamic(modname, path)
+
def prepare():
# Don't create *.pyc files
sys.dont_write_bytecode = True
@@ -69,8 +76,8 @@ def prepare():
# find the directories for the source and build
from distutils.util import get_platform
root = abspath(dirname(__file__))
- platform = '%s-%s'%(get_platform(),sys.version[:3])
- build_path = joinpath(root, 'build','lib.'+platform)
+ platform = '%s-%s' % (get_platform(), sys.version[:3])
+ build_path = joinpath(root, 'build', 'lib.' + platform)
# Notify the help menu that the Sphinx documentation is in a different
# place than it otherwise would be.
@@ -81,15 +88,24 @@ def prepare():
#os.environ['MPLCONFIGDIR'] = mplconfig
#if not os.path.exists(mplconfig): os.mkdir(mplconfig)
#import matplotlib
- #matplotlib.use('Agg')
- #print matplotlib.__file__
+ # matplotlib.use('Agg')
+ # print matplotlib.__file__
#import pylab; pylab.hold(False)
# add periodictable to the path
- try: import periodictable
- except: addpath(joinpath(root, '..','periodictable'))
+ try:
+ import periodictable
+ except:
+ addpath(joinpath(root, '..', 'periodictable'))
- try: import bumps
- except: addpath(joinpath(root, '..','bumps'))
+ try:
+ import bumps
+ except:
+ addpath(joinpath(root, '..', 'bumps'))
+
+ try:
+ import tinycc
+ except:
+ addpath(joinpath(root, '../tinycc/build/lib'))
# select wx version
#addpath(os.path.join(root, '..','wxPython-src-3.0.0.0','wxPython'))
@@ -106,11 +122,6 @@ def prepare():
# sasmodels on the path
addpath(joinpath(root, '../sasmodels/'))
- # Import the sasview package from root/sasview as sas.sasview. It would
- # be better to just store the package in src/sas/sasview.
- import sas
- sas.sasview = import_package('sas.sasview', joinpath(root,'sasview'))
-
# The sas.models package Compiled Model files should be pulled in from the build directory even though
# the source is stored in src/sas/models.
@@ -118,25 +129,58 @@ def prepare():
# Some packages are not where they are needed, so load them explicitly.
import sas.sascalc.pr
sas.sascalc.pr.core = import_package('sas.sascalc.pr.core',
- joinpath(build_path, 'sas', 'sascalc', 'pr', 'core'))
+ joinpath(build_path, 'sas', 'sascalc', 'pr', 'core'))
# Compiled modules need to be pulled from the build directory.
# Some packages are not where they are needed, so load them explicitly.
import sas.sascalc.file_converter
sas.sascalc.file_converter.core = import_package('sas.sascalc.file_converter.core',
- joinpath(build_path, 'sas', 'sascalc', 'file_converter', 'core'))
+ joinpath(build_path, 'sas', 'sascalc', 'file_converter', 'core'))
- # Compiled modules need to be pulled from the build directory.
- # Some packages are not where they are needed, so load them explicitly.
import sas.sascalc.calculator
sas.sascalc.calculator.core = import_package('sas.sascalc.calculator.core',
- joinpath(build_path, 'sas', 'sascalc', 'calculator', 'core'))
+ joinpath(build_path, 'sas', 'sascalc', 'calculator', 'core'))
sys.path.append(build_path)
- #print "\n".join(sys.path)
+ set_git_tag()
+ # print "\n".join(sys.path)
+
+def set_git_tag():
+ try:
+ import subprocess
+ import os
+ import platform
+ FNULL = open(os.devnull, 'w')
+ if platform.system() == "Windows":
+ args = ['git', 'describe', '--tags']
+ else:
+ args = ['git describe --tags']
+ git_revision = subprocess.check_output(args, stderr=FNULL, shell=True)
+ import sas.sasview
+ sas.sasview.__build__ = str(git_revision).strip()
+ except subprocess.CalledProcessError as cpe:
+ get_logger().warning("Error while determining build number\n Using command:\n %s \n Output:\n %s"% (cpe.cmd,cpe.output))
+
+_logger = None
+def get_logger():
+ global _logger
+ if _logger is None:
+ from sas.logger_config import SetupLogger
+ _logger = SetupLogger(__name__).config_development()
+ return _logger
if __name__ == "__main__":
+ # Need to add absolute path before actual prepare call,
+ # so logging can be done during initialization process too
+ root = abspath(dirname(__file__))
+ addpath(joinpath(root, 'src'))
+
+ get_logger().debug("Starting SASVIEW in debug mode.")
prepare()
- from sas.sasview.sasview import run
- run()
+ from sas.sasview.sasview import run_cli, run_gui
+ if len(sys.argv) == 1:
+ run_gui()
+ else:
+ run_cli()
+ get_logger().debug("Ending SASVIEW in debug mode.")
diff --git a/sasview/__init__.py b/sasview/__init__.py
deleted file mode 100644
index dbc9890..0000000
--- a/sasview/__init__.py
+++ /dev/null
@@ -1,18 +0,0 @@
-__version__ = "4.1.2"
-__build__ = "GIT_COMMIT"
-try:
- import logging
- import subprocess
- import os
- import platform
- FNULL = open(os.devnull, 'w')
- if platform.system() == "Windows":
- args = ['git', 'describe', '--tags']
- else:
- args = ['git describe --tags']
- git_revision = subprocess.check_output(args,
- stderr=FNULL,
- shell=True)
- __build__ = str(git_revision).strip()
-except subprocess.CalledProcessError as cpe:
- logging.warning("Error while determining build number\n Using command:\n %s \n Output:\n %s"% (cpe.cmd,cpe.output))
diff --git a/sasview/sasview.py b/sasview/sasview.py
deleted file mode 100644
index 3588399..0000000
--- a/sasview/sasview.py
+++ /dev/null
@@ -1,213 +0,0 @@
-"""
-Base module for loading and running the main SasView application.
-"""
-################################################################################
-#This software was developed by the University of Tennessee as part of the
-#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
-#project funded by the US National Science Foundation.
-#
-#See the license text in license.txt
-#
-#copyright 2009, University of Tennessee
-################################################################################
-import os
-import sys
-import logging
-import traceback
-
-logging.basicConfig(level=logging.INFO,
- format='%(asctime)s %(levelname)s %(message)s',
- filename=os.path.join(os.path.expanduser("~"),
- 'sasview.log'))
-logging.captureWarnings(True)
-
-class StreamToLogger(object):
- """
- File-like stream object that redirects writes to a logger instance.
- """
- def __init__(self, logger, log_level=logging.INFO):
- self.logger = logger
- self.log_level = log_level
- self.linebuf = ''
-
- def write(self, buf):
- """
- Main logging method
- """
- # Write the message to stdout so we can see it when running interactively
- sys.stdout.write(buf)
- for line in buf.rstrip().splitlines():
- self.logger.log(self.log_level, line.rstrip())
-
-stderr_logger = logging.getLogger('STDERR')
-sl = StreamToLogger(stderr_logger, logging.ERROR)
-sys.stderr = sl
-
-# Log the start of the session
-logging.info(" --- SasView session started ---")
-
-# Log the python version
-logging.info("Python: %s" % sys.version)
-
-# Allow the dynamic selection of wxPython via an environment variable, when devs
-# who have multiple versions of the module installed want to pick between them.
-# This variable does not have to be set of course, and through normal usage will
-# probably not be, but this can make things a little easier when upgrading to a
-# new version of wx.
-WX_ENV_VAR = "SASVIEW_WX_VERSION"
-if WX_ENV_VAR in os.environ:
- logging.info("You have set the %s environment variable to %s." % \
- (WX_ENV_VAR, os.environ[WX_ENV_VAR]))
- import wxversion
- if wxversion.checkInstalled(os.environ[WX_ENV_VAR]):
- logging.info("Version %s of wxPython is installed, so using that version." % os.environ[WX_ENV_VAR])
- wxversion.select(os.environ[WX_ENV_VAR])
- else:
- logging.error("Version %s of wxPython is not installed, so using default version." % os.environ[WX_ENV_VAR])
-else:
- logging.info("You have not set the %s environment variable, so using default version of wxPython." % WX_ENV_VAR)
-
-import wx
-
-try:
- logging.info("Wx version: %s" % wx.__version__)
-except:
- logging.error("Wx version: error reading version")
-
-import wxcruft
-wxcruft.call_later_fix()
-#wxcruft.trace_new_id()
-
-#Always use private .matplotlib setup to avoid conflicts with other
-#uses of matplotlib
-#Have to check if .sasview exists first
-sasdir = os.path.join(os.path.expanduser("~"),'.sasview')
-if not os.path.exists(sasdir):
- os.mkdir(sasdir)
-mplconfigdir = os.path.join(os.path.expanduser("~"),'.sasview','.matplotlib')
-if not os.path.exists(mplconfigdir):
- os.mkdir(mplconfigdir)
-os.environ['MPLCONFIGDIR'] = mplconfigdir
-reload(sys)
-sys.setdefaultencoding("iso-8859-1")
-from sas.sasgui.guiframe import gui_manager
-from sas.sasgui.guiframe.gui_style import GUIFRAME
-from welcome_panel import WelcomePanel
-# For py2exe, import config here
-import local_config
-PLUGIN_MODEL_DIR = 'plugin_models'
-APP_NAME = 'SasView'
-
-from matplotlib import backend_bases
-backend_bases.FigureCanvasBase.filetypes.pop('pgf', None)
-
-class SasView():
- """
- Main class for running the SasView application
- """
- def __init__(self):
- """
- """
- #from gui_manager import ViewApp
- self.gui = gui_manager.SasViewApp(0)
- # Set the application manager for the GUI
- self.gui.set_manager(self)
- # Add perspectives to the basic application
- # Additional perspectives can still be loaded
- # dynamically
- # Note: py2exe can't find dynamically loaded
- # modules. We load the fitting module here
- # to ensure a complete Windows executable build.
-
- # Fitting perspective
- try:
- import sas.sasgui.perspectives.fitting as module
- fitting_plug = module.Plugin()
- self.gui.add_perspective(fitting_plug)
- except Exception:
- logging.error("%s: could not find Fitting plug-in module"% APP_NAME)
- logging.error(traceback.format_exc())
-
- # P(r) perspective
- try:
- import sas.sasgui.perspectives.pr as module
- pr_plug = module.Plugin()
- self.gui.add_perspective(pr_plug)
- except:
- logging.error("%s: could not find P(r) plug-in module"% APP_NAME)
- logging.error(traceback.format_exc())
-
- #Invariant perspective
- try:
- import sas.sasgui.perspectives.invariant as module
- invariant_plug = module.Plugin()
- self.gui.add_perspective(invariant_plug)
- except Exception as e :
- logging.error("%s: could not find Invariant plug-in module"% \
- APP_NAME)
- logging.error(traceback.format_exc())
-
- # Corfunc perspective
- try:
- import sas.sasgui.perspectives.corfunc as module
- corfunc_plug = module.Plugin()
- self.gui.add_perspective(corfunc_plug)
- except:
- logging.error("Unable to load corfunc module")
-
- #Calculator perspective
- try:
- import sas.sasgui.perspectives.calculator as module
- calculator_plug = module.Plugin()
- self.gui.add_perspective(calculator_plug)
- except:
- logging.error("%s: could not find Calculator plug-in module"% \
- APP_NAME)
- logging.error(traceback.format_exc())
-
- # File converter tool
- try:
- import sas.sasgui.perspectives.file_converter as module
- converter_plug = module.Plugin()
- self.gui.add_perspective(converter_plug)
- except:
- logging.error("%s: could not find File Converter plug-in module"% \
- APP_NAME)
- logging.error(traceback.format_exc())
-
-
- # Add welcome page
- self.gui.set_welcome_panel(WelcomePanel)
-
- # Build the GUI
- self.gui.build_gui()
- # delete unused model folder
- self.gui.clean_plugin_models(PLUGIN_MODEL_DIR)
- # Start the main loop
- self.gui.MainLoop()
-
-
-def run():
- """
- __main__ method for loading and running SasView
- """
- from multiprocessing import freeze_support
- freeze_support()
- if len(sys.argv) > 1:
- ## Run sasview as an interactive python interpreter
- #if sys.argv[1] == "-i":
- # sys.argv = ["ipython", "--pylab"]
- # from IPython import start_ipython
- # sys.exit(start_ipython())
- thing_to_run = sys.argv[1]
- sys.argv = sys.argv[1:]
- import runpy
- if os.path.exists(thing_to_run):
- runpy.run_path(thing_to_run, run_name="__main__")
- else:
- runpy.run_module(thing_to_run, run_name="__main__")
- else:
- SasView()
-
-if __name__ == "__main__":
- run()
diff --git a/sasview/setup_mac.py b/sasview/setup_mac.py
deleted file mode 100644
index 2edf589..0000000
--- a/sasview/setup_mac.py
+++ /dev/null
@@ -1,158 +0,0 @@
-"""
-This is a setup.py script partly generated by py2applet
-
-Usage:
- python setup.py py2app
-
-
-NOTES:
- 12/01/2011: When seeing an error related to pytz.zoneinfo not being found, change the following line in py2app/recipes/matplotlib.py
- mf.import_hook('pytz.tzinfo', m, ['UTC'])
- 12/05/2011: Needs macholib >= 1.4.3 and py2app >= 0.6.4 to create a 64-bit app
-"""
-from setuptools import setup
-import periodictable.xsf
-import sas.sascalc.dataloader.readers
-import os
-import string
-import local_config
-import pytz
-import sys
-import platform
-#Extending recursion limit
-sys.setrecursionlimit(10000)
-
-from distutils.util import get_platform
-root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
-platform = '%s-%s'%(get_platform(),sys.version[:3])
-build_path = os.path.join(root, 'build','lib.'+platform)
-sys.path.insert(0, build_path)
-print "BUILDING PATH INSIDE", build_path
-ICON = local_config.SetupIconFile_mac
-EXTENSIONS_LIST = []
-DATA_FILES = []
-RESOURCES_FILES = []
-
-#Periodictable data file
-DATA_FILES = periodictable.data_files()
-#invariant and calculator help doc
-import sas.sasgui.perspectives.fitting as fitting
-DATA_FILES += fitting.data_files()
-import sas.sasgui.perspectives.calculator as calculator
-DATA_FILES += calculator.data_files()
-import sas.sasgui.perspectives.invariant as invariant
-DATA_FILES += invariant.data_files()
-import sasmodels as models
-DATA_FILES += models.data_files()
-import sas.sasgui.guiframe as guiframe
-DATA_FILES += guiframe.data_files()
-
-#CANSAxml reader data files
-RESOURCES_FILES.append(os.path.join(sas.sascalc.dataloader.readers.get_data_path(),'defaults.json'))
-
-# Locate libxml2 library
-lib_locs = ['/usr/local/lib', '/usr/lib']
-libxml_path = None
-for item in lib_locs:
- libxml_path_test = '%s/libxml2.2.dylib' % item
- if os.path.isfile(libxml_path_test):
- libxml_path = libxml_path_test
-if libxml_path == None:
- raise RuntimeError, "Could not find libxml2 on the system"
-
-APP = ['sasview.py']
-DATA_FILES += ['images','test','media', 'custom_config.py', 'local_config.py']
-if os.path.isfile("BUILD_NUMBER"):
- DATA_FILES.append("BUILD_NUMBER")
-
-# See if the documentation has been built, and if so include it.
-doc_path = os.path.join(build_path, "doc")
-print doc_path
-if os.path.exists(doc_path):
- for dirpath, dirnames, filenames in os.walk(doc_path):
- for filename in filenames:
- sub_dir = os.path.join("doc", os.path.relpath(dirpath, doc_path))
- DATA_FILES.append((sub_dir, [os.path.join(dirpath, filename)]))
-else:
- raise Exception("You must first build the documentation before creating an installer.")
-
-# locate file extensions
-def find_extension():
- """
- Describe the extensions that can be read by the current application
- """
- try:
- list = []
- EXCEPTION_LIST = ['*', '.', '']
- from sas.sascalc.dataloader.loader import Loader
- wild_cards = Loader().get_wildcards()
- for item in wild_cards:
- #['All (*.*)|*.*']
- file_type, ext = string.split(item, "|*.", 1)
- if ext.strip() not in EXCEPTION_LIST and ext.strip() not in list:
- list.append(ext)
- except:
- pass
- try:
- file_type, ext = string.split(local_config.APPLICATION_WLIST, "|*.", 1)
- if ext.strip() not in EXCEPTION_LIST and ext.strip() not in list:
- list.append(ext)
- except:
- pass
- try:
- for item in local_config.PLUGINS_WLIST:
- file_type, ext = string.split(item, "|*.", 1)
- if ext.strip() not in EXCEPTION_LIST and ext.strip() not in list:
- list.append(ext)
- except:
- pass
-
- return list
-
-EXTENSIONS_LIST = find_extension()
-
-
-plist = dict(CFBundleDocumentTypes=[dict(CFBundleTypeExtensions=EXTENSIONS_LIST,
- CFBundleTypeIconFile=ICON,
- CFBundleTypeName="sasview file",
- CFBundleTypeRole="Shell" )],)
-
-#Get version - NB nasty hack. Need to find correct way to give path to installed sasview (AJJ)
-#h5py has been added to packages. It requires hdf5 to be installed separetly
-#
-import __init__ as sasviewver
-
-VERSION = sasviewver.__version__
-APPNAME = "SasView "+VERSION
-DMGNAME = "SasView-"+VERSION+"-MacOSX"
-
-APP = ['sasview.py']
-DATA_FILES += ['images','test','media']
-
-EXCLUDES = ['PyQt4', 'sip', 'QtGui']
-
-OPTIONS = {'argv_emulation': True,
- 'packages': ['lxml','numpy', 'scipy', 'pytz', 'encodings',
- 'encodings','matplotlib', 'periodictable',
- 'reportlab','sasmodels',"pyopencl", "h5py"
- ],
- 'iconfile': ICON,
- 'frameworks':[libxml_path],
- 'resources': RESOURCES_FILES,
- 'plist':plist,
- 'excludes' : EXCLUDES,
- }
-setup(
- name=APPNAME,
- app=APP,
- data_files=DATA_FILES,
- include_package_data= True,
- options={'py2app': OPTIONS},
- setup_requires=['py2app'],
-)
-
-#Build dmg
-DMG="dist/%s.dmg"%DMGNAME
-if os.path.exists(DMG): os.unlink(DMG)
-os.system('cd dist && ../../build_tools/dmgpack.sh "%s" "%s.app"'%(DMGNAME,APPNAME))
-os.system('chmod a+r "%s"'%DMG)
diff --git a/sasview/test/2d_data/Dec07031.ASC b/sasview/test/2d_data/Dec07031.ASC
deleted file mode 100644
index 39ece42..0000000
--- a/sasview/test/2d_data/Dec07031.ASC
+++ /dev/null
@@ -1,16403 +0,0 @@
-FILE: Dec07031.SA2_LP _P322 CREATED: 7-DEC-2007 15:38:16
-LABEL: Scatt 13.5m lamellar 65% 2011-7 28degrees
-MON CNT LAMBDA(A) DET_OFF(cm) DET_DIST(m) TRANS THICK(cm)
-6.6207e+06 6 0 13.5 0.63053 0.1
-BCENT(X,Y) A1(mm) A2(mm) A1A2DIST(m) DL/L BSTOP(mm) DET_TYP
-66.22 62.37 50 12.7 14.729 0.124 76.2 ORNL
-SAM: RAW Data File: Dec07031.SA2_LP _P322
-BGD: none
-EMP: none
-DIV: none
-MASK: none
-ABS Parameters (3-6): none
-Average Choices: none
-
-*** Data written from RAW folder and may not be a fully corrected data file ***
-The detector image is a standard X-Y coordinate system
-Data is written by row, starting with Y=1 and X=(1->128)
-ASCII data created Mon, Jan 25, 2010 6:58:01 PM
-
-97
-95
-105
-107
-86
-98
-113
-101
-106
-101
-117
-107
-100
-94
-91
-118
-132
-123
-109
-121
-130
-126
-112
-127
-90
-117
-112
-120
-116
-116
-97
-114
-147
-132
-131
-120
-103
-130
-114
-117
-122
-127
-120
-108
-117
-108
-120
-114
-108
-107
-120
-92
-110
-112
-116
-104
-113
-123
-108
-121
-82
-86
-107
-97
-94
-97
-100
-94
-111
-110
-101
-102
-97
-90
-90
-106
-82
-88
-108
-83
-94
-89
-93
-114
-102
-93
-102
-112
-82
-96
-120
-91
-78
-92
-93
-81
-111
-77
-108
-103
-98
-95
-71
-78
-90
-87
-85
-83
-73
-83
-97
-73
-94
-102
-100
-85
-68
-75
-85
-82
-89
-86
-96
-80
-74
-64
-81
-41
-55
-38
-50
-61
-56
-53
-60
-58
-59
-58
-60
-53
-58
-64
-61
-60
-62
-71
-60
-59
-55
-55
-64
-64
-67
-74
-64
-56
-60
-60
-76
-59
-68
-80
-66
-63
-66
-67
-49
-56
-65
-69
-48
-66
-60
-71
-53
-53
-67
-60
-63
-62
-56
-62
-51
-63
-59
-59
-58
-58
-56
-54
-56
-38
-48
-54
-61
-46
-52
-54
-52
-61
-50
-43
-55
-54
-52
-61
-63
-53
-58
-52
-63
-52
-53
-55
-53
-50
-48
-54
-53
-60
-57
-57
-51
-37
-46
-56
-67
-70
-54
-41
-51
-53
-54
-49
-57
-58
-47
-51
-67
-46
-59
-47
-50
-63
-54
-42
-47
-39
-54
-51
-42
-54
-41
-58
-43
-29
-55
-51
-60
-56
-62
-64
-49
-59
-45
-71
-53
-62
-48
-49
-50
-61
-52
-53
-47
-76
-59
-70
-67
-69
-60
-50
-52
-57
-63
-51
-46
-67
-56
-57
-84
-62
-57
-75
-64
-78
-58
-53
-67
-54
-72
-57
-52
-64
-70
-64
-58
-69
-62
-57
-61
-59
-49
-61
-49
-59
-52
-38
-50
-58
-42
-74
-54
-44
-44
-44
-47
-54
-45
-60
-49
-55
-39
-47
-51
-43
-52
-39
-57
-61
-50
-53
-44
-45
-47
-59
-51
-45
-56
-54
-47
-42
-61
-37
-48
-51
-52
-62
-48
-41
-48
-44
-59
-49
-50
-61
-47
-44
-39
-40
-55
-29
-45
-55
-42
-38
-46
-36
-36
-31
-43
-46
-39
-13
-50
-54
-60
-68
-50
-60
-51
-79
-55
-55
-54
-54
-57
-58
-60
-66
-62
-55
-78
-67
-53
-76
-61
-60
-67
-59
-49
-65
-62
-68
-52
-52
-69
-62
-70
-84
-63
-80
-53
-69
-62
-55
-50
-67
-76
-57
-66
-78
-72
-55
-62
-61
-68
-63
-86
-69
-56
-47
-55
-69
-67
-65
-55
-58
-59
-52
-56
-55
-49
-56
-56
-55
-74
-48
-50
-60
-55
-48
-54
-53
-65
-60
-65
-59
-57
-54
-56
-61
-50
-55
-51
-44
-68
-61
-49
-47
-45
-43
-56
-57
-59
-54
-49
-48
-49
-49
-45
-62
-42
-62
-58
-48
-59
-65
-52
-56
-45
-44
-41
-32
-39
-45
-45
-46
-38
-43
-42
-19
-37
-50
-63
-56
-60
-70
-64
-55
-68
-56
-63
-66
-58
-55
-63
-54
-61
-71
-61
-66
-70
-81
-86
-80
-86
-75
-68
-68
-69
-76
-78
-63
-62
-57
-67
-76
-72
-65
-68
-75
-76
-75
-79
-60
-75
-65
-64
-63
-53
-69
-62
-57
-68
-57
-62
-73
-78
-76
-75
-54
-60
-77
-60
-60
-46
-64
-63
-53
-65
-69
-56
-59
-46
-61
-54
-66
-67
-64
-56
-49
-56
-67
-50
-51
-51
-62
-69
-51
-52
-70
-53
-51
-49
-61
-52
-54
-62
-54
-55
-45
-62
-47
-42
-47
-51
-54
-64
-44
-57
-52
-39
-53
-62
-50
-43
-53
-37
-45
-54
-63
-49
-64
-46
-53
-39
-48
-41
-22
-58
-58
-58
-58
-61
-53
-70
-55
-62
-45
-55
-64
-70
-75
-56
-56
-62
-67
-74
-71
-48
-69
-72
-67
-70
-82
-69
-81
-59
-62
-79
-88
-73
-70
-76
-67
-74
-85
-68
-61
-58
-77
-67
-79
-67
-78
-63
-71
-70
-69
-69
-62
-54
-64
-65
-76
-52
-63
-66
-68
-58
-64
-54
-68
-59
-54
-58
-67
-62
-62
-63
-58
-51
-55
-72
-65
-58
-47
-51
-60
-64
-63
-60
-65
-59
-54
-51
-61
-63
-61
-57
-55
-54
-71
-65
-60
-63
-58
-71
-66
-67
-49
-60
-52
-55
-64
-66
-46
-70
-49
-47
-41
-45
-67
-50
-50
-52
-50
-50
-54
-53
-44
-48
-60
-35
-52
-46
-32
-58
-65
-55
-67
-53
-63
-68
-60
-57
-49
-60
-65
-70
-60
-81
-64
-80
-81
-78
-87
-66
-75
-73
-83
-72
-65
-63
-72
-73
-71
-69
-68
-61
-84
-64
-64
-88
-68
-71
-73
-87
-81
-61
-72
-77
-92
-63
-75
-62
-76
-78
-63
-78
-56
-67
-68
-63
-56
-73
-66
-57
-53
-61
-54
-67
-65
-60
-60
-54
-56
-75
-62
-63
-54
-75
-70
-50
-51
-81
-61
-51
-54
-63
-54
-57
-60
-67
-64
-70
-45
-74
-67
-64
-64
-63
-57
-67
-54
-58
-60
-49
-66
-58
-57
-53
-45
-51
-47
-42
-57
-36
-54
-61
-46
-36
-54
-46
-56
-50
-43
-46
-45
-50
-47
-56
-53
-54
-34
-53
-50
-58
-51
-53
-57
-69
-51
-66
-52
-55
-53
-68
-70
-68
-59
-52
-81
-75
-71
-66
-63
-60
-70
-85
-80
-65
-56
-71
-63
-79
-62
-69
-74
-69
-86
-83
-71
-84
-72
-71
-76
-72
-83
-78
-68
-71
-68
-53
-66
-58
-60
-61
-58
-54
-59
-62
-81
-63
-90
-57
-77
-63
-55
-49
-62
-62
-72
-39
-63
-61
-64
-57
-51
-54
-55
-63
-48
-58
-63
-55
-48
-45
-57
-66
-57
-59
-65
-63
-49
-72
-69
-67
-52
-62
-57
-77
-46
-64
-77
-68
-63
-60
-56
-57
-49
-57
-64
-41
-49
-50
-69
-59
-55
-53
-47
-53
-60
-55
-38
-50
-44
-50
-45
-47
-49
-50
-23
-53
-79
-75
-66
-75
-85
-94
-68
-52
-78
-76
-71
-84
-72
-80
-81
-70
-83
-81
-90
-70
-77
-81
-82
-65
-88
-81
-83
-95
-102
-94
-81
-93
-81
-92
-72
-79
-84
-88
-88
-91
-86
-83
-82
-78
-66
-82
-81
-68
-66
-69
-74
-72
-84
-84
-70
-70
-75
-82
-77
-62
-82
-63
-84
-70
-68
-68
-83
-70
-70
-72
-76
-70
-67
-69
-66
-73
-64
-83
-75
-85
-67
-66
-59
-78
-62
-58
-65
-60
-80
-67
-66
-77
-84
-56
-75
-66
-64
-66
-70
-50
-70
-72
-61
-62
-49
-64
-64
-50
-61
-49
-70
-53
-47
-63
-72
-57
-57
-54
-46
-38
-55
-53
-43
-56
-66
-52
-44
-76
-52
-58
-67
-81
-70
-62
-59
-65
-75
-81
-78
-75
-77
-86
-98
-80
-97
-82
-95
-82
-102
-83
-82
-87
-82
-99
-81
-81
-92
-91
-77
-91
-80
-84
-77
-87
-100
-102
-88
-106
-88
-97
-91
-89
-105
-83
-84
-83
-71
-94
-88
-84
-95
-81
-86
-102
-62
-81
-86
-89
-83
-76
-72
-91
-73
-78
-62
-70
-65
-93
-79
-65
-63
-68
-64
-75
-67
-63
-75
-67
-82
-65
-73
-71
-86
-70
-75
-87
-67
-68
-82
-77
-70
-89
-72
-71
-66
-76
-71
-58
-80
-66
-64
-60
-78
-61
-69
-71
-70
-75
-64
-85
-57
-50
-71
-60
-61
-72
-70
-67
-69
-56
-58
-46
-48
-49
-36
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-1
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-79
-66
-78
-93
-110
-109
-102
-113
-96
-99
-112
-115
-106
-109
-107
-113
-133
-118
-114
-127
-115
-122
-93
-126
-129
-124
-95
-103
-118
-135
-120
-132
-115
-125
-108
-119
-127
-133
-126
-106
-117
-122
-119
-113
-110
-122
-107
-135
-108
-125
-116
-108
-117
-113
-130
-119
-98
-122
-98
-114
-94
-112
-118
-99
-108
-88
-104
-113
-109
-112
-97
-108
-100
-92
-101
-108
-111
-108
-103
-113
-102
-117
-77
-97
-105
-93
-93
-116
-108
-106
-98
-94
-87
-90
-79
-84
-82
-111
-96
-90
-104
-98
-110
-89
-106
-85
-94
-84
-105
-83
-95
-75
-93
-83
-73
-71
-99
-89
-63
-77
-90
-81
-79
-72
-73
-64
-64
-53
-56
-54
-72
-83
-73
-86
-76
-63
-74
-83
-67
-72
-67
-92
-91
-83
-93
-82
-86
-88
-72
-90
-79
-91
-90
-106
-95
-101
-84
-81
-89
-99
-104
-99
-82
-107
-94
-92
-104
-82
-94
-103
-97
-93
-89
-101
-81
-93
-84
-85
-84
-101
-75
-88
-96
-89
-81
-63
-76
-86
-81
-74
-91
-82
-87
-66
-75
-81
-78
-81
-88
-69
-68
-68
-73
-92
-63
-63
-76
-73
-84
-69
-80
-78
-86
-73
-68
-86
-76
-80
-84
-81
-83
-68
-63
-81
-70
-77
-84
-58
-74
-71
-73
-76
-64
-84
-69
-81
-69
-62
-56
-76
-66
-67
-62
-74
-64
-57
-50
-38
-47
-60
-58
-63
-44
-53
-61
-47
-74
-67
-74
-75
-64
-87
-60
-54
-81
-78
-73
-67
-69
-60
-76
-69
-83
-85
-73
-81
-78
-91
-93
-93
-93
-91
-73
-99
-86
-93
-79
-94
-100
-105
-100
-109
-93
-87
-108
-103
-96
-100
-91
-92
-98
-116
-95
-96
-99
-91
-72
-66
-98
-90
-82
-87
-90
-94
-71
-100
-79
-87
-88
-90
-80
-75
-87
-88
-67
-76
-76
-70
-59
-65
-91
-75
-66
-69
-69
-78
-75
-82
-88
-75
-86
-78
-89
-66
-98
-100
-78
-71
-92
-74
-74
-82
-88
-70
-68
-73
-62
-86
-77
-56
-74
-68
-88
-77
-60
-54
-73
-77
-103
-51
-51
-71
-60
-73
-74
-63
-62
-61
-57
-72
-66
-64
-53
-50
-65
-64
-72
-80
-89
-61
-90
-102
-65
-100
-88
-90
-77
-88
-73
-78
-87
-101
-111
-88
-90
-75
-107
-96
-89
-105
-95
-125
-88
-112
-96
-98
-112
-103
-101
-111
-114
-95
-101
-84
-100
-106
-96
-106
-106
-102
-105
-93
-106
-88
-86
-84
-100
-95
-99
-86
-88
-81
-99
-83
-99
-94
-78
-90
-76
-94
-83
-100
-102
-79
-79
-78
-72
-71
-89
-85
-80
-89
-81
-68
-85
-100
-73
-80
-90
-85
-80
-82
-89
-79
-81
-91
-80
-93
-73
-75
-73
-99
-77
-83
-72
-67
-73
-80
-74
-86
-71
-72
-57
-72
-75
-70
-74
-59
-48
-63
-58
-66
-52
-76
-67
-56
-57
-62
-60
-49
-76
-52
-81
-68
-76
-83
-76
-73
-76
-77
-94
-79
-79
-88
-77
-91
-103
-91
-111
-84
-76
-105
-98
-102
-75
-100
-101
-99
-92
-104
-91
-109
-103
-112
-108
-117
-106
-121
-103
-111
-115
-117
-118
-99
-125
-104
-124
-105
-118
-116
-82
-108
-96
-79
-101
-100
-90
-113
-95
-85
-91
-87
-90
-96
-86
-88
-71
-92
-85
-89
-83
-89
-96
-87
-97
-99
-93
-89
-86
-83
-98
-81
-107
-91
-103
-69
-91
-90
-101
-92
-87
-95
-86
-88
-74
-108
-96
-75
-91
-89
-87
-90
-90
-81
-77
-59
-78
-74
-71
-82
-84
-78
-69
-79
-70
-73
-76
-76
-81
-68
-52
-66
-75
-71
-75
-48
-70
-65
-54
-50
-82
-65
-69
-70
-70
-77
-88
-79
-82
-82
-82
-75
-92
-100
-77
-89
-103
-116
-78
-83
-99
-104
-114
-105
-110
-116
-103
-106
-96
-105
-114
-104
-109
-94
-115
-113
-109
-106
-111
-101
-96
-110
-112
-111
-104
-122
-117
-103
-98
-107
-90
-105
-101
-111
-103
-98
-111
-82
-78
-88
-89
-78
-88
-94
-94
-81
-101
-97
-89
-84
-94
-75
-89
-92
-80
-76
-119
-91
-87
-85
-87
-86
-98
-87
-76
-90
-77
-82
-104
-71
-93
-92
-80
-70
-88
-77
-94
-70
-88
-84
-71
-67
-88
-82
-81
-72
-74
-84
-58
-73
-53
-79
-65
-59
-64
-65
-63
-74
-53
-64
-57
-74
-63
-61
-49
-71
-49
-44
-75
-76
-95
-85
-80
-81
-82
-84
-95
-78
-83
-75
-81
-120
-96
-80
-90
-103
-112
-90
-101
-97
-101
-104
-102
-112
-112
-120
-114
-116
-105
-133
-94
-110
-125
-114
-127
-114
-137
-130
-117
-91
-115
-104
-106
-109
-115
-121
-117
-108
-93
-108
-106
-120
-100
-98
-107
-104
-95
-87
-110
-88
-98
-94
-84
-101
-94
-105
-79
-80
-92
-100
-88
-90
-84
-94
-92
-91
-122
-96
-112
-95
-94
-96
-83
-105
-87
-89
-89
-98
-92
-88
-70
-82
-78
-102
-82
-80
-87
-78
-63
-91
-86
-77
-67
-65
-88
-64
-89
-80
-76
-75
-68
-79
-72
-62
-60
-67
-73
-63
-82
-58
-68
-55
-65
-72
-73
-65
-66
-71
-88
-81
-89
-84
-81
-94
-84
-88
-85
-80
-88
-99
-108
-79
-116
-102
-82
-108
-106
-95
-107
-118
-110
-116
-107
-131
-130
-114
-143
-136
-129
-135
-131
-131
-115
-106
-134
-158
-105
-125
-117
-117
-116
-114
-112
-111
-121
-111
-104
-116
-102
-112
-102
-105
-108
-105
-116
-103
-114
-87
-91
-111
-102
-89
-104
-99
-104
-93
-90
-104
-115
-98
-98
-87
-100
-97
-110
-88
-85
-112
-107
-91
-92
-90
-96
-98
-129
-93
-77
-101
-100
-108
-98
-110
-98
-104
-90
-86
-96
-81
-84
-75
-86
-80
-71
-91
-76
-89
-82
-69
-70
-71
-94
-94
-67
-82
-78
-75
-71
-69
-66
-63
-62
-68
-74
-60
-67
-82
-66
-81
-84
-87
-81
-91
-92
-98
-98
-84
-93
-102
-132
-108
-88
-136
-108
-102
-105
-110
-90
-128
-98
-121
-124
-125
-137
-118
-112
-126
-128
-134
-112
-115
-127
-125
-125
-131
-133
-137
-117
-124
-125
-121
-115
-129
-119
-124
-118
-112
-116
-100
-118
-109
-138
-90
-114
-114
-103
-114
-118
-111
-97
-105
-119
-107
-115
-96
-94
-115
-109
-89
-103
-105
-95
-94
-97
-98
-127
-103
-100
-89
-91
-100
-105
-97
-95
-102
-112
-87
-94
-90
-91
-101
-102
-79
-78
-108
-91
-82
-96
-97
-75
-81
-83
-79
-90
-94
-76
-80
-79
-64
-85
-70
-60
-79
-68
-72
-80
-65
-65
-60
-58
-62
-68
-55
-99
-103
-83
-108
-88
-88
-91
-98
-104
-87
-117
-93
-97
-118
-121
-103
-123
-114
-107
-117
-116
-120
-114
-129
-101
-113
-118
-127
-110
-124
-139
-144
-121
-150
-140
-137
-147
-142
-152
-142
-159
-145
-145
-114
-114
-124
-131
-134
-140
-119
-134
-121
-139
-128
-127
-134
-112
-119
-106
-107
-97
-116
-117
-110
-104
-114
-116
-118
-91
-84
-111
-111
-106
-116
-93
-89
-105
-125
-107
-102
-116
-116
-118
-107
-101
-108
-94
-94
-106
-90
-93
-88
-98
-106
-113
-87
-108
-100
-91
-97
-77
-101
-89
-90
-100
-96
-88
-69
-78
-88
-98
-105
-66
-77
-64
-75
-60
-75
-77
-79
-70
-74
-66
-78
-63
-62
-69
-66
-69
-98
-110
-68
-91
-83
-85
-91
-104
-79
-98
-93
-100
-126
-117
-103
-101
-122
-132
-93
-109
-118
-114
-116
-125
-123
-114
-116
-122
-135
-132
-137
-149
-130
-146
-118
-143
-117
-142
-138
-155
-142
-134
-136
-145
-154
-140
-133
-133
-122
-140
-128
-130
-129
-122
-110
-125
-113
-103
-132
-115
-125
-110
-116
-99
-99
-105
-102
-106
-103
-104
-115
-92
-126
-121
-111
-116
-112
-124
-126
-111
-87
-105
-98
-108
-99
-139
-101
-128
-102
-118
-113
-89
-103
-103
-100
-107
-97
-102
-94
-84
-86
-106
-114
-96
-82
-91
-92
-85
-84
-82
-97
-84
-66
-84
-75
-87
-77
-83
-80
-74
-92
-53
-53
-62
-71
-71
-55
-94
-92
-77
-109
-94
-91
-105
-94
-97
-101
-119
-107
-127
-143
-114
-107
-125
-114
-125
-116
-128
-138
-136
-137
-123
-114
-132
-141
-126
-143
-164
-178
-144
-137
-137
-157
-149
-144
-182
-141
-163
-144
-152
-162
-142
-147
-137
-150
-160
-153
-140
-144
-149
-141
-108
-130
-155
-123
-120
-135
-103
-120
-120
-132
-107
-137
-133
-127
-92
-115
-129
-125
-133
-121
-92
-105
-142
-136
-127
-112
-117
-142
-119
-133
-128
-123
-105
-114
-111
-127
-122
-125
-122
-109
-113
-93
-114
-119
-100
-109
-107
-80
-85
-95
-104
-84
-100
-110
-107
-99
-95
-86
-83
-84
-73
-86
-82
-78
-73
-83
-80
-63
-58
-59
-70
-64
-57
-73
-90
-94
-97
-99
-90
-83
-109
-87
-106
-101
-108
-103
-93
-117
-124
-120
-126
-131
-107
-122
-124
-133
-152
-148
-136
-143
-138
-146
-152
-132
-174
-140
-177
-166
-134
-151
-149
-157
-161
-146
-155
-152
-189
-158
-179
-164
-158
-147
-151
-176
-137
-137
-157
-157
-153
-144
-142
-127
-146
-143
-144
-126
-145
-115
-126
-139
-144
-145
-135
-127
-119
-131
-136
-156
-134
-121
-133
-118
-150
-107
-143
-137
-132
-144
-115
-127
-124
-106
-113
-124
-133
-122
-116
-112
-138
-110
-101
-113
-103
-126
-98
-103
-118
-85
-117
-110
-75
-112
-96
-89
-79
-94
-86
-95
-84
-94
-97
-83
-79
-82
-85
-90
-63
-67
-83
-64
-71
-65
-87
-78
-93
-108
-123
-98
-117
-100
-114
-112
-106
-117
-111
-127
-115
-119
-115
-142
-146
-128
-131
-138
-121
-146
-165
-125
-156
-140
-154
-165
-158
-141
-179
-171
-169
-170
-165
-159
-181
-167
-153
-167
-175
-177
-167
-170
-188
-148
-158
-162
-155
-175
-154
-148
-142
-166
-139
-124
-151
-139
-95
-126
-114
-152
-128
-122
-121
-129
-131
-134
-121
-139
-118
-137
-147
-136
-115
-142
-150
-134
-134
-124
-154
-129
-120
-126
-112
-123
-132
-105
-121
-124
-115
-117
-124
-108
-125
-105
-106
-130
-98
-114
-95
-108
-99
-126
-97
-116
-110
-89
-88
-94
-95
-73
-101
-88
-92
-75
-74
-82
-85
-88
-78
-75
-69
-66
-64
-66
-95
-88
-95
-105
-88
-98
-92
-88
-113
-104
-112
-115
-89
-96
-113
-126
-108
-131
-134
-133
-124
-126
-137
-149
-158
-138
-150
-154
-162
-157
-148
-167
-181
-178
-175
-163
-186
-174
-184
-179
-187
-170
-173
-149
-190
-174
-169
-168
-171
-177
-170
-166
-157
-166
-135
-149
-151
-145
-148
-133
-147
-141
-124
-117
-126
-122
-126
-116
-111
-122
-128
-144
-145
-116
-140
-140
-141
-134
-124
-129
-141
-153
-146
-137
-134
-143
-127
-140
-138
-133
-123
-103
-134
-121
-129
-118
-116
-130
-122
-119
-134
-116
-90
-123
-122
-112
-121
-107
-101
-84
-90
-97
-89
-82
-91
-113
-92
-92
-79
-99
-81
-72
-76
-83
-73
-78
-79
-54
-101
-100
-91
-105
-101
-102
-101
-103
-98
-135
-124
-112
-141
-117
-101
-120
-115
-135
-142
-152
-150
-148
-127
-166
-136
-148
-137
-153
-166
-151
-202
-165
-199
-215
-173
-200
-179
-206
-219
-186
-198
-202
-217
-181
-192
-233
-205
-221
-187
-184
-164
-169
-197
-155
-166
-160
-155
-167
-145
-145
-161
-137
-136
-130
-117
-116
-136
-148
-123
-146
-153
-143
-140
-145
-141
-142
-151
-150
-140
-174
-168
-155
-154
-159
-140
-164
-149
-146
-136
-155
-142
-137
-154
-166
-132
-121
-158
-118
-135
-141
-123
-126
-114
-108
-138
-116
-92
-116
-89
-120
-101
-108
-88
-86
-100
-100
-87
-80
-106
-86
-77
-76
-71
-87
-90
-82
-70
-69
-102
-95
-105
-92
-98
-104
-95
-104
-104
-113
-101
-124
-128
-123
-120
-113
-136
-116
-127
-115
-124
-137
-132
-167
-145
-136
-160
-174
-169
-185
-182
-196
-177
-197
-181
-188
-173
-210
-179
-200
-193
-173
-210
-197
-200
-162
-193
-205
-172
-189
-180
-183
-187
-158
-160
-150
-175
-151
-137
-139
-153
-130
-139
-137
-150
-167
-146
-144
-136
-143
-119
-143
-138
-122
-151
-149
-131
-152
-169
-143
-177
-154
-165
-138
-154
-147
-157
-181
-158
-160
-166
-152
-142
-141
-134
-148
-128
-141
-138
-117
-128
-123
-126
-120
-111
-119
-110
-114
-110
-105
-103
-114
-96
-131
-79
-95
-91
-97
-100
-87
-99
-92
-89
-91
-75
-103
-73
-76
-109
-101
-107
-101
-107
-101
-110
-112
-97
-125
-116
-126
-131
-118
-141
-136
-146
-147
-118
-165
-131
-153
-189
-184
-151
-179
-184
-173
-209
-200
-207
-168
-208
-188
-194
-238
-216
-209
-209
-197
-216
-211
-185
-235
-199
-228
-231
-177
-197
-206
-197
-192
-183
-178
-154
-187
-169
-147
-172
-182
-176
-139
-129
-140
-141
-144
-149
-146
-135
-154
-148
-172
-167
-182
-165
-140
-154
-156
-196
-145
-176
-168
-149
-155
-182
-179
-165
-162
-157
-157
-174
-146
-134
-172
-142
-162
-157
-137
-138
-129
-132
-128
-132
-139
-128
-124
-122
-124
-117
-101
-108
-105
-114
-99
-106
-105
-93
-98
-102
-103
-96
-73
-97
-79
-82
-97
-78
-79
-91
-87
-107
-91
-96
-117
-110
-111
-105
-114
-140
-125
-151
-131
-132
-122
-138
-151
-124
-146
-161
-173
-168
-166
-193
-177
-165
-210
-189
-197
-193
-163
-201
-218
-215
-241
-229
-255
-237
-244
-220
-226
-254
-261
-257
-257
-214
-228
-192
-200
-202
-205
-222
-195
-188
-157
-165
-171
-179
-158
-166
-147
-156
-162
-124
-161
-130
-152
-143
-131
-141
-155
-120
-163
-164
-164
-166
-159
-160
-149
-147
-169
-186
-166
-179
-185
-164
-170
-181
-163
-150
-172
-164
-148
-161
-155
-178
-156
-155
-151
-147
-133
-149
-131
-145
-115
-135
-121
-110
-130
-105
-117
-105
-113
-126
-94
-95
-101
-87
-104
-84
-111
-78
-96
-90
-82
-93
-75
-105
-96
-98
-111
-124
-117
-117
-113
-120
-135
-141
-153
-152
-174
-130
-117
-155
-182
-178
-167
-173
-167
-162
-184
-177
-198
-194
-203
-191
-195
-222
-245
-220
-228
-211
-208
-220
-240
-237
-241
-245
-253
-215
-257
-257
-224
-218
-229
-215
-206
-204
-201
-193
-185
-175
-177
-188
-164
-165
-178
-157
-170
-151
-143
-129
-156
-140
-150
-149
-133
-173
-169
-136
-135
-135
-177
-157
-155
-187
-155
-153
-176
-196
-169
-174
-170
-178
-185
-184
-172
-194
-190
-177
-158
-152
-159
-130
-167
-152
-154
-135
-149
-132
-140
-118
-129
-142
-124
-98
-131
-111
-120
-97
-126
-115
-101
-110
-93
-82
-113
-92
-92
-79
-95
-66
-94
-96
-84
-114
-110
-96
-117
-114
-97
-115
-119
-115
-111
-134
-130
-102
-149
-142
-149
-163
-160
-152
-147
-185
-169
-181
-188
-187
-192
-164
-207
-202
-214
-228
-198
-212
-261
-219
-247
-247
-243
-218
-215
-266
-223
-263
-230
-243
-233
-223
-256
-217
-211
-183
-221
-212
-183
-206
-183
-173
-177
-165
-173
-168
-151
-145
-175
-152
-138
-149
-167
-146
-167
-160
-173
-166
-145
-163
-157
-173
-159
-176
-165
-171
-189
-185
-204
-168
-179
-192
-189
-182
-161
-167
-185
-160
-156
-171
-165
-142
-151
-153
-159
-133
-149
-146
-159
-134
-136
-137
-141
-118
-112
-116
-122
-111
-118
-98
-101
-116
-112
-117
-93
-99
-106
-87
-72
-90
-113
-95
-72
-110
-122
-96
-101
-126
-130
-137
-119
-119
-111
-151
-136
-149
-137
-149
-157
-163
-165
-175
-183
-183
-167
-187
-182
-189
-199
-211
-227
-245
-227
-220
-242
-267
-270
-233
-266
-249
-278
-230
-295
-285
-258
-234
-265
-264
-240
-245
-265
-221
-212
-225
-199
-183
-186
-209
-185
-167
-170
-174
-172
-157
-160
-158
-171
-150
-163
-168
-160
-186
-173
-154
-173
-132
-152
-172
-150
-153
-166
-179
-169
-203
-198
-164
-163
-190
-194
-175
-194
-175
-203
-177
-166
-179
-177
-167
-185
-174
-182
-162
-180
-152
-141
-153
-130
-137
-111
-142
-124
-153
-142
-119
-110
-140
-111
-108
-95
-96
-99
-89
-90
-111
-96
-107
-90
-65
-99
-82
-66
-101
-110
-115
-112
-121
-121
-125
-110
-109
-121
-147
-127
-156
-148
-174
-146
-149
-175
-177
-163
-175
-192
-162
-194
-228
-201
-209
-213
-250
-220
-242
-247
-272
-262
-260
-271
-288
-285
-255
-262
-247
-246
-265
-288
-278
-263
-259
-267
-254
-215
-213
-214
-210
-190
-207
-205
-176
-182
-186
-178
-154
-172
-178
-138
-145
-145
-156
-153
-151
-153
-139
-147
-147
-201
-171
-171
-194
-167
-185
-173
-182
-175
-180
-183
-212
-193
-163
-207
-197
-204
-185
-201
-207
-205
-192
-164
-177
-184
-167
-169
-155
-149
-156
-154
-162
-139
-148
-152
-143
-128
-141
-135
-128
-120
-124
-104
-109
-119
-112
-98
-100
-102
-115
-98
-96
-111
-82
-92
-117
-113
-123
-128
-135
-138
-121
-147
-132
-149
-147
-148
-171
-165
-160
-158
-181
-190
-193
-212
-185
-205
-229
-223
-189
-213
-246
-236
-246
-256
-286
-294
-250
-258
-285
-288
-279
-335
-266
-274
-312
-267
-279
-304
-298
-270
-264
-277
-265
-239
-235
-227
-197
-218
-211
-183
-206
-207
-178
-223
-175
-196
-189
-187
-155
-148
-143
-146
-170
-173
-176
-174
-164
-173
-159
-175
-162
-182
-184
-164
-195
-200
-201
-179
-200
-191
-203
-205
-213
-212
-203
-198
-199
-199
-191
-178
-168
-169
-170
-196
-173
-181
-168
-158
-153
-152
-137
-158
-137
-144
-143
-122
-137
-129
-116
-131
-103
-132
-93
-129
-82
-121
-84
-100
-98
-107
-84
-77
-100
-99
-104
-117
-142
-129
-150
-159
-115
-152
-143
-147
-147
-173
-163
-160
-164
-188
-185
-194
-179
-211
-224
-230
-231
-221
-213
-229
-237
-266
-277
-255
-274
-289
-286
-274
-285
-299
-299
-304
-303
-288
-282
-301
-264
-307
-301
-271
-261
-221
-249
-234
-212
-217
-229
-212
-212
-194
-168
-181
-183
-193
-162
-183
-181
-177
-153
-161
-175
-187
-187
-165
-158
-188
-182
-155
-196
-179
-181
-180
-194
-199
-221
-175
-190
-184
-204
-222
-198
-210
-228
-192
-209
-203
-201
-208
-189
-194
-214
-204
-181
-185
-154
-158
-175
-137
-141
-148
-154
-158
-134
-143
-127
-109
-122
-135
-133
-119
-118
-123
-103
-109
-100
-126
-114
-104
-95
-91
-118
-107
-132
-128
-114
-124
-134
-144
-166
-141
-147
-141
-143
-143
-165
-187
-189
-168
-178
-199
-196
-219
-234
-245
-237
-239
-240
-286
-239
-268
-304
-267
-330
-288
-277
-311
-344
-303
-322
-309
-305
-321
-332
-301
-314
-284
-271
-274
-261
-270
-227
-236
-242
-237
-205
-214
-208
-169
-197
-174
-172
-165
-169
-182
-150
-178
-159
-169
-182
-196
-171
-164
-175
-184
-178
-197
-177
-188
-207
-204
-203
-214
-161
-198
-223
-186
-223
-223
-214
-217
-227
-232
-211
-206
-217
-190
-195
-196
-182
-186
-177
-196
-180
-170
-193
-165
-152
-176
-133
-147
-152
-140
-115
-140
-145
-133
-133
-123
-111
-123
-98
-109
-104
-78
-93
-92
-100
-109
-121
-104
-115
-139
-150
-121
-142
-130
-156
-145
-141
-149
-133
-177
-188
-175
-183
-207
-213
-191
-200
-227
-217
-235
-250
-234
-261
-252
-274
-257
-310
-290
-298
-301
-332
-333
-342
-344
-343
-343
-306
-340
-326
-294
-281
-295
-263
-273
-246
-238
-242
-229
-244
-244
-239
-231
-212
-186
-213
-206
-195
-197
-188
-203
-174
-187
-183
-185
-163
-185
-173
-188
-174
-198
-188
-188
-204
-203
-198
-190
-210
-208
-218
-243
-234
-233
-206
-213
-222
-187
-245
-220
-207
-227
-216
-215
-218
-201
-209
-200
-186
-170
-197
-186
-189
-166
-162
-190
-168
-153
-159
-145
-149
-145
-140
-121
-113
-102
-143
-130
-110
-114
-122
-121
-114
-110
-114
-117
-124
-145
-135
-124
-123
-143
-126
-158
-142
-171
-146
-157
-143
-187
-170
-172
-181
-210
-213
-219
-225
-252
-215
-239
-259
-269
-284
-277
-260
-306
-339
-286
-313
-334
-315
-372
-326
-346
-359
-341
-358
-325
-321
-333
-333
-346
-307
-316
-272
-269
-298
-272
-227
-239
-232
-239
-241
-232
-213
-217
-186
-211
-193
-199
-164
-192
-197
-209
-184
-179
-196
-202
-158
-201
-206
-218
-199
-194
-214
-198
-206
-221
-232
-202
-210
-225
-212
-223
-234
-215
-205
-235
-252
-239
-253
-232
-215
-230
-221
-225
-212
-198
-196
-201
-175
-193
-168
-161
-154
-156
-169
-166
-158
-133
-140
-130
-147
-123
-122
-112
-139
-124
-113
-106
-93
-94
-101
-127
-124
-132
-120
-122
-127
-115
-130
-150
-136
-163
-132
-160
-164
-189
-178
-171
-189
-196
-209
-209
-222
-245
-205
-251
-253
-307
-298
-269
-296
-293
-294
-329
-344
-394
-330
-336
-363
-410
-342
-363
-340
-335
-316
-295
-385
-313
-314
-297
-258
-246
-267
-266
-247
-251
-236
-231
-225
-219
-191
-215
-225
-209
-197
-180
-164
-221
-185
-185
-192
-198
-183
-186
-185
-193
-210
-195
-206
-224
-180
-213
-187
-225
-219
-203
-232
-203
-230
-235
-247
-230
-215
-238
-247
-249
-246
-216
-238
-239
-249
-218
-196
-208
-205
-210
-206
-188
-184
-190
-170
-172
-178
-165
-133
-155
-153
-161
-152
-135
-124
-119
-130
-107
-101
-97
-122
-126
-112
-102
-123
-122
-128
-140
-129
-145
-151
-149
-140
-154
-156
-152
-155
-171
-178
-166
-194
-218
-217
-244
-212
-245
-232
-284
-254
-277
-290
-299
-345
-290
-361
-367
-316
-364
-373
-399
-375
-405
-377
-391
-388
-366
-341
-324
-329
-311
-301
-313
-266
-280
-242
-297
-270
-263
-246
-308
-251
-224
-212
-234
-230
-209
-196
-224
-173
-211
-184
-197
-174
-196
-204
-229
-188
-193
-209
-224
-212
-186
-226
-222
-208
-228
-218
-228
-215
-241
-217
-254
-243
-224
-257
-240
-250
-223
-263
-233
-226
-220
-219
-226
-212
-200
-190
-205
-190
-186
-203
-169
-184
-187
-170
-147
-152
-133
-162
-134
-144
-120
-123
-138
-131
-123
-111
-108
-147
-111
-129
-97
-126
-127
-125
-151
-132
-146
-142
-147
-150
-165
-158
-153
-175
-204
-206
-181
-191
-207
-210
-227
-229
-262
-225
-303
-274
-258
-281
-305
-313
-368
-360
-344
-337
-366
-369
-379
-399
-361
-367
-415
-398
-316
-344
-365
-331
-307
-335
-331
-303
-286
-312
-288
-317
-266
-283
-236
-253
-252
-221
-229
-251
-250
-232
-219
-190
-213
-215
-218
-216
-210
-213
-215
-201
-198
-209
-201
-212
-242
-215
-212
-226
-197
-237
-229
-217
-276
-239
-264
-245
-256
-276
-257
-246
-257
-272
-262
-254
-253
-250
-236
-228
-234
-230
-260
-185
-192
-197
-203
-203
-167
-153
-174
-151
-168
-118
-141
-137
-140
-125
-139
-138
-119
-132
-113
-123
-112
-116
-111
-134
-148
-139
-146
-139
-151
-132
-160
-174
-186
-176
-165
-166
-167
-176
-224
-194
-224
-218
-232
-246
-239
-287
-294
-291
-289
-295
-357
-341
-355
-389
-372
-432
-406
-417
-402
-404
-445
-403
-383
-366
-342
-354
-375
-341
-368
-334
-350
-315
-324
-312
-277
-298
-296
-262
-280
-280
-246
-257
-246
-241
-239
-186
-252
-231
-213
-226
-215
-213
-240
-209
-210
-218
-230
-246
-238
-249
-245
-265
-237
-233
-251
-227
-242
-272
-230
-238
-252
-254
-259
-271
-260
-291
-258
-247
-303
-252
-245
-264
-257
-248
-210
-235
-226
-227
-212
-202
-222
-196
-189
-209
-187
-146
-153
-171
-149
-160
-172
-141
-136
-130
-126
-130
-133
-144
-114
-100
-121
-104
-139
-125
-139
-134
-150
-139
-159
-159
-148
-161
-169
-204
-185
-201
-195
-204
-257
-209
-239
-247
-235
-270
-278
-276
-293
-330
-314
-357
-349
-370
-394
-401
-417
-404
-378
-394
-384
-383
-386
-400
-387
-369
-377
-349
-349
-347
-339
-336
-334
-292
-315
-320
-284
-280
-279
-287
-251
-250
-247
-257
-254
-236
-259
-240
-242
-212
-228
-209
-233
-207
-230
-216
-233
-221
-237
-205
-258
-250
-256
-236
-250
-257
-246
-247
-233
-236
-254
-286
-270
-251
-262
-267
-277
-296
-275
-253
-256
-263
-260
-265
-239
-239
-241
-205
-233
-206
-215
-193
-172
-198
-173
-176
-193
-148
-170
-172
-149
-134
-135
-139
-107
-138
-140
-122
-133
-109
-93
-128
-136
-107
-124
-144
-144
-163
-173
-178
-152
-192
-199
-193
-190
-238
-217
-196
-226
-212
-269
-289
-261
-280
-298
-320
-330
-295
-338
-372
-404
-468
-404
-431
-424
-448
-399
-445
-417
-411
-378
-399
-412
-356
-398
-351
-338
-380
-312
-315
-333
-318
-315
-299
-301
-299
-287
-314
-288
-263
-267
-249
-273
-265
-278
-238
-252
-218
-224
-217
-254
-225
-250
-244
-237
-228
-260
-219
-264
-246
-267
-264
-287
-225
-268
-274
-255
-242
-243
-254
-278
-293
-257
-319
-284
-263
-267
-266
-268
-262
-269
-239
-273
-247
-225
-226
-250
-215
-233
-189
-235
-194
-191
-204
-184
-147
-172
-151
-159
-130
-147
-123
-154
-142
-125
-131
-132
-112
-117
-117
-119
-136
-147
-147
-171
-149
-183
-165
-173
-168
-182
-194
-186
-192
-231
-197
-223
-236
-272
-272
-281
-282
-310
-317
-342
-355
-362
-382
-406
-466
-422
-396
-453
-445
-439
-447
-428
-411
-414
-413
-370
-390
-369
-365
-396
-407
-351
-344
-327
-324
-326
-309
-325
-299
-319
-316
-308
-303
-288
-278
-309
-254
-301
-231
-237
-236
-233
-254
-243
-261
-272
-253
-262
-262
-268
-252
-221
-289
-255
-306
-246
-311
-296
-281
-268
-297
-306
-278
-291
-285
-270
-275
-274
-296
-288
-286
-306
-280
-286
-292
-282
-281
-281
-248
-241
-240
-218
-233
-233
-201
-186
-190
-163
-155
-156
-179
-175
-148
-143
-169
-139
-112
-128
-133
-118
-128
-120
-140
-135
-152
-128
-138
-150
-149
-169
-168
-174
-174
-189
-199
-209
-214
-203
-247
-231
-257
-268
-285
-265
-314
-309
-324
-341
-354
-395
-361
-368
-414
-421
-447
-433
-411
-438
-446
-417
-429
-435
-388
-366
-384
-365
-375
-380
-316
-346
-357
-359
-328
-339
-345
-354
-354
-373
-289
-323
-298
-308
-304
-275
-272
-279
-274
-270
-227
-263
-238
-231
-250
-301
-247
-239
-254
-269
-265
-294
-305
-256
-267
-273
-240
-284
-268
-266
-266
-273
-295
-277
-285
-273
-272
-299
-281
-308
-276
-280
-291
-295
-247
-269
-288
-264
-231
-240
-245
-220
-197
-212
-206
-185
-180
-186
-148
-155
-138
-162
-143
-141
-126
-141
-135
-119
-118
-114
-131
-138
-111
-131
-138
-141
-124
-155
-145
-152
-163
-174
-187
-194
-220
-204
-209
-197
-252
-259
-257
-244
-269
-300
-335
-318
-359
-321
-397
-369
-360
-389
-409
-413
-408
-454
-415
-432
-412
-416
-408
-403
-413
-397
-419
-412
-389
-397
-399
-380
-369
-369
-373
-373
-341
-355
-352
-362
-362
-342
-341
-357
-316
-322
-303
-269
-304
-306
-256
-283
-298
-274
-283
-255
-261
-279
-281
-289
-296
-286
-278
-261
-259
-305
-314
-287
-305
-272
-290
-292
-284
-287
-276
-305
-327
-326
-302
-330
-318
-321
-323
-304
-292
-273
-291
-297
-287
-283
-273
-247
-236
-205
-216
-231
-223
-202
-210
-185
-159
-157
-165
-171
-158
-137
-147
-148
-134
-123
-137
-130
-111
-142
-131
-142
-146
-131
-150
-186
-178
-179
-201
-207
-223
-205
-218
-235
-249
-233
-255
-265
-267
-320
-297
-346
-367
-345
-370
-400
-410
-427
-428
-475
-427
-491
-463
-477
-421
-431
-399
-377
-453
-392
-395
-400
-416
-399
-376
-405
-394
-391
-367
-345
-368
-375
-377
-348
-347
-355
-348
-368
-317
-330
-318
-344
-285
-284
-310
-305
-312
-280
-305
-322
-294
-289
-273
-312
-330
-293
-313
-270
-315
-330
-267
-323
-310
-310
-305
-290
-317
-327
-302
-320
-313
-333
-300
-343
-303
-325
-320
-330
-353
-322
-321
-314
-310
-266
-269
-266
-235
-234
-185
-213
-179
-216
-170
-172
-192
-190
-171
-150
-160
-140
-131
-128
-138
-135
-118
-138
-134
-131
-137
-160
-158
-160
-172
-169
-178
-185
-187
-198
-180
-211
-213
-221
-226
-235
-287
-313
-266
-288
-338
-372
-320
-397
-407
-418
-498
-477
-478
-405
-488
-497
-466
-444
-434
-484
-452
-480
-453
-418
-404
-455
-401
-397
-440
-383
-409
-402
-352
-445
-405
-413
-396
-426
-384
-410
-393
-380
-396
-344
-339
-329
-360
-297
-324
-324
-327
-308
-306
-321
-326
-301
-335
-316
-319
-365
-356
-329
-307
-345
-324
-371
-332
-293
-317
-305
-315
-319
-343
-322
-349
-365
-332
-369
-324
-373
-368
-351
-347
-344
-345
-324
-319
-307
-279
-290
-248
-238
-243
-222
-199
-199
-195
-173
-182
-188
-185
-154
-166
-135
-158
-153
-149
-145
-109
-145
-122
-136
-147
-142
-145
-156
-133
-153
-177
-196
-188
-200
-182
-219
-235
-241
-250
-283
-261
-271
-263
-328
-343
-349
-376
-350
-425
-430
-455
-455
-463
-504
-501
-514
-424
-493
-447
-485
-453
-453
-437
-405
-447
-439
-421
-444
-420
-395
-407
-428
-370
-401
-400
-405
-389
-442
-389
-410
-400
-379
-377
-379
-350
-364
-327
-357
-364
-336
-371
-337
-318
-361
-310
-321
-357
-342
-324
-347
-336
-342
-295
-323
-346
-337
-338
-355
-332
-302
-349
-322
-330
-349
-305
-351
-321
-349
-329
-320
-328
-332
-317
-311
-314
-312
-281
-274
-276
-268
-262
-237
-234
-233
-210
-211
-187
-188
-188
-169
-156
-158
-143
-178
-145
-128
-142
-119
-124
-161
-118
-118
-155
-154
-150
-151
-167
-173
-193
-170
-168
-181
-179
-195
-235
-208
-250
-260
-273
-309
-271
-287
-321
-337
-354
-379
-411
-426
-438
-473
-437
-490
-514
-462
-474
-472
-475
-436
-407
-419
-431
-420
-434
-408
-437
-391
-384
-456
-423
-404
-385
-452
-424
-418
-442
-437
-390
-443
-434
-415
-376
-421
-383
-434
-365
-360
-326
-360
-400
-364
-358
-336
-351
-353
-340
-372
-349
-352
-371
-366
-351
-344
-341
-342
-398
-319
-333
-334
-358
-336
-336
-364
-357
-345
-331
-373
-352
-368
-358
-355
-333
-340
-355
-366
-332
-301
-299
-282
-270
-243
-236
-238
-247
-223
-187
-177
-162
-219
-187
-171
-177
-160
-144
-133
-125
-164
-145
-143
-124
-156
-160
-159
-144
-174
-171
-167
-194
-179
-185
-200
-190
-215
-209
-253
-224
-255
-270
-303
-305
-332
-358
-414
-378
-381
-406
-446
-446
-446
-477
-489
-463
-484
-482
-510
-446
-430
-395
-459
-431
-386
-422
-438
-441
-425
-465
-434
-444
-447
-381
-451
-417
-496
-458
-447
-457
-402
-434
-501
-440
-395
-433
-454
-424
-418
-397
-476
-401
-378
-416
-390
-378
-416
-403
-381
-397
-384
-413
-360
-369
-372
-340
-361
-354
-368
-364
-351
-338
-361
-364
-342
-381
-381
-347
-347
-368
-358
-374
-345
-341
-381
-336
-333
-327
-300
-278
-297
-288
-259
-258
-255
-232
-246
-223
-207
-222
-204
-168
-192
-150
-152
-156
-140
-166
-160
-153
-159
-143
-122
-132
-135
-150
-173
-162
-160
-152
-168
-172
-179
-209
-192
-231
-219
-248
-277
-285
-277
-312
-366
-328
-352
-369
-399
-408
-469
-427
-463
-452
-500
-480
-459
-446
-484
-476
-456
-446
-473
-433
-403
-448
-455
-422
-481
-466
-442
-455
-490
-465
-474
-468
-460
-487
-436
-446
-468
-483
-468
-472
-429
-519
-488
-439
-445
-435
-455
-403
-385
-442
-436
-378
-419
-436
-447
-421
-435
-431
-386
-387
-391
-376
-385
-376
-391
-339
-388
-385
-362
-385
-392
-350
-359
-365
-381
-421
-403
-339
-379
-407
-380
-404
-368
-352
-350
-343
-307
-322
-271
-282
-271
-265
-203
-190
-215
-207
-207
-201
-187
-175
-180
-164
-141
-175
-151
-142
-180
-140
-122
-156
-140
-162
-158
-154
-149
-175
-174
-194
-191
-230
-218
-223
-229
-233
-275
-257
-276
-289
-337
-311
-370
-400
-444
-453
-442
-480
-484
-508
-473
-521
-480
-426
-483
-432
-452
-445
-446
-455
-443
-483
-411
-453
-433
-434
-496
-457
-477
-441
-488
-457
-506
-488
-470
-500
-562
-475
-537
-485
-510
-426
-283
-174
-135
-148
-226
-328
-480
-476
-439
-473
-483
-438
-459
-430
-463
-401
-422
-403
-386
-390
-393
-383
-388
-422
-417
-377
-380
-385
-345
-373
-355
-338
-361
-345
-393
-377
-341
-391
-370
-389
-376
-365
-320
-303
-338
-312
-283
-294
-291
-203
-249
-245
-203
-219
-208
-203
-216
-179
-171
-161
-164
-165
-146
-145
-168
-116
-113
-141
-155
-143
-153
-156
-150
-141
-176
-172
-195
-203
-255
-219
-221
-249
-273
-231
-272
-292
-318
-335
-386
-360
-387
-424
-413
-438
-464
-479
-461
-460
-478
-475
-442
-459
-420
-433
-411
-461
-397
-423
-425
-464
-437
-468
-472
-441
-477
-456
-487
-472
-474
-465
-542
-517
-528
-548
-550
-494
-296
-64
-3
-1
-1
-0
-3
-23
-147
-382
-518
-451
-466
-457
-433
-448
-451
-457
-397
-438
-449
-394
-419
-401
-385
-378
-389
-386
-372
-397
-355
-354
-383
-431
-432
-387
-411
-398
-458
-381
-385
-373
-379
-356
-362
-357
-299
-298
-295
-252
-267
-225
-229
-232
-243
-190
-190
-208
-175
-190
-168
-162
-143
-150
-161
-121
-153
-133
-153
-140
-157
-149
-150
-187
-167
-171
-199
-221
-214
-225
-234
-226
-258
-253
-275
-265
-258
-291
-327
-316
-386
-364
-406
-448
-445
-449
-483
-506
-457
-447
-506
-470
-455
-485
-452
-437
-438
-448
-420
-436
-437
-431
-466
-469
-490
-478
-470
-472
-512
-456
-529
-547
-531
-591
-547
-564
-537
-201
-13
-1
-0
-1
-1
-3
-0
-1
-1
-65
-348
-507
-511
-472
-481
-492
-507
-469
-470
-465
-419
-434
-427
-405
-411
-369
-374
-428
-378
-405
-389
-392
-409
-387
-381
-375
-383
-396
-420
-382
-403
-383
-421
-354
-350
-346
-324
-307
-300
-262
-293
-265
-257
-245
-223
-234
-196
-217
-190
-186
-171
-157
-157
-141
-160
-128
-163
-151
-149
-167
-163
-157
-146
-153
-155
-165
-183
-210
-208
-224
-219
-221
-249
-261
-273
-268
-287
-327
-280
-377
-348
-402
-413
-421
-476
-486
-470
-425
-471
-476
-499
-423
-441
-431
-477
-448
-449
-493
-408
-460
-462
-442
-463
-466
-493
-461
-474
-467
-523
-528
-571
-534
-573
-608
-587
-627
-315
-16
-0
-2
-0
-1
-1
-0
-2
-2
-0
-1
-110
-444
-579
-535
-566
-547
-506
-507
-474
-499
-442
-430
-405
-477
-455
-413
-415
-375
-420
-453
-412
-394
-411
-417
-415
-400
-412
-401
-417
-461
-440
-412
-431
-376
-375
-333
-351
-352
-321
-271
-257
-252
-246
-229
-231
-201
-204
-193
-222
-200
-190
-182
-176
-167
-152
-137
-154
-129
-141
-140
-147
-158
-165
-173
-178
-176
-201
-196
-175
-196
-229
-212
-245
-250
-270
-302
-294
-334
-338
-343
-372
-420
-396
-457
-440
-456
-439
-474
-480
-473
-503
-466
-464
-441
-484
-436
-465
-459
-474
-444
-428
-430
-472
-464
-489
-513
-495
-509
-531
-565
-532
-528
-612
-580
-639
-503
-62
-1
-0
-2
-1
-2
-1
-0
-0
-1
-2
-0
-4
-225
-568
-567
-602
-541
-492
-533
-530
-472
-479
-423
-480
-452
-456
-398
-417
-424
-413
-407
-441
-438
-395
-387
-436
-407
-456
-391
-420
-433
-431
-439
-416
-392
-411
-360
-376
-318
-320
-297
-289
-251
-257
-267
-246
-229
-221
-178
-195
-185
-177
-178
-163
-174
-134
-140
-161
-125
-137
-135
-138
-134
-153
-142
-174
-170
-197
-189
-192
-201
-201
-237
-246
-245
-265
-267
-307
-286
-328
-319
-336
-358
-423
-384
-438
-466
-501
-471
-399
-479
-505
-451
-432
-495
-414
-413
-432
-440
-434
-429
-430
-446
-454
-491
-489
-459
-438
-477
-471
-527
-513
-555
-571
-552
-670
-309
-10
-3
-0
-2
-3
-1
-1
-3
-1
-1
-0
-0
-0
-72
-468
-572
-573
-506
-502
-532
-534
-456
-441
-458
-462
-470
-429
-457
-438
-422
-415
-482
-418
-435
-403
-421
-421
-393
-380
-387
-433
-434
-440
-396
-460
-408
-361
-386
-355
-322
-344
-303
-293
-259
-240
-221
-253
-196
-225
-188
-199
-200
-186
-174
-171
-156
-151
-150
-178
-139
-152
-163
-130
-122
-196
-148
-141
-160
-192
-203
-197
-226
-234
-238
-216
-240
-272
-271
-278
-317
-306
-343
-352
-370
-418
-412
-445
-435
-399
-516
-425
-427
-478
-427
-460
-435
-462
-436
-420
-481
-420
-431
-482
-450
-466
-487
-465
-477
-487
-491
-545
-499
-512
-561
-562
-635
-615
-168
-2
-3
-0
-1
-2
-1
-1
-0
-0
-1
-0
-1
-1
-27
-438
-617
-579
-575
-510
-545
-490
-447
-472
-483
-472
-458
-458
-428
-442
-442
-386
-459
-473
-430
-421
-423
-398
-420
-424
-406
-468
-458
-447
-424
-423
-383
-393
-347
-382
-344
-333
-304
-293
-279
-255
-232
-227
-254
-217
-223
-179
-182
-201
-176
-170
-186
-168
-168
-171
-140
-134
-126
-145
-161
-141
-139
-166
-164
-203
-211
-198
-190
-213
-210
-216
-247
-283
-278
-269
-288
-321
-346
-335
-357
-386
-452
-433
-443
-469
-495
-459
-460
-443
-404
-433
-454
-426
-421
-428
-450
-436
-462
-447
-474
-490
-503
-474
-501
-493
-474
-533
-537
-566
-514
-598
-655
-650
-132
-0
-0
-0
-2
-2
-0
-1
-1
-3
-0
-0
-0
-4
-7
-357
-628
-646
-559
-525
-567
-539
-540
-559
-490
-463
-490
-475
-468
-474
-455
-476
-446
-431
-461
-398
-412
-407
-496
-435
-458
-424
-427
-464
-431
-481
-422
-383
-409
-402
-324
-341
-309
-301
-267
-264
-250
-266
-238
-212
-222
-177
-193
-213
-183
-176
-148
-150
-150
-171
-123
-147
-133
-149
-164
-160
-171
-168
-179
-200
-231
-209
-207
-224
-260
-237
-240
-257
-288
-299
-298
-338
-360
-375
-370
-417
-435
-419
-455
-431
-400
-441
-433
-461
-424
-474
-417
-446
-430
-409
-451
-410
-437
-411
-433
-464
-486
-467
-459
-485
-495
-529
-555
-558
-553
-613
-574
-623
-138
-0
-1
-1
-0
-1
-0
-0
-0
-0
-0
-0
-1
-2
-14
-430
-636
-603
-530
-566
-586
-513
-530
-517
-475
-470
-479
-459
-417
-446
-449
-477
-425
-400
-405
-445
-411
-472
-405
-464
-407
-475
-443
-481
-498
-479
-400
-417
-386
-379
-334
-366
-286
-283
-264
-294
-233
-244
-201
-228
-199
-219
-153
-178
-169
-176
-157
-171
-154
-178
-134
-124
-156
-146
-152
-159
-154
-159
-179
-169
-187
-188
-195
-203
-236
-249
-237
-244
-262
-320
-286
-358
-326
-353
-326
-390
-404
-399
-432
-468
-464
-428
-480
-453
-400
-406
-454
-426
-414
-434
-418
-439
-419
-472
-428
-452
-509
-444
-484
-446
-495
-489
-516
-565
-565
-625
-616
-616
-195
-3
-2
-1
-1
-1
-0
-1
-0
-3
-0
-0
-0
-0
-24
-513
-641
-617
-601
-578
-563
-547
-505
-483
-471
-485
-499
-494
-439
-476
-443
-403
-439
-463
-448
-441
-461
-465
-446
-480
-456
-459
-494
-446
-453
-444
-443
-454
-415
-435
-359
-332
-331
-298
-300
-278
-261
-231
-241
-200
-213
-198
-215
-201
-186
-179
-162
-159
-160
-162
-139
-114
-136
-159
-144
-141
-158
-160
-158
-171
-166
-185
-214
-211
-232
-217
-235
-280
-264
-275
-310
-321
-302
-365
-361
-396
-390
-410
-404
-417
-416
-434
-448
-447
-359
-436
-407
-427
-407
-420
-426
-421
-421
-416
-413
-452
-471
-461
-450
-474
-498
-522
-523
-558
-561
-587
-590
-622
-394
-11
-1
-2
-0
-1
-2
-0
-0
-1
-3
-1
-3
-1
-82
-529
-588
-616
-569
-523
-562
-514
-522
-526
-498
-492
-469
-476
-430
-454
-439
-477
-460
-446
-458
-460
-440
-432
-450
-472
-443
-480
-448
-500
-478
-474
-404
-447
-423
-399
-362
-347
-344
-354
-300
-289
-263
-233
-224
-249
-212
-199
-190
-185
-165
-168
-141
-158
-177
-167
-131
-105
-135
-160
-142
-149
-164
-177
-181
-163
-200
-211
-207
-193
-229
-217
-244
-255
-273
-281
-295
-319
-332
-416
-365
-353
-354
-383
-424
-441
-455
-420
-426
-394
-455
-435
-416
-427
-416
-409
-423
-379
-417
-442
-440
-470
-435
-462
-428
-466
-471
-494
-481
-527
-541
-566
-593
-602
-526
-94
-1
-0
-0
-0
-0
-1
-0
-1
-1
-0
-2
-11
-354
-585
-597
-607
-589
-557
-582
-473
-521
-531
-498
-472
-484
-452
-440
-462
-446
-421
-460
-465
-464
-478
-490
-422
-455
-444
-503
-511
-477
-466
-478
-440
-464
-428
-416
-441
-336
-345
-328
-310
-296
-283
-269
-247
-234
-211
-242
-195
-212
-195
-176
-183
-181
-161
-166
-154
-147
-139
-140
-147
-151
-154
-155
-160
-152
-201
-178
-193
-214
-217
-226
-245
-229
-240
-283
-291
-291
-323
-338
-361
-363
-384
-390
-394
-429
-403
-445
-439
-428
-440
-409
-421
-373
-385
-432
-382
-377
-388
-416
-449
-447
-462
-437
-431
-436
-411
-479
-443
-462
-556
-521
-538
-494
-515
-593
-359
-29
-0
-2
-1
-1
-1
-2
-0
-2
-0
-0
-128
-549
-599
-491
-571
-533
-591
-518
-506
-533
-508
-446
-514
-494
-450
-437
-459
-487
-434
-463
-427
-405
-473
-421
-444
-430
-494
-457
-455
-493
-461
-477
-473
-435
-392
-421
-420
-361
-339
-331
-285
-309
-273
-233
-239
-236
-221
-208
-208
-200
-187
-188
-168
-194
-159
-161
-175
-117
-149
-148
-139
-157
-157
-135
-169
-148
-203
-208
-180
-176
-211
-193
-198
-228
-276
-278
-284
-281
-285
-300
-312
-322
-349
-401
-371
-388
-411
-404
-403
-410
-393
-402
-374
-369
-369
-330
-378
-429
-394
-434
-381
-410
-432
-431
-423
-368
-413
-419
-455
-470
-477
-470
-479
-482
-544
-514
-476
-233
-46
-1
-5
-0
-1
-2
-1
-2
-5
-114
-464
-559
-566
-560
-579
-519
-491
-468
-476
-530
-500
-458
-478
-504
-459
-417
-467
-466
-450
-461
-470
-465
-467
-504
-441
-438
-491
-423
-446
-443
-459
-460
-485
-447
-430
-399
-381
-377
-322
-336
-305
-270
-268
-253
-230
-229
-204
-215
-227
-193
-202
-165
-191
-188
-155
-162
-176
-131
-138
-144
-150
-144
-176
-146
-131
-167
-190
-170
-204
-184
-204
-207
-204
-229
-223
-229
-269
-287
-281
-304
-301
-330
-319
-341
-359
-356
-378
-411
-380
-373
-373
-339
-408
-399
-357
-422
-417
-354
-380
-368
-405
-371
-410
-415
-392
-396
-438
-409
-438
-408
-471
-418
-505
-447
-483
-486
-456
-472
-317
-109
-23
-9
-3
-2
-9
-45
-201
-404
-515
-531
-525
-487
-462
-494
-465
-452
-476
-506
-463
-484
-450
-467
-467
-404
-493
-388
-448
-492
-417
-428
-446
-438
-458
-387
-449
-444
-446
-486
-490
-492
-421
-451
-460
-381
-392
-338
-364
-321
-305
-291
-273
-251
-236
-211
-243
-231
-227
-204
-178
-193
-181
-165
-155
-172
-184
-138
-116
-136
-116
-145
-120
-145
-146
-175
-145
-190
-173
-196
-219
-203
-209
-227
-242
-232
-258
-256
-294
-329
-351
-318
-333
-366
-358
-381
-382
-405
-389
-386
-363
-372
-389
-374
-384
-421
-431
-369
-390
-368
-416
-376
-368
-409
-419
-416
-407
-401
-425
-415
-433
-448
-425
-390
-429
-461
-442
-396
-391
-388
-295
-207
-187
-187
-265
-358
-469
-448
-444
-454
-453
-481
-479
-458
-462
-467
-461
-473
-500
-477
-426
-480
-469
-446
-430
-448
-443
-458
-452
-435
-433
-461
-439
-435
-501
-444
-486
-497
-493
-521
-440
-448
-436
-396
-376
-346
-331
-340
-328
-309
-293
-260
-279
-246
-229
-227
-213
-213
-214
-165
-179
-167
-155
-172
-179
-128
-125
-124
-121
-153
-120
-161
-176
-168
-181
-184
-221
-209
-210
-203
-205
-225
-236
-235
-253
-253
-317
-281
-343
-355
-348
-319
-355
-396
-356
-393
-370
-356
-405
-359
-357
-371
-402
-369
-381
-361
-327
-351
-379
-423
-408
-379
-396
-366
-388
-404
-406
-341
-378
-375
-389
-383
-373
-382
-421
-345
-369
-362
-372
-345
-394
-395
-352
-409
-402
-388
-458
-418
-420
-424
-479
-440
-447
-431
-449
-429
-466
-427
-431
-421
-425
-410
-438
-446
-383
-416
-418
-424
-378
-419
-491
-419
-455
-424
-494
-482
-451
-457
-488
-464
-429
-407
-393
-346
-353
-314
-283
-288
-276
-264
-266
-262
-240
-201
-200
-201
-190
-179
-147
-160
-157
-169
-159
-108
-125
-131
-147
-130
-139
-164
-166
-141
-146
-158
-158
-179
-169
-207
-210
-210
-223
-244
-253
-237
-264
-259
-319
-294
-322
-344
-329
-341
-331
-354
-350
-373
-387
-364
-339
-359
-343
-376
-330
-332
-365
-330
-354
-334
-332
-378
-394
-339
-346
-357
-393
-361
-392
-373
-375
-375
-385
-338
-363
-338
-372
-362
-351
-337
-355
-347
-347
-357
-412
-410
-390
-366
-389
-399
-404
-420
-428
-415
-444
-430
-455
-416
-437
-457
-411
-401
-452
-442
-426
-420
-439
-459
-414
-444
-422
-420
-429
-441
-458
-469
-499
-471
-487
-414
-428
-405
-394
-360
-337
-324
-317
-310
-288
-255
-253
-220
-261
-232
-220
-220
-167
-159
-176
-169
-165
-156
-193
-121
-133
-137
-143
-140
-132
-145
-144
-157
-164
-174
-189
-202
-187
-213
-204
-227
-210
-246
-244
-250
-290
-280
-295
-342
-313
-341
-345
-309
-357
-348
-342
-393
-380
-353
-408
-343
-339
-367
-355
-327
-332
-309
-372
-329
-343
-337
-393
-338
-318
-325
-365
-388
-327
-350
-344
-327
-325
-367
-337
-316
-319
-297
-315
-302
-321
-321
-343
-336
-354
-376
-314
-372
-364
-391
-404
-411
-407
-396
-429
-378
-401
-382
-441
-421
-381
-412
-439
-433
-387
-416
-420
-391
-446
-422
-437
-387
-479
-449
-462
-457
-474
-444
-490
-453
-426
-377
-394
-330
-364
-292
-314
-257
-266
-252
-227
-234
-209
-195
-189
-213
-183
-188
-154
-162
-162
-147
-185
-127
-129
-128
-141
-136
-143
-152
-163
-156
-163
-152
-186
-149
-172
-193
-196
-179
-232
-214
-254
-273
-250
-266
-259
-305
-296
-305
-324
-350
-342
-349
-342
-342
-376
-326
-329
-343
-340
-350
-335
-321
-303
-349
-338
-314
-317
-331
-355
-330
-307
-301
-307
-326
-326
-303
-318
-336
-321
-299
-310
-296
-284
-292
-291
-277
-273
-305
-298
-320
-269
-312
-337
-381
-358
-351
-351
-373
-370
-365
-393
-392
-393
-389
-399
-415
-409
-387
-411
-422
-414
-393
-412
-384
-454
-407
-436
-433
-406
-444
-414
-489
-425
-491
-413
-396
-399
-387
-367
-343
-316
-318
-287
-308
-294
-267
-247
-223
-224
-222
-176
-197
-208
-159
-177
-152
-154
-149
-150
-112
-125
-128
-129
-132
-141
-145
-141
-153
-147
-167
-173
-164
-174
-191
-211
-207
-221
-240
-244
-235
-264
-220
-290
-282
-268
-313
-317
-319
-370
-325
-302
-332
-339
-326
-346
-302
-366
-316
-328
-356
-337
-311
-333
-343
-315
-306
-346
-281
-300
-326
-333
-325
-324
-305
-290
-316
-296
-291
-284
-260
-255
-249
-254
-249
-259
-264
-292
-289
-296
-307
-305
-336
-346
-339
-350
-332
-344
-374
-366
-359
-392
-345
-352
-404
-385
-392
-362
-379
-390
-380
-372
-398
-397
-423
-426
-426
-415
-423
-456
-448
-462
-443
-390
-398
-391
-380
-365
-356
-314
-270
-276
-243
-242
-209
-246
-240
-217
-190
-220
-205
-168
-167
-166
-169
-155
-136
-165
-113
-116
-135
-138
-144
-135
-129
-136
-162
-159
-153
-162
-188
-171
-173
-200
-209
-191
-191
-227
-240
-254
-277
-257
-249
-273
-268
-291
-339
-340
-322
-324
-308
-330
-298
-319
-336
-296
-325
-305
-310
-317
-297
-327
-325
-324
-290
-312
-314
-304
-328
-287
-330
-291
-289
-262
-286
-261
-266
-274
-273
-281
-257
-238
-266
-252
-262
-290
-272
-273
-278
-260
-324
-306
-296
-311
-352
-346
-357
-344
-355
-365
-358
-349
-392
-397
-373
-398
-379
-383
-374
-383
-363
-430
-409
-422
-397
-415
-471
-427
-436
-442
-430
-430
-393
-401
-343
-361
-339
-298
-292
-281
-280
-235
-244
-227
-222
-207
-202
-208
-180
-187
-169
-187
-151
-156
-158
-172
-114
-102
-121
-123
-123
-135
-137
-151
-139
-141
-167
-164
-149
-171
-184
-188
-178
-204
-166
-202
-229
-226
-254
-264
-218
-289
-312
-297
-312
-305
-324
-309
-314
-336
-282
-304
-336
-269
-291
-323
-279
-300
-310
-292
-268
-288
-298
-326
-260
-294
-255
-267
-281
-284
-280
-278
-277
-283
-265
-243
-265
-262
-220
-239
-205
-241
-217
-267
-237
-276
-258
-261
-277
-257
-310
-316
-344
-313
-340
-333
-354
-330
-362
-347
-380
-381
-348
-353
-377
-382
-412
-417
-393
-403
-393
-425
-405
-429
-408
-411
-451
-447
-453
-419
-397
-366
-367
-365
-311
-303
-266
-303
-236
-250
-256
-236
-222
-209
-233
-203
-175
-195
-187
-173
-158
-151
-128
-161
-127
-115
-104
-125
-132
-108
-109
-120
-122
-140
-162
-168
-169
-185
-170
-175
-181
-193
-193
-199
-234
-245
-216
-210
-297
-264
-248
-252
-258
-253
-304
-303
-326
-331
-314
-306
-319
-298
-283
-286
-307
-293
-289
-284
-273
-286
-290
-279
-273
-300
-269
-266
-254
-275
-233
-290
-237
-274
-253
-243
-256
-246
-219
-232
-233
-246
-247
-235
-239
-253
-284
-265
-275
-296
-275
-337
-333
-321
-359
-301
-311
-338
-342
-374
-374
-384
-351
-362
-417
-385
-372
-365
-379
-427
-421
-384
-417
-443
-407
-446
-433
-456
-417
-407
-389
-387
-362
-345
-301
-289
-290
-294
-259
-270
-225
-239
-207
-257
-200
-193
-199
-200
-171
-185
-170
-167
-160
-161
-121
-113
-126
-138
-131
-124
-129
-153
-152
-154
-144
-147
-160
-156
-175
-173
-183
-219
-176
-200
-214
-215
-236
-252
-251
-240
-267
-269
-316
-270
-305
-309
-307
-339
-330
-304
-298
-281
-273
-281
-337
-312
-295
-256
-280
-282
-269
-295
-242
-262
-246
-271
-265
-246
-259
-224
-252
-235
-241
-241
-218
-226
-227
-234
-213
-235
-215
-211
-216
-222
-230
-254
-257
-252
-270
-299
-286
-278
-277
-289
-339
-328
-310
-353
-339
-342
-314
-334
-363
-356
-407
-378
-398
-368
-375
-399
-379
-391
-394
-410
-413
-351
-410
-376
-365
-327
-318
-317
-285
-308
-276
-252
-252
-239
-200
-205
-222
-185
-178
-180
-203
-181
-176
-160
-125
-172
-150
-159
-112
-112
-108
-124
-126
-132
-144
-128
-133
-128
-142
-121
-139
-151
-159
-157
-168
-201
-188
-216
-200
-222
-241
-243
-260
-249
-271
-261
-248
-290
-296
-271
-273
-270
-289
-302
-280
-284
-295
-290
-289
-300
-277
-299
-279
-268
-287
-270
-275
-258
-249
-279
-270
-234
-231
-240
-229
-234
-239
-215
-226
-248
-196
-217
-205
-226
-225
-203
-213
-223
-221
-225
-276
-281
-243
-251
-286
-270
-295
-285
-307
-313
-314
-325
-337
-306
-343
-376
-384
-357
-333
-407
-379
-373
-375
-387
-392
-409
-417
-414
-409
-430
-408
-356
-360
-335
-304
-327
-319
-270
-258
-261
-256
-225
-233
-197
-188
-215
-205
-183
-194
-185
-161
-132
-148
-155
-136
-136
-117
-108
-95
-121
-130
-144
-144
-118
-152
-143
-154
-151
-162
-157
-162
-202
-204
-188
-206
-187
-177
-181
-213
-258
-230
-228
-229
-239
-264
-274
-273
-294
-266
-302
-256
-278
-260
-297
-277
-254
-270
-302
-286
-255
-316
-262
-265
-274
-239
-243
-230
-246
-220
-217
-244
-216
-221
-211
-225
-194
-209
-193
-188
-200
-216
-206
-198
-182
-210
-197
-192
-214
-252
-238
-273
-272
-254
-259
-288
-281
-267
-289
-304
-304
-348
-304
-313
-343
-353
-331
-357
-358
-372
-406
-382
-369
-407
-405
-411
-392
-393
-383
-396
-401
-343
-309
-307
-278
-297
-280
-222
-247
-239
-226
-211
-215
-199
-212
-173
-200
-180
-140
-159
-151
-173
-150
-128
-162
-104
-106
-126
-97
-129
-111
-120
-109
-110
-152
-147
-124
-155
-148
-153
-155
-170
-187
-189
-201
-195
-168
-216
-226
-207
-244
-238
-251
-241
-294
-290
-275
-260
-288
-274
-271
-271
-271
-288
-266
-299
-256
-255
-265
-255
-249
-233
-255
-243
-242
-231
-228
-239
-236
-218
-248
-218
-212
-227
-187
-180
-204
-183
-220
-191
-178
-175
-187
-210
-195
-196
-232
-236
-234
-237
-240
-258
-261
-273
-272
-278
-270
-279
-281
-327
-326
-299
-343
-331
-309
-342
-344
-320
-372
-370
-359
-354
-359
-354
-396
-382
-383
-338
-318
-322
-298
-302
-312
-266
-227
-257
-226
-192
-228
-212
-210
-219
-198
-169
-193
-171
-176
-180
-136
-157
-141
-129
-162
-104
-127
-103
-126
-122
-126
-125
-140
-130
-137
-159
-134
-126
-165
-163
-165
-162
-170
-179
-174
-176
-161
-214
-200
-184
-216
-244
-230
-249
-254
-257
-253
-264
-288
-229
-288
-277
-266
-250
-242
-267
-229
-224
-254
-269
-238
-234
-228
-209
-212
-210
-197
-203
-200
-217
-210
-192
-206
-187
-196
-180
-196
-167
-185
-178
-188
-174
-198
-166
-225
-200
-209
-201
-221
-207
-222
-227
-242
-262
-211
-240
-285
-253
-258
-308
-291
-289
-312
-299
-300
-349
-346
-351
-353
-333
-377
-354
-384
-351
-365
-401
-370
-330
-292
-292
-271
-276
-279
-252
-255
-268
-242
-215
-193
-185
-189
-217
-185
-177
-167
-151
-154
-147
-174
-143
-145
-148
-138
-111
-112
-106
-99
-118
-125
-105
-120
-115
-153
-137
-132
-149
-161
-123
-110
-185
-135
-163
-151
-168
-190
-180
-201
-199
-227
-222
-226
-228
-244
-215
-247
-262
-254
-231
-270
-272
-244
-277
-260
-240
-224
-223
-243
-250
-226
-241
-246
-204
-222
-195
-199
-177
-190
-196
-169
-228
-189
-172
-185
-155
-155
-165
-188
-186
-169
-187
-179
-160
-176
-204
-213
-188
-196
-216
-243
-230
-240
-234
-223
-256
-258
-259
-274
-257
-295
-301
-335
-290
-330
-341
-314
-345
-330
-374
-344
-346
-367
-329
-359
-341
-333
-304
-309
-318
-290
-277
-255
-227
-249
-228
-254
-231
-192
-180
-213
-201
-191
-178
-175
-177
-170
-145
-164
-150
-161
-140
-141
-99
-112
-100
-104
-125
-119
-112
-131
-143
-133
-124
-138
-123
-151
-157
-168
-160
-137
-158
-176
-168
-192
-231
-191
-201
-206
-222
-228
-216
-196
-236
-250
-253
-278
-261
-284
-261
-253
-256
-242
-246
-245
-230
-224
-214
-236
-199
-214
-220
-222
-230
-223
-183
-200
-192
-194
-194
-177
-181
-183
-172
-194
-167
-190
-169
-176
-155
-187
-136
-183
-178
-200
-176
-192
-224
-217
-223
-212
-220
-226
-243
-214
-294
-282
-277
-274
-277
-293
-290
-275
-317
-353
-328
-315
-344
-320
-311
-334
-319
-350
-334
-312
-307
-284
-263
-283
-275
-257
-206
-245
-251
-238
-206
-210
-214
-208
-177
-171
-172
-165
-175
-150
-161
-150
-135
-132
-128
-149
-104
-106
-123
-102
-117
-106
-118
-122
-117
-117
-121
-123
-125
-147
-150
-130
-173
-158
-154
-170
-174
-174
-186
-181
-180
-182
-208
-213
-216
-234
-211
-232
-251
-234
-240
-248
-242
-244
-240
-243
-231
-241
-223
-235
-224
-237
-221
-205
-217
-188
-180
-181
-186
-211
-188
-204
-193
-181
-187
-164
-157
-175
-165
-172
-150
-148
-167
-163
-153
-157
-176
-184
-190
-203
-227
-203
-218
-217
-234
-195
-225
-263
-256
-265
-252
-266
-253
-316
-300
-309
-274
-306
-320
-345
-365
-366
-364
-335
-284
-349
-336
-309
-305
-291
-254
-245
-251
-262
-254
-242
-243
-219
-199
-195
-180
-189
-175
-174
-177
-172
-162
-160
-161
-166
-167
-145
-149
-145
-94
-98
-102
-98
-99
-115
-119
-109
-132
-114
-113
-110
-121
-141
-145
-136
-138
-154
-139
-161
-157
-180
-176
-186
-173
-180
-187
-198
-191
-218
-220
-212
-249
-224
-240
-231
-234
-250
-209
-218
-248
-234
-202
-230
-222
-211
-217
-188
-208
-198
-178
-166
-173
-174
-201
-175
-172
-166
-149
-172
-166
-164
-156
-157
-164
-159
-156
-161
-152
-155
-172
-203
-148
-194
-176
-202
-197
-204
-214
-196
-187
-228
-254
-250
-246
-244
-260
-301
-298
-282
-302
-280
-289
-299
-332
-314
-293
-322
-292
-330
-291
-288
-292
-272
-261
-251
-232
-261
-190
-194
-200
-182
-202
-184
-165
-171
-180
-173
-164
-144
-146
-123
-126
-140
-136
-141
-132
-138
-102
-76
-103
-102
-115
-103
-108
-125
-121
-125
-122
-153
-136
-131
-129
-120
-137
-146
-142
-139
-152
-146
-177
-182
-186
-200
-184
-191
-183
-191
-224
-220
-221
-235
-211
-239
-236
-238
-231
-244
-211
-227
-247
-214
-214
-204
-189
-215
-171
-192
-189
-194
-186
-181
-184
-162
-166
-192
-145
-158
-176
-143
-139
-153
-128
-174
-168
-149
-155
-170
-156
-170
-172
-171
-189
-184
-221
-189
-207
-225
-220
-209
-212
-229
-225
-232
-265
-276
-294
-260
-302
-283
-338
-283
-301
-353
-335
-321
-294
-292
-257
-280
-262
-251
-244
-235
-225
-221
-220
-221
-221
-175
-245
-218
-150
-159
-150
-171
-168
-141
-171
-160
-124
-119
-118
-109
-119
-108
-87
-90
-111
-87
-107
-113
-107
-114
-111
-109
-112
-103
-127
-124
-126
-133
-156
-151
-151
-137
-160
-153
-154
-173
-163
-188
-189
-177
-219
-215
-192
-199
-225
-228
-207
-233
-216
-218
-205
-228
-215
-205
-223
-233
-210
-208
-173
-208
-222
-176
-194
-198
-175
-184
-154
-158
-161
-165
-162
-166
-120
-143
-187
-165
-131
-158
-161
-165
-159
-161
-161
-198
-142
-193
-188
-197
-183
-167
-244
-195
-222
-202
-218
-259
-251
-263
-270
-251
-271
-265
-304
-275
-288
-342
-284
-306
-282
-285
-300
-288
-272
-278
-252
-245
-225
-223
-206
-181
-198
-207
-168
-206
-205
-162
-161
-184
-158
-146
-154
-160
-179
-144
-132
-131
-134
-121
-140
-132
-78
-78
-92
-98
-79
-111
-103
-108
-104
-104
-112
-122
-119
-109
-122
-128
-110
-144
-135
-110
-132
-143
-149
-157
-165
-185
-163
-177
-183
-150
-219
-184
-169
-200
-216
-215
-213
-212
-206
-206
-198
-197
-209
-169
-190
-200
-196
-176
-192
-181
-172
-157
-165
-203
-152
-155
-169
-175
-146
-125
-153
-136
-145
-158
-144
-149
-169
-150
-132
-160
-151
-175
-140
-151
-180
-172
-175
-180
-194
-195
-204
-221
-232
-250
-234
-259
-245
-273
-264
-234
-293
-279
-265
-293
-304
-286
-280
-284
-282
-255
-245
-279
-230
-246
-198
-200
-207
-189
-212
-175
-189
-164
-204
-181
-183
-168
-174
-172
-151
-140
-132
-130
-128
-157
-115
-121
-133
-138
-85
-119
-107
-91
-100
-104
-83
-102
-109
-111
-109
-120
-101
-109
-133
-121
-118
-152
-127
-128
-138
-136
-156
-162
-147
-137
-171
-170
-191
-147
-186
-174
-179
-201
-201
-212
-197
-211
-188
-183
-231
-203
-207
-199
-213
-175
-167
-205
-187
-194
-182
-172
-159
-155
-157
-174
-159
-150
-137
-145
-134
-155
-130
-136
-132
-132
-150
-134
-149
-131
-129
-141
-168
-154
-162
-172
-179
-159
-175
-195
-214
-216
-197
-229
-230
-231
-258
-256
-246
-255
-253
-263
-279
-274
-289
-254
-255
-246
-266
-238
-238
-249
-255
-231
-213
-174
-204
-205
-188
-173
-172
-186
-164
-173
-169
-158
-147
-138
-170
-143
-140
-127
-116
-134
-155
-143
-122
-138
-73
-79
-76
-92
-89
-103
-91
-97
-112
-84
-93
-110
-112
-116
-109
-131
-126
-150
-115
-121
-120
-133
-152
-156
-144
-159
-177
-153
-169
-163
-166
-170
-167
-194
-184
-186
-191
-202
-198
-208
-181
-195
-196
-203
-198
-208
-181
-179
-171
-199
-172
-180
-156
-164
-152
-150
-163
-163
-133
-146
-149
-139
-140
-147
-144
-126
-145
-142
-157
-142
-145
-163
-162
-173
-179
-176
-189
-166
-195
-182
-199
-213
-208
-199
-219
-231
-241
-228
-237
-242
-226
-260
-248
-247
-230
-229
-253
-235
-231
-248
-225
-218
-234
-241
-186
-195
-200
-193
-186
-172
-166
-176
-174
-164
-141
-159
-153
-164
-154
-156
-141
-138
-142
-136
-125
-128
-113
-143
-92
-105
-94
-95
-82
-101
-98
-94
-107
-102
-104
-99
-102
-118
-107
-129
-97
-113
-137
-126
-96
-133
-151
-137
-156
-155
-131
-152
-153
-162
-135
-185
-143
-164
-158
-174
-180
-180
-199
-186
-172
-198
-178
-189
-177
-209
-189
-185
-162
-164
-158
-174
-152
-164
-161
-143
-125
-130
-140
-143
-128
-152
-124
-137
-105
-142
-144
-136
-131
-146
-136
-136
-153
-139
-165
-182
-164
-160
-167
-174
-157
-203
-187
-232
-218
-209
-234
-227
-230
-242
-258
-250
-245
-248
-228
-255
-243
-241
-259
-236
-215
-227
-194
-200
-198
-188
-191
-188
-185
-179
-167
-150
-157
-162
-146
-161
-159
-148
-142
-156
-118
-154
-130
-143
-128
-109
-114
-117
-81
-66
-93
-85
-79
-88
-81
-96
-89
-90
-95
-116
-107
-123
-113
-118
-101
-120
-110
-114
-121
-121
-140
-128
-125
-153
-148
-141
-161
-161
-175
-170
-162
-176
-162
-178
-159
-165
-192
-183
-209
-189
-172
-186
-181
-174
-151
-176
-184
-161
-166
-169
-161
-143
-162
-148
-140
-134
-138
-144
-119
-149
-127
-148
-143
-136
-135
-126
-127
-127
-149
-152
-159
-152
-148
-144
-146
-184
-194
-161
-197
-190
-191
-180
-213
-214
-217
-223
-226
-253
-225
-249
-218
-220
-230
-224
-197
-221
-223
-209
-208
-200
-187
-210
-199
-186
-190
-198
-171
-187
-180
-162
-173
-159
-160
-138
-139
-150
-127
-144
-145
-122
-126
-101
-108
-143
-104
-116
-73
-79
-81
-100
-102
-78
-106
-100
-101
-107
-101
-102
-121
-129
-103
-116
-102
-106
-120
-115
-124
-109
-127
-117
-134
-101
-132
-141
-142
-160
-140
-146
-146
-162
-154
-179
-174
-193
-140
-170
-150
-189
-190
-174
-188
-177
-163
-186
-166
-165
-142
-151
-136
-150
-163
-131
-131
-146
-137
-125
-136
-146
-139
-116
-127
-132
-116
-122
-127
-128
-143
-123
-142
-164
-131
-167
-152
-145
-178
-168
-207
-194
-182
-181
-203
-216
-185
-241
-202
-218
-210
-227
-228
-246
-214
-191
-209
-197
-203
-191
-202
-202
-212
-176
-179
-169
-182
-167
-139
-167
-171
-156
-160
-146
-147
-115
-148
-147
-122
-132
-124
-113
-120
-109
-115
-107
-137
-94
-72
-70
-94
-102
-84
-100
-94
-75
-83
-93
-81
-96
-98
-112
-109
-109
-102
-108
-112
-133
-106
-132
-124
-129
-123
-128
-163
-139
-131
-147
-136
-163
-160
-151
-148
-187
-160
-159
-158
-173
-165
-172
-192
-163
-161
-184
-167
-170
-163
-141
-153
-156
-134
-157
-133
-131
-140
-139
-148
-147
-127
-117
-113
-112
-141
-129
-139
-111
-154
-123
-129
-162
-137
-149
-181
-151
-154
-155
-169
-150
-179
-168
-177
-199
-191
-172
-201
-230
-175
-219
-198
-216
-213
-216
-201
-220
-228
-184
-219
-195
-194
-205
-181
-187
-178
-158
-159
-165
-156
-147
-160
-126
-133
-140
-139
-144
-136
-128
-129
-124
-113
-126
-114
-110
-113
-116
-119
-103
-70
-79
-93
-62
-86
-92
-85
-87
-73
-112
-104
-98
-98
-102
-97
-106
-102
-105
-104
-97
-139
-123
-127
-142
-124
-129
-140
-130
-142
-149
-144
-142
-171
-163
-154
-154
-136
-137
-155
-164
-133
-158
-158
-156
-169
-163
-153
-167
-158
-145
-151
-160
-160
-137
-133
-142
-129
-131
-114
-138
-115
-133
-135
-113
-130
-123
-117
-107
-124
-123
-123
-125
-131
-126
-142
-133
-147
-131
-169
-146
-146
-189
-184
-179
-177
-199
-178
-170
-208
-178
-194
-193
-176
-193
-176
-184
-184
-176
-196
-177
-182
-163
-188
-177
-169
-162
-129
-151
-138
-149
-151
-156
-146
-150
-119
-122
-156
-119
-120
-101
-103
-102
-110
-113
-82
-111
-98
-113
-83
-64
-90
-77
-78
-85
-80
-73
-89
-94
-88
-85
-83
-92
-88
-95
-92
-90
-99
-108
-134
-130
-108
-137
-131
-132
-112
-129
-132
-140
-123
-130
-150
-150
-158
-141
-142
-127
-139
-133
-164
-153
-151
-148
-169
-144
-149
-172
-139
-143
-140
-137
-141
-128
-144
-143
-136
-127
-98
-139
-124
-110
-129
-138
-123
-109
-124
-128
-123
-126
-141
-123
-125
-135
-137
-146
-151
-139
-142
-169
-174
-171
-184
-176
-194
-173
-177
-168
-172
-182
-212
-170
-183
-180
-192
-189
-171
-160
-189
-163
-183
-170
-191
-174
-145
-178
-158
-156
-156
-121
-150
-159
-130
-124
-146
-132
-108
-138
-118
-121
-118
-123
-124
-117
-100
-107
-110
-121
-70
-82
-72
-67
-66
-71
-65
-95
-86
-108
-87
-84
-80
-82
-85
-95
-97
-103
-110
-100
-104
-105
-106
-107
-103
-124
-131
-120
-120
-111
-127
-109
-125
-112
-120
-119
-122
-143
-119
-125
-146
-149
-149
-133
-157
-157
-158
-116
-132
-154
-132
-120
-114
-118
-121
-115
-101
-126
-111
-138
-119
-114
-133
-122
-105
-103
-109
-115
-118
-131
-120
-101
-123
-129
-125
-135
-133
-119
-148
-106
-130
-149
-161
-147
-173
-151
-141
-178
-159
-162
-164
-174
-156
-172
-183
-159
-151
-156
-149
-175
-136
-145
-158
-153
-130
-127
-146
-124
-143
-141
-144
-137
-134
-142
-124
-120
-122
-136
-106
-116
-133
-116
-99
-106
-101
-104
-104
-122
-68
-59
-72
-60
-70
-77
-80
-78
-80
-84
-76
-79
-105
-84
-92
-101
-111
-82
-91
-115
-105
-97
-97
-107
-116
-97
-112
-109
-111
-124
-117
-142
-121
-113
-119
-115
-105
-136
-125
-148
-142
-117
-129
-107
-135
-127
-137
-139
-135
-119
-118
-118
-125
-125
-125
-109
-116
-121
-110
-112
-117
-120
-128
-114
-105
-117
-112
-114
-127
-119
-122
-103
-118
-100
-132
-108
-132
-128
-130
-135
-143
-154
-152
-155
-169
-164
-148
-155
-153
-134
-139
-159
-149
-166
-164
-154
-145
-135
-158
-151
-135
-136
-153
-152
-155
-163
-139
-140
-135
-129
-114
-122
-117
-119
-121
-105
-116
-117
-113
-110
-109
-122
-102
-98
-105
-115
-100
-90
-64
-64
-66
-70
-84
-77
-93
-84
-79
-99
-79
-96
-61
-89
-78
-95
-96
-93
-85
-107
-96
-100
-95
-121
-127
-113
-121
-105
-132
-103
-99
-142
-130
-140
-142
-145
-136
-120
-127
-123
-120
-124
-116
-128
-122
-131
-123
-158
-128
-99
-128
-128
-116
-110
-113
-113
-142
-127
-130
-120
-105
-101
-111
-95
-109
-110
-103
-123
-100
-116
-117
-129
-111
-123
-104
-146
-123
-167
-139
-131
-141
-141
-134
-156
-152
-154
-155
-134
-154
-122
-142
-161
-158
-158
-168
-153
-142
-140
-163
-131
-128
-130
-117
-146
-140
-128
-148
-136
-126
-138
-133
-133
-114
-130
-110
-119
-114
-98
-126
-101
-105
-107
-104
-83
-102
-117
-87
-101
-73
-68
-82
-65
-54
-73
-83
-83
-74
-78
-74
-83
-72
-85
-88
-80
-81
-114
-88
-78
-95
-90
-113
-115
-111
-107
-94
-106
-87
-114
-105
-108
-102
-121
-112
-127
-114
-125
-118
-115
-124
-131
-130
-118
-126
-121
-128
-116
-117
-115
-125
-124
-145
-125
-113
-106
-131
-105
-107
-111
-101
-102
-94
-115
-124
-97
-106
-105
-117
-119
-114
-110
-113
-111
-99
-117
-108
-104
-116
-139
-122
-132
-140
-121
-121
-129
-136
-115
-156
-135
-147
-141
-133
-146
-166
-147
-149
-136
-143
-130
-148
-128
-134
-135
-139
-121
-131
-120
-113
-128
-128
-127
-122
-117
-137
-116
-106
-103
-104
-115
-115
-96
-123
-85
-98
-92
-98
-81
-60
-61
-74
-66
-76
-76
-78
-85
-92
-83
-82
-81
-93
-79
-105
-77
-73
-106
-90
-76
-70
-93
-101
-96
-83
-102
-93
-102
-98
-102
-114
-98
-119
-131
-112
-110
-115
-114
-114
-122
-130
-123
-120
-101
-97
-113
-142
-117
-131
-97
-112
-101
-101
-103
-110
-126
-88
-109
-103
-85
-99
-95
-99
-98
-87
-92
-103
-92
-100
-94
-112
-93
-114
-105
-108
-102
-125
-98
-108
-116
-139
-131
-124
-118
-128
-145
-130
-119
-134
-116
-156
-124
-155
-128
-121
-121
-133
-112
-121
-148
-151
-123
-139
-131
-130
-123
-98
-121
-135
-129
-106
-113
-142
-104
-119
-93
-108
-104
-99
-103
-86
-100
-103
-93
-100
-103
-91
-87
-66
-63
-60
-59
-79
-74
-71
-77
-74
-82
-72
-75
-69
-92
-80
-69
-68
-74
-89
-85
-84
-94
-90
-98
-103
-95
-107
-87
-93
-83
-78
-91
-96
-127
-88
-118
-108
-95
-82
-120
-99
-104
-116
-102
-115
-131
-125
-128
-107
-97
-117
-115
-121
-107
-123
-105
-119
-101
-110
-92
-96
-101
-80
-90
-94
-83
-106
-95
-107
-112
-97
-95
-99
-91
-104
-99
-104
-122
-124
-126
-110
-121
-137
-118
-127
-122
-114
-132
-126
-114
-123
-123
-110
-148
-107
-125
-136
-120
-117
-111
-111
-112
-109
-119
-110
-138
-118
-105
-102
-112
-152
-123
-122
-108
-95
-100
-98
-107
-116
-79
-105
-93
-91
-92
-84
-99
-87
-93
-52
-54
-56
-49
-75
-78
-66
-67
-77
-68
-64
-79
-68
-68
-74
-81
-75
-80
-76
-87
-75
-98
-92
-85
-91
-104
-97
-93
-97
-98
-101
-104
-111
-96
-108
-91
-111
-97
-87
-85
-118
-101
-99
-102
-106
-90
-125
-100
-104
-107
-101
-102
-109
-113
-99
-90
-116
-89
-103
-121
-91
-79
-102
-84
-81
-86
-111
-101
-91
-82
-106
-95
-95
-93
-99
-105
-107
-102
-109
-96
-124
-91
-112
-96
-117
-111
-121
-127
-113
-100
-126
-101
-104
-109
-129
-114
-131
-107
-114
-113
-110
-117
-137
-93
-125
-111
-111
-103
-112
-95
-104
-109
-120
-124
-99
-109
-102
-100
-83
-99
-102
-82
-101
-93
-83
-83
-78
-82
-59
-65
-73
-62
-68
-61
-57
-75
-67
-73
-76
-78
-71
-75
-69
-60
-78
-79
-75
-69
-77
-77
-78
-79
-82
-88
-82
-95
-88
-81
-81
-80
-94
-93
-97
-90
-99
-101
-97
-89
-98
-91
-96
-86
-104
-100
-105
-110
-111
-98
-105
-90
-96
-99
-96
-101
-85
-78
-103
-84
-79
-82
-95
-102
-93
-79
-79
-95
-85
-80
-84
-97
-105
-99
-111
-83
-107
-87
-126
-94
-101
-114
-101
-110
-104
-104
-119
-116
-120
-102
-104
-135
-114
-100
-106
-127
-145
-100
-111
-134
-111
-125
-108
-118
-110
-104
-97
-111
-117
-119
-108
-108
-124
-91
-104
-102
-95
-94
-102
-104
-100
-78
-98
-76
-120
-79
-74
-70
-60
-56
-52
-51
-51
-59
-61
-67
-64
-57
-64
-71
-64
-65
-67
-61
-57
-70
-77
-80
-70
-70
-81
-69
-78
-77
-78
-97
-86
-86
-74
-94
-93
-107
-81
-110
-105
-116
-91
-91
-100
-91
-83
-101
-85
-100
-88
-89
-96
-87
-89
-93
-92
-82
-90
-92
-70
-83
-100
-96
-75
-74
-92
-81
-90
-91
-101
-75
-99
-70
-82
-84
-86
-81
-91
-88
-102
-76
-105
-114
-121
-103
-109
-92
-98
-131
-114
-106
-117
-98
-113
-114
-120
-92
-107
-87
-118
-93
-119
-127
-95
-94
-99
-112
-100
-113
-102
-116
-83
-79
-72
-99
-111
-86
-90
-97
-98
-109
-93
-90
-81
-102
-67
-89
-85
-101
-75
-73
-55
-57
-59
-62
-61
-61
-68
-84
-75
-72
-69
-65
-72
-56
-75
-69
-70
-87
-95
-81
-76
-79
-73
-74
-77
-78
-93
-77
-83
-100
-85
-92
-95
-77
-82
-87
-95
-79
-91
-86
-83
-87
-101
-79
-88
-90
-102
-86
-83
-75
-87
-95
-101
-66
-93
-73
-97
-103
-72
-72
-95
-82
-73
-90
-87
-76
-83
-89
-79
-74
-86
-74
-90
-93
-96
-98
-84
-95
-91
-96
-102
-82
-76
-111
-101
-118
-90
-94
-116
-102
-129
-106
-128
-112
-103
-100
-104
-110
-112
-109
-104
-101
-114
-115
-119
-99
-116
-113
-108
-115
-93
-94
-105
-103
-107
-92
-82
-87
-84
-90
-79
-94
-78
-94
-80
-72
-110
-86
-60
-52
-66
-54
-60
-65
-69
-59
-86
-71
-72
-58
-69
-71
-67
-63
-73
-75
-84
-65
-77
-78
-89
-69
-79
-92
-84
-78
-90
-76
-84
-61
-84
-96
-77
-87
-82
-92
-86
-76
-84
-95
-71
-89
-89
-97
-80
-72
-93
-89
-79
-74
-72
-82
-98
-95
-96
-67
-72
-81
-72
-83
-91
-71
-78
-85
-79
-78
-75
-83
-91
-81
-95
-85
-91
-98
-88
-85
-104
-83
-86
-96
-72
-98
-98
-87
-97
-100
-107
-99
-116
-90
-103
-88
-93
-93
-107
-110
-111
-104
-97
-103
-100
-113
-123
-115
-115
-85
-85
-103
-100
-93
-96
-87
-73
-79
-87
-108
-59
-84
-71
-82
-75
-75
-64
-73
-78
-73
-54
-47
-53
-52
-55
-64
-56
-59
-58
-58
-64
-57
-52
-78
-58
-66
-73
-66
-67
-63
-79
-79
-71
-68
-74
-91
-75
-66
-68
-52
-85
-83
-86
-84
-76
-82
-73
-86
-89
-79
-87
-67
-65
-88
-85
-73
-79
-68
-77
-78
-80
-60
-89
-72
-82
-65
-69
-80
-66
-84
-75
-61
-56
-70
-81
-60
-83
-71
-84
-69
-72
-74
-76
-76
-104
-77
-67
-73
-82
-65
-93
-71
-92
-104
-88
-88
-88
-87
-97
-77
-93
-86
-91
-119
-100
-93
-86
-81
-99
-108
-94
-113
-91
-102
-100
-63
-89
-115
-89
-90
-99
-81
-95
-99
-102
-80
-82
-85
-72
-88
-88
-80
-73
-83
-79
-77
-82
-64
-46
-55
-59
-60
-62
-55
-73
-50
-61
-67
-77
-53
-58
-58
-70
-52
-62
-61
-80
-73
-56
-60
-63
-73
-58
-86
-60
-75
-58
-91
-80
-70
-55
-78
-80
-84
-79
-97
-81
-80
-70
-82
-88
-86
-68
-74
-72
-89
-78
-71
-73
-81
-73
-63
-62
-64
-78
-60
-75
-65
-67
-71
-68
-75
-72
-72
-76
-52
-72
-83
-65
-77
-81
-85
-75
-64
-71
-82
-79
-94
-103
-89
-80
-81
-82
-90
-76
-73
-85
-84
-104
-85
-72
-93
-96
-86
-76
-91
-89
-96
-106
-91
-106
-107
-85
-90
-89
-103
-89
-84
-88
-97
-82
-88
-88
-85
-66
-85
-71
-75
-105
-71
-83
-70
-93
-75
-77
-58
-52
-49
-58
-59
-47
-55
-51
-61
-60
-50
-61
-54
-47
-69
-63
-62
-75
-68
-64
-60
-61
-51
-68
-70
-83
-59
-57
-72
-63
-57
-71
-58
-76
-66
-69
-78
-76
-59
-67
-73
-59
-85
-76
-79
-76
-83
-87
-75
-66
-62
-66
-85
-54
-73
-80
-73
-65
-71
-71
-70
-58
-76
-71
-65
-73
-62
-77
-79
-67
-81
-78
-83
-64
-61
-59
-80
-74
-78
-82
-59
-82
-103
-77
-98
-66
-81
-81
-88
-69
-73
-94
-108
-89
-75
-99
-86
-76
-84
-98
-69
-88
-92
-97
-97
-82
-82
-93
-72
-86
-79
-101
-84
-76
-89
-89
-75
-80
-80
-72
-86
-81
-84
-95
-79
-78
-80
-73
-73
-46
-44
-62
-49
-39
-65
-56
-59
-61
-63
-54
-58
-66
-76
-54
-58
-63
-65
-82
-65
-57
-63
-77
-77
-61
-78
-48
-72
-75
-71
-60
-54
-77
-76
-67
-78
-64
-86
-67
-79
-86
-58
-50
-73
-85
-75
-89
-72
-82
-58
-70
-70
-76
-70
-82
-61
-70
-67
-59
-75
-61
-70
-54
-66
-73
-60
-48
-68
-64
-77
-62
-69
-91
-64
-71
-68
-69
-81
-91
-71
-71
-77
-92
-78
-83
-80
-64
-73
-72
-79
-65
-86
-75
-84
-82
-92
-76
-87
-83
-85
-105
-66
-79
-82
-94
-86
-103
-67
-58
-87
-81
-82
-87
-72
-77
-69
-76
-70
-80
-78
-71
-95
-63
-77
-70
-80
-68
-65
-45
-46
-53
-49
-43
-64
-70
-58
-63
-51
-57
-52
-51
-40
-58
-56
-58
-62
-64
-77
-66
-66
-56
-59
-57
-73
-48
-64
-82
-74
-60
-60
-68
-67
-65
-67
-69
-66
-89
-48
-66
-62
-73
-70
-56
-60
-66
-74
-56
-72
-67
-65
-72
-93
-51
-62
-53
-61
-59
-70
-67
-76
-74
-57
-76
-63
-71
-58
-54
-61
-71
-70
-68
-67
-58
-63
-61
-74
-74
-74
-72
-75
-76
-66
-71
-66
-77
-76
-75
-81
-83
-77
-86
-66
-90
-79
-82
-75
-83
-84
-97
-92
-91
-76
-87
-85
-84
-78
-66
-70
-90
-88
-72
-80
-78
-74
-75
-71
-75
-85
-74
-63
-70
-75
-75
-69
-71
-57
-35
-43
-48
-48
-48
-49
-52
-48
-60
-49
-54
-51
-47
-61
-59
-49
-63
-50
-68
-48
-54
-63
-54
-42
-60
-44
-45
-76
-47
-57
-67
-56
-73
-62
-48
-78
-65
-74
-70
-59
-65
-65
-57
-62
-60
-67
-57
-66
-66
-67
-64
-60
-59
-58
-42
-71
-70
-75
-57
-72
-72
-71
-70
-61
-47
-58
-57
-52
-57
-57
-61
-60
-65
-57
-73
-66
-57
-85
-74
-78
-90
-61
-67
-74
-51
-75
-79
-72
-67
-74
-78
-67
-83
-71
-65
-80
-72
-66
-78
-64
-87
-77
-79
-75
-70
-69
-74
-83
-62
-77
-71
-74
-63
-78
-75
-59
-77
-55
-56
-68
-63
-66
-66
-73
-61
-65
-55
-58
-50
-40
-49
-49
-67
-55
-40
-43
-55
-55
-48
-41
-46
-56
-57
-44
-51
-48
-60
-68
-69
-60
-61
-55
-58
-59
-75
-51
-67
-60
-62
-49
-73
-63
-64
-79
-69
-65
-89
-49
-52
-72
-70
-63
-65
-53
-59
-63
-49
-55
-69
-50
-61
-62
-56
-60
-60
-51
-60
-43
-49
-58
-54
-54
-47
-63
-55
-67
-49
-59
-57
-53
-55
-63
-60
-52
-62
-63
-81
-65
-58
-65
-82
-66
-67
-61
-66
-77
-51
-73
-62
-68
-63
-75
-68
-68
-79
-90
-86
-88
-79
-81
-69
-68
-82
-83
-88
-73
-89
-78
-65
-63
-64
-64
-72
-65
-76
-65
-71
-84
-76
-66
-53
-63
-78
-64
-72
-51
-52
-41
-48
-48
-48
-48
-54
-51
-45
-58
-47
-38
-64
-40
-41
-51
-46
-42
-57
-51
-52
-52
-53
-58
-52
-48
-74
-51
-67
-65
-54
-49
-64
-55
-74
-54
-56
-68
-58
-39
-77
-48
-62
-57
-58
-57
-54
-54
-61
-64
-57
-45
-56
-58
-52
-48
-59
-51
-59
-49
-69
-51
-53
-64
-56
-61
-58
-60
-63
-62
-66
-60
-60
-66
-55
-56
-68
-54
-53
-53
-61
-56
-66
-48
-73
-68
-73
-76
-77
-65
-67
-70
-73
-54
-68
-69
-68
-73
-60
-72
-81
-66
-63
-80
-75
-63
-76
-72
-86
-72
-83
-67
-77
-68
-76
-74
-63
-67
-70
-71
-54
-50
-59
-72
-58
-70
-68
-49
-38
-29
-40
-48
-43
-48
-38
-43
-52
-42
-50
-58
-45
-60
-38
-44
-43
-50
-45
-58
-71
-57
-47
-47
-48
-63
-54
-58
-78
-55
-64
-64
-64
-63
-53
-56
-62
-61
-80
-38
-55
-58
-53
-56
-76
-54
-51
-48
-49
-46
-48
-52
-49
-54
-61
-50
-81
-56
-50
-51
-56
-57
-47
-55
-65
-50
-44
-48
-47
-48
-65
-58
-50
-77
-45
-63
-58
-70
-60
-47
-72
-65
-58
-48
-55
-69
-71
-64
-76
-56
-60
-67
-61
-76
-70
-52
-71
-77
-82
-71
-74
-67
-64
-71
-66
-67
-69
-67
-74
-56
-69
-65
-87
-62
-73
-73
-73
-76
-71
-62
-60
-60
-62
-69
-70
-73
-51
-64
-38
-40
-40
-29
-42
-40
-46
-55
-49
-52
-41
-38
-42
-51
-42
-60
-53
-48
-54
-35
-61
-54
-64
-47
-59
-67
-50
-50
-49
-54
-46
-36
-53
-58
-52
-59
-54
-72
-48
-48
-54
-58
-69
-63
-58
-62
-68
-49
-51
-52
-48
-66
-51
-52
-56
-55
-39
-52
-55
-55
-48
-50
-50
-44
-64
-41
-47
-51
-60
-48
-51
-45
-50
-50
-44
-60
-72
-55
-59
-55
-48
-75
-60
-53
-42
-59
-51
-61
-62
-61
-64
-51
-65
-79
-69
-64
-65
-71
-63
-70
-54
-56
-63
-62
-57
-67
-71
-55
-77
-65
-65
-61
-61
-64
-71
-73
-54
-72
-51
-65
-56
-61
-57
-56
-52
-52
-38
-46
-40
-28
-40
-53
-44
-57
-47
-47
-48
-44
-44
-42
-33
-51
-49
-42
-40
-48
-53
-48
-47
-56
-49
-39
-55
-50
-47
-56
-46
-50
-53
-61
-54
-55
-60
-53
-55
-40
-48
-48
-48
-59
-45
-55
-51
-52
-55
-55
-44
-48
-54
-48
-51
-41
-43
-52
-45
-44
-55
-55
-46
-49
-55
-49
-55
-45
-38
-54
-48
-54
-62
-46
-61
-35
-56
-54
-54
-39
-56
-59
-67
-71
-71
-56
-55
-53
-59
-54
-64
-58
-72
-54
-70
-62
-59
-55
-67
-67
-73
-62
-60
-61
-72
-60
-68
-60
-71
-64
-58
-74
-77
-58
-54
-51
-57
-58
-58
-70
-46
-64
-51
-70
-41
-68
-64
-52
-65
-50
-33
-36
-47
-41
-40
-60
-50
-42
-32
-32
-42
-47
-33
-43
-46
-47
-55
-36
-50
-39
-50
-48
-62
-54
-53
-45
-50
-37
-55
-48
-43
-56
-47
-60
-50
-45
-49
-60
-55
-46
-61
-42
-53
-54
-41
-51
-57
-50
-45
-41
-56
-52
-52
-53
-54
-42
-46
-40
-46
-50
-51
-49
-53
-51
-49
-52
-49
-44
-52
-41
-69
-51
-60
-54
-56
-47
-53
-48
-63
-49
-59
-61
-51
-60
-57
-56
-62
-55
-48
-58
-55
-54
-61
-57
-53
-55
-60
-54
-62
-71
-61
-75
-55
-66
-55
-61
-74
-47
-52
-68
-72
-65
-59
-61
-74
-60
-60
-73
-49
-45
-50
-54
-62
-55
-60
-55
-51
-60
-36
-38
-46
-48
-45
-47
-48
-33
-48
-39
-44
-42
-37
-40
-32
-36
-52
-45
-41
-47
-49
-44
-37
-32
-55
-48
-51
-38
-54
-48
-62
-51
-50
-48
-42
-60
-46
-59
-51
-56
-51
-53
-53
-45
-42
-57
-47
-48
-39
-53
-54
-39
-50
-50
-47
-48
-55
-63
-50
-59
-44
-45
-57
-50
-63
-42
-54
-49
-45
-59
-47
-45
-44
-41
-60
-53
-56
-55
-54
-42
-52
-45
-45
-49
-57
-52
-50
-39
-62
-44
-61
-44
-50
-65
-69
-59
-55
-62
-51
-43
-61
-65
-82
-66
-52
-59
-53
-76
-63
-64
-59
-64
-57
-69
-58
-64
-62
-51
-67
-62
-63
-64
-56
-51
-60
-54
-52
-51
-37
-44
-39
-38
-26
-46
-32
-44
-50
-40
-34
-47
-47
-38
-35
-40
-50
-36
-32
-38
-50
-41
-51
-44
-41
-43
-42
-43
-41
-51
-44
-47
-41
-60
-53
-48
-57
-47
-51
-30
-46
-52
-40
-47
-45
-53
-45
-54
-36
-55
-53
-47
-50
-44
-34
-54
-48
-55
-47
-33
-47
-46
-41
-40
-41
-41
-53
-42
-39
-25
-42
-52
-56
-44
-34
-47
-46
-45
-58
-52
-47
-42
-47
-53
-31
-62
-57
-61
-46
-46
-56
-44
-44
-56
-45
-56
-60
-65
-51
-54
-58
-72
-61
-60
-62
-69
-74
-50
-51
-59
-45
-60
-59
-49
-43
-50
-47
-58
-61
-51
-54
-41
-67
-36
-60
-52
-49
-41
-44
-41
-40
-44
-34
-45
-39
-41
-46
-51
-36
-39
-25
-38
-44
-47
-46
-45
-47
-28
-40
-53
-45
-43
-44
-36
-56
-47
-47
-47
-55
-41
-53
-38
-43
-42
-45
-49
-63
-42
-54
-43
-45
-37
-45
-44
-45
-37
-45
-46
-46
-38
-51
-58
-47
-38
-50
-45
-39
-42
-40
-52
-45
-30
-44
-35
-35
-42
-32
-39
-45
-49
-41
-47
-43
-52
-33
-58
-49
-38
-42
-57
-47
-51
-45
-45
-38
-54
-50
-41
-62
-51
-55
-61
-66
-54
-48
-58
-61
-64
-50
-48
-69
-45
-57
-70
-47
-62
-50
-53
-66
-58
-49
-56
-59
-57
-50
-37
-54
-50
-69
-60
-55
-58
-55
-55
-62
-35
-26
-33
-45
-44
-27
-45
-32
-44
-44
-41
-30
-28
-34
-47
-35
-27
-44
-40
-49
-43
-43
-31
-46
-47
-54
-41
-39
-33
-38
-37
-48
-44
-40
-48
-47
-44
-41
-45
-41
-46
-40
-42
-54
-47
-37
-47
-38
-38
-43
-42
-39
-53
-43
-33
-48
-38
-45
-44
-38
-49
-38
-45
-52
-38
-48
-44
-38
-38
-49
-44
-41
-37
-55
-41
-48
-36
-41
-49
-47
-38
-51
-44
-42
-45
-39
-46
-46
-58
-44
-55
-38
-43
-67
-48
-48
-56
-52
-54
-77
-55
-45
-54
-67
-52
-54
-52
-57
-50
-63
-59
-62
-54
-44
-51
-51
-53
-50
-50
-55
-44
-46
-47
-50
-66
-53
-50
-50
-33
-31
-36
-36
-36
-29
-42
-46
-35
-47
-39
-33
-42
-43
-51
-39
-31
-48
-39
-34
-30
-49
-30
-37
-41
-35
-39
-46
-53
-42
-38
-44
-40
-33
-42
-35
-38
-31
-33
-44
-35
-42
-47
-35
-51
-34
-41
-38
-44
-44
-32
-38
-40
-27
-44
-45
-34
-39
-43
-44
-45
-54
-53
-34
-43
-30
-37
-38
-31
-41
-39
-45
-40
-39
-35
-46
-30
-33
-52
-45
-33
-45
-46
-45
-40
-42
-40
-54
-54
-51
-45
-53
-46
-47
-55
-55
-58
-60
-44
-62
-46
-58
-52
-52
-55
-44
-43
-57
-53
-54
-61
-55
-65
-52
-59
-61
-54
-59
-48
-47
-50
-47
-65
-58
-42
-53
-62
-56
-38
-32
-31
-46
-33
-28
-40
-36
-39
-34
-32
-37
-34
-39
-34
-41
-31
-35
-38
-38
-36
-36
-35
-36
-45
-38
-45
-46
-37
-48
-31
-36
-38
-49
-36
-45
-43
-36
-37
-39
-28
-46
-52
-41
-33
-43
-49
-52
-33
-52
-47
-61
-40
-34
-45
-34
-55
-43
-29
-33
-37
-57
-46
-44
-46
-35
-46
-41
-33
-40
-36
-51
-45
-38
-25
-36
-51
-39
-47
-43
-51
-50
-52
-40
-34
-44
-49
-44
-40
-43
-46
-55
-48
-53
-56
-51
-46
-71
-35
-52
-54
-60
-42
-53
-36
-57
-59
-59
-61
-58
-52
-59
-44
-57
-64
-50
-43
-50
-48
-50
-49
-53
-41
-61
-56
-57
-44
-46
-40
-55
-43
-70
-52
-49
-45
-54
-56
-61
-68
-59
-48
-54
-61
-41
-61
-52
-57
-87
-76
-54
-52
-58
-66
-60
-58
-68
-56
-51
-59
-68
-48
-59
-57
-71
-58
-64
-52
-60
-69
-68
-58
-63
-57
-62
-54
-60
-50
-70
-55
-75
-62
-63
-54
-69
-47
-46
-63
-76
-49
-52
-65
-69
-58
-65
-55
-64
-65
-57
-66
-51
-64
-68
-53
-64
-59
-71
-53
-64
-45
-87
-66
-87
-69
-72
-60
-70
-59
-76
-83
-77
-65
-79
-77
-71
-75
-71
-56
-90
-68
-70
-89
-63
-82
-79
-56
-74
-71
-93
-87
-70
-71
-80
-82
-79
-60
-78
-69
-90
-82
-58
-83
-75
-74
-70
-61
-60
-36
diff --git a/sasview/test/2d_data/HiResSAN14.ASC b/sasview/test/2d_data/HiResSAN14.ASC
deleted file mode 100644
index 811b1cc..0000000
--- a/sasview/test/2d_data/HiResSAN14.ASC
+++ /dev/null
@@ -1,36883 +0,0 @@
-FILE: HiResSANS_exp18_scan0014_0001 CREATED: 2008-02-11 18:52:06
-LABEL: Scatt 3m 6A cho
-MON CNT LAMBDA(A) DET_OFF(cm) DET_DIST(m) TRANS THICK(cm)
-3.6874e+05 6 1 3 1 0.2
-BCENT(X,Y) A1(mm) A2(mm) A1A2DIST(m) DL/L BSTOP(mm) DET_TYP
-20.981 95.891 60 40 17.495 0.13 76 ORNL CG-2
-SAM: RAW Data File: HiResSANS_exp18_scan0014_0001
-BGD: none
-EMP: none
-DIV: none
-MASK: none
-ABS Parameters (3-6): none
-Average Choices: none
-
-*** Data written from RAW folder and may not be a fully corrected data file ***
-The detector image is a standard X-Y coordinate system
-Data is written by row, starting with Y=1 and X=(1->128)
-ASCII data created Wed, Jan 14, 2009 3:28:21 PM
-
-74
-69
-58
-79
-60
-66
-58
-62
-70
-72
-61
-63
-59
-71
-76
-60
-67
-59
-64
-61
-49
-69
-63
-53
-55
-65
-61
-86
-64
-60
-55
-71
-54
-68
-63
-67
-68
-69
-65
-69
-70
-84
-65
-65
-60
-72
-61
-76
-70
-60
-58
-86
-53
-71
-80
-65
-55
-72
-64
-67
-67
-67
-78
-58
-60
-73
-79
-70
-72
-68
-51
-71
-65
-61
-57
-49
-61
-54
-62
-58
-75
-76
-69
-53
-51
-54
-69
-61
-59
-67
-52
-67
-57
-59
-61
-63
-72
-65
-57
-65
-62
-55
-58
-63
-61
-75
-66
-45
-62
-54
-54
-57
-70
-54
-59
-57
-59
-66
-48
-61
-85
-58
-39
-56
-56
-76
-48
-65
-55
-50
-53
-50
-47
-54
-58
-57
-50
-53
-50
-64
-46
-48
-52
-47
-49
-51
-41
-47
-49
-50
-56
-54
-56
-44
-55
-52
-48
-59
-48
-46
-49
-53
-35
-43
-42
-42
-35
-51
-44
-30
-41
-43
-35
-47
-39
-41
-41
-34
-35
-37
-45
-46
-46
-37
-31
-35
-40
-43
-40
-41
-33
-41
-22
-21
-32
-16
-22
-28
-22
-17
-23
-21
-31
-29
-23
-30
-30
-22
-22
-27
-32
-20
-32
-19
-26
-16
-23
-27
-26
-28
-21
-32
-25
-28
-23
-30
-21
-28
-29
-27
-24
-26
-24
-28
-27
-24
-28
-27
-26
-29
-26
-27
-18
-26
-22
-29
-22
-32
-38
-33
-23
-27
-30
-27
-21
-19
-31
-32
-23
-30
-15
-24
-23
-19
-31
-31
-23
-23
-28
-22
-24
-26
-19
-23
-26
-19
-29
-20
-32
-19
-26
-25
-17
-19
-24
-20
-25
-25
-23
-25
-14
-22
-27
-18
-13
-21
-22
-30
-22
-22
-20
-31
-28
-20
-31
-18
-13
-27
-18
-21
-22
-19
-21
-16
-16
-28
-24
-13
-20
-17
-20
-25
-9
-29
-13
-17
-21
-16
-23
-25
-16
-20
-15
-14
-21
-13
-19
-13
-16
-20
-10
-21
-17
-19
-14
-7
-19
-18
-14
-16
-16
-17
-13
-15
-15
-10
-15
-13
-18
-8
-10
-14
-14
-19
-13
-20
-9
-13
-9
-17
-18
-14
-7
-20
-15
-16
-20
-8
-12
-11
-13
-24
-8
-13
-37
-41
-17
-26
-36
-32
-25
-22
-22
-31
-33
-35
-35
-25
-21
-22
-31
-20
-37
-30
-26
-23
-35
-29
-30
-22
-14
-29
-23
-33
-22
-26
-25
-30
-23
-25
-21
-31
-33
-24
-32
-26
-24
-22
-26
-21
-19
-21
-22
-32
-31
-27
-22
-23
-29
-20
-38
-30
-24
-29
-28
-36
-24
-31
-33
-25
-19
-21
-31
-30
-31
-23
-24
-29
-34
-24
-13
-24
-17
-17
-20
-24
-25
-24
-30
-33
-20
-27
-17
-28
-28
-30
-37
-28
-23
-29
-27
-23
-22
-24
-30
-25
-29
-28
-25
-25
-23
-22
-21
-19
-21
-12
-20
-27
-25
-16
-23
-17
-22
-30
-23
-24
-20
-15
-26
-23
-14
-19
-19
-27
-21
-17
-23
-20
-29
-20
-19
-16
-22
-18
-18
-23
-14
-13
-15
-27
-19
-14
-14
-18
-21
-20
-16
-20
-22
-14
-27
-20
-11
-11
-18
-13
-19
-16
-16
-15
-14
-19
-13
-14
-14
-11
-19
-16
-12
-11
-9
-12
-7
-16
-15
-20
-8
-12
-16
-22
-14
-17
-15
-16
-16
-12
-32
-20
-25
-21
-18
-22
-22
-21
-31
-27
-22
-28
-30
-28
-42
-15
-23
-28
-27
-23
-32
-24
-30
-27
-29
-17
-21
-18
-28
-22
-27
-31
-32
-26
-25
-36
-21
-28
-26
-28
-27
-30
-24
-27
-18
-22
-39
-24
-25
-21
-31
-22
-32
-31
-23
-14
-15
-17
-21
-32
-20
-29
-29
-22
-35
-21
-30
-28
-16
-26
-26
-21
-21
-28
-18
-23
-24
-18
-25
-25
-20
-25
-32
-18
-20
-26
-19
-29
-26
-24
-24
-21
-29
-22
-23
-29
-27
-18
-23
-13
-20
-24
-21
-26
-16
-23
-16
-23
-14
-25
-18
-22
-27
-28
-21
-26
-13
-19
-19
-25
-31
-25
-26
-19
-22
-20
-14
-19
-18
-20
-22
-18
-17
-16
-21
-18
-19
-25
-11
-21
-17
-24
-14
-18
-15
-9
-14
-24
-16
-18
-11
-29
-26
-16
-23
-19
-23
-21
-8
-12
-20
-21
-18
-14
-14
-13
-17
-14
-18
-10
-21
-14
-15
-17
-23
-8
-19
-13
-18
-11
-18
-10
-15
-16
-15
-17
-14
-11
-11
-18
-15
-15
-28
-21
-21
-26
-26
-25
-19
-22
-28
-20
-27
-23
-23
-27
-19
-28
-24
-23
-30
-24
-23
-22
-24
-33
-38
-24
-28
-27
-26
-20
-21
-26
-30
-20
-22
-20
-18
-20
-16
-26
-27
-40
-29
-26
-28
-25
-26
-30
-45
-25
-31
-27
-26
-25
-21
-29
-18
-27
-25
-25
-30
-27
-27
-25
-18
-22
-13
-20
-28
-41
-31
-27
-30
-29
-26
-36
-22
-27
-32
-16
-17
-17
-25
-21
-28
-21
-21
-28
-16
-15
-22
-32
-27
-20
-23
-24
-27
-23
-30
-23
-24
-18
-27
-19
-29
-15
-25
-18
-24
-25
-21
-18
-25
-18
-25
-26
-19
-15
-19
-22
-29
-18
-15
-19
-24
-20
-17
-17
-20
-16
-19
-21
-24
-19
-15
-22
-17
-17
-19
-21
-18
-25
-14
-15
-24
-16
-18
-15
-15
-22
-20
-21
-14
-17
-17
-16
-13
-17
-24
-12
-21
-16
-19
-16
-15
-15
-15
-20
-12
-14
-13
-9
-15
-20
-20
-16
-19
-16
-10
-7
-22
-14
-10
-19
-10
-4
-15
-22
-13
-10
-11
-17
-20
-29
-27
-25
-28
-19
-25
-21
-22
-24
-25
-22
-26
-17
-26
-24
-20
-18
-22
-26
-24
-16
-17
-27
-24
-22
-18
-24
-27
-25
-32
-20
-21
-24
-29
-27
-18
-18
-27
-19
-33
-23
-22
-23
-24
-24
-25
-29
-23
-23
-21
-20
-21
-24
-16
-25
-22
-27
-37
-21
-18
-23
-15
-25
-25
-28
-26
-32
-15
-23
-17
-24
-25
-21
-17
-25
-16
-22
-22
-18
-16
-23
-26
-24
-31
-22
-19
-18
-22
-22
-23
-22
-24
-27
-22
-12
-21
-31
-15
-25
-25
-21
-18
-32
-23
-16
-26
-17
-21
-18
-28
-19
-15
-25
-16
-33
-17
-19
-22
-24
-18
-18
-17
-15
-19
-18
-15
-23
-18
-16
-20
-26
-19
-19
-17
-19
-22
-22
-18
-20
-15
-22
-23
-22
-23
-22
-21
-12
-9
-14
-16
-10
-13
-13
-21
-16
-19
-13
-18
-12
-18
-18
-14
-20
-15
-8
-13
-10
-11
-12
-16
-20
-20
-13
-13
-12
-12
-13
-7
-9
-11
-17
-13
-18
-18
-14
-11
-8
-18
-12
-8
-9
-22
-28
-21
-16
-30
-27
-35
-26
-20
-29
-18
-32
-16
-27
-26
-22
-20
-39
-21
-22
-32
-25
-22
-24
-27
-21
-19
-28
-24
-33
-27
-23
-28
-22
-28
-21
-29
-21
-22
-28
-15
-28
-22
-27
-26
-17
-25
-21
-22
-25
-19
-20
-29
-25
-34
-31
-24
-19
-17
-19
-32
-35
-26
-17
-33
-27
-31
-33
-25
-22
-21
-27
-23
-27
-28
-19
-27
-29
-23
-27
-34
-28
-13
-26
-26
-19
-18
-34
-26
-19
-21
-13
-27
-22
-21
-20
-26
-23
-20
-16
-24
-35
-20
-30
-29
-17
-30
-24
-23
-25
-22
-23
-20
-25
-19
-21
-17
-22
-20
-17
-14
-24
-18
-17
-20
-25
-22
-18
-18
-18
-20
-27
-21
-17
-21
-14
-20
-12
-19
-19
-20
-23
-20
-22
-20
-15
-26
-18
-19
-12
-21
-20
-23
-16
-12
-16
-12
-16
-10
-20
-14
-17
-15
-13
-13
-10
-11
-11
-15
-15
-18
-15
-16
-13
-17
-20
-11
-11
-18
-18
-15
-11
-12
-11
-9
-15
-9
-17
-18
-10
-10
-15
-34
-16
-21
-21
-22
-26
-26
-25
-22
-30
-25
-36
-23
-22
-25
-31
-18
-21
-29
-26
-24
-31
-39
-18
-20
-25
-21
-28
-19
-27
-25
-25
-22
-26
-29
-24
-14
-19
-29
-29
-23
-24
-17
-31
-21
-21
-18
-27
-30
-19
-22
-32
-28
-25
-17
-22
-22
-22
-22
-27
-23
-24
-25
-24
-21
-21
-19
-24
-17
-19
-15
-36
-22
-22
-22
-29
-25
-25
-17
-24
-18
-28
-20
-25
-23
-16
-19
-21
-34
-15
-25
-26
-27
-28
-18
-15
-21
-24
-28
-22
-25
-17
-27
-19
-25
-24
-11
-23
-21
-18
-17
-18
-16
-20
-10
-20
-26
-22
-19
-24
-23
-20
-23
-17
-30
-21
-21
-20
-14
-7
-20
-14
-12
-19
-16
-18
-14
-29
-30
-22
-25
-12
-7
-9
-20
-18
-11
-8
-20
-21
-14
-16
-13
-14
-18
-19
-22
-18
-12
-27
-15
-14
-14
-22
-17
-13
-16
-18
-18
-11
-15
-16
-19
-17
-22
-17
-4
-14
-14
-10
-13
-15
-20
-12
-12
-11
-11
-15
-9
-17
-14
-9
-31
-18
-17
-19
-25
-19
-18
-28
-13
-19
-26
-18
-22
-20
-22
-23
-18
-19
-19
-25
-27
-21
-20
-28
-21
-27
-20
-21
-25
-33
-26
-27
-25
-24
-25
-25
-24
-22
-28
-28
-26
-20
-28
-24
-22
-22
-17
-26
-18
-24
-15
-22
-25
-21
-25
-22
-18
-26
-21
-17
-29
-21
-28
-23
-26
-25
-26
-27
-26
-16
-31
-32
-20
-23
-29
-24
-20
-27
-29
-22
-28
-22
-33
-19
-27
-9
-25
-11
-29
-23
-24
-23
-26
-23
-10
-25
-30
-17
-24
-27
-24
-21
-17
-18
-20
-30
-20
-24
-18
-21
-24
-13
-18
-19
-15
-19
-17
-12
-16
-15
-19
-20
-14
-19
-19
-22
-24
-19
-20
-30
-22
-13
-15
-19
-16
-15
-21
-25
-19
-20
-15
-23
-18
-20
-19
-22
-18
-16
-17
-20
-12
-12
-16
-13
-16
-18
-25
-16
-19
-19
-15
-7
-9
-11
-14
-15
-8
-13
-10
-13
-15
-11
-12
-14
-17
-12
-13
-9
-12
-14
-15
-12
-12
-12
-15
-8
-6
-14
-11
-17
-18
-12
-30
-30
-24
-25
-21
-27
-19
-19
-24
-26
-32
-24
-24
-26
-22
-23
-17
-16
-25
-23
-25
-23
-25
-28
-27
-26
-31
-24
-32
-18
-29
-26
-21
-20
-31
-23
-23
-26
-24
-22
-24
-27
-27
-24
-31
-21
-27
-27
-13
-27
-27
-22
-22
-20
-24
-23
-21
-17
-18
-28
-18
-19
-24
-31
-24
-29
-21
-19
-21
-24
-25
-22
-24
-25
-23
-23
-26
-22
-29
-21
-24
-18
-26
-29
-17
-16
-16
-34
-24
-17
-27
-22
-28
-20
-21
-17
-29
-22
-22
-15
-24
-22
-22
-31
-18
-23
-23
-20
-25
-18
-22
-22
-20
-28
-25
-16
-19
-18
-26
-28
-21
-19
-14
-18
-20
-24
-19
-20
-28
-19
-25
-22
-26
-13
-18
-21
-16
-18
-9
-28
-21
-11
-15
-17
-11
-19
-23
-17
-15
-22
-17
-19
-16
-10
-16
-18
-21
-23
-17
-15
-24
-18
-20
-17
-19
-13
-11
-17
-8
-12
-15
-11
-14
-16
-21
-12
-18
-10
-12
-22
-14
-8
-10
-19
-11
-16
-9
-19
-18
-14
-6
-7
-35
-20
-30
-24
-21
-24
-28
-21
-36
-16
-31
-28
-23
-25
-27
-33
-31
-24
-28
-33
-21
-20
-31
-17
-26
-36
-31
-29
-26
-19
-27
-26
-24
-21
-19
-27
-24
-19
-20
-22
-24
-24
-28
-28
-22
-31
-23
-27
-33
-29
-23
-20
-25
-29
-27
-24
-18
-17
-23
-21
-20
-25
-22
-24
-25
-30
-23
-25
-30
-32
-25
-24
-24
-31
-32
-15
-20
-28
-27
-18
-22
-20
-27
-23
-39
-23
-17
-16
-33
-13
-29
-23
-21
-18
-23
-21
-24
-25
-25
-23
-20
-14
-18
-24
-17
-15
-16
-18
-24
-25
-21
-18
-28
-21
-21
-22
-19
-21
-17
-22
-16
-17
-24
-25
-16
-25
-12
-12
-22
-24
-25
-17
-27
-17
-18
-30
-24
-19
-16
-17
-20
-19
-14
-23
-18
-20
-24
-10
-15
-14
-16
-15
-15
-16
-13
-28
-18
-20
-22
-15
-12
-10
-18
-12
-8
-13
-16
-16
-18
-12
-20
-17
-4
-15
-18
-14
-16
-20
-16
-15
-12
-18
-11
-15
-14
-13
-12
-8
-10
-12
-12
-17
-32
-28
-24
-21
-22
-19
-24
-22
-16
-30
-31
-23
-28
-30
-25
-24
-30
-29
-24
-31
-18
-27
-17
-23
-21
-25
-24
-17
-21
-19
-22
-22
-22
-25
-40
-18
-25
-27
-18
-27
-18
-21
-25
-23
-27
-29
-21
-24
-18
-26
-18
-22
-25
-21
-22
-22
-25
-18
-20
-24
-22
-25
-21
-26
-27
-26
-25
-22
-18
-14
-25
-30
-33
-27
-24
-26
-20
-22
-18
-18
-20
-30
-24
-17
-38
-23
-24
-16
-23
-18
-28
-32
-27
-24
-27
-16
-25
-28
-20
-24
-17
-23
-15
-19
-16
-17
-20
-20
-20
-20
-17
-19
-27
-22
-20
-17
-28
-19
-15
-25
-20
-22
-24
-15
-26
-21
-24
-18
-19
-19
-15
-15
-22
-17
-27
-16
-25
-31
-16
-17
-18
-25
-22
-12
-17
-12
-15
-17
-26
-20
-16
-14
-19
-15
-15
-14
-23
-17
-25
-19
-19
-19
-16
-13
-15
-15
-16
-17
-28
-19
-10
-12
-15
-10
-10
-21
-18
-16
-13
-18
-18
-9
-15
-10
-8
-11
-18
-12
-12
-12
-16
-17
-30
-23
-25
-21
-27
-31
-17
-40
-31
-19
-28
-21
-24
-30
-28
-25
-28
-31
-21
-30
-28
-19
-26
-27
-28
-29
-27
-19
-23
-30
-32
-18
-17
-21
-23
-23
-30
-23
-24
-23
-29
-25
-22
-18
-24
-19
-20
-23
-22
-26
-28
-25
-25
-23
-23
-23
-19
-27
-23
-27
-24
-29
-32
-20
-21
-18
-34
-34
-37
-18
-25
-17
-25
-22
-29
-22
-25
-24
-16
-27
-31
-19
-26
-15
-20
-23
-21
-18
-22
-22
-19
-21
-21
-23
-24
-20
-25
-22
-26
-29
-21
-20
-16
-22
-23
-19
-19
-24
-26
-21
-22
-30
-21
-21
-26
-24
-18
-14
-21
-17
-19
-16
-22
-23
-23
-17
-20
-18
-18
-18
-12
-18
-19
-18
-21
-24
-17
-19
-10
-25
-14
-20
-13
-18
-12
-12
-27
-24
-19
-14
-21
-14
-20
-10
-13
-22
-20
-16
-15
-12
-22
-22
-12
-14
-14
-18
-12
-25
-14
-18
-13
-9
-8
-15
-18
-13
-14
-15
-12
-8
-10
-11
-16
-17
-11
-15
-16
-11
-9
-8
-13
-17
-30
-22
-27
-20
-22
-26
-20
-17
-21
-27
-18
-21
-23
-25
-24
-24
-29
-30
-15
-32
-34
-23
-31
-29
-21
-21
-29
-17
-33
-26
-24
-23
-22
-31
-23
-21
-32
-27
-27
-17
-21
-24
-21
-21
-26
-26
-36
-21
-21
-29
-25
-27
-17
-23
-18
-19
-19
-24
-17
-27
-33
-27
-31
-16
-30
-24
-28
-28
-26
-25
-17
-33
-32
-21
-24
-20
-30
-23
-23
-22
-24
-24
-26
-29
-18
-27
-25
-20
-21
-28
-26
-14
-19
-19
-23
-20
-22
-23
-14
-23
-20
-22
-22
-24
-18
-19
-19
-28
-17
-26
-21
-20
-21
-24
-18
-27
-17
-14
-22
-17
-29
-15
-15
-19
-22
-22
-21
-17
-12
-14
-15
-25
-23
-16
-26
-16
-28
-17
-18
-21
-20
-27
-18
-18
-31
-15
-21
-10
-25
-21
-17
-20
-18
-29
-16
-14
-18
-16
-15
-11
-18
-17
-24
-16
-16
-19
-18
-15
-19
-11
-17
-18
-15
-9
-12
-14
-12
-14
-18
-13
-24
-14
-16
-14
-10
-10
-13
-18
-10
-3
-12
-10
-24
-19
-18
-12
-27
-29
-21
-18
-22
-26
-31
-32
-23
-26
-22
-28
-25
-23
-26
-27
-26
-29
-23
-29
-17
-30
-19
-27
-30
-20
-17
-24
-29
-26
-24
-25
-17
-17
-27
-20
-31
-21
-35
-26
-15
-22
-23
-26
-31
-17
-34
-24
-25
-21
-20
-17
-21
-33
-30
-26
-29
-27
-27
-31
-28
-22
-29
-17
-33
-19
-28
-21
-15
-19
-25
-18
-20
-26
-14
-18
-24
-20
-24
-20
-27
-18
-27
-30
-30
-17
-21
-31
-18
-29
-17
-18
-23
-27
-27
-21
-19
-11
-33
-29
-27
-17
-24
-23
-22
-19
-20
-19
-22
-13
-18
-12
-19
-15
-24
-29
-19
-26
-14
-22
-21
-19
-14
-17
-19
-23
-29
-22
-30
-30
-14
-25
-12
-22
-15
-25
-16
-21
-27
-26
-12
-15
-18
-11
-19
-17
-20
-21
-20
-20
-9
-23
-19
-13
-16
-22
-9
-20
-16
-18
-20
-17
-9
-25
-15
-15
-15
-15
-15
-12
-18
-12
-20
-17
-17
-15
-11
-7
-17
-21
-15
-19
-10
-12
-13
-10
-12
-14
-22
-30
-17
-15
-26
-26
-27
-26
-21
-23
-25
-31
-22
-31
-32
-27
-31
-35
-34
-30
-30
-27
-25
-29
-33
-30
-28
-24
-21
-20
-25
-20
-26
-26
-36
-30
-26
-26
-26
-25
-24
-33
-24
-27
-36
-28
-29
-25
-27
-24
-26
-20
-26
-27
-20
-21
-28
-22
-22
-27
-20
-20
-26
-29
-22
-22
-23
-27
-14
-26
-19
-27
-15
-24
-22
-20
-30
-33
-23
-22
-19
-30
-21
-27
-21
-16
-29
-17
-18
-30
-31
-22
-19
-16
-17
-33
-27
-19
-22
-18
-15
-26
-15
-17
-18
-24
-25
-24
-7
-26
-23
-32
-33
-24
-20
-16
-25
-19
-21
-15
-20
-17
-21
-26
-15
-29
-18
-20
-25
-16
-27
-21
-25
-16
-17
-20
-20
-21
-19
-17
-22
-23
-11
-15
-10
-20
-22
-13
-23
-22
-25
-11
-20
-29
-26
-14
-18
-15
-11
-17
-17
-14
-18
-16
-10
-15
-20
-18
-21
-11
-14
-13
-15
-13
-23
-9
-19
-11
-17
-12
-11
-19
-10
-15
-11
-13
-14
-11
-20
-10
-13
-18
-28
-25
-23
-26
-26
-28
-20
-24
-27
-28
-26
-25
-20
-23
-24
-25
-27
-20
-30
-24
-25
-23
-27
-29
-18
-18
-30
-31
-35
-29
-34
-29
-29
-20
-24
-21
-26
-29
-35
-31
-23
-19
-20
-26
-26
-27
-32
-18
-22
-22
-25
-25
-18
-29
-36
-23
-23
-21
-25
-29
-23
-26
-34
-21
-26
-20
-21
-39
-24
-28
-17
-18
-21
-27
-17
-24
-16
-29
-35
-27
-13
-24
-22
-20
-20
-23
-42
-23
-19
-24
-21
-29
-16
-23
-15
-22
-22
-25
-30
-24
-22
-16
-20
-20
-16
-24
-20
-19
-18
-26
-13
-21
-18
-20
-12
-25
-20
-22
-19
-23
-27
-16
-24
-23
-23
-17
-21
-23
-19
-20
-24
-20
-23
-22
-14
-29
-15
-17
-21
-23
-15
-16
-16
-14
-16
-14
-14
-19
-15
-18
-15
-10
-19
-19
-27
-19
-19
-15
-8
-16
-20
-14
-14
-13
-24
-11
-14
-16
-15
-14
-14
-18
-26
-8
-13
-8
-9
-11
-11
-20
-14
-17
-14
-10
-17
-13
-17
-14
-18
-14
-17
-21
-27
-23
-29
-36
-19
-30
-31
-27
-19
-29
-24
-27
-27
-29
-33
-21
-23
-29
-27
-20
-34
-24
-19
-26
-30
-30
-38
-34
-21
-28
-28
-19
-22
-19
-31
-33
-26
-18
-30
-25
-31
-24
-28
-38
-25
-33
-27
-27
-23
-21
-23
-30
-26
-30
-23
-27
-23
-24
-16
-32
-19
-23
-29
-27
-20
-21
-18
-26
-24
-32
-28
-27
-31
-22
-24
-24
-28
-23
-21
-25
-26
-21
-18
-21
-23
-24
-27
-26
-23
-17
-24
-26
-15
-24
-22
-22
-26
-21
-20
-14
-21
-18
-19
-20
-17
-22
-23
-24
-26
-26
-17
-20
-30
-16
-17
-14
-19
-24
-20
-24
-13
-13
-23
-22
-22
-17
-21
-24
-20
-15
-13
-25
-15
-19
-19
-18
-17
-15
-16
-22
-16
-18
-29
-16
-21
-16
-12
-23
-18
-17
-20
-10
-13
-21
-20
-20
-20
-23
-18
-21
-17
-14
-22
-10
-11
-17
-12
-17
-14
-22
-12
-15
-18
-13
-11
-15
-20
-16
-13
-18
-18
-12
-9
-19
-11
-16
-12
-14
-13
-12
-11
-17
-31
-20
-33
-28
-25
-28
-33
-37
-27
-35
-37
-24
-23
-22
-20
-38
-23
-24
-27
-20
-33
-23
-26
-40
-31
-23
-25
-19
-35
-24
-30
-29
-23
-17
-26
-32
-22
-29
-24
-35
-27
-34
-34
-23
-21
-32
-29
-18
-24
-20
-21
-19
-25
-23
-30
-18
-32
-34
-22
-27
-21
-26
-24
-27
-24
-17
-30
-22
-30
-26
-21
-26
-32
-29
-32
-30
-27
-24
-33
-15
-24
-28
-20
-32
-31
-26
-28
-19
-31
-26
-32
-25
-20
-24
-16
-18
-27
-22
-21
-30
-23
-24
-18
-18
-24
-35
-27
-41
-19
-13
-27
-25
-23
-23
-24
-27
-24
-23
-21
-18
-15
-23
-16
-18
-20
-19
-24
-17
-13
-14
-20
-26
-19
-21
-32
-17
-20
-22
-15
-25
-22
-16
-23
-14
-18
-21
-19
-22
-16
-13
-25
-14
-17
-27
-18
-15
-24
-21
-13
-16
-19
-12
-19
-17
-15
-22
-18
-20
-21
-14
-11
-16
-16
-13
-13
-22
-17
-16
-19
-8
-12
-18
-11
-10
-12
-16
-11
-10
-12
-10
-12
-16
-25
-26
-21
-26
-28
-32
-23
-24
-26
-30
-27
-28
-23
-17
-17
-16
-40
-33
-16
-24
-30
-26
-31
-28
-23
-26
-28
-29
-20
-34
-28
-34
-29
-34
-30
-29
-28
-20
-20
-20
-26
-24
-25
-30
-25
-21
-15
-27
-25
-27
-19
-26
-28
-18
-15
-23
-24
-23
-31
-24
-18
-19
-25
-22
-29
-26
-22
-26
-25
-24
-25
-30
-15
-29
-25
-25
-18
-26
-21
-19
-22
-13
-32
-18
-23
-22
-28
-22
-22
-29
-34
-22
-28
-22
-16
-15
-18
-17
-16
-20
-33
-22
-24
-23
-21
-12
-20
-26
-20
-17
-22
-23
-25
-26
-21
-17
-17
-24
-19
-17
-18
-23
-21
-30
-28
-22
-15
-24
-27
-16
-21
-17
-32
-15
-23
-14
-17
-24
-21
-20
-11
-23
-18
-27
-14
-20
-18
-17
-13
-11
-12
-26
-19
-18
-21
-15
-17
-14
-11
-10
-15
-19
-14
-16
-11
-16
-17
-9
-19
-17
-19
-14
-15
-11
-14
-16
-11
-11
-8
-10
-10
-23
-16
-17
-14
-11
-15
-14
-21
-18
-13
-21
-30
-21
-21
-24
-21
-26
-21
-20
-31
-27
-24
-30
-34
-23
-28
-31
-29
-19
-36
-25
-25
-34
-29
-24
-18
-20
-28
-27
-32
-25
-22
-27
-26
-31
-22
-26
-20
-35
-25
-29
-23
-28
-32
-32
-29
-21
-30
-22
-39
-20
-25
-24
-23
-22
-25
-24
-27
-27
-25
-28
-26
-20
-21
-28
-27
-27
-21
-21
-25
-31
-27
-30
-16
-35
-22
-28
-25
-25
-19
-27
-24
-18
-29
-24
-24
-24
-20
-19
-22
-25
-17
-26
-25
-22
-26
-18
-31
-20
-20
-26
-22
-19
-20
-24
-20
-28
-28
-25
-22
-17
-13
-31
-14
-19
-23
-25
-15
-31
-20
-21
-19
-23
-23
-13
-28
-20
-23
-18
-22
-25
-15
-22
-10
-20
-23
-18
-17
-22
-13
-19
-24
-23
-18
-15
-11
-24
-14
-22
-14
-13
-19
-21
-23
-18
-18
-20
-23
-18
-19
-12
-10
-13
-16
-16
-20
-16
-14
-18
-15
-7
-17
-9
-11
-14
-13
-17
-14
-9
-11
-18
-14
-14
-10
-19
-25
-13
-10
-13
-13
-14
-10
-18
-24
-28
-29
-31
-33
-35
-37
-26
-22
-21
-21
-21
-26
-30
-30
-29
-33
-34
-21
-22
-21
-27
-24
-27
-29
-28
-24
-21
-22
-30
-25
-21
-27
-28
-34
-26
-23
-25
-21
-25
-24
-17
-23
-36
-26
-35
-22
-38
-27
-28
-41
-22
-24
-21
-26
-32
-25
-24
-24
-16
-24
-26
-21
-27
-28
-19
-21
-22
-23
-26
-25
-30
-26
-16
-30
-19
-27
-40
-21
-13
-18
-31
-26
-23
-19
-26
-25
-25
-23
-27
-23
-18
-22
-26
-24
-22
-19
-21
-20
-26
-26
-24
-22
-13
-25
-18
-28
-22
-27
-20
-23
-21
-34
-25
-25
-22
-16
-25
-25
-21
-21
-19
-28
-19
-26
-19
-19
-23
-17
-19
-19
-13
-20
-15
-13
-21
-14
-20
-20
-20
-21
-19
-22
-22
-16
-25
-20
-18
-19
-21
-21
-22
-21
-16
-21
-22
-8
-5
-20
-22
-17
-13
-12
-17
-21
-24
-19
-20
-17
-16
-13
-14
-10
-17
-8
-8
-22
-12
-14
-14
-15
-16
-12
-17
-10
-25
-17
-13
-14
-13
-14
-13
-23
-21
-31
-24
-29
-18
-31
-24
-27
-24
-37
-35
-29
-28
-32
-32
-34
-18
-22
-33
-35
-29
-27
-35
-27
-37
-24
-21
-26
-23
-27
-20
-26
-23
-36
-28
-24
-21
-30
-34
-33
-22
-24
-30
-18
-25
-22
-30
-29
-23
-34
-14
-26
-29
-39
-22
-23
-24
-24
-29
-22
-30
-21
-38
-25
-31
-15
-29
-19
-18
-26
-26
-23
-27
-30
-18
-28
-29
-34
-25
-31
-25
-30
-35
-25
-23
-22
-18
-25
-25
-25
-21
-24
-30
-26
-21
-24
-30
-27
-26
-19
-24
-20
-22
-25
-19
-18
-23
-22
-14
-23
-22
-29
-30
-14
-26
-20
-27
-21
-24
-24
-24
-13
-24
-27
-21
-25
-19
-23
-25
-12
-19
-22
-22
-16
-26
-27
-27
-30
-15
-13
-17
-22
-16
-21
-18
-18
-21
-20
-15
-19
-17
-13
-12
-24
-15
-21
-14
-18
-21
-15
-17
-20
-10
-15
-15
-18
-12
-17
-7
-11
-15
-16
-20
-18
-18
-16
-10
-8
-13
-13
-7
-16
-14
-17
-10
-12
-10
-12
-13
-13
-14
-30
-29
-29
-34
-30
-29
-29
-24
-29
-27
-43
-28
-34
-24
-22
-22
-31
-27
-28
-21
-28
-36
-19
-35
-31
-36
-22
-33
-21
-30
-29
-20
-30
-29
-21
-28
-25
-37
-29
-27
-28
-32
-33
-24
-19
-31
-23
-28
-33
-29
-38
-22
-29
-23
-23
-25
-28
-26
-26
-21
-35
-24
-21
-36
-30
-25
-30
-25
-20
-26
-23
-20
-28
-20
-19
-27
-12
-21
-23
-19
-24
-31
-27
-16
-31
-24
-22
-19
-27
-24
-23
-22
-27
-24
-19
-19
-20
-24
-20
-27
-25
-21
-14
-12
-16
-30
-21
-24
-18
-20
-23
-21
-19
-22
-25
-22
-16
-31
-27
-19
-23
-21
-23
-23
-23
-22
-17
-28
-31
-21
-14
-14
-26
-18
-20
-25
-28
-22
-13
-25
-18
-20
-19
-14
-20
-18
-21
-17
-28
-19
-20
-26
-29
-20
-15
-15
-20
-22
-19
-29
-21
-9
-10
-15
-21
-16
-21
-16
-17
-16
-12
-19
-13
-15
-20
-14
-17
-13
-11
-12
-15
-11
-17
-18
-14
-14
-11
-6
-12
-19
-8
-17
-30
-27
-31
-28
-25
-15
-23
-30
-20
-27
-29
-34
-29
-31
-28
-34
-29
-31
-42
-22
-22
-24
-28
-34
-33
-29
-38
-33
-26
-35
-29
-37
-26
-25
-27
-29
-24
-18
-23
-25
-26
-29
-26
-33
-26
-26
-34
-32
-30
-35
-24
-34
-21
-17
-31
-23
-22
-31
-13
-30
-19
-24
-26
-27
-30
-17
-29
-22
-35
-31
-29
-28
-19
-38
-21
-24
-21
-24
-33
-26
-31
-25
-28
-27
-36
-28
-32
-19
-21
-17
-18
-23
-19
-26
-18
-22
-26
-26
-15
-28
-29
-26
-18
-23
-21
-24
-22
-27
-25
-27
-21
-17
-28
-27
-22
-25
-17
-13
-23
-21
-28
-20
-18
-24
-22
-25
-19
-21
-29
-21
-27
-15
-20
-18
-18
-22
-24
-20
-23
-33
-22
-13
-28
-10
-15
-30
-19
-20
-21
-20
-14
-23
-13
-14
-16
-18
-14
-13
-13
-12
-15
-15
-20
-13
-18
-24
-16
-24
-28
-17
-13
-16
-16
-11
-17
-15
-18
-17
-18
-15
-15
-16
-13
-18
-23
-16
-11
-24
-15
-16
-17
-13
-33
-27
-35
-28
-34
-27
-32
-27
-26
-29
-20
-36
-37
-31
-30
-23
-34
-30
-25
-27
-42
-23
-29
-30
-27
-28
-23
-24
-19
-29
-31
-31
-19
-20
-28
-29
-30
-31
-28
-19
-19
-31
-33
-28
-29
-35
-19
-28
-31
-22
-31
-16
-27
-27
-36
-32
-29
-32
-24
-16
-27
-21
-22
-21
-31
-26
-29
-28
-29
-20
-21
-22
-28
-27
-32
-23
-27
-31
-32
-26
-32
-27
-27
-30
-31
-15
-24
-28
-18
-27
-29
-28
-21
-32
-24
-13
-23
-25
-23
-23
-24
-24
-21
-25
-25
-15
-22
-16
-21
-26
-25
-30
-19
-23
-18
-18
-17
-28
-28
-27
-23
-18
-18
-19
-19
-25
-22
-21
-25
-21
-27
-17
-19
-17
-24
-15
-25
-29
-17
-16
-21
-24
-11
-21
-21
-19
-24
-19
-19
-18
-18
-19
-21
-17
-13
-16
-16
-19
-20
-15
-20
-16
-18
-15
-26
-15
-18
-20
-15
-9
-24
-9
-17
-17
-13
-13
-14
-19
-21
-14
-23
-12
-12
-22
-14
-9
-15
-15
-12
-15
-14
-11
-38
-32
-28
-26
-29
-37
-36
-27
-27
-28
-28
-27
-24
-29
-43
-25
-37
-43
-30
-19
-34
-28
-33
-21
-35
-35
-29
-28
-33
-28
-24
-28
-27
-31
-22
-34
-31
-31
-31
-19
-31
-24
-27
-23
-20
-27
-32
-24
-22
-14
-24
-19
-25
-19
-35
-27
-31
-29
-31
-19
-27
-35
-26
-26
-28
-25
-21
-34
-32
-22
-25
-28
-25
-24
-28
-24
-26
-23
-21
-14
-14
-15
-31
-30
-21
-21
-25
-21
-31
-26
-19
-34
-18
-26
-22
-26
-25
-25
-20
-23
-32
-35
-24
-23
-23
-16
-25
-21
-19
-28
-19
-19
-27
-22
-19
-28
-22
-25
-22
-28
-19
-20
-31
-19
-18
-20
-21
-25
-20
-28
-35
-13
-19
-21
-26
-19
-18
-18
-19
-13
-15
-15
-25
-27
-23
-23
-21
-17
-17
-16
-19
-28
-14
-21
-24
-18
-15
-17
-16
-14
-21
-13
-12
-15
-18
-26
-18
-15
-15
-16
-15
-20
-20
-17
-8
-17
-11
-12
-9
-14
-14
-17
-14
-21
-14
-12
-17
-9
-16
-12
-10
-22
-31
-20
-39
-34
-23
-26
-22
-22
-26
-40
-33
-39
-30
-34
-37
-30
-23
-36
-35
-26
-26
-30
-27
-27
-26
-33
-33
-30
-25
-29
-33
-33
-18
-19
-27
-25
-35
-32
-21
-24
-25
-31
-31
-45
-32
-35
-22
-16
-30
-29
-26
-24
-22
-26
-24
-24
-24
-23
-30
-33
-28
-31
-17
-23
-21
-26
-31
-27
-26
-29
-27
-24
-35
-31
-23
-26
-23
-24
-23
-17
-23
-25
-23
-28
-25
-20
-27
-23
-23
-21
-23
-30
-24
-27
-28
-28
-21
-27
-26
-24
-26
-19
-24
-30
-29
-35
-22
-15
-26
-22
-26
-21
-18
-29
-20
-18
-22
-20
-23
-23
-21
-21
-16
-19
-14
-22
-23
-19
-25
-20
-20
-19
-23
-27
-21
-12
-21
-24
-12
-22
-22
-16
-18
-24
-20
-20
-19
-15
-21
-25
-15
-12
-16
-20
-12
-16
-29
-16
-15
-17
-22
-20
-21
-19
-24
-20
-16
-16
-13
-20
-16
-11
-15
-10
-15
-15
-12
-13
-11
-6
-14
-15
-10
-14
-10
-14
-22
-12
-20
-15
-11
-22
-30
-35
-21
-26
-37
-31
-38
-33
-35
-37
-26
-31
-39
-25
-22
-41
-32
-28
-25
-23
-35
-26
-18
-24
-37
-25
-40
-31
-34
-24
-25
-23
-29
-24
-28
-29
-22
-36
-27
-32
-32
-28
-29
-21
-33
-24
-22
-27
-26
-25
-20
-37
-31
-20
-19
-21
-33
-28
-25
-36
-24
-23
-27
-24
-22
-26
-20
-26
-23
-30
-37
-21
-23
-36
-17
-26
-24
-21
-28
-24
-25
-26
-26
-20
-29
-29
-23
-22
-33
-23
-20
-26
-23
-30
-32
-19
-23
-22
-26
-25
-29
-20
-21
-23
-31
-19
-24
-17
-23
-30
-23
-27
-32
-21
-24
-20
-16
-30
-20
-21
-18
-16
-17
-22
-22
-25
-25
-27
-27
-20
-16
-17
-22
-22
-13
-22
-24
-16
-22
-22
-24
-20
-19
-20
-22
-21
-12
-16
-22
-17
-23
-17
-16
-21
-15
-22
-14
-16
-13
-13
-13
-18
-20
-17
-18
-8
-22
-21
-21
-18
-21
-17
-12
-21
-16
-15
-12
-13
-16
-20
-14
-11
-22
-11
-20
-13
-16
-13
-16
-13
-17
-22
-28
-28
-20
-23
-27
-28
-43
-32
-24
-21
-35
-33
-46
-38
-26
-28
-26
-33
-34
-30
-34
-35
-30
-44
-31
-28
-23
-37
-28
-32
-28
-32
-38
-32
-30
-31
-39
-35
-21
-31
-32
-32
-27
-21
-29
-35
-34
-27
-36
-22
-32
-25
-20
-31
-30
-24
-19
-28
-27
-25
-28
-30
-34
-31
-28
-30
-24
-28
-21
-30
-21
-36
-22
-26
-24
-19
-21
-21
-31
-25
-36
-22
-26
-22
-29
-25
-23
-27
-25
-18
-27
-26
-22
-22
-26
-27
-18
-23
-30
-22
-21
-16
-19
-28
-28
-16
-26
-21
-17
-26
-13
-18
-25
-13
-25
-30
-17
-20
-27
-17
-19
-17
-22
-23
-19
-22
-18
-19
-32
-27
-28
-10
-20
-28
-29
-18
-15
-16
-20
-15
-19
-14
-18
-15
-22
-15
-23
-14
-15
-22
-10
-12
-18
-22
-28
-19
-16
-21
-17
-17
-21
-15
-15
-21
-17
-11
-17
-16
-14
-14
-13
-14
-16
-20
-16
-19
-13
-14
-15
-13
-20
-11
-16
-12
-16
-8
-17
-11
-10
-6
-20
-21
-41
-41
-31
-33
-35
-19
-18
-39
-27
-24
-21
-25
-40
-29
-33
-33
-35
-34
-33
-26
-32
-36
-22
-26
-30
-32
-26
-34
-35
-25
-32
-28
-26
-33
-24
-34
-24
-27
-26
-30
-27
-35
-27
-34
-22
-30
-19
-22
-30
-27
-35
-23
-36
-23
-28
-47
-32
-22
-28
-21
-26
-30
-26
-21
-29
-27
-29
-15
-30
-30
-28
-31
-29
-23
-22
-16
-20
-28
-31
-26
-33
-19
-30
-20
-27
-17
-24
-32
-21
-24
-21
-21
-21
-22
-21
-20
-24
-13
-19
-20
-32
-26
-23
-20
-19
-22
-30
-20
-16
-18
-21
-15
-29
-30
-25
-28
-25
-31
-33
-25
-21
-28
-22
-23
-20
-28
-31
-26
-24
-16
-25
-16
-21
-28
-23
-17
-23
-22
-24
-24
-15
-25
-23
-20
-22
-16
-15
-17
-24
-13
-23
-20
-13
-18
-20
-13
-15
-19
-19
-13
-19
-13
-16
-16
-23
-27
-15
-18
-16
-15
-22
-23
-16
-9
-30
-11
-27
-14
-15
-8
-18
-14
-8
-12
-8
-17
-16
-19
-19
-19
-18
-16
-42
-30
-30
-30
-33
-30
-35
-23
-32
-37
-26
-18
-35
-33
-30
-26
-33
-35
-30
-29
-41
-38
-31
-45
-18
-31
-30
-35
-38
-32
-37
-34
-35
-31
-32
-46
-38
-28
-48
-39
-39
-34
-34
-30
-28
-22
-33
-23
-31
-37
-31
-19
-25
-26
-33
-32
-20
-20
-30
-30
-22
-29
-31
-17
-22
-23
-25
-33
-26
-24
-26
-27
-25
-25
-26
-39
-16
-30
-32
-26
-17
-23
-30
-35
-23
-22
-20
-31
-31
-23
-25
-39
-18
-18
-27
-27
-25
-23
-27
-18
-16
-23
-25
-23
-22
-24
-23
-20
-23
-22
-26
-17
-17
-20
-20
-27
-24
-24
-16
-19
-25
-24
-17
-14
-32
-27
-20
-26
-22
-24
-22
-28
-33
-26
-20
-26
-22
-27
-14
-29
-26
-20
-22
-17
-15
-21
-17
-22
-19
-17
-20
-25
-18
-10
-23
-23
-15
-29
-18
-12
-26
-19
-18
-19
-16
-18
-10
-17
-20
-18
-23
-19
-18
-13
-25
-28
-11
-13
-12
-17
-19
-22
-14
-20
-21
-12
-20
-19
-14
-14
-20
-18
-40
-35
-27
-29
-32
-31
-32
-27
-35
-49
-35
-39
-40
-32
-33
-31
-23
-29
-36
-35
-39
-27
-23
-36
-48
-33
-28
-30
-38
-39
-37
-24
-33
-31
-30
-28
-30
-23
-46
-21
-33
-28
-33
-30
-29
-30
-26
-26
-21
-31
-22
-28
-28
-33
-36
-29
-22
-25
-25
-28
-30
-29
-26
-28
-34
-25
-27
-27
-29
-26
-32
-25
-37
-41
-22
-23
-34
-31
-20
-19
-29
-27
-29
-18
-37
-28
-22
-12
-25
-23
-26
-28
-20
-26
-33
-28
-17
-22
-28
-22
-27
-29
-21
-28
-18
-21
-16
-25
-30
-27
-32
-22
-17
-27
-24
-27
-35
-23
-16
-21
-15
-24
-24
-27
-22
-27
-19
-18
-16
-24
-36
-17
-20
-20
-28
-19
-18
-34
-20
-18
-25
-23
-22
-18
-18
-20
-16
-20
-19
-24
-19
-24
-13
-14
-24
-22
-19
-27
-16
-23
-21
-27
-24
-20
-8
-20
-13
-14
-22
-13
-8
-14
-20
-16
-23
-30
-8
-10
-10
-15
-15
-14
-17
-20
-14
-16
-12
-14
-16
-14
-20
-14
-41
-39
-24
-33
-29
-29
-25
-28
-35
-24
-27
-39
-44
-30
-34
-25
-40
-20
-41
-36
-20
-47
-31
-25
-43
-33
-36
-35
-32
-32
-45
-27
-33
-32
-38
-26
-30
-33
-31
-26
-32
-29
-30
-25
-50
-28
-33
-33
-18
-31
-47
-34
-24
-27
-24
-30
-28
-24
-20
-26
-26
-27
-25
-31
-28
-23
-18
-18
-27
-35
-33
-25
-27
-25
-30
-27
-24
-30
-32
-29
-31
-25
-33
-33
-29
-28
-27
-30
-29
-24
-24
-28
-23
-19
-31
-26
-17
-23
-34
-19
-13
-17
-16
-20
-26
-22
-29
-33
-23
-32
-22
-18
-23
-28
-28
-17
-17
-34
-31
-21
-28
-20
-20
-18
-18
-21
-20
-28
-23
-23
-21
-20
-17
-25
-24
-16
-24
-11
-16
-20
-20
-24
-17
-23
-30
-26
-25
-19
-22
-24
-19
-14
-14
-18
-22
-24
-23
-20
-19
-21
-15
-18
-12
-18
-18
-15
-19
-15
-16
-19
-18
-24
-18
-16
-21
-17
-19
-18
-10
-16
-17
-10
-13
-10
-14
-10
-10
-9
-19
-11
-13
-22
-27
-44
-33
-43
-31
-41
-36
-35
-32
-44
-36
-48
-44
-35
-28
-34
-39
-42
-33
-30
-42
-36
-29
-34
-29
-27
-39
-42
-44
-25
-32
-36
-32
-40
-31
-36
-24
-34
-35
-35
-42
-34
-26
-30
-50
-37
-34
-36
-32
-34
-24
-21
-21
-39
-34
-29
-41
-27
-40
-28
-23
-15
-30
-33
-22
-31
-32
-23
-21
-35
-21
-26
-31
-38
-30
-28
-28
-31
-21
-23
-21
-37
-21
-23
-24
-33
-24
-24
-30
-27
-17
-22
-26
-21
-31
-24
-25
-17
-23
-26
-15
-32
-20
-23
-25
-17
-23
-28
-28
-25
-25
-20
-33
-22
-18
-30
-25
-22
-19
-22
-17
-22
-21
-20
-15
-26
-21
-21
-22
-18
-19
-25
-26
-24
-23
-14
-24
-25
-22
-27
-25
-24
-19
-27
-23
-23
-18
-18
-20
-14
-23
-22
-22
-23
-10
-28
-17
-18
-18
-25
-16
-18
-12
-22
-31
-18
-15
-16
-14
-19
-11
-15
-10
-10
-14
-19
-17
-23
-18
-18
-21
-16
-16
-14
-16
-13
-10
-15
-14
-15
-9
-16
-29
-35
-24
-43
-34
-35
-31
-40
-27
-39
-29
-46
-36
-32
-26
-38
-42
-38
-22
-30
-32
-32
-46
-25
-40
-38
-27
-37
-49
-33
-36
-34
-29
-37
-40
-40
-27
-41
-26
-35
-31
-33
-33
-28
-21
-30
-30
-30
-27
-33
-32
-26
-28
-27
-34
-19
-24
-26
-22
-36
-31
-25
-29
-25
-35
-44
-31
-21
-32
-21
-21
-33
-27
-21
-29
-21
-22
-28
-22
-39
-31
-25
-22
-32
-29
-30
-27
-24
-27
-30
-19
-18
-22
-24
-18
-24
-19
-16
-35
-28
-24
-20
-30
-22
-26
-16
-23
-21
-29
-31
-15
-25
-30
-21
-26
-21
-23
-24
-35
-16
-25
-26
-22
-16
-22
-20
-27
-27
-30
-14
-20
-21
-24
-16
-19
-20
-22
-26
-22
-27
-27
-24
-13
-16
-26
-25
-18
-8
-21
-18
-22
-27
-13
-28
-20
-16
-22
-20
-20
-22
-16
-20
-17
-24
-18
-21
-14
-12
-13
-18
-15
-18
-14
-16
-25
-14
-20
-13
-18
-16
-16
-15
-16
-17
-13
-13
-11
-14
-12
-20
-17
-12
-35
-42
-32
-27
-41
-39
-30
-33
-30
-40
-47
-36
-54
-24
-35
-42
-36
-35
-46
-28
-48
-40
-27
-38
-31
-35
-34
-33
-34
-23
-39
-42
-29
-28
-46
-22
-25
-35
-28
-38
-25
-29
-38
-43
-28
-34
-27
-33
-39
-38
-35
-31
-27
-41
-28
-27
-24
-23
-24
-33
-27
-33
-33
-32
-20
-28
-34
-18
-30
-24
-26
-25
-21
-28
-30
-25
-21
-24
-18
-24
-31
-26
-24
-32
-21
-22
-24
-31
-19
-37
-25
-19
-34
-32
-20
-28
-19
-42
-18
-20
-27
-24
-22
-33
-25
-20
-17
-25
-18
-27
-26
-22
-23
-25
-21
-28
-17
-27
-29
-26
-16
-34
-27
-21
-21
-26
-17
-17
-26
-28
-22
-22
-22
-21
-17
-21
-24
-22
-23
-21
-22
-22
-16
-21
-16
-21
-19
-19
-20
-17
-23
-22
-19
-20
-15
-15
-19
-20
-17
-23
-20
-15
-19
-16
-25
-20
-11
-17
-18
-17
-19
-16
-20
-21
-20
-10
-11
-13
-17
-19
-17
-14
-20
-16
-14
-15
-9
-11
-13
-12
-19
-15
-41
-28
-36
-39
-35
-35
-30
-40
-40
-36
-34
-40
-41
-36
-36
-27
-31
-34
-32
-33
-39
-39
-41
-36
-39
-32
-32
-31
-35
-39
-40
-28
-29
-43
-37
-34
-35
-31
-32
-29
-36
-36
-39
-30
-36
-38
-37
-27
-40
-36
-26
-31
-25
-38
-30
-27
-30
-42
-27
-29
-27
-22
-31
-29
-28
-27
-28
-24
-44
-28
-28
-28
-27
-28
-28
-18
-43
-20
-25
-24
-24
-31
-19
-25
-22
-20
-30
-30
-26
-23
-29
-33
-25
-29
-29
-29
-22
-30
-28
-26
-31
-30
-18
-27
-20
-18
-26
-41
-24
-26
-21
-17
-28
-34
-13
-21
-26
-25
-22
-19
-27
-18
-25
-23
-19
-20
-23
-19
-21
-16
-18
-19
-14
-17
-15
-22
-24
-23
-22
-23
-20
-18
-30
-21
-25
-14
-24
-17
-14
-22
-8
-23
-24
-21
-17
-15
-25
-16
-23
-16
-11
-16
-12
-22
-22
-14
-22
-27
-14
-20
-21
-17
-12
-15
-12
-22
-14
-22
-14
-18
-9
-13
-13
-20
-20
-16
-16
-19
-13
-14
-12
-20
-43
-28
-41
-35
-34
-49
-32
-42
-31
-39
-42
-26
-44
-38
-27
-40
-34
-41
-37
-36
-42
-43
-41
-37
-45
-36
-37
-40
-40
-33
-35
-36
-43
-37
-33
-30
-32
-27
-34
-32
-36
-39
-36
-36
-36
-37
-28
-37
-31
-31
-33
-33
-36
-31
-41
-30
-30
-33
-25
-36
-29
-29
-38
-30
-29
-19
-27
-24
-30
-26
-25
-41
-30
-27
-30
-27
-29
-24
-20
-26
-26
-31
-26
-30
-22
-31
-15
-29
-25
-18
-25
-24
-19
-30
-17
-30
-22
-22
-29
-30
-24
-20
-32
-22
-24
-32
-36
-26
-21
-22
-23
-27
-16
-20
-19
-17
-25
-10
-24
-21
-28
-22
-19
-21
-24
-26
-21
-24
-18
-25
-17
-12
-18
-29
-17
-30
-21
-18
-26
-19
-19
-20
-14
-21
-19
-16
-20
-16
-20
-11
-27
-13
-12
-22
-23
-22
-25
-19
-20
-14
-15
-18
-22
-19
-17
-23
-13
-25
-11
-24
-15
-14
-17
-15
-12
-14
-24
-15
-11
-21
-11
-20
-15
-14
-15
-12
-17
-17
-21
-9
-8
-16
-32
-29
-30
-28
-30
-31
-43
-33
-38
-33
-37
-46
-38
-53
-30
-42
-32
-41
-40
-34
-35
-45
-37
-40
-29
-21
-36
-39
-43
-46
-46
-42
-44
-33
-32
-33
-33
-34
-27
-39
-42
-37
-38
-35
-28
-33
-29
-33
-41
-31
-29
-17
-24
-33
-28
-36
-33
-20
-25
-22
-26
-28
-33
-23
-28
-37
-23
-23
-26
-38
-28
-27
-22
-26
-27
-27
-27
-23
-28
-24
-21
-23
-20
-28
-32
-27
-27
-26
-16
-30
-24
-29
-22
-28
-32
-23
-31
-31
-24
-35
-16
-16
-20
-20
-19
-22
-26
-36
-22
-19
-23
-21
-16
-26
-20
-23
-32
-25
-31
-18
-25
-25
-29
-22
-19
-26
-21
-22
-19
-20
-21
-17
-18
-23
-22
-14
-30
-20
-23
-20
-22
-26
-22
-27
-12
-19
-18
-16
-30
-23
-14
-19
-14
-23
-24
-13
-22
-16
-20
-14
-16
-22
-17
-10
-24
-10
-17
-20
-18
-25
-14
-18
-20
-15
-23
-14
-18
-15
-22
-14
-15
-18
-15
-14
-15
-13
-18
-15
-16
-20
-14
-19
-46
-34
-41
-40
-41
-43
-39
-47
-40
-37
-37
-32
-26
-37
-44
-32
-31
-34
-38
-34
-55
-25
-31
-25
-36
-43
-30
-36
-33
-48
-27
-51
-42
-36
-31
-41
-39
-35
-38
-31
-23
-39
-33
-35
-55
-29
-39
-33
-36
-27
-45
-35
-31
-28
-30
-42
-28
-36
-37
-38
-29
-36
-31
-31
-31
-32
-21
-31
-32
-24
-28
-27
-24
-34
-27
-19
-28
-26
-24
-28
-26
-27
-17
-26
-32
-29
-22
-18
-24
-17
-24
-22
-26
-28
-18
-31
-34
-29
-27
-25
-31
-16
-29
-18
-24
-28
-22
-10
-27
-11
-23
-20
-28
-28
-28
-24
-21
-21
-27
-25
-23
-18
-22
-34
-26
-24
-23
-24
-34
-16
-17
-20
-20
-30
-20
-13
-17
-20
-19
-19
-19
-23
-20
-19
-15
-22
-23
-18
-20
-18
-23
-16
-16
-21
-15
-18
-18
-21
-21
-19
-24
-19
-18
-17
-21
-9
-13
-25
-16
-17
-21
-16
-11
-10
-16
-18
-19
-13
-14
-19
-20
-24
-12
-12
-14
-16
-16
-15
-15
-19
-16
-16
-36
-36
-30
-29
-33
-37
-44
-31
-34
-34
-37
-43
-45
-43
-41
-30
-45
-34
-43
-33
-46
-38
-37
-29
-42
-36
-41
-42
-38
-37
-37
-32
-34
-36
-33
-38
-35
-54
-39
-36
-24
-37
-39
-37
-22
-35
-30
-39
-28
-35
-39
-31
-31
-31
-28
-29
-31
-28
-29
-21
-31
-25
-34
-26
-41
-33
-30
-28
-31
-25
-34
-16
-31
-26
-35
-20
-28
-30
-22
-23
-28
-18
-31
-33
-22
-28
-22
-25
-24
-31
-24
-28
-24
-21
-29
-20
-27
-21
-17
-28
-19
-31
-25
-29
-23
-19
-26
-23
-25
-24
-20
-23
-24
-25
-20
-25
-29
-32
-14
-33
-14
-23
-28
-21
-30
-17
-22
-12
-19
-22
-22
-22
-26
-19
-24
-26
-26
-18
-23
-14
-19
-28
-16
-20
-22
-21
-14
-24
-19
-22
-28
-18
-25
-20
-31
-23
-24
-17
-16
-11
-18
-21
-10
-16
-19
-16
-14
-20
-18
-20
-18
-19
-14
-12
-13
-20
-12
-14
-16
-20
-14
-14
-13
-22
-21
-6
-21
-23
-11
-16
-16
-14
-31
-43
-47
-36
-42
-35
-37
-42
-39
-51
-46
-41
-45
-36
-48
-40
-43
-51
-35
-43
-29
-50
-39
-35
-49
-41
-47
-47
-49
-36
-43
-54
-47
-44
-38
-38
-33
-41
-34
-30
-34
-44
-45
-32
-29
-36
-37
-30
-37
-37
-25
-28
-41
-33
-33
-33
-26
-30
-24
-31
-36
-31
-37
-28
-34
-31
-30
-28
-32
-32
-23
-25
-27
-33
-33
-26
-40
-27
-30
-29
-32
-20
-35
-27
-30
-29
-29
-30
-18
-18
-21
-21
-26
-35
-27
-30
-27
-22
-18
-17
-18
-26
-20
-27
-26
-14
-21
-24
-32
-25
-35
-21
-28
-19
-26
-26
-24
-23
-24
-28
-22
-20
-22
-32
-24
-17
-28
-22
-12
-19
-24
-20
-25
-20
-26
-22
-26
-18
-25
-19
-20
-27
-17
-22
-16
-25
-20
-26
-21
-21
-19
-17
-12
-18
-10
-26
-20
-20
-24
-18
-24
-21
-24
-15
-10
-17
-16
-21
-14
-25
-12
-19
-28
-13
-16
-17
-14
-19
-12
-16
-15
-18
-13
-16
-13
-17
-23
-22
-13
-10
-14
-14
-39
-37
-41
-32
-30
-37
-32
-36
-37
-41
-48
-46
-47
-34
-51
-40
-45
-33
-38
-43
-43
-41
-33
-41
-36
-37
-39
-41
-42
-49
-33
-39
-46
-36
-35
-39
-25
-34
-38
-33
-46
-38
-55
-38
-31
-38
-30
-32
-37
-32
-33
-24
-50
-28
-34
-26
-32
-27
-25
-30
-24
-28
-29
-25
-28
-29
-36
-23
-24
-23
-32
-28
-25
-34
-31
-23
-20
-26
-36
-19
-27
-23
-33
-21
-30
-26
-28
-31
-35
-27
-25
-22
-23
-22
-28
-17
-23
-23
-18
-32
-30
-25
-31
-20
-27
-29
-25
-22
-27
-28
-31
-16
-30
-21
-26
-25
-31
-26
-28
-24
-16
-33
-24
-33
-18
-19
-21
-34
-23
-13
-15
-23
-24
-22
-29
-17
-19
-28
-15
-21
-17
-18
-28
-23
-25
-18
-23
-21
-14
-24
-18
-22
-23
-14
-18
-20
-23
-23
-19
-18
-16
-14
-17
-23
-12
-16
-18
-12
-18
-20
-12
-9
-10
-15
-16
-17
-21
-18
-12
-12
-18
-15
-21
-18
-13
-18
-17
-11
-22
-21
-11
-17
-39
-53
-32
-31
-40
-42
-43
-52
-37
-41
-45
-52
-40
-35
-36
-48
-39
-26
-45
-50
-41
-35
-56
-48
-54
-34
-43
-44
-47
-49
-45
-45
-35
-34
-40
-35
-36
-32
-49
-53
-45
-32
-31
-34
-32
-35
-34
-39
-41
-32
-33
-32
-35
-34
-36
-30
-36
-38
-26
-31
-26
-29
-23
-40
-28
-24
-30
-29
-34
-30
-32
-34
-30
-30
-34
-33
-25
-31
-24
-26
-25
-32
-24
-32
-22
-27
-28
-29
-30
-29
-31
-24
-22
-22
-28
-33
-25
-22
-26
-38
-30
-20
-21
-16
-22
-28
-23
-26
-18
-24
-18
-24
-29
-29
-19
-27
-23
-29
-23
-25
-19
-28
-23
-22
-21
-9
-25
-27
-28
-24
-26
-19
-26
-22
-19
-27
-22
-26
-17
-22
-18
-18
-16
-18
-16
-17
-27
-16
-24
-22
-12
-12
-17
-21
-22
-15
-13
-24
-31
-17
-20
-14
-20
-16
-17
-30
-24
-24
-11
-15
-12
-20
-16
-14
-22
-25
-14
-24
-15
-14
-17
-14
-20
-15
-20
-17
-14
-11
-14
-9
-15
-22
-40
-45
-47
-27
-44
-32
-42
-42
-52
-43
-39
-42
-38
-42
-40
-35
-32
-37
-45
-44
-47
-50
-37
-40
-44
-63
-45
-34
-44
-38
-43
-25
-46
-43
-50
-42
-40
-25
-33
-32
-43
-28
-44
-27
-34
-40
-33
-41
-31
-33
-35
-30
-29
-26
-37
-41
-28
-33
-29
-36
-32
-32
-37
-32
-32
-24
-24
-27
-28
-29
-31
-19
-34
-28
-29
-33
-19
-27
-36
-20
-32
-32
-18
-24
-34
-26
-33
-20
-24
-23
-17
-21
-23
-27
-25
-23
-20
-33
-22
-26
-30
-23
-30
-20
-23
-24
-29
-27
-26
-16
-22
-18
-27
-22
-26
-21
-30
-18
-21
-20
-29
-28
-27
-35
-20
-23
-24
-34
-32
-27
-20
-30
-20
-27
-24
-21
-24
-31
-21
-23
-25
-12
-28
-19
-22
-16
-28
-28
-24
-25
-10
-14
-19
-18
-21
-10
-30
-21
-32
-21
-26
-15
-15
-20
-17
-14
-20
-15
-15
-13
-22
-20
-12
-15
-14
-12
-23
-13
-15
-11
-19
-19
-10
-17
-21
-13
-18
-21
-18
-16
-19
-16
-58
-49
-36
-34
-39
-36
-44
-38
-41
-42
-42
-39
-50
-39
-44
-51
-41
-55
-55
-45
-52
-40
-49
-46
-50
-56
-38
-44
-34
-45
-39
-38
-35
-48
-27
-40
-43
-31
-47
-37
-37
-40
-50
-33
-46
-35
-33
-49
-42
-42
-33
-36
-33
-41
-29
-21
-26
-39
-33
-34
-37
-40
-32
-30
-29
-22
-36
-36
-34
-35
-36
-35
-25
-31
-28
-33
-29
-29
-36
-24
-32
-19
-23
-26
-26
-27
-25
-17
-25
-33
-25
-31
-25
-25
-27
-16
-26
-26
-27
-22
-27
-29
-18
-25
-31
-30
-23
-17
-23
-23
-20
-27
-30
-26
-28
-20
-22
-15
-25
-21
-14
-23
-26
-15
-30
-17
-28
-20
-31
-18
-25
-22
-20
-25
-22
-26
-21
-26
-19
-20
-24
-17
-21
-23
-17
-18
-20
-20
-12
-18
-22
-22
-23
-12
-20
-19
-25
-17
-18
-19
-26
-23
-21
-19
-17
-25
-14
-19
-16
-13
-15
-20
-12
-16
-13
-20
-13
-18
-21
-9
-17
-22
-12
-7
-12
-20
-13
-17
-14
-15
-11
-10
-43
-36
-51
-41
-48
-48
-30
-35
-49
-48
-36
-44
-59
-43
-43
-35
-46
-54
-49
-42
-45
-50
-56
-42
-63
-49
-58
-44
-38
-52
-42
-45
-48
-41
-46
-42
-44
-44
-45
-42
-46
-33
-41
-55
-34
-40
-42
-45
-35
-30
-47
-32
-46
-35
-29
-26
-27
-35
-33
-37
-31
-38
-32
-41
-28
-37
-34
-29
-32
-32
-29
-28
-20
-31
-24
-30
-21
-27
-39
-29
-31
-36
-24
-32
-32
-34
-26
-23
-18
-18
-21
-24
-28
-24
-27
-23
-34
-20
-33
-19
-22
-27
-22
-30
-22
-28
-24
-28
-18
-26
-21
-29
-20
-25
-33
-26
-22
-19
-24
-22
-30
-28
-21
-32
-21
-21
-27
-26
-30
-17
-19
-24
-27
-15
-18
-29
-17
-17
-21
-24
-14
-18
-26
-27
-16
-26
-18
-19
-18
-21
-18
-17
-27
-25
-27
-10
-12
-28
-28
-29
-18
-20
-15
-13
-15
-28
-19
-11
-9
-12
-18
-17
-17
-24
-19
-17
-16
-17
-21
-20
-13
-20
-20
-14
-17
-16
-13
-23
-5
-19
-21
-17
-43
-45
-44
-39
-39
-40
-47
-43
-45
-48
-36
-45
-54
-54
-58
-48
-42
-32
-46
-44
-42
-46
-51
-42
-38
-45
-36
-54
-48
-39
-46
-44
-40
-40
-54
-48
-47
-47
-39
-38
-50
-44
-44
-46
-32
-34
-36
-41
-35
-44
-39
-35
-36
-47
-35
-39
-40
-45
-42
-38
-35
-37
-29
-31
-37
-36
-34
-36
-40
-24
-37
-33
-37
-30
-32
-38
-33
-41
-31
-23
-24
-32
-32
-19
-18
-31
-30
-24
-25
-37
-27
-26
-21
-30
-26
-22
-33
-28
-32
-25
-29
-24
-21
-27
-29
-31
-25
-21
-24
-22
-28
-23
-20
-28
-27
-24
-20
-25
-27
-18
-20
-27
-17
-24
-24
-21
-21
-17
-23
-36
-28
-16
-20
-16
-30
-20
-25
-19
-16
-17
-23
-22
-13
-16
-23
-26
-15
-17
-27
-16
-19
-20
-17
-20
-18
-17
-20
-21
-23
-13
-26
-25
-24
-16
-17
-18
-15
-21
-18
-13
-18
-21
-17
-20
-13
-23
-32
-19
-20
-14
-22
-13
-12
-16
-17
-20
-11
-16
-15
-20
-21
-16
-32
-40
-42
-46
-43
-42
-53
-38
-49
-44
-45
-47
-49
-55
-63
-46
-61
-49
-49
-39
-51
-42
-42
-45
-48
-46
-44
-60
-52
-48
-52
-45
-41
-44
-50
-43
-49
-34
-45
-49
-49
-54
-44
-43
-47
-38
-47
-38
-37
-48
-34
-40
-42
-39
-45
-34
-47
-35
-48
-31
-41
-38
-44
-32
-35
-34
-38
-29
-33
-25
-28
-27
-22
-26
-30
-35
-27
-23
-25
-22
-25
-25
-25
-45
-24
-32
-26
-31
-34
-24
-28
-23
-25
-26
-20
-30
-22
-26
-30
-27
-22
-23
-19
-25
-24
-24
-17
-29
-25
-14
-24
-19
-30
-23
-25
-24
-24
-19
-34
-22
-26
-25
-21
-20
-29
-24
-27
-26
-29
-22
-30
-25
-19
-18
-16
-24
-19
-23
-31
-19
-22
-28
-21
-28
-19
-23
-17
-25
-28
-28
-21
-25
-22
-19
-27
-22
-23
-25
-12
-20
-20
-19
-19
-23
-14
-21
-18
-22
-22
-22
-26
-17
-13
-11
-20
-16
-14
-16
-17
-19
-14
-7
-20
-9
-17
-19
-17
-19
-16
-21
-18
-19
-54
-48
-44
-48
-64
-54
-48
-53
-46
-47
-51
-41
-54
-52
-52
-70
-43
-48
-53
-60
-50
-49
-67
-45
-64
-53
-64
-52
-66
-49
-48
-41
-35
-43
-47
-45
-45
-49
-43
-30
-43
-44
-39
-55
-52
-28
-42
-43
-42
-44
-44
-47
-37
-46
-39
-29
-37
-45
-33
-30
-28
-35
-41
-32
-36
-30
-24
-27
-39
-32
-33
-31
-37
-34
-29
-29
-28
-20
-22
-13
-26
-24
-28
-18
-26
-23
-28
-29
-26
-28
-28
-24
-25
-27
-29
-23
-26
-28
-33
-28
-26
-18
-31
-26
-29
-23
-21
-31
-25
-22
-29
-24
-23
-24
-23
-25
-16
-16
-30
-24
-22
-28
-27
-14
-34
-24
-19
-13
-22
-27
-19
-16
-21
-24
-20
-27
-22
-24
-19
-24
-31
-22
-27
-28
-21
-16
-24
-21
-21
-18
-26
-21
-22
-16
-19
-10
-27
-22
-13
-24
-25
-21
-28
-22
-19
-26
-22
-21
-23
-18
-14
-11
-20
-22
-17
-14
-16
-13
-17
-13
-10
-12
-17
-23
-15
-16
-17
-8
-12
-18
-10
-20
-60
-52
-52
-52
-49
-49
-40
-55
-40
-50
-37
-48
-54
-47
-59
-53
-55
-49
-54
-52
-56
-55
-62
-54
-53
-48
-52
-56
-55
-44
-58
-47
-55
-62
-38
-50
-54
-48
-53
-45
-44
-39
-45
-36
-43
-35
-40
-34
-41
-51
-40
-39
-36
-37
-38
-47
-30
-39
-35
-29
-31
-28
-30
-26
-29
-35
-35
-37
-37
-30
-34
-32
-37
-26
-30
-21
-30
-25
-38
-18
-18
-30
-31
-29
-23
-20
-31
-30
-29
-27
-27
-26
-30
-31
-28
-30
-22
-26
-21
-26
-20
-29
-29
-31
-19
-27
-19
-27
-23
-21
-16
-29
-23
-34
-28
-24
-23
-27
-30
-21
-21
-26
-19
-17
-13
-20
-24
-14
-26
-16
-24
-24
-25
-14
-20
-22
-22
-22
-25
-28
-14
-20
-23
-20
-25
-15
-22
-23
-18
-14
-19
-22
-27
-13
-21
-16
-22
-20
-19
-23
-15
-23
-22
-20
-20
-23
-14
-12
-17
-27
-16
-20
-16
-20
-16
-25
-14
-22
-19
-25
-24
-14
-16
-16
-17
-11
-10
-6
-19
-15
-11
-16
-45
-57
-37
-50
-55
-58
-47
-60
-59
-58
-51
-60
-59
-61
-57
-58
-62
-53
-65
-52
-78
-72
-75
-70
-42
-54
-61
-61
-61
-60
-74
-67
-54
-53
-49
-50
-51
-47
-55
-53
-45
-50
-48
-57
-42
-59
-57
-45
-38
-42
-41
-40
-33
-53
-43
-31
-42
-30
-37
-28
-37
-35
-25
-31
-30
-34
-33
-37
-25
-32
-33
-31
-43
-30
-24
-40
-33
-19
-31
-30
-28
-30
-14
-31
-23
-23
-19
-18
-22
-17
-26
-30
-29
-26
-34
-26
-25
-34
-20
-31
-26
-30
-23
-18
-24
-26
-22
-24
-24
-33
-30
-31
-17
-19
-29
-37
-27
-31
-32
-23
-30
-24
-20
-24
-26
-19
-20
-15
-18
-22
-22
-23
-26
-24
-27
-20
-22
-17
-22
-26
-25
-16
-23
-16
-13
-24
-29
-26
-20
-22
-17
-25
-18
-17
-23
-25
-19
-31
-26
-16
-10
-15
-14
-14
-17
-20
-17
-17
-25
-11
-10
-11
-10
-16
-25
-19
-14
-16
-16
-14
-15
-17
-11
-23
-11
-14
-17
-11
-16
-16
-22
-16
-46
-50
-49
-46
-47
-46
-49
-49
-52
-42
-59
-49
-58
-48
-62
-53
-60
-61
-60
-57
-60
-50
-62
-66
-59
-51
-62
-46
-50
-61
-51
-53
-54
-56
-56
-57
-41
-49
-62
-52
-46
-42
-39
-37
-53
-51
-51
-42
-49
-44
-45
-34
-47
-47
-51
-37
-34
-30
-36
-31
-43
-32
-35
-42
-25
-36
-29
-33
-39
-30
-36
-28
-31
-33
-37
-30
-35
-38
-37
-26
-36
-29
-35
-20
-26
-23
-26
-19
-23
-28
-29
-32
-20
-17
-27
-24
-21
-29
-23
-23
-21
-30
-33
-27
-29
-33
-27
-25
-19
-17
-15
-27
-27
-23
-17
-28
-27
-25
-23
-16
-29
-29
-28
-22
-22
-27
-21
-18
-23
-20
-25
-18
-20
-24
-21
-27
-19
-18
-21
-14
-21
-19
-23
-24
-18
-16
-22
-28
-15
-21
-16
-22
-15
-22
-18
-23
-26
-17
-16
-10
-15
-19
-30
-14
-21
-22
-16
-30
-13
-17
-13
-16
-15
-29
-15
-11
-26
-16
-19
-18
-10
-14
-11
-16
-20
-9
-15
-13
-15
-24
-17
-10
-63
-44
-57
-60
-55
-53
-52
-49
-47
-65
-64
-61
-66
-63
-50
-60
-57
-46
-51
-56
-73
-71
-67
-58
-64
-67
-77
-67
-65
-65
-80
-79
-38
-51
-67
-58
-49
-52
-55
-55
-55
-33
-56
-45
-56
-40
-50
-48
-51
-44
-44
-53
-44
-45
-32
-34
-34
-29
-33
-19
-41
-45
-37
-34
-31
-35
-47
-28
-30
-44
-31
-42
-31
-34
-22
-21
-34
-30
-27
-27
-23
-26
-28
-26
-21
-25
-24
-26
-23
-27
-22
-27
-24
-31
-24
-26
-29
-20
-22
-31
-24
-20
-23
-30
-23
-24
-18
-28
-17
-30
-23
-25
-25
-29
-23
-20
-18
-24
-23
-22
-21
-27
-18
-16
-24
-23
-15
-18
-25
-20
-24
-24
-22
-29
-20
-20
-24
-26
-25
-22
-12
-21
-9
-29
-25
-18
-21
-19
-26
-28
-23
-27
-22
-23
-21
-26
-29
-18
-17
-21
-24
-19
-16
-15
-14
-21
-24
-25
-17
-12
-16
-13
-18
-24
-24
-13
-20
-20
-23
-14
-18
-15
-20
-11
-18
-19
-16
-15
-18
-11
-13
-15
-58
-63
-52
-36
-58
-58
-46
-57
-41
-63
-58
-59
-60
-60
-59
-53
-54
-59
-55
-49
-75
-66
-64
-58
-58
-56
-72
-57
-51
-44
-66
-51
-55
-47
-63
-57
-56
-51
-58
-50
-48
-55
-48
-51
-41
-52
-38
-48
-41
-44
-37
-40
-36
-38
-33
-39
-36
-33
-53
-35
-36
-29
-31
-38
-32
-27
-37
-40
-32
-29
-35
-30
-43
-24
-33
-31
-22
-27
-35
-29
-36
-32
-29
-24
-21
-24
-20
-26
-19
-25
-21
-27
-26
-20
-31
-27
-19
-30
-23
-28
-22
-22
-21
-19
-24
-26
-13
-36
-28
-29
-23
-24
-22
-17
-15
-25
-21
-22
-19
-31
-29
-32
-22
-26
-31
-25
-24
-34
-25
-34
-28
-31
-18
-20
-23
-20
-26
-20
-30
-24
-20
-24
-19
-28
-21
-21
-37
-20
-26
-19
-25
-22
-19
-15
-18
-15
-16
-20
-24
-27
-13
-13
-18
-15
-37
-29
-15
-20
-27
-21
-16
-20
-25
-23
-18
-14
-20
-23
-18
-16
-16
-17
-17
-17
-15
-16
-26
-17
-21
-15
-10
-13
-60
-51
-52
-50
-55
-67
-61
-57
-59
-63
-61
-64
-61
-63
-58
-55
-59
-66
-60
-65
-66
-73
-56
-51
-59
-73
-74
-66
-55
-53
-71
-64
-54
-59
-67
-52
-52
-64
-54
-57
-57
-49
-58
-54
-55
-41
-39
-48
-43
-43
-37
-44
-42
-46
-33
-46
-50
-35
-31
-33
-34
-48
-40
-31
-47
-34
-31
-34
-31
-38
-30
-37
-30
-26
-25
-29
-34
-23
-28
-22
-28
-31
-24
-20
-18
-27
-18
-31
-27
-35
-30
-17
-26
-27
-29
-21
-31
-26
-22
-26
-29
-29
-22
-24
-12
-19
-35
-22
-20
-36
-20
-26
-23
-22
-25
-23
-16
-15
-26
-26
-18
-17
-19
-24
-16
-32
-14
-19
-21
-20
-18
-25
-25
-15
-25
-20
-22
-26
-23
-22
-24
-21
-22
-23
-27
-23
-19
-19
-22
-21
-29
-22
-24
-21
-21
-23
-19
-22
-22
-25
-15
-15
-23
-13
-18
-18
-19
-14
-23
-21
-10
-20
-16
-12
-13
-17
-12
-23
-16
-7
-16
-13
-19
-19
-17
-18
-21
-16
-16
-14
-11
-12
-68
-62
-52
-50
-65
-60
-68
-57
-63
-84
-76
-80
-69
-73
-58
-69
-72
-69
-77
-79
-66
-81
-70
-78
-72
-65
-66
-62
-62
-66
-71
-68
-55
-57
-61
-55
-58
-58
-54
-59
-57
-59
-61
-51
-55
-49
-53
-53
-59
-41
-41
-46
-44
-44
-46
-34
-31
-42
-44
-38
-54
-38
-46
-37
-35
-42
-34
-30
-33
-25
-33
-39
-30
-32
-39
-31
-37
-36
-35
-26
-22
-30
-31
-19
-22
-33
-25
-40
-17
-35
-33
-36
-28
-29
-18
-25
-25
-29
-16
-32
-25
-25
-26
-26
-24
-24
-30
-38
-24
-22
-26
-18
-28
-32
-18
-22
-26
-21
-24
-25
-28
-21
-21
-25
-24
-32
-19
-24
-30
-29
-33
-25
-26
-28
-26
-27
-26
-21
-37
-22
-19
-26
-22
-24
-19
-20
-34
-17
-30
-25
-25
-27
-19
-25
-19
-21
-20
-26
-16
-27
-24
-17
-19
-21
-12
-13
-12
-23
-19
-14
-22
-20
-15
-15
-24
-12
-13
-16
-14
-20
-15
-21
-17
-15
-12
-11
-12
-15
-19
-18
-14
-13
-63
-65
-48
-59
-48
-57
-54
-71
-62
-68
-50
-86
-73
-52
-64
-65
-72
-65
-78
-64
-75
-56
-81
-66
-70
-68
-72
-93
-68
-76
-69
-50
-79
-77
-65
-59
-70
-56
-50
-52
-48
-60
-70
-58
-47
-45
-57
-45
-55
-50
-44
-50
-48
-27
-37
-38
-36
-37
-38
-48
-43
-29
-39
-32
-27
-22
-27
-33
-45
-29
-33
-36
-41
-36
-30
-34
-22
-36
-28
-32
-30
-30
-31
-34
-24
-24
-19
-28
-31
-30
-39
-28
-28
-40
-16
-28
-37
-28
-31
-32
-26
-17
-19
-23
-25
-27
-29
-33
-24
-12
-27
-25
-27
-34
-17
-30
-18
-17
-22
-17
-20
-26
-14
-23
-26
-24
-21
-18
-32
-17
-22
-27
-28
-24
-26
-22
-19
-19
-21
-19
-24
-29
-22
-25
-25
-23
-20
-20
-34
-21
-26
-17
-20
-19
-10
-18
-20
-20
-18
-15
-16
-18
-20
-22
-17
-23
-20
-18
-16
-27
-17
-19
-16
-18
-17
-11
-23
-8
-16
-13
-16
-20
-10
-15
-16
-24
-11
-11
-14
-19
-12
-14
-67
-54
-49
-62
-50
-58
-70
-48
-57
-57
-76
-59
-73
-72
-69
-62
-64
-81
-72
-63
-78
-68
-88
-70
-90
-65
-64
-77
-70
-67
-66
-42
-67
-83
-63
-74
-67
-77
-62
-63
-56
-60
-58
-42
-67
-54
-40
-44
-62
-57
-58
-39
-41
-36
-37
-45
-29
-33
-39
-41
-39
-52
-34
-41
-34
-39
-38
-25
-37
-32
-23
-27
-27
-23
-41
-29
-28
-28
-24
-41
-27
-37
-20
-17
-27
-20
-24
-21
-25
-29
-28
-18
-21
-18
-32
-29
-17
-18
-22
-26
-31
-28
-19
-29
-27
-28
-32
-29
-20
-21
-24
-26
-24
-26
-21
-33
-27
-21
-25
-23
-29
-21
-14
-16
-20
-30
-20
-27
-17
-28
-20
-16
-22
-23
-30
-11
-21
-23
-24
-22
-26
-21
-16
-24
-12
-24
-13
-18
-22
-23
-9
-24
-24
-17
-20
-18
-23
-10
-22
-24
-22
-29
-24
-20
-10
-14
-13
-27
-20
-15
-16
-22
-17
-16
-19
-11
-16
-28
-14
-9
-9
-15
-25
-19
-17
-10
-11
-11
-19
-17
-18
-22
-60
-74
-56
-70
-63
-55
-68
-63
-69
-66
-74
-79
-82
-77
-59
-88
-51
-71
-78
-64
-92
-71
-75
-63
-71
-71
-74
-82
-58
-66
-84
-69
-54
-86
-74
-74
-74
-75
-69
-64
-46
-53
-60
-54
-52
-62
-67
-45
-45
-57
-47
-47
-44
-39
-44
-31
-44
-57
-24
-51
-41
-46
-34
-42
-29
-33
-34
-36
-39
-35
-43
-38
-23
-44
-35
-38
-23
-28
-34
-29
-46
-38
-34
-28
-34
-31
-32
-24
-35
-35
-24
-22
-19
-25
-33
-26
-24
-38
-27
-30
-26
-31
-24
-21
-22
-24
-28
-16
-21
-22
-25
-21
-31
-24
-28
-30
-23
-22
-20
-13
-21
-34
-20
-20
-30
-20
-27
-22
-22
-26
-20
-22
-24
-33
-20
-27
-21
-19
-23
-21
-23
-20
-23
-27
-21
-24
-22
-14
-24
-22
-24
-29
-23
-20
-27
-16
-19
-17
-20
-20
-17
-16
-19
-16
-19
-17
-18
-22
-11
-12
-17
-15
-10
-23
-19
-13
-19
-10
-19
-25
-18
-21
-28
-18
-16
-15
-17
-8
-25
-12
-18
-12
-72
-74
-68
-64
-63
-74
-61
-62
-60
-66
-79
-91
-74
-67
-85
-73
-70
-82
-79
-81
-68
-73
-78
-89
-88
-84
-72
-80
-58
-66
-59
-75
-63
-62
-64
-70
-56
-74
-66
-62
-54
-66
-58
-56
-47
-55
-74
-40
-48
-58
-45
-57
-46
-54
-52
-53
-51
-40
-37
-29
-40
-34
-39
-41
-47
-44
-48
-41
-30
-33
-26
-34
-26
-40
-32
-32
-34
-29
-22
-24
-38
-32
-29
-35
-31
-32
-22
-26
-33
-36
-30
-25
-28
-29
-16
-38
-33
-22
-24
-45
-28
-21
-20
-29
-32
-16
-26
-26
-18
-20
-18
-20
-31
-19
-23
-31
-20
-23
-23
-25
-18
-28
-20
-24
-18
-29
-37
-25
-23
-20
-27
-20
-25
-27
-22
-25
-26
-23
-21
-21
-25
-29
-33
-27
-31
-25
-14
-16
-18
-20
-20
-18
-21
-24
-14
-27
-18
-19
-20
-26
-22
-17
-24
-17
-19
-21
-17
-17
-18
-10
-15
-24
-14
-17
-23
-18
-13
-17
-20
-15
-21
-18
-12
-13
-22
-21
-19
-20
-16
-17
-12
-18
-76
-84
-57
-70
-68
-67
-60
-77
-68
-87
-90
-83
-91
-78
-76
-90
-85
-77
-100
-72
-77
-86
-81
-76
-83
-75
-76
-73
-81
-79
-100
-60
-83
-62
-63
-72
-85
-73
-61
-86
-70
-69
-50
-68
-58
-57
-61
-49
-48
-47
-43
-52
-45
-43
-34
-58
-42
-47
-47
-35
-43
-40
-44
-34
-50
-45
-36
-44
-43
-31
-25
-45
-23
-38
-20
-38
-30
-26
-40
-27
-32
-27
-32
-39
-28
-27
-34
-25
-33
-21
-34
-35
-31
-28
-30
-25
-31
-26
-22
-23
-23
-26
-21
-20
-26
-20
-26
-21
-27
-26
-26
-30
-30
-22
-21
-22
-20
-17
-19
-26
-29
-19
-17
-21
-21
-25
-25
-25
-28
-35
-26
-22
-20
-20
-34
-24
-21
-16
-20
-27
-21
-14
-20
-23
-29
-23
-11
-19
-30
-20
-27
-19
-21
-22
-21
-27
-24
-25
-19
-25
-14
-28
-22
-19
-10
-24
-17
-28
-13
-26
-18
-16
-14
-23
-26
-16
-22
-21
-18
-15
-20
-22
-27
-19
-23
-18
-10
-13
-12
-14
-19
-20
-70
-78
-66
-70
-78
-66
-82
-89
-71
-99
-65
-83
-73
-87
-78
-88
-77
-90
-83
-78
-85
-85
-102
-96
-83
-83
-77
-97
-97
-76
-70
-67
-68
-87
-61
-58
-59
-70
-59
-53
-69
-76
-66
-69
-68
-63
-65
-47
-40
-51
-65
-38
-54
-50
-52
-62
-52
-49
-47
-42
-38
-50
-46
-34
-46
-39
-44
-41
-30
-32
-44
-33
-39
-36
-35
-26
-35
-37
-39
-26
-33
-36
-27
-37
-29
-33
-29
-31
-23
-28
-26
-29
-33
-37
-32
-17
-25
-23
-37
-25
-27
-20
-22
-24
-27
-27
-23
-28
-22
-25
-24
-22
-21
-26
-25
-23
-30
-21
-23
-19
-32
-19
-12
-30
-26
-20
-24
-8
-24
-24
-21
-27
-20
-23
-20
-17
-30
-23
-24
-21
-31
-23
-26
-27
-23
-23
-23
-22
-24
-30
-25
-17
-25
-21
-20
-22
-13
-16
-22
-24
-24
-14
-17
-20
-27
-17
-14
-26
-20
-20
-17
-10
-13
-18
-17
-30
-22
-16
-12
-12
-20
-11
-12
-20
-24
-27
-15
-13
-16
-13
-23
-19
-79
-74
-72
-59
-75
-68
-80
-80
-57
-75
-77
-86
-82
-84
-90
-101
-95
-79
-96
-80
-94
-93
-95
-98
-82
-98
-78
-82
-77
-77
-85
-78
-84
-90
-72
-94
-60
-75
-77
-78
-77
-64
-60
-73
-72
-55
-64
-56
-68
-53
-40
-59
-43
-50
-45
-44
-38
-50
-38
-39
-39
-35
-35
-43
-37
-41
-36
-43
-41
-41
-34
-43
-35
-33
-29
-29
-34
-26
-35
-28
-38
-24
-28
-32
-22
-28
-30
-27
-29
-31
-29
-32
-25
-25
-30
-18
-20
-26
-20
-27
-25
-26
-23
-28
-31
-25
-27
-28
-31
-23
-31
-16
-25
-32
-23
-20
-32
-26
-22
-19
-24
-22
-35
-17
-26
-24
-19
-31
-21
-21
-30
-23
-24
-19
-25
-25
-20
-19
-19
-20
-19
-15
-20
-20
-29
-18
-20
-20
-21
-22
-20
-17
-20
-16
-22
-18
-24
-16
-16
-20
-16
-9
-24
-20
-14
-24
-19
-25
-13
-11
-18
-13
-14
-23
-20
-20
-21
-23
-17
-20
-23
-15
-13
-13
-20
-14
-23
-16
-18
-15
-16
-27
-78
-54
-67
-74
-93
-85
-79
-80
-81
-99
-93
-93
-88
-117
-75
-88
-90
-86
-105
-89
-92
-78
-91
-105
-101
-96
-95
-100
-88
-77
-84
-88
-86
-85
-87
-66
-59
-94
-81
-63
-71
-71
-61
-74
-66
-45
-70
-66
-60
-44
-64
-47
-69
-48
-48
-55
-41
-49
-54
-43
-46
-49
-51
-36
-48
-40
-39
-39
-37
-50
-40
-31
-30
-33
-35
-38
-39
-37
-29
-27
-24
-27
-33
-39
-33
-33
-25
-30
-24
-26
-36
-33
-25
-34
-27
-30
-32
-31
-28
-20
-27
-20
-23
-26
-27
-27
-27
-23
-21
-36
-26
-22
-20
-26
-26
-17
-24
-23
-26
-24
-25
-18
-21
-23
-29
-21
-22
-21
-25
-29
-22
-26
-23
-14
-19
-17
-22
-23
-17
-30
-20
-18
-24
-28
-26
-27
-24
-22
-23
-13
-25
-21
-35
-18
-22
-18
-20
-31
-18
-17
-17
-15
-18
-18
-23
-20
-21
-25
-14
-11
-17
-16
-29
-22
-18
-13
-14
-9
-14
-12
-20
-23
-12
-20
-12
-17
-17
-15
-16
-19
-18
-15
-101
-76
-84
-72
-88
-61
-77
-103
-80
-84
-98
-97
-95
-113
-111
-95
-105
-94
-114
-112
-102
-108
-95
-88
-93
-103
-87
-91
-85
-90
-93
-93
-72
-95
-76
-80
-90
-81
-80
-58
-94
-88
-65
-68
-57
-71
-66
-61
-55
-53
-64
-50
-52
-54
-48
-60
-49
-43
-57
-43
-35
-40
-42
-38
-42
-35
-33
-46
-36
-51
-42
-33
-39
-26
-28
-32
-37
-31
-28
-28
-25
-26
-33
-37
-24
-34
-32
-31
-24
-13
-27
-19
-5
-22
-33
-28
-33
-27
-21
-27
-20
-27
-23
-28
-30
-24
-22
-22
-19
-25
-23
-16
-25
-29
-29
-31
-19
-25
-28
-18
-24
-29
-22
-25
-24
-26
-19
-22
-23
-32
-18
-24
-19
-24
-20
-18
-22
-25
-23
-17
-17
-19
-22
-22
-24
-20
-17
-16
-30
-25
-30
-23
-15
-17
-15
-24
-25
-20
-24
-24
-15
-21
-22
-17
-14
-20
-24
-20
-19
-28
-22
-20
-22
-17
-19
-17
-24
-16
-20
-17
-23
-16
-22
-14
-18
-14
-12
-16
-19
-12
-16
-21
-69
-83
-87
-66
-84
-91
-88
-105
-84
-71
-85
-97
-88
-89
-106
-102
-107
-98
-95
-84
-85
-102
-85
-114
-111
-99
-95
-106
-77
-99
-91
-92
-79
-77
-87
-82
-77
-69
-91
-88
-87
-85
-72
-59
-77
-69
-69
-72
-68
-53
-69
-55
-56
-57
-44
-50
-34
-41
-39
-53
-50
-38
-47
-42
-41
-41
-36
-33
-48
-38
-33
-24
-28
-32
-33
-32
-41
-29
-39
-28
-33
-28
-31
-24
-34
-23
-30
-38
-28
-40
-28
-22
-21
-43
-34
-29
-22
-15
-26
-27
-19
-29
-31
-21
-20
-25
-20
-28
-32
-23
-32
-26
-22
-23
-23
-19
-28
-36
-23
-27
-31
-21
-22
-23
-24
-19
-27
-25
-28
-16
-34
-21
-23
-32
-28
-27
-30
-22
-16
-23
-28
-25
-21
-22
-27
-25
-18
-23
-21
-21
-29
-25
-21
-17
-21
-24
-14
-18
-19
-7
-14
-21
-21
-23
-22
-19
-26
-23
-17
-20
-20
-15
-19
-12
-16
-26
-27
-25
-11
-17
-13
-17
-25
-14
-18
-17
-16
-19
-17
-27
-21
-16
-79
-104
-80
-80
-94
-88
-86
-108
-100
-121
-86
-106
-129
-101
-105
-123
-112
-118
-126
-114
-114
-115
-119
-121
-129
-104
-116
-112
-99
-119
-110
-113
-95
-101
-101
-98
-93
-81
-85
-77
-94
-82
-73
-75
-81
-91
-77
-60
-69
-69
-59
-68
-62
-59
-54
-51
-52
-53
-46
-47
-53
-54
-46
-49
-57
-45
-43
-50
-49
-37
-38
-44
-43
-32
-32
-36
-45
-42
-44
-38
-32
-32
-34
-21
-20
-29
-32
-30
-25
-32
-35
-22
-22
-32
-29
-30
-19
-33
-28
-27
-32
-27
-25
-18
-30
-24
-25
-27
-29
-20
-27
-24
-27
-20
-30
-20
-23
-26
-24
-32
-28
-30
-19
-23
-30
-29
-26
-21
-19
-27
-28
-18
-22
-30
-24
-18
-27
-35
-24
-22
-29
-32
-16
-21
-24
-16
-24
-20
-18
-12
-24
-17
-24
-20
-23
-15
-25
-15
-23
-11
-19
-20
-22
-20
-17
-26
-19
-21
-14
-17
-19
-18
-20
-8
-17
-18
-20
-20
-16
-20
-19
-16
-18
-22
-19
-13
-13
-15
-10
-24
-19
-20
-86
-82
-73
-84
-92
-92
-97
-103
-97
-111
-130
-104
-106
-111
-135
-115
-118
-112
-124
-137
-120
-131
-115
-136
-119
-112
-120
-122
-104
-108
-86
-104
-96
-104
-96
-86
-81
-82
-89
-87
-80
-83
-73
-88
-82
-69
-84
-76
-72
-72
-63
-60
-69
-68
-67
-50
-55
-62
-43
-37
-44
-46
-48
-42
-44
-49
-36
-45
-37
-38
-51
-39
-26
-27
-34
-35
-42
-34
-51
-27
-39
-27
-28
-37
-36
-26
-41
-18
-29
-34
-23
-18
-13
-22
-28
-26
-20
-28
-31
-32
-21
-17
-26
-27
-25
-29
-24
-26
-27
-29
-24
-23
-34
-27
-25
-34
-14
-26
-21
-27
-27
-33
-25
-33
-22
-22
-20
-22
-25
-37
-24
-25
-29
-29
-29
-30
-34
-21
-25
-24
-24
-27
-13
-20
-23
-17
-16
-20
-22
-21
-19
-22
-23
-24
-18
-20
-17
-17
-23
-20
-29
-18
-33
-19
-16
-24
-16
-17
-22
-14
-19
-15
-25
-15
-17
-23
-16
-14
-12
-27
-24
-9
-24
-23
-20
-14
-22
-18
-13
-21
-14
-20
-83
-96
-86
-89
-86
-79
-96
-113
-106
-120
-119
-116
-130
-115
-134
-130
-136
-147
-156
-124
-141
-153
-127
-117
-131
-127
-136
-138
-110
-108
-144
-115
-91
-101
-113
-86
-92
-103
-73
-82
-75
-85
-73
-83
-71
-76
-71
-74
-61
-70
-63
-60
-70
-69
-61
-54
-57
-47
-52
-37
-47
-47
-37
-43
-55
-39
-38
-37
-51
-40
-35
-30
-33
-36
-32
-34
-43
-27
-28
-31
-30
-22
-23
-31
-29
-30
-20
-26
-28
-32
-20
-35
-21
-41
-26
-24
-29
-26
-19
-24
-18
-20
-15
-24
-21
-26
-30
-27
-23
-18
-26
-15
-28
-29
-28
-25
-18
-17
-28
-30
-24
-28
-18
-23
-31
-23
-23
-14
-21
-27
-23
-21
-34
-21
-26
-21
-20
-31
-26
-12
-20
-30
-21
-21
-21
-17
-15
-26
-19
-25
-20
-28
-27
-16
-27
-14
-12
-17
-26
-14
-23
-21
-21
-16
-14
-24
-27
-21
-21
-19
-24
-13
-22
-17
-13
-20
-16
-14
-14
-11
-13
-17
-15
-16
-22
-16
-17
-21
-13
-15
-18
-12
-98
-94
-96
-94
-96
-82
-106
-90
-105
-116
-116
-145
-140
-149
-133
-125
-150
-133
-150
-148
-151
-174
-129
-135
-146
-141
-117
-123
-121
-126
-135
-122
-135
-102
-99
-102
-100
-76
-91
-101
-86
-74
-76
-84
-83
-76
-76
-77
-71
-68
-65
-61
-50
-53
-64
-62
-62
-54
-57
-53
-50
-40
-46
-42
-49
-40
-43
-44
-36
-37
-39
-40
-29
-34
-44
-35
-47
-40
-42
-34
-37
-31
-25
-37
-43
-28
-27
-22
-33
-35
-25
-31
-23
-17
-21
-22
-23
-25
-31
-26
-40
-29
-21
-24
-18
-22
-25
-29
-24
-29
-26
-13
-22
-25
-29
-37
-19
-30
-19
-23
-23
-28
-31
-20
-22
-29
-32
-36
-23
-13
-27
-17
-21
-16
-32
-30
-31
-21
-26
-23
-23
-18
-23
-25
-20
-15
-21
-22
-20
-14
-22
-27
-27
-26
-26
-20
-20
-22
-21
-29
-21
-20
-18
-14
-22
-15
-18
-23
-21
-20
-17
-24
-14
-16
-25
-16
-20
-10
-16
-17
-20
-17
-16
-12
-16
-10
-23
-20
-10
-14
-21
-17
-98
-92
-78
-98
-129
-103
-120
-112
-144
-120
-113
-157
-118
-182
-159
-174
-158
-174
-167
-172
-150
-158
-180
-156
-171
-138
-131
-162
-147
-131
-134
-124
-111
-113
-131
-114
-101
-97
-86
-82
-114
-86
-89
-107
-90
-66
-74
-68
-66
-74
-63
-65
-74
-46
-60
-58
-75
-56
-63
-57
-46
-61
-47
-43
-52
-45
-31
-37
-42
-56
-42
-31
-43
-33
-22
-39
-45
-28
-38
-33
-29
-37
-29
-31
-33
-29
-25
-31
-31
-29
-22
-37
-28
-32
-27
-28
-21
-35
-24
-34
-28
-24
-26
-32
-27
-31
-26
-20
-24
-28
-20
-23
-22
-23
-14
-31
-29
-27
-24
-34
-21
-24
-19
-17
-30
-10
-25
-18
-30
-27
-20
-27
-23
-21
-24
-23
-26
-24
-23
-22
-21
-21
-26
-19
-25
-23
-23
-16
-25
-18
-17
-28
-25
-22
-23
-29
-26
-23
-15
-30
-23
-19
-17
-19
-16
-17
-21
-19
-8
-21
-24
-21
-18
-17
-19
-18
-18
-11
-18
-18
-22
-18
-14
-17
-18
-12
-21
-9
-13
-10
-16
-17
-98
-89
-103
-120
-118
-115
-124
-123
-149
-160
-124
-129
-146
-152
-158
-155
-181
-158
-197
-148
-202
-185
-172
-157
-160
-182
-199
-149
-157
-157
-145
-131
-128
-121
-128
-117
-123
-99
-100
-90
-96
-97
-87
-79
-84
-71
-84
-60
-90
-71
-88
-59
-67
-65
-49
-55
-61
-48
-65
-57
-60
-32
-57
-34
-42
-38
-39
-45
-41
-48
-62
-43
-35
-49
-41
-36
-38
-35
-40
-32
-23
-39
-38
-36
-30
-31
-22
-28
-28
-24
-29
-29
-23
-23
-21
-25
-23
-25
-28
-31
-26
-32
-31
-33
-26
-27
-27
-24
-25
-29
-28
-27
-25
-29
-24
-26
-28
-31
-23
-22
-18
-20
-26
-32
-28
-32
-26
-23
-23
-19
-27
-27
-22
-17
-23
-18
-29
-25
-27
-25
-28
-28
-23
-25
-19
-26
-19
-20
-22
-23
-18
-19
-20
-25
-11
-20
-19
-23
-21
-22
-22
-20
-19
-21
-21
-26
-23
-17
-23
-19
-15
-20
-17
-16
-20
-21
-24
-10
-10
-15
-20
-12
-13
-15
-12
-21
-22
-18
-20
-17
-19
-22
-108
-112
-111
-114
-119
-132
-134
-149
-163
-162
-178
-161
-153
-197
-179
-182
-204
-192
-222
-179
-198
-214
-177
-175
-187
-209
-186
-190
-176
-182
-162
-160
-149
-134
-115
-116
-128
-113
-99
-108
-81
-98
-82
-79
-81
-73
-79
-72
-69
-82
-78
-77
-65
-57
-63
-65
-54
-50
-42
-43
-62
-45
-57
-43
-46
-57
-36
-32
-32
-42
-41
-36
-33
-39
-36
-36
-32
-30
-49
-35
-35
-39
-26
-33
-35
-19
-15
-46
-28
-28
-29
-31
-21
-33
-31
-19
-16
-28
-23
-24
-18
-19
-23
-32
-29
-25
-33
-29
-24
-32
-28
-26
-29
-29
-23
-23
-20
-23
-30
-30
-23
-21
-17
-30
-26
-31
-18
-27
-35
-31
-23
-24
-16
-29
-18
-27
-18
-22
-21
-20
-26
-26
-19
-23
-14
-17
-27
-24
-20
-27
-28
-15
-22
-25
-19
-26
-18
-17
-30
-28
-16
-21
-20
-22
-23
-17
-23
-19
-20
-22
-21
-15
-16
-13
-17
-19
-23
-12
-32
-16
-11
-23
-20
-15
-21
-23
-19
-16
-12
-20
-17
-20
-105
-119
-102
-121
-98
-161
-129
-148
-169
-171
-181
-211
-199
-195
-184
-196
-208
-171
-176
-232
-201
-232
-226
-184
-191
-218
-198
-220
-173
-144
-163
-157
-168
-131
-158
-149
-125
-124
-108
-118
-122
-85
-91
-85
-71
-79
-80
-78
-94
-79
-67
-70
-71
-57
-61
-54
-58
-63
-48
-47
-61
-59
-52
-52
-50
-45
-40
-38
-55
-54
-45
-42
-46
-36
-34
-39
-39
-34
-41
-29
-37
-29
-25
-34
-39
-21
-35
-32
-34
-31
-25
-26
-21
-32
-36
-27
-25
-24
-21
-23
-28
-32
-18
-20
-20
-18
-27
-24
-19
-25
-22
-26
-15
-34
-25
-20
-17
-21
-25
-23
-29
-23
-23
-18
-21
-26
-24
-24
-33
-28
-20
-27
-20
-18
-18
-26
-16
-25
-24
-25
-24
-29
-23
-21
-21
-19
-20
-11
-28
-22
-14
-23
-26
-26
-18
-27
-31
-23
-11
-38
-23
-22
-21
-23
-26
-16
-15
-11
-18
-13
-7
-20
-23
-16
-21
-27
-27
-18
-18
-14
-15
-20
-16
-17
-13
-12
-17
-19
-23
-18
-12
-19
-117
-113
-112
-120
-138
-161
-182
-168
-168
-180
-195
-214
-217
-241
-219
-220
-214
-252
-229
-220
-261
-268
-241
-225
-231
-221
-211
-242
-220
-212
-188
-168
-148
-164
-140
-135
-139
-126
-134
-118
-96
-99
-96
-99
-88
-88
-81
-78
-83
-76
-72
-71
-72
-79
-87
-65
-68
-64
-48
-47
-54
-50
-53
-40
-51
-51
-37
-44
-36
-51
-44
-52
-46
-50
-35
-42
-33
-38
-44
-21
-26
-41
-28
-35
-29
-29
-35
-33
-31
-27
-37
-40
-26
-37
-24
-34
-37
-21
-26
-30
-22
-20
-26
-21
-28
-23
-22
-25
-27
-26
-19
-14
-19
-33
-20
-23
-23
-26
-24
-25
-26
-20
-15
-24
-14
-27
-21
-21
-20
-18
-31
-15
-17
-29
-29
-26
-35
-24
-34
-19
-23
-23
-17
-35
-30
-21
-22
-25
-21
-22
-26
-19
-22
-27
-21
-21
-23
-17
-24
-24
-27
-27
-21
-15
-18
-30
-15
-11
-21
-13
-26
-18
-28
-7
-14
-21
-21
-14
-16
-18
-12
-15
-16
-10
-20
-25
-17
-24
-17
-14
-14
-28
-132
-113
-123
-140
-146
-168
-165
-153
-174
-208
-195
-202
-194
-244
-249
-234
-265
-255
-261
-223
-256
-254
-247
-251
-254
-250
-217
-250
-209
-208
-214
-210
-178
-171
-170
-144
-137
-132
-133
-130
-110
-112
-97
-103
-88
-73
-75
-84
-92
-77
-83
-64
-62
-69
-67
-64
-68
-63
-60
-56
-46
-44
-44
-59
-42
-50
-43
-46
-46
-38
-38
-38
-36
-46
-43
-31
-32
-24
-34
-29
-38
-44
-23
-36
-33
-27
-34
-40
-34
-24
-32
-37
-31
-32
-44
-24
-21
-24
-28
-25
-32
-32
-17
-14
-30
-21
-25
-31
-22
-18
-25
-23
-32
-34
-27
-31
-26
-24
-24
-28
-29
-16
-26
-24
-23
-22
-18
-19
-22
-23
-23
-24
-23
-20
-21
-20
-27
-19
-20
-24
-19
-29
-25
-15
-21
-34
-17
-20
-32
-17
-19
-11
-19
-18
-26
-18
-23
-14
-23
-32
-16
-23
-18
-20
-12
-21
-13
-22
-12
-16
-18
-23
-31
-18
-24
-16
-20
-18
-21
-12
-17
-18
-18
-20
-17
-14
-19
-10
-14
-18
-14
-18
-132
-147
-130
-149
-147
-169
-200
-211
-213
-226
-219
-232
-247
-255
-301
-282
-306
-288
-292
-287
-308
-321
-285
-307
-252
-241
-282
-237
-257
-208
-211
-235
-204
-185
-172
-180
-167
-175
-141
-140
-146
-113
-105
-114
-98
-93
-85
-79
-82
-76
-96
-79
-77
-80
-68
-70
-67
-55
-53
-65
-66
-58
-47
-55
-50
-44
-49
-32
-51
-50
-32
-41
-32
-47
-31
-35
-39
-34
-32
-41
-26
-43
-29
-40
-32
-26
-33
-32
-42
-23
-27
-32
-32
-28
-35
-30
-30
-26
-23
-26
-24
-27
-30
-40
-27
-31
-34
-28
-16
-27
-18
-23
-30
-25
-29
-23
-28
-25
-24
-22
-32
-21
-26
-23
-17
-18
-26
-25
-32
-29
-26
-19
-18
-25
-21
-32
-27
-25
-16
-14
-19
-23
-12
-20
-35
-18
-11
-21
-16
-26
-20
-14
-30
-28
-30
-19
-23
-24
-16
-24
-16
-23
-25
-21
-20
-22
-19
-21
-14
-20
-20
-20
-21
-16
-13
-15
-13
-25
-28
-19
-10
-14
-12
-14
-23
-15
-9
-13
-11
-12
-16
-15
-127
-153
-142
-130
-171
-189
-186
-201
-203
-235
-244
-257
-267
-266
-321
-265
-281
-319
-331
-343
-323
-315
-323
-316
-321
-265
-298
-269
-256
-235
-210
-232
-225
-173
-192
-168
-159
-183
-132
-132
-109
-121
-114
-106
-83
-101
-82
-91
-78
-73
-70
-72
-88
-62
-68
-53
-58
-70
-76
-61
-65
-52
-60
-47
-39
-49
-49
-44
-46
-44
-35
-42
-42
-32
-39
-43
-29
-29
-42
-35
-34
-36
-32
-36
-38
-39
-23
-29
-28
-27
-21
-24
-28
-36
-21
-20
-31
-22
-22
-35
-25
-23
-26
-26
-26
-30
-30
-35
-20
-24
-26
-30
-21
-20
-21
-26
-33
-24
-31
-26
-33
-29
-22
-16
-22
-31
-19
-26
-15
-25
-18
-29
-19
-26
-16
-25
-29
-36
-27
-28
-21
-24
-24
-29
-18
-26
-21
-26
-22
-16
-19
-24
-29
-31
-12
-27
-20
-20
-23
-25
-22
-23
-29
-22
-23
-18
-15
-25
-18
-15
-29
-22
-12
-20
-16
-16
-14
-26
-20
-19
-17
-18
-15
-16
-20
-18
-16
-10
-27
-12
-17
-15
-136
-157
-157
-165
-176
-200
-190
-205
-214
-245
-247
-286
-288
-304
-321
-331
-310
-377
-341
-354
-363
-387
-356
-342
-353
-321
-304
-304
-283
-284
-220
-245
-229
-213
-195
-173
-191
-161
-144
-117
-157
-131
-118
-108
-98
-77
-95
-83
-72
-87
-72
-59
-67
-73
-77
-67
-69
-55
-54
-49
-45
-49
-46
-38
-44
-51
-49
-41
-51
-45
-45
-40
-38
-31
-46
-53
-26
-36
-39
-36
-33
-34
-30
-36
-25
-27
-26
-33
-22
-24
-28
-23
-29
-28
-20
-26
-25
-21
-25
-32
-26
-23
-16
-24
-13
-15
-27
-32
-32
-27
-29
-26
-28
-30
-16
-20
-17
-20
-29
-37
-27
-25
-21
-25
-16
-22
-18
-24
-30
-32
-28
-26
-28
-29
-20
-31
-19
-23
-22
-23
-29
-22
-15
-24
-19
-23
-19
-19
-21
-19
-22
-22
-27
-25
-25
-19
-15
-17
-17
-17
-22
-22
-23
-13
-19
-32
-12
-14
-20
-20
-23
-16
-13
-12
-22
-16
-10
-13
-17
-17
-20
-14
-8
-23
-25
-11
-18
-14
-19
-16
-17
-19
-170
-164
-149
-180
-178
-194
-211
-252
-239
-332
-270
-303
-306
-333
-380
-367
-366
-409
-399
-399
-429
-435
-426
-397
-416
-374
-361
-335
-320
-263
-275
-255
-243
-223
-215
-210
-190
-189
-165
-174
-135
-125
-123
-129
-97
-101
-99
-91
-81
-81
-81
-63
-75
-80
-75
-71
-79
-70
-56
-62
-59
-41
-52
-54
-45
-42
-44
-48
-41
-39
-39
-51
-50
-45
-35
-30
-23
-31
-35
-38
-31
-38
-30
-37
-31
-35
-37
-34
-36
-36
-34
-15
-31
-27
-28
-24
-20
-31
-26
-30
-26
-28
-26
-21
-22
-16
-13
-31
-37
-24
-32
-26
-24
-21
-24
-26
-18
-28
-33
-18
-15
-20
-28
-15
-20
-18
-24
-23
-24
-25
-20
-31
-27
-19
-31
-26
-28
-39
-18
-24
-30
-22
-21
-22
-35
-16
-24
-23
-24
-21
-26
-13
-15
-22
-32
-26
-19
-20
-26
-20
-19
-20
-28
-22
-19
-23
-16
-25
-23
-20
-27
-18
-21
-16
-20
-18
-16
-19
-25
-17
-14
-13
-22
-19
-14
-20
-17
-15
-18
-29
-21
-21
-147
-140
-190
-168
-173
-192
-222
-222
-270
-278
-282
-292
-341
-351
-418
-404
-438
-462
-521
-461
-506
-490
-521
-445
-424
-417
-387
-388
-387
-311
-287
-283
-216
-254
-190
-212
-194
-181
-148
-128
-128
-133
-114
-122
-108
-100
-97
-91
-89
-88
-75
-71
-81
-76
-66
-62
-66
-71
-70
-35
-53
-66
-53
-40
-32
-54
-48
-49
-50
-39
-33
-38
-46
-33
-33
-51
-40
-38
-29
-33
-33
-39
-27
-38
-32
-37
-28
-28
-29
-28
-22
-20
-29
-30
-35
-28
-30
-29
-28
-26
-20
-29
-26
-22
-27
-24
-21
-25
-13
-37
-28
-23
-26
-23
-18
-20
-24
-18
-16
-34
-28
-29
-29
-30
-18
-21
-18
-13
-24
-19
-22
-16
-15
-21
-28
-26
-25
-24
-24
-24
-20
-19
-25
-21
-25
-19
-26
-25
-22
-24
-28
-21
-21
-16
-23
-31
-22
-27
-16
-25
-30
-14
-24
-29
-38
-20
-23
-23
-18
-19
-16
-18
-18
-18
-13
-11
-19
-17
-20
-16
-18
-13
-17
-8
-15
-19
-17
-11
-18
-19
-14
-28
-177
-187
-193
-184
-231
-252
-252
-280
-298
-288
-354
-373
-382
-409
-492
-548
-561
-588
-641
-656
-640
-654
-640
-570
-552
-502
-475
-438
-412
-345
-330
-290
-283
-280
-246
-246
-204
-211
-180
-169
-177
-139
-142
-153
-111
-104
-112
-81
-79
-85
-87
-74
-62
-75
-63
-61
-63
-73
-57
-68
-56
-54
-56
-49
-43
-40
-45
-41
-39
-44
-48
-37
-38
-46
-34
-41
-32
-42
-34
-30
-28
-27
-38
-35
-29
-27
-25
-27
-29
-36
-28
-26
-28
-26
-25
-33
-34
-25
-17
-16
-25
-25
-15
-23
-26
-32
-32
-37
-16
-13
-31
-20
-27
-22
-17
-25
-16
-18
-22
-24
-21
-24
-18
-24
-24
-19
-17
-25
-18
-24
-26
-16
-20
-25
-18
-21
-17
-29
-15
-19
-23
-25
-18
-20
-27
-25
-28
-14
-22
-31
-27
-22
-18
-23
-20
-22
-27
-19
-22
-19
-20
-18
-16
-17
-15
-24
-18
-17
-20
-26
-16
-20
-10
-25
-10
-19
-23
-20
-17
-22
-13
-24
-11
-23
-11
-12
-19
-17
-14
-14
-6
-15
-180
-180
-196
-214
-245
-254
-244
-306
-322
-334
-374
-409
-474
-537
-585
-616
-718
-773
-691
-719
-699
-636
-669
-715
-697
-693
-573
-532
-469
-410
-378
-352
-312
-304
-299
-248
-227
-219
-196
-168
-166
-160
-161
-127
-120
-110
-120
-89
-92
-94
-79
-88
-79
-72
-77
-66
-62
-63
-85
-46
-48
-57
-51
-48
-46
-53
-55
-50
-47
-35
-54
-38
-40
-41
-37
-40
-41
-32
-35
-31
-28
-24
-26
-27
-34
-33
-37
-29
-28
-25
-34
-28
-40
-33
-22
-31
-30
-23
-34
-31
-30
-24
-36
-30
-28
-30
-27
-25
-22
-31
-23
-25
-22
-26
-20
-26
-25
-26
-25
-20
-29
-27
-26
-23
-35
-27
-27
-33
-15
-26
-32
-19
-18
-28
-27
-34
-21
-22
-16
-23
-26
-29
-37
-29
-28
-19
-23
-17
-25
-28
-20
-38
-18
-25
-16
-27
-25
-20
-30
-28
-21
-22
-29
-24
-18
-24
-24
-28
-22
-28
-33
-18
-24
-23
-16
-17
-26
-15
-20
-16
-16
-23
-19
-16
-15
-23
-15
-11
-17
-19
-20
-24
-200
-195
-174
-247
-245
-263
-283
-287
-291
-391
-397
-445
-550
-571
-681
-732
-657
-476
-302
-229
-164
-181
-274
-350
-502
-626
-681
-592
-508
-437
-427
-373
-338
-310
-310
-260
-236
-208
-185
-169
-166
-153
-146
-126
-102
-119
-95
-102
-99
-98
-80
-79
-75
-75
-74
-69
-53
-64
-59
-62
-56
-58
-65
-67
-48
-49
-55
-51
-41
-47
-40
-37
-40
-38
-40
-40
-32
-27
-40
-28
-25
-23
-29
-37
-35
-33
-31
-24
-30
-32
-30
-21
-18
-26
-33
-31
-30
-17
-17
-31
-25
-22
-24
-22
-28
-22
-34
-27
-17
-25
-20
-18
-18
-26
-25
-20
-27
-28
-22
-30
-21
-27
-26
-21
-31
-21
-24
-26
-25
-23
-24
-22
-16
-26
-21
-30
-20
-28
-21
-23
-21
-24
-18
-24
-19
-21
-23
-25
-29
-21
-30
-17
-25
-22
-24
-15
-20
-15
-19
-17
-23
-22
-29
-24
-22
-21
-26
-18
-16
-13
-25
-21
-19
-27
-23
-11
-26
-21
-18
-19
-20
-12
-12
-13
-19
-25
-14
-23
-18
-20
-14
-32
-188
-202
-223
-234
-276
-244
-311
-337
-368
-466
-499
-605
-669
-765
-710
-330
-108
-28
-3
-1
-1
-3
-7
-18
-69
-250
-535
-679
-626
-564
-459
-403
-349
-346
-330
-269
-272
-242
-230
-197
-178
-163
-145
-132
-140
-121
-113
-76
-104
-94
-106
-86
-66
-73
-77
-70
-69
-64
-74
-49
-60
-66
-52
-46
-51
-50
-43
-56
-46
-43
-50
-32
-35
-37
-46
-38
-37
-41
-37
-27
-37
-42
-40
-33
-25
-27
-29
-34
-29
-33
-31
-36
-26
-28
-40
-31
-29
-26
-32
-22
-30
-30
-30
-28
-27
-37
-35
-31
-15
-32
-27
-21
-32
-25
-34
-31
-39
-19
-22
-21
-19
-27
-28
-28
-29
-23
-21
-25
-24
-18
-29
-21
-22
-21
-29
-27
-20
-22
-24
-27
-18
-35
-24
-31
-21
-22
-21
-21
-16
-32
-25
-20
-23
-40
-25
-27
-29
-16
-20
-24
-12
-18
-25
-25
-26
-18
-20
-25
-23
-20
-21
-19
-13
-26
-16
-23
-17
-17
-16
-20
-12
-12
-20
-23
-19
-14
-16
-21
-16
-23
-21
-15
-195
-196
-191
-264
-255
-281
-305
-379
-386
-427
-524
-626
-771
-560
-170
-21
-2
-1
-3
-2
-1
-8
-1
-2
-4
-6
-76
-416
-643
-648
-517
-419
-375
-365
-297
-283
-259
-229
-226
-196
-203
-168
-144
-129
-134
-127
-131
-98
-97
-100
-92
-95
-88
-83
-59
-79
-59
-63
-57
-51
-68
-60
-58
-59
-41
-50
-38
-44
-51
-38
-45
-62
-46
-45
-29
-31
-43
-27
-38
-33
-35
-48
-24
-35
-32
-37
-30
-34
-24
-26
-31
-33
-26
-28
-38
-17
-36
-24
-29
-30
-23
-34
-28
-23
-27
-34
-26
-23
-23
-18
-20
-32
-31
-25
-30
-20
-19
-18
-21
-27
-23
-16
-27
-35
-28
-21
-21
-33
-17
-30
-23
-24
-28
-24
-18
-19
-25
-19
-23
-18
-23
-24
-23
-26
-29
-16
-19
-26
-22
-26
-22
-19
-28
-20
-22
-26
-23
-21
-20
-26
-9
-15
-20
-17
-27
-18
-14
-21
-20
-20
-13
-24
-27
-21
-22
-19
-14
-10
-18
-13
-19
-12
-21
-16
-13
-14
-13
-19
-19
-19
-13
-24
-184
-230
-226
-259
-283
-300
-312
-373
-451
-533
-609
-746
-589
-113
-4
-1
-1
-3
-3
-5
-1
-2
-2
-4
-3
-0
-5
-45
-369
-633
-616
-473
-432
-374
-357
-311
-273
-253
-256
-217
-206
-184
-184
-122
-147
-137
-119
-110
-104
-83
-95
-95
-85
-81
-76
-65
-67
-60
-65
-51
-48
-58
-63
-42
-56
-50
-50
-44
-50
-40
-59
-38
-55
-28
-34
-37
-29
-34
-44
-34
-28
-30
-37
-31
-31
-24
-24
-38
-30
-33
-22
-36
-27
-18
-30
-17
-28
-28
-27
-31
-39
-30
-32
-30
-22
-20
-25
-21
-26
-27
-24
-18
-28
-23
-22
-24
-32
-20
-18
-26
-28
-20
-26
-27
-23
-18
-19
-28
-18
-20
-25
-39
-29
-26
-16
-25
-25
-28
-24
-28
-22
-30
-18
-17
-21
-25
-18
-25
-17
-15
-20
-19
-25
-18
-14
-25
-28
-18
-23
-21
-23
-20
-22
-21
-25
-22
-13
-21
-19
-9
-24
-20
-20
-27
-16
-17
-17
-15
-26
-21
-17
-22
-22
-26
-18
-27
-17
-14
-19
-20
-26
-18
-254
-219
-238
-265
-292
-330
-357
-429
-501
-567
-720
-663
-136
-5
-5
-2
-6
-4
-1
-2
-1
-3
-2
-3
-1
-0
-3
-3
-52
-434
-656
-601
-493
-412
-326
-315
-285
-232
-272
-249
-233
-176
-184
-172
-156
-158
-97
-139
-107
-92
-89
-90
-84
-79
-86
-68
-89
-72
-70
-61
-68
-56
-51
-47
-57
-62
-50
-50
-55
-47
-50
-44
-44
-47
-48
-33
-37
-39
-47
-32
-40
-40
-39
-26
-56
-35
-28
-37
-40
-27
-24
-26
-29
-27
-24
-32
-25
-24
-22
-29
-29
-34
-42
-30
-24
-28
-24
-19
-15
-28
-24
-21
-25
-30
-28
-19
-24
-23
-29
-25
-26
-30
-26
-31
-27
-21
-23
-18
-31
-24
-20
-25
-31
-19
-25
-21
-25
-25
-25
-26
-29
-29
-30
-18
-19
-34
-17
-17
-19
-25
-28
-21
-18
-21
-24
-16
-25
-27
-31
-26
-21
-20
-25
-26
-25
-24
-15
-16
-23
-17
-21
-19
-20
-12
-25
-27
-11
-24
-14
-18
-19
-17
-17
-19
-18
-17
-16
-11
-14
-20
-14
-11
-205
-219
-223
-279
-320
-331
-400
-420
-543
-684
-721
-302
-13
-5
-2
-2
-2
-1
-3
-3
-1
-2
-1
-2
-1
-3
-2
-2
-6
-120
-606
-596
-471
-450
-363
-306
-275
-261
-245
-231
-199
-195
-164
-158
-165
-122
-140
-122
-131
-76
-93
-87
-90
-93
-80
-85
-76
-75
-62
-55
-64
-56
-73
-47
-58
-55
-50
-56
-51
-46
-44
-36
-38
-40
-47
-39
-46
-29
-30
-38
-32
-37
-37
-36
-29
-30
-44
-28
-30
-37
-26
-21
-38
-19
-35
-24
-25
-20
-23
-32
-25
-20
-18
-20
-25
-26
-20
-26
-31
-21
-24
-29
-34
-21
-22
-30
-26
-28
-21
-24
-19
-27
-18
-23
-32
-22
-21
-31
-17
-23
-24
-23
-18
-18
-17
-30
-28
-21
-19
-19
-30
-21
-17
-30
-21
-23
-17
-16
-26
-16
-30
-17
-23
-21
-21
-18
-33
-13
-19
-17
-23
-14
-28
-22
-24
-26
-21
-16
-15
-20
-30
-11
-19
-17
-22
-12
-17
-25
-21
-16
-19
-18
-17
-16
-21
-14
-19
-22
-15
-16
-13
-22
-205
-228
-236
-256
-307
-328
-368
-466
-500
-715
-562
-49
-2
-4
-3
-0
-1
-4
-3
-3
-4
-3
-4
-1
-0
-1
-0
-0
-4
-18
-309
-594
-531
-450
-435
-315
-318
-280
-236
-239
-210
-172
-159
-163
-150
-113
-128
-125
-103
-93
-90
-79
-100
-69
-70
-68
-65
-61
-53
-47
-58
-65
-57
-51
-41
-47
-51
-54
-52
-52
-45
-52
-43
-32
-40
-32
-50
-32
-34
-33
-40
-45
-32
-36
-42
-40
-32
-30
-27
-28
-30
-28
-30
-21
-25
-27
-26
-28
-21
-19
-27
-23
-23
-16
-29
-26
-25
-22
-23
-26
-22
-23
-20
-16
-34
-24
-24
-21
-23
-24
-33
-26
-34
-29
-27
-23
-29
-34
-19
-25
-28
-18
-20
-17
-20
-25
-22
-23
-25
-13
-22
-19
-22
-24
-28
-24
-31
-19
-28
-33
-17
-14
-16
-25
-25
-22
-19
-24
-24
-21
-20
-18
-20
-25
-14
-23
-25
-28
-15
-20
-24
-17
-16
-15
-23
-14
-13
-15
-24
-10
-18
-20
-14
-27
-13
-16
-15
-15
-15
-25
-10
-19
-222
-252
-235
-298
-336
-362
-435
-475
-566
-734
-407
-6
-3
-2
-5
-5
-1
-2
-3
-1
-3
-4
-0
-1
-0
-2
-1
-3
-6
-3
-146
-555
-553
-516
-411
-373
-305
-297
-230
-231
-222
-184
-199
-153
-168
-122
-119
-100
-101
-97
-91
-71
-92
-81
-63
-66
-69
-69
-65
-88
-63
-52
-68
-57
-47
-51
-45
-50
-54
-39
-30
-43
-32
-44
-48
-52
-35
-38
-41
-29
-42
-27
-31
-44
-30
-33
-23
-33
-32
-27
-35
-26
-26
-20
-25
-25
-29
-31
-32
-33
-26
-23
-27
-28
-23
-30
-16
-17
-26
-24
-26
-29
-24
-26
-17
-30
-32
-23
-23
-36
-30
-25
-40
-28
-18
-27
-30
-21
-17
-25
-20
-31
-33
-23
-28
-24
-24
-23
-17
-24
-24
-30
-21
-29
-15
-28
-19
-25
-30
-27
-21
-21
-14
-25
-15
-24
-27
-19
-16
-20
-24
-21
-15
-24
-17
-21
-19
-17
-17
-17
-17
-16
-12
-21
-15
-14
-16
-16
-17
-9
-15
-14
-18
-14
-18
-8
-20
-13
-11
-18
-24
-23
-214
-231
-263
-292
-315
-342
-381
-500
-579
-726
-191
-4
-5
-4
-2
-2
-2
-1
-2
-0
-2
-3
-1
-3
-3
-3
-2
-3
-4
-3
-81
-525
-529
-481
-418
-333
-305
-264
-267
-223
-212
-168
-197
-163
-137
-127
-138
-113
-98
-106
-96
-83
-103
-76
-66
-64
-70
-94
-51
-58
-58
-50
-47
-51
-54
-50
-57
-43
-50
-46
-42
-51
-36
-45
-44
-32
-25
-44
-34
-37
-34
-28
-39
-38
-43
-38
-29
-41
-32
-27
-26
-25
-35
-29
-27
-22
-33
-25
-26
-25
-18
-26
-24
-24
-27
-24
-27
-29
-20
-26
-25
-22
-23
-18
-23
-25
-22
-20
-19
-29
-27
-19
-20
-21
-18
-22
-24
-21
-26
-28
-27
-26
-24
-15
-16
-15
-20
-25
-21
-35
-20
-21
-17
-23
-24
-19
-21
-24
-24
-31
-19
-27
-22
-29
-21
-19
-11
-19
-23
-18
-14
-32
-23
-17
-15
-18
-20
-11
-23
-19
-20
-16
-19
-21
-20
-12
-14
-18
-15
-20
-9
-13
-14
-27
-19
-15
-19
-13
-20
-22
-22
-15
-215
-266
-226
-262
-302
-338
-439
-523
-623
-664
-100
-3
-2
-1
-2
-2
-1
-1
-3
-2
-2
-2
-2
-4
-3
-0
-3
-3
-1
-4
-30
-420
-584
-487
-384
-346
-291
-257
-255
-211
-208
-176
-169
-165
-157
-140
-120
-111
-96
-93
-84
-69
-83
-81
-67
-82
-72
-68
-64
-59
-47
-68
-58
-63
-51
-52
-44
-36
-45
-38
-47
-50
-36
-34
-34
-35
-41
-38
-39
-32
-33
-33
-34
-45
-37
-24
-33
-40
-29
-30
-34
-28
-35
-39
-29
-26
-33
-39
-31
-27
-21
-20
-30
-32
-23
-29
-31
-22
-21
-27
-23
-28
-19
-28
-22
-21
-33
-29
-22
-22
-23
-30
-19
-28
-15
-28
-13
-15
-16
-22
-23
-19
-28
-13
-23
-21
-23
-15
-22
-15
-18
-16
-28
-26
-21
-33
-26
-24
-25
-20
-30
-31
-27
-17
-20
-23
-19
-29
-18
-26
-21
-12
-15
-21
-19
-22
-20
-13
-17
-21
-23
-20
-17
-23
-18
-19
-12
-21
-20
-31
-14
-22
-21
-26
-26
-18
-17
-20
-18
-11
-18
-19
-238
-232
-258
-288
-297
-367
-425
-524
-609
-558
-77
-3
-1
-2
-1
-4
-3
-2
-3
-4
-1
-3
-3
-3
-2
-3
-1
-4
-4
-3
-15
-367
-559
-476
-390
-372
-328
-275
-241
-228
-221
-204
-154
-161
-143
-142
-101
-113
-112
-90
-97
-83
-83
-67
-82
-76
-70
-70
-66
-73
-57
-64
-48
-52
-45
-51
-49
-45
-47
-40
-49
-46
-44
-35
-39
-41
-46
-32
-45
-25
-33
-35
-27
-54
-15
-37
-37
-26
-33
-33
-26
-22
-32
-27
-27
-24
-21
-29
-33
-23
-32
-26
-27
-25
-24
-18
-23
-36
-30
-28
-25
-24
-23
-17
-22
-34
-22
-29
-22
-20
-23
-28
-23
-29
-21
-35
-26
-24
-24
-26
-25
-28
-28
-15
-21
-25
-23
-27
-21
-15
-23
-24
-27
-18
-12
-17
-22
-25
-26
-20
-25
-28
-17
-23
-18
-17
-21
-18
-17
-16
-19
-22
-26
-31
-17
-17
-23
-23
-19
-22
-16
-17
-14
-18
-20
-16
-15
-9
-24
-19
-20
-17
-15
-18
-19
-19
-20
-19
-12
-27
-21
-23
-217
-215
-252
-301
-325
-352
-454
-513
-617
-664
-87
-4
-8
-4
-2
-3
-3
-2
-0
-1
-2
-4
-2
-2
-3
-2
-3
-6
-2
-4
-13
-384
-583
-517
-396
-389
-350
-288
-252
-236
-210
-199
-182
-180
-142
-134
-113
-99
-106
-92
-88
-104
-82
-87
-86
-67
-92
-76
-68
-70
-56
-55
-73
-48
-48
-47
-53
-50
-41
-40
-49
-34
-29
-48
-43
-36
-42
-29
-33
-38
-29
-39
-40
-38
-51
-26
-29
-37
-24
-41
-33
-38
-24
-34
-25
-28
-31
-29
-25
-28
-27
-27
-40
-25
-36
-30
-23
-24
-22
-28
-25
-24
-31
-24
-28
-30
-25
-26
-25
-26
-27
-24
-19
-23
-28
-19
-24
-35
-24
-15
-26
-26
-26
-27
-16
-29
-23
-34
-17
-23
-25
-16
-16
-28
-18
-22
-31
-19
-20
-27
-12
-24
-29
-24
-22
-28
-15
-23
-20
-17
-13
-20
-22
-20
-20
-29
-24
-27
-23
-16
-23
-21
-19
-18
-18
-23
-17
-20
-16
-25
-11
-15
-15
-25
-23
-26
-18
-16
-14
-19
-17
-20
-218
-243
-249
-282
-299
-367
-372
-484
-557
-637
-134
-2
-2
-2
-2
-0
-1
-2
-0
-2
-1
-5
-1
-2
-5
-2
-3
-3
-1
-3
-26
-423
-552
-481
-365
-363
-328
-264
-248
-236
-222
-181
-172
-168
-140
-129
-124
-84
-112
-121
-91
-73
-97
-74
-82
-83
-76
-72
-71
-70
-58
-72
-52
-52
-40
-66
-49
-51
-45
-52
-33
-43
-35
-39
-37
-36
-30
-32
-47
-39
-36
-24
-29
-36
-29
-37
-20
-40
-25
-32
-36
-41
-23
-30
-31
-27
-31
-26
-26
-29
-22
-19
-20
-29
-18
-31
-33
-18
-25
-24
-21
-32
-27
-18
-23
-32
-14
-24
-26
-18
-24
-23
-21
-25
-32
-20
-22
-25
-22
-32
-22
-26
-22
-25
-18
-18
-23
-22
-16
-28
-21
-25
-22
-24
-21
-18
-24
-22
-16
-14
-23
-22
-28
-21
-23
-22
-19
-19
-22
-30
-17
-22
-24
-24
-21
-18
-23
-25
-22
-25
-23
-27
-23
-20
-20
-19
-20
-24
-16
-19
-22
-19
-17
-13
-24
-21
-21
-24
-19
-9
-22
-11
-220
-250
-266
-271
-312
-320
-361
-464
-582
-698
-234
-5
-3
-3
-0
-3
-7
-2
-5
-2
-2
-3
-3
-2
-3
-0
-4
-1
-2
-2
-59
-505
-528
-464
-340
-316
-317
-280
-252
-214
-209
-175
-154
-160
-158
-133
-142
-108
-99
-101
-96
-95
-72
-69
-80
-71
-70
-74
-66
-54
-66
-67
-59
-45
-54
-54
-50
-50
-60
-41
-44
-44
-46
-46
-36
-42
-43
-41
-39
-41
-33
-39
-48
-34
-36
-29
-26
-25
-26
-34
-38
-28
-31
-31
-22
-25
-20
-24
-27
-25
-25
-25
-21
-28
-27
-29
-26
-20
-21
-29
-33
-29
-21
-23
-20
-20
-21
-30
-22
-26
-25
-25
-22
-30
-27
-26
-31
-21
-28
-28
-19
-35
-24
-26
-14
-26
-19
-26
-20
-27
-25
-28
-16
-37
-20
-19
-22
-29
-19
-18
-18
-27
-16
-19
-20
-19
-13
-29
-22
-19
-21
-27
-19
-18
-19
-21
-27
-17
-11
-20
-19
-25
-12
-23
-24
-23
-19
-20
-26
-22
-15
-18
-17
-28
-17
-18
-12
-18
-19
-16
-24
-14
-210
-214
-238
-278
-307
-336
-350
-463
-518
-661
-367
-33
-2
-1
-4
-2
-3
-1
-1
-5
-1
-0
-2
-0
-2
-5
-1
-2
-3
-4
-208
-585
-514
-404
-367
-343
-263
-281
-253
-234
-231
-189
-173
-172
-158
-142
-102
-90
-93
-95
-98
-76
-69
-81
-77
-62
-58
-69
-70
-61
-55
-76
-64
-63
-58
-63
-42
-40
-42
-39
-45
-41
-39
-43
-42
-38
-38
-42
-34
-29
-33
-36
-25
-27
-29
-28
-24
-30
-36
-32
-29
-30
-33
-27
-28
-30
-33
-32
-31
-24
-23
-28
-19
-21
-26
-22
-29
-23
-21
-26
-22
-25
-26
-29
-23
-28
-16
-30
-24
-25
-22
-23
-28
-15
-27
-19
-22
-26
-22
-17
-33
-16
-25
-25
-33
-17
-26
-25
-17
-21
-26
-29
-25
-23
-23
-20
-25
-18
-25
-21
-19
-26
-22
-22
-22
-15
-22
-21
-18
-25
-10
-22
-14
-22
-23
-18
-14
-21
-23
-27
-17
-24
-19
-25
-18
-21
-23
-19
-17
-17
-16
-16
-22
-18
-18
-17
-20
-14
-22
-14
-28
-18
-200
-233
-233
-272
-323
-364
-363
-433
-538
-605
-554
-123
-9
-0
-2
-0
-4
-4
-1
-2
-3
-2
-3
-4
-5
-2
-2
-2
-2
-27
-421
-564
-477
-423
-351
-329
-300
-222
-235
-206
-205
-189
-173
-144
-142
-143
-118
-101
-90
-91
-95
-96
-71
-73
-86
-76
-75
-65
-84
-59
-61
-48
-61
-58
-49
-46
-63
-61
-41
-44
-38
-49
-44
-31
-35
-40
-41
-28
-43
-28
-35
-32
-44
-45
-26
-34
-26
-33
-41
-23
-35
-27
-39
-33
-35
-26
-31
-19
-34
-36
-19
-27
-36
-19
-29
-25
-23
-30
-30
-29
-27
-21
-24
-21
-28
-37
-32
-24
-24
-24
-29
-23
-24
-20
-22
-27
-26
-29
-25
-24
-26
-24
-21
-11
-20
-20
-25
-37
-24
-33
-28
-19
-18
-33
-25
-28
-25
-24
-20
-28
-24
-20
-22
-25
-16
-24
-18
-20
-24
-21
-16
-25
-31
-22
-16
-20
-26
-26
-17
-21
-17
-31
-15
-13
-11
-24
-15
-24
-20
-15
-35
-20
-23
-15
-23
-20
-15
-7
-18
-22
-17
-24
-235
-240
-211
-260
-303
-291
-338
-390
-476
-585
-650
-384
-38
-2
-3
-6
-3
-0
-5
-2
-2
-1
-6
-4
-4
-3
-3
-1
-10
-183
-568
-601
-426
-406
-333
-302
-262
-241
-203
-214
-223
-202
-176
-146
-158
-128
-102
-100
-107
-60
-93
-87
-69
-76
-79
-78
-66
-76
-68
-66
-56
-62
-57
-52
-48
-58
-51
-37
-38
-43
-46
-46
-35
-42
-49
-35
-30
-45
-35
-37
-26
-41
-38
-41
-35
-34
-25
-34
-31
-35
-43
-30
-29
-29
-28
-23
-25
-19
-28
-26
-28
-24
-19
-28
-29
-27
-30
-25
-29
-35
-24
-19
-17
-30
-26
-24
-20
-39
-22
-20
-36
-31
-23
-18
-29
-35
-33
-23
-27
-26
-20
-27
-21
-24
-26
-28
-26
-27
-28
-38
-31
-24
-26
-29
-19
-22
-27
-30
-28
-25
-32
-22
-21
-18
-25
-21
-18
-24
-15
-12
-27
-24
-14
-24
-20
-12
-19
-18
-20
-15
-23
-16
-27
-17
-19
-17
-17
-18
-27
-23
-11
-23
-14
-18
-20
-20
-21
-13
-14
-18
-14
-18
-204
-222
-234
-260
-271
-327
-369
-372
-445
-533
-629
-611
-255
-19
-1
-8
-2
-2
-3
-4
-3
-1
-2
-4
-4
-1
-1
-1
-113
-509
-596
-447
-409
-382
-337
-285
-243
-264
-221
-213
-173
-173
-181
-157
-152
-114
-121
-102
-92
-92
-110
-80
-94
-84
-79
-68
-57
-79
-89
-65
-68
-62
-61
-45
-50
-55
-43
-40
-43
-39
-41
-34
-42
-56
-53
-46
-44
-28
-24
-33
-35
-28
-26
-38
-21
-34
-30
-27
-23
-28
-34
-42
-36
-29
-34
-25
-24
-34
-29
-36
-16
-25
-28
-22
-22
-25
-28
-28
-26
-25
-23
-24
-25
-23
-21
-30
-28
-23
-32
-23
-35
-20
-25
-25
-24
-30
-25
-27
-19
-24
-40
-24
-22
-23
-26
-24
-25
-21
-30
-23
-21
-23
-18
-29
-30
-22
-28
-24
-22
-23
-19
-16
-29
-17
-22
-24
-18
-14
-28
-28
-29
-24
-24
-27
-21
-13
-17
-18
-24
-18
-25
-21
-17
-19
-11
-23
-17
-20
-16
-17
-15
-14
-13
-20
-12
-18
-19
-18
-14
-20
-13
-20
-159
-210
-211
-213
-249
-279
-310
-357
-382
-478
-521
-641
-605
-207
-22
-2
-2
-2
-5
-3
-2
-2
-2
-4
-4
-1
-5
-104
-475
-650
-528
-453
-377
-365
-279
-268
-249
-251
-204
-194
-169
-165
-137
-140
-127
-112
-139
-120
-93
-89
-89
-88
-89
-83
-72
-60
-77
-85
-71
-54
-71
-59
-61
-46
-45
-55
-48
-34
-47
-34
-40
-32
-30
-47
-41
-45
-40
-45
-39
-35
-32
-34
-40
-46
-35
-31
-34
-33
-21
-26
-25
-31
-29
-29
-31
-23
-31
-24
-26
-32
-28
-30
-29
-24
-38
-30
-25
-25
-19
-20
-21
-23
-34
-20
-32
-23
-19
-31
-21
-31
-21
-21
-14
-24
-22
-25
-23
-26
-22
-19
-24
-21
-19
-19
-26
-32
-21
-29
-17
-20
-14
-26
-29
-32
-24
-18
-25
-18
-24
-17
-24
-18
-15
-14
-27
-16
-23
-20
-20
-17
-20
-16
-28
-19
-19
-25
-23
-30
-11
-20
-22
-25
-27
-25
-16
-24
-27
-17
-33
-21
-19
-12
-15
-18
-20
-24
-23
-11
-17
-21
-16
-21
-163
-202
-218
-219
-232
-282
-324
-322
-342
-390
-474
-525
-622
-631
-287
-55
-5
-5
-3
-2
-3
-2
-8
-2
-4
-22
-154
-507
-608
-548
-421
-372
-343
-333
-281
-266
-253
-247
-217
-210
-159
-164
-137
-129
-121
-105
-105
-115
-97
-92
-80
-85
-96
-68
-70
-67
-67
-68
-55
-83
-71
-65
-63
-63
-52
-59
-47
-46
-59
-33
-45
-56
-32
-50
-45
-36
-36
-40
-30
-30
-37
-41
-33
-27
-31
-28
-32
-35
-30
-30
-25
-43
-30
-30
-27
-25
-30
-23
-27
-24
-27
-31
-17
-30
-29
-24
-31
-25
-25
-26
-36
-19
-36
-25
-24
-26
-24
-28
-24
-27
-30
-28
-25
-25
-27
-25
-21
-29
-21
-21
-16
-24
-26
-21
-31
-22
-29
-23
-23
-25
-35
-23
-23
-33
-27
-20
-24
-29
-35
-23
-28
-28
-17
-22
-11
-28
-17
-27
-23
-20
-23
-24
-22
-19
-19
-20
-27
-17
-24
-14
-15
-22
-19
-15
-21
-19
-19
-24
-16
-16
-21
-14
-27
-19
-22
-20
-15
-22
-20
-14
-18
-16
-206
-171
-236
-184
-259
-269
-296
-297
-320
-360
-388
-438
-522
-584
-653
-480
-231
-87
-28
-11
-4
-11
-16
-57
-164
-350
-587
-595
-489
-416
-423
-353
-333
-280
-261
-288
-227
-237
-215
-183
-154
-153
-140
-117
-111
-121
-111
-106
-87
-94
-86
-97
-99
-87
-64
-65
-61
-58
-71
-34
-58
-61
-67
-49
-62
-53
-44
-47
-40
-43
-38
-34
-36
-45
-38
-44
-42
-43
-39
-24
-30
-32
-35
-35
-28
-33
-28
-18
-39
-15
-36
-21
-34
-19
-34
-34
-30
-31
-25
-23
-24
-30
-28
-35
-28
-25
-27
-18
-18
-26
-33
-21
-26
-25
-25
-27
-22
-28
-31
-21
-31
-26
-21
-27
-21
-18
-16
-18
-28
-26
-19
-24
-18
-29
-15
-23
-23
-29
-26
-26
-25
-19
-20
-26
-23
-26
-25
-23
-22
-20
-27
-17
-27
-25
-26
-24
-17
-20
-24
-20
-21
-18
-17
-26
-17
-13
-12
-20
-14
-21
-23
-16
-18
-24
-19
-15
-16
-17
-22
-13
-20
-16
-17
-11
-16
-13
-22
-15
-21
-27
-20
-12
-193
-193
-175
-209
-255
-256
-259
-291
-289
-340
-391
-385
-473
-490
-553
-638
-585
-553
-437
-340
-301
-334
-390
-536
-608
-600
-581
-481
-450
-407
-387
-311
-271
-325
-262
-254
-199
-202
-184
-194
-195
-159
-135
-142
-117
-95
-89
-93
-90
-97
-69
-86
-65
-82
-75
-79
-68
-55
-51
-58
-65
-55
-71
-54
-42
-53
-43
-46
-45
-38
-33
-46
-30
-38
-45
-36
-33
-51
-46
-39
-25
-37
-25
-34
-20
-36
-35
-31
-34
-31
-31
-28
-28
-29
-29
-28
-24
-33
-17
-26
-31
-34
-28
-23
-24
-26
-22
-24
-27
-28
-29
-25
-38
-27
-36
-26
-18
-17
-23
-35
-20
-16
-31
-24
-31
-22
-21
-19
-20
-17
-31
-24
-26
-23
-21
-25
-28
-23
-18
-26
-19
-23
-26
-23
-26
-20
-21
-20
-29
-20
-22
-27
-24
-20
-21
-27
-24
-18
-19
-22
-25
-13
-21
-19
-24
-26
-17
-12
-13
-20
-27
-22
-25
-24
-25
-20
-22
-21
-22
-17
-20
-20
-14
-19
-16
-15
-12
-10
-16
-19
-20
-19
-167
-139
-168
-174
-203
-224
-222
-323
-282
-287
-332
-351
-403
-429
-450
-502
-524
-579
-609
-662
-611
-604
-607
-597
-502
-514
-473
-423
-375
-387
-345
-273
-296
-252
-224
-230
-260
-176
-184
-164
-172
-143
-134
-118
-119
-102
-91
-98
-95
-92
-76
-73
-73
-69
-58
-73
-68
-60
-75
-66
-50
-66
-53
-65
-57
-50
-41
-51
-34
-50
-39
-31
-28
-35
-31
-33
-32
-26
-35
-22
-34
-45
-36
-35
-26
-29
-31
-29
-33
-23
-30
-24
-35
-29
-27
-41
-21
-28
-27
-28
-30
-27
-20
-29
-29
-27
-25
-23
-26
-27
-17
-24
-28
-21
-28
-28
-37
-25
-19
-19
-28
-28
-26
-30
-25
-17
-26
-22
-30
-28
-17
-32
-20
-19
-22
-18
-25
-20
-31
-22
-26
-19
-19
-28
-17
-19
-23
-22
-31
-22
-20
-19
-22
-17
-25
-18
-23
-23
-25
-24
-22
-22
-17
-20
-19
-19
-21
-13
-18
-24
-18
-22
-21
-19
-20
-22
-13
-14
-18
-16
-21
-19
-15
-22
-22
-12
-14
-12
-16
-17
-17
-27
-158
-176
-159
-191
-170
-221
-236
-249
-287
-261
-296
-320
-320
-374
-382
-401
-438
-462
-512
-498
-469
-465
-475
-476
-449
-404
-386
-345
-362
-305
-285
-282
-275
-232
-238
-215
-170
-185
-162
-167
-150
-150
-146
-112
-109
-108
-93
-92
-83
-87
-68
-60
-73
-72
-64
-71
-63
-53
-78
-58
-64
-55
-59
-53
-50
-46
-60
-45
-52
-39
-40
-34
-24
-47
-34
-42
-41
-45
-26
-36
-46
-40
-40
-36
-33
-41
-29
-40
-29
-29
-34
-30
-38
-22
-21
-21
-28
-29
-28
-27
-26
-23
-25
-28
-24
-25
-33
-27
-32
-22
-32
-16
-28
-36
-26
-21
-25
-27
-21
-26
-18
-21
-22
-26
-24
-24
-30
-15
-33
-15
-24
-17
-25
-26
-30
-21
-23
-25
-18
-21
-16
-30
-19
-38
-22
-17
-25
-38
-30
-20
-18
-18
-24
-26
-32
-24
-28
-15
-23
-23
-17
-16
-23
-21
-28
-23
-18
-23
-20
-15
-21
-17
-17
-21
-31
-20
-16
-13
-22
-21
-19
-21
-15
-27
-14
-17
-19
-16
-28
-19
-13
-26
-163
-173
-154
-173
-204
-195
-198
-212
-232
-256
-252
-263
-325
-309
-348
-347
-364
-411
-392
-387
-434
-423
-385
-392
-372
-332
-359
-329
-301
-261
-294
-272
-220
-217
-224
-199
-218
-174
-171
-152
-159
-127
-120
-123
-121
-102
-104
-108
-85
-122
-77
-80
-71
-57
-69
-61
-76
-67
-51
-58
-62
-54
-47
-46
-51
-49
-48
-41
-41
-26
-42
-44
-41
-29
-39
-40
-32
-41
-26
-36
-41
-28
-23
-35
-34
-36
-26
-28
-30
-24
-29
-33
-33
-29
-31
-28
-32
-31
-28
-27
-22
-29
-17
-27
-27
-29
-29
-18
-27
-30
-27
-25
-31
-19
-22
-18
-19
-36
-21
-22
-28
-22
-27
-33
-25
-24
-21
-28
-29
-30
-19
-19
-21
-20
-13
-18
-24
-21
-17
-28
-30
-20
-28
-21
-19
-29
-32
-24
-24
-24
-23
-16
-28
-25
-25
-37
-17
-23
-20
-26
-19
-17
-24
-21
-19
-25
-14
-25
-29
-19
-17
-13
-18
-13
-23
-11
-20
-22
-21
-19
-20
-29
-19
-21
-18
-18
-23
-26
-15
-19
-22
-22
-145
-172
-134
-193
-161
-207
-206
-208
-218
-248
-263
-272
-301
-309
-334
-314
-334
-349
-322
-346
-391
-356
-350
-325
-349
-332
-333
-285
-275
-279
-267
-252
-203
-201
-214
-153
-181
-163
-137
-141
-128
-124
-109
-102
-114
-92
-91
-77
-73
-73
-99
-77
-62
-62
-73
-63
-57
-69
-60
-56
-59
-52
-47
-54
-52
-48
-48
-39
-46
-46
-31
-45
-37
-46
-35
-39
-29
-22
-35
-48
-39
-32
-28
-28
-25
-31
-29
-29
-26
-34
-21
-34
-30
-28
-25
-30
-23
-28
-22
-26
-26
-32
-33
-31
-24
-38
-27
-31
-31
-20
-32
-18
-29
-17
-21
-26
-28
-27
-23
-32
-25
-24
-17
-29
-25
-16
-27
-20
-23
-24
-31
-26
-27
-24
-22
-15
-25
-24
-27
-25
-22
-20
-20
-33
-21
-24
-28
-14
-28
-18
-24
-22
-18
-25
-15
-32
-17
-27
-26
-18
-28
-18
-15
-23
-22
-20
-17
-19
-19
-17
-20
-23
-22
-24
-24
-18
-23
-23
-23
-19
-25
-16
-15
-15
-18
-24
-17
-11
-23
-16
-20
-25
-152
-158
-135
-144
-160
-190
-176
-187
-197
-215
-241
-255
-255
-285
-314
-277
-318
-334
-330
-322
-318
-355
-310
-297
-294
-315
-287
-260
-295
-229
-227
-220
-210
-225
-187
-182
-152
-156
-148
-121
-137
-132
-110
-105
-86
-99
-103
-112
-86
-88
-77
-84
-90
-70
-55
-60
-56
-73
-56
-59
-52
-63
-47
-62
-55
-63
-63
-55
-48
-39
-39
-29
-39
-50
-34
-39
-30
-25
-33
-34
-37
-40
-25
-26
-25
-27
-34
-37
-35
-36
-23
-31
-33
-30
-27
-29
-28
-29
-22
-36
-24
-25
-32
-27
-22
-26
-22
-26
-15
-25
-14
-23
-28
-30
-30
-30
-19
-15
-24
-31
-25
-31
-33
-31
-30
-25
-25
-21
-35
-25
-21
-23
-33
-28
-23
-27
-22
-26
-27
-34
-25
-21
-21
-21
-21
-23
-27
-31
-21
-21
-18
-25
-18
-19
-24
-23
-17
-21
-19
-20
-17
-26
-21
-24
-20
-27
-14
-17
-15
-26
-12
-19
-28
-14
-13
-16
-21
-21
-25
-27
-26
-16
-20
-13
-17
-24
-22
-15
-14
-17
-23
-21
-123
-133
-129
-155
-160
-168
-202
-184
-183
-223
-229
-236
-213
-225
-252
-278
-242
-264
-283
-279
-276
-291
-262
-267
-251
-244
-258
-232
-237
-226
-207
-230
-178
-177
-170
-173
-142
-141
-121
-124
-101
-105
-94
-98
-84
-77
-98
-85
-87
-87
-65
-47
-74
-69
-54
-68
-66
-67
-78
-44
-59
-59
-46
-41
-48
-45
-44
-48
-41
-46
-36
-46
-26
-37
-33
-36
-35
-42
-32
-35
-32
-41
-42
-27
-27
-30
-21
-38
-27
-37
-21
-20
-25
-29
-35
-43
-36
-18
-20
-21
-25
-34
-25
-35
-28
-24
-21
-28
-25
-24
-18
-18
-27
-33
-23
-24
-25
-27
-33
-23
-23
-34
-14
-32
-22
-29
-22
-27
-23
-32
-14
-22
-18
-31
-26
-34
-23
-23
-25
-26
-23
-20
-18
-26
-26
-22
-28
-19
-22
-17
-24
-22
-18
-28
-13
-30
-16
-26
-12
-25
-25
-22
-17
-25
-16
-24
-17
-19
-18
-23
-21
-21
-28
-20
-24
-14
-25
-17
-16
-20
-17
-13
-16
-20
-21
-20
-21
-10
-16
-21
-16
-26
-134
-111
-123
-148
-125
-127
-150
-160
-159
-184
-209
-218
-221
-239
-253
-246
-235
-226
-249
-249
-265
-247
-256
-254
-229
-211
-222
-222
-224
-203
-199
-176
-182
-154
-174
-144
-120
-156
-142
-115
-112
-89
-96
-101
-91
-87
-89
-93
-73
-94
-76
-69
-85
-57
-69
-68
-67
-52
-71
-65
-62
-51
-46
-47
-40
-46
-26
-26
-35
-40
-43
-30
-24
-26
-44
-44
-33
-41
-39
-30
-35
-30
-26
-32
-25
-34
-33
-27
-26
-34
-25
-24
-19
-11
-28
-31
-23
-27
-20
-29
-29
-28
-29
-19
-21
-26
-23
-16
-31
-25
-20
-20
-15
-23
-26
-26
-16
-21
-22
-25
-23
-23
-20
-22
-22
-30
-20
-28
-19
-17
-22
-21
-19
-26
-25
-22
-17
-23
-30
-18
-25
-15
-23
-25
-27
-17
-25
-21
-27
-18
-27
-23
-23
-22
-22
-22
-26
-19
-22
-17
-23
-22
-25
-16
-22
-23
-21
-17
-21
-18
-21
-27
-21
-20
-26
-15
-13
-21
-24
-23
-14
-19
-14
-18
-15
-16
-17
-7
-28
-18
-18
-12
-125
-129
-123
-147
-134
-137
-135
-167
-172
-170
-182
-194
-201
-191
-230
-230
-207
-252
-256
-250
-248
-274
-229
-218
-248
-214
-211
-206
-193
-174
-188
-180
-154
-162
-155
-131
-149
-145
-121
-111
-100
-113
-100
-94
-86
-79
-86
-73
-72
-67
-62
-74
-76
-58
-73
-50
-61
-68
-55
-61
-61
-43
-35
-54
-56
-58
-44
-43
-38
-36
-35
-45
-45
-33
-39
-33
-37
-46
-36
-32
-26
-30
-33
-25
-25
-33
-25
-31
-30
-31
-30
-24
-23
-37
-33
-27
-26
-23
-28
-27
-24
-24
-30
-21
-21
-28
-30
-30
-22
-30
-32
-16
-36
-29
-38
-29
-29
-29
-26
-20
-24
-22
-27
-28
-25
-22
-20
-21
-22
-21
-21
-21
-21
-30
-32
-20
-8
-21
-15
-33
-19
-18
-34
-26
-22
-22
-20
-21
-22
-28
-22
-20
-18
-32
-19
-29
-18
-29
-19
-20
-22
-29
-22
-24
-30
-18
-20
-21
-18
-15
-20
-23
-23
-31
-28
-21
-17
-18
-23
-23
-13
-22
-22
-25
-15
-15
-17
-22
-25
-10
-14
-27
-93
-106
-99
-120
-129
-145
-123
-148
-145
-166
-195
-182
-193
-178
-192
-210
-215
-195
-218
-238
-249
-246
-220
-221
-215
-195
-217
-198
-185
-149
-204
-152
-143
-190
-112
-145
-131
-126
-96
-114
-122
-97
-95
-114
-84
-95
-91
-78
-95
-87
-67
-74
-64
-77
-53
-69
-61
-71
-57
-73
-54
-56
-50
-52
-53
-45
-42
-38
-39
-41
-38
-38
-40
-48
-37
-41
-31
-43
-34
-33
-29
-37
-26
-27
-32
-38
-30
-25
-35
-35
-28
-33
-28
-24
-32
-24
-30
-32
-30
-25
-35
-23
-25
-23
-19
-21
-29
-42
-27
-27
-24
-20
-41
-21
-29
-26
-30
-26
-28
-35
-26
-22
-14
-23
-24
-18
-34
-23
-28
-21
-21
-22
-15
-26
-21
-19
-28
-31
-25
-19
-27
-26
-21
-29
-25
-29
-20
-29
-27
-30
-28
-26
-21
-18
-26
-15
-30
-12
-24
-19
-24
-28
-17
-17
-28
-21
-28
-21
-18
-15
-19
-25
-17
-23
-12
-15
-18
-12
-20
-18
-21
-21
-21
-13
-24
-13
-17
-16
-22
-13
-23
-13
-117
-106
-94
-125
-107
-125
-126
-126
-133
-155
-149
-152
-173
-163
-167
-187
-161
-198
-189
-205
-225
-201
-194
-189
-183
-155
-180
-175
-171
-135
-152
-135
-134
-153
-124
-104
-112
-106
-106
-84
-99
-91
-80
-92
-86
-90
-89
-72
-78
-62
-57
-71
-67
-59
-63
-65
-53
-40
-47
-56
-42
-62
-38
-40
-47
-42
-45
-43
-42
-40
-40
-41
-33
-40
-36
-40
-34
-38
-30
-31
-44
-28
-36
-35
-35
-28
-25
-31
-34
-30
-27
-31
-38
-22
-23
-25
-36
-28
-28
-38
-20
-30
-15
-23
-36
-26
-28
-30
-27
-19
-23
-26
-22
-25
-25
-33
-17
-30
-22
-17
-19
-32
-28
-30
-21
-13
-17
-22
-20
-17
-21
-24
-34
-24
-20
-20
-19
-22
-24
-21
-16
-14
-30
-17
-24
-20
-29
-22
-28
-31
-23
-27
-17
-23
-22
-24
-17
-28
-15
-22
-19
-18
-24
-21
-15
-18
-22
-20
-18
-19
-14
-16
-22
-15
-22
-16
-20
-33
-18
-16
-27
-17
-20
-16
-17
-14
-18
-14
-18
-14
-15
-20
-103
-90
-86
-104
-108
-139
-109
-121
-125
-147
-148
-145
-157
-157
-172
-166
-180
-175
-187
-176
-181
-170
-185
-158
-157
-169
-166
-140
-159
-152
-149
-131
-127
-132
-128
-121
-101
-102
-115
-100
-92
-91
-85
-94
-80
-84
-75
-77
-84
-87
-74
-77
-62
-82
-69
-58
-55
-53
-54
-64
-56
-56
-55
-56
-45
-45
-46
-43
-35
-28
-39
-40
-38
-45
-34
-33
-30
-22
-32
-28
-29
-31
-33
-39
-32
-39
-36
-31
-21
-35
-32
-34
-24
-31
-21
-23
-19
-16
-24
-18
-23
-25
-35
-26
-26
-27
-21
-22
-25
-29
-37
-24
-34
-19
-21
-21
-20
-23
-20
-24
-28
-21
-19
-30
-30
-29
-26
-21
-27
-20
-18
-29
-26
-22
-34
-25
-29
-17
-29
-26
-31
-25
-23
-26
-28
-23
-28
-21
-24
-25
-23
-24
-27
-24
-25
-21
-19
-18
-22
-23
-19
-27
-28
-25
-18
-18
-23
-27
-17
-24
-22
-26
-21
-21
-16
-21
-20
-21
-23
-19
-17
-14
-16
-20
-19
-21
-15
-15
-17
-15
-24
-16
-89
-92
-86
-92
-109
-106
-105
-131
-129
-132
-124
-155
-134
-141
-144
-169
-148
-152
-161
-141
-165
-140
-167
-168
-170
-155
-173
-144
-141
-127
-150
-118
-117
-105
-103
-105
-105
-98
-107
-84
-87
-81
-81
-84
-84
-60
-57
-65
-72
-65
-70
-56
-77
-83
-56
-56
-67
-47
-48
-51
-46
-44
-48
-48
-43
-46
-38
-36
-47
-40
-36
-41
-53
-42
-29
-41
-35
-39
-33
-39
-44
-39
-36
-37
-39
-39
-23
-28
-26
-34
-25
-34
-18
-27
-36
-26
-33
-25
-29
-28
-26
-24
-20
-27
-25
-20
-36
-19
-23
-24
-26
-36
-22
-16
-24
-23
-26
-19
-15
-25
-23
-26
-25
-17
-22
-25
-14
-19
-16
-20
-15
-31
-22
-15
-26
-29
-20
-28
-21
-25
-20
-26
-21
-25
-22
-17
-31
-17
-21
-28
-38
-15
-21
-12
-21
-27
-27
-22
-17
-23
-24
-21
-18
-26
-18
-24
-18
-24
-21
-16
-22
-21
-25
-12
-10
-20
-24
-13
-22
-8
-11
-14
-18
-26
-15
-23
-23
-18
-17
-21
-16
-30
-104
-104
-83
-96
-94
-96
-113
-108
-97
-109
-114
-136
-148
-152
-150
-139
-134
-146
-106
-135
-143
-144
-141
-145
-129
-133
-146
-132
-134
-138
-125
-105
-111
-110
-106
-103
-96
-103
-85
-92
-102
-109
-88
-93
-83
-77
-68
-76
-79
-64
-55
-61
-72
-53
-65
-55
-56
-59
-43
-57
-58
-48
-48
-36
-44
-40
-40
-47
-38
-32
-36
-29
-32
-37
-30
-32
-34
-43
-47
-29
-39
-30
-36
-31
-28
-34
-35
-37
-24
-29
-31
-35
-29
-23
-21
-28
-21
-23
-25
-31
-26
-30
-27
-26
-25
-20
-21
-32
-21
-25
-27
-20
-40
-23
-32
-25
-22
-23
-20
-24
-17
-18
-27
-22
-28
-28
-25
-29
-25
-29
-26
-22
-29
-17
-18
-14
-19
-21
-29
-28
-18
-20
-32
-21
-18
-20
-17
-27
-30
-22
-25
-19
-19
-22
-21
-34
-15
-25
-23
-21
-24
-21
-16
-18
-20
-17
-13
-22
-11
-19
-19
-23
-19
-15
-21
-18
-21
-20
-18
-21
-16
-24
-23
-14
-20
-11
-23
-18
-25
-17
-15
-25
-84
-93
-93
-104
-115
-108
-97
-109
-101
-124
-115
-103
-135
-106
-119
-139
-126
-134
-144
-129
-126
-117
-135
-141
-142
-144
-137
-117
-114
-109
-117
-109
-102
-91
-109
-93
-111
-100
-81
-92
-92
-79
-86
-103
-82
-70
-85
-69
-63
-62
-65
-63
-66
-54
-59
-45
-55
-44
-63
-47
-42
-48
-40
-43
-32
-48
-42
-32
-42
-33
-33
-34
-32
-29
-39
-34
-43
-31
-29
-26
-29
-28
-25
-42
-34
-32
-31
-31
-19
-30
-37
-23
-27
-22
-28
-28
-24
-18
-34
-30
-20
-19
-19
-30
-28
-30
-27
-25
-25
-22
-27
-24
-34
-22
-30
-19
-18
-29
-17
-25
-19
-25
-27
-29
-27
-19
-23
-23
-24
-21
-19
-15
-21
-26
-24
-25
-27
-18
-20
-22
-38
-18
-15
-18
-27
-20
-19
-19
-25
-23
-18
-17
-26
-27
-21
-21
-19
-24
-14
-27
-26
-27
-29
-22
-21
-27
-13
-24
-18
-26
-19
-22
-31
-18
-20
-16
-27
-19
-17
-17
-17
-22
-13
-19
-14
-18
-15
-14
-20
-17
-19
-21
-81
-85
-78
-91
-89
-82
-102
-91
-89
-86
-95
-122
-93
-107
-107
-116
-112
-108
-111
-130
-135
-131
-133
-127
-111
-120
-130
-129
-133
-111
-97
-95
-93
-98
-93
-111
-84
-78
-70
-90
-81
-76
-75
-98
-71
-65
-86
-70
-73
-62
-71
-63
-65
-68
-55
-44
-68
-45
-45
-47
-47
-42
-27
-42
-44
-35
-36
-49
-46
-38
-38
-34
-31
-37
-37
-32
-27
-42
-31
-36
-33
-35
-31
-27
-31
-21
-23
-38
-27
-32
-32
-22
-24
-27
-25
-29
-27
-19
-29
-22
-31
-34
-24
-26
-32
-32
-26
-22
-24
-20
-23
-22
-31
-17
-26
-33
-23
-29
-25
-16
-27
-25
-27
-35
-23
-22
-29
-28
-25
-24
-29
-24
-20
-27
-33
-26
-18
-35
-21
-26
-31
-17
-19
-18
-18
-22
-23
-23
-25
-24
-19
-22
-17
-23
-25
-23
-18
-34
-26
-21
-23
-16
-19
-25
-15
-23
-21
-27
-14
-23
-23
-14
-25
-9
-14
-18
-19
-21
-16
-17
-14
-16
-21
-13
-15
-12
-30
-19
-19
-17
-16
-18
-89
-82
-86
-72
-85
-102
-90
-84
-105
-89
-108
-106
-122
-99
-113
-112
-113
-111
-115
-103
-119
-124
-96
-101
-116
-111
-102
-115
-119
-96
-102
-85
-94
-106
-84
-92
-96
-92
-78
-81
-85
-79
-65
-87
-79
-74
-79
-69
-79
-63
-73
-57
-58
-53
-46
-62
-62
-56
-45
-49
-40
-45
-37
-34
-38
-49
-33
-44
-34
-44
-47
-31
-26
-35
-28
-28
-32
-32
-38
-29
-33
-35
-25
-33
-29
-29
-27
-37
-26
-31
-24
-35
-19
-30
-29
-25
-20
-33
-24
-33
-26
-30
-36
-23
-34
-31
-18
-27
-21
-30
-28
-27
-29
-32
-36
-22
-20
-15
-17
-31
-25
-21
-24
-17
-27
-30
-20
-36
-26
-20
-23
-27
-22
-22
-20
-24
-29
-21
-19
-24
-19
-25
-28
-22
-21
-22
-32
-27
-22
-26
-18
-28
-17
-33
-15
-16
-24
-14
-26
-24
-24
-25
-30
-23
-22
-22
-20
-21
-13
-17
-23
-19
-25
-9
-26
-18
-17
-23
-20
-17
-13
-22
-21
-20
-19
-17
-17
-17
-17
-21
-12
-21
-75
-82
-81
-81
-99
-81
-85
-97
-81
-96
-102
-103
-111
-111
-116
-103
-129
-115
-120
-102
-110
-123
-112
-143
-119
-106
-101
-109
-102
-108
-100
-98
-115
-92
-102
-96
-80
-70
-71
-76
-82
-69
-77
-68
-61
-70
-57
-74
-74
-59
-47
-69
-59
-64
-53
-59
-46
-49
-46
-49
-41
-45
-42
-38
-41
-40
-36
-37
-36
-49
-37
-29
-37
-38
-27
-44
-37
-27
-44
-39
-31
-36
-35
-50
-27
-32
-32
-22
-31
-32
-24
-30
-37
-21
-25
-24
-37
-25
-26
-18
-26
-30
-21
-30
-23
-31
-33
-30
-29
-26
-12
-20
-21
-23
-24
-26
-25
-34
-21
-25
-33
-27
-17
-16
-34
-29
-20
-28
-27
-23
-24
-23
-24
-18
-24
-16
-26
-34
-21
-22
-20
-26
-23
-27
-27
-35
-25
-22
-28
-32
-20
-22
-27
-19
-36
-29
-14
-27
-17
-23
-24
-31
-24
-25
-24
-21
-14
-22
-17
-24
-24
-19
-13
-28
-17
-17
-13
-24
-22
-18
-30
-18
-22
-20
-19
-18
-17
-21
-17
-17
-16
-24
-82
-76
-84
-80
-67
-96
-78
-89
-79
-105
-98
-81
-100
-81
-107
-101
-98
-94
-106
-103
-102
-93
-105
-90
-112
-118
-96
-79
-101
-94
-77
-80
-77
-83
-84
-71
-82
-74
-79
-71
-73
-75
-75
-71
-73
-67
-73
-55
-62
-60
-50
-44
-46
-53
-50
-45
-55
-51
-47
-47
-43
-38
-39
-39
-41
-40
-44
-45
-30
-35
-28
-32
-37
-29
-25
-31
-39
-33
-35
-27
-23
-34
-36
-31
-28
-32
-38
-39
-31
-21
-24
-30
-33
-33
-22
-31
-29
-34
-38
-28
-23
-20
-24
-26
-21
-23
-18
-25
-29
-32
-16
-18
-22
-37
-29
-20
-19
-17
-29
-18
-24
-28
-22
-28
-16
-15
-29
-21
-26
-24
-34
-19
-26
-25
-17
-14
-21
-22
-22
-25
-19
-19
-18
-25
-14
-23
-23
-26
-24
-30
-14
-28
-25
-17
-34
-20
-25
-20
-20
-29
-25
-10
-22
-23
-20
-23
-20
-25
-21
-25
-27
-18
-15
-19
-19
-19
-21
-25
-11
-15
-19
-9
-28
-21
-34
-16
-14
-17
-19
-22
-15
-16
-76
-56
-69
-73
-69
-61
-74
-80
-83
-91
-81
-83
-96
-92
-84
-75
-90
-69
-99
-88
-92
-85
-90
-99
-99
-82
-84
-78
-87
-107
-77
-81
-72
-75
-67
-82
-73
-73
-76
-74
-70
-55
-50
-70
-53
-64
-61
-67
-56
-45
-56
-59
-54
-59
-55
-51
-51
-41
-40
-36
-43
-47
-39
-32
-52
-44
-44
-47
-40
-34
-45
-35
-40
-30
-28
-31
-44
-30
-32
-25
-31
-36
-32
-44
-33
-32
-21
-33
-28
-32
-28
-22
-25
-33
-32
-23
-22
-20
-23
-25
-21
-23
-14
-13
-27
-26
-28
-28
-22
-22
-31
-21
-18
-23
-14
-25
-24
-25
-26
-29
-25
-24
-21
-15
-21
-21
-27
-25
-22
-26
-24
-16
-18
-27
-40
-27
-22
-26
-25
-20
-25
-20
-17
-12
-21
-21
-27
-18
-18
-27
-28
-26
-16
-22
-24
-12
-11
-23
-22
-23
-23
-18
-26
-26
-27
-15
-14
-20
-26
-19
-27
-26
-18
-19
-17
-13
-16
-17
-19
-20
-29
-23
-21
-15
-14
-19
-20
-23
-15
-17
-11
-20
-71
-73
-59
-74
-75
-91
-69
-66
-82
-84
-75
-81
-103
-69
-89
-97
-84
-80
-82
-96
-81
-90
-94
-80
-83
-82
-83
-72
-88
-67
-78
-76
-83
-85
-72
-74
-63
-71
-71
-75
-68
-62
-62
-69
-76
-58
-74
-71
-60
-51
-52
-72
-47
-50
-52
-47
-50
-52
-28
-29
-40
-36
-42
-39
-47
-47
-33
-40
-31
-39
-38
-40
-32
-33
-30
-37
-26
-40
-38
-27
-36
-29
-32
-37
-38
-31
-26
-29
-29
-24
-33
-25
-29
-28
-23
-18
-17
-19
-29
-16
-24
-17
-17
-28
-23
-15
-18
-23
-21
-23
-27
-24
-26
-27
-24
-31
-25
-31
-15
-18
-26
-16
-27
-21
-24
-17
-29
-22
-23
-28
-26
-17
-20
-15
-19
-17
-21
-19
-15
-16
-28
-15
-26
-22
-29
-21
-29
-15
-22
-25
-27
-24
-22
-11
-15
-28
-25
-20
-27
-22
-15
-20
-15
-18
-15
-19
-16
-28
-19
-22
-20
-15
-18
-11
-24
-16
-24
-17
-16
-18
-15
-21
-22
-23
-12
-22
-13
-18
-17
-17
-19
-22
-70
-65
-91
-67
-55
-71
-73
-54
-76
-84
-65
-80
-69
-85
-86
-76
-79
-90
-87
-75
-67
-93
-78
-74
-78
-67
-71
-87
-84
-81
-72
-79
-66
-79
-82
-77
-70
-72
-61
-62
-55
-76
-52
-64
-46
-50
-53
-58
-56
-47
-55
-46
-50
-52
-41
-41
-32
-45
-37
-48
-33
-44
-39
-30
-30
-30
-40
-39
-32
-32
-33
-31
-39
-30
-34
-29
-29
-29
-33
-21
-37
-25
-26
-33
-22
-30
-24
-39
-23
-22
-21
-22
-26
-32
-21
-22
-23
-28
-28
-31
-24
-25
-31
-29
-22
-24
-31
-23
-26
-23
-22
-27
-27
-29
-25
-17
-28
-15
-31
-27
-23
-21
-22
-26
-30
-24
-24
-27
-34
-25
-21
-23
-25
-17
-17
-28
-22
-18
-28
-18
-18
-19
-18
-21
-19
-26
-26
-23
-23
-27
-25
-18
-21
-20
-18
-17
-24
-19
-22
-24
-17
-25
-11
-20
-13
-19
-20
-19
-19
-17
-15
-19
-19
-11
-18
-19
-14
-22
-19
-14
-11
-12
-13
-21
-17
-7
-18
-18
-18
-24
-9
-15
-92
-89
-67
-62
-62
-63
-73
-71
-81
-81
-73
-82
-89
-68
-82
-92
-78
-81
-70
-70
-76
-88
-85
-95
-92
-92
-62
-78
-75
-90
-73
-66
-63
-85
-71
-81
-71
-61
-71
-60
-84
-54
-68
-59
-75
-51
-56
-63
-60
-47
-45
-46
-50
-53
-44
-35
-45
-43
-44
-35
-43
-33
-53
-35
-38
-53
-41
-33
-41
-36
-23
-36
-32
-23
-36
-37
-38
-35
-34
-35
-31
-26
-31
-27
-29
-28
-23
-27
-31
-24
-29
-27
-24
-25
-34
-18
-23
-28
-29
-25
-26
-35
-26
-25
-24
-25
-27
-29
-25
-21
-29
-21
-27
-28
-20
-33
-18
-25
-19
-22
-20
-18
-22
-29
-32
-18
-12
-23
-19
-25
-22
-20
-29
-24
-36
-15
-14
-26
-24
-16
-20
-26
-22
-34
-28
-22
-21
-24
-30
-33
-22
-21
-22
-25
-19
-29
-24
-23
-26
-14
-19
-15
-24
-25
-30
-17
-20
-17
-16
-19
-18
-12
-19
-20
-21
-22
-13
-22
-23
-23
-25
-25
-24
-11
-16
-19
-18
-22
-22
-25
-20
-17
-70
-80
-72
-77
-61
-79
-68
-55
-70
-79
-76
-84
-76
-66
-81
-61
-73
-96
-81
-63
-86
-83
-62
-97
-68
-88
-72
-76
-72
-78
-83
-80
-79
-66
-69
-51
-66
-73
-61
-69
-60
-64
-65
-57
-59
-56
-45
-64
-48
-60
-62
-59
-41
-52
-49
-57
-37
-33
-40
-55
-35
-33
-48
-43
-28
-34
-37
-38
-38
-42
-37
-34
-30
-30
-47
-49
-36
-27
-24
-24
-30
-27
-26
-25
-30
-24
-27
-33
-38
-26
-28
-29
-25
-31
-27
-23
-26
-33
-30
-29
-40
-35
-21
-32
-21
-22
-31
-29
-18
-28
-18
-23
-30
-27
-16
-22
-16
-18
-22
-25
-17
-31
-25
-28
-28
-24
-26
-13
-27
-23
-24
-18
-21
-20
-33
-21
-33
-30
-27
-20
-30
-21
-29
-19
-19
-25
-21
-29
-26
-32
-26
-22
-24
-19
-24
-19
-20
-23
-22
-18
-20
-18
-21
-19
-24
-16
-15
-10
-17
-18
-28
-17
-21
-24
-18
-21
-19
-14
-24
-19
-19
-14
-20
-21
-11
-20
-14
-17
-21
-23
-19
-18
-55
-43
-52
-60
-56
-70
-58
-58
-57
-70
-65
-69
-64
-74
-72
-65
-66
-77
-65
-66
-74
-58
-51
-70
-56
-73
-63
-70
-61
-66
-77
-68
-79
-59
-62
-63
-59
-54
-69
-52
-65
-56
-48
-47
-43
-52
-51
-50
-52
-47
-47
-49
-50
-44
-42
-41
-41
-37
-39
-33
-36
-32
-33
-34
-30
-29
-33
-26
-26
-29
-40
-32
-29
-36
-31
-29
-34
-43
-29
-32
-31
-21
-23
-23
-26
-24
-23
-35
-23
-22
-28
-24
-17
-25
-25
-22
-23
-19
-28
-23
-19
-12
-25
-28
-24
-18
-18
-23
-18
-28
-22
-13
-33
-17
-20
-28
-29
-27
-22
-19
-31
-25
-14
-26
-18
-32
-16
-29
-22
-21
-29
-21
-27
-21
-14
-21
-26
-23
-14
-24
-26
-25
-27
-17
-22
-18
-14
-25
-23
-25
-25
-13
-22
-15
-18
-29
-19
-20
-16
-14
-20
-14
-19
-24
-20
-23
-26
-16
-14
-17
-19
-16
-19
-19
-21
-10
-16
-23
-19
-18
-21
-23
-26
-18
-16
-18
-13
-19
-15
-14
-16
-17
-58
-51
-62
-47
-53
-50
-53
-77
-60
-67
-53
-66
-66
-80
-64
-65
-58
-56
-69
-65
-72
-74
-72
-66
-65
-67
-66
-64
-68
-62
-74
-65
-62
-70
-56
-71
-59
-76
-52
-54
-57
-55
-53
-62
-39
-39
-60
-53
-38
-62
-33
-42
-46
-44
-39
-35
-33
-44
-43
-41
-36
-33
-32
-36
-30
-32
-26
-36
-31
-31
-23
-30
-27
-31
-37
-26
-36
-28
-34
-34
-26
-25
-32
-32
-26
-23
-23
-29
-18
-27
-26
-33
-25
-28
-26
-30
-33
-27
-19
-35
-21
-26
-18
-17
-26
-15
-15
-21
-16
-14
-22
-17
-24
-18
-22
-25
-25
-24
-30
-21
-24
-22
-16
-24
-16
-23
-30
-27
-17
-21
-22
-15
-22
-20
-20
-22
-24
-23
-14
-26
-25
-14
-14
-20
-19
-21
-16
-27
-24
-16
-24
-17
-24
-22
-17
-14
-18
-26
-11
-18
-18
-13
-17
-16
-20
-17
-23
-22
-19
-17
-16
-13
-17
-21
-20
-21
-17
-15
-17
-12
-23
-19
-21
-14
-20
-15
-19
-14
-12
-16
-12
-20
-48
-56
-62
-58
-64
-49
-64
-63
-64
-81
-79
-87
-68
-63
-69
-63
-65
-68
-94
-80
-68
-74
-68
-88
-82
-78
-66
-64
-56
-82
-53
-66
-60
-64
-62
-65
-50
-64
-62
-70
-57
-61
-61
-57
-59
-69
-62
-48
-57
-50
-43
-55
-41
-34
-40
-43
-39
-46
-54
-36
-43
-41
-40
-38
-42
-41
-34
-35
-42
-29
-34
-44
-35
-34
-33
-30
-36
-30
-22
-23
-38
-27
-32
-27
-36
-17
-29
-29
-29
-29
-21
-35
-25
-21
-29
-24
-25
-19
-26
-33
-34
-29
-23
-26
-19
-29
-34
-27
-27
-27
-18
-26
-27
-27
-34
-27
-27
-24
-18
-22
-28
-19
-28
-41
-22
-19
-21
-26
-23
-32
-25
-26
-30
-23
-32
-34
-31
-24
-32
-23
-27
-25
-33
-24
-32
-21
-25
-28
-30
-17
-30
-29
-26
-23
-23
-23
-32
-36
-33
-31
-23
-22
-28
-17
-22
-30
-18
-26
-19
-23
-14
-19
-29
-32
-23
-16
-29
-22
-20
-15
-13
-15
-18
-19
-26
-20
-20
-25
-28
-15
-13
-12
-65
-60
-55
-54
-67
-59
-74
-59
-68
-73
-62
-70
-81
-64
-73
-74
-60
-85
-74
-70
-66
-74
-68
-73
-70
-76
-76
-95
-67
-84
-65
-65
-57
-51
-70
-66
-58
-50
-61
-55
-63
-59
-52
-58
-54
-45
-64
-46
-63
-55
-51
-58
-43
-34
-35
-42
-49
-53
-35
-29
-59
-38
-36
-34
-43
-42
-39
-38
-32
-30
-40
-28
-37
-33
-27
-30
-24
-36
-41
-35
-33
-39
-37
-21
-34
-26
-27
-35
-26
-27
-15
-26
-32
-28
-41
-40
-21
-25
-26
-28
-30
-17
-22
-26
-35
-25
-23
-22
-27
-30
-18
-27
-19
-30
-23
-20
-34
-27
-25
-27
-21
-24
-26
-19
-20
-27
-24
-22
-26
-24
-24
-34
-25
-23
-28
-22
-19
-27
-27
-13
-24
-26
-18
-24
-16
-17
-24
-22
-33
-26
-24
-29
-24
-20
-23
-23
-23
-25
-23
-18
-20
-17
-24
-22
-15
-26
-23
-21
-19
-15
-15
-22
-18
-20
-22
-18
-29
-21
-31
-23
-15
-19
-14
-16
-21
-20
-23
-18
-16
-16
-12
-18
-56
-64
-50
-58
-39
-58
-66
-59
-56
-65
-68
-68
-76
-53
-64
-54
-81
-53
-86
-58
-66
-59
-74
-75
-57
-65
-76
-64
-64
-74
-58
-58
-52
-60
-51
-60
-60
-64
-61
-54
-72
-75
-64
-44
-55
-47
-49
-46
-59
-44
-41
-44
-31
-36
-46
-39
-37
-36
-34
-38
-35
-39
-38
-36
-36
-28
-40
-44
-30
-36
-36
-27
-37
-29
-26
-35
-35
-24
-39
-28
-21
-42
-42
-34
-27
-26
-39
-25
-23
-33
-32
-25
-22
-22
-22
-29
-23
-26
-34
-23
-27
-25
-22
-23
-28
-28
-20
-25
-18
-30
-28
-22
-27
-21
-25
-10
-17
-23
-26
-33
-23
-31
-24
-20
-33
-26
-20
-20
-22
-20
-32
-22
-15
-25
-24
-23
-20
-19
-15
-23
-32
-19
-23
-27
-24
-32
-26
-21
-22
-21
-16
-24
-26
-26
-17
-18
-21
-24
-18
-15
-13
-26
-29
-12
-26
-31
-21
-19
-20
-17
-18
-22
-17
-11
-28
-18
-27
-11
-27
-18
-17
-11
-22
-18
-18
-17
-20
-15
-21
-18
-17
-22
-54
-57
-53
-52
-62
-49
-56
-49
-72
-52
-38
-56
-56
-73
-63
-66
-66
-66
-84
-59
-58
-69
-60
-60
-76
-74
-70
-55
-66
-58
-55
-73
-52
-54
-58
-51
-50
-50
-52
-63
-60
-64
-56
-46
-57
-49
-42
-49
-46
-43
-40
-58
-44
-34
-39
-43
-49
-32
-39
-43
-45
-26
-32
-37
-35
-24
-26
-30
-52
-39
-24
-27
-33
-37
-31
-31
-31
-30
-30
-26
-37
-33
-30
-26
-25
-34
-23
-30
-20
-28
-27
-26
-21
-27
-24
-29
-21
-21
-22
-25
-28
-26
-33
-26
-19
-29
-25
-23
-15
-27
-24
-18
-28
-24
-20
-22
-24
-22
-21
-26
-23
-18
-15
-35
-18
-23
-15
-21
-21
-29
-21
-20
-26
-18
-16
-18
-27
-30
-17
-24
-22
-19
-20
-24
-21
-21
-21
-11
-21
-25
-21
-22
-22
-20
-21
-26
-24
-16
-23
-15
-17
-20
-22
-23
-19
-22
-20
-22
-29
-14
-13
-15
-15
-23
-19
-17
-13
-19
-24
-21
-16
-12
-7
-14
-26
-15
-12
-19
-17
-24
-12
-15
-52
-44
-50
-57
-52
-51
-59
-48
-44
-63
-53
-56
-50
-52
-76
-61
-54
-59
-60
-60
-45
-43
-67
-64
-58
-68
-55
-61
-53
-71
-50
-58
-59
-70
-52
-43
-53
-49
-50
-76
-50
-51
-49
-58
-44
-45
-45
-43
-45
-48
-45
-36
-41
-43
-42
-35
-42
-36
-42
-33
-28
-36
-38
-34
-42
-32
-32
-36
-18
-27
-17
-29
-25
-29
-23
-26
-39
-18
-26
-29
-28
-25
-33
-33
-26
-22
-30
-24
-24
-20
-17
-35
-23
-31
-25
-29
-16
-32
-26
-19
-30
-23
-21
-19
-24
-16
-34
-23
-20
-29
-31
-23
-17
-26
-26
-13
-24
-23
-25
-19
-27
-21
-23
-30
-17
-23
-19
-18
-29
-20
-27
-21
-20
-26
-21
-25
-16
-22
-18
-22
-28
-20
-25
-22
-20
-17
-17
-16
-15
-24
-22
-15
-22
-24
-21
-22
-21
-15
-24
-20
-14
-18
-16
-15
-21
-15
-22
-35
-27
-16
-15
-19
-16
-9
-19
-22
-12
-16
-10
-15
-20
-17
-18
-19
-20
-19
-17
-18
-13
-18
-13
-22
-56
-52
-46
-49
-50
-48
-39
-52
-55
-59
-47
-55
-52
-50
-61
-43
-61
-62
-65
-55
-53
-49
-52
-59
-59
-59
-62
-64
-62
-50
-51
-51
-51
-58
-56
-53
-55
-55
-52
-54
-43
-39
-61
-43
-41
-53
-53
-37
-42
-43
-57
-58
-62
-41
-50
-37
-43
-38
-41
-43
-52
-25
-50
-39
-37
-44
-38
-33
-25
-43
-29
-33
-29
-38
-26
-30
-33
-39
-29
-23
-25
-26
-33
-26
-34
-39
-33
-20
-38
-25
-28
-23
-23
-21
-31
-25
-32
-29
-33
-29
-26
-17
-25
-22
-25
-23
-27
-34
-29
-22
-25
-25
-28
-27
-20
-25
-25
-28
-30
-20
-35
-30
-36
-28
-22
-26
-21
-26
-25
-25
-28
-25
-22
-16
-28
-22
-28
-26
-21
-28
-27
-23
-27
-26
-23
-18
-25
-24
-25
-22
-20
-21
-24
-27
-24
-24
-19
-27
-34
-32
-24
-27
-13
-22
-25
-16
-21
-17
-24
-20
-19
-20
-12
-22
-21
-28
-14
-18
-26
-39
-24
-19
-16
-18
-13
-17
-17
-22
-19
-21
-19
-21
-53
-48
-56
-49
-60
-46
-56
-51
-43
-44
-55
-56
-63
-57
-45
-53
-49
-59
-54
-68
-48
-65
-63
-39
-58
-64
-50
-62
-68
-73
-56
-47
-44
-40
-49
-49
-53
-43
-43
-48
-42
-52
-50
-35
-45
-46
-44
-39
-36
-36
-39
-33
-44
-31
-37
-41
-36
-30
-54
-42
-33
-41
-34
-31
-32
-38
-33
-36
-33
-36
-40
-29
-17
-36
-43
-27
-35
-32
-30
-26
-29
-27
-28
-29
-26
-24
-32
-30
-28
-30
-40
-34
-29
-41
-30
-20
-31
-29
-25
-33
-23
-20
-26
-26
-24
-33
-22
-19
-15
-23
-25
-27
-17
-32
-21
-27
-20
-29
-34
-29
-28
-27
-22
-24
-23
-37
-23
-17
-14
-24
-23
-36
-22
-31
-18
-21
-30
-24
-28
-24
-22
-26
-22
-19
-19
-16
-27
-22
-21
-18
-23
-26
-19
-19
-26
-25
-30
-16
-24
-19
-23
-21
-21
-15
-26
-23
-27
-27
-24
-27
-23
-19
-26
-17
-24
-26
-16
-23
-20
-7
-19
-18
-15
-16
-23
-25
-19
-15
-18
-13
-21
-17
-40
-51
-33
-36
-42
-42
-56
-47
-48
-36
-49
-49
-48
-48
-53
-54
-39
-50
-41
-55
-54
-38
-43
-57
-58
-50
-52
-50
-43
-38
-42
-50
-41
-37
-41
-54
-45
-59
-56
-39
-42
-40
-48
-39
-49
-42
-51
-49
-47
-34
-33
-45
-22
-28
-35
-31
-31
-22
-40
-30
-34
-35
-34
-23
-31
-36
-27
-33
-37
-34
-25
-26
-32
-29
-32
-25
-25
-26
-27
-25
-21
-24
-17
-34
-33
-22
-22
-25
-30
-22
-27
-21
-35
-15
-17
-31
-23
-25
-23
-22
-22
-30
-17
-24
-18
-24
-32
-28
-26
-23
-36
-23
-20
-16
-25
-22
-17
-15
-22
-17
-23
-17
-16
-15
-26
-21
-28
-26
-18
-25
-16
-12
-20
-22
-25
-29
-11
-15
-10
-18
-27
-21
-23
-23
-21
-27
-17
-21
-14
-26
-19
-27
-17
-26
-14
-20
-26
-14
-30
-14
-15
-13
-20
-21
-11
-22
-16
-16
-14
-17
-22
-25
-21
-20
-15
-14
-13
-12
-16
-19
-27
-20
-11
-13
-10
-18
-8
-15
-11
-22
-17
-27
-55
-48
-58
-42
-42
-44
-53
-58
-56
-50
-50
-55
-56
-61
-57
-53
-52
-37
-53
-59
-66
-54
-41
-52
-65
-52
-48
-68
-58
-50
-43
-53
-47
-44
-41
-56
-42
-58
-53
-33
-53
-49
-52
-43
-50
-36
-40
-51
-42
-39
-46
-34
-30
-33
-37
-53
-38
-35
-45
-43
-42
-34
-36
-40
-46
-32
-25
-40
-37
-35
-38
-33
-29
-36
-34
-34
-40
-26
-36
-38
-45
-30
-32
-27
-25
-20
-24
-33
-36
-26
-23
-35
-31
-17
-38
-27
-25
-23
-29
-30
-35
-24
-30
-20
-23
-25
-27
-35
-25
-20
-20
-32
-32
-31
-13
-30
-18
-23
-33
-21
-27
-17
-23
-28
-29
-33
-24
-23
-17
-15
-22
-26
-22
-15
-33
-24
-25
-25
-32
-20
-28
-17
-31
-21
-20
-16
-21
-22
-21
-23
-23
-22
-21
-27
-29
-24
-25
-19
-16
-23
-16
-24
-19
-18
-15
-29
-23
-14
-15
-29
-19
-25
-20
-24
-18
-22
-25
-27
-21
-14
-13
-16
-22
-15
-16
-20
-19
-17
-11
-13
-23
-23
-45
-47
-39
-38
-46
-50
-48
-41
-50
-36
-30
-52
-46
-37
-43
-48
-41
-51
-49
-52
-57
-40
-59
-53
-46
-55
-45
-39
-41
-62
-38
-44
-40
-51
-50
-49
-42
-47
-35
-36
-39
-49
-35
-39
-33
-33
-47
-49
-35
-39
-40
-36
-39
-27
-34
-34
-44
-35
-39
-38
-28
-24
-30
-36
-40
-38
-24
-37
-43
-36
-25
-36
-18
-24
-21
-26
-18
-25
-30
-30
-38
-25
-23
-25
-24
-30
-25
-23
-25
-32
-29
-33
-23
-14
-27
-22
-24
-23
-21
-25
-30
-23
-22
-22
-27
-19
-30
-34
-16
-25
-25
-23
-22
-29
-25
-20
-29
-26
-31
-30
-30
-19
-20
-28
-21
-19
-25
-29
-22
-25
-21
-22
-31
-18
-23
-22
-26
-23
-25
-27
-19
-21
-23
-21
-16
-24
-20
-19
-16
-23
-18
-17
-21
-28
-17
-17
-24
-22
-24
-19
-31
-10
-15
-16
-25
-18
-22
-19
-16
-25
-21
-18
-25
-18
-19
-19
-14
-15
-26
-30
-15
-18
-13
-12
-20
-17
-22
-11
-13
-23
-16
-22
-39
-53
-35
-45
-40
-52
-57
-44
-41
-49
-47
-54
-48
-53
-54
-43
-57
-47
-46
-52
-50
-51
-44
-56
-57
-55
-40
-47
-46
-45
-41
-37
-56
-46
-42
-43
-51
-47
-45
-53
-40
-44
-39
-52
-41
-55
-48
-47
-37
-35
-39
-34
-37
-42
-34
-33
-31
-32
-38
-22
-51
-35
-37
-38
-32
-30
-44
-21
-28
-26
-37
-33
-31
-35
-30
-32
-33
-32
-28
-29
-32
-36
-34
-22
-28
-25
-37
-27
-21
-28
-20
-33
-27
-23
-27
-31
-34
-25
-27
-27
-25
-32
-25
-19
-21
-29
-25
-24
-26
-25
-24
-23
-30
-35
-23
-23
-31
-29
-23
-28
-25
-26
-22
-25
-20
-26
-26
-11
-23
-22
-27
-23
-24
-23
-29
-23
-34
-28
-28
-21
-22
-33
-27
-20
-31
-20
-24
-31
-15
-25
-27
-29
-29
-27
-22
-21
-17
-22
-16
-14
-32
-21
-19
-29
-19
-19
-19
-23
-28
-19
-27
-15
-18
-9
-22
-24
-24
-17
-16
-19
-15
-18
-14
-22
-16
-21
-21
-17
-25
-20
-18
-18
-52
-49
-43
-38
-32
-47
-41
-45
-53
-36
-46
-40
-43
-60
-40
-45
-46
-42
-53
-49
-42
-38
-38
-53
-48
-45
-52
-54
-50
-55
-54
-46
-31
-35
-46
-37
-51
-46
-40
-39
-60
-44
-44
-53
-49
-32
-42
-39
-38
-40
-36
-36
-30
-39
-36
-23
-40
-36
-36
-33
-34
-27
-41
-33
-31
-30
-32
-32
-35
-38
-33
-36
-26
-32
-25
-24
-35
-38
-31
-26
-37
-31
-30
-36
-18
-16
-19
-23
-28
-20
-25
-26
-25
-31
-31
-26
-25
-24
-33
-25
-26
-21
-28
-17
-17
-36
-39
-25
-23
-33
-19
-23
-25
-22
-26
-25
-24
-21
-26
-24
-31
-25
-22
-26
-20
-22
-33
-34
-33
-27
-28
-21
-27
-32
-23
-26
-26
-25
-22
-25
-28
-21
-30
-24
-24
-22
-27
-30
-25
-22
-16
-22
-24
-24
-37
-15
-21
-25
-22
-32
-22
-22
-26
-24
-25
-20
-14
-20
-19
-19
-24
-18
-26
-20
-24
-21
-20
-18
-15
-17
-31
-24
-18
-15
-18
-11
-14
-23
-19
-20
-18
-23
-42
-42
-45
-36
-49
-57
-49
-39
-41
-33
-41
-42
-51
-35
-39
-52
-38
-58
-42
-46
-49
-40
-48
-33
-45
-38
-37
-46
-42
-36
-34
-40
-49
-40
-47
-56
-38
-34
-42
-37
-42
-44
-30
-37
-44
-39
-45
-30
-42
-49
-34
-27
-36
-30
-37
-36
-38
-31
-28
-33
-23
-22
-25
-31
-41
-27
-34
-20
-20
-20
-22
-36
-26
-19
-30
-28
-31
-27
-31
-30
-16
-19
-30
-27
-33
-26
-22
-25
-21
-22
-25
-23
-26
-24
-33
-18
-27
-33
-16
-23
-19
-29
-23
-31
-24
-21
-21
-21
-33
-22
-23
-23
-22
-22
-28
-28
-16
-28
-19
-22
-27
-18
-25
-22
-24
-18
-22
-15
-25
-20
-22
-30
-25
-17
-18
-25
-18
-20
-22
-17
-18
-18
-27
-21
-13
-18
-11
-18
-24
-28
-19
-26
-21
-24
-17
-24
-14
-15
-15
-15
-17
-20
-17
-18
-10
-24
-16
-24
-26
-13
-13
-14
-14
-17
-27
-18
-14
-23
-18
-15
-12
-12
-21
-23
-12
-17
-19
-12
-14
-19
-18
-16
-42
-47
-31
-52
-41
-35
-44
-38
-45
-47
-53
-46
-48
-47
-51
-35
-58
-46
-47
-41
-50
-37
-41
-31
-32
-47
-45
-43
-54
-42
-32
-33
-35
-57
-47
-31
-39
-35
-28
-52
-48
-40
-41
-36
-30
-49
-40
-39
-31
-35
-34
-30
-44
-36
-33
-26
-26
-40
-34
-29
-35
-40
-34
-22
-35
-27
-28
-28
-30
-37
-28
-29
-43
-22
-23
-19
-30
-23
-33
-26
-23
-19
-21
-32
-23
-26
-29
-25
-28
-23
-23
-30
-17
-28
-31
-20
-27
-27
-28
-25
-21
-30
-19
-26
-25
-24
-35
-33
-22
-27
-26
-23
-29
-21
-27
-28
-33
-20
-19
-19
-27
-20
-36
-22
-25
-16
-22
-22
-22
-21
-21
-20
-23
-21
-19
-22
-27
-20
-24
-23
-21
-12
-26
-19
-20
-27
-18
-20
-36
-22
-22
-20
-22
-25
-30
-28
-27
-20
-19
-29
-17
-26
-19
-19
-20
-22
-16
-22
-20
-22
-23
-21
-12
-22
-23
-15
-18
-17
-18
-20
-19
-22
-14
-16
-13
-16
-20
-16
-12
-20
-17
-17
-42
-44
-37
-42
-41
-46
-43
-35
-48
-33
-35
-31
-37
-46
-41
-45
-39
-43
-36
-41
-31
-41
-49
-42
-45
-52
-30
-42
-41
-42
-38
-39
-41
-32
-44
-48
-34
-27
-48
-49
-41
-43
-38
-31
-44
-44
-30
-40
-41
-31
-37
-37
-28
-32
-40
-23
-27
-35
-30
-33
-34
-35
-43
-28
-31
-40
-29
-35
-29
-27
-27
-28
-25
-27
-28
-29
-21
-20
-26
-18
-22
-33
-28
-27
-25
-28
-14
-23
-19
-25
-20
-28
-35
-19
-25
-17
-25
-22
-22
-25
-26
-22
-24
-29
-24
-20
-19
-23
-35
-29
-18
-22
-22
-17
-30
-21
-19
-14
-23
-24
-29
-22
-31
-20
-32
-22
-23
-21
-24
-22
-18
-20
-23
-16
-21
-20
-24
-17
-22
-22
-20
-18
-30
-17
-22
-22
-16
-14
-23
-22
-24
-20
-17
-26
-28
-17
-22
-13
-20
-24
-18
-18
-23
-21
-14
-15
-28
-14
-18
-16
-21
-23
-24
-12
-16
-17
-17
-19
-17
-17
-21
-23
-13
-17
-18
-19
-17
-19
-16
-16
-23
-21
-35
-39
-36
-37
-34
-34
-37
-44
-45
-48
-51
-40
-35
-39
-40
-47
-44
-41
-45
-45
-50
-42
-45
-38
-38
-28
-50
-54
-42
-52
-34
-44
-44
-48
-51
-51
-49
-56
-42
-26
-43
-41
-45
-47
-29
-33
-36
-33
-30
-41
-37
-34
-28
-33
-33
-47
-18
-40
-28
-39
-44
-25
-38
-31
-28
-34
-26
-21
-35
-29
-23
-35
-35
-32
-29
-24
-24
-33
-31
-26
-30
-28
-25
-25
-23
-33
-24
-29
-33
-14
-34
-27
-25
-22
-28
-32
-29
-30
-38
-24
-24
-25
-25
-27
-20
-28
-25
-32
-27
-21
-29
-20
-25
-23
-30
-13
-25
-24
-19
-37
-28
-26
-23
-24
-29
-25
-18
-33
-20
-21
-27
-13
-31
-27
-27
-24
-22
-26
-21
-23
-20
-18
-28
-24
-32
-22
-18
-18
-21
-30
-15
-23
-20
-18
-19
-21
-21
-24
-16
-20
-21
-17
-18
-16
-17
-19
-22
-16
-26
-16
-20
-24
-21
-20
-27
-18
-18
-21
-16
-18
-18
-22
-23
-20
-21
-17
-20
-13
-11
-20
-22
-19
-24
-42
-38
-36
-26
-41
-49
-30
-43
-52
-37
-45
-31
-46
-44
-44
-48
-50
-39
-44
-38
-40
-42
-39
-45
-42
-37
-37
-44
-44
-53
-29
-27
-40
-36
-43
-34
-35
-32
-50
-44
-39
-28
-52
-55
-29
-45
-32
-32
-32
-39
-29
-32
-33
-31
-36
-28
-31
-33
-42
-38
-23
-37
-32
-21
-33
-34
-30
-32
-30
-25
-21
-37
-23
-36
-23
-22
-22
-27
-32
-21
-24
-22
-36
-22
-21
-29
-31
-26
-28
-23
-20
-21
-23
-29
-25
-27
-29
-22
-17
-35
-20
-16
-33
-24
-14
-29
-26
-21
-28
-18
-25
-20
-30
-22
-26
-19
-26
-27
-22
-23
-21
-18
-26
-25
-17
-13
-21
-17
-23
-23
-20
-23
-18
-22
-26
-30
-25
-21
-26
-18
-18
-24
-27
-20
-24
-25
-24
-20
-25
-23
-34
-19
-20
-26
-22
-14
-22
-21
-10
-19
-19
-21
-26
-20
-25
-19
-25
-14
-24
-8
-22
-29
-16
-20
-20
-22
-23
-17
-16
-11
-20
-19
-17
-20
-18
-15
-24
-27
-17
-11
-16
-38
-45
-36
-33
-42
-32
-37
-45
-45
-41
-35
-43
-41
-50
-41
-38
-45
-40
-45
-31
-36
-38
-47
-38
-30
-48
-28
-46
-39
-41
-35
-45
-38
-38
-39
-37
-37
-43
-27
-37
-43
-39
-47
-39
-29
-45
-43
-30
-36
-35
-35
-39
-30
-25
-34
-36
-38
-25
-30
-24
-23
-39
-33
-24
-32
-24
-26
-39
-20
-26
-26
-20
-27
-29
-35
-31
-32
-23
-29
-27
-23
-30
-39
-29
-26
-25
-25
-25
-22
-23
-29
-25
-27
-24
-18
-29
-27
-17
-35
-32
-25
-18
-26
-33
-25
-29
-24
-28
-14
-29
-22
-23
-25
-21
-19
-18
-20
-22
-25
-13
-19
-25
-20
-44
-17
-22
-20
-19
-16
-31
-21
-31
-27
-21
-21
-26
-33
-28
-18
-21
-13
-25
-23
-26
-25
-21
-14
-18
-22
-11
-14
-26
-15
-28
-21
-18
-22
-24
-12
-22
-23
-19
-22
-17
-26
-13
-21
-16
-16
-24
-26
-13
-14
-17
-15
-21
-26
-13
-14
-22
-22
-25
-15
-11
-16
-17
-17
-17
-13
-12
-15
-15
-38
-35
-36
-36
-39
-37
-35
-35
-34
-36
-37
-40
-39
-50
-46
-40
-38
-53
-34
-42
-37
-47
-36
-38
-43
-34
-36
-45
-43
-34
-31
-39
-46
-32
-37
-29
-38
-33
-27
-44
-37
-41
-32
-35
-37
-32
-33
-37
-32
-32
-31
-32
-26
-28
-28
-34
-34
-42
-39
-23
-33
-25
-30
-28
-35
-28
-31
-34
-25
-35
-32
-30
-27
-30
-31
-23
-24
-30
-28
-24
-23
-32
-20
-26
-25
-32
-36
-25
-29
-31
-22
-18
-35
-33
-22
-26
-25
-32
-23
-19
-22
-24
-28
-28
-19
-23
-23
-21
-22
-11
-24
-21
-16
-30
-25
-27
-30
-28
-21
-30
-32
-23
-21
-23
-23
-21
-28
-26
-22
-27
-16
-26
-19
-21
-15
-23
-23
-18
-22
-26
-22
-31
-22
-31
-21
-27
-13
-21
-22
-19
-25
-25
-33
-20
-17
-26
-27
-28
-25
-21
-16
-20
-35
-19
-25
-19
-20
-26
-14
-19
-13
-15
-21
-13
-18
-24
-21
-20
-26
-13
-11
-17
-7
-18
-22
-26
-17
-18
-14
-11
-25
-17
-37
-39
-36
-27
-45
-35
-28
-36
-37
-49
-35
-27
-31
-32
-21
-26
-33
-37
-38
-34
-40
-46
-36
-34
-40
-28
-31
-31
-38
-38
-36
-38
-27
-38
-37
-31
-50
-35
-33
-28
-36
-44
-43
-42
-37
-32
-35
-32
-31
-39
-32
-29
-37
-26
-33
-29
-30
-33
-32
-27
-34
-34
-30
-34
-31
-28
-24
-38
-29
-29
-27
-21
-36
-28
-23
-24
-31
-33
-24
-28
-27
-14
-18
-26
-25
-29
-23
-27
-32
-24
-27
-24
-28
-19
-29
-36
-23
-34
-17
-20
-23
-27
-15
-21
-24
-25
-34
-25
-21
-22
-19
-19
-30
-11
-28
-27
-19
-20
-29
-22
-22
-16
-18
-20
-12
-24
-16
-19
-26
-33
-19
-18
-30
-26
-25
-17
-19
-33
-25
-21
-25
-19
-19
-27
-24
-30
-28
-20
-18
-19
-27
-23
-24
-19
-29
-20
-11
-15
-14
-25
-28
-18
-17
-19
-22
-14
-10
-19
-17
-17
-27
-24
-19
-13
-23
-23
-23
-14
-24
-22
-22
-15
-18
-15
-19
-21
-11
-26
-22
-21
-21
-19
-32
-31
-39
-40
-31
-36
-41
-30
-38
-45
-51
-34
-37
-40
-35
-31
-31
-34
-36
-42
-38
-35
-36
-35
-40
-37
-42
-34
-36
-29
-40
-30
-37
-37
-42
-36
-27
-32
-40
-43
-32
-30
-35
-43
-21
-31
-23
-24
-37
-39
-25
-22
-24
-23
-25
-26
-36
-23
-30
-38
-23
-35
-31
-24
-32
-28
-22
-25
-43
-31
-20
-34
-27
-29
-21
-32
-29
-21
-30
-18
-37
-32
-25
-29
-23
-30
-22
-28
-31
-29
-31
-26
-24
-36
-27
-28
-25
-28
-22
-27
-29
-17
-35
-25
-15
-20
-21
-26
-21
-24
-23
-25
-22
-21
-19
-29
-24
-23
-24
-27
-31
-18
-15
-20
-29
-27
-24
-23
-26
-25
-22
-13
-17
-23
-20
-26
-28
-18
-25
-26
-32
-27
-27
-29
-16
-23
-27
-15
-22
-23
-18
-21
-21
-24
-25
-23
-23
-18
-17
-24
-17
-24
-23
-20
-25
-16
-14
-24
-24
-21
-21
-14
-12
-18
-17
-26
-25
-30
-14
-15
-17
-17
-17
-27
-16
-19
-13
-11
-16
-18
-9
-17
-37
-49
-42
-43
-31
-29
-35
-41
-32
-35
-27
-29
-35
-30
-28
-34
-35
-35
-43
-45
-25
-37
-34
-36
-28
-35
-32
-36
-35
-46
-42
-35
-28
-31
-42
-31
-28
-35
-28
-21
-36
-30
-39
-30
-41
-49
-34
-28
-42
-34
-27
-42
-34
-25
-36
-20
-27
-33
-41
-23
-30
-33
-27
-33
-23
-26
-30
-37
-27
-38
-29
-22
-22
-30
-33
-26
-32
-38
-24
-20
-29
-24
-24
-28
-23
-28
-26
-25
-29
-15
-26
-29
-44
-15
-24
-21
-20
-26
-28
-29
-29
-29
-20
-24
-23
-30
-21
-18
-19
-27
-19
-18
-26
-17
-27
-25
-29
-19
-15
-21
-34
-22
-28
-26
-24
-23
-17
-23
-29
-23
-22
-25
-18
-23
-17
-26
-25
-30
-18
-25
-21
-17
-20
-29
-24
-19
-24
-20
-28
-28
-22
-22
-18
-29
-23
-18
-18
-23
-20
-19
-21
-14
-14
-14
-17
-19
-16
-27
-24
-13
-16
-17
-18
-21
-17
-17
-19
-21
-11
-15
-19
-19
-16
-13
-14
-21
-17
-14
-20
-11
-23
-21
-43
-41
-37
-35
-23
-39
-23
-31
-41
-35
-44
-40
-45
-33
-37
-51
-37
-43
-36
-34
-37
-40
-33
-29
-36
-36
-33
-43
-38
-40
-33
-32
-33
-42
-27
-33
-32
-42
-31
-30
-37
-33
-35
-32
-27
-39
-37
-43
-24
-20
-32
-29
-28
-28
-38
-22
-24
-27
-39
-26
-34
-31
-36
-35
-31
-30
-27
-27
-25
-22
-27
-37
-23
-25
-32
-20
-20
-28
-19
-18
-28
-22
-30
-29
-25
-24
-35
-28
-26
-21
-16
-29
-28
-26
-19
-23
-35
-33
-20
-24
-28
-30
-27
-22
-25
-20
-29
-21
-20
-25
-22
-27
-27
-23
-24
-26
-30
-15
-29
-28
-23
-19
-21
-23
-19
-24
-28
-23
-20
-23
-28
-28
-22
-21
-18
-19
-20
-32
-22
-22
-34
-24
-27
-24
-28
-18
-24
-19
-23
-21
-32
-10
-17
-17
-23
-19
-23
-15
-17
-20
-22
-27
-20
-18
-19
-16
-21
-23
-16
-20
-19
-23
-16
-14
-19
-26
-16
-14
-17
-18
-23
-17
-16
-21
-16
-21
-24
-22
-23
-27
-15
-12
-37
-36
-38
-31
-26
-33
-33
-38
-33
-33
-31
-34
-45
-36
-32
-29
-30
-48
-40
-37
-34
-50
-29
-29
-40
-34
-39
-27
-30
-44
-37
-30
-29
-28
-30
-34
-41
-42
-37
-35
-36
-31
-40
-38
-32
-28
-24
-27
-30
-38
-29
-27
-25
-28
-31
-41
-35
-32
-21
-28
-27
-27
-23
-33
-29
-33
-17
-28
-26
-31
-28
-29
-29
-31
-25
-29
-21
-32
-30
-22
-28
-32
-30
-25
-24
-23
-25
-29
-28
-25
-24
-15
-26
-25
-27
-31
-30
-24
-21
-25
-29
-27
-25
-27
-23
-27
-20
-35
-23
-22
-20
-14
-28
-24
-31
-22
-27
-27
-24
-23
-17
-22
-22
-20
-25
-34
-24
-31
-29
-28
-32
-31
-23
-27
-24
-28
-26
-16
-26
-30
-19
-28
-17
-21
-32
-17
-21
-27
-25
-25
-15
-23
-31
-23
-22
-24
-18
-24
-18
-23
-21
-25
-23
-17
-27
-28
-26
-25
-17
-14
-20
-15
-16
-24
-11
-19
-22
-19
-21
-26
-20
-16
-18
-21
-14
-25
-16
-21
-14
-9
-13
-14
-33
-37
-34
-23
-34
-36
-33
-33
-28
-37
-30
-26
-41
-27
-35
-24
-31
-24
-30
-30
-30
-35
-33
-35
-35
-26
-42
-33
-32
-32
-33
-35
-33
-31
-33
-35
-36
-33
-34
-31
-36
-39
-28
-35
-27
-29
-39
-29
-33
-34
-27
-31
-36
-37
-29
-34
-30
-27
-28
-32
-25
-34
-30
-17
-33
-33
-33
-25
-22
-22
-28
-28
-18
-20
-29
-30
-32
-25
-22
-27
-23
-29
-21
-25
-23
-17
-24
-19
-29
-36
-29
-27
-39
-26
-25
-25
-31
-32
-27
-20
-18
-29
-22
-21
-19
-23
-25
-18
-15
-28
-24
-28
-16
-27
-20
-23
-13
-24
-27
-18
-17
-18
-25
-24
-16
-17
-17
-17
-22
-20
-24
-29
-23
-19
-29
-26
-23
-20
-21
-32
-21
-20
-25
-27
-21
-20
-21
-20
-30
-24
-26
-29
-23
-17
-25
-22
-23
-18
-24
-17
-23
-23
-12
-14
-15
-26
-18
-23
-23
-20
-21
-18
-15
-19
-18
-19
-18
-13
-14
-17
-20
-17
-14
-22
-12
-20
-15
-15
-20
-13
-19
-13
-44
-36
-39
-41
-33
-30
-29
-34
-28
-35
-33
-30
-47
-35
-36
-30
-33
-40
-35
-33
-37
-29
-38
-40
-30
-29
-31
-35
-30
-25
-36
-30
-31
-33
-31
-30
-36
-50
-36
-25
-29
-31
-24
-21
-39
-27
-39
-22
-33
-27
-25
-24
-36
-25
-19
-31
-27
-40
-23
-34
-25
-26
-33
-31
-30
-21
-25
-20
-30
-23
-11
-32
-14
-26
-33
-28
-23
-36
-26
-21
-31
-24
-36
-35
-31
-21
-23
-30
-24
-25
-18
-29
-16
-23
-19
-20
-21
-20
-22
-25
-26
-25
-19
-18
-21
-22
-38
-25
-20
-15
-24
-19
-25
-21
-17
-27
-26
-26
-17
-28
-20
-22
-21
-20
-17
-21
-26
-25
-16
-29
-27
-25
-20
-18
-13
-14
-26
-14
-26
-19
-24
-27
-14
-22
-13
-26
-23
-26
-24
-21
-18
-21
-20
-22
-32
-15
-8
-18
-22
-22
-19
-11
-27
-31
-20
-22
-22
-29
-20
-24
-16
-15
-12
-20
-19
-17
-25
-14
-22
-14
-12
-13
-17
-20
-6
-22
-18
-15
-19
-20
-14
-19
-33
-32
-22
-33
-45
-29
-36
-34
-37
-37
-38
-31
-31
-30
-38
-26
-31
-36
-37
-30
-31
-25
-26
-29
-31
-33
-28
-33
-28
-38
-36
-35
-37
-26
-33
-36
-34
-22
-47
-29
-34
-38
-42
-37
-27
-33
-36
-30
-28
-37
-36
-20
-34
-32
-33
-27
-29
-26
-30
-30
-23
-29
-43
-31
-30
-27
-27
-25
-23
-35
-26
-24
-24
-25
-20
-26
-24
-31
-28
-28
-26
-31
-26
-21
-27
-23
-34
-32
-18
-20
-18
-18
-25
-29
-33
-30
-25
-21
-26
-20
-20
-26
-22
-20
-22
-14
-33
-16
-21
-22
-25
-24
-27
-31
-20
-23
-20
-30
-33
-20
-28
-26
-20
-27
-20
-30
-26
-17
-31
-20
-29
-25
-26
-24
-24
-29
-20
-26
-22
-23
-27
-28
-25
-26
-21
-31
-28
-26
-25
-20
-17
-18
-22
-15
-23
-20
-17
-17
-22
-22
-15
-22
-17
-12
-26
-20
-26
-27
-19
-31
-18
-18
-16
-23
-19
-16
-23
-24
-16
-20
-14
-11
-20
-14
-20
-17
-11
-17
-13
-18
-13
-17
-24
-43
-38
-37
-31
-26
-38
-42
-36
-39
-34
-30
-38
-38
-33
-32
-33
-30
-32
-26
-37
-40
-34
-35
-24
-33
-30
-28
-35
-37
-36
-26
-36
-31
-33
-29
-31
-26
-29
-30
-33
-25
-27
-34
-29
-35
-29
-27
-27
-38
-33
-27
-37
-29
-26
-28
-32
-25
-24
-21
-23
-28
-23
-35
-28
-25
-32
-25
-35
-19
-24
-29
-22
-27
-30
-38
-32
-30
-30
-20
-23
-29
-19
-24
-20
-25
-31
-29
-28
-20
-21
-20
-22
-28
-38
-19
-26
-24
-29
-21
-18
-26
-21
-24
-30
-21
-24
-23
-24
-28
-22
-22
-31
-24
-23
-25
-27
-16
-22
-32
-22
-16
-29
-26
-30
-22
-14
-23
-28
-19
-17
-17
-26
-22
-20
-19
-27
-30
-23
-24
-21
-26
-21
-17
-27
-23
-21
-32
-13
-28
-24
-21
-32
-25
-16
-28
-25
-14
-18
-24
-17
-19
-21
-21
-18
-19
-17
-16
-23
-14
-18
-16
-21
-23
-21
-16
-20
-18
-15
-11
-16
-13
-20
-11
-11
-19
-20
-23
-20
-14
-12
-15
-26
-32
-14
-29
-32
-27
-34
-35
-38
-39
-29
-27
-33
-34
-35
-38
-43
-35
-45
-44
-33
-38
-29
-31
-25
-28
-34
-40
-30
-34
-35
-29
-39
-36
-24
-37
-38
-28
-36
-35
-26
-44
-33
-27
-25
-29
-33
-33
-22
-23
-44
-38
-38
-22
-35
-26
-20
-27
-34
-25
-30
-24
-29
-26
-27
-27
-25
-21
-22
-31
-24
-33
-30
-33
-32
-27
-16
-27
-37
-22
-25
-24
-31
-23
-28
-28
-31
-26
-23
-27
-26
-25
-28
-30
-24
-25
-26
-23
-21
-27
-22
-27
-20
-24
-27
-18
-23
-22
-31
-20
-29
-26
-24
-19
-32
-18
-22
-23
-27
-22
-20
-30
-20
-18
-24
-26
-25
-12
-31
-30
-27
-21
-17
-21
-22
-23
-9
-12
-18
-31
-16
-35
-17
-28
-27
-26
-30
-26
-17
-21
-23
-10
-17
-23
-17
-19
-22
-14
-24
-19
-25
-17
-18
-21
-20
-14
-21
-21
-27
-19
-20
-17
-19
-23
-25
-20
-19
-21
-20
-21
-14
-17
-21
-10
-19
-26
-16
-23
-15
-23
-17
-14
-24
-32
-34
-21
-31
-26
-26
-28
-31
-26
-44
-34
-31
-29
-30
-28
-30
-22
-36
-37
-28
-32
-30
-37
-29
-36
-22
-32
-25
-25
-39
-33
-25
-23
-34
-31
-34
-28
-30
-32
-39
-22
-27
-31
-30
-29
-26
-26
-39
-27
-23
-30
-29
-30
-41
-34
-29
-28
-18
-36
-27
-29
-31
-29
-27
-22
-34
-18
-31
-36
-17
-29
-16
-29
-21
-31
-29
-18
-24
-22
-26
-32
-30
-17
-19
-30
-28
-25
-23
-15
-31
-19
-25
-32
-25
-19
-25
-28
-25
-20
-29
-25
-22
-29
-24
-31
-29
-29
-22
-22
-25
-23
-25
-24
-20
-28
-34
-26
-23
-19
-23
-25
-19
-36
-30
-30
-28
-23
-25
-24
-21
-20
-21
-21
-21
-23
-24
-23
-22
-18
-24
-40
-24
-22
-31
-21
-22
-17
-21
-23
-22
-14
-26
-13
-20
-28
-22
-21
-18
-31
-17
-12
-22
-19
-23
-16
-18
-21
-20
-12
-22
-22
-21
-17
-23
-17
-16
-18
-21
-24
-18
-18
-13
-21
-20
-22
-23
-10
-15
-21
-12
-14
-35
-30
-20
-26
-34
-27
-28
-42
-30
-34
-46
-34
-38
-27
-32
-40
-44
-26
-42
-39
-29
-34
-32
-24
-36
-30
-35
-30
-20
-17
-35
-20
-41
-26
-35
-27
-38
-31
-36
-43
-31
-32
-34
-28
-27
-28
-26
-33
-31
-27
-31
-37
-35
-32
-22
-25
-35
-18
-33
-23
-25
-28
-20
-22
-24
-35
-25
-30
-25
-27
-31
-27
-25
-29
-24
-26
-29
-25
-25
-25
-18
-24
-34
-34
-17
-18
-21
-26
-24
-23
-25
-29
-24
-23
-16
-25
-26
-35
-15
-21
-23
-16
-20
-26
-23
-23
-24
-26
-21
-17
-27
-20
-21
-32
-23
-22
-23
-22
-28
-33
-25
-25
-21
-28
-25
-19
-21
-33
-18
-30
-17
-14
-28
-24
-24
-22
-27
-13
-25
-23
-25
-21
-21
-25
-20
-26
-18
-24
-26
-25
-18
-18
-19
-26
-24
-15
-17
-13
-24
-27
-11
-22
-23
-17
-14
-19
-28
-17
-13
-19
-23
-16
-28
-20
-26
-19
-16
-17
-10
-23
-14
-17
-16
-15
-15
-16
-15
-17
-18
-16
-23
-10
-29
-22
-24
-28
-28
-30
-23
-21
-30
-32
-26
-35
-31
-30
-30
-30
-31
-24
-26
-38
-35
-40
-27
-28
-35
-35
-19
-30
-32
-35
-37
-31
-33
-31
-29
-33
-37
-30
-33
-28
-32
-31
-23
-31
-31
-25
-20
-31
-23
-25
-19
-22
-30
-28
-26
-26
-28
-25
-19
-29
-33
-27
-24
-28
-30
-37
-30
-29
-20
-27
-23
-25
-22
-22
-23
-30
-26
-23
-32
-30
-26
-25
-30
-21
-23
-31
-24
-30
-19
-30
-20
-25
-23
-24
-30
-23
-20
-34
-19
-21
-29
-23
-32
-30
-22
-26
-29
-23
-24
-21
-19
-28
-13
-20
-23
-23
-23
-22
-26
-25
-21
-21
-34
-35
-26
-25
-23
-26
-27
-21
-27
-19
-26
-26
-30
-24
-20
-24
-16
-25
-19
-33
-27
-23
-25
-25
-29
-25
-25
-25
-18
-16
-18
-26
-26
-21
-19
-17
-15
-21
-19
-21
-29
-20
-25
-19
-23
-20
-17
-26
-18
-23
-24
-17
-21
-18
-16
-25
-22
-13
-17
-14
-20
-23
-17
-19
-18
-12
-15
-16
-17
-18
-31
-24
-23
-29
-29
-29
-24
-26
-30
-38
-22
-33
-25
-29
-40
-37
-37
-29
-25
-38
-42
-30
-38
-41
-30
-29
-33
-32
-45
-31
-31
-30
-24
-29
-36
-38
-24
-34
-30
-20
-32
-27
-22
-31
-27
-29
-28
-30
-26
-33
-27
-25
-28
-28
-29
-30
-22
-34
-21
-29
-23
-23
-21
-29
-39
-21
-29
-26
-24
-24
-26
-29
-21
-25
-22
-29
-23
-22
-31
-27
-25
-33
-33
-26
-29
-27
-29
-34
-23
-21
-28
-31
-23
-22
-30
-24
-27
-29
-22
-35
-29
-25
-21
-21
-17
-28
-26
-18
-23
-22
-21
-24
-22
-20
-34
-22
-28
-23
-21
-20
-20
-20
-17
-22
-22
-24
-29
-15
-27
-30
-19
-23
-28
-29
-18
-20
-24
-25
-16
-26
-21
-24
-28
-28
-23
-23
-26
-19
-23
-17
-20
-10
-26
-23
-33
-15
-23
-28
-17
-24
-21
-28
-16
-21
-27
-20
-15
-19
-23
-20
-19
-26
-14
-28
-17
-13
-16
-15
-17
-22
-19
-21
-20
-19
-20
-14
-15
-21
-14
-15
-15
-19
-29
-22
-23
-33
-29
-31
-22
-24
-31
-33
-24
-28
-33
-27
-39
-22
-31
-29
-29
-32
-24
-26
-34
-28
-27
-25
-26
-18
-32
-20
-30
-24
-26
-35
-38
-41
-28
-30
-26
-27
-31
-28
-25
-27
-29
-24
-38
-21
-26
-32
-19
-27
-30
-28
-21
-23
-26
-20
-32
-35
-33
-26
-27
-27
-20
-25
-25
-19
-24
-26
-21
-20
-30
-29
-22
-24
-30
-23
-25
-25
-16
-13
-30
-15
-20
-23
-21
-25
-33
-22
-19
-24
-20
-28
-19
-24
-26
-25
-38
-24
-23
-23
-29
-13
-28
-20
-32
-35
-26
-29
-26
-33
-24
-30
-26
-32
-21
-24
-27
-25
-21
-22
-11
-17
-26
-20
-20
-20
-22
-24
-15
-24
-22
-21
-32
-24
-16
-15
-27
-15
-20
-22
-14
-26
-23
-19
-18
-15
-24
-22
-17
-22
-26
-23
-18
-14
-19
-20
-17
-16
-28
-22
-16
-25
-18
-18
-21
-17
-27
-16
-22
-12
-15
-24
-20
-10
-20
-16
-23
-22
-17
-30
-21
-21
-23
-19
-15
-20
-18
-15
-14
-19
-30
-27
-37
-25
-31
-40
-36
-25
-31
-43
-24
-34
-26
-31
-24
-27
-21
-30
-32
-30
-34
-30
-33
-29
-32
-25
-35
-33
-30
-35
-26
-41
-29
-32
-22
-31
-31
-42
-30
-25
-28
-30
-25
-16
-30
-33
-22
-37
-15
-36
-23
-19
-29
-26
-24
-25
-30
-24
-24
-35
-24
-41
-20
-29
-21
-32
-23
-22
-34
-31
-24
-25
-27
-27
-29
-40
-22
-32
-23
-24
-25
-29
-28
-24
-31
-31
-18
-21
-26
-20
-21
-28
-26
-29
-20
-21
-23
-19
-22
-21
-23
-20
-22
-23
-28
-24
-25
-31
-29
-22
-24
-16
-20
-25
-28
-24
-19
-25
-33
-26
-19
-25
-19
-16
-21
-23
-22
-24
-21
-20
-17
-21
-29
-22
-20
-21
-14
-16
-18
-26
-22
-16
-17
-24
-26
-21
-23
-26
-23
-18
-19
-22
-28
-27
-21
-22
-18
-15
-17
-16
-18
-18
-21
-28
-37
-24
-17
-19
-21
-18
-23
-23
-26
-9
-22
-23
-19
-22
-20
-14
-24
-26
-11
-18
-18
-14
-13
-12
-14
-13
-23
-15
-36
-23
-23
-26
-27
-33
-26
-30
-24
-19
-36
-26
-45
-28
-27
-25
-20
-29
-33
-32
-29
-29
-22
-33
-33
-25
-35
-30
-29
-34
-22
-25
-25
-25
-19
-25
-21
-28
-24
-28
-33
-18
-30
-21
-32
-23
-20
-31
-26
-19
-38
-24
-24
-26
-26
-19
-35
-29
-23
-26
-27
-20
-26
-33
-30
-25
-22
-20
-26
-27
-28
-30
-21
-25
-24
-20
-24
-31
-29
-24
-27
-24
-24
-11
-25
-23
-29
-33
-25
-25
-30
-23
-21
-30
-24
-16
-27
-28
-27
-17
-21
-12
-18
-21
-24
-15
-21
-21
-18
-21
-19
-29
-21
-25
-14
-22
-25
-20
-27
-19
-24
-24
-20
-26
-29
-21
-21
-30
-23
-13
-20
-22
-25
-32
-27
-21
-24
-23
-14
-20
-34
-18
-25
-26
-27
-27
-21
-24
-31
-14
-22
-14
-33
-26
-24
-15
-18
-24
-28
-17
-17
-17
-25
-15
-18
-16
-19
-18
-18
-14
-19
-15
-13
-21
-32
-18
-17
-21
-22
-18
-17
-17
-20
-16
-12
-16
-19
-21
-16
-15
-14
-12
-41
-38
-29
-24
-29
-24
-28
-27
-28
-25
-18
-29
-30
-30
-26
-28
-28
-31
-32
-38
-30
-27
-28
-33
-29
-29
-33
-33
-33
-30
-25
-30
-30
-24
-32
-21
-36
-28
-29
-38
-19
-28
-38
-34
-35
-30
-19
-27
-35
-37
-28
-32
-19
-25
-19
-24
-29
-26
-22
-30
-26
-24
-19
-25
-23
-20
-17
-23
-25
-22
-41
-16
-28
-33
-23
-26
-23
-29
-22
-24
-28
-25
-21
-22
-25
-32
-21
-19
-29
-23
-35
-26
-27
-19
-25
-23
-22
-23
-28
-22
-29
-19
-22
-25
-19
-20
-17
-26
-19
-19
-23
-20
-25
-15
-19
-18
-15
-31
-28
-29
-27
-29
-28
-16
-19
-22
-34
-28
-29
-18
-21
-21
-20
-18
-22
-25
-25
-17
-19
-17
-29
-25
-24
-17
-31
-16
-21
-18
-21
-33
-32
-24
-20
-15
-16
-19
-19
-18
-21
-20
-21
-17
-24
-18
-16
-18
-12
-16
-13
-16
-20
-17
-19
-22
-26
-15
-24
-19
-22
-14
-20
-19
-19
-23
-22
-15
-24
-12
-11
-16
-15
-16
-32
-34
-28
-39
-32
-25
-23
-16
-32
-37
-31
-27
-18
-29
-31
-33
-27
-18
-31
-34
-24
-43
-33
-19
-36
-21
-31
-30
-31
-23
-21
-20
-27
-24
-27
-20
-25
-27
-18
-37
-31
-30
-29
-18
-25
-21
-21
-28
-31
-22
-31
-28
-26
-26
-26
-20
-33
-26
-27
-33
-25
-23
-31
-21
-20
-25
-19
-20
-30
-33
-27
-27
-23
-24
-17
-19
-29
-28
-23
-26
-30
-36
-26
-22
-30
-30
-27
-24
-36
-24
-19
-11
-30
-25
-33
-16
-31
-22
-34
-29
-30
-21
-28
-31
-25
-22
-34
-16
-28
-26
-24
-17
-29
-25
-30
-23
-23
-24
-31
-29
-21
-17
-20
-26
-19
-24
-29
-23
-20
-27
-18
-25
-29
-31
-22
-28
-23
-23
-32
-20
-19
-29
-20
-22
-24
-22
-20
-14
-18
-17
-21
-17
-19
-12
-21
-19
-32
-21
-17
-17
-28
-24
-23
-20
-20
-15
-23
-22
-24
-13
-15
-28
-18
-18
-18
-23
-17
-14
-18
-26
-19
-18
-16
-18
-24
-19
-16
-16
-15
-12
-17
-17
-27
-28
-26
-26
-28
-30
-31
-39
-29
-26
-27
-27
-32
-30
-18
-34
-25
-39
-44
-30
-21
-27
-43
-27
-26
-35
-27
-22
-26
-32
-24
-32
-25
-29
-23
-28
-25
-15
-26
-43
-29
-26
-22
-32
-30
-22
-30
-23
-21
-24
-31
-24
-26
-26
-21
-29
-27
-29
-26
-24
-30
-29
-24
-25
-25
-25
-31
-22
-27
-15
-18
-29
-28
-28
-24
-29
-29
-21
-24
-21
-22
-23
-19
-22
-23
-28
-15
-23
-24
-27
-24
-20
-26
-30
-21
-20
-25
-15
-26
-29
-25
-26
-27
-28
-25
-23
-22
-22
-21
-33
-20
-24
-21
-25
-31
-28
-20
-30
-24
-22
-31
-22
-20
-21
-21
-21
-23
-24
-25
-16
-15
-16
-25
-17
-20
-24
-16
-27
-19
-15
-26
-25
-26
-17
-25
-29
-27
-25
-23
-15
-21
-21
-20
-23
-12
-20
-21
-23
-20
-24
-21
-17
-16
-17
-19
-21
-25
-23
-22
-20
-21
-14
-19
-19
-16
-12
-17
-18
-27
-12
-22
-19
-15
-16
-21
-11
-18
-22
-15
-17
-15
-20
-26
-32
-28
-25
-18
-25
-24
-21
-23
-28
-24
-26
-29
-34
-18
-17
-27
-18
-30
-29
-29
-29
-27
-30
-27
-24
-37
-31
-27
-30
-20
-17
-25
-33
-24
-35
-17
-21
-42
-33
-40
-22
-38
-25
-25
-26
-24
-17
-24
-32
-26
-28
-31
-21
-18
-24
-30
-35
-24
-23
-25
-17
-30
-17
-17
-23
-30
-18
-24
-22
-23
-26
-24
-13
-21
-28
-26
-35
-29
-24
-15
-24
-28
-24
-19
-20
-21
-29
-20
-29
-23
-15
-19
-25
-26
-23
-27
-22
-18
-18
-26
-30
-25
-25
-27
-29
-25
-28
-17
-27
-21
-26
-18
-31
-26
-15
-25
-25
-22
-17
-24
-20
-11
-18
-25
-14
-19
-22
-32
-17
-28
-24
-30
-15
-19
-24
-16
-28
-16
-23
-33
-24
-17
-19
-24
-18
-21
-19
-22
-20
-23
-21
-21
-13
-21
-20
-19
-22
-19
-24
-19
-20
-20
-18
-24
-14
-15
-22
-20
-16
-13
-19
-15
-20
-10
-21
-18
-26
-17
-17
-20
-25
-14
-18
-13
-22
-20
-17
-20
-14
-11
-13
-36
-19
-27
-29
-24
-34
-23
-27
-17
-21
-32
-34
-28
-16
-29
-24
-32
-23
-29
-20
-32
-21
-28
-23
-32
-24
-26
-24
-18
-30
-34
-20
-23
-33
-19
-29
-27
-22
-19
-32
-26
-19
-17
-25
-28
-30
-27
-31
-32
-24
-26
-31
-28
-28
-38
-18
-30
-26
-23
-23
-19
-20
-25
-30
-33
-30
-27
-27
-21
-19
-26
-25
-32
-26
-26
-28
-20
-29
-18
-23
-21
-23
-23
-14
-29
-24
-22
-25
-23
-30
-19
-27
-32
-25
-21
-22
-27
-24
-23
-28
-22
-20
-28
-22
-21
-26
-23
-31
-28
-21
-20
-27
-25
-26
-16
-19
-29
-11
-23
-23
-29
-31
-15
-25
-21
-28
-16
-27
-25
-29
-21
-27
-23
-24
-22
-23
-27
-23
-29
-18
-25
-25
-22
-25
-23
-23
-21
-17
-19
-31
-21
-17
-22
-19
-20
-23
-12
-21
-23
-19
-14
-21
-11
-21
-17
-22
-14
-24
-11
-19
-27
-21
-18
-18
-10
-21
-24
-12
-13
-18
-22
-15
-17
-22
-15
-13
-8
-17
-15
-21
-16
-10
-27
-32
-20
-24
-29
-22
-29
-27
-33
-32
-26
-24
-33
-24
-22
-36
-33
-26
-26
-24
-25
-31
-16
-24
-21
-19
-26
-20
-29
-29
-36
-26
-25
-30
-25
-24
-36
-20
-24
-20
-24
-25
-26
-25
-20
-23
-25
-27
-39
-27
-27
-19
-26
-24
-25
-24
-20
-22
-25
-17
-21
-32
-19
-26
-26
-19
-24
-21
-20
-25
-22
-23
-32
-32
-30
-29
-25
-31
-14
-26
-19
-28
-30
-11
-20
-21
-27
-27
-23
-27
-20
-33
-22
-27
-27
-27
-29
-14
-24
-26
-26
-18
-28
-22
-27
-18
-27
-23
-16
-31
-25
-22
-22
-29
-25
-24
-22
-21
-21
-20
-27
-12
-26
-29
-27
-16
-17
-21
-29
-27
-28
-27
-19
-24
-16
-26
-29
-11
-16
-23
-24
-18
-20
-29
-22
-20
-24
-17
-25
-17
-27
-25
-13
-18
-18
-18
-16
-13
-23
-24
-19
-10
-19
-24
-16
-12
-18
-19
-16
-21
-15
-18
-15
-17
-21
-22
-12
-17
-14
-18
-18
-14
-19
-21
-15
-9
-19
-25
-17
-18
-12
-15
-27
-24
-27
-24
-32
-24
-28
-17
-40
-22
-23
-31
-28
-26
-28
-30
-32
-27
-28
-27
-13
-28
-25
-38
-27
-35
-30
-30
-24
-33
-21
-20
-33
-18
-29
-21
-21
-19
-23
-28
-34
-27
-19
-22
-25
-25
-18
-19
-28
-20
-23
-28
-33
-31
-28
-28
-22
-30
-21
-18
-18
-26
-18
-20
-24
-26
-24
-28
-24
-25
-27
-15
-16
-21
-18
-29
-25
-22
-18
-13
-24
-22
-24
-27
-20
-25
-20
-23
-25
-25
-21
-30
-23
-16
-32
-24
-24
-21
-24
-34
-15
-22
-29
-15
-20
-17
-21
-18
-19
-20
-26
-18
-26
-20
-18
-15
-19
-18
-24
-22
-28
-24
-20
-26
-30
-20
-27
-18
-21
-18
-20
-20
-20
-22
-25
-24
-25
-28
-26
-34
-18
-30
-19
-15
-18
-16
-28
-20
-21
-25
-23
-25
-15
-19
-18
-23
-20
-24
-28
-22
-24
-20
-14
-23
-20
-17
-15
-14
-22
-15
-11
-17
-16
-18
-12
-16
-24
-16
-19
-20
-15
-22
-18
-14
-15
-12
-15
-15
-19
-11
-14
-19
-27
-29
-24
-23
-24
-27
-18
-24
-36
-18
-23
-19
-25
-32
-23
-32
-30
-27
-29
-27
-25
-14
-33
-27
-29
-24
-23
-22
-25
-21
-25
-27
-18
-25
-20
-22
-32
-26
-27
-26
-29
-16
-31
-25
-31
-24
-43
-22
-19
-21
-23
-24
-19
-28
-27
-27
-30
-22
-29
-22
-25
-26
-36
-19
-31
-27
-28
-13
-23
-26
-20
-25
-14
-23
-23
-25
-20
-21
-19
-21
-15
-34
-23
-33
-24
-30
-21
-34
-32
-23
-22
-20
-24
-23
-30
-29
-28
-24
-17
-28
-21
-27
-25
-15
-33
-26
-19
-33
-16
-26
-32
-21
-27
-24
-26
-26
-26
-16
-23
-20
-23
-22
-26
-12
-25
-23
-26
-18
-20
-20
-27
-24
-23
-20
-26
-32
-10
-32
-23
-19
-20
-24
-21
-23
-28
-17
-22
-18
-27
-22
-23
-19
-26
-17
-25
-27
-29
-27
-21
-17
-22
-19
-26
-16
-20
-19
-16
-19
-21
-16
-19
-15
-23
-15
-28
-13
-10
-11
-15
-17
-20
-15
-10
-19
-13
-15
-17
-17
-24
-17
-19
-18
-32
-26
-23
-28
-20
-34
-18
-25
-32
-15
-21
-27
-20
-32
-28
-19
-36
-25
-21
-23
-29
-34
-30
-35
-25
-18
-25
-30
-27
-32
-24
-30
-34
-14
-27
-36
-29
-19
-25
-30
-27
-19
-19
-32
-18
-28
-28
-26
-26
-33
-27
-29
-20
-34
-38
-27
-24
-21
-28
-24
-26
-24
-28
-26
-16
-31
-25
-19
-27
-19
-34
-26
-22
-21
-18
-27
-22
-34
-31
-21
-27
-24
-18
-20
-20
-23
-29
-26
-27
-29
-28
-23
-29
-24
-31
-20
-19
-23
-24
-27
-37
-30
-22
-23
-24
-27
-26
-29
-27
-26
-25
-19
-33
-18
-29
-27
-23
-17
-24
-21
-24
-17
-20
-29
-18
-20
-14
-20
-33
-18
-27
-26
-34
-18
-20
-26
-25
-18
-22
-30
-18
-24
-25
-15
-18
-22
-20
-9
-26
-21
-26
-15
-29
-26
-16
-26
-21
-17
-19
-12
-19
-17
-22
-13
-18
-16
-21
-20
-14
-14
-13
-18
-18
-28
-17
-19
-16
-20
-12
-16
-16
-16
-11
-17
-16
-12
-18
-14
-15
-13
-17
-15
-26
-18
-29
-19
-25
-27
-23
-19
-23
-22
-20
-27
-26
-25
-30
-30
-18
-25
-15
-12
-32
-25
-28
-25
-42
-19
-21
-25
-22
-29
-27
-25
-24
-23
-21
-27
-21
-25
-29
-25
-19
-22
-18
-29
-24
-34
-31
-24
-22
-22
-19
-21
-23
-25
-31
-19
-20
-42
-17
-25
-27
-24
-29
-16
-19
-16
-29
-23
-25
-24
-21
-22
-18
-32
-19
-16
-36
-23
-26
-15
-25
-21
-21
-17
-29
-26
-19
-26
-17
-23
-17
-29
-22
-14
-18
-19
-30
-23
-28
-23
-24
-14
-31
-32
-19
-22
-22
-28
-28
-23
-22
-12
-18
-20
-17
-26
-12
-19
-37
-18
-17
-21
-26
-26
-27
-26
-25
-18
-23
-19
-22
-20
-19
-21
-21
-24
-25
-17
-20
-21
-22
-15
-21
-17
-22
-16
-21
-25
-22
-22
-15
-20
-22
-13
-15
-27
-19
-16
-13
-18
-13
-15
-25
-10
-18
-20
-15
-27
-18
-19
-22
-15
-18
-19
-12
-8
-12
-19
-13
-12
-16
-21
-16
-17
-19
-13
-18
-10
-19
-16
-10
-14
-32
-24
-21
-21
-31
-36
-24
-26
-31
-28
-22
-30
-28
-17
-26
-20
-17
-21
-23
-23
-37
-25
-29
-26
-27
-33
-22
-26
-24
-19
-24
-20
-31
-23
-17
-34
-31
-34
-22
-25
-30
-34
-29
-19
-25
-29
-29
-26
-30
-33
-22
-23
-23
-16
-32
-21
-20
-32
-14
-25
-26
-17
-28
-24
-24
-23
-21
-22
-18
-25
-26
-28
-23
-19
-26
-23
-28
-22
-17
-19
-21
-36
-29
-15
-24
-18
-19
-26
-23
-12
-24
-19
-25
-16
-16
-23
-20
-31
-19
-28
-28
-24
-16
-27
-24
-26
-27
-17
-19
-25
-19
-24
-21
-24
-12
-25
-22
-18
-15
-20
-24
-23
-23
-28
-25
-27
-21
-24
-19
-17
-24
-26
-17
-32
-25
-15
-21
-20
-17
-32
-19
-23
-23
-26
-21
-13
-18
-20
-24
-18
-15
-21
-18
-24
-17
-20
-26
-18
-11
-29
-18
-18
-22
-13
-21
-17
-20
-18
-24
-19
-11
-18
-24
-22
-23
-16
-16
-20
-19
-13
-21
-10
-13
-11
-15
-11
-15
-17
-18
-15
-15
-13
-30
-25
-20
-23
-25
-24
-22
-30
-27
-26
-19
-23
-23
-30
-28
-23
-29
-33
-18
-27
-23
-24
-23
-16
-24
-32
-33
-27
-21
-20
-27
-25
-30
-33
-29
-20
-24
-21
-25
-23
-23
-22
-24
-26
-26
-27
-24
-27
-24
-24
-30
-21
-21
-34
-21
-23
-19
-17
-27
-27
-21
-26
-32
-34
-27
-28
-25
-26
-24
-26
-30
-24
-24
-19
-22
-23
-13
-29
-27
-33
-22
-18
-16
-28
-21
-18
-20
-14
-27
-17
-23
-28
-17
-27
-33
-15
-28
-24
-27
-25
-29
-18
-23
-28
-20
-20
-21
-28
-31
-31
-26
-22
-28
-28
-29
-30
-26
-18
-20
-20
-28
-23
-19
-23
-27
-16
-19
-18
-23
-18
-18
-28
-30
-26
-18
-24
-31
-19
-14
-30
-19
-18
-22
-24
-25
-15
-20
-19
-10
-22
-26
-23
-20
-15
-20
-24
-16
-14
-28
-25
-25
-21
-31
-22
-13
-17
-19
-25
-24
-14
-13
-20
-15
-15
-14
-18
-16
-22
-15
-12
-11
-13
-25
-12
-21
-9
-16
-20
-18
-18
-11
-12
-31
-25
-25
-16
-32
-22
-28
-27
-28
-25
-18
-36
-27
-26
-24
-21
-18
-20
-24
-19
-21
-24
-30
-34
-31
-29
-31
-28
-26
-25
-22
-17
-25
-23
-21
-28
-37
-18
-25
-37
-29
-22
-27
-27
-23
-27
-31
-29
-27
-30
-24
-24
-34
-26
-26
-32
-20
-20
-22
-21
-21
-24
-22
-24
-21
-34
-21
-33
-19
-25
-29
-22
-27
-22
-20
-22
-25
-25
-30
-26
-20
-15
-24
-19
-29
-23
-33
-20
-29
-27
-23
-32
-27
-27
-8
-26
-29
-25
-27
-31
-26
-24
-16
-26
-24
-25
-19
-20
-28
-24
-15
-21
-18
-24
-15
-23
-28
-19
-20
-31
-29
-29
-24
-36
-31
-23
-19
-21
-23
-22
-21
-27
-20
-27
-28
-29
-31
-27
-28
-22
-22
-20
-15
-19
-25
-28
-14
-19
-18
-21
-23
-18
-35
-15
-23
-21
-22
-18
-32
-25
-23
-32
-22
-20
-20
-17
-17
-16
-24
-17
-18
-17
-20
-19
-22
-19
-25
-17
-21
-23
-18
-23
-10
-11
-19
-13
-26
-12
-19
-17
-14
-20
-16
-23
-27
-19
-23
-22
-27
-16
-22
-25
-27
-24
-33
-30
-22
-25
-25
-29
-15
-22
-22
-35
-22
-24
-31
-24
-35
-31
-27
-33
-23
-27
-30
-30
-20
-22
-28
-29
-19
-26
-29
-14
-24
-24
-28
-20
-24
-22
-19
-23
-25
-28
-19
-15
-27
-23
-23
-25
-20
-25
-15
-26
-27
-33
-24
-26
-29
-20
-32
-31
-22
-21
-24
-26
-21
-21
-17
-20
-22
-35
-19
-27
-20
-24
-25
-25
-21
-23
-16
-26
-18
-19
-18
-21
-23
-24
-24
-10
-28
-28
-25
-26
-23
-13
-27
-24
-21
-25
-24
-18
-15
-35
-18
-23
-29
-20
-17
-19
-27
-35
-23
-26
-20
-21
-28
-19
-21
-24
-32
-23
-19
-18
-30
-35
-22
-24
-28
-21
-27
-20
-23
-31
-21
-21
-31
-19
-20
-24
-22
-19
-25
-22
-19
-21
-13
-18
-19
-13
-18
-20
-19
-10
-25
-19
-17
-17
-19
-22
-14
-18
-18
-19
-23
-25
-22
-19
-15
-19
-24
-15
-16
-15
-17
-18
-8
-11
-18
-15
-19
-21
-12
-14
-25
-24
-33
-25
-35
-19
-31
-24
-22
-19
-24
-23
-16
-25
-23
-35
-21
-23
-24
-25
-26
-24
-26
-36
-32
-30
-23
-27
-23
-23
-26
-25
-28
-29
-30
-25
-22
-31
-22
-27
-31
-27
-28
-23
-20
-20
-27
-39
-29
-23
-29
-30
-35
-21
-26
-24
-33
-20
-21
-23
-22
-22
-31
-16
-21
-30
-19
-26
-23
-26
-28
-23
-16
-19
-23
-35
-27
-17
-31
-15
-17
-31
-17
-20
-15
-21
-31
-21
-19
-26
-21
-27
-24
-30
-28
-18
-17
-25
-28
-29
-30
-25
-20
-20
-24
-23
-27
-22
-24
-16
-29
-13
-19
-16
-25
-23
-30
-23
-19
-21
-27
-22
-10
-19
-29
-19
-14
-30
-17
-29
-24
-23
-17
-17
-26
-23
-26
-17
-24
-27
-24
-25
-24
-21
-21
-19
-22
-8
-15
-31
-22
-17
-30
-25
-22
-24
-16
-19
-15
-10
-12
-22
-23
-31
-8
-14
-14
-24
-17
-25
-18
-11
-15
-18
-22
-21
-18
-14
-18
-13
-22
-15
-12
-17
-21
-12
-23
-13
-17
-16
-19
-15
-21
-23
-26
-19
-24
-34
-17
-21
-22
-26
-30
-29
-26
-28
-21
-29
-23
-26
-19
-19
-23
-26
-25
-25
-29
-27
-25
-25
-29
-20
-24
-23
-28
-20
-24
-19
-21
-17
-24
-18
-32
-21
-24
-25
-21
-23
-22
-26
-27
-31
-21
-32
-27
-31
-27
-29
-25
-21
-22
-26
-18
-27
-31
-21
-37
-25
-27
-30
-28
-22
-24
-25
-20
-35
-22
-30
-17
-25
-22
-22
-24
-22
-24
-19
-18
-14
-20
-21
-16
-22
-31
-28
-20
-25
-23
-25
-32
-17
-22
-14
-31
-23
-29
-21
-26
-20
-20
-30
-20
-29
-28
-18
-17
-26
-20
-21
-22
-20
-21
-28
-22
-25
-23
-13
-28
-18
-14
-24
-19
-17
-24
-20
-31
-20
-22
-19
-12
-23
-23
-22
-23
-12
-21
-21
-17
-15
-20
-24
-19
-20
-30
-19
-16
-20
-24
-22
-17
-10
-28
-28
-18
-18
-17
-11
-18
-14
-25
-19
-16
-15
-24
-14
-10
-18
-21
-16
-16
-20
-12
-15
-13
-13
-15
-21
-21
-12
-17
-19
-16
-10
-16
-7
-22
-27
-18
-32
-22
-26
-27
-29
-22
-16
-19
-20
-23
-29
-25
-19
-27
-30
-18
-21
-32
-30
-32
-31
-27
-28
-30
-16
-21
-23
-23
-22
-23
-24
-14
-36
-27
-24
-19
-23
-20
-32
-34
-33
-20
-24
-16
-31
-17
-23
-30
-20
-32
-24
-21
-21
-24
-20
-30
-29
-20
-29
-15
-22
-23
-28
-27
-25
-28
-24
-26
-32
-20
-20
-18
-25
-21
-21
-29
-24
-17
-23
-20
-16
-21
-20
-21
-21
-25
-25
-24
-18
-25
-22
-31
-15
-23
-21
-25
-20
-17
-26
-17
-24
-34
-36
-24
-20
-26
-19
-23
-25
-23
-26
-25
-14
-21
-25
-27
-22
-20
-18
-21
-26
-27
-27
-24
-16
-24
-21
-28
-31
-18
-25
-27
-32
-17
-30
-16
-26
-22
-24
-21
-25
-25
-15
-28
-24
-24
-18
-16
-24
-21
-23
-19
-14
-27
-15
-22
-19
-17
-14
-19
-23
-21
-19
-24
-24
-22
-13
-23
-19
-16
-21
-18
-22
-21
-17
-17
-15
-25
-21
-21
-9
-13
-20
-17
-13
-13
-22
-13
-19
-38
-18
-19
-27
-24
-27
-17
-21
-27
-27
-28
-27
-33
-32
-27
-25
-26
-35
-19
-27
-26
-31
-29
-32
-26
-20
-31
-22
-20
-24
-29
-23
-18
-27
-31
-30
-22
-23
-28
-22
-35
-26
-24
-22
-24
-16
-23
-23
-32
-26
-26
-31
-13
-30
-26
-23
-26
-22
-18
-18
-29
-26
-19
-29
-27
-23
-18
-21
-24
-28
-28
-24
-34
-19
-28
-19
-24
-22
-24
-24
-25
-17
-31
-21
-24
-36
-30
-21
-12
-29
-20
-28
-24
-29
-23
-18
-18
-30
-21
-22
-19
-18
-29
-34
-19
-22
-24
-30
-21
-20
-23
-20
-21
-22
-17
-21
-19
-19
-27
-22
-25
-16
-16
-19
-15
-22
-19
-19
-23
-17
-26
-30
-28
-20
-19
-24
-16
-26
-14
-26
-26
-20
-25
-22
-20
-22
-25
-24
-18
-24
-17
-18
-19
-26
-20
-19
-21
-24
-20
-18
-19
-15
-15
-17
-19
-15
-19
-18
-10
-15
-25
-14
-21
-18
-19
-26
-17
-17
-15
-18
-23
-24
-16
-15
-9
-17
-16
-16
-20
-10
-19
-20
-20
-29
-27
-23
-27
-18
-28
-18
-26
-25
-26
-24
-25
-19
-17
-26
-38
-27
-28
-29
-27
-33
-20
-29
-18
-32
-28
-22
-29
-30
-26
-22
-30
-27
-30
-27
-38
-26
-32
-29
-27
-27
-31
-24
-17
-30
-25
-44
-16
-24
-28
-24
-23
-29
-27
-31
-25
-25
-24
-29
-29
-26
-22
-26
-17
-26
-31
-24
-25
-42
-31
-31
-21
-28
-25
-26
-24
-21
-27
-24
-28
-16
-20
-27
-20
-19
-20
-22
-27
-21
-11
-27
-24
-26
-26
-23
-26
-31
-25
-19
-27
-31
-27
-22
-32
-21
-27
-33
-25
-17
-21
-19
-21
-33
-23
-19
-18
-24
-33
-19
-21
-22
-24
-23
-21
-26
-20
-22
-14
-21
-22
-25
-26
-19
-17
-20
-27
-20
-26
-23
-19
-27
-20
-25
-19
-23
-26
-18
-23
-26
-23
-20
-19
-27
-23
-21
-28
-20
-24
-21
-15
-18
-20
-18
-22
-15
-19
-23
-24
-17
-18
-19
-18
-21
-14
-17
-17
-21
-15
-12
-22
-14
-16
-16
-16
-17
-19
-18
-14
-20
-12
-18
-30
-34
-27
-28
-22
-24
-20
-22
-29
-29
-20
-16
-38
-27
-28
-36
-16
-33
-30
-25
-24
-32
-21
-16
-37
-26
-23
-23
-38
-32
-25
-26
-29
-23
-27
-24
-26
-38
-29
-26
-26
-34
-28
-31
-20
-27
-20
-34
-21
-16
-23
-23
-29
-31
-28
-22
-20
-25
-18
-24
-23
-27
-21
-26
-36
-26
-22
-26
-32
-22
-31
-26
-33
-17
-30
-24
-21
-28
-21
-20
-23
-27
-33
-27
-31
-25
-18
-28
-36
-28
-24
-16
-24
-32
-29
-28
-37
-20
-33
-32
-29
-23
-22
-35
-24
-24
-19
-13
-28
-22
-20
-26
-25
-30
-23
-16
-32
-24
-24
-28
-14
-12
-16
-23
-14
-24
-16
-20
-23
-25
-24
-26
-28
-22
-24
-24
-28
-21
-22
-17
-16
-19
-22
-19
-26
-17
-13
-21
-21
-20
-20
-19
-18
-21
-28
-21
-17
-25
-19
-22
-16
-13
-16
-19
-17
-16
-24
-20
-7
-9
-18
-21
-16
-12
-18
-20
-21
-21
-21
-22
-16
-21
-11
-14
-15
-18
-21
-14
-26
-14
-11
-13
-23
-32
-23
-25
-35
-21
-19
-19
-22
-25
-22
-21
-30
-31
-25
-25
-27
-26
-26
-16
-17
-25
-30
-33
-20
-26
-31
-28
-25
-23
-25
-20
-32
-30
-32
-25
-31
-31
-24
-26
-23
-31
-33
-21
-31
-31
-23
-29
-25
-25
-16
-19
-26
-26
-48
-30
-24
-27
-30
-36
-24
-24
-27
-26
-26
-25
-22
-27
-27
-28
-22
-30
-21
-21
-22
-18
-19
-22
-15
-17
-32
-25
-30
-23
-21
-20
-20
-40
-23
-22
-26
-34
-18
-24
-21
-24
-29
-14
-28
-26
-27
-17
-21
-26
-27
-24
-24
-24
-24
-21
-20
-19
-26
-26
-25
-24
-26
-29
-29
-26
-20
-25
-17
-20
-28
-18
-23
-23
-21
-19
-22
-30
-29
-24
-18
-24
-23
-23
-19
-18
-17
-20
-21
-31
-25
-22
-19
-26
-22
-25
-17
-28
-23
-11
-27
-27
-10
-19
-16
-15
-22
-30
-19
-21
-21
-21
-19
-16
-21
-25
-18
-15
-20
-13
-13
-16
-20
-16
-18
-14
-19
-10
-14
-13
-11
-16
-16
-15
-15
-14
-21
-19
-24
-20
-32
-39
-29
-25
-30
-32
-27
-20
-33
-28
-20
-24
-26
-26
-28
-24
-19
-29
-28
-33
-21
-41
-18
-22
-32
-28
-21
-31
-26
-29
-23
-22
-23
-28
-26
-32
-27
-28
-24
-28
-25
-34
-31
-37
-19
-32
-23
-25
-25
-23
-15
-27
-38
-20
-26
-26
-22
-26
-24
-25
-21
-23
-24
-25
-26
-17
-22
-23
-31
-20
-25
-16
-27
-25
-24
-24
-24
-23
-22
-23
-26
-22
-22
-31
-29
-24
-16
-27
-30
-17
-24
-26
-31
-21
-20
-29
-22
-31
-13
-36
-18
-26
-23
-28
-27
-29
-24
-26
-18
-22
-34
-27
-27
-34
-14
-26
-19
-27
-22
-34
-14
-24
-16
-18
-26
-24
-18
-27
-32
-27
-14
-27
-31
-21
-33
-36
-26
-23
-25
-27
-23
-18
-17
-20
-40
-20
-24
-25
-24
-20
-23
-15
-19
-29
-14
-16
-13
-30
-24
-15
-16
-16
-16
-18
-21
-21
-21
-16
-11
-21
-21
-20
-18
-24
-17
-16
-15
-12
-16
-28
-19
-16
-20
-19
-21
-18
-13
-21
-17
-16
-18
-32
-24
-35
-21
-29
-21
-35
-28
-22
-29
-35
-29
-30
-31
-38
-26
-24
-26
-27
-31
-28
-24
-27
-30
-29
-21
-31
-32
-28
-22
-34
-27
-27
-19
-33
-31
-26
-20
-25
-17
-19
-28
-31
-33
-32
-28
-28
-25
-28
-28
-35
-44
-28
-20
-24
-26
-30
-29
-26
-32
-33
-22
-25
-15
-25
-15
-25
-25
-32
-20
-31
-22
-33
-39
-26
-29
-23
-22
-30
-17
-24
-28
-24
-20
-30
-23
-27
-25
-26
-23
-26
-24
-17
-28
-16
-24
-26
-17
-23
-27
-21
-16
-24
-29
-27
-22
-19
-28
-21
-24
-25
-30
-22
-11
-25
-30
-18
-26
-21
-21
-23
-20
-17
-29
-28
-15
-25
-27
-26
-28
-25
-21
-21
-23
-21
-16
-17
-20
-15
-19
-25
-29
-18
-19
-20
-20
-24
-25
-23
-21
-22
-21
-21
-13
-20
-18
-29
-23
-21
-22
-28
-20
-19
-24
-13
-27
-22
-16
-16
-23
-20
-21
-20
-6
-23
-18
-18
-15
-13
-19
-13
-23
-16
-17
-12
-24
-17
-24
-18
-26
-16
-43
-37
-58
-45
-48
-48
-51
-44
-47
-53
-45
-40
-62
-48
-53
-56
-47
-37
-50
-57
-46
-56
-45
-61
-51
-53
-50
-57
-49
-54
-60
-55
-41
-61
-43
-43
-48
-51
-43
-46
-55
-60
-39
-62
-51
-42
-47
-66
-48
-44
-41
-47
-53
-36
-50
-51
-36
-59
-53
-39
-37
-43
-51
-54
-41
-45
-47
-51
-46
-45
-45
-52
-54
-53
-60
-46
-44
-42
-42
-50
-47
-53
-52
-39
-37
-48
-45
-52
-43
-53
-42
-37
-32
-39
-27
-44
-49
-47
-47
-43
-44
-48
-47
-44
-41
-57
-46
-57
-45
-40
-47
-33
-54
-44
-35
-39
-31
-41
-48
-40
-29
-52
-45
-40
-34
-36
-43
-57
-39
-39
-33
-49
-41
-35
-50
-36
-47
-61
-32
-51
-31
-48
-39
-41
-45
-31
-46
-39
-37
-37
-35
-43
-32
-36
-39
-36
-32
-34
-35
-39
-24
-33
-34
-29
-30
-37
-37
-42
-35
-41
-32
-27
-32
-39
-37
-30
-42
-32
-31
-28
-29
-32
-29
-31
-31
-28
-22
-24
-35
-33
-21
-26
diff --git a/sasview/test/2d_data/MAR07262.ASC b/sasview/test/2d_data/MAR07262.ASC
deleted file mode 100644
index 7c2cf79..0000000
--- a/sasview/test/2d_data/MAR07262.ASC
+++ /dev/null
@@ -1,16403 +0,0 @@
-FILE: MAR07262.SA3_LP _V978 CREATED: Tuesday, Mar 13, 2007 12:42:07 PM
-LABEL: 13m Rad 250Pa Fib1 Th 0.16 PH7.4 Ca 2.5mM
-MON CNT LAMBDA(A) DET_OFF(cm) DET_DIST(m) TRANS THICK(cm)
-1e+08 8.4 0 13.705 0.84357 0.2
-BCENT(X,Y) A1(mm) A2(mm) A1A2DIST(m) DL/L BSTOP(mm) DET_TYP
-68.76 62.47 38 17.5 15.723 0.142 76.2 ORNL
-SAM: MAR07262.SA3_LP _V978
-BGD: MAR07171.SA3_LP_V887,
-EMP: MAR07060.SA3_LP_V776,MAR07061.SA3_LP_V777,
-DIV: PLEX_04JAN07_NG3.DIV,
-MASK: DEFAULT.MASK,
-ABS Parameters (3-6): TSTAND=1;DSTAND=1;IZERO=84.433;XSECT=1
-Average Choices: AVTYPE=2D_ASCII;SAVE=Yes;NAME=Auto;PLOT=Yes;
-
-*** Data written from ABS folder and may not be a fully corrected data file ***
-The detector image is a standard X-Y coordinate system
-Data is written by row, starting with Y=1 and X=(1->128)
-ASCII data created Tuesday, Mar 13, 2007 12:42:07 PM
-
-0.418265
-0.166727
-0.166814
-0.0598404
--0.168623
-0.364459
-0.240687
-0.124927
--0.154008
-0.0435788
-0.0491204
--0.0301643
--0.164288
-0.499962
--0.0800917
-0.0469735
--0.164055
-0.217711
-0.0183355
-0.144775
-0.0153499
-0.126423
-0.0178016
-0.271138
-0.0153664
--0.0763996
--0.238873
-0.169531
--0.0339659
-0.0485327
-0.181019
-0.184344
-0.193224
-0.116066
-0.254994
-0.271
-0.101052
-0.263675
-0
-0.379963
-0.0556205
-0.238007
--0.305304
-0.155484
--0.297917
--0.0851463
-0.0537777
-0.277175
-0.259224
-0.186829
--0.0363297
--0.252573
--0.221403
-0.157001
--0.0358881
-0.382762
-0.105496
-0.132042
--0.08766
--0.0357219
-0.342129
--0.123215
--0.123858
-0.581562
-0.359674
-0.158182
-0.10659
-0.235744
--0.0859083
-0.238659
--0.185233
--0.0849962
--0.0705175
-0.447684
-0.346508
-0.0719322
-0.202099
--0.0357673
--0.0368335
-0.103313
-0.0537073
-0.309735
-0.172666
-0.262765
-0.145031
-0.402887
-0.0528493
--0.115221
-0.110123
--0.151253
-0.292988
-0.360103
-0.333103
-0.219571
-0.331379
--0.116235
-0.198383
-0.0958776
-0.0526908
-0.0933233
-0.0490975
--0.191348
--0.0668154
-0.163025
-0.272732
-0.282647
--0.161607
-0.536183
--0.256234
-0.0909638
-0.222293
-0.159726
--0.0590538
-0.206486
-0.215839
--0.0422706
-0.0136576
-0.0163849
-0.248551
--0.030093
--0.0988086
-0.415578
-0.0429112
-0.111665
--0.0286037
--0.123032
-0.36424
--0.174713
-0.618662
--0.0872582
--0.0631149
-0.150765
--0.0314376
--0.086353
--0.15235
-0.0521312
--0.195021
-0.259687
-0.383924
-0.134875
--0.16013
--0.121393
-0.168438
--0.0346083
--0.0471516
-0.194274
-0.218351
-0.158843
-0.257436
-0.189777
-0.398892
-0.153279
-0.317658
-0.0176269
-0.735849
--0.170657
-0.100474
-0.411872
--0.123768
-0.0657323
--0.0880042
-0.0157373
-0.175058
-0.433106
-0.0524499
--0.254281
-0.180519
-0.0639481
-0.0518362
-0.561415
-0.276215
-0.138415
-0.107184
-0.409516
-0.0520761
-0.369051
--0.0139801
-0.153209
--0.197873
-0.29486
-0.152329
-0.0700951
--0.169496
-0.272899
-0.325473
-0.191152
--0.151182
-0.45966
-0.160135
-0.880927
--0.089357
-0.100463
-0.682835
-0.0194782
--0.158652
--0.0160377
--0.0839089
-0.404995
-0.215743
-0.185702
-0.0661584
-0.152156
-0.0679602
-0.189581
-0.018448
--0.211952
-0.0526624
-0.189354
-0.48573
-0.0555939
-0.33158
-0.198529
--0.0338231
-0.328056
-0.140625
-0.277889
--0.255663
-0.165657
-0.571349
-0.319841
--0.291474
--0.069552
-0.0542825
-0.185594
-0.22482
--0.0363729
-0.463084
-0.444861
-0.10083
-0.272864
--0.271116
-0.0989433
-0.0190017
-0.0484307
-0.28579
--0.180852
-0.223652
-0.0691515
-0.181487
-0.144931
--0.235449
-0.0674086
-0.19039
--0.334146
-0.0971631
-0.0499073
--0.0857646
-0.238546
--0.113412
-0.0479519
--0.0636277
-0.473292
-0.0174926
-0.0179964
-0.0981605
-0.206324
-0.394255
--0.0367555
-0.0486612
-0
-0.0465705
-0.344064
-0.559414
-0.0722162
-0.222114
-0.299934
--0.0313616
-0.0500404
-0.0505335
--0.0882855
--0.0857874
-0.152134
-0.219879
--0.172661
-0.41427
-0.190243
-0.127189
-0.164317
--0.17354
-0.164245
-0.0501438
-0
-0.309807
--0.0347527
-0.289732
-0.196371
--0.176262
-0.139008
-0.591086
-0.0160813
--0.0668379
-0.0165889
--0.0721875
--0.0915692
--0.0852018
-0.0185068
-0.103524
--0.151971
-0.426628
--0.183948
-0.190172
-0.200526
-0.247862
-0.28327
--0.0199808
-0.249811
-0.248694
-0.128596
-0.168937
-0.347676
--0.0365127
-0.141346
-0.0161602
-0.241504
-0.396752
-0.109361
-0.265076
-0.288483
-0.0712238
-0.073704
-0.204002
-0.450646
--0.270883
-0.190684
-0.29441
-0.067224
-0.293434
-0.0353311
-0.693537
-0.261603
--0.0724627
-0.143994
-0.19875
-0.395893
--0.0381234
-0.0698944
-0.427472
--0.039191
--0.130546
-0
--0.168458
-0.292552
-0.0164794
-0.0164444
-0.267636
-0.207999
--0.0373316
--0.12479
-0.115759
--0.401961
--0.0359364
--0.134171
-0.178396
-0.166525
--0.090516
-0.0534972
-0.338754
-0.325276
-0.142861
--0.0381774
--0.0951249
--0.0201066
-0.429065
-0.0527404
-0.0155593
--0.0965245
-0.194423
--0.119574
-0.198687
-0.0524771
--0.0682561
-0.283427
-0.101767
--0.090878
-0.0151298
-0.737865
-0.0495779
-0.160846
--0.0678186
-0.33033
-0
-0.330431
-0.188542
--0.0759771
--0.0435321
-0.0218183
--0.22747
-0
-0.142726
-0.195587
--0.0877919
--0.485378
-0.0163978
--0.0393791
-0
--0.0962997
--0.133214
-0.605203
--0.135881
--0.0391245
-0.0523336
--0.277116
-0.0169559
--0.039486
-0.0194908
-0.515003
-0.10782
-0
-0.259682
-0.0548569
-0.206548
-0
--0.0387392
-0.351731
--0.0969237
--0.0189435
-0.331426
-0.306821
-0.347837
--0.131426
-0.0173993
-0.809183
--0.0392084
-0.514323
-0.172775
-0.0577668
--0.131835
-0.114508
--0.234644
--0.0968535
-0.260312
-0.109874
-0.20785
-0.127961
--0.092545
--0.0408915
-0.176538
-0.116471
--0.092516
--0.03945
-0.600467
-0.0568137
--0.360047
-0.464765
-0.17058
-0.0213541
-0.259782
-0.304311
-0.777354
-0.450737
--0.0406613
-0.204374
-0.202188
-0.346112
-0.357225
--0.0803309
-0.114857
--0.13372
-0.207903
--0.192722
-0.0541698
-0.443509
-0.209252
--0.197446
-0.360208
-0.372304
-0.262523
-0.376128
-0.173023
-0.215852
--0.0559468
-0.328381
-0.15242
-0.10953
-0.212801
-0.306672
-0.213774
-0.416178
-0.310419
--0.199217
-0.202169
-0.314767
-0.408629
--0.127416
-0.162218
-0.56218
-0.114339
--0.192347
--0.191883
-0.0536429
-0.195221
-0.198472
--0.088677
--0.0372086
--0.016484
--0.0910933
-0.526258
-0.468924
-0.141845
--0.176814
-0.252572
-0.431767
-0.158717
-0
--0.0350783
-0.0170513
--0.0362426
-0.0562545
-0.056171
-0.162447
--0.0374823
--0.1052
-0.270285
-0.397672
-0.250828
--0.174395
-0.486074
--0.0924871
-0.418571
-0.584398
--0.0921027
-0.165739
-0
--0.188929
-0.302832
-0.198284
-0.109989
-0.264457
-0.196179
-0
-0.198146
-0.112188
-0.140272
-0.170209
--0.0887009
-0.514189
-0.204575
-0.258819
-0.0689904
-0.174691
--0.136128
--0.0952203
-0.464621
-0.311314
--0.135263
--0.0924905
-0.192104
-0.14408
--0.187577
--0.193258
-0.366435
-0.0532528
--0.131364
-0.415639
--0.0386458
-0.151064
-0.1745
-0.270576
-0
--0.0387247
-0.223706
-0.560527
-0.313188
-0.291347
--0.0795956
--0.288765
-0.274182
-0.0579216
-0.301827
-0.175008
-0.114036
-0.463631
-0.16659
--0.233294
-0.0175175
-0.166212
-0.0583758
--0.0980463
-0.0597883
-0.149982
-0.0173318
-0.170711
-0.0578795
--0.0390813
-0.993737
--0.475107
-0.113255
-0.419424
--0.645184
-0.304034
-0.381218
-0.267939
-0.153551
-0.152509
-0
--0.119975
-0.506073
--0.416148
-0.271928
-0.179507
--0.0398027
--0.235815
-0
--0.13031
--0.293631
--0.193806
-0.388605
-0.0551875
-0.019912
-0.122264
-0
-0.0551409
-0
-0.610419
--0.30305
-0.141221
-0.0210726
-0.110169
--0.036504
--0.131615
-0.0192179
-0.115192
-0
--0.0894279
-0.0513069
-0.401326
--0.181541
--0.125364
--0.0328095
-0.299041
--0.240868
-0.195333
-0
-0.201167
-0.197334
-0.343535
--0.157896
-0.0174234
--0.213562
-0.162149
-0.366249
-0.322069
-0.202287
-0
--0.180257
--0.0369142
-0.19545
-0.202747
-0.284768
-0.0571501
-0.11667
-0.437456
-0.144421
-0.294958
-0.292531
--0.0379661
-0.332553
-0.054739
-0.34592
-0.15871
-0.248247
-0.304395
--0.0383144
--0.0378107
--0.0934177
--0.0365845
-0.262754
-0.441711
-0.209857
-0.346624
-0.0550318
-0.251548
-0.10781
-0.369953
--0.279784
-0.203789
--0.19054
--0.0900908
--0.0357566
-0.314893
-0.207402
-0.578025
-0.055479
--0.168481
-0.251601
-0.163044
-0.511796
-0.355861
-0.0558742
-0.327525
--0.0727055
-0.111475
-0.072224
-0.356853
-0.144421
--0.184869
-0.189649
-0.36043
--0.269742
--0.376298
--0.221724
-0.951147
-0.735269
--0.0380747
-0.82731
--0.018017
--0.0148624
-0.219236
-0.0172205
-0.0546426
-0.322381
-0.349742
-0.45336
-0.599232
-0.280528
--0.076045
-0.707957
--0.0388925
-0.240886
-0.204485
--0.0939633
-0.107268
-0.280525
-0.114038
-0.599443
-0.0535219
-0.366395
-0.303339
-0.113925
-0.296301
--0.130514
-0.19848
--0.0363766
-0.145162
-0.254221
-0.0168139
--0.124053
-0.431306
-0.409647
--0.0355684
-0.340938
--0.193505
-0.30072
-1.01829
-0
-0.136512
-0.291077
-0.358138
-0.382159
--0.0371908
-0.108458
-0.0524384
--0.0855428
-0.195466
-0.272719
--0.116963
--0.114662
-0.105455
--0.083434
-0.186792
-0.13921
-0.102169
-0.100109
--0.254319
--0.0331603
--0.293205
--0.121918
-0.0574694
--0.201474
-0.055268
-0.256551
--0.0375619
--0.0371364
-0.165275
-0.0169057
-0.159341
-0.446703
-0.112627
-0.730018
--0.224849
-0.171989
-0.200047
-0.359313
-0.208897
--0.0382681
-0.259306
-0.462319
-0.45915
--0.0363091
-0.151858
--0.196326
-0.360642
--0.0926498
--0.0365742
--0.0379299
--0.0956655
-0.0205632
-0.431265
-0.590741
-0.0542961
-0.577118
--0.191867
--0.0937817
--0.0386474
--0.0729564
-0.154904
--0.0371108
-0.168633
-0.136558
-0.318471
-0.0600095
--0.134732
-0.302891
--0.0935067
-0.435245
--0.0799596
-0.261859
--0.142798
-0.448659
--0.227747
-0.597158
-0.307893
-0.285481
-0.172776
--0.0399764
--0.236106
--0.268286
-0.810383
-0.273303
-0.0576174
-0.273695
-0.205151
--0.0967605
-0.417016
-0.209008
-0.114113
-0.259815
-0.111485
--0.139246
-0.296264
-0.153227
-0.0173948
-0.383855
-0.0218375
-0.0164247
-0.154616
--0.0978907
-0.153425
-0.357024
-0.349925
--0.0402184
-0.215448
--0.127185
--0.184183
-0.316885
-0.114804
-0.21656
--0.0761823
-0.0569715
-0.0539828
-0.272766
-0.530648
-0.061163
-0.17005
--0.129918
--0.291701
--0.0898274
-0.108834
--0.37178
--0.0751651
--0.374682
-0.212243
-0.0393709
-0.0543752
--0.036818
-0
-0.0531191
--0.0979679
-0.11106
-0.0169409
--0.0904609
-0.0544077
--0.0351669
--0.0904069
-0.102595
--0.0935374
-0.287194
-0.333309
--0.179316
--0.0918237
--0.256112
-0.643989
--0.0368739
--0.281022
--0.179802
-0.333051
--0.316784
--0.20808
-0.505732
--0.133993
-0.303193
-0.117134
-0.0542365
-0.0578217
-0.231485
--0.137674
-0.472093
-0.210657
-0.0598529
--0.0982003
-0.310971
-0.0751203
-0.110003
--0.0938998
-0.419004
--0.0975196
--0.0882446
-0.272518
-0.110813
--0.0968439
--0.0411652
-0
-0.322702
--0.0918041
-0.163679
--0.192149
-0.30286
--0.0403469
-0.274501
-0.11904
--0.195599
-0.207772
--0.196165
-0.212542
--0.0998191
-0.0586336
--0.0985628
-0.207362
-0.114706
-0.0586887
-0.23456
-0.464027
-0.0183465
-0.567217
--0.1877
-0.220514
-0.206082
--0.0999139
-0.0180008
-0.307206
-0.210228
-0.490255
-0.175807
-0.177042
-0.414746
-0.0586508
-0.47953
--0.134004
--0.0151288
--0.041174
-0.0750185
-0.585375
--0.304405
-0.170388
--0.1897
-0.0585126
-0.117617
-0.017812
-0.266141
-0.268117
-0.114704
-0.387053
-0.0783948
-0.283964
--0.300377
-0.423134
--0.227552
--0.289629
-0.210298
-0.348659
-0.0563168
-0.171147
-0.216884
-0.637759
-0.179818
-0.699231
--0.231155
-0.208388
-0.567494
--0.0392652
--0.192017
-0.0588836
-0.200347
-0.471657
-0.154322
-0.196441
--0.0378936
-0.141485
-0.209718
--0.287869
--0.198934
--0.0172745
-0.257384
--0.0385736
-0.29491
-0.270718
-0.0550197
-0.222903
--0.0920596
-0.153502
-0.110957
-0.203675
--0.0739028
--0.0374281
--0.133583
-0.149349
-0.0524191
-0.0513902
--0.0899389
-0.295534
-0.345626
--0.0376848
-0.107161
-0.231663
-0.0207224
--0.174744
-0.0684994
-0.271631
--0.0853084
-0.0520803
-0.129063
--0.276007
--0.034133
-0.340784
--0.0352605
--0.0822872
-0.585655
-0.459292
--0.211984
--0.0358322
--0.0327538
-0.0708339
-0.29535
-0.0538416
-0.0504973
-0.193315
-0.136581
-0.554538
-0.106984
-0.190374
-0.0193294
--0.087361
-0.157926
-0.157027
-0.0525932
-0.189525
-0.14198
--0.0731907
-0.0504373
-0.287231
-0
--0.0327396
--0.0346986
-0.106323
--0.231554
--0.26468
-0.144126
--0.0374083
--0.0910036
-0.367859
-0.352523
-0.155661
-0.0716536
-0.755214
-0.200728
-0.317418
-0.0167638
--0.122353
--0.38329
-0.0702302
-0
-0.0161684
-0.396911
-0
-0.145774
--0.184547
-0.0523618
--0.0700982
--0.16104
--0.376964
-0.526098
--0.0173233
--0.0388144
-0.108743
-0.0550752
-0.41276
-0.354664
--0.0959668
--0.0743176
-0.334127
-0.0707028
-0.265076
-0.0764552
-0.304397
-0.453525
-0.567478
-0.29139
--0.0395635
-0.0560802
-0.148256
--0.379139
--0.073473
-0.113918
-0.590731
-0.202661
--0.037118
--0.191286
-0.0788875
--0.166496
-0.111359
-0.478372
--0.191993
-0.506019
--0.0172918
-0.338879
-0.341981
-0.36619
-0.202732
--0.180864
-0.144602
-0.0166909
--0.127156
-0.165257
-0.25179
-0.1866
-0.247315
-0.291107
-0.301059
-0.24292
--0.0914253
-0.378695
--0.19245
-0.070183
-0.285627
-1.00156
-0.345205
--0.0357279
--0.173873
--0.287079
-0.104461
-0.191999
--0.0987322
-0.059164
-0.151193
-0.0557424
-0.0563629
--0.0372329
-0.0570251
-0.139478
--0.198565
--0.0931066
-0.114088
-0.259021
--0.188612
--0.0908877
-0
--0.12766
--0.298746
-0.105834
--0.287011
--0.0923113
-0.336022
-0.104591
--0.28949
-0.490294
-0.208417
-0.113137
-0.279573
-0.0524944
-0.557918
-0.269107
-0.267207
--0.284917
-0.207666
-0.0565779
-0.41671
-0.170571
-0.364459
-0.0170419
-0.0549403
-0.0567128
--0.364964
--0.042283
-0.363719
--0.195663
--0.179231
-0.207716
--0.188485
-0.635535
-0.0604588
-0.0560117
--0.136647
--0.0925091
-0.0206187
-0.0571991
--0.350266
--0.366583
-0.227033
--0.0407756
-0.21361
-0.232781
--0.300943
--0.204998
-0.354648
-0.0214084
-0.0552815
-0.215071
--0.0417811
-0.27983
--0.0388053
-0.0170313
-0.613197
-0.119874
-0.111726
-0.170152
-0.306854
--0.0412434
--0.294843
-0.218069
-0.119635
--0.0807512
-0.808983
--0.131317
-0.0580013
-0
-0.110717
-0.31202
--0.0388748
-0.636535
-0.316964
-0.156088
--0.36967
-0.0184054
-0.35396
-0.210819
--0.083698
--0.29287
-0.057321
-0.257178
--0.192047
--0.188181
-0.346039
--0.227253
-0.0552935
-0.111813
-0.0163814
-0.0600373
-0.34631
-0.0162996
-0.0546721
--0.131802
--0.132263
--0.187056
-0.0530381
-0.106695
-0.210007
--0.123384
-0.256719
-0.068447
-0.146534
--0.0364646
--0.072073
-0.144991
--0.0378838
--0.248673
-0.110765
--0.12213
-0.0547509
-0.343307
--0.0845348
-0.152814
-0.0966633
-0.329875
-0.0762313
-0.116387
-0.272477
-0.26882
-0.0530097
--0.0882437
-0.147189
--0.127823
-0.281312
-0.0547489
--0.12721
-0.481839
-0.341459
--0.127627
-0.0530249
--0.383068
-0.127106
-0.276132
-0.10958
--0.167154
-0.55722
-0.337462
-0.112216
-0.0541068
-0.107287
-0.0161695
-0.347267
-0.138694
--0.0859897
-0.284795
--0.187328
--0.210582
-0.304058
-0.738034
-0.0166342
-0.0166899
-0.0163852
-0.437872
--0.0384669
-0.105637
-0.141989
--0.0747928
--0.130413
-0.454565
-0.598271
-0.218671
--0.226763
-0.251653
-0.112481
-0.198612
-0.299807
--0.0908087
-0.296658
-0.113117
--0.0904652
-0.159018
--0.0718195
-0.112052
-0.0558655
-0.0346989
-0.0697301
-0.441277
-0.468136
-0.43636
-0.0164831
-0.290978
--0.130507
-0.0574577
-0.257829
-0.199565
-0.211417
-0.0562682
--0.0772246
-0.353017
-0.0564698
-0.372954
-0.0531447
-0.448287
-0.200392
-0.264069
-0.017436
-0.103978
-0.302947
-0.50762
-0.0169629
--0.382971
--0.0335029
-0
--0.183778
-0.329203
-0.157395
-0.150403
-0.0355948
-0.0361963
-0.264492
--0.0384662
-0.33346
-0.341095
--0.0896146
-0.401824
-0.0164317
-0.508759
--0.293663
-0.294409
-0.145826
-0.106129
-0.345885
--0.327509
-0.600368
--0.179724
--0.129565
-0.163255
--0.0740557
--0.0879834
-0.0536526
-0.426555
--0.0687342
-0.142199
--0.121966
--0.0354886
-0.330926
-0.246341
--0.131327
--0.251808
-0.21446
--0.185266
-0.559643
-0.220931
-0.678039
--0.191867
-0.516287
-0.585758
--0.109323
-0.0581018
-0.0650032
-0.807404
-0
-0.0604181
--0.473643
-0.168343
-0.129051
-0.0543293
--0.145489
-0.373285
--0.0429258
-0.0203409
-0.162531
-0.116064
--0.22079
--0.243587
--0.382764
--0.0407354
-0.345913
--0.100156
-0.0627582
--0.141498
-0.392625
--0.281367
--0.0426407
--0.237381
-0.578256
-0.0597498
-0.317293
-0
--0.204731
-0.187087
-0.425279
--0.0417262
-0.226243
-0.164665
--0.101457
-0.562747
-0.402723
-0.314382
-0
--0.204681
-0.118763
-0.380045
-0.0189392
-0.314259
-0.55338
--0.0382236
-0.0183735
-0.612378
-0.0187031
-0.125696
--0.144534
-0.444057
-0.23317
-0.0603229
--0.294219
--0.197469
-0.381331
-0.280849
-0.69471
-0.0763242
-0.267673
--0.0232432
-0.180543
-0.222166
-0.0187016
--0.382891
-0.0785166
-0.392803
--0.178858
-0.618525
--0.083089
--0.229885
-0.895344
--0.120861
-0.0574082
-0.1529
-0.379336
--0.307396
-0.532649
-0.161885
--0.177111
--0.10539
-0.0217025
-0.0224655
--0.040943
--0.0778627
--0.323138
-0.274421
--0.22893
-0.153549
-0.159223
-0.552969
-0.220245
-0.285138
--0.218319
--0.0393194
-0.216874
-0.407819
-0.0622931
--0.133028
--0.132945
-0.161691
-0
-0.0542677
--0.0823696
-0.293391
-0.627325
-0.260502
-0.367703
-0.353687
--0.13555
-0.386028
-0.432913
-0.454885
--0.100894
-0.216749
--0.106046
-0.358352
--0.0888309
-0.132708
--0.0353086
--0.0342785
-0.187666
-0.182028
-0.578672
-0.050474
-0.102487
-0.0172698
-0.0496321
-0.0518911
-0.515455
--0.0881796
-0.180471
-0.106417
-0.174742
-0.10605
-0.101716
--0.0721165
-0.0157121
-0.370027
-0.0159616
-0.343248
-0.40644
--0.122403
-0.45817
-0.112055
-0.14301
-0.0546278
-0.0665916
--0.210776
-0.0504556
-0.0533213
-0.435905
-0.40778
--0.121702
-0.20343
-0.051867
-0.295363
-0.325528
-0.543892
-0.198427
--0.0379764
-0.613045
-0.106461
--0.124167
-0.0531501
--0.184733
-0.107489
-0.440005
-0.785874
--0.0344149
-0.401876
-0.139921
-0.105019
--0.0202903
-0.0506814
--0.123017
-0.427367
-0.287292
-0.110319
-0.032632
-0.0752367
--0.0887053
--0.25589
--0.124867
-0.344423
-0.0697284
-0.300745
--0.541116
-0.339504
-0.036754
--0.129323
--0.296649
-0.203803
-0.786998
--0.0920828
-0.488956
-0.355902
-0.433699
-0.495923
--0.21902
--0.285301
--0.300008
-0.113933
-0.196377
-0.203317
--0.27133
-0.515673
--0.035536
-0.368421
--0.0378153
-0.296743
-0.419417
-0.105494
--0.188497
-0.0540082
--0.153187
-0.142242
--0.211768
-0.126614
-0.160359
--0.0987026
--0.0353126
-0.334648
-0.143104
-0.244495
--0.035786
--0.18314
--0.166527
-0.0525018
-0.13641
-0.252185
--0.179418
-0.101637
-0.194949
-0.0488777
--0.121817
-0.556582
-0.0519279
-0.576544
--0.086164
--0.148887
-0.329303
-0.182867
-0.0540505
--0.0381664
--0.0973409
--0.0141364
-0.311135
--0.118857
--0.292434
--0.0332557
-0.221214
-0.377796
-0.05935
-0.285093
-0.225396
-0.423289
--0.0960362
--0.0913693
--0.200002
-0.324347
-0.0773988
-0.0157718
-0.506239
-0.0159399
--0.403288
-0
--0.0158527
-0.255143
-0.112302
-0.253403
-0.504287
--0.136301
-0.297411
-0.44295
--0.278907
-0.0563705
-0.207233
--0.124785
--0.139635
-0.609891
--0.0396747
--0.107878
-0.0794002
-0.541556
-0.429604
-0.479236
-0.0586001
-0.192458
--0.0791675
-0.209187
-0.760872
--0.0368648
--0.136474
-0
--0.132858
-0.171948
--0.058338
-0.342493
-0.448315
-0.0552043
--0.0901184
-0.930225
-0.21125
-0.2243
-0.497741
-0.164191
-0.0559397
--0.0387857
-0.22775
-0.516499
-0.420495
-0.0703724
--0.133869
-0.543585
-0.327912
-0.264781
--0.483952
-0.410704
--0.0226768
-0.439639
-0.259281
-0.115868
-0.530224
-0.0201044
-0.220223
-0.314631
-0.638505
-0.392534
--0.190541
-0.198302
--0.290377
-0.459901
-0.21356
-0.15075
--0.18979
--0.183816
--0.238176
--0.192698
--0.116293
--0.211561
-0.0595816
-0.494948
--0.132669
--0.0376084
--0.129807
-0.256277
-0.653678
--0.195851
-0.635027
--0.253922
--0.27999
-0.143561
-0.576101
--0.279252
-0.0196624
-0.0669603
-0.164843
-0.105927
-0.0556981
--0.0877266
-0.837705
-0.27391
--0.038298
--0.354804
-0.323623
--0.0894111
-0.348897
-0
-0.0538938
-0.0169709
--0.101966
-0.148361
-0.28528
-0.328265
-0.452163
--0.119987
--0.122027
-0.195541
--0.124302
-0.0685999
-0.017956
-0.338853
-0.0490783
--0.0370051
-0.0336175
--0.123936
--0.171431
-0.105853
-0.262732
-0.10349
--0.035
-0.673923
--0.211216
--0.0362171
--0.088046
-0.0538439
--0.0341657
--0.210772
-0.132537
-0.0541573
-0.0164606
-0.104456
--0.0347779
--0.137113
-0.138892
-0.052342
--0.123135
-0.162585
--0.0682845
-0.0540738
-0.520554
-0.111932
-0.0721815
--0.179021
-0.260573
-0.266496
-0.0161852
-0.108165
--0.2594
-0.0551812
--0.304713
-0.579765
-0.195247
--0.225827
-0.355097
--0.133581
-0.587603
--0.37231
-0.3839
--0.0904944
--0.1696
--0.548164
-0.12541
-0.14269
-0.574145
-0.432187
-0.213032
-0.582752
-0.296513
-0.482115
-0.250473
-0.452123
-0.296435
--0.0369819
--0.249121
-0.262503
-0.252166
-0.395126
-0.0526244
-0.0175744
-0.500601
-0.426831
-0.195659
--0.128823
-0.363145
-0.0554331
--0.180355
-0.892138
--0.266504
-0.196898
-0.347272
-0.056965
-0.337446
-0.202538
-0.584967
-0.477058
-0.110587
-0.371269
--0.0916207
-0.434907
-0.304999
-0.562971
-0.187689
-0.147111
-0.246327
--0.288158
-0.100894
--0.0894444
-0.282104
--0.160066
--0.183918
-0.148025
-0.408325
-0.193112
--0.0366247
-0.1981
-0.190965
-0.441206
-0.187088
-0.287412
-0.625281
-0.141302
-0
--0.0354154
-0.137468
--0.0700365
--0.0903889
-0.284554
-0.165537
-0.0602982
--0.0423073
--0.131802
--0.0942072
--0.186906
-0.172335
-0.157986
--0.148111
-0.403535
-0.474166
--0.0969259
-0.143066
--0.128242
-0.116152
-0.262254
-0.0598626
--0.0348086
-0.0183929
-0.106144
-0.0606277
-0.110249
-0.117614
-0.349055
--0.204859
--0.225362
-0.05591
-0.393491
--0.242325
-0.157889
-0.0580906
-0.296064
-0.341527
-0.738388
-0.058631
-0.600386
-0.500453
-0.211293
-0.0784814
-0.364302
-0.360566
--0.188289
-0.330514
-1.23379
-0.634099
--0.0374189
-0.159232
-0.378947
--0.354947
-0.0535161
--0.0404266
--0.0182227
-0.0579207
-0.377316
--0.207318
-0.803286
--0.235557
-0.216717
--0.369982
-0.462394
-0.695031
-0.453143
-0.116087
--0.0827099
-0.567789
-0.116094
-0.121694
-0.316567
--0.270069
-0.210897
-0.48014
-0.217
-0.502355
-0.0603247
-0.642555
--0.0396927
-0.496428
--0.133228
-0.222619
--0.0402458
-0.213904
-0.4113
-0.526526
--0.27035
--0.0999262
--0.124616
-0.769351
-0.159667
-0.0587752
-0.31491
-0.277868
-0.172461
-0.218137
-0.429196
--0.146279
--0.193349
-0.178033
-0.435579
-0.17494
-0.207988
-0.318248
-0.401981
-0.225187
-0.706225
--0.141862
-0.220985
--0.0785727
-0.0173222
--0.0950464
-0.110188
-0.444175
-0.206185
-0.0207031
--0.0931084
-0.530647
-0.148847
--0.185344
-0.282433
--0.190315
-0.0718733
-0.216581
-0.142529
-0.363191
--0.182711
-0.169555
-0.0540227
-0.0556728
-0.249495
--0.0438014
--0.217503
-0.205434
--0.117466
-0.10392
-0.548021
-0.273837
-0.0478645
--0.0361502
-0.370724
--0.423082
-0.199387
-0.316613
--0.122836
-0.185248
-0.142355
-0.457999
-0.282152
-0.11981
-0.338792
--0.0350201
-0.460111
-0.0158562
-0.105758
-0.426299
-0.0173786
-0.0185251
-0.0514334
-0.0523415
--0.17817
--0.123158
--0.0706691
--0.0899629
--0.369317
-0.293587
-0
-0.0522928
--0.126673
--0.306673
--0.127667
-0.0163709
--0.0943606
-0
-0.280825
-0.265945
-0.161766
-0.248092
-0.348014
-0.138082
-0.34491
--0.0372164
-0.351651
-0.123892
-0.160193
--0.0363782
-0.262372
-0.0164087
-0.437654
-0.374926
-0.459564
--0.0363581
-0.108276
-0.532004
-0.141881
-0.104214
-0.162546
-0.460132
-0.316107
--0.0199269
-0.469473
-0.10745
-0.203572
--0.0723767
--0.185052
-0.565313
-0.124919
-0.159506
--0.0363495
--0.0206704
-0.173631
-0.569374
-0.25424
-0.309248
-0.442591
-0.201575
-0.726868
-0.343415
-0.10819
-0.273119
-0.486368
-0.149757
-0.199254
-0.0163113
-0.30889
-0.27912
-0.113393
-0.487021
-0.335707
-0.108802
-0.254045
-0
-0.103767
-0.158215
-0
-0.0160005
-0.0176628
--0.0369375
-0.341574
-0.2519
-0.2468
--0.12659
--0.0372768
--0.180917
-0.278476
-0.109872
--0.0927019
-0.138012
--0.0866848
-0.243359
-0.211814
-0.343892
--0.178698
-0.0520324
-0.252878
--0.0350785
-0.137296
-0.0707119
--0.350232
-0.313196
-0.621824
-0.155439
-0.129094
--0.0946304
--0.258581
-0.0543181
--0.177049
--0.394224
-0.019519
-0.303122
--0.21229
-0.111494
-0.204747
-0.198417
-0.24845
--0.316897
-0.19663
-0.35228
-0.355582
--0.29318
-0.200474
--0.0391501
--0.0887995
--0.300251
-0.486177
-0.514407
-0.293555
-0.0174106
-0.217923
--0.135489
-0.133162
-0.323604
-0.110531
-0.212165
-0.628938
--0.135211
-0.507636
--0.279485
-0.0544007
-0.0569613
-0.117713
-0.359064
-0.0736012
--0.237339
-0.448251
--0.280603
--0.190347
-0.474436
-0.423412
--0.114859
-0.0164661
-0
-0.129351
-0.366416
--0.128994
-0.51078
-0.109359
--0.0927577
--0.0379543
-0.115987
-0.0535351
-0.306587
-0.315648
-0.323828
-0.270624
-0.421609
-0.0168965
-0.594967
-0.146297
-0.296649
-0.448688
--0.0390151
-0.0170628
-0.2695
-0.152327
--0.131662
-0.316298
-0.149822
-0.430174
-0.54356
-0.311908
--0.0387284
--0.0376821
-0.511803
-0.494126
--0.212599
-0.336289
-0.450133
-0.0748019
--0.0409783
-0.556922
-0.280829
-0.288618
-0.155606
-0.844979
-0.112253
-0.164989
--0.0181484
--0.276028
-0.104932
-0.705055
-0.571232
-0.268341
-0.45558
--0.0808817
--0.128093
-0.3379
--0.181476
-0.327584
--0.0927075
-0.381704
--0.32676
-0.158148
-0.113328
-0.0515387
--0.131443
--0.0367137
-0.256111
-0
--0.0375829
-0.0538132
-0.396414
--0.300362
-0.104386
-0.246585
-0.0544719
--0.351607
--0.102152
-0.327175
-0.109655
-0
-0.0547457
-0.241908
-0.253321
-0.0528974
--0.137122
-0.0555304
-0.219618
-0.299649
-0.249369
-0.299235
-0.151071
--0.0367277
--0.0318718
-0.274406
-0.346793
--0.131437
-0.170051
--0.0379173
-0.0549232
-0.552146
--0.0382232
-0.505546
-0.0683358
-0.40988
-0.107355
-0.214771
-0.016924
--0.124841
-0.39878
--0.0960423
--0.0376103
-0.221797
-0.465521
--0.274691
--0.0907145
-0.592927
-0.441617
-0.222936
-0.297868
--0.13685
-1.17523
-0.21856
--0.039132
-0.273155
-0
-0.474026
-0.350805
--0.0380796
-0.252088
-0.429689
-0.512158
-0.169969
-0.149299
-0.0570778
-0.788563
-0.021104
-0.390046
-0.322581
-0.322903
-0.377084
-0.201473
--0.320312
-0.206878
--0.076922
-0.349623
-0.432086
-0.607611
-0.373493
-0.0174477
-0.403278
-0.54212
-0.111974
-0.215206
-0.312451
-0.167766
--0.191112
--0.00412692
-0.469894
-0.367995
-0.0727109
-0.112686
-0.230441
-0.110997
-1.16375
-0.469643
-0.116242
-0.0166108
-0.274356
-0.673267
-0.268934
-0.198398
-0.210028
-0.0535607
-0.219202
--0.324527
-0.0550155
-0.660292
-0.434729
-0.364814
-0.0177219
--0.318281
-0.216029
-0.0732208
-0.146166
-0.147401
-0
-0.153079
--0.222436
-0.328582
-0.450768
-0.164578
-0.595575
--0.0914141
-0.0529384
-0.57108
-0.149962
-0.25364
--0.0368943
-0.194659
--0.0337468
-0.0158363
-0.0172053
-0.417686
-0.463566
-0.317508
--0.0755447
-0
-0.288155
--0.0941291
-0.327683
--0.126418
-0.181044
-0.208021
-0.0510681
-0.442023
-0.216029
--0.0719817
--0.176029
-0.106148
--0.0869457
-0.0748618
-0.104145
-0.193561
-0.275485
-0.0540977
--0.0341106
--0.0767283
--0.0379864
--0.28283
--0.162109
--0.0726297
-0.108975
-0.588924
--0.171964
-0.108933
--0.266533
--0.293469
-0.443011
-0.305209
-0.163592
-0.568358
-0.107863
--0.184401
--0.129219
--0.229948
-0.206627
-0.461984
-0.158319
--0.038738
--0.210929
-0.249526
-0.0164173
--0.0377576
-0.111522
-0.270377
--0.114194
-0.290789
-0.392817
-0.146723
-0.0166901
-0.217243
-0.745994
-0.0168681
-0.5125
--0.276203
--0.169089
-0.309573
-0.362677
-0.216461
-0.493868
-0.422732
-0.492655
-0.5316
-0.108033
--0.0399419
-0.0168923
-0.572359
-0.255121
-0.0161941
-0.368217
-0.0963271
-0.567239
-0.106509
--0.453717
-0.764887
-0.54723
--0.0592484
-0.490837
--0.220863
-0.0165907
-0.0537883
-0.149108
-0.111195
-0.106235
--0.226059
--0.0895776
-0.11082
-0.0547909
-0.306758
-0.225846
--0.036125
-0.0533637
-0.253761
-0.0572912
--0.213141
-0.0530596
-0.473271
-0.164477
-0.0168054
-0.164854
-0.107036
--0.181448
-0.14622
--0.118019
--0.168473
--0.266969
-0.0505609
-0.268148
--0.0381742
-0.326823
-0.267353
--0.164835
--0.129984
--0.240502
-0.0167039
-0.205716
-0.0169188
--0.0706081
-0.430336
-0
-0.197794
--0.127122
--0.189236
-0.210156
-0.105129
-0.137199
--0.0365028
-0.187602
-0.335412
-0.266794
-0.490568
-0.336275
-0.24224
--0.218915
-0.188991
-0.109157
-0.318986
-0.0551934
--0.235541
-0.0531492
-0.188432
--0.0381011
--0.168904
-0.054033
--0.261399
-0.143531
--0.261649
--0.0757166
-0.0158813
--0.0370626
-0.414258
--0.0389924
-0.105541
-0.0159641
-0.255459
-0.334816
-0.18951
-0.266594
-0.0159205
--0.130062
-0.210834
--0.0208364
-0.302022
--0.231411
-0.191806
-0.434806
-0.253724
--0.0764838
-0.19742
-0.208651
-0.155558
--0.0368954
-0.295782
-0.75451
-0.105884
--0.171636
-0.444278
-0.351914
-0.257454
-0.313153
--0.0736582
-0.396384
-0.40363
--0.0177975
-0.610979
-0.254188
-0.341056
-1.05123
-0.361386
-0.345636
--0.073454
-0.294845
-0.224533
-0.52335
-0.221628
-0.259465
-0.0172506
-0.0169271
-0.0718081
--0.0730481
--0.227626
-0.263034
-0.201678
-0.475768
-0.219895
-0.106109
-0.581761
--0.128273
-0.0162467
-0.628968
-0.391705
--0.0376356
-0.733408
-0.208638
--0.0723631
-0.112863
-0.43187
--0.274281
-0.256437
--0.226153
-0.495582
-0.0564737
-0.0161572
-0.480908
-0.47658
-0.156937
-0.102565
--0.0756788
-0.0997087
--0.0201306
-0.253868
--0.0895093
-0.197618
-0.350011
-0.136789
-0.327888
-0.253697
-0.427903
-0.104968
-0.167229
-0.439297
-0.190157
-0.190686
-0.0529485
-0.0539882
--0.0353278
-0.560654
-0.155093
-0.216485
-0.330202
--0.0912366
--0.284315
-0.115838
-0.0714394
-0.0550378
-0.36044
-0.20319
--0.128511
-0.318368
-0.715323
--0.0384357
-0.205325
-0.0785906
--0.375646
--0.0956434
-0.335845
-0.272019
-0.412068
--0.0950402
-0.323135
--0.172652
-0.474622
--0.294005
-0.0532068
--0.290839
-0.110852
-0.0560293
-0.107621
--0.040529
-0.356484
-0.0564506
-0.109616
--0.0149624
-0.41635
--0.390172
-0.422832
--0.039241
-0.16168
-0.261075
-0.359145
-0.305438
-0.152071
-0.114069
--0.0398213
-0.418088
-0.260885
-0.115946
-0.26874
--0.0401997
-0
-0.0723524
-0.345959
-0.227825
-0.110157
--0.0758702
-0.112923
-0.350511
-0.567751
-0.114633
--0.110204
-0.213507
-0.319938
-0.0727306
-0.211482
--0.134751
-0.30486
-0.11336
-0.64273
-0.519186
-0.206523
-0.0369045
-0.406546
-0.167452
-0.109712
-0.937758
--0.115128
-0.16962
--0.136576
-0.800367
-0.581934
--0.0179781
-0.327656
-0.0181369
-0.384021
--0.0394496
-0.852055
-0.113296
-0.44879
-0.166222
-0.678666
-0.515817
--0.0771598
--0.0738447
-0.17235
-0.267213
--0.17826
--0.128736
--0.0741986
-0.0168043
-0.365817
-0.109185
-0.159938
--0.0378216
-0.0173257
--0.184156
-0.058355
--0.276984
-0.440916
--0.0964816
-0.488678
-0.165817
-0.165659
-0.0169665
-0.276279
-0.447584
-0.932532
--0.177532
-0.0513031
-0.11173
-0.0155484
-0.110563
-0.103818
--0.0355995
--0.352492
--0.309551
--0.0350979
-0.161516
--0.0353332
--0.038649
-0.112194
-0.399116
-0.142652
--0.342934
--0.0714302
--0.24259
-0.102123
-0.282677
--0.0165637
-0.184101
-0.457605
--0.251642
-0.207348
--0.0337842
--0.182627
-0.05166
--0.133064
--0.496334
-0.0561985
-0
--0.127831
-0.102715
--0.0369497
--0.0356686
--0.278058
-0.240204
--0.219494
--0.21599
-0.20385
--0.289753
-0.105613
-0.158524
-0.453164
--0.0366545
--0.305742
-0.0519328
--0.039001
-0.196229
--0.216851
-0.433415
--0.0386134
-0.578502
--0.0179979
-0.199077
-0.16181
--0.0726192
-0.0173286
-0.329224
--0.039678
--0.305716
--0.274407
--0.0757474
-0.0413568
--0.037782
--0.128095
-0.167917
-0.108954
-0.784854
--0.466459
-0.826175
--0.132041
-0.693731
-0.304846
-0.676141
--0.0807851
-0.756637
-0.255993
-0.29477
-0.352542
-0.315255
-0.68962
-0.126154
-0.056675
--0.0758283
-0.305181
-0.497599
-0.483692
-0.325486
--0.0180783
-0.0175265
-0.422951
-0.0697705
-0.559752
-0.261821
-0.17095
-0.340782
-0.398337
--0.461983
-0.295391
-0.507892
-0.463186
-0.579743
-0.113164
-0.402295
-0.233883
-0.206334
-0.148264
-0.504606
--0.174316
-0.0165739
-0.743523
--0.0922731
--0.13411
--0.0366105
-0.512774
-0.154358
-0.0162493
-0.290205
-0.337786
-0.163796
-0.106475
-0
-0.139204
-0.10703
--0.125097
--0.26074
-0.309843
-0.183914
-0.414027
-0.0159423
-0.158124
--0.30026
-0.0559383
-0.480122
--0.129451
--0.126859
-0.272151
-0.331056
-0.0163363
-0.595811
--0.0358182
--0.130505
-0.656576
-0.347041
-0.0146983
-0.0582489
-0.516348
-0.0552399
-0.141983
-0.054491
--0.177585
-0.147727
--0.121495
-0.146135
--0.0348044
-0.574851
--0.0710891
-0.405389
-0.329924
-0
-0.831251
-0.113846
-0.0162938
-0.0155867
-0.196699
--0.0924902
--0.130818
-0.353837
--0.0885137
--0.0136075
--0.573489
--0.314507
-0.519784
--0.0957552
-0.0174799
-0.197042
-0.148623
-0.0164846
--0.278035
-0.680582
--0.128942
-0.0560159
-0.2476
--0.191335
-0.273951
-0
-0.160162
-0.592134
-0.254097
-0.0178185
-0.407281
-0.430253
--0.037313
--0.221608
-0.317661
--0.425242
-0.300526
-0.525682
-1.16119
--0.274686
-0.712261
-0.82072
--0.207848
-0.277029
--0.255691
-0.4846
--0.163786
-0.327405
-0.129442
-0.794771
-0.441078
--0.0728744
-0.26048
-0.200574
--0.142197
-0.623576
-0.0734523
--0.128777
-0.399804
-0.966252
-0.015978
-0.347493
-0.467757
--0.418221
-0.0530961
--0.312533
-0.509822
-0.753445
--0.0737762
-0.0196093
-0.0171228
--0.0939636
-0.16805
--0.131159
--0.256071
-0.205434
-0.106774
--0.221179
--0.248074
--0.368032
-0.374135
-0.492873
--0.0406867
-0.317127
--0.0369552
--0.133283
-0.572204
-0
--0.134539
--0.172787
-0.247031
-0.107143
-0.205808
--0.189527
--0.172994
-0.275138
--0.300512
-0.443475
-0.101196
-0.0194508
--0.125584
-0.161068
--0.123901
--0.0888759
-0.329244
--0.0399461
-0.49319
-0.016385
-0.0507074
--0.17583
-0.140805
-0.140335
-0.195741
-0.291162
-0.313173
-0.444426
-0.417738
-0.0159267
--0.13077
-0.10743
-0.149667
-0.106473
-0.375194
-0.603418
-0.0589428
-0.0522227
-0.160836
--0.124565
--0.037047
-0.0728679
--0.194571
--0.0358923
-0.0174218
-0.140777
-0.655508
-0.109471
-0.167602
-0.103543
--0.345443
-0.10536
--0.189698
-0.142343
--0.0957921
-0.907812
--0.130348
--0.038027
-0.1364
-0.762284
--0.132558
-0.252249
--0.28171
--0.375808
-0.171459
--0.131062
-0.567987
-0.0374431
--0.0389061
--0.190413
-0.348463
--0.0762996
--0.0921553
-0.643955
-0.0171654
-0.633599
-0.0940659
-0.266729
-0.363956
--0.0371637
-0.304774
-0.16407
--0.138088
--0.0377922
-0.405441
-0.124151
-0.484779
-0.645576
-0.667648
-0.462403
-0.497641
-0.999376
--0.0214681
--0.0733599
--0.079279
-0.810544
-0.172627
-0.163718
-0.662024
-0.131225
--0.074237
-0.44298
--0.0175
--0.125334
-0.1749
-0.154994
-0.313502
-0.60558
-0.375427
--0.225421
-0.480333
-0.249831
-0.0179023
-0.416693
--0.133223
-0.464068
--0.133276
--0.0376191
--0.173301
--0.461409
--0.0793724
--0.298972
--0.292207
-0.0685852
-0.106161
-0
-0.0690256
-0.795998
--0.0757222
-0.0527718
-0.107024
-0.0517994
-0.441795
-0.333433
-0
-0.247234
--0.181146
--0.0364692
-0.334622
-0.10557
-0.164244
--0.122187
-0.335087
-0.161519
-0.106211
--0.0684747
--0.0688395
-0.0551842
-0.143282
--0.0881496
-0.0500768
--0.18046
-0.147989
-0.171135
-0.0156054
-0.111109
-0.425978
-0.110184
--0.0370303
-0.59393
-0.153407
-0.348113
-0.0491843
-0.15826
-0.258038
-0.0578393
-0.323825
-0.124687
-0.14859
-0.209236
--0.209762
-0.47963
-0.838277
-0.0174807
-0.254429
-0.0548392
-0.104711
-0.562083
-0.0544304
--0.379114
--0.035693
--0.0367285
-0.140215
-0.575489
-0.069616
-0.145054
-0.217333
-0.502895
-0.368673
-0.455972
-0.0161462
-0.0172955
-0.322242
-0.525773
--0.0369323
-0.256489
-0.535545
-0.371763
-0.654072
--0.0726806
--0.0732634
-0.36172
-0.672632
--0.0360042
-0.162192
-0.667893
-0.744816
-0.284226
-0.356709
-0.16015
-0.592356
-0.536709
-0.219779
-0.792396
-0.163018
-0.587362
-0.0548757
-0.918634
-0.328472
-0.542448
-0.793621
-0.913187
-0.265418
-0.364164
-0.408705
-0.311356
-0.635834
-0.413886
-0.102783
-0.569808
--0.0194673
--0.166985
--0.226995
-0.156317
-0.239759
-0.400145
--0.0740261
-0.479205
-0.111214
-0.0200979
--0.16622
-0.685897
-0.218594
-0.115903
-0.106929
-0.284484
--0.181024
-0.211219
-0.111361
-0.331083
-0.172073
-0.271164
-0.143786
-0.10922
--0.0350982
-0.821172
-0.152608
--0.0370968
-0.374764
-0.3979
--0.20983
-0.496469
-0.314209
-0.346263
-0.389157
-0.438326
--0.0911847
--0.0867515
-0.187361
-0.349984
-0.377017
--0.109524
-0.0510705
--0.0373321
-0.551338
-0.0200673
-0
--0.243128
-0.0669838
-0.273346
-0.186177
--0.0727264
--0.0910395
-0.375301
-0.705117
-0.189519
--0.281976
--0.178789
-0.0530751
-0.342746
-0.0170046
-0.27501
--0.128985
-0.432122
-0.0520807
-0.188644
-0.0516958
-0.4794
-0.0537357
--0.0849819
-0.452497
-0.423126
-0.0550787
-0.633211
-0.074138
-0.0364868
--0.388728
--0.297119
-0.351825
-0.352951
-0.055053
-0.120425
--0.377324
-0.0164167
--0.0778374
-0.143665
-0.339852
-0.262204
-0.370943
--0.160989
-0.0720883
-0.549988
-0.478183
--0.166519
-0.415183
-0.106192
-0.312669
-0.16271
-0.353169
--0.0747187
-0.868616
-0.0165197
--0.113515
-0.51145
-0.451144
-0.400097
--0.221568
--0.170252
-0.163903
-0.351644
-0.942318
-0.319607
-0.179122
-0.431525
-0.681972
-0.698138
-1.27746
-0.459172
-0.181988
-0.34967
-0.640871
-0.0707551
--0.227523
-0.253545
-0.270101
--0.2155
-0.492752
-0.0166534
-0.866132
-0.354426
-0.11279
-0.391682
-0.444977
-0.601926
-0.314558
-0.336415
-0.0176526
-0.109325
-0.27063
--0.144634
-0.461417
-0.158198
--0.0217249
-0.363244
-0.36733
--0.0890568
-0.261981
-0.200369
-0.877859
-0.323535
-0.105773
-0.198256
--0.36863
-0.053115
-0.106343
-0.0535468
-0.214226
-0.069467
-0.110968
-0.191284
-0.0535399
--0.124819
--0.0356283
--0.178926
-0.246247
-0
-0
--0.0711244
-0.215545
-0.13898
-0.286431
--0.0996695
-0.318976
--0.0850575
-0.185455
--0.0743261
-0.0496223
--0.089341
-0.262523
-0.10829
--0.205139
-0.403985
--0.120815
-0.457355
-0.0154929
--0.0377891
-0.10255
--0.0369251
-0.0988395
-0.105738
-0.298767
-0.539882
--0.0703899
--0.12651
--0.336422
--0.305174
--0.0367608
-0.103733
-0.160473
-0.157211
--0.0359729
-0.245207
--0.367933
-0.101844
--0.0380081
-0.107227
-0.338122
-0.146893
--0.155104
-0.356655
-0.376777
-0.0169085
-0.341481
-0.293531
-0.371505
-0.279273
-0.615002
--0.0210188
-0.249094
-0.260796
-0.253704
-0.0542488
-0.123324
-0.43099
-0.39435
-0.403308
-0.592776
-0.424279
-0.538451
-0.386337
-0.0160301
-0.396441
-0.30676
-0.211748
-0.248015
-0.445212
-0.108196
-0.485459
-1.30459
-0.188343
-0.156377
-0.38915
-0.0702389
--0.206938
-0.694189
-0.338722
-0.504619
-0.312386
-0.0154745
-0.121264
-0.165519
-0.157622
-0.473877
-0.744084
-0.119327
-0.43739
-0.0350262
-0.301299
-0.0162211
--0.211698
-0.131021
--0.0370645
-0.195643
-0.287594
--0.185009
-0.475852
-0.474604
--0.131737
-0.068905
-0.280302
-0.505942
-0.337936
-0.745928
-0.160553
--0.215727
-0
--0.0380032
-0.10246
--0.260394
-0.159147
-0.240866
-0.140802
-0.330651
-0.242185
-0.408735
-0.103079
--0.0363136
-0.0162922
-0.153831
--0.119813
-0.270225
-0.104283
--0.253108
--0.0339722
--0.0687386
-0.140813
-0.151396
-0.191852
--0.173359
--0.318113
-0
--0.0359715
-0
-0.0567871
-0.0164643
-0.110623
--0.0896557
-0.608577
-0.0527605
--0.0875354
--0.0979222
-0.573462
--0.0946313
-0.203028
--0.183706
-0.43266
-0.302421
--0.0366485
-0.204216
-0.312659
--0.0383837
--0.0363509
-0.309092
-0.0205106
--0.0999076
-0.211665
--0.27801
-0.159856
--0.0380694
--0.0365176
--0.194074
--0.0382597
--0.0982245
-0.371052
--0.0931109
-0.25881
--0.131573
-0.597603
-0.51553
-0.539543
--0.0393409
-0.0165257
-0.221491
-0.25195
-0.650533
-0.569781
--0.0214541
-0.461337
--0.332512
-0.588264
-0.0171629
-0.168607
-0.673238
--0.360711
-0.0552188
-0.0565664
-0.769066
-0.267319
-1.39241
-0.864534
-0.410454
-0.997354
-0.813901
-0.658527
-0.370388
-0.810603
-0.606739
-0.301845
-0.244731
-0.978323
-0.474153
-0.299327
-0.791432
-0.0515768
-0.239032
-0.910149
-0.63927
--0.0192792
-0.653678
-0.163305
-0.466741
-0.557453
-0.555943
-0.385286
-0.58883
-0.198367
--0.458804
--0.0212766
-0.663828
-0.467406
--0.373174
-0.10464
-0.534859
-0.0542862
-0.323403
-0.602598
-0.113654
-0.203986
-0.653573
-0.19386
--0.0952916
-0.161945
-0.204975
-0.250781
-0.377064
--0.0362054
--0.0383102
-0.29378
-0.145755
-0.155623
-0.349666
-0.301392
-0.0528066
--0.0141116
-0.107826
-0.242803
-0.157339
-0.247871
--0.316107
--0.0884554
-0.0354287
-0.534126
-0.341468
-0.155791
-0.291162
-0.104551
--0.0355439
--0.115629
--0.218135
-0.199131
-0.404537
-0.150004
-0.684468
-0.155881
-0.0505584
-0.159183
-0.102036
-0
-0.148501
-0.0554765
-0.105594
--0.217635
--0.035887
-0.300794
-0.912864
-0.0203686
-0.0536966
-0.414564
--0.0343759
-0.261884
-0.629906
--0.300622
--0.0180262
-0.21069
--0.308788
--0.0775217
--0.0211694
--0.0391509
-0.705271
-0.0189118
-0.315216
-0.0539134
--0.182595
-0.0561427
-0.394564
-0.316526
-0.108995
-0.207212
-0.409828
-0.254905
--0.391933
-0.361176
-0.689313
-0.912706
-0.222118
--0.260591
-0.168019
-0.169934
--0.171824
-0.326001
-0.116293
-0.438859
-0.109899
-0.683583
-0.278634
-0.920944
-0.573461
-0.752126
-0.322658
-0.708152
-0.926662
-0.996067
-0.44693
-0.482368
-0.268236
--0.0204456
--0.0597385
-0.224146
-0.629871
-1.43636
-0.23848
-0.771852
-0.536332
-0.458644
-0.772711
-0.383175
-0.841201
-0.761115
-0.684945
-0.0171509
-0.877364
-0.503586
-0.814853
-0.351256
-1.3224
-0.168457
-0.161379
-0.1656
--0.0400469
--0.212939
--0.0386428
-0.138704
-0.0698219
-0.432842
-0.348473
--0.0930007
-0.310925
-0.249712
-0.0698443
-0.0159562
--0.0373977
-0.105124
-0.076213
-0.195903
--0.272597
-0.482062
-0.277097
-0.300957
-0.506125
-0.257072
-0.192727
-0.152609
-0.0337052
-0.143491
--0.250073
--0.131019
--0.198561
-0.0546102
-0.241244
--0.359261
-0.137353
-0.143291
--0.0696078
-0.28417
-0.0164759
-0.103139
-0.186587
-0.233329
-0.052543
--0.337736
--0.195203
-0.1014
-0.137367
--0.35529
-0.0164883
-0.064896
-0.223053
-0.289568
-0.016352
--0.0346867
-0.0672595
--0.167557
-0.0541352
--0.0344988
--0.0174589
--0.172316
-0.736979
--0.0714336
-0.670099
-0.289738
--0.125028
-0.234535
-0.521743
--0.124095
--0.304252
--0.0332428
-0.111163
-0.0160376
--0.10715
--0.174139
-0.420578
-0.535468
--0.128695
-0.251689
-0.312101
--0.292962
--0.0375473
-0.205111
-0.804381
-0.109475
--0.0735022
-0.475561
--0.0729178
-0.496378
-0.0171762
--0.319513
-0.191652
-0.0167815
-0.528254
-0.347364
-0.299607
--0.127987
-0.970458
-0.8443
-0.714397
--0.261143
-0.197305
-0.958901
-0.412588
-0.486887
-0.179805
-1.21239
-0.383764
--0.0734698
-1.78424
-0.795393
-0.695444
-0.746156
-0.78741
-0.117528
-0.525321
-0.252868
--0.198195
-0.0164744
-0.439556
-1.07119
-0.464247
--0.0730497
-0.410269
-0.866421
-0.778
-0.188698
-0.610054
-0.0160903
-0.309569
-0.725682
-0.313786
-0.299753
-0.0733935
--0.27363
-0.502079
--0.165347
-0.0180672
-0.272602
-0.419104
-0.821334
-0.20204
-0.2361
--0.292441
-0
--0.0389024
-0.188742
-0.0193139
-0.252596
-0.0158909
-0.298804
-0.343329
--0.331125
--0.280694
--0.0355076
-0.434124
-0.382784
--0.298597
-0.241812
-0.244592
-0.0715412
--0.0699577
--0.0167003
--0.0884289
--0.118914
-0.194519
-0.391525
-0.0161644
-0.182806
-0.248051
-0.166669
-0.137774
-0.0197959
-0.136607
-0.0548305
-0.04763
-0.054809
-0.0973925
-0.287283
-0.561087
-0.248543
-0.192425
-0.200265
-0.192974
-0.196491
-0.0185767
-0.246586
-0.190753
-0.743637
--0.152741
-0.146533
-0.241092
-0.257685
-1.0154
-0.202812
--0.0374763
-0.113321
--0.0358937
-0.360521
--0.231542
-0.610523
--0.159922
-0.05357
-0.437939
-0.190617
-0.295652
--0.292161
-0.199497
-0.155782
-0.162402
-0.632009
-0.955309
-0.936773
--0.167267
-0.585261
-0.335742
-0.716233
-0.0164748
-0.224543
-0.342149
-0.740985
-0.494482
-0.68653
-0.845608
-0.71344
--0.358091
-0.560903
-0.623833
-1.33914
-0.837987
-0.344934
-0.586634
--0.109785
-0.679254
-1.70349
-0.298864
-1.16978
-0.771991
-0.238253
-0.806033
-0.935477
-0.426569
-1.53535
--0.256283
-0.228083
--0.237276
-1.09009
-1.20012
-0.452838
-0.201194
-0.073789
--0.22041
-0.112118
-0.485164
-0.303943
-0.479787
-0.20212
-0.0716366
-0.214742
--0.0184039
-0.322378
--0.0372866
--0.461551
-0.454395
-0.490212
-0.336166
--0.0381402
-0.749882
-0.196212
--0.195178
-0.266607
-0.28707
-0.0167049
-0.0542153
-0.0169254
--0.210361
-0.107896
-0.0509749
-0.426137
--0.0365646
-0.321709
-0.494744
-0.355921
--0.181307
-1.03695
-0.159459
--0.0394663
-0.387953
-0.144362
-0.321846
--0.0904864
--0.0708579
--0.0752524
-0.486841
-0.144315
-0.0500816
-0.107823
--0.0371128
--0.0856424
--0.213112
--0.239474
--0.176684
-0.470549
-0.153181
-0.0520545
-0.234019
-0.0159763
-0.437614
-0.0160234
-0.0523762
-0.136448
-0.193901
--0.15656
--0.221945
-0.0187074
-0.0712266
--0.0845508
--0.0166885
-0.190262
-0.287456
-0.422916
-0.107186
-0.0164345
-0.156191
-0.418182
--0.349421
--0.0362656
-0.444436
-0.543131
-0.132897
-0.479254
-0
-0.19368
-0.248528
-0.587908
-0.345286
--0.0735002
--0.0913895
-0.341692
--0.108589
--0.0777344
-0.159127
--0.0705667
-0.509506
-0.466416
-0.395339
-0.691202
-0.318398
--0.258729
-0.214352
-0.437801
-0.301772
-0.738542
-0.22766
-0.817643
-0.0346511
-0.68736
-0.69593
-1.20645
-0.585005
-0.92295
-0.400387
-0.828676
-1.28868
-0.711269
-0.538916
-1.00199
-1.19056
-0.178317
-1.44565
--0.0758515
-1.01925
-0.713988
-0.748319
-0.91312
-0.611536
-1.02441
-0.527315
-0.512324
--0.0774135
-0.35706
-1.42604
--0.224059
-0.417117
-0.235729
--0.0734336
-0.0163572
-0.360913
--0.128854
-0.252292
--0.155115
--0.267068
-0.122452
--0.279238
-0.458746
-0.653363
--0.313507
--0.248536
--0.325858
-0.0522338
-0.137089
-0.890006
-0.678801
--0.449564
--0.072457
-0.378326
-0.26352
-0.0367717
--0.290096
--0.310827
-0.135658
-0.0550145
-0.108417
-0.190114
--0.274585
-0.159342
--0.263146
-0.104694
--0.207318
-0.251416
--0.38676
-0.147774
-0.247361
-0.051992
--0.149257
--0.0713663
--0.0707745
--0.215856
-0.436392
-0.19487
--0.0955919
-0
--0.399013
-0.147047
--0.0382796
--0.282017
-0.323122
-0.349298
-0.143511
-0.256076
-0.0204495
-0.0168002
-0.195612
--0.186549
--0.111803
-0.053084
-0.4477
-0.423278
--0.0752732
-0.0567097
-0.0691426
-0.107536
-0.392887
-0.440863
-0.204492
-0.265789
-0.257286
-0.264858
-0.590688
-0.108561
-0.658665
-0.630317
-0.486284
-0.0744818
-0.106603
-0.73414
-0.439005
-0.108961
-0.6135
-0.780378
-0.436856
-0.161733
-0.581705
-0.0720833
-0.28778
-0.650261
-0.921531
-0.261468
--0.250556
-0.514125
-0.0719796
-0.33993
-0.919586
-0.841707
-1.00334
-1.05107
-0.147302
-0.434709
-0.96758
-1.67096
-0.816085
-1.62077
-1.42906
-0.766161
-0.542393
-1.69961
-1.23738
-1.31555
-0.794614
-1.13572
-0.323882
-0.630563
-0.327741
-1.11767
-0.751851
--0.0588644
-0.676898
--0.218491
-0.375764
--0.158281
--0.0177105
-0.0688571
-0.175324
-0.331873
--0.0171891
-0.342458
-0.320216
--0.209473
-0.778024
-0.343668
-0.615373
-0.434169
-0.504399
-0.159622
-0.0515083
-0.119142
--0.149798
-0.644656
-0.0530735
--0.204125
-0.716661
--0.210138
-0.549738
-0.195854
-0.05296
--0.0368834
-0.311329
-0.133436
-0.403715
-0.0689439
-0
-0.360425
-0.529479
-0.0153288
-0.28797
--0.0688025
-0.0516501
-1.00234
-0.237664
--0.0873425
-0.0716673
-0.439158
--0.0479545
--0.0686045
-0.233469
-0.249358
-0.0193939
-0.380242
--0.255473
-0.573789
-0.0160985
-0.280389
--0.0344939
-0.362169
--0.124821
-0.0726998
-0.197065
-0.248481
-0.581124
--0.366619
-0.103221
-0.0725578
--0.0209116
-0.420435
--0.107013
--0.129732
-0.437472
--0.272525
-0.244415
-0.483187
-0.245734
-0.427771
-0.144302
-0.104104
-0.473023
-0.454178
--0.0354466
-0.350338
--0.346202
-0.0540296
-0.328523
--0.512628
--0.0783184
-0.108923
-0.211282
--0.224996
-0.157268
-0.245457
-0.395259
-0.146668
-0.0697502
-0.0732319
-0.201815
-0.225253
-0.832578
--0.375149
-0.481915
-0.723873
-0.768839
--0.0215119
-0.504363
-0.575137
-1.14914
-0.692365
-0.89677
-0.319204
-1.07189
-1.80417
-2.00869
-1.12891
-1.76202
-1.91736
-0.51812
--0.00377991
-0.832443
-1.75551
-0.592761
-1.3466
-1.64568
-0.655777
-0.370867
-1.24723
-0.475583
-0.433065
-1.02819
-0.707168
-0.443098
-0.671971
-0.563347
--0.0209257
-0.571232
--0.0182386
-0.0522732
--0.0551044
-0.0162314
-0.301755
-0.198604
--0.343371
-0.5576
--0.0182361
--0.0523935
-0.0170843
--0.578005
--0.370968
-0.466044
-0.687572
-0.104572
-0.985488
-0.194447
--0.215071
--0.204391
--0.212695
--0.221489
--0.276059
--0.206058
-0.764475
-0.141105
-0.0535798
--0.294201
--0.210091
-0.326047
-0.0712356
-0.245309
--0.036576
--0.0200565
--0.0205328
-0.0528807
--0.239893
-0
-0.18857
-0.340284
-0.101182
-0.0352298
-0.395016
-0.192185
--0.246922
-0.155077
--0.0672027
-0.138707
--0.285095
--0.308983
-0.162229
-0.133414
--0.257473
--0.219743
--0.124933
-0.206336
-0.0686087
-0.191677
-0.0741866
--0.200762
-0.0529017
--0.259635
-0.0161035
--0.0362696
-0.052618
-0.476239
-0.159747
--0.0176945
-0.275135
-0.0560958
-0.562875
-0.107602
-0.110538
--0.168691
-0.532541
-0.524271
-0.246837
-0.245025
-0.258822
-0.568726
--0.389358
-0.389981
-0.198932
-0.590255
--0.2233
-0.345939
--0.263431
-1.18258
--0.196745
-0.431962
-0.0923161
-0.505192
-0.993606
-0.319186
-1.12665
-0.374041
-1.51778
-1.13029
-0.43049
-1.03932
-0.228569
-1.29422
-1.7205
-1.4016
-0.892084
-1.16249
-0.144582
-1.56062
-0.645087
-1.66018
-1.63157
-0.987586
-1.64135
-1.07331
-1.71856
-1.73854
-0.63303
-1.21562
-0.343441
-1.04487
-1.60717
-1.19335
-1.05585
-0.470479
-0.391208
-0.455327
-0.640731
-0.554583
-0.409316
-0.413097
-0.653899
-0.215239
-0.572657
-0.188856
-0.254874
-0.708941
-0.446573
-0.596336
-0.207178
-0.0333924
-0.349193
-0.342496
-0.111902
-0.0157753
-0.0364608
-0.366895
--0.0356706
-0.392385
-0
--0.0731291
-0
-0.238754
-0.537306
--0.291401
-0.431303
--0.0170316
--0.034165
--0.0359125
--0.0352361
-0.150819
-0
-0.339596
-0
--0.0353711
--0.158859
-0.0522299
-0.457371
--0.0335989
-0.365262
-0.0991264
--0.0359887
--0.0164675
-0.0517498
-0.0512789
-0.243157
-0.334787
-0.146304
-0.284104
--0.0184816
--0.198044
-0.0558309
-0.276135
-0.111891
-0.564523
-0.519819
--0.0680299
--0.197863
--0.0352851
-0.493302
--0.255002
-0.172338
--0.272194
-0.622001
-0.183467
-0.556126
--0.171815
-0.282793
-0.199082
-0.311787
-0.100092
-0.459398
-0.481227
-0.133187
-0.0726739
-0.457068
--0.0362327
--0.264095
-0.288976
-0.639011
--0.123588
-0.0700202
--0.10665
-0.108076
-0.627827
-0.711789
--0.0709241
-0.84316
-0.303218
-1.01542
-0.623384
-1.28392
-1.19781
-0.126716
-0.598425
-1.30611
-1.34803
-1.80389
-1.60304
-1.81724
-0.431623
-1.2647
-1.29344
-0.957377
-2.0659
-2.59608
-1.46945
-0.285225
-2.4936
-2.00539
-0.800506
-1.69619
-2.02757
-0.501147
-0.945096
-0.952684
-2.11514
-1.32684
-0.94899
-0.311546
-0.502743
-0.220038
-0.361263
--0.0591346
--0.19554
-0.31383
-0.637307
-0.0174536
-0.333026
-0.362324
-0.317264
-0.0173328
-0.411217
-0.286109
-0.197273
-0.174426
-0.728282
-0.0175792
-0.716102
-0.615171
-0.315049
--0.128314
-0.0349744
-0.512501
-0.33277
--0.156769
--0.070131
-0.372485
-0.0707023
-0.114678
-0.386396
-0.0543147
-0.28602
-0.25193
-0.121562
-0.162916
-0.304784
-0.480169
-0.286251
-0.278154
-0.0161026
--0.0897686
-0.0520997
-0.186658
-0.388088
-0.102554
--0.0333857
-0.0526504
--0.12565
-0.42392
-0.107803
-0.159503
-0.255524
--0.0838044
-0.112641
--0.0360944
--0.445702
-0.761824
-0.162731
-0.0168854
-0.35769
--0.0733363
--0.0370319
-0.0172509
-0.279184
--0.0368805
--0.0372108
-0.0530764
-0.204057
--0.0730623
-0.0204904
-0.494224
-0.451955
--0.0747986
-0.362011
-0.165387
-0.0170462
-0.0534722
-0.255702
--0.0210968
--0.0171387
-0.121622
-0.215506
-0.0361849
-0.361874
-0.106241
-0.162809
-0.939017
-0.514769
-0.356988
-0.222132
-0.828562
-0.593922
-0.765087
-0.350753
-0.220333
--0.021574
-0.485895
-0.218695
-0.746135
-0.357433
--0.180444
-1.07934
-0.42309
-1.67782
-2.12437
-0.773346
-1.18999
-1.65848
-1.81602
-1.97669
-1.7324
-2.21552
-1.64916
-1.83155
-1.71387
-1.89648
-2.17409
-1.29207
-2.0126
-1.32062
-1.11658
-1.30705
-1.60183
-1.40332
-0.879587
-1.35557
-0.373727
-1.7581
-1.20196
-1.71269
-0.389518
--0.0174095
-1.40529
-0.268238
-0.134875
-1.14656
-0.70015
-0.252539
-0.859511
-0.769728
-0.0752194
-0.997106
-0.426595
-0.618591
-0
-0.343969
-0.191818
--0.0373751
-0.557009
--0.0355695
-0.26333
-0.104276
-0.0201675
-0.109419
-0.603103
-0.333252
--0.127597
--0.015972
-0.535782
-0.558085
-0.564331
-0.16176
-0.281279
-0.384778
--0.35846
-0.153318
--0.167968
-0.545183
-0.104527
--0.102696
--0.169075
-0.321799
-0.186534
-0
-0.133475
-0.0153829
-0.10669
--0.365522
-0.452655
-0.328134
-0.0502536
-0.196911
--0.0361687
-0.102437
-0.265426
-0.1053
-0.195345
-0.455892
-0.0570133
-0.541041
--0.0951639
-0.104996
--0.606175
-0.474546
--0.164028
-0.450947
-0.210047
-0.249025
-0.108129
-0.344453
--0.222408
-0.299932
-0.164531
--0.162186
-0.226945
-0.158905
--0.0390847
--0.0727352
--0.510325
-0.44865
--0.126518
-0.750884
-0.0167717
-0.108314
-0.242604
--0.0710903
-0.259523
-0.521718
-0.517275
-0.321169
-0.516543
-0.683783
-0.375709
-0.884137
-0.433527
-0.664995
-0.781892
-2.01619
-1.11252
-1.01199
-0.203094
-0.995754
-1.09817
-0.948689
-1.34588
-2.53768
-2.19528
-0.85461
-2.28507
-0.860731
-1.99274
-2.00192
-2.62653
-2.03594
-2.04746
-1.23625
-1.82106
-2.64833
-1.94757
-0.977174
-1.59252
-1.79901
-0.285551
-1.4001
-0.828384
-1.19332
-0.30787
-0.408119
-0.582229
-0.937709
-0.80447
-0.96293
-0.570227
-0.212603
-0.261232
-0.391881
-0.297586
-0.500068
-1.13729
-0.489436
--0.136621
-0.508961
--0.0774336
--0.0774897
-0.259761
-0.214464
-0.167532
-0.123224
-0.154559
-0.911272
-0.165637
-0.256783
-0.106364
-0.262982
-0.432694
-0.191894
-0.0553356
-0.0530858
-0.151875
--0.156529
--0.197432
-0.18917
--0.174749
--0.0736493
-0.278787
-0.0158895
-0.254174
-0.0515598
--0.124331
-0.0154446
-0.293564
-0.0936717
-0.0537593
-0.152018
-0.108317
-0.0531767
-0.0532315
-0.351988
-0.580125
-0.11301
-0.299162
--0.0367379
-0.020188
--0.409142
-0.613407
--0.179907
--0.214358
-0.0534686
-0.054068
-0.0549563
-0.110585
-0.0540102
--0.15787
-0.204649
-0.860162
--0.0171581
-0.10625
-0.483072
--0.110554
-0.345713
-0.477707
-0.251029
-0.14245
-0.0730064
-0.111172
-0.198289
-0.0161411
-0.0165424
-0.347063
-0.3139
-0.310652
-0.231583
--0.299862
-0.406322
-0.877543
-0.072001
--0.333693
-0.897685
-0.699406
-0.326598
-0.369563
-0.071127
-0.593426
-0.752355
-1.69326
--0.00384394
-0.750796
-1.30008
-0.883479
-1.20402
-0.919364
-2.036
-1.89914
-2.23031
-4.2596
-2.30416
-2.4057
-2.66575
-2.45911
-4.56286
-3.54224
-2.83484
-2.1329
-1.44979
-2.37447
-3.07609
-1.97103
-2.37743
-2.29215
-1.44076
-1.94042
-0.304681
-0.382085
-0.882807
-1.17458
-0.492675
-0.196228
-1.27178
-1.51119
-0.127992
-0.724503
-0.773619
-0.254386
-0.310039
-0.0586138
-0.802975
-0.0729789
-0.245534
-0.316744
--0.301702
--0.0210698
-0.160934
-0.464948
-0.245329
-0.496355
-0.718631
-0.284642
-0.50314
--0.261838
-0.779952
--0.0730551
-0.128445
--0.0878813
-0.0525247
--0.35865
--0.0352538
-0.117128
-0.341204
-0.188177
-0.402703
--0.0858957
--0.0370272
-0.0515311
-0.205557
--0.12324
-0.283764
-0.428284
-0.678662
-0.184804
-0.146724
-0.291688
-0.140013
-0.321623
-0.0491717
--0.118445
--0.161001
--0.0349496
-0.252751
-0.208149
--0.070494
-0.0541266
--0.193804
-0.144463
-0.327605
-0.0517891
-0.0152559
-0.0169859
-0.0149281
-0.36181
-0.202825
-0.219253
-0.338742
-0.157634
--0.171717
-0.591879
-0.425704
--0.363207
-0.187556
-0.106739
-0.0677354
-0.248489
-0.188446
--0.12741
-0.557736
-0.167682
-0.575175
-0.451901
--0.0170964
-0.250638
-0.343702
-0.683656
--0.120295
-1.18223
-0.584115
-0.388563
--0.144383
--0.165777
-0.92309
-0.366983
-0.370546
-1.31349
-0.490934
-0.846834
-1.913
-0.754274
-0.789739
-0.272022
-1.09089
-1.55922
-1.07915
-1.2474
-0.721206
-1.97264
-3.10103
-2.23237
-2.84215
-3.76839
-4.86951
-3.01277
-3.00444
-2.26384
-1.94928
-2.76828
-2.86605
-1.85472
-1.50591
-1.21076
-1.35476
-0.798534
-1.41907
-1.98453
-0.933533
-1.82962
-0.900857
-0.491397
-0.564773
-0.790065
-1.21587
-0.428767
--0.0204759
-0.630807
-0.202323
-0.125223
-0.203957
-0.523726
-0.338639
-0.0543751
--0.0868604
-0.166667
-0.639996
-0.0715658
-0.142302
-0.202421
-0.616329
-0.360398
-0.243082
-0.738582
--0.222803
-0.582958
-0.214414
-0.200725
--0.200873
--0.12583
-0.104244
-0.334284
-0.274273
-0.199339
-0.480597
-0.7584
-0.242904
--0.152025
-0.100608
-0.572198
--0.0351652
-0.0994212
-0.0500328
-0.186955
-0.251016
--0.120819
-0.30652
-0.0534281
-0.200691
-0.690194
-0.162575
-0.158059
-0.207587
-0.0364282
-0.194246
--0.126496
-0.0200777
-0.436935
-0.501262
--0.0929974
-0.0562187
--0.0173145
-0.27552
-0.142408
--0.129064
-0.138614
-0.141758
-0.19619
--0.0743801
-0.0205202
-0.162
--0.2775
-0.492814
-0.397903
-0.591856
--0.0199587
-0.0166227
--0.0791441
-0.106931
-0.0162025
-0.109292
-0.108778
-0.221316
-0.255249
--0.0206254
--0.0380354
-0.537821
-0.360897
-0.365349
-0.808651
-0.282349
-0.855205
-0.512352
-1.36649
-0.421305
-0.429919
-0.882094
-2.58603
-0.42005
-1.85239
-1.74246
-1.59126
-1.33923
-1.36158
-2.54592
-2.86924
-2.67876
-3.70754
-3.92629
-2.55842
-6.02087
-4.42114
-3.13855
-4.2468
-3.86779
-3.96227
-3.86308
-4.13795
-2.15349
-2.397
-1.26454
-2.57975
-2.08343
-1.87422
-1.71847
-2.16824
-3.60629
-2.34908
-0.255134
-1.03711
-0.6587
-0.689652
-0.390092
--0.0885734
-1.01499
-0.357845
--0.107975
-0.580554
-0.421398
-0.406216
-0.35078
-0.135011
-0.503711
--0.273953
-0.740566
-0.238419
-0.597821
--0.21468
-0.462982
-0.311412
-0.236953
-0.156071
-0.194184
--0.0368811
-0.207559
-0.0166261
-0.289632
-0.105692
-0.648522
-0.107465
-0.236652
-0.0515456
-0.193639
--0.170707
-0.28321
-0.239901
-0.098952
-0.0701139
-0.199813
-0.695045
-0.376252
-0.273888
--0.110446
-0.351449
-0.826958
-0.0548188
--0.105647
--0.0907037
-0.0516568
--0.267188
-0.103552
-0.0551285
-0.419673
-0.21071
-0.141961
--0.0387638
-0.461186
-0.404129
-0.357624
-0.147562
--0.0134634
--0.0390024
-0.291076
-0.153759
--0.222614
-0.161086
-0.206135
-0.463321
-0.124682
--0.187632
--0.0215472
-0.708914
-0.298975
-0.548147
-0.208965
--0.116426
--0.130328
-0.25509
--0.0362221
--0.387586
-0.581463
--0.111267
-0.0550318
-0.354689
-0.0716646
-0.616688
-0.447417
-0.579991
-0.412726
-0.544784
-0.763104
-0.493983
-0.851787
-0.262382
-0.0895544
-0.444953
-0.197942
-2.16656
-0.797838
-2.2732
-1.26538
-1.92592
-3.51187
-2.44213
-3.19496
-3.95421
-4.10912
-3.70932
-2.88932
-3.41593
-4.35512
-5.4722
-3.80552
-4.86827
-4.68813
-4.24276
-4.70075
-3.55315
-2.92561
-2.5887
-2.46088
-2.60921
-2.27743
-0.924334
-1.52535
-1.92657
-0.504208
-1.0089
-1.16256
-1.19885
-1.15747
-0.601673
-1.30745
-0.17404
-0.551736
-0.01695
-0.124732
-0.644648
--0.0787321
-0.174885
-0.209934
--0.124776
--0.0378745
-0.115717
-0.370673
--0.128881
-0.0703272
-0.113706
-0.258942
--0.185057
-0.106292
-0.796364
--0.0727995
-0.21812
--0.0903316
-0.0704903
-0.470521
-0.277005
-0.2948
-0.0163879
--0.227121
-0.145079
-0.454701
-0.736673
-0.158566
-0.0542111
-0.244376
-0.0544437
-0.0167369
--0.0726359
-0.436275
-0.0179717
-0.0505782
-0.153072
-0.342588
-0.439792
--0.206848
-0.227542
-0.145919
-0.119817
-0.0193113
-0.466283
-0.0700776
-0.016325
--0.0903777
-0.194692
-0.276221
-0.0163592
--0.0344584
-0.278403
-0.0161189
-0.0511278
--0.217141
-0
-0.28247
-0.10633
-0.206615
-0.254663
-0.246465
--0.0711731
-0.595771
--0.178979
-0.0162017
-0.311982
-0.248382
--0.157237
--0.304192
-0.0167521
-0.603697
-0.775056
-0.306869
-0.357864
-0.203846
-0.970196
-0.76027
--0.162985
-0.265934
-0.487513
--0.0929471
-1.96495
-0.914079
-0.14149
-0.626762
-0.889858
-2.2387
-2.2392
-1.66451
-3.07482
-2.7532
-1.19562
-2.67698
-4.10712
-4.36724
-5.02405
-4.09914
-5.23018
-4.97385
-5.94364
-5.23011
-7.37092
-4.74199
-5.16239
-6.24487
-5.13656
-5.55245
-4.14144
-4.01598
-3.32292
-1.82285
-3.54164
-1.39418
-2.52163
-0.984076
-2.14419
-0.832146
-0.976447
-0.188605
-0.470152
-1.38799
-1.20176
-1.1564
-0.854658
-0.159335
-0.108986
-0.0157998
-0.350642
-0.524829
--0.220268
-0.295743
--0.020337
-0.0564862
-0.241195
-0.332556
-0.352463
--0.330447
-0.232975
-0
-0.470107
-0.0519441
--0.463886
-0.053128
--0.397538
-0.2789
--0.165454
-0.210696
--0.126963
-0.05217
--0.217284
--0.0354678
--0.0535922
-0.156779
--0.125133
-0.327603
-0.189352
-0.107613
--0.0862615
-0.0185684
--0.0170469
--0.250419
-0.241749
-0.234205
--0.268679
--0.0189523
-0.104427
--0.297171
-0.42378
-0.283517
--0.0703112
-0.0158294
-0.0525183
-0.312799
--0.0917791
--0.0165105
-0.43834
-0.20672
-0.204856
-0.639708
-0.298967
-0.4154
--0.0378514
--0.0209559
-0.39434
--0.0704534
-0.158874
-0.182231
-0.795496
--0.515791
--0.306622
-0.15608
--0.409588
-0.193584
-0.0748509
--0.0692516
-0.454571
--0.126533
-0.314324
-0.343539
-0.109613
-0.265302
-0.5527
-0.106648
-0.492122
-0.536869
-0.355356
-0.365053
-0.708689
-0.20836
-0.502204
-0.469609
-0.99829
-0.591578
-1.80208
-0.158791
-2.10761
-0.803761
-2.15877
-1.17858
-2.78071
-3.13415
-2.98356
-5.77038
-5.08414
-5.39204
-6.15678
-6.10462
-9.30029
-8.40157
-8.05731
-8.59764
-4.95285
-5.85035
-10.0887
-5.57898
-2.75685
-4.45785
-3.57941
-1.89237
-2.78358
-2.81746
-1.68536
-2.5142
-1.50304
-1.68566
-1.26262
-0.660167
-0.344394
-0.591453
-0.283884
-0.982795
-0.430096
-0.430955
-0.314293
--0.274225
-0.131797
--0.0772119
-0.328237
-0.1579
-0.270787
-0.069921
--0.362183
-0.94794
-0.730281
-0.37231
-0.158799
-0.294615
-0.150121
-0.0700387
-0.698104
-0.197372
-0.306749
--0.0356418
-0.257387
--0.0368938
-0.312284
--0.0199998
-0.477601
-0.0537678
-0.308733
-0.252266
-0.19413
--0.115447
-0.480841
--0.088684
-1.01057
-0.49204
-0.137235
-0.224366
--0.170419
--0.180997
-0.0498987
--0.0888323
-0.137876
-0.30099
--0.0335241
--0.221475
-0.200343
-0.0990312
--0.0355887
-0.193617
-0.104777
-0.0162259
-0.356829
-0.0704051
-0.189449
-0.0519452
-0.340038
--0.122368
-0.200628
--0.0373429
-0.102895
-0.343073
-0.147788
-0.527621
--0.0710751
--0.107385
-0.354062
-0.104138
-0.257898
--0.0375147
-0.107469
-0.195987
-0.507782
-0.300926
--0.167035
-0.10673
-0.680345
--0.0712153
-0.231177
-0.439473
-0.0696149
-0.264486
-0.412788
-0.763673
-0.446567
-1.5072
-0.653237
-1.34434
-1.22532
-0.369445
-0.572265
-1.0953
-2.48122
-1.60757
-1.83328
-2.64958
-3.73174
-4.47432
-4.53934
-6.7699
-7.33158
-5.81342
-11.1117
-8.09105
-12.8992
-6.42325
-11.5552
-7.57506
-10.9106
-9.58009
-8.73204
-6.5422
-6.80777
-5.59935
-5.12241
-3.65653
-4.65172
-3.60455
-1.76689
-2.72945
-1.61661
-1.06259
-1.13742
-0.360439
-1.81635
-1.19956
-1.34814
-0.255589
-0.917559
-0.500134
-0.386822
-0.426366
-0.162336
-0.909892
-0.264187
-0.344664
--0.474711
-0.224588
-0.892655
-0.127386
-0.163797
--0.0375842
-0.113731
-0.358346
--0.124185
-0.102754
--0.0734102
-0.0162036
--0.179344
-0.0159387
-0.0714074
-0
--0.129329
--0.272915
-0.11883
--0.125628
--0.217593
--0.0867922
-0.566108
-0.0164875
--0.358398
--0.0877223
--0.124894
--0.0698495
--0.0337122
--0.162802
-0.0707289
--0.111789
-0.328199
--0.122496
-0.108035
--0.0835218
--0.0843181
-0.10639
-0.142281
-0.191995
-0.349808
-0.183266
-0.40739
-0.194519
-0.413507
-0.284647
-0.303967
--0.122628
-0.292466
-0.123438
--0.169678
-0.0518715
-0.107648
--0.0361383
-0.446751
-0.193558
-0.10863
-0.108177
--0.037731
-0.3949
-0.166987
-0.0162487
-0.292557
-0.393747
--0.039092
-0.1602
--0.376084
-0.247091
-0.0553244
-0.458879
-0.167406
-0.216286
-0.0934131
-0.236155
-1.26907
-0.523182
-0.7284
-0.864501
-1.64045
-1.19658
-0.382651
-1.20621
-1.43755
-1.39704
-1.90981
-2.51735
-2.77909
-4.0639
-4.84229
-3.31458
-6.52321
-8.71832
-9.07984
-8.3127
-12.6549
-10.2167
-14.7261
-13.6002
-11.9074
-13.1441
-13.288
-11.8773
-13.5337
-10.9458
-6.14478
-5.92922
-4.71624
-5.5026
-5.05994
-3.53618
-2.85324
-2.51762
-2.83219
-0.943412
-1.59027
-1.02988
-1.48308
-1.71182
-0.691881
-0.270311
-0.785545
-0.975325
-0.478454
-0.135039
--0.115306
-0.495911
-0.534666
-0.240055
--0.213424
-0.107474
--0.13062
-0.17947
-0.376686
-0.249585
-0.582158
--0.107547
--0.0209467
-0.676916
-0.471631
-0.390397
-0.50622
-0.287189
-0.108033
-0.0516809
-0.310125
--0.215046
-0.147657
-0.03354
-0.101835
-0.136897
--0.0170029
-0.049436
-0.104968
-0.379143
--0.305338
-0.280143
-0
-0.189351
--0.0350388
-0.0538496
--0.0936044
-0.142002
--0.122137
-0.25262
-0.187011
-0.258184
-0.54579
-0.158223
-0.203584
-0.193013
--0.127915
-0.0558214
-0.150806
--0.0905528
--0.223901
--0.13145
-0.320417
-0.347952
-0.0552143
-0.295691
--0.0364156
-0.114236
-0.110809
-0.149512
--0.0866013
--0.0205657
--0.0373517
-0.0172788
-0.168364
-0.217899
-0.338354
-0.161869
--0.113787
-0.399929
--0.377807
--0.0215689
-1.00507
--0.165118
-0.369849
-0.906985
--0.367354
-0.53996
-0.123248
-0.534001
-0.41404
-0.695721
-1.1468
-0.256247
-0.747742
-1.72109
-0.986201
-3.14878
-1.98684
-2.72199
-1.99366
-4.39294
-4.82342
-5.15709
-7.88995
-8.55464
-9.97995
-14.3925
-13.7177
-18.0515
-17.6252
-16.4688
-19.088
-19.163
-16.0633
-15.7636
-14.9651
-13.6158
-9.66247
-10.9596
-7.73864
-7.60678
-5.79281
-3.26559
-1.86938
-2.8847
-2.69676
-2.18572
-0.599738
-1.75847
-1.04229
-0.594875
-0.619104
-0.516389
-0.860394
-0.587721
--0.0212743
-1.085
-0.417699
-0.159007
--0.310332
--0.451339
-0.164283
-0.345825
-0.339861
-1.1151
-0.367037
-0.682663
-0.31608
-0.813128
--0.0365602
--0.317089
--0.36033
-0.596545
--0.251995
--0.121226
-0.440753
-0.636324
--0.45196
--0.329884
-0.168025
-0.0170644
-0.204948
--0.128682
-0.0521167
-0.491576
--0.0725276
--0.124451
--0.0898769
-0.19115
-0.28747
-0.0977242
--0.0337055
-0.495778
--0.121938
-0.0496014
--0.0348414
-0.105849
--0.0358925
-0.525259
--0.0867176
-0.191466
-0.0164503
-0.0969816
-0.584218
-0.0811726
-0.053482
-0.0491438
-0.0564416
--0.0161854
-0.0528672
-0.0982192
--0.0880173
--0.0200829
--0.104791
--0.349367
-0.446856
-0.427958
-0.425472
--0.0714781
-0.334439
-0.160937
--0.219564
--0.153557
-0.0170398
-0.237974
-0.874903
--0.166091
-0.768325
--0.217533
-0.916873
-0.413327
-1.02389
-0.762962
-1.35556
-0.0699788
-0.497564
-0.124505
-0.328045
-0.805232
-1.66328
-0.621112
-1.56334
-2.36363
-0.0689188
-1.85404
-3.1699
-2.78404
-3.76319
-3.98875
-8.73968
-5.45697
-9.21883
-12.7817
-12.6857
-15.7551
-19.1178
-21.2141
-23.2121
-26.1849
-25.5491
-26.0517
-26.3865
-23.8762
-19.9792
-13.5988
-14.0091
-10.9104
-11.6437
-6.85332
-5.8253
-5.13832
-3.58741
-3.00552
-2.59821
-2.54536
-1.63511
-1.68407
-0.957463
-1.18934
-0.763482
-0.466811
-0.746223
-1.81012
-0.27499
-1.47257
--0.119938
-0.681812
-0.363415
-1.2942
-0.691519
-0.809135
-0.0724876
-0.111083
-0.472708
-0.698732
-0.435337
--0.159747
-0.221784
-0
--0.0367684
--0.273129
-0.0182925
--0.349091
-0.0523201
-0.676296
--0.128347
-0.196703
-0.103073
--0.17731
-0.0164973
-0.534122
-0.0205286
-0.239105
-0.157407
--0.03463
-0.0517112
-0.108046
-0.391563
-0.41005
-0.328379
--0.123404
-0
-0.477825
-0.387351
-0.144351
-0.188806
-0.0558883
-0.27706
--0.162958
--0.282808
-0.19187
-0.0530917
--0.252022
--0.0887918
-0.43796
-0.564082
--0.246729
--0.283266
-0.199383
--0.0200026
--0.0213853
-0.295444
-0.241132
-0.703668
-0.485837
-0.257346
-0.295341
-0.108571
-0.477938
-0.334311
--0.242603
-0.190807
-0.587554
--0.225757
-0.30685
--0.214356
-0.440391
-0.563642
-0.544927
-0.181667
-0.94529
-0.128426
-0.652584
-1.2523
--0.0567804
-1.28452
-0.860342
--0.0430382
-1.6806
-1.72264
-2.49193
-2.19134
-1.60716
-3.15888
-3.78734
-4.60567
-6.86287
-10.1738
-10.2669
-11.2052
-15.5232
-17.4357
-20.8876
-22.7855
-27.2985
-34.8106
-37.4228
-35.9839
-33.5544
-32.6314
-32.4795
-24.9689
-22.0681
-14.9545
-14.3077
-11.64
-10.7185
-6.82957
-6.90309
-5.02234
-4.17693
-3.01573
-2.12113
-3.34752
-2.93028
-1.21216
-1.09611
-0.587924
-1.22313
-0.748172
-1.65817
-1.38441
-0.423059
-1.09942
-1.06712
-0.265568
-0.580912
--0.18489
-0.216658
-0.212139
-0.460084
-0.110763
--0.229155
-0.0728002
-0.150301
-0.171573
-0
--0.0883617
-0.56991
--0.263315
--0.0345699
-0.0531286
--0.0355376
-0.160477
--0.0712488
-0.10466
-0.298084
-0.015863
-0.106736
-0.614247
-0.187198
-0.104915
--0.284434
-0.456856
-0.186669
-0.102333
-0.0921463
--0.0660034
--0.119592
-0.0542656
--0.206021
-0.159018
-0.121355
--0.0320367
-0.289863
--0.0379972
-0.276302
--0.0212397
-0.195702
-0.217163
-0.0500104
--0.221896
--0.46922
--0.135375
-0.050181
-0.074077
-0.0164551
-0.194318
-0.195161
--0.0728318
-0.0684165
-0.446208
--0.156699
--0.0392039
--0.394236
-0.128526
-0.211284
--0.0395691
-0.592693
-0.214048
-0.397604
-0.0179755
-0.483871
-0.522734
-0.281982
-0.319053
--0.133063
--0.0212678
-0.414199
-0.517976
-0.126602
-0.285395
-1.46624
-1.09175
-1.2394
-0.69923
-1.57732
--0.0429572
-2.021
-1.88853
-3.64122
-3.83397
-4.51963
-6.04101
-5.8223
-6.47683
-9.63104
-14.2288
-17.8043
-23.1299
-27.5501
-36.8259
-41.9834
-44.5147
-52.0474
-55.8097
-49.9563
-49.893
-39.7784
-37.5164
-26.2535
-24.54
-19.3887
-15.2218
-11.8199
-11.2299
-10.0673
-5.53967
-5.13213
-2.83986
-3.72932
-3.26382
-2.1128
-0.887227
-0.663703
-2.15378
-0.425787
-1.36772
-1.10087
-0.114609
-0.0721206
-0.166944
-0.0717959
-0.375743
-0.387205
-0.632707
-0.220198
--0.0378872
-0.487301
-0.933705
--0.307525
--0.081954
--0.110384
-0.435936
-0.346782
-0.197584
-0.280648
-0.452692
-0.190032
-0.567861
--0.47742
-0.654547
-0.10393
--0.31223
-0.0164305
-0.437125
-0.069052
-0.191974
-0.279327
--0.114281
-0.431177
-0.1949
--0.106314
-0.466076
--0.0328283
-0
-0.276017
-0
-0.567614
-0.457988
-0.177951
-0.238517
-0.340041
-0.47961
-0.0686902
-0.260807
--0.0858825
-0.0505761
-0.145582
-0.202175
-0.20006
-0.200314
-0.469095
--0.0375044
--0.212239
--0.177432
--0.266745
-0.104948
-0.293358
-0.727694
--0.180714
--0.127952
-0.847573
-0.158466
-0.0694275
-0.251232
-0.586722
-0.112392
-0.0168247
-0.108317
--0.0172859
--0.293391
-0.720941
-0.436908
-0.451908
-0.461114
-0.262542
-0.549323
-1.05258
-0.1822
-0.691563
-0.293881
-1.08861
-1.86346
-1.22121
-1.39549
-1.94263
-2.13627
-2.94097
-4.82351
-3.51115
-5.36447
-8.5517
-9.08845
-13.8978
-20.1469
-23.6566
-27.3884
-37.7685
-49.6311
-59.4109
-70.9437
-70.4584
-80.5821
-78.3678
-69.2161
-62.5084
-47.2787
-39.2349
-32.8653
-25.8796
-21.3995
-16.1215
-12.0072
-7.95427
-6.13525
-4.32405
-3.34912
-1.86709
-1.39003
-2.09187
-0.698222
-1.63241
-1.83976
-1.66387
-1.60731
-1.46191
-0.758247
-0.707027
-0.810119
-1.2135
-0.462662
-0.252503
-0.750616
-1.02174
-0.364402
-0.104445
-0.579515
--0.162242
-0.436017
-0.608506
-0.254511
--0.130402
--0.128758
-0.209028
-0.583718
-0.205458
--0.364513
-0.108153
-0.169899
-0.101773
-0
-0.340045
-0.340433
-0.212956
-0.244526
-0.191437
-0.345895
-0.158389
-0.052265
-0.0161835
-0.0700628
-0.046653
--0.0892214
--0.069049
-0.470098
-0.152192
--0.172427
-0.286852
-0.151592
-0
-0.249444
--0.0187904
--0.0730757
-0.148248
--0.325006
--0.125475
-0.346202
-0.0671983
-0.111326
-0.237619
-0.21049
-0.141063
-0.655353
-0.0203972
-0.159584
-0.256646
-0.146973
--0.119284
-0.262411
-0.639856
-0.217983
-0.57937
--0.181983
-0.576646
--0.385431
-0.212609
-0.426487
--0.0724139
-0.712624
-0.425703
-0.087061
-0.767116
-0.531989
-0.490083
-0.499903
-2.15665
-0.494157
-1.16139
-0.012648
-0.376886
-1.66473
-1.95949
-3.30385
-2.17719
-1.97078
-2.91271
-3.86499
-5.80407
-5.84986
-10.17
-13.6646
-17.8363
-24.2626
-32.9226
-42.7875
-52.4157
-73.1221
-77.973
-87.5781
-103.472
-105.292
-108.59
-93.0741
-70.9606
-71.048
-55.5347
-43.4168
-29.9032
-25.6529
-18.4859
-13.8856
-9.70283
-7.339
-6.49995
-6.17302
-2.32504
-2.30388
-1.58267
-2.60625
-2.10824
-0.561879
-0.876528
-0.539083
-0.230888
-0.191718
-0.804963
-0.610136
-0.675189
-0.366713
-0.0679382
-1.1417
-0.623699
-0.791025
-0.671888
-0.368801
-0.390723
--0.13303
-0.11962
-0.20304
--0.0374886
-0.195814
-0.499926
-0.0172553
-0.386971
-0.0197207
-0.0165127
--0.0216779
-0.286414
-0.144431
-0.0160676
--0.307229
--0.0142627
-0.566199
-0.133319
-0.197831
-0.0699663
-0.41337
-0.276692
-0.397693
-0.295543
-0.36989
--0.159268
-0.390438
-0.140044
-0.160708
-0.107074
-0.115022
-0.58002
-0.0181276
-0
-0.587107
-0.585528
-0.571478
--0.216012
-0
-0.287874
--0.345058
--0.211559
-0.105326
-0.339454
-0.433288
--0.218138
-0.291309
-0.350365
-0.198005
--0.0190917
--0.0355786
--0.131934
-0.574547
--0.0382526
-0.106519
-0.0679339
-0.409037
-0.120617
-0.245203
-0.0712886
-0.585147
-0.179372
-0.0699849
--0.019668
-0.325483
-0.828472
-0.839271
-0.625057
-0.6127
-0.654759
-1.13609
-1.04097
-0.726622
-1.15423
-1.98548
-1.36355
-2.68609
-3.50701
-5.74963
-6.49193
-8.73836
-13.1398
-18.2472
-21.0101
-30.8935
-37.9249
-50.2208
-73.9969
-96.3169
-116.181
-137.893
-148.944
-149.891
-151.134
-133.767
-108.095
-93.6413
-75.123
-52.6505
-38.3197
-29.279
-23.8312
-16.5741
-13.9391
-7.67409
-7.37129
-3.71149
-3.15768
-2.73624
-2.69532
-2.40869
--0.553564
-1.52227
-0.892822
-0.0130288
-1.37356
-1.06373
-0.191471
-0.83574
-0.70127
-0.0734679
--0.0737346
-0.538799
--0.111834
-0.893949
-0.128443
-0.273219
-0.575604
-0.10905
-0.156445
-0.194853
-0.362141
--0.223548
-0.118566
--0.223504
--0.125984
-0.0168891
-0.483345
--0.213388
-0.528442
--0.127975
-0.293462
--0.213993
--0.0882138
-0.016761
-0.16731
-0.223245
--0.0138478
-0.0511471
-0.525905
-0.052886
-0.0633518
--0.0852826
-0.376293
-0.14051
-0.101707
-0.430576
--0.0344442
--0.169346
-0.18905
-0.051343
-0.201474
-0.151007
-0.288401
-0.290865
-0.104214
-0.109786
-0.326589
--0.0794477
--0.119086
--0.108282
-0.238415
-0.764091
--0.127037
-0.251017
-0.257796
--0.037924
--0.172071
-0.201974
-0.570943
-0.156807
-0.161624
-0.265107
-0.281995
--0.226428
--0.000755705
-0.159769
-0.216439
-0.851377
-0.563572
-0.548734
-0.556814
--0.180248
--0.378737
-0.127138
-0.572767
--0.0886353
-0.709972
-1.45274
-1.41479
-2.2258
-1.8917
-3.26245
-1.20477
-4.39598
-2.7699
-5.93783
-7.93975
-9.29946
-12.6493
-19.4414
-27.4682
-35.2142
-51.3916
-69.0249
-89.1355
-112.414
-114.213
-82.8693
-59.9514
-60.8033
-73.0373
-106.267
-124.557
-118.513
-92.0762
-65.054
-47.3862
-34.0196
-27.5184
-21.337
-10.4846
-9.31973
-6.22075
-7.04452
-3.2866
-2.67033
-1.75446
-2.90113
-1.20926
-1.50893
-1.08627
-0.873307
-1.82433
-0.812446
-0.568941
-1.11524
-0.222281
-0.665335
-0.541516
--0.179285
-0.626569
--0.20933
--0.109358
-0.351568
--0.000753067
-0.438479
-0.471994
-0.200875
-0.50209
-0.347615
--0.0372993
--0.348784
-0.323505
-0.109696
-0.657061
--0.186089
-0.158685
--0.0890904
--0.0884093
-0.131031
-0.0194882
-0.0512821
-0.475247
-0.0744692
-0.605696
-0.319381
-0.159305
-0.273686
-0.0491142
--0.235344
-0.406961
-0.279665
-0.171321
--0.174062
-0.112264
--0.438376
--0.0697286
-0.103606
--0.0365654
-0.284436
-0.105713
-0.0750852
--0.128829
-0.201154
-0.0549187
-0.149347
-0.190478
--0.0932549
-0.309914
-0.30468
--0.380252
-0.0536067
--0.21912
--0.0375133
-0.104354
-0.222039
-0.429998
-0.0167004
-0.125834
-0.12642
--0.0709252
-0.382234
-0.411566
-0.535342
-0.0509524
-0.684024
-0.55262
-0.0346624
-0.0743628
-0.855483
-1.07903
-0.414687
-0.842143
-1.09192
-0.81911
--0.269159
-1.2828
-0.914464
-1.62344
-2.69424
-1.94288
-4.43459
-4.34135
-5.67523
-7.22126
-15.0717
-17.6127
-21.8353
-27.9047
-44.4908
-58.7032
-88.993
-80.0449
-50.2382
-9.52119
-0.951665
-0.0537201
-0.301846
-0.690247
-2.89923
-26.9179
-80.9982
-111.703
-84.5327
-60.8289
-42.089
-30.8991
-24.2985
-15.8193
-15.0223
-8.64291
-7.34103
-3.19854
-3.17102
-2.46146
-1.93733
-2.73304
-1.66147
-1.29847
-0.203829
-0.360132
-1.46975
-0.093909
-0.737725
-0.0326689
-0.257342
-0.143633
-0.265981
--0.0736083
-0.506976
-0.260929
-0.61463
-0.678144
-0.164331
--0.178234
-0.126711
-0.766388
-0.0525068
--0.0203844
--0.197628
--0.128493
--0.308626
--0.121134
-0.343159
--0.120508
--0.0382638
-0.107647
-0.328733
--0.0906629
-0.251711
-0.346873
-0.053252
--0.0370587
-0.3382
-0.307891
-0.464684
--0.195105
--0.0315782
-0.13889
--0.0169321
--0.0642688
--0.337252
-0.287073
-0.138518
--0.205356
--0.0696436
-0.191101
--0.213706
-0.399094
-0.25532
-0.378591
-0.0529535
-0.152846
-0.163117
-0.100631
-0.124643
-0.335107
-0.340475
-0.257153
--0.131589
--0.072149
-0.189334
--0.120362
--0.0208939
-0.464932
-0.246029
-0.784464
-0.469307
--0.263471
-1.06587
-0.679984
-0.364039
-0.36165
-0.493549
-0.585217
-0.646997
-0.372992
-0.0683222
-0.118662
--0.236376
-0.421497
-0.953872
-1.21448
-1.17216
-1.12962
-1.02549
-2.01396
-2.50706
-3.59843
-3.22711
-4.62214
-5.34136
-10.45
-15.3087
-17.9284
-25.2877
-39.3621
-48.6176
-71.4451
-72.6317
-14.5078
-0.40916
--0.160447
-0
-0
-0.292834
-0.0534025
-0.171734
-0.420352
-3.86199
-51.8691
-88.1309
-69.0158
-49.9271
-32.2689
-23.0459
-20.509
-10.4672
-7.34861
-5.07876
-4.04445
-2.604
-2.21437
-2.60684
-2.65187
-2.62004
-0.892761
-0.702929
-1.23582
-0.296536
-0.561469
--0.0220599
-0.802706
-0.698134
-0.346495
-1.1205
-0.960361
--0.161602
-0.476704
-0.230245
-0.623288
-0.602437
-0.172359
--0.13293
-0.112463
-0.202003
-0.208925
--0.13541
-0.304299
-0.761413
-0.0165016
--0.224308
--0.0175922
--0.281645
-0.198364
--0.130157
-0.398199
--0.0368447
-0.468977
--0.0361692
-0.142153
-0.676161
--0.0942132
-0.0506048
-0
-0.0476083
--0.121333
--0.0849977
-0.696898
--0.105543
-0.641051
-0.140341
-0.0554809
-0.252798
--0.120155
--0.272953
--0.0364192
--0.0368888
--0.129817
-0.342391
-0.34311
--0.0719832
--0.0903286
-0.109582
-0.663809
--0.356877
-0.211069
-0.347094
-0.445768
--0.184268
--0.265794
-0.108359
-0.191286
-0.195938
-0.539076
--0.218046
-0.214306
-0.0338764
-0.819219
-0.598378
--0.380035
-1.14995
-0.398311
-0.357731
-0.466927
-0.33026
-0.139675
--0.0193197
-0.379042
-0.772014
-1.19205
-1.25843
-0.23906
-1.01018
-1.43508
-2.78052
-2.59296
-3.57165
-5.22832
-8.18401
-11.9999
-14.8325
-17.3973
-30.6768
-36.773
-60.3331
-69.8147
-15.7749
-0.13491
-0.155913
-0
-0
-0.140581
-0
--0.0873693
--0.0915038
-0
-0
-3.28418
-55.4804
-84.6071
-61.8837
-41.1791
-31.0033
-15.6269
-17.1681
-10.5811
-8.07626
-3.52749
-3.61581
-4.59199
-2.30692
-3.02663
-1.75686
-1.28098
-0.696761
-0.337221
-1.00257
-1.46191
-0.236691
-0.576678
-0.464186
-0.526286
-0.383991
--0.417783
-0.694271
-0.258938
-0.5518
-0.375239
-0.461437
-0.384255
-0.757945
--0.428868
-0.16525
-0.688274
--0.269142
-0.740425
--0.0705725
-0.594761
-0.107905
-0.12491
-0.332515
--0.217172
-0.663546
-0.309871
-0.496329
-0.0684777
-0.520621
-0.0522319
-0.099302
-0.140028
-0.100598
--0.248355
-0.317841
-0.0149662
--0.173077
--0.345477
-0.182298
--0.0889787
-0.0182709
-0.282698
-0.0163099
--0.212699
-0.503033
-0.051671
--0.131659
-0.488056
-0.0170162
-0.386539
--0.395399
-0.0155431
-0.258209
-0.0196595
--0.0206314
-0.447233
--0.224099
-0.01585
-0.35967
-0.152879
--0.184711
-0.354736
--0.0579722
-0.159468
-0.30467
-0.193699
-0.505213
-0.5075
-1.04959
-0.0685728
-0.109369
-0.276663
--0.00392257
-0.179001
-0.532204
-0.556929
-0.448614
-0.257575
-0.438232
-0.668402
-0.261682
-0.340141
-2.51748
-1.67521
-1.55819
-2.55017
-4.1778
-6.09453
-6.92284
-12.3451
-14.2008
-21.5781
-25.368
-43.5605
-66.8683
-32.8148
--0.00405439
-0.144369
-0
-0.0541466
-0.0596678
-0
-0
--0.0953311
-0.143897
--0.0360006
-0.145108
--0.0929458
-8.36593
-67.9032
-65.3394
-43.8772
-32.2087
-21.7969
-18.2689
-8.52145
-7.21382
-3.38679
-2.58807
-3.17999
-4.25291
-1.67407
-2.01522
-1.16055
-3.47356
-1.13696
-2.22945
-0.989123
-0.574106
-0.52146
-1.38574
-0.575503
-0.282611
-0.563065
--0.136604
-1.24184
-0.038941
-0.561852
--0.329425
-0.115809
-0.408771
-0.113768
--0.0790685
--0.199093
-0.911757
-0.19977
-0.668614
-0.784293
-0.112767
--0.0369945
-0.159932
-0.10557
-0.148288
-0.0333032
-0.369462
-0.0695448
-0.718555
--0.128182
-0.234535
--0.0169589
--0.181488
-0.229004
-0.181098
--0.120091
--0.0344827
-0.274986
-0.0982374
-0.186137
-0.0151334
-0.137369
-0.526304
-0.0506399
-0.330285
-0.0195927
-0.242524
--0.171301
-0.445514
--0.318206
-0.105868
-0.414341
--0.391433
-0.233381
--0.168009
-0.240454
-0.513865
-0.55112
--0.0782386
--0.204868
-0.12642
-0.358482
--0.0562411
--0.253611
-0.525757
-0.302806
-0.494425
-0.203372
-0.206791
-0.459002
--0.122617
-0.171127
-0.854084
-0.482661
-0.323136
-0.8143
-0.20707
-1.41846
-0.457038
-1.02349
-1.22241
-2.02475
-2.18854
-1.20219
-3.1505
-2.91098
-4.78771
-7.85869
-7.71186
-10.8267
-16.1869
-20.2628
-34.5989
-46.4578
-63.0539
-11.9
-0
-0
-0.279843
-0.339986
-0
-0.276356
-0.134788
--0.0341989
--0.127425
-0
-0.052315
-0.287098
-0.392073
-38.2049
-70.8643
-46.3151
-36.0632
-28.2437
-15.9473
-9.71628
-8.45829
-7.72739
-3.50944
-3.86518
-1.96235
-1.2885
-1.1946
-1.00345
-1.20068
-0.421369
-0.83584
-1.24465
-0.234689
-0.211994
-0.965023
--0.146644
-0.237367
-0.123366
-0.445041
-0.266908
-0.612524
-0.822036
-0.270433
--0.0205547
-0.270039
-0.353228
-0.210444
-0.572459
-0.104412
-0.326883
-0.888792
--0.212356
-0.650682
--0.0706858
--0.0714313
-0.662557
-0.296327
--0.110076
-0.125578
-0.15017
--0.211979
-0.0157906
--0.0352811
-0.242258
-0.117693
--0.332889
-0.111689
-0.193821
-0.144056
-0.15889
--0.0473289
-1.02413
--0.173279
-0.108995
--0.122583
--0.126738
-0.147832
-0.0154537
--0.188207
--0.0357118
-0.0170362
--0.350372
-0.260593
-0.414734
--0.181306
-0.645815
--0.160038
--0.0207047
-0.104863
--0.263188
-0.200196
-0.736905
-0.165894
-0.510691
-0.632133
--0.0537797
--0.108402
-0.292646
-0.0566922
-0.157146
-0.0167886
--0.0204687
-0.263436
-0.280908
--0.113229
-0.489579
-1.41881
-0.498033
-0.181677
-1.28045
-0.1713
-0.67789
-0.793822
-2.46386
-2.38527
-2.71484
-1.99201
-3.00597
-4.527
-5.14825
-9.49377
-12.9661
-14.9725
-25.6415
-33.1432
-48.7027
-43.1228
-1.43248
-0
-0.146717
-0
-0
-0.0544695
-0.138411
-0
--0.0349674
--0.0922684
-0.0512681
-0.149634
--0.0898068
-0
-18.5303
-71.3596
-49.3053
-36.8068
-24.564
-17.8017
-10.0166
-7.87036
-6.11625
-5.23134
-3.59745
-1.87794
-2.76784
-1.65833
-3.39644
-1.88014
-1.29125
-1.6802
-0.690581
--0.240421
-0.763194
-0.546486
-0.0899171
-0.0553168
-0.39334
-0.236845
-0.359981
-0.229751
--0.150149
--0.118461
-0.128555
-0.318559
--0.320962
-0.106418
-0.598462
-0.0745901
-0.176246
-0.39293
-0.47459
-0.0174434
--0.0752713
--0.0201409
-0.488924
-0.0169548
-0.159727
-0.109177
--0.214103
--0.359524
-0.325274
-0.470006
-0.018832
-0.10372
--0.249574
-0.269308
-0.0538226
-0.282811
-0.367617
-0.0705782
--0.0380319
--0.117176
-0.263119
-0.251014
--0.274676
--0.128057
-0.164156
-0.42957
--0.0366197
-0.0536688
-0.247183
--0.182371
-0.053242
-0.079601
-0.0512688
-0.338077
-0.0547524
-0.249519
-0.146588
-0.654418
-0.364506
-0.838266
-0.470907
--0.130105
-0.537589
-0.0524236
-0.217888
-0.305919
-0.319339
--0.163085
--0.226064
-0.591751
-0.624042
-0.976232
-0.696998
-0.606201
-0.0335354
-0.475195
-0.88147
-1.35665
-1.08424
-1.23359
-1.5577
-2.32848
-2.00555
-3.71851
-1.48969
-3.75934
-3.09105
-6.27521
-12.8599
-15.8559
-25.4637
-41.0838
-53.5813
-42.5261
-1.81602
-0.147596
-0.444317
-0.0563888
-0
-0.054319
-0.0535581
--0.180072
-0
--0.0894567
-0.146612
-0
-0.147842
-0
-12.9819
-69.9286
-54.045
-39.3638
-22.3483
-22.893
-15.3811
-7.1708
-6.06336
-4.27015
-2.59649
-3.08059
-2.01194
-2.05295
-1.28684
-0.730615
-0.74146
-0.674582
-0.0346874
-1.64801
-0.357653
-0.439112
-0.407758
-0.90605
-0.573697
--0.381079
--0.354175
-0.253743
-0.706439
-0.270182
-0.130732
-0.209209
-0.31459
--0.0376132
-0.0747529
-0.789258
-0.0160256
-0.157095
-0.196594
-0.0691157
-0.250963
-0.0157687
-0.222507
-0.0341331
-0.428748
--0.0364457
-0.0690289
-0.0522222
-0.197933
-0.160377
--0.181221
-0.28516
-0.140246
-0.275893
--0.105475
--0.0707767
--0.0858495
-0.0502663
-0.157796
-0.376645
-0.332058
--0.121753
-0.720387
--0.0935913
-0.203735
-0.0532084
--0.306613
-0.104249
-0.102947
--0.129668
-0.392213
-0
-0.0517862
-0.421981
-0.392913
-0.110447
--0.0359969
--0.131064
--0.0207155
-0.601337
-0.193362
-0.44965
--0.542033
-0.528605
-0.295858
-0.113376
-0.606633
-0.620441
-0.60955
-0.0715044
-0.281044
-0.0173112
-0.320133
--0.268589
-0.356645
-0.779441
-0.14203
-0.0490441
-0.892817
-1.45144
-2.30168
-1.77576
-2.56883
-2.13642
-5.3535
-3.75656
-3.9682
-9.29948
-11.3763
-19.5108
-28.175
-34.2023
-49.8584
-44.6821
-0.777008
-0
--0.183228
-0.149992
--0.0932388
-0.155371
-0
--0.0737313
-0
-0.153964
-0.258265
-0.29571
-0
-0
-13.2115
-64.9845
-49.5507
-35.9624
-23.5127
-18.0228
-11.8458
-9.05644
-7.37911
-5.6743
-2.8012
-2.24837
-2.22952
-2.99782
-2.00484
-1.40308
-1.85651
-1.78612
-1.70691
-0.473858
--0.153801
-0.300392
-0.642112
-0.961505
-0.527777
-0.488627
-0.465368
-0.426116
-0.407927
-0.184064
-0.673432
-0.360864
-0.547208
--0.223512
-0.261077
-0.0171469
-0.428441
--0.1703
-0.0703762
--0.542741
-0.457159
--0.0697628
-0.253749
--0.0708624
-0.33724
-0.0167923
-0.0164525
--0.091811
--0.0382889
-0.203262
-0.0716741
-0.102814
-0.232458
-0.199254
-0.0531853
-0.194015
-0.494091
--0.123716
-0.166772
-0
-0.0565738
-0.5044
--0.366395
-0.198572
-0.485953
--0.0894349
-0
--0.0930562
-0.0530344
-0.34796
-0.107418
-0.112696
-0.100765
-0.293124
-0.287391
-0.124539
-0
--0.221635
-0.595059
-0.339472
-0.198954
--0.217722
-0.167618
--0.0581046
-0.0315055
-0.412562
-0.21564
-0.464955
-0.109979
-0.175941
--0.309372
-0.666765
-0.348495
-1.42494
-0.665639
-0.515224
-2.19064
-1.49101
-1.3548
-2.0125
-1.62448
-2.24299
-3.09857
-3.70951
-3.89717
-4.0825
-6.33324
-8.75559
-11.2974
-14.9561
-23.1714
-35.366
-53.5944
-48.9267
-3.594
-0.144362
-0.141327
-0.143722
-0
--0.0354532
-0.194861
-0
-0
-0.0514979
-0
-0.250975
--0.12333
--0.086518
-15.2475
-71.3985
-48.3389
-32.1621
-26.1305
-19.6455
-12.0467
-9.76263
-7.74673
-6.07077
-2.27178
-2.07729
-2.69741
-1.70685
-1.61853
-2.58591
-1.72892
-1.33187
-0.45281
-0.238766
-0.450475
-0.264366
--0.169171
-0.61436
-0.354696
-0.121229
-0.0706603
-0.341161
-0.0154175
--0.171198
-0.26566
-0.120407
-0.545077
-0.296305
-0.402525
-0.267134
-0.051837
--0.379019
-0.255247
--0.402952
-0.333377
--0.214133
-0.41004
-0.324538
-0.0524675
-0.287312
-0.438382
-0.0539419
-0.291746
-0.15339
-0.210292
-0.679108
-0.370113
--0.251008
--0.222732
-0.0163189
-0.129562
--0.164376
-0.189899
--0.0858348
-0.103942
--0.0360302
--0.249612
-0.205043
-0.176511
-0.0536943
--0.0343098
-0.0163317
-0.130933
-0.0555624
--0.184357
-0.343045
-0.182231
-0.25302
--0.121176
-0.104975
--0.322784
-0.283342
-0.402804
--0.038234
--0.119034
--0.0202809
-0.418187
-0.311487
--0.0201757
-0.204167
-0.0155035
-0.384865
-0.0330488
-0.67327
-0.381584
-0.347378
-0.140557
-0.747779
-0.273776
-1.20722
-0.136205
-0.224719
-1.08701
-0.399925
-1.12678
-2.07159
-1.30084
-3.46834
-3.00182
-3.85613
-7.66892
-7.10026
-11.2938
-16.8966
-25.2144
-32.8235
-43.7671
-50.609
-13.7787
-0
-0.429769
-0.151072
-0.285661
-0
-0.155793
-0
-0.149384
-0.0572266
-0
-0
-0
-0.760811
-41.2966
-71.2563
-49.8358
-31.279
-22.911
-14.784
-10.739
-8.78456
-5.70627
-4.01297
-4.56074
-2.38999
-1.24709
-1.95456
-0.454967
-1.29729
-1.26773
-0.205072
-0.846668
-0.961152
--0.0207761
-0.426101
-0.170626
-0.0770116
-0.202619
-0.964704
-0.113228
--0.121996
-0.639022
-0.864709
--0.262459
-0.336868
-0.201151
-0.371393
-0.115762
--0.075744
--0.177388
-0.0767525
-0.0524903
--0.132931
--0.178959
--0.0721276
-0.290744
-0.0557513
--0.248632
-0.0536825
-0.296698
-0.53848
-0.109382
-0.0514202
-0.1378
-0.594377
-0.397463
-0.442078
--0.164625
-0.184501
-0.0499748
--0.0351085
-0.281598
-0.411051
-0.0701176
-0.0497435
-0.104011
--0.0892089
-0.0500708
-0.290263
-0.247262
-0.325035
-0.662477
-0.0521931
-0.0158127
--0.125117
-0.194367
-0.152355
-0.567164
-0.33964
-0.0521626
-0.189349
-0.313369
-0.390927
--0.279016
--0.109973
-0.199324
--0.123225
-0.202992
-0.337014
-0.457996
-1.03518
-0.742823
--0.000735208
-0.484322
-1.38201
-0.125221
-1.04366
-0.33845
-0.399636
-1.44521
-1.19171
-1.1498
-0.972687
-0.86561
-3.22461
-2.65832
-2.90638
-3.71703
-5.2332
-5.78658
-8.3124
-11.9426
-14.7
-18.0139
-29.3475
-44.1919
-67.2194
-35.68
-0.908823
--0.0864181
-0.0523807
--0.179802
-0
-0
-0
-0.150389
--0.0343987
-0
-0.135936
-0
-11.1751
-75.3342
-68.8803
-44.9521
-33.7139
-22.4353
-12.5071
-9.6255
-7.08922
-7.5412
-4.30918
-3.45339
-3.71269
-2.04234
-0.723885
-0.882514
-1.16809
-1.40171
-0.49428
-1.24665
-0.331762
--0.534775
-0.693184
-0.741912
-0.397851
--0.000789266
--0.160807
-0.303131
-0.489022
-0.492969
--0.0204202
-0.283409
-0.306081
-0.55766
--0.205463
-0.121535
--0.111539
--0.332315
-0.123471
--0.447625
-0.514119
-0.519178
-0.234121
--0.035849
-0.292027
-0.293616
-0.190186
-0.015335
-0.0694229
-0.197149
--0.0833852
-0.419258
--0.0861133
--0.297988
--0.0674948
--0.0340094
-0.149974
-0.327182
-0.0522006
-0.0690037
-0.238541
-0.256572
-0.248667
-0.0163645
-0.784401
-0.392304
-0.206125
-1.04584
-0.3481
-0.249672
-0.17091
-0.0676377
-0.304304
-0.250282
-0.598516
-0.165104
-0.0163685
-0.290465
-0.365494
-0.325836
-0.270197
-0.391631
--0.221331
--0.036825
-0.263172
-0.469245
-0.0724798
-0.0326371
--0.219167
-0.0191471
--0.315061
-0.310227
-0.220376
-0.088579
-0.476854
--0.426845
-0.978623
-0.960156
-1.34536
-1.22028
-1.48686
-1.04877
-0.60069
-2.46688
-2.39192
-4.40599
-3.67902
-5.59806
-9.21477
-9.93698
-13.4002
-20.8865
-26.6591
-41.1142
-54.3005
-66.1497
-17.5064
-0.571921
-0.307725
-0.144017
-0.157413
-0.149048
--0.0973058
-0.448961
-0.1475
-0.14692
-0.306455
-3.65834
-53.3524
-80.889
-56.7219
-42.8176
-26.6442
-19.4606
-13.398
-9.49199
-5.96807
-5.5816
-3.96626
-3.38134
-3.38416
-2.11377
-2.13636
-2.06288
-0.495499
-2.11331
-0.79547
-0.953152
-0.658704
-0.0720892
-0.299343
-0.156286
-0.580779
-1.24141
-0.318942
-0.0746697
-0.893612
-0.0336027
-0.258744
-0.640034
--0.0717558
-0.0707749
-0.397746
-0.64493
-0.299232
-0.564053
-0.107489
-0.512695
--0.0766926
-0.286884
--0.0369458
--0.320946
-0.256707
-0.103809
-0.343153
--0.208558
-0.345803
-0.0714006
--0.0367446
--0.0358932
--0.128155
-0.194151
-0.0507849
-0.183334
--0.0712461
-0.313909
-0.44402
--0.127609
-0.0665988
-0.0164741
-0.0189706
-0.0716221
-0.266017
-0.0524391
-0.144709
-0.120965
--0.185807
-0.338696
--0.387291
--0.0360989
-0.309529
-0.0506861
-0.24617
-0.25413
-0.2567
--0.0204956
-0.589873
-0.208035
-0.434465
-0.0495117
-0.0716532
--0.110431
-0.218003
-0.913505
--0.0554722
-0.476325
-0.495192
-0.68738
-0.104774
-0.439674
-0.280651
-0.165959
-0.656669
-0.154102
-0.290716
-0.36257
--0.219613
-0.179665
-1.11302
-0.950204
-1.00377
-1.53221
-3.29687
-2.76937
-3.51181
-5.03563
-5.9715
-11.5137
-12.9937
-19.3885
-25.8018
-35.1425
-44.5836
-66.5362
-60.3005
-22.4003
-0.620328
-0.150622
-0.148624
-0.418524
-0
-0.147667
-0.443849
-0.291798
-5.39337
-49.7856
-105.047
-70.4676
-50.5082
-35.3017
-23.5332
-14.5931
-14.7942
-9.38224
-6.25458
-6.1613
-3.64529
-2.88972
-3.62105
-1.76878
-1.87195
-1.03219
-1.01875
-0.873902
-0.558274
-0.911517
-0.0353414
-0.213635
-0.814523
-0.263188
-0.210066
-0.38177
-0.485681
-0.399972
-0.221469
-0.833572
-0.0552923
-0.178054
-0.310412
--0.304591
-0.28486
-0.249488
-0.948394
-0.158118
-0.746432
--0.0363564
-0.258033
-0.302667
--0.00079431
-0.0701514
-0.0709785
-0.316764
--0.267468
-0.707315
-0.202653
-0.107458
--0.214179
-0.562795
--0.181775
-0.10483
--0.201375
-0.0941955
-0.199779
-0.31791
-0.269465
--0.177897
-0.272616
-0.100267
-0.0518031
-0.197348
-0.198271
-0.0667967
-0.100683
-0.467248
-0.341706
-0.208488
--0.187773
-0.34267
-0.248934
-0
-0.159971
--0.177573
-0.105055
-0.804903
-0.196002
--0.0719094
-0.196336
-0.476242
-0.301295
--0.302897
-0.0703584
--0.321806
-0.370715
-0.456896
-0.315399
--0.0753032
--0.163223
-0.576986
-0.44903
--0.0749267
-0.517623
-0.375051
-0.583243
-0.985031
-1.04824
-0.378604
-0.731413
-0.397114
-1.96832
-2.66747
-2.18951
-1.85022
-1.929
-5.02618
-5.62177
-9.29788
-8.90093
-14.3108
-23.2399
-28.0707
-38.4062
-62.8237
-89.152
-87.8726
-44.877
-18.2699
-5.44736
-0.735917
-0.288267
-1.19748
-4.87681
-33.2514
-75.54
-107.989
-88.3062
-58.4379
-41.711
-27.8484
-19.5382
-15.6539
-9.5238
-8.48978
-5.30847
-4.31259
-3.3032
-2.9068
-1.87369
-0.464314
-2.07851
-1.36031
-1.13753
-0.589789
-1.20004
-1.41728
-0.171486
-0.809785
-0.629128
-0.147347
-0.464296
-0.70583
--0.113189
-0.508835
-0.31969
--0.220928
-0.214779
--0.0899373
-0.298493
-0.196584
--0.208641
--0.0213926
--0.0941732
-0.426383
--0.129942
-0.696427
-0.195636
--0.219099
--0.037258
-0.49185
-0.20309
-0.472385
-0.341422
-0.194542
-0.203184
-0.0519898
-0.301065
-0.29891
-0.126436
-0.101107
-0.263742
-0.150533
-0.136046
--0.0361648
--0.442105
-0.0541502
-0.50497
-0.107622
-0.4936
-0.0700608
-0.293138
--0.222816
-0.109903
--0.126913
-0.254411
--0.220156
-0.139702
-0.274814
-0.107083
-0.47772
-0.0698495
-0.0173576
-0.243849
-0.632146
-0.202087
-0.419186
--0.1137
-0.110548
--0.0361539
-0.365949
-0.367666
-0.0170136
--0.229686
-0.664027
-0.157059
-0.440966
-0.536799
-0.963366
-0.317312
-0.507473
-0.279247
-0.500227
-0.491745
-0.543906
-0.538817
-1.0763
-1.86818
-0.715448
-1.08026
-2.5803
-1.55358
-2.62794
-2.74249
-3.07235
-4.34565
-7.1529
-9.01798
-14.2807
-15.5972
-25.8081
-34.8363
-48.0019
-69.6284
-92.9836
-117.213
-111.108
-102.699
-70.5639
-65.6269
-81.3719
-114.579
-132.107
-125.748
-88.0704
-66.8916
-47.3922
-36.6418
-21.9239
-16.0188
-13.4174
-10.4997
-6.34234
-4.76208
-4.06389
-2.33081
-2.937
-2.13853
-2.19723
-0.980993
-1.0688
-1.35669
-1.46632
-0.379331
-1.15644
-0.111463
-0.707082
-0.600796
-0.353438
-0.378508
-0.123969
-0.69028
--0.0775865
-0.220009
--0.105709
-0.382311
-0.552415
-0.24819
-0.457283
-0.387611
-0.111351
-0.249835
-0.103255
--0.163809
--0.190638
--0.0753809
--0.128795
--0.0205418
--0.0765163
--0.222771
-0.252171
-0.0529215
-0.0161127
-0.288197
--0.126308
--0.129233
-0
-0.241206
-0.101089
--0.0342258
-0.226585
-0.528379
-0.0501627
-0.639558
-0.103438
--0.17046
--0.118829
-0.0500012
-0.0474115
-0.14385
-0.437427
-0.33772
-0.0694102
-0.4909
-0.262663
-1.02526
-0.0998477
--0.129583
--0.120313
-0.067968
--0.123346
-0
--0.0696419
-0.516273
-0.609903
-0.8514
-0.142582
-0.0540764
-0.588711
-0.622974
-0.568624
-0.638769
--0.0690523
--0.091959
-0.213352
-0.127839
-0.210491
-0.896043
-0.432669
-0.631088
--0.530025
-1.11682
--0.0588599
-1.1005
-0.545333
-0.0162606
-1.01051
-1.37434
-1.65911
-2.20902
-1.98216
-3.65255
-3.40973
-4.02828
-6.59323
-8.77705
-12.3646
-17.2385
-19.697
-26.006
-37.1857
-45.8979
-67.9064
-84.971
-107.234
-125.354
-142.246
-155.049
-145.499
-132.968
-103.378
-82.0943
-68.0644
-52.1568
-32.8318
-31.2972
-20.0682
-14.7948
-11.8312
-10.5734
-6.55831
-3.8467
-4.56175
-3.03739
-2.12017
-2.20918
-1.90188
-2.40342
-0.724243
-0.981115
-0.279881
-0.504073
-0.877509
-0.383775
--0.114907
-0.537257
-0.690342
--0.0220133
-0.447072
-0.652574
-0.217888
-0.721542
-0.0679622
-0.527312
--0.0368219
--0.31977
-0.169136
--0.17998
-0.166371
--0.219959
-0.438543
-0.567165
-0.171723
--0.0942825
-0.105366
-0.436518
--0.176941
-0.421956
-0.344962
-0.198658
-0.380887
-0.108608
-0.207759
-0.350031
--0.0682012
--0.123414
-0.0651963
-0
--0.340903
-0.0668549
--0.0192085
--0.173055
-0.430163
--0.0358524
-0.249423
--0.175499
-0.392817
--0.412566
--0.259261
-0.107638
-0.28463
-0.353858
-0.502401
-0.167504
-0.208212
-0.519016
-0.28416
--0.348326
-0.247604
-0.34225
-0.144405
--0.285721
--0.174962
--0.130678
-0.176477
--0.0365101
--0.0745179
--0.272432
-0.0545702
-0.47304
-0.126452
-0.0162879
-0.0688002
-0.0712228
-0.309477
-0.036205
-0.169581
-1.31279
-0.657224
-0.278842
-0.948583
--0.168351
-1.67004
-0.999613
-1.08985
-2.16544
-1.32133
-2.07816
-1.81712
-2.89965
-3.54721
-5.50848
-5.92017
-9.38406
-8.72786
-14.4387
-16.7867
-24.6798
-30.8696
-39.5991
-50.808
-64.479
-84.7659
-97.5682
-102.924
-105.782
-101.612
-95.2066
-81.5194
-70.7925
-48.7407
-41.5865
-31.307
-25.1729
-15.8032
-15.8709
-10.8237
-9.68921
-5.12815
-3.86593
-3.39825
-2.14832
-2.07905
-2.38525
-1.44816
-0.955379
-1.14406
-0.713064
-1.31678
-0.571548
-0.460604
-0.489281
-0.923539
-0.219342
-0.626613
--0.155534
-0.0700343
-0.485359
-0.731701
-0.247469
-0.574612
-0.164728
-0.211771
--0.21858
-0.258443
-0.112338
--0.166423
-0.195158
-0.100885
-0.257206
-0.339789
-0.907576
-0.293091
-0.0530648
-0.329079
--0.101759
-0.0716455
-0.0161918
-0.678164
--0.396866
--0.207917
-0.134874
-0.0161377
-0.194384
-0.595053
-0.315907
--0.168348
--0.153754
-0.0495382
--0.206155
-0.157863
--0.0353196
-0
--0.107939
-0.0187503
--0.200364
--0.12133
--0.0868214
-0.0154809
-0.151477
-0.266812
-0.0714015
--0.295561
--0.0391219
-0.193582
--0.0365553
-0.589044
-0.157114
-0.189102
--0.306673
--0.0687168
-0.211624
-0.412797
-0.584639
-0.0692041
--0.125651
-0.276415
--0.233127
--0.0701691
-0.199804
-0.775647
-0.139801
-0.653503
-0.164553
-1.31382
-0.464029
--0.192731
-1.39433
-0.261838
-0.499202
-0.518315
--0.309747
-1.2108
-0.924411
-2.0925
-1.61816
-2.09409
-3.22088
-2.82914
-3.31721
-3.94424
-5.6841
-7.10261
-9.0332
-13.3412
-15.5287
-21.5418
-26.6065
-37.1032
-48.1763
-50.4133
-67.9023
-61.0515
-71.3033
-67.4726
-62.4381
-62.8743
-44.5925
-43.0679
-35.0741
-21.4298
-18.5855
-18.3831
-8.19305
-7.60601
-7.43799
-5.05154
-4.61489
-1.54035
-1.23489
-1.1927
-2.04138
-0.406951
-1.36707
-1.63246
-0.503417
-1.0938
-0.553645
--0.259946
--0.101907
-0.106655
--0.114291
-0.378645
-0.391324
-0.388228
-0.448537
--0.161365
-0.0750774
-0.649711
-0.617679
-0.264909
-0.941306
-0.217626
-0.25713
-0.528438
--0.176878
-0.307056
--0.372513
-0.247111
-0.621657
-0.107019
--0.176638
--0.125503
--0.199995
--0.265998
-0.0522421
--0.180463
-0.268316
-0.20298
-0.633145
-0.103208
-0.0518159
-0.326229
--0.0353574
--0.33778
-0.052658
-0.555663
-0.0524323
-0.19751
-0.324329
-0.0546376
-0.138012
-0.199279
-0.501824
--0.016539
-0.144512
-0.281716
-0.207563
-0.157964
--0.0175956
-0.0185873
-0.273545
--0.0364677
-0.647273
--0.223237
-0.900806
-0.016911
--0.282007
-0.203995
-0.19922
-1.0095
-0.10586
-0.0161915
-0.0533104
-0.165208
--0.0558173
-0.18811
--0.0201598
-1.236
-0.556822
-0.460111
-0.668662
-0.743065
-0.729885
-0.568648
-0.242182
--0.058756
-0.0325321
-0.902896
-0.734065
-1.12935
-1.50994
-0.735464
-1.04354
-2.49857
-2.3844
-3.19718
-2.75238
-3.21324
-4.77222
-7.39935
-7.20791
-12.727
-15.5821
-18.0025
-23.5414
-27.5226
-35.5867
-43.8972
-45.6149
-51.2064
-47.8063
-49.7642
-48.6518
-43.2972
-33.2861
-29.569
-23.0451
-17.1474
-15.4249
-13.1981
-8.72165
-6.34755
-6.08051
-3.7536
-4.37949
-2.34096
-2.52669
-2.01724
-1.95549
-0.733068
-0.606176
-1.49679
-0.605691
-1.45511
-0.316312
-0.710847
-1.66997
-0.515703
--0.377422
-0.0682133
-0.23125
-0.594065
-0.261781
-0.198723
--0.0555172
-0.6595
-0.25447
--0.108285
--0.403781
-0.556807
--0.126569
-0.358953
-0.845958
-0.309556
-0.199345
-0.352224
--0.037545
-0.199097
-0.436093
-0.160523
-0.397413
-0.341627
-0.714355
-0.0528932
-0.432448
--0.0375953
-0.152034
--0.0721679
--0.069701
-0.104583
-0.0482083
-0.303679
--0.168555
-0.014747
-0.71988
--0.121145
--0.0165834
-0.218047
-0.234634
-0.154791
-0.056708
-0.241282
-0.341337
-0.0510592
-0.475803
-0.18882
-0.0163647
--0.121861
-0.43428
--0.036541
-0.209745
-0.192023
-0.283054
--0.0206244
-0.32625
--0.034453
--0.326811
-0.305998
-0.104514
--0.021698
--0.0745538
-0.248988
-0.510053
-0.338552
-0.386005
-0.773253
-0.447826
-0.0688651
-0.305485
--0.0752164
-0.0348052
-0.433297
-0.12221
-0.910323
-0.0327428
-0.464218
-0.77774
-1.60463
-1.374
-1.1322
-1.60959
-0.984528
-2.3052
-3.0947
-3.53287
-3.95129
-2.47933
-7.4072
-9.1878
-8.11545
-12.2098
-12.8929
-18.4222
-21.4922
-25.7291
-25.1599
-32.614
-38.1183
-40.4878
-37.7824
-35.3467
-30.7856
-25.2959
-18.299
-18.9903
-15.6027
-11.8023
-8.48635
-6.51414
-3.97971
-4.07644
-3.72901
-2.62228
-1.46801
-1.87834
-0.612193
-1.70699
-1.26215
-0.525923
-0.380812
-0.704845
-1.10332
-0.517002
-0.345526
-0.660313
-0.264816
-0.439566
-0.317735
-0.563132
-0.507194
-0.0348603
-0.256159
-0.358944
--0.03604
-0.942041
--0.01978
-0.401104
-0.161447
-0.252871
--0.400963
-0.216095
-0.245974
-0.262306
--0.0705473
-0.395043
-0.24568
-0.0704829
-0.381969
-0.386206
-0.451647
-0.293251
-0.0190646
--0.124953
--0.033016
-0.274026
--0.120234
-0.19148
--0.0325797
-0.187196
--0.0858333
-0.247235
-0.112268
-0.194582
-0.0203823
-0.0160215
--0.128754
-0.103044
-0.0706885
-0.311822
-0.336593
-0.0551702
--0.186856
-0.342406
--0.17507
-0.2065
-0.154781
--0.0740917
--0.0935522
-0.05117
-0.0555422
--0.163878
--0.0736896
-0.0169619
-0.474814
-0.617075
-0.540779
-0.158226
-0
-0.033903
-0.397144
--0.331754
--0.300547
-0.202191
-0.0709206
-1.08249
-0.16446
-0.323875
-0.212029
--0.0211393
-0.304578
-0.597564
-1.25368
-0.623105
-1.37341
-0.0950758
-0.299668
-0.700499
-0.898364
-2.50702
-1.1415
-1.33279
-2.95025
-2.36994
-2.60967
-3.89509
-3.34824
-4.19109
-7.38636
-9.61286
-13.6002
-14.9733
-16.3316
-20.0749
-23.4771
-23.542
-27.8194
-29.5849
-26.8924
-23.8994
-20.509
-21.9024
-18.3634
-12.7894
-9.80043
-9.20142
-6.55838
-6.75025
-4.79712
-4.4874
-3.82681
-3.07359
-1.95383
-2.24789
-1.32975
-0.640887
--0.227422
-1.26657
-0.190953
-0.539296
-0.457405
-0.395549
-0.581568
-0.760884
--0.211357
-0.339902
-0.0160388
--0.166641
-0.507226
--0.0369785
-1.15475
-0.489136
-0.339079
-0.169437
--0.304301
-0.598668
--0.218618
--0.0565268
-0.518058
-0.760186
--0.268664
-0.249622
-0.400922
--0.130843
--0.129535
-0.0531656
--0.0356608
-0.0524083
--0.268945
-0.428957
-0.269074
-0.204623
--0.0362958
--0.266638
-0.260698
--0.0350522
-0.281377
-0.510377
--0.0328082
-0.134439
-0.0519553
--0.119471
-0.316847
-0.281624
-0.193583
--0.0335632
-0.37965
-0.0565078
-0.279027
-0.0687372
-0.0154806
-0.0539544
-0.309747
-0.195788
--0.123177
-0.175101
--0.118691
-0.466419
--0.26921
--0.0744
-0.0702262
-0.281564
-0.45663
-0.181816
-0.50802
-0.160771
-0.106146
--0.217794
-0.0723302
-0.0697448
-0.33775
--0.130941
-0.632122
-0.558356
-0.0325003
-0.542899
-0.679579
-0.594207
-0.869372
-0.162993
-0.0358339
-1.68821
-1.04969
-0.402393
-1.21521
-1.33281
-0.798912
-0.209043
-1.49482
-2.13533
-2.88486
-2.95992
-1.00953
-2.5941
-5.21899
-4.73644
-5.83743
-6.1755
-9.4652
-10.1319
-10.0568
-14.4606
-18.2822
-15.9208
-19.8189
-19.1166
-23.3878
-15.2213
-18.3762
-12.3449
-13.7731
-9.29785
-9.56201
-5.50369
-4.94405
-3.20638
-2.95328
-4.12922
-3.25502
-2.48738
-0.822915
-1.51861
-1.87946
-0.809698
-0.843276
-0.718499
-0.939136
-1.00368
-1.23446
-0.433938
--0.399487
-0.971518
--0.0579902
-0.176057
-0.347252
-0.300889
-0.420186
-0.508479
-0.347677
--0.185269
--0.0729899
-0.319545
-0.20304
-0.111844
-0.0538223
--0.16187
--0.21735
--0.170049
-0.56304
-0.0203306
--0.0723616
--0.0722672
-0.480316
-0.256148
-0.0521341
-0.0160976
-0.0533839
--0.0367864
-0.378732
-0.313424
-0.337277
-0.0503648
-0.0525827
-0.441262
-0.670233
-0.182282
-0.0549145
-0.337563
-0.168724
-0.178818
-0.202416
-0.132717
-0.0569381
-0.286454
-0.109783
-0.251706
-0.252093
-0.281107
-0.490792
--0.13258
-0.0169785
-0.345298
-0.194317
--0.131058
--0.273452
-0.135678
-0.359597
--0.0161675
--0.0770973
-0.302455
--0.128329
--0.0369588
-0.249332
-0.350388
-0.424426
-0.166514
-0.268098
-0.176237
-0.249518
-0.174771
-0.393815
--0.0206126
-0.109254
-0.219883
-1.61376
-0.0324888
-0.426673
-0.128801
-0.0710524
-1.10618
-0.246889
-0.168565
-0.77596
-1.35349
-1.14667
-1.11816
-1.14613
-0.973568
-1.6906
-1.75287
-3.25253
-4.13558
-3.45872
-2.78319
-5.48723
-6.30232
-5.36105
-7.54626
-9.94354
-8.55725
-10.3301
-12.1679
-16.6186
-11.4733
-13.675
-11.5995
-10.7191
-7.83463
-9.98105
-8.11523
-9.35893
-5.16357
-5.35832
-3.3812
-3.80289
-1.40143
-2.82325
-1.28811
-1.62285
-2.21471
-0.739119
-1.33068
-0.986908
-0.514298
-1.38809
-1.18239
-0.433678
-0.58671
-0.455546
-0.337333
-0.15806
--0.193352
--0.397694
--0.224838
--0.115481
-0.895423
-0.815558
-0.44286
-0.101928
-0.768654
-0.190999
-0.663948
-0.166856
-0.0693593
-0.739791
-0.184528
-0.607287
-0.105517
-0.537136
-0.4711
-0.28433
-0.331456
-0.253091
-0.101852
-0.0196998
--0.163359
--0.0749554
-0.193968
-0.139246
-0.0490153
-0.166961
-0.0502769
-0.131812
-0
-0.090207
-0.289886
--0.200071
-0.194715
-0.070056
-0.183535
-0.393078
--0.0739344
-0.0672587
--0.0375383
-0.147706
-0.197144
-0.462964
--0.03955
-0.155674
-0.111485
-0.545505
-0.20738
-0.24098
-0.104317
-0.0533267
--0.0889462
-0
--0.136074
--0.01712
-0.114266
-0.0365119
-0.336717
-0.557972
--0.0822991
-0.209128
--0.138756
-0.108098
-0.371103
-0.250986
-0.316775
--0.22691
--0.232604
--0.178281
-0.451075
-0.301071
-1.46736
-0.436879
--0.0170782
-0.567314
-1.09358
-0.818754
-0.237465
-1.36465
-0.992225
-0.997526
-0.399677
-2.64694
-1.012
-2.77689
-2.66943
-1.33999
-4.71275
-2.7927
-5.34739
-4.38428
-5.39634
-6.07932
-8.57073
-10.4849
-8.7671
-7.22172
-11.1404
-9.3981
-10.7475
-8.02111
-8.07256
-7.11798
-6.99785
-5.58849
-4.68398
-5.08163
-3.82937
-3.11811
-2.19276
-1.79876
-0.444318
-1.54084
-0.762273
-0.994271
-0.818298
-1.14373
-0.907684
-1.51047
-1.1044
-0.492881
-1.06977
-0.218125
-0.852158
--0.184744
-0.16967
-0.240764
-0.790155
-0.205713
-0.605885
-0.72083
-0.336843
-0.0161507
-0.256817
-0.0523535
-0.126174
-0.604932
-0.203401
-0.181206
-0.0177661
-0.0368916
-0.351236
-0.25375
--0.0213049
--0.128714
-0.114694
-0.34399
-0.290882
-0.19614
--0.0374541
-0.0508309
-0.434788
-0
-0.245747
--0.155242
--0.213028
-0.015802
-0.199153
--0.0937856
-0.291873
--0.213665
-0.106962
-0.438766
--0.0674683
--0.13598
--0.257223
-0.0554445
-0.0716281
-0.329972
-0.140855
--0.180227
-0.199811
-0.0707778
-0.490243
-0.20563
--0.167667
-0.0173355
-0.160505
-0.585336
-0.240336
--0.0386042
-0.347033
-0.249917
--0.129374
--0.126092
--0.124533
-0.450411
-0.0194697
-0.775361
--0.0198523
-0.46018
-0.697235
-0.518266
-0.0168544
-0.302635
-0.594807
-0.283273
--0.0572761
--0.0209804
-0.35495
-0.96379
-1.43833
-0.263272
-1.17548
-0.979889
-0.610681
-0.689646
-1.063
-1.34899
-1.57378
-1.43201
-1.4092
-1.76966
-3.52313
-2.44893
-4.50657
-5.09581
-3.23515
-4.5358
-4.80759
-4.04637
-6.31799
-7.91056
-6.66767
-7.18325
-7.14531
-8.81155
-7.21045
-7.74953
-6.09617
-7.53472
-4.3961
-4.52232
-4.57472
-3.39803
-2.4732
-1.69867
-1.82371
-1.44415
-1.32324
-1.53442
-0.206059
-1.6658
--0.278677
-0.635494
-1.35013
-0.661422
-0.824947
-0.888959
--0.0377977
-0.928412
-0.275049
-0.25312
--0.110049
-0.542983
--0.213231
-0.264694
-0.0171089
-0.16461
-0.565249
-0.339512
-0.306589
-0.666846
-0.753028
-0.277598
-0.156223
--0.0382834
-0.0534952
-0.365035
-0.690907
-0.168309
-0.248161
-0.122153
--0.28622
-0.256877
-0.334291
-0.157961
-0.346755
--0.173237
--0.125928
--0.370918
-0
-0.157614
--0.0853508
-0.294774
-0.148469
-0.187229
-0.294805
-0.318786
-0.0505168
-0.388168
-0.0493543
-0.0497259
-0.105315
-0.479797
-0.255426
-0.434442
-0.0158253
-0.0479771
-0.137498
-0.185346
-0.107425
-0.254892
--0.0380505
--0.035244
--0.5113
-0.0158523
-0.286615
-0.473616
-0.105608
--0.342554
-0.444316
--0.0907515
-0.248869
-0.342483
--0.223459
-0.0188159
--0.188164
-0.19044
-0.0719497
-0.494805
-0.296036
-0.206264
-0.965665
-1.11062
-0.391306
--0.0200036
-0.319498
-0.122501
-0.554551
-1.10824
-0.645336
-0.972282
-0.559605
-0.948308
--0.333596
-1.10095
-0.308209
-0.731643
-1.37035
-1.93472
-2.45625
-2.49318
-2.94841
-2.08485
-3.91584
-4.40361
-3.98635
-4.41853
-6.4607
-5.98839
-4.29902
-5.12391
-5.7335
-5.83725
-6.73542
-4.19031
-4.56027
-3.55672
-3.51358
-2.87876
-3.51097
-2.48032
-2.39604
-3.12523
-1.97328
-1.41884
-2.12413
-0.700418
-1.28512
-1.21624
-0.948911
-0.373972
-0.928059
--0.150073
-0.457217
-0.450637
-0.558341
-0.33167
-1.06996
-1.55222
-0.0752602
-0.420546
-0.267352
-0.808895
-0.108858
-0.279155
-0.054851
-0.154851
-0.0572612
-0.322242
-0.110749
-0.495307
-0.128765
-0.353554
-0.0576512
-0.0517015
-0.144409
-0.0543733
--0.0182172
-0.257796
--0.0377635
-0.250825
--0.0924627
-0.200288
--0.276887
-0.0701125
-0.454501
-0.158985
-0.339671
--0.0887131
--0.247984
-0.284564
-0.100807
--0.0193307
-0.0716583
-0.258325
--0.0348023
-0.10707
-0.0526481
-0.150167
-0.321232
-0.18894
-0.46549
-0.4839
--0.205386
-0.0725638
-0.0550452
-0.255639
-0.108479
--0.25068
--0.294096
-0.38402
-1.07582
-0.353644
-0.197202
-0.108266
--0.0376202
--0.0392404
-0.339373
-0.169907
--0.0375351
-0.0170285
-0.210269
-0.250291
-0.394509
-0.375635
-0.346961
-0.462361
-0.467429
-0.0172527
-0.275692
-0.468274
-0.643781
-0.731074
-0.392814
--0.108263
--0.0553015
--0.259181
-0.726739
--0.114033
-1.39747
-0.528947
-1.29132
-0.870807
-1.4197
-1.30706
-1.67998
-2.18053
-0.96743
-2.12024
-1.85388
-1.43581
-2.33319
-2.26883
-3.76297
-3.24708
-4.0411
-4.43489
-5.04881
-3.42357
-2.56042
-3.71056
-4.70092
-3.73247
-2.6604
-4.08925
-3.72318
-3.79417
-3.95255
-1.20633
-2.0191
-2.51866
-1.23102
-1.53415
-0.198552
-1.93527
-0.135129
-0.842935
-0.109294
-0.472096
-0.633369
-0.782592
--0.00406978
-0.313789
-0.182886
-0.317624
-0.838964
-0.175059
-0.112668
-0.264861
-0.268984
-0.493981
--0.0209805
-0.712288
-0.258497
--0.130491
-0.475463
--0.128953
-0.199973
-0.52826
-0.390869
-0.147298
-0.332883
-0.734597
--0.492678
-0.163595
--0.368351
--0.312439
-0.201546
-0.109168
-0.446102
-0
-0.0526215
--0.360236
--0.036898
-0.580563
-0.142014
-0.289955
--0.0366465
--0.0168961
-0.186746
--0.11175
-0.145111
-0.644119
-0.321642
-0.12343
-0.422575
-0.104476
-0.6031
-0.0166257
-0.0172318
--0.122047
--0.0377667
-0.292599
-0.49198
-0.158321
--0.201954
--0.0348631
--0.186513
-0.427552
--0.213922
-0.0557993
-0.439509
--0.0366143
-0.112607
-0.0531278
--0.219108
--0.367759
--0.188835
--0.221565
-0.147739
--0.036311
-0.301509
-0.349197
-0.398497
-0.48139
-1.04477
--0.0175191
-0.516162
-0.63335
--0.07267
--0.12387
-0.975371
-0.319606
-0.747603
-0.918587
--0.0776847
-0.785954
-0.888763
-0.676246
-1.05349
-1.40519
-1.13994
-0.959952
-1.41084
-1.01139
-0.167619
-1.81929
-1.81821
-1.97028
-3.19577
-2.32465
-3.96038
-3.66712
-3.09066
-3.01215
-3.3323
-3.33151
-4.16949
-3.36613
-4.17579
-3.75616
-4.79563
-2.66017
-3.2003
-0.494139
-1.81911
-1.65828
-0.56147
-2.38183
-2.14645
-1.36804
-0.509546
-1.04789
-1.18289
-1.66867
-0.703627
-0.604925
-1.16424
-0.425338
-0.0874581
-0.378535
--0.0556984
-0.260449
-0.309302
--0.0758399
--0.0798718
-0.990589
--0.0220878
-0.505914
--0.220276
-0
-0.203697
-0.307615
-0.294161
--0.28943
-0.143266
-0.103926
--0.27378
-0.343835
-0.894029
-0.587619
-0.494755
-0.160427
-0.0168266
--0.0881781
-0.398484
--0.0900249
-0.291964
-0.195348
-0.0165596
-0.188013
--0.130166
-0.0191525
-0.10667
--0.127867
-0.107956
-0
--0.151025
-0.423029
--0.0364948
--0.126289
-0.235521
--0.0896315
-0.10482
-0.311134
-0.333578
--0.253201
-0.105296
--0.0704842
-0.342771
-0.566736
--0.220751
-0.316983
--0.0729269
-0.454636
-0.263078
-0.198816
--0.0364007
--0.0384942
--0.0192359
-0.350329
-0.448606
--0.138723
-0.447054
-0.308211
--0.206095
-0.458005
-0.286208
-0.293189
-0.0768413
--0.0931922
-0.10566
-0.0564432
--0.0383279
--0.0898867
-0.185457
-0.254101
--0.0770752
-0.126223
-0.281681
-0.0165739
-0.22141
-0.366789
--0.416039
-0.0328783
-0.258704
-0.843738
-0.753771
-0.626298
-1.22559
-1.3518
-0.391347
-0.0341779
-1.29308
-1.39896
-1.10246
-1.13009
-2.00667
-0.903107
-3.08038
-2.62103
-3.49934
-3.22412
-2.33555
-2.73395
-1.25518
-2.77391
-3.02281
-3.88958
-2.39717
-1.62362
-2.9873
-2.0603
-1.78139
-1.25607
-1.84974
-0.712132
-0.592482
-1.27448
-1.55747
-0.935361
-0.408951
-0.999319
-0.0707258
-0.528123
-0.49968
-0.867794
-0.209927
-0.599227
-0.068632
-0.123451
-0.849525
--0.0711912
-0.175472
-0.15803
-0.162066
-0.304883
-0.54833
-0.346995
-0.719175
-0.329701
-0.293112
-0.514297
-0.738604
-0
-0.101887
-0.071504
--0.036902
--0.0170284
--0.0209051
--0.0368581
-0.338241
--0.205889
-0.472595
-0.624915
-0.0507066
-0.0705055
--0.0362812
-0.336566
-0.246515
-0.479845
-0.157896
-0.0532283
-0.413467
-0.175144
-0.157921
-0.221301
-0.14847
-0.237299
-0.417324
-0.150647
-0.364021
-0.413492
-0.245704
--0.0693487
-0.146982
-0.100957
-0.1241
-0.273166
--0.185003
-0.0524559
--0.0390526
-0.102552
-0.110773
-0.0151239
--0.133419
-0.353741
-0.717691
--0.176212
-0.521266
-0.0527667
-0.0172921
-0.141493
--0.075601
--0.128118
-0.419164
-0.388202
-0.328363
-0.659313
--0.134874
-0.245423
-0
-0.131156
-0.623109
-0.0329366
-0.275148
--0.106113
-0.851099
-0.543528
-0.33708
-0.384248
-0.362352
-0.221116
-0.328816
-0.563401
-1.03187
--0.198267
-1.31379
-0.748293
-0.678698
-1.22135
-2.11651
-1.25472
-1.13176
-2.50114
-2.64499
-2.10839
-2.83766
-1.79905
-2.78261
-1.71839
-1.9045
-2.13843
-2.08775
-2.58603
-2.12634
-1.43618
-2.17615
-1.40913
-1.68603
-1.97458
-1.74861
-0.400619
-1.58582
-1.54659
-1.79805
-1.32152
-0.413247
-0.478197
-0.360443
-0.72946
-0.75863
-0.334777
-0.491854
-0.39031
-0.995505
-0.248211
-0.98006
--0.162754
-1.17158
-0.57718
-0.0331831
-0.0151998
-0.0732727
-0.406855
--0.0924174
-0.133524
-0.160734
-0.15562
--0.19608
-0.252269
--0.39309
-0.0203956
-0.769257
-0.020346
-0.351045
-0.215689
-0.585834
--0.0901102
-0.365294
-0.543433
--0.0921987
-0.239909
-0.26728
-0.0534137
-0.253936
--0.037535
--0.12723
--0.211873
-0.274516
--0.0358897
--0.0885237
-0.320778
--0.115686
-0.103778
-0.419588
-0.348545
-0.621727
-0
-0.362523
-0.252916
-0.523065
-0.145216
--0.176913
-0.0163759
-0.615957
-0.0202581
-0.447098
--0.0908715
-0.104028
-0.334633
-0.111625
-0.0533512
-0.288676
-0.107829
-0.0536611
-0.0172274
--0.0930168
--0.180924
-0.0174408
--0.12151
-0.0165499
-0.0200983
-0.295581
-0.24771
-0.504446
-0.250241
-0.287294
-0.393902
-0.261666
--0.222206
-0.590939
-0.533601
-0.215921
-0.0359455
--0.185244
-0.326123
-0.505628
-0.521905
-1.00513
-0.804384
-1.06398
--0.0594241
-0.791313
-0.70524
-0.614334
-0.412823
-0.792761
-1.52821
-1.6479
-1.35344
-1.26378
-1.44106
-0.894531
-0.877513
-2.33772
-2.47329
-2.41236
-2.61772
-2.16934
-1.18114
-1.12568
-1.33626
-2.25692
-2.47387
-1.17919
-1.94036
-1.69789
-1.85894
-1.46763
-0.0742167
-0.613372
-1.66256
-1.52885
-1.1286
-1.30874
-0.74735
-1.31266
-0.557396
-0.743193
-0.300471
-0.617156
-0.927527
--0.162198
-0.393319
-0.217636
-0.312162
-0.381791
-0.545045
-0.34628
-0.974049
-0.31334
-0.0528404
-0.326248
-0.549697
-0.199755
-0.761461
--0.0689202
--0.164444
-0.340994
--0.187194
-0.486719
-0.496102
--0.204297
--0.305975
--0.158288
-0.199498
-0.273661
-0.398791
-0.196255
-0.141245
--0.377078
--0.0385382
--0.019678
-0
--0.180387
-0.29132
--0.0361835
-0.191215
--0.0886448
--0.17325
--0.120362
-0.109786
-0.332251
--0.121155
-0.243188
--0.0360958
-0.237442
--0.177778
-0.016191
-0.0632891
--0.130999
-0.11485
-0.582277
--0.0348078
-0.641928
--0.170194
-0.292105
-0.443714
-0
--0.0882214
-0.447919
-0.192299
-0.109395
-0.489102
-0.0732148
-0.324704
-0.507547
-0.202026
-0.253623
--0.401629
--0.115413
--0.0172328
--0.137215
-0.105585
-0.255519
-0.105888
-0.0163022
-0.660247
-0.122998
-0.0879216
--0.075514
--0.162143
-0.585098
-0.621701
-0.430863
-0.474172
-0.779284
-0.00229672
-0.0718032
-0.685137
-0.677861
-0.0380632
-1.33431
-0.643757
-0.409346
-0.346285
-0.126347
--0.00375744
-0.854626
-0.290912
-1.04933
-1.15278
-1.41252
-2.6548
-1.45939
-0.797472
-0.665286
-2.34943
-1.99284
-1.84777
-1.63939
-2.38634
-2.48898
-1.18332
-1.91446
-0.563548
-1.64488
-1.28323
-0.51777
-0.0698826
-0.800647
-0.807858
-0.202782
-1.36244
-0.857616
-0.998004
--0.117698
--0.0724306
-0.308641
-0.171938
-0.715496
-0.0165897
-0.701516
--0.130489
--0.175371
--0.220176
-0.640281
--0.246735
-0.133248
-1.04941
-0.55436
--0.209343
-0.113305
-0.101797
-0.0201163
--0.0684896
--0.0375366
-0.0524725
-0.301418
--0.211709
-0.341182
-0.504197
--0.377549
-0.249075
-0.549374
-0.189775
-0.290229
-0.544521
-0.0522068
-0.0357413
--0.038121
-0.345856
--0.036476
--0.0367526
--0.0364
-0.101089
--0.18507
--0.0337881
-0.0179047
--0.0907782
-0
--0.182515
-0.100936
-0.105597
-0.103974
--0.184177
--0.169195
-0.109139
--0.136191
--0.0359301
-0.278084
--0.0371773
-0.486143
--0.127271
-0.339495
--0.0866963
-0.249971
-0.722971
-0.140882
-0.436948
-0.289424
--0.219928
-0.180602
-0.195924
-0.0374316
-0.0563763
-0.0512746
--0.110966
-0.39982
--0.252717
--0.171765
--0.264067
-0.201819
--0.0911622
-0.467057
--0.185966
-0.343166
-0.262015
-0.106605
-0.222896
-0.21624
-0.540423
-0.210984
-0.108713
-0.482619
-0.602657
-0.587351
-0.226216
-0.186111
-0.419375
-1.19524
--0.301639
-0.827947
-1.16594
-0.876142
-0.56671
-1.1527
-1.10838
-1.21268
-0.829976
-1.12552
-1.54286
-2.47639
-2.0682
-1.4188
-1.78958
-2.10179
-1.3209
-1.65431
-1.17848
-1.55494
-1.9284
-0.595321
-1.55497
-1.33356
-1.0374
-0.468375
-0.765571
-0.0691419
-1.18885
-0.891531
-0.725089
-1.02229
-1.37756
--0.442656
-0.803247
-0.173201
-0.0356643
-0.526436
--0.0980102
-0.542648
-0.272222
-0.497394
-0.158144
--0.569323
-0.450032
-0.0167322
-0.259015
-0.245025
-0.712359
--0.0377987
-0.0519328
--0.130945
-0.206605
--0.111682
--0.0907985
-0.399191
--0.258659
-0.428787
-0.0514295
-0.250316
--0.0367882
-0.110135
-0.732177
-0.333819
-0.253892
-0.105012
--0.0370562
-0.0169048
-0.108079
-0.0162965
-0.152166
-0.015607
-0.24733
--0.301632
--0.180637
-0.313642
--0.363934
-0.197147
-0.333121
-0.288614
-0
--0.0699174
-0.0193621
--0.0358472
-0.104675
-0
-0.298624
-0.0192778
-0.0712014
-0.490575
--0.263734
--0.0397563
--0.416263
-0.275864
-0.169254
--0.19858
-0.356175
-0.292839
-0.0159624
--0.0376396
-0.296198
-0.042425
--0.200544
-0.017502
-0.386695
-0.0535079
-0.198158
-0.598487
-0.301319
-0.0175658
-0.534217
-0.0695694
-0.513649
-0.263992
-0.721252
-0.559348
--0.0705785
-0.264366
-0.507568
--0.125789
-1.39814
-0.357066
-0.610961
-0.473654
-0.510852
-0.585648
-0.664477
-0.797049
-0.98926
-0.578227
-0.595716
-1.02205
-0.693719
-0.75294
-0.801282
-1.13905
-0.963816
-0.662644
-1.70126
-0.97135
-1.00845
-0.954407
-1.21233
-1.00814
-2.09535
-0.548573
-0.781777
-0.833476
-1.61841
-0.860454
-1.22912
-1.24239
-1.09416
-1.67701
-1.22283
-0.811939
-0.701083
-0.995546
-0.650772
-0.0171926
--0.0039378
-1.04889
-0.545214
-0.038218
-0.405516
--0.26371
-0.590375
-0.653363
-0.271387
-0.544397
-0.643164
-0.208233
-0.243556
--0.0384579
--0.127342
--0.186115
--0.128736
--0.112582
-0.406424
-0.168661
--0.119039
-0.600859
-0.196111
-0.391931
--0.32204
-0.701269
-0.154614
--0.0375565
-0.241267
--0.188339
-0.270285
--0.211231
-0.103948
--0.0883773
-0.347888
--0.172349
-0.132452
-0.281686
-0.29019
--0.0907479
-0.442232
-0.303176
-0.0501007
--0.122002
--0.0360591
-0.0166468
--0.208444
--0.120949
-0.161285
-0.363008
-0.02103
-0.273
--0.0861732
-0.291535
--0.0202345
--0.121616
-0.0187814
-0.107347
--0.123887
-0.0197784
-0.201621
-0.10965
--0.213738
-0.0155249
-0.268547
-0.246963
-0.143887
-0.0552103
-0.154019
-0.016869
-0.0548673
--0.0890783
--0.133203
-0.285671
-0.193045
-0.104027
-0.397772
-0.159034
-0.439729
--0.0704491
-0.199653
--0.0706716
--0.155692
-0.411763
-0.529908
-1.04098
-0.180605
-1.58368
-0.491483
-0.2399
-0.685067
-0.282003
-0.56461
-0.324461
--0.161682
-0.932602
-0.453558
-0.828347
-0.864143
-0.986759
-0.0699801
-0.716223
-0.630936
-0.415545
-0.32381
-0.977669
-0.571675
-0.512321
-1.12067
-1.00203
-0.700197
-0.950241
-1.06323
-0.815031
-0.694346
-1.1402
-0.479317
-1.61417
-0.483669
-0.949479
-0.414855
-0.415568
-0.215529
-0.296347
-0.562646
-0.394396
-0.95725
-0.307021
-0.642649
-0.201445
-0.855997
-0.614384
--0.128448
-0.494546
-0.430128
-0.186727
-0.200078
--0.0362081
-0.952995
-0.0727457
-0.461895
-0.446427
-0.169163
-0.0166984
-0.0171792
-0.067968
-0.380807
-0.696916
-0.0535992
-0.0529203
-0.0159079
-0.288334
-0.450984
-0.161668
-0.0163033
--0.218439
-0.327229
-0.0520971
-0.102532
--0.125325
--0.0362798
-0.066042
-0.198462
-0.0531438
-0
--0.0858539
-0.34245
--0.117955
--0.0690653
--0.0137212
-0.15418
-0.129036
-0.278816
--0.0390162
--0.0345454
-0.100102
-0.326801
--0.0325838
-0.338754
-0.184948
-0.395813
--0.0899058
-0.323073
-0.345751
--0.0345585
-0.275448
--0.118727
-0.110559
--0.0350062
-0.481788
-0.0156525
--0.360239
--0.160117
-0.296273
-0.596496
-0.433713
-0.350594
-0.204626
-0.411037
-0.252666
-0
-0.0164083
-0.292173
-0.352693
-0.327136
--0.279992
-0.309094
-0.0698929
-0.543847
-0.465595
-0.0521019
-0.950946
-0.889914
-0.553508
-0.162601
-0.0531918
-0.160976
-0.534658
-0.274627
-0.166606
--0.218018
-0.718785
-0.297428
-0.299839
-0.49063
-0.542662
-1.2859
-0.670321
-0.246202
-0.49562
-0.435999
-1.09783
-0.839802
-0.700391
-1.06965
-0.814822
-1.11908
-1.29412
-1.04976
-1.42903
-1.22803
-1.01233
-0.876624
-0.880144
-0.183046
-0.682545
-0.818065
-1.47926
-0.774896
-0.0165292
-0.0324516
-0.323668
-0.497801
-1.02987
-0.281809
-0.714526
-0.106137
-0.359496
-0.482091
-0.253152
-0.611629
-0.181082
-0.197427
-0.308158
--0.0759092
-0.0171931
--0.0373605
-0.174858
-0.189849
-0.0558667
-0.44854
-0.59364
-0.0908744
-0.247429
--0.0668179
-0.363889
-0.189249
-0.473703
-0.199522
--0.305781
-0.194279
-0.199992
-0.616864
--0.130936
--0.0736164
--0.399752
-0.10447
-0.112455
--0.194825
-0.0709595
-0.295158
-0.0164212
--0.123395
-0.0522344
--0.0370832
--0.0167398
-0.140491
--0.273939
-0.190396
-0.398405
-0.196571
-0.104976
--0.0369512
--0.0681116
--0.209262
-0.523244
--0.272536
-0.243391
--0.0147026
-0.164315
-0.290603
--0.151307
-0.0531172
-0.106073
--0.358571
--0.0378816
--0.0366487
-0.0748531
-0.0556986
-0.10179
--0.164051
--0.123875
-0.499928
-0.0172733
-0.194103
-0.400524
--0.162958
-0.109692
-0.144167
--0.180643
--0.127277
-0.0532382
-0
-0.0681967
-0.25618
-0.388018
--0.296712
-0.453719
--0.0396036
-0.148695
--0.122364
-0.334629
-1.00442
--0.167082
-0.257076
-0.408731
--0.107768
-0.168782
-0.269645
-0.883373
-0.679945
-0.227872
-0.610101
-0.696099
-0.368174
-0.372723
-0.360489
-0.0362253
-0.479626
-0.557854
-0.92199
-0.457218
-0.866673
-0.840857
-1.23376
-0.862388
-1.67974
-0.685018
--0.185066
-0.561502
-0.65249
-0.673999
-0.819824
-1.12483
-0.0916378
-0.121905
-0.223021
-0.213207
-0.719432
-0.746749
-0.946219
-0.669179
--0.290636
-0.0161447
-0.488946
-0.0164052
--0.0768077
-0.445771
-0.162616
-0.788993
-0.78897
-0.247924
-0.651325
--0.0364825
-0.161576
-0.367942
--0.159138
-0.748196
-0.85734
--0.247595
-0.210301
-0.242786
-0.0997412
-0.172882
-0.290849
-0.106498
-0.276619
--0.0729994
-0.05218
-0.0159875
-0.0511872
--0.356845
-0.196981
-0.0488296
--0.0164179
-0.251391
-0.204001
-0.0489059
-0.332192
--0.126198
--0.161345
-0.138798
-0.615132
--0.120219
--0.0906685
--0.035517
-0.133562
--0.12346
-0.0151031
--0.0377557
--0.087051
-0.290082
-0.103469
--0.258733
-0.143155
-0.305386
-0.29105
-0
--0.342898
--0.268438
-0.156034
-0.247306
-0.145786
--0.0970399
--0.263339
-0.116543
-0.19324
--0.180106
-0.289059
-0.0558113
-0.350432
-0.330035
-0.38181
--0.0742219
-0.0161798
--0.203893
--0.222626
-0.644805
--0.036917
-0.357856
-0.562379
-0.11127
--0.0201808
-0.600419
--0.132187
-0.200763
-0.688265
-0.0175184
-0.0167686
-0.138329
-0.207237
-0.308988
-0.156562
-1.54901
-0.462714
-0.766637
-0.765767
-1.28341
-0.486469
-0.391739
-0.851581
-0.852444
-0.125282
--0.129208
-0.391964
-0.32043
-0.424166
-0.943429
-0.858898
-0.387195
-0.541042
-0.293802
-0.910259
-0.611561
-1.38326
-0.507019
-1.42149
-0.893795
-1.39949
-1.36572
-0.844248
-0.534367
-0.878557
-0.837447
-0.0340671
-0.90265
-1.38868
-0.753812
--0.299796
--0.203696
-0.758921
-0.580777
-0.527188
-0.410689
-0.263035
--0.18228
-0.12257
-0.711577
-0.760612
-0.420159
--0.0753028
--0.135139
--0.11115
-0.172016
-0.202487
--0.131512
-0.268822
--0.230672
-0.454371
--0.525114
-0.0157431
-0.543979
-0.294344
--0.0375658
-0.251695
--0.0199952
--0.190116
-0.249363
-0.364991
--0.364535
-0.053473
-0.18089
-0.12022
-0.457224
-0.252499
-0.298802
-0.101495
--0.0700669
-0.241875
--0.182782
-0.424244
-0.477428
-0.164455
-0.0189658
--0.11262
-0.103492
-0.267702
-0.0501842
--0.075494
--0.081234
-0.108394
-0.526593
-0.288752
-0.18479
-0.316573
--0.359169
-0.0523615
-0.190922
--0.091332
-0.053895
-0.0536696
-0.283458
-0.271705
-0.158467
-0.140175
--0.122562
-0.114
--0.101607
--0.182164
-0.106143
-0.539515
--0.386951
-0.566715
-0.156377
--0.0394448
-0.308816
--0.112198
-0.24256
-0.0166112
-0.135596
-0.207206
-0.0162746
--0.182834
-0.158562
-0.0699311
-0.193197
--0.210514
-0.467009
-0.0511478
-0.356423
-0.386239
-0.502804
-0.175093
-0.327802
-0.461314
--0.0197863
-0.138618
-0.956934
-0.406682
--0.36635
-0.582473
-0.264606
-0.817661
--0.0552619
-0.446818
-0.724136
-0.758462
-0.713904
-0.860757
-0.779011
-0.875314
-0.79804
-0.166449
-1.28435
-0.731833
-0.261391
-0.910705
-0.889008
-0.125593
-0.265595
-0.567463
-1.26465
-0.945884
-0.444628
-0.353058
--0.40716
-0.520606
-0.322646
-1.64248
-0.879151
-0.87392
-0.866824
--0.131333
-0.734654
-0.244552
-0.293994
-0.0166673
-1.15558
--0.26798
-0.323982
-0.0157197
-0.205742
--0.0882244
-0.403209
-0.64388
-0.0161026
-0.292954
-0.384577
--0.0368576
-0.11505
--0.262429
-0.0161637
--0.0171983
-0.194535
-0.107449
--0.0714146
-0.0158054
-0.015884
-0.157214
-0.0161144
-0
-0.15534
-0.295406
-0.15886
-0.0678338
-0.015817
--0.0361632
-0.104529
-0.719373
-0.370741
--0.0882149
-0.244229
-0
--0.086296
-0.395501
-0.0529598
--0.168367
-0.129003
-0.134435
-0.104273
-0.103004
-0.19371
--0.117887
--0.0370514
--0.327604
-0.105474
--0.0341778
-0.278704
-0.27044
-0.202211
--0.347622
-0.208324
-0.494369
-0.0166944
-0.344209
-0.345973
-0.0517284
-0.0175101
-0.371347
--0.227139
-0.104963
-0.198496
--0.394594
-0.166407
-0.191116
-0.109458
-0.215924
--0.0895617
-0.0168842
--0.0208518
-0.286209
-0.525222
-0.294365
-0.165486
-0.333555
--0.132744
--0.0145561
-0.156714
-0.387504
-0.26054
--0.0549081
--0.113228
-0.345101
-0.25223
-0.247729
-0.4184
-0.0325431
-0.287866
-0.0323623
--0.0738602
-0.531896
-1.14744
-0.985651
-0.458563
-0.696483
-0.88387
-1.31594
-0.62635
-0.205965
-0.241902
-0.456828
--0.02041
-0.735817
-1.14173
-1.01126
-0.619146
-0.18308
-0.539215
-0.0915303
-0.538678
-0.446049
-0.0701201
-0.82036
-0.842142
-0.392057
-0.161348
-0.380014
-0.119618
-0.39357
-0.768997
--0.165842
--0.258152
-0.832053
-0.169065
-0.127988
-0.808104
--0.0357739
--0.0379378
-0.248233
-0.306239
-0.301295
-0.109043
--0.126831
-0.34083
--0.119044
-0.515299
--0.0359064
-0.107814
--0.242655
-0.0517489
-0.201269
-0.158905
-0.10594
-0.195402
-0.413766
--0.0695223
--0.0705255
--0.0377464
-0.189712
-0.0500706
-0.568343
-0.412616
--0.0362325
--0.0352773
--0.281702
-0
--0.153204
-0.0499161
-0.799121
-0.151239
-0.188237
-0.0517031
-0.502226
-0.103425
--0.0993652
-0.0510231
--0.183452
--0.124843
-0.0183204
-0.356086
-0.438554
-0.296943
-0.148566
-0.0160263
--0.132149
-0.159116
-0.15129
-0.0508742
-0.20026
-0.453577
-0.68956
-0.195368
--0.0211342
-0.0518488
-0.297881
-0.195273
-0.379273
--0.193901
-0.226316
-0.0545256
-0.148173
--0.0372593
-0.0525398
-0.0538003
-0.307988
--0.163507
-0.257884
-0.307751
-0.621082
-0.108218
-0.400168
-0.0728347
-0.253336
--0.0176474
-0.602062
-0.111386
--0.188886
-0.223602
--0.446558
-0.0154229
--0.131445
-0.46515
-0.463404
-0.523019
-0.32305
-0.629244
-0.0714443
-0.37917
-0.109416
-0.59903
-0.104206
-0.124309
-0.398096
-0.888731
-0.502752
-0.259346
-0.607162
-0.118499
-0.172428
-0.506861
-0.735445
-1.01718
-1.25848
-0.799056
-0.698537
-0.874595
-0.176095
-0.271369
-0.262893
--0.203207
-1.16155
-0.615885
-0.64814
-0.239722
-0.0574435
-0.330882
-0.364798
-0.07106
-0.273583
-0.156305
-0.462835
-0.48351
--0.166177
-0.634431
-0.311311
-0.955074
-0.212377
-0.395659
-0.192475
-0.701992
-0.354758
-0.259998
-0.254211
--0.27483
-0.210097
-0.0172475
-0.201077
-0.193742
-0.532629
-0.0513678
--0.128172
--0.164545
-0.119265
--0.0203871
--0.268454
--0.21298
--0.157267
-0.704135
-0.351674
--0.0356829
--0.0364733
-0.0162938
-0.276943
-0.335285
-0
-0.0499358
-0.474605
--0.0693888
-0.0534237
-0.5093
-0.39046
--0.169342
--0.17351
-0.192007
-0.240092
-0.134297
-0.0505241
-0.0511143
-0.243619
-0.0542652
-0.378912
--0.0901832
--0.102443
-0.142857
--0.036806
-0.336665
-0.341232
-0.0560474
-0.339694
--0.0884467
--0.0733696
-0.244067
-0.0544838
--0.193411
-0.107334
--0.097317
-0.191437
-0.674026
--0.275093
-0.0167387
-0.336971
--0.359911
--0.0705543
-0.108359
-0.331889
-0.649697
--0.177646
-0.249215
--0.127743
-0.525754
-0.0552027
--0.0209262
-0.129842
-0.747617
-0.0698751
--0.284951
-0.250206
-0.0353849
-0.359077
--0.11917
-0.532915
-0.0719458
-0.313318
-0.571393
-0.355298
-0.42957
-0.0541905
-0.407984
-0.356098
-0.647306
-0.202326
-0.364038
-1.0303
-0.996736
-0.0371637
-0.43956
-0.552057
-1.20082
-1.10097
-0.631826
-0.741135
-0.954079
-0.460471
-0.590315
-0.109721
-0.941985
-0.0762943
-0.0176029
-1.23274
-0.175772
-0.559332
-0.45803
-1.29482
-0.378405
-0.482609
-0.795625
-0.203356
-0.183701
-0.348595
-0.218302
-0.259867
-0.476441
-0.146066
-0.853834
-0.253978
--0.0759397
--0.127135
-0.0578942
--0.268252
-0.218489
-0.745477
-0.0545655
-0
-0.105912
--0.0770963
-0.273125
-0.37075
--0.216627
-0.0170284
--0.0389965
--0.158722
-0.0175397
-0.0554108
--0.356969
--0.179304
--0.0376684
--0.0778968
-0.164244
--0.0372367
--0.309299
--0.0363537
-0.0548773
-0.110991
-0.0165397
--0.13416
-0.169555
-0.373646
-0.267563
--0.178886
--0.0871882
--0.114909
--0.267984
-0.0186784
-0.128992
-0.203599
-0.100309
-0.110587
-0.12837
--0.343455
-0.474843
--0.0359306
-0.623303
-0.394836
-0.44632
--0.181051
--0.0905345
-0.284037
-0.0190294
-0.346345
-0.211202
--0.0905291
-0.144805
-0.415346
-0.241909
-0.211673
-0.254044
--0.0350901
-0.340228
-0.158306
-0.052965
--0.0702297
-0.303283
-0.0192384
--0.0728741
-0.0517389
--0.163993
--0.180125
-0.511629
-0.124749
--0.243076
-0.194227
-0.584962
-0.403427
--0.134598
-0.436601
-0.0157877
--0.40844
-0.337057
-0.294586
-0.268188
--0.164286
--0.123458
--0.200152
-0.273119
-0.344894
-0.972746
-0.170996
-0.997436
-0.903502
-0.600859
-0.156303
-0.580347
-0.3663
-0.248709
-0.484403
-0.300033
-0.922446
--0.020398
-0.900827
-0.596209
-0.212713
-0.31455
-0.593377
-0.51989
-0.360337
-0.0710235
-0.199646
--0.302583
-0.255254
-0.105135
-0.330337
-0.0161695
-0.805388
-0.108693
-0.345843
-0.210137
-0.0164161
-0.017115
-0.400612
-0.130304
--0.197489
-0.307089
-0.0164475
--0.177577
-0.0705712
--0.226102
--0.294638
-0.0696923
--0.186662
-0.578177
-0.0519733
-0.0162602
-0.374428
-0.180522
-0.345451
--0.210942
-0.0168213
-0.245112
-0.413557
-0.0192959
-0.397729
--0.363535
-0.388815
--0.124816
--0.0361368
--0.0885362
-0.428077
--0.0699055
--0.206498
-0.429265
-0.304346
-0
-0
-0.273245
--0.0372147
--0.0362683
-0.0161343
--0.125613
--0.0702591
-0.153891
--0.0868893
--0.0339037
-0.476893
--0.0875824
--0.45343
-0.144106
-0.118837
--0.0917011
-0.289516
--0.102592
--0.293119
-0.109619
--0.0349811
--0.224599
-0
--0.174938
-0.256856
-0.068645
--0.0870703
--0.27818
-0.0166828
-0.444771
--0.03548
-0.148682
--0.0926657
-0.0168966
-0.0678112
--0.274739
--0.0722842
-0.247079
-0.343415
-0.254332
-0.16514
-0.254952
-0.0171438
-0.417066
-0.415504
-0.103163
-0.306131
-0.254658
-0.95635
--0.135546
-0.0714888
-0.180754
-0.476044
-0.88062
-0.353114
-0.385468
-0.414309
-0.577181
-0.0333411
-0.017121
-0.71155
--0.109853
-0.0366779
-0.0173934
--0.105791
-0.627106
-0.0170525
-1.59749
-0.651617
-0.202601
-0.606122
--0.158061
-0.447871
-0.709455
--0.0749936
-0.123309
-0.208671
-0.358535
-0.228304
-0.761193
-0.849613
-0.410085
--0.0362571
-0.849219
--0.117124
--0.0382954
--0.395145
--0.0744367
-0.0893135
-0.500124
--0.0164288
-0.448738
--0.174236
-0.309099
--0.0368503
-0.017833
--0.0774376
-0.164001
-0.211752
-0.0208756
-0.104639
--0.0143392
--0.184936
--0.537072
-0.250595
--0.03658
--0.558324
--0.667376
--0.271161
-0.344369
-0.5297
-0.106329
-0.204834
--0.358596
-0.612069
-0.103078
-0.168194
-0.0718218
-0.105835
--0.12788
--0.179925
-0.0161755
-0.617554
-0.349012
--0.0860819
-0.297576
-0.158505
--0.0363163
-0.393038
--0.242282
-0.110251
--0.0867261
-0.148303
--0.0871527
--0.181309
--0.068547
--0.0760803
-0.0158068
-0.403967
-0.0189652
--0.0397948
-0.202469
--0.211891
-0.251825
--0.157923
-0.0170419
--0.0875458
-0.783285
--0.398607
--0.017031
-0.142949
-0.332137
-0.584314
-0.300261
-0.24847
-0.440361
-0.259544
-0.0359781
-0.164867
-0.777638
--0.0381084
-0.287364
--0.035902
-0.0553935
--0.184553
-0.62091
-0.638186
--0.0348079
--0.18126
-0.110971
-0.316658
-0.287831
--0.37298
-0.12764
--0.0747403
-0.393864
-0.392662
-0.191419
-0.35544
-0.319661
-0.150598
-0.107184
-0.128709
--0.219574
-0.0543297
-0.26786
-0.312908
-0.462227
-0.155258
-0.217307
-0.463962
-0.161153
-0.252106
--0.210019
-0.0953818
-0.267515
-0.449751
-0.394649
-0.534445
-0.466239
-0.583745
-0.501628
--0.0379746
--0.109322
-0.811405
-0.666117
-0.842675
-0.447518
-0.37711
-0.0733359
-0.25653
-0.192698
-0.300559
-0.108235
-0.114463
-0.683973
-0.162323
-0.727152
--0.549478
-0.827226
-0.830016
-0.322874
-0.0752543
-0.106791
-0.169723
-0.341122
-0.112015
--0.368224
-0.571411
-0.208838
--0.188473
--0.182798
--0.13522
-0.374983
--0.290324
--0.276662
--0.0751452
-0.307444
--0.0367633
-0.262954
-0.417145
-0.163734
--0.0375594
-0.573419
--0.215733
--0.0922195
-0.583263
-0.466
-0.1911
--0.0350394
--0.0172727
-0.254739
-0.0535159
-0.0515946
-0.0168897
-0.267688
--0.037043
-0.348685
--0.200172
--0.123805
-0.289235
-0
-0.290678
--0.176233
-0.156784
-0.0989453
-0.163758
-0.191906
--0.304233
-0.150754
--0.251727
-0.0778895
-0.195135
--0.130041
--0.15779
--0.318621
-0.46371
--0.0389946
-0.350975
-0.194947
-0.202671
--0.163336
-0.258266
-0.268958
-0.107149
-0.216439
-0.0571126
-0
-0.0201204
-0.161895
-0.337607
--0.182131
-0.348088
-0.742931
-0.151798
--0.132874
--0.0380238
-0.226426
-0.466047
-0.1151
-0.4046
-0.201936
-0.440078
-0.263257
-0.337428
--0.338223
--0.0211827
-0.358613
-0.616517
-0.362352
-0.251222
-0.660074
-0.0713364
-0.451451
-0.611903
-0.755006
-0.244092
-0.619578
-0.59851
-0.268845
-0.222557
-0.51217
-0.21779
-0.880423
-0.552328
-0.20749
-0.185901
-0.450517
-0.548934
-0.148407
-0.454294
-0.571629
-0.411517
-0.4426
--0.132423
--0.162635
-0.698042
-0.223305
-0.395785
-0.106861
-0.347526
-0.271979
-0.0372914
-0.0726309
-0.111038
--0.0999251
--0.252457
--0.133305
--0.0361029
-0.0705259
-0.451767
-0.360056
-0.0739622
-0.377832
-0.0175079
-0.108812
-0.214644
-0.113512
-0.14678
-0.245807
--0.161986
-0.479086
-0.364866
--0.132635
-0.471042
-0.0168475
-0.0168019
--0.0180896
--0.0361726
-0.452938
-0.105814
-0.0727294
--0.0755939
-0.190713
--0.178351
-0.285746
--0.179379
-0.052378
-0.294159
-0.194225
--0.0706253
--0.26764
-0.0534696
-0.137568
-0
-0.287767
--0.0911018
-0.456106
-0.356084
--0.273918
--0.189299
-0.539246
-0.150332
-0.100698
-0.150084
-0.0158987
-0.0561982
--0.176282
-0.158726
-0.600359
--0.095245
-0.339365
-0.109525
-0.188014
--0.094509
-0.331611
-0.112838
-0.465487
--0.483741
-0.332248
-0.202965
-0.200631
-0.0167681
--0.223333
-0.11185
-0.126317
-0.172145
-0.248538
--0.0171525
-0.345444
-0.16849
--0.128197
-0.263999
-0.894634
-0.154215
-0.483425
--0.301639
-0.254601
-0.0172563
--0.301562
-0.758886
-0.10321
-0.700142
-0.211188
--0.0731342
-0.417542
-0.133167
-0.311304
-0.360185
-0.245261
-0.25611
-1.09578
--0.476026
-0.229344
--0.0921914
-0.0547938
-0.205044
-0.219825
-0.508495
-0.308923
-0.37151
-0.166211
-0.330068
-0.253749
-0.609207
-0.0705165
-0.0175539
-0.905342
--0.258879
--0.0923592
-0.289428
--0.166729
-0.731354
--0.129432
-0.167298
-0.372187
--0.221416
--0.0691449
-0.454966
-0.0160249
-0.414927
-0.287292
--0.128553
-0.149283
-0.268397
-0.403637
--0.28499
--0.0378879
-0.499203
-0.198758
-0.017367
-0.552145
-0.104543
-0.359761
--0.037801
--0.1768
--0.133818
-0.16147
-0.202374
-0.38651
-0.0728348
-0.103897
-0.242301
--0.17652
--0.034842
-0.160938
-0.300154
-0.457482
--0.254545
-0.24822
-0.0365352
--0.128086
-0.249247
-0.157715
-0.0168029
-0.156032
-0.144985
-0.249894
-0.559641
--0.29667
-0
--0.122148
-0.0751723
-0.343255
--0.0355524
-0.0509759
-0.336845
--0.17895
-0.0514955
-0.0636364
-0.326223
-0.266501
-0.0157661
-0.0194523
--0.0313527
-0.105523
-0.235917
-0.104508
-0.015952
-0.18772
-0.231408
-0.390201
-0.0692321
-0.168626
--0.03496
-0.328607
-0.45849
--0.43724
-0.608208
-0.730735
-0.370028
-0.126697
-0.333566
-0.388275
-0.473159
-0.483934
-0.203253
--0.362937
-0.772619
-0.260494
-0.289973
-0.0167106
-0.191674
-0.0164841
--0.271769
--0.0380741
--0.0743647
-0.467295
--0.0177762
-0.0531216
--0.0763837
-0.166554
-0.641743
--0.162397
-0.407733
-0.068279
-0.242242
--0.169629
-0.0161957
--0.035919
-0.0173531
-0.111241
-0.15643
-0.335402
--0.0211362
--0.0895853
-0.425369
-1.05484
-0.553551
-0.470414
--0.0732488
--0.401144
-0.346664
--0.402616
-0.0874517
-0.561529
-0.335572
-0.631862
-0.158183
--0.0594708
-0.344566
-0.462862
--0.0898532
--0.0382655
-0.0532141
--0.0374088
-0.123188
-0.625417
-0.545028
--0.24973
-0.541164
-0.364366
-0.581786
--0.0916724
-0.0162221
-0.399755
-0.501368
--0.137433
--0.141166
-0.442422
-0.34625
-0.200056
--0.0360817
--0.171846
-0.322337
-0.235201
-0.341982
-0.213187
-0.0720334
-0.167265
-0.410356
-0.302148
-0.432618
-0.103434
-0.11224
-0.468281
-0
-0.19145
-0.0166903
-0.280546
--0.0199719
--0.202667
-0.203144
--0.0374823
-0.490726
--0.0710657
--0.120872
-0.191064
-0.427935
-0.186475
-0.0693131
-0.103485
-0.536659
-0.142271
-0.356678
-0.483444
-0.285928
-0.0512108
-0.253915
-0.0494959
--0.099276
-0.184322
--0.0346924
-0.105984
-0.487617
--0.178389
-0.174719
-0.0523978
-0.212145
--0.0389531
--0.0927627
-0.583956
-0.297377
-0.0512298
-0.0531204
--0.427162
-0.255123
--0.184305
-0.151696
--0.0915414
-0.146914
-0.0171674
--0.132897
--0.0759282
-0.0691983
-0.0189801
-0.401462
-0.535362
--0.0344602
--0.0924788
-0.653313
-0.550445
-0.406511
-0.0550978
-0.577592
-0.189768
-0.209958
-0.427876
-0.165684
-0.466407
-0.207783
-0.481782
-0.269767
-0.0714157
--0.216637
-0.354292
-0.207057
-0.142519
-0.260663
-0.108527
-0.462215
--0.185133
--0.174654
-0.351639
-0.288509
-0.265
-0.149897
-0.285406
-0.124647
-0.21116
-0.307571
-0.191217
-0.212007
-0.498864
-0.127754
--0.217397
-0.114063
-0.254534
-0.558105
-0.178692
--0.134209
-0.868992
--0.438207
--0.0178542
-0.108292
-0.755171
--0.0384136
--0.111179
--0.226063
-0.0543566
-0.107453
-0.549051
-0.314154
--0.0716872
-0.463987
--0.130216
-0.268233
-0.204748
-0.206136
-0.431979
-0.194227
-0.316046
-0.0524871
-0.267704
-0.166171
-0.0160051
--0.177843
-0.108775
-0.613611
-0.284442
--0.0381214
-0.0160515
-0.479277
-0.306178
-0.38624
-0
-0.310516
-0.28437
-0.495973
--0.0371432
--0.127938
-0.10236
-0.0711983
-0.562584
-0.0540357
-0.368078
-0.115177
-0.681186
--0.124693
--0.178368
-0.0573347
--0.0923108
--0.0908538
-0.285283
-0.413978
--0.0353891
--0.178316
-0.399067
--0.0907124
--0.0166201
--0.0872016
--0.17709
-0.0516257
--0.126783
-0.157229
-0.444348
-0.33479
--0.269393
-0.092785
--0.0380615
--0.0367751
-0.282171
-0.05438
--0.0909814
-0.141579
-0.309047
-0.332331
--0.129141
--0.0368149
--0.212059
-0.299054
-0.486478
-0.757476
-0.352543
-0.0694869
-0.29497
-0.300157
-0.0525515
-0.0546145
--0.0373293
-0.143973
-0.0346738
--0.164573
--0.0378307
--0.0719736
-0.157519
-0.328337
-0.581971
-0.104348
-0.0398835
--0.0937798
-0.782225
-0.348431
-0.306237
-0.587602
-0.265634
--0.110218
-0.179819
-0.394592
--0.131656
--0.271441
-0.260157
--0.450633
-0.438129
-0.357848
-0.470529
-0.219481
-0.211854
-0.0532623
-0.210027
-0.516994
-0.416415
-0.278801
-0.162535
-0.123407
-0.764674
-0.201123
--0.281567
-0.360545
-0.497734
-0.0730402
-0.0334325
-0.442087
-0.306248
--0.0359823
-0.530745
-0.3396
-0.465079
-0.30644
-0.0346998
--0.123684
-0.532289
--0.577586
--0.187011
-0.831106
-0.432397
--0.177001
-0.164542
-0.253069
-0.401182
-0.199202
--0.16236
-0.0207339
--0.124146
--0.178948
--0.188568
-0.053901
--0.0363599
-0.202331
-0.157563
-0
-0.190563
-0.102218
--0.0898544
-0.0562941
--0.109802
-0.1616
-0.0530651
-0.121948
--0.0349176
-0.277098
--0.0168564
-0.0515329
--0.0373245
-0.162354
-0.409772
-0.104595
-0.692356
-0.151109
-0.135627
-0.290969
-0.191271
--0.365999
--0.0847856
-0.0545202
-0.23936
-0.156066
-0.180986
-0.290771
-0.434184
-0.199586
-0.197847
-0
-0.125709
-0.204891
-0.416515
-0.14715
-0.0154567
-0.292693
-0.144497
-0
-0.0519292
-0.407114
-0.10764
-0.109239
-0.128015
--0.189211
-0.0169855
--0.0957208
-0.489992
-0.295606
-0.198185
-0.209599
-0.332344
-0.0172358
-0.485909
-0.353152
-0.0539723
-0.464965
-0.0544456
-0.407853
-0.196919
-0.043224
-0.340733
--0.0752045
-0.304021
-0.35333
--0.0201827
-0.161141
-0.216615
-0.0167239
-0.566709
-0.253849
-0.483599
-0.112681
-0.930188
-0.218645
-0.334356
-0.682715
--0.12788
--0.18886
-0.252969
-0.168657
-0.831744
-0.415817
--0.166174
-0.0710399
-0.939944
-0.163324
-0.468221
-0.204816
--0.129733
-0.258235
-0.223649
-0.317447
-0.109866
-0.288653
-0.453179
-0.295988
-0.103948
-0.495463
--0.118807
-0.112529
-0.0503025
-0.655923
-0.300307
-0.073371
--0.126391
-0.259993
-0.017103
-0.0170722
--0.322942
-0.0551525
--0.0389352
-0.447578
--0.036997
-0.111135
--0.0379723
-0.252137
--0.123641
-0.147522
-0.190421
--0.032594
--0.358922
-0.303682
-0.0189062
-0.395471
-0.279195
--0.201989
-0.471388
-0.102926
-0.412481
--0.323681
--0.0360381
--0.12607
-0.250666
--0.218475
--0.212146
--0.0366624
-0.612503
-0.106193
-0.286945
--0.450442
-0.106158
-0.203237
--0.0730585
--0.204858
--0.272972
-0.291002
--0.122233
--0.432403
-0.0367752
--0.0700271
-0.188259
-0.252321
-0.134392
-0.0514664
-0.349948
-0.276441
-0.250075
-0.490816
--0.0880337
-0.195184
--0.0893328
-0.0526438
--0.111413
-0.051488
-0.102083
-0.278123
-0.0525525
-0.108373
-0.529537
-0.285282
-0.249682
-0.515155
-0.108291
--0.162554
-0.0734842
--0.0379968
-0.148954
--0.183959
--0.205184
--0.13307
--0.448358
--0.0367599
-0.107349
-0.0519935
-0.202791
-0.0522907
--0.0719568
-0.203106
-0.254807
-0.337276
-0.606387
-0.29791
-0.59436
-0.0170679
-0.159331
--0.165048
-0.627143
--0.0952462
--0.0706074
-0.168261
-0.196059
-0.0754042
--0.216252
-0.202447
-0.297416
-0.407903
-0.164276
-0.320477
-0.821587
-0.36122
-0.571486
-0.404713
--0.0732545
-0.46042
--0.13334
-0.204923
-0.204933
-0.258658
-0.108777
--0.128741
-0.491808
-0.564063
-0.4263
-0.641004
-0.0205919
-0.111289
-0.106051
--0.131831
-0.728781
-0.107356
-0.519384
-0.644857
-0.0169658
-0.31279
--0.0789805
-0.685363
-0.324764
-0.199827
--0.0374724
-0.326958
-0.0722724
-0.0695253
-0.0554813
-0.589203
--0.271749
--0.0377825
-0.0162006
--0.436972
--0.131592
--0.0347718
-0.349366
-0.203807
-0.0534999
--0.0897659
--0.356387
-0.393792
-0.102563
--0.0361336
-0.332857
--0.0859784
--0.0721209
-0.0525378
--0.305301
--0.0363296
--0.184644
--0.165059
--0.178286
-0.630821
-0.105392
-0.242501
-0.146868
-0.156481
--0.274076
--0.0949824
--0.036126
-0.351094
--0.0824511
-0.594787
-0.28821
--0.200237
-0.292278
-0.213668
--0.0351914
-0.212683
-0.139087
--0.0179922
--0.0359024
-0.202341
-0.321002
-0.111665
-0.437094
--0.037363
-0.31321
-0.638288
--0.260326
-0.358702
-0.392957
--0.0949397
-0.213197
--0.0380433
-0.146299
-0.0732709
-0.618006
-0.202746
--0.130081
-0.164884
-0.499939
-0.112872
--0.0745759
-0.314409
-0.149384
-0.0727537
-0.142094
-0.0531698
--0.186136
-0.0184323
-0.150286
--0.0753358
-0.0575576
-0.132193
--0.0559524
-0.476803
-0.108395
-0.604523
-0.0533042
--0.19095
-0.756252
-0.0554347
-0.108956
-0.340047
-0.610038
--0.0181637
-0.199318
-0.163892
-0.13033
--0.411211
-0.0732445
-0.369041
-0.347152
-0.163103
-0.584424
-0.162586
--0.128015
-0.0552275
-0.0168724
-0.364294
--0.0392803
-0.602503
-0.193745
-0.206742
-0.137918
-0.166927
--0.110232
-0.115387
--0.126457
--0.0384804
-0.579604
-0.534006
--0.0372235
-0.0707797
--0.0731681
-0.322733
-0.158593
-0.0170944
-0.253114
-0.309028
-0.165273
--0.132623
--0.069895
-0.419744
-0.698313
--0.0182168
-0.10005
-0.354291
--0.0354641
--0.123748
--0.185414
--0.218963
--0.160056
-0.204971
--0.0358229
-0.108401
-0.0166061
-0.243717
-0.469138
--0.182207
-0.382138
-0.055545
--0.0165203
-0.246578
--0.0740918
-0
-0.190836
-0.145243
--0.205526
-0.303031
-0.192578
-0.668877
-0.254926
-0.184271
-0.146581
-0.298611
--0.126967
-0.19026
-0.159096
-0.283583
--0.175785
-0.28475
--0.0366085
-0.288317
-0.0538924
-0.176485
-0.0570089
-0.0152193
-0.195133
--0.036244
-0.300726
-0
-0.0537813
-0.15786
-0.269714
--0.0376813
--0.129347
-0.14506
-0.113584
-0.0519703
-0.515238
--0.0375925
-0.205342
-0.201883
--0.187588
-0.436753
-0.0561577
-0
--0.0380042
--0.038339
--0.0382102
-0.05457
-0.105961
-0.352248
--0.274214
-0.107937
-0.111428
-0.0536052
-0.308581
-0.2001
-0.211839
--0.127241
--0.123425
-0.167411
--0.179413
-0.252919
--0.037552
-0.392105
-0.487974
--0.341967
--0.132381
-0.259691
--0.474209
-0.808799
--0.0363644
--0.0746649
-0.403238
-0.1525
-0.37502
-0.0367944
--0.32789
-0.791478
-0.359292
--0.0780424
-0.426161
--0.253719
-0.355317
-0.0563283
-0.109937
-0.316291
-0.475163
-0.207353
-0.210502
--0.0379928
-0.44631
-0.252803
-0.198389
--0.078178
-0.251241
-0.398419
-0.223079
-0.439446
-0.299935
-0.346639
-0.194938
--0.0368618
-0.357709
--0.0377485
-0.464922
-0.508942
-0.205426
--0.0911443
-0.431324
-0.201449
-0.206887
-0.145768
--0.220472
-0.409697
-0.450791
--0.0352402
-0.29665
--0.0355706
--0.038137
--0.182869
-0.704984
--0.17168
--0.224126
-0.457605
-0.14647
-0.106536
-0.104473
--0.0703682
-0.106129
-0.246247
-0.0162506
-0.884895
--0.035431
-0.354837
-0.329357
-0.0532861
-0.183929
-0.276666
-0.427886
--0.0383166
--0.173649
-0.055411
--0.0343934
--0.228208
-0.04977
-0.164956
--0.0831549
--0.135076
--0.0721612
-0.450285
-0.241635
--0.132446
-0.432162
-0.302682
--0.0848552
-0.119475
-0.333308
-0.207871
-0.0497721
-0.152649
--0.17306
-0.571577
-0.871058
-0.203655
-0.309108
-0.0176031
--0.0375733
-0.434837
-0.321501
-0.112694
-0.0528352
-0.218205
-0.275393
-0.304817
-0.251507
--0.191333
-0.616416
-0.109785
--0.0759105
-0.112515
-0.0529049
-0.149738
--0.311945
-0.262731
-0.0202224
-0.0553756
-0.0989101
-0.328306
-0.829996
--0.260274
-0.273569
--0.184105
-0.216413
-0.301201
--0.0924358
-0.508571
-0.408912
--0.461822
-0.114177
-0.110249
--0.306076
-0.507171
-0.255438
-0.362765
-0.595049
--0.136733
--0.132203
-0.478588
-0.303207
-0.388153
-0.0716622
--0.190692
-0.315046
--0.187409
--0.0377612
-0.302635
-0.0762521
-0.542024
--0.253923
--0.344039
-0.289491
-0.241157
-0.107744
--0.0395893
--0.163293
--0.0400622
--0.0177615
-0.296444
-0.40643
--0.378084
-0.0556641
-0.154028
-0.167494
--0.0948982
-0.530246
--0.0413496
--0.0750397
-0.214083
--0.206787
-0.358906
--0.264019
--0.0374577
--0.26716
-0.0565131
-0.108046
-0.0581078
--0.178765
-0.0173196
-0.203656
--0.112558
--0.0723401
-0.112781
-0.0527596
-0.165725
-0.210895
--0.0407659
-0.166093
-0
--0.0890551
--0.225769
-0
-0.307551
--0.213208
--0.0796847
-0.870799
--0.110955
-0.149735
-0.0556178
-0.0537965
--0.262865
--0.258069
-0.1557
--0.0836861
-0.195678
-0.0731913
-0.240059
--0.037234
-0.184024
--0.0907114
-0.231112
--0.0369318
-0.19115
-0.11177
-0.191375
--0.280434
-0.40265
-0.0548231
--0.0741358
-0.290488
-0.107753
-0.207652
-0.0528579
--0.0393161
-0.0532928
-0.251154
--0.216068
-0.05233
-0.0707076
-0.440721
--0.0174329
-0.11032
--0.122939
-0.109348
--0.217297
--0.0396753
-0.0544301
-0.307937
-0.470072
-0.112602
-0.197309
-0.579134
-0.164367
-0.106795
-0.351521
-0.254809
--0.130949
--0.22423
--0.0209287
-0.0554201
-0.150495
-0.253667
--0.232571
-0.203259
--0.354801
-0.473068
-0.352978
-0.202687
-0.267133
-0.162428
-0.429142
-0.441776
-0.348374
-0.257829
--0.0380615
-0.602608
-0.210022
--0.190887
-0.224124
-0.288144
-0.268304
-0.658816
--0.30808
--0.0382398
-0.149394
--0.0179094
-0.352746
--0.0762712
-0.1924
--0.0359287
-0.419163
-0.016379
-0.305505
-0.0571658
-0.288832
--0.078769
-0.246253
-0.415622
-0.260938
--0.309327
-0.0560171
-0.216384
--0.0377216
-0.318175
-0.294823
-0.205113
-0.453522
-0.146591
-0.208891
--0.0362083
--0.0863067
-0.0567215
-0.156344
-0.159965
-0.0168674
--0.266599
--0.159172
-0.257878
-0.154297
--0.0354991
--0.190262
--0.549675
-0.0539283
-0.529657
-0.0512891
--0.172664
-0.138714
--0.0884567
--0.0363014
-0.056471
--0.0371128
--0.175971
--0.132613
-0.0526101
-0
-0.362646
--0.103305
-0.483866
-0.380125
--0.0358217
-0.161998
--0.0701953
-0.638099
-0.0191005
-0.333142
-0.0516942
-0.466498
-0.0165305
-0.31893
--0.0351645
--0.227164
--0.0164184
-0.0758273
-0.250956
--0.194111
--0.0379247
--0.103131
-0.251854
--0.19378
-0.0556046
--0.388632
-0.0535207
-0.179025
-0.360015
-0.313324
--0.189915
-0.276327
--0.0202301
-0.183248
-0.106106
-0.276307
--0.0911606
-0.316053
-0.428536
-0.218765
--0.0208637
-0.230539
-0.110606
-0.219739
-0.105664
-0.0569873
-0.15178
-0.431461
-0.107456
-0.16362
-0.333715
-0.680351
-0.162066
--0.0375397
-0.437727
-0.222322
-0.324658
-0.226104
-0.0169519
-0.301118
--0.0402558
-0.606815
-0.0168168
--0.0411577
-0.50801
--0.136887
-0.286956
-0.313432
-0.201391
-0.114514
--0.130195
-0.11967
-0.0570532
-0.626054
--0.467987
-0.573952
-0.197878
-0.216933
-0.464637
-0.42867
-0.487355
--0.303853
-0.0751677
-0.650785
-0.481667
-0.581485
-0.201616
--0.262921
-0.206301
-0.017862
-0
-0.770214
-0.405337
--0.0382773
-0.113926
-0.215185
-0.252928
-0.218459
-0.730726
--0.0413692
-0.72005
-0.115568
-0.405136
-0.0516464
-0.212203
-0.14912
-0.290725
-0.322423
-0.0544499
-0
-0.466164
-0.0702624
-0.019256
--0.0942096
-0.216528
--0.0189761
-0.0166886
--0.132842
-0.103537
--0.317033
--0.0920146
-0.359937
-0.405917
-0
-0.426647
-0.206446
-0.503324
-0.13019
-0.275522
-0.196614
-0.0494261
-0.0524401
-0.0482749
--0.213685
--0.0335772
-0.13881
-0.0519026
--0.0841977
--0.0357761
-0.523865
-0.333339
-0.626877
-0.272966
--0.0891159
-0.341126
-0.14152
-0
-0.127568
--0.0339579
-0.396352
--0.255859
--0.26256
-0.105962
-0.723355
-0.103421
-0
--0.270978
--0.230344
-0.137738
--0.176174
--0.0753674
-0.997947
--0.300874
-0.0162613
-0.106689
--0.358678
-0.0695291
--0.0208589
-0.350867
-0.200077
--0.212698
-0.195067
-0.035844
-0.0741822
--0.48499
-0.285672
--0.190287
-0.160343
--0.0207915
-0.536239
-0.138271
-0.0564204
-0.289219
-0.521201
-0.422748
-0.254682
--0.27255
-0.455736
-0
--0.0761155
-0.177088
-0.0550988
-0.0686706
--0.12817
--0.310302
-0.737121
-0.316206
-0.278364
--0.0528266
-0.653199
-0.104463
-0.144747
-0
-0.254039
-0.161277
-0.112969
--0.0385227
--0.312321
-0.0163891
--0.371667
-0.215166
--0.127557
-0.300618
--0.131135
-0.218619
--0.0766142
-0.217381
--0.180019
-0.171946
-0.0525392
-0.262809
-0.0168759
-0.11246
-0.600286
--0.230041
--0.0887734
-0.217875
-0.151373
-0.103104
--0.0771818
-0.240625
--0.167349
-0.0170285
-0.42452
-0
-0.194845
--0.122793
--0.190446
--0.0372137
--0.211474
--0.071283
-0.203505
-0.109827
-0.196571
-0.755326
-0.0184646
-0.444199
-0.199261
--0.0898159
--0.172638
--0.124035
-0.106834
-0.0498609
--0.123731
-0.340546
-0.484315
--0.0145351
-0.608143
-0.407153
-0.206572
-0.293361
-0.354791
-0.604416
--0.040864
--0.0881051
-0.149271
--0.121826
--0.195787
--0.304816
-0.301256
--0.179823
-0.11001
--0.0359015
--0.317401
--0.209905
-0.420111
-0.0516185
-0.149847
-0.29414
--0.0392845
--0.0380358
-0.568439
-0.0751917
-0.594109
-0.207562
--0.0405987
-0.298403
-0.261517
-0.348547
-0.304148
-0.393597
-0.329554
--0.0899979
--0.0966014
-0.493288
-0.0577398
-0.0552232
-0.0559959
-0.162516
-0.0554639
-0.0176895
-0.112492
-0.267462
--0.0178519
-0.14401
-0.473885
-0.487363
-0.510106
-0.0551164
-0.15618
-0.0755137
-0
-0.153019
-0.683611
-0.293729
--0.0395362
-0.110407
-0.354716
--0.0377816
-0.373649
--0.0735134
--0.0401399
-0.0686322
-0.206446
-0.0343329
-0.609602
-0.312462
--0.0384506
-0.64215
-0.207319
--0.135894
--0.13235
--0.0381599
--0.0394208
-0.108908
-0.0177837
-0.452558
-0.232592
-0.585725
-0.423903
-0.253968
-0.149707
-0.21737
--0.0736302
-0.558728
-0.319045
-0.203689
--0.291497
--0.324512
-0.0601306
--0.286691
-0.11241
-0.256308
-0.119929
-0.0557163
-0.0555859
--0.13189
--0.0929706
-0.646898
-0
--0.018119
-0.112326
--0.133521
--0.039478
--0.1267
-0.0184253
-0.470181
--0.130992
-0.474567
-0.17065
-0
-0.30656
--0.0714607
-0.269563
-0.2017
-0.259642
-0.291539
-0
--0.0366155
--0.0950365
-0
-0.173989
--0.275741
--0.107643
--0.0950879
-0.316905
-0.139345
-0.0557681
-0.052222
--0.0899189
-0.101541
-0.552201
--0.0350254
-0.581337
--0.0928985
-0.106025
-0.055811
-0.166516
--0.377361
-0.0540102
--0.18884
--0.0915752
-0.265187
-0.198581
-0.104249
-0.0543439
--0.0371435
--0.179519
-0.261922
-0.0548152
-0
-0.45358
-0.210282
-0.457357
--0.221471
--0.0972167
-0.119079
-0.0566889
-0.47175
-0.531694
--0.038853
-0.204532
-0.14978
--0.291797
--0.094894
-0.0554669
-0.260792
-0.212738
-0.0548315
--0.0956054
--0.0367489
-0.0607326
-0.041107
--0.097008
-0.195718
-0.301652
-0.259174
--0.0377505
-0.287198
-0.179007
-0.198607
--0.18602
-0.0197004
-0.073533
--0.0386523
--0.306817
-0.205049
-0.201169
-0.166704
-0.354406
--0.27944
-0.388031
-0.0545858
-0.0556904
-0.111346
-0.213218
-0.699969
-0.309117
-0.327314
-0
-0.40324
-0.0200877
--0.22579
-0.566706
-0.124203
-0.409535
--0.209266
--0.362351
-0.106518
--0.0369901
-0.31366
-0.413792
--0.369975
-0.105913
-0.357433
--0.130675
-0.265163
-0.309833
--0.19804
-0.193094
-0.0161435
-0.295737
-0.206638
-0.171152
-0.198154
--0.186134
-0.102939
-0.368748
-0.143999
--0.0727456
--0.0369903
--0.0366363
-0.0529379
--0.0930282
-0.0541755
-0.0163213
--0.0902165
-0.692023
--0.130191
--0.0875822
-0.565745
-0.0532805
-0.105498
--0.125821
-0.141734
--0.182124
-0
-0.198894
--0.173159
-0.053501
--0.271853
-0.282345
-0.147266
--0.193652
-0.286341
-0.438669
-0.266946
--0.275327
-0.0992954
-0.0532108
-0.155022
-0.146096
--0.175507
-0.334103
-0.0163069
--0.0941967
-0.381442
-0.197046
--0.119594
--0.0380783
--0.0367862
--0.133294
-0.190591
--0.0393701
--0.0377781
-0.107151
-0.110434
-0.327524
--0.0799688
--0.136509
-0.45369
-0.465698
-0
-0.209113
-0.351921
--0.0980842
-0.0551914
-0.112664
-0.10347
-0.112605
--0.0386401
-0.0171886
-0.455249
-0.115864
-0.633043
-0.0814076
--0.155029
-0.210375
-0.216367
--0.0375913
-0.307751
--0.0955882
-0.204649
--0.0392033
-0.492629
--0.135462
--0.0709561
-0.496741
-0.056119
-0.298353
--0.0753637
-0.850259
-0.927824
-0.0170545
--0.19499
-0.377686
-0.0165983
-0.260714
-0.394357
-0.363907
-0.346485
-0.151864
-0.163206
-0.0175698
-0.505993
-0.258182
-0.0171801
-0.692486
-0.295071
-0.109916
-0.0565898
-0
-0.290986
-0.355366
--0.0770671
-0.0580958
-0.24683
--0.0393614
-0.129224
-0.0736175
-0.587548
-0.419262
--0.131435
-0.110607
-0.595281
-0.15095
-0.254103
--0.0944775
--0.0701755
-0.487556
-0.29671
-0.206693
-0.186977
--0.56108
--0.124217
-0.289209
-0.114566
-0.305077
-0.200284
-0.0554922
-0.584279
-0.0587121
-0.0541567
-0
-0.190745
-0
--0.361105
-0.258434
-0.0516274
-0.055012
-0.418821
-0
-0
-0.0573184
--0.0382087
-0.344101
-0.188221
-0.115409
--0.0395625
-0.228548
-0.253647
-0.150037
-0.148581
--0.0901996
-0.0187348
-0.0515705
-0.100958
--0.0931595
--0.0881457
-0.193487
-0.0168289
-0.154614
-0.0679381
-0.190724
-0.201167
--0.0380838
-0.28121
-0.147462
-0.284523
-0.292419
-0.0534547
-0.206144
--0.0883567
-0.282997
-0.229017
--0.0951392
-0
--0.0364716
-0.0161058
--0.038132
-0.386298
-0.0541816
-0.109457
--0.190368
--0.0366819
-0.57492
--0.0364581
-0.222526
-0.0535267
--0.0803637
-0.207453
--0.132977
-0.410382
-0.0555699
-0.29428
--0.0390328
--0.220998
-0.111811
--0.371248
-0.111238
--0.285419
--0.132914
-0.0535834
-0.0182698
-0.401061
-0.213182
-0.0547979
-0.110962
-0.110251
--0.138254
-0.723465
--0.172954
-0.524744
-0.209605
-0.055457
-0.413323
-0.588974
-0.052526
-0.161886
-0.266633
-0.256294
-0.147665
-0.0560942
-0.0551326
-0.224475
--0.307001
-0.433259
-0.420003
-0.0195582
--0.0376896
--0.0922486
--0.13183
--0.129898
-0.0211233
-0.0517
-0.075674
--0.0523229
-0.199854
--0.185471
-0.286675
--0.0749229
-0.365904
-0.0176417
-0.353102
-0.0171679
--0.28007
--0.0934481
-0.0761251
--0.0932072
--0.167351
-0.414906
--0.0372368
-0.160548
-0.103538
-0.369876
--0.0362302
-0.050336
-0.0554993
-0.283197
-0
-0.203563
-0.245142
-0.106668
-0.170701
-0.287045
-0.0193312
-0.107417
-0.291366
-0.387677
-0.304915
-0.0532304
-0.106654
-0.29507
-0.103176
-0.24339
-0.3498
-0.0508543
-0
-0.0554434
--0.0832187
-0.206239
-0.152837
--0.0344475
--0.13456
-0.274221
--0.0383409
-0.10443
--0.140901
-0.0528919
-0.150619
-0.564494
-0.512606
-0.292379
-0.674857
-0.192102
-0.145707
-0.19363
--0.093159
--0.0190495
--0.189921
--0.0866245
-0.26479
--0.0384362
-0.157467
-0.34409
--0.0927411
--0.038036
-0.20171
-0.196013
-0.169329
--0.221027
-0.0573911
-0.198438
-0.0565637
-0.283559
-0.355792
-0.412396
-0.782068
-0.458743
--0.0386336
-0.351516
-0.116528
-0.111558
-0.214454
-0.116619
-0.280676
--0.269742
-0.281305
-0.145972
-0.429025
-0.051495
--0.0391418
--0.037686
-0.413597
--0.313753
-0.448009
-0.204365
-0.523838
-0.249926
-0.563497
--0.130497
-0.349824
--0.0882885
-0.172668
-0.546425
--0.196682
-0.501288
-0.345513
-0.34241
-0.0764421
--0.0785259
--0.188323
-0.418006
--0.0381538
--0.106978
-0.115036
--0.0381925
--0.0388945
-0.105226
--0.4581
--0.0706431
-0.277171
--0.0372707
--0.0385696
-0.110104
-0.210769
--0.0374677
-0.172949
--0.0715449
--0.0367901
-0
-0.41199
--0.0372766
-0.608456
-0.0541276
--0.0377636
-0.291151
-0.21049
--0.126465
-0.112427
-0.155221
--0.0368909
-0.0561122
-0.16498
-0.162185
-0.10765
-0.0521457
-0.199192
-0.203108
--0.0951923
--0.0677796
--0.0371626
--0.0859628
-0.142836
--0.299124
-0.205288
-0.572914
-0.143758
-0.71614
-0.510138
--0.124642
-0.413278
-0.286552
--0.227595
-0.197125
-0.0594272
-0.0529783
-0.112155
--0.130926
-0.0205126
-0.190394
--0.0383838
-0.190631
-0.517989
-0.338263
--0.131879
-0
--0.127434
--0.18864
-0.291029
--0.179938
-0
-0.0168852
-0.104156
--0.160972
-0.20995
-0.106387
--0.16092
--0.21707
-0.113614
--0.2169
--0.38047
--0.290266
-0.873087
-0
-0.113195
-0.205036
-0.208549
--0.0945234
-0.316345
-0.294189
--0.0971196
-0.300796
-0.354177
--0.190141
-0.368593
-0.0174788
-0.321045
--0.0392425
-0.516276
-0.30053
--0.134791
-0.0176612
-0.522259
-0.210282
-0.112026
-0.110755
-0.215618
--0.0766949
--0.288278
-0.0735469
--0.0772122
-0.35018
-0.441183
--0.277535
-0.306815
-0.509306
--0.078219
-0.344756
-0.14935
-0.344601
-0.486503
--0.226562
-0.0543863
--0.227081
-0.315909
-0.303481
-0.408693
-0.200849
--0.294528
--0.0207787
-0.0175737
--0.168209
-0.414918
-0.743761
--0.192989
-0.127409
-0.454348
--0.127063
-0.213405
--0.129687
-0.57811
-0.666421
--0.072698
--0.0380977
--0.0705878
-0.369164
-0.0550638
-0.326178
-0.89298
-0.295899
--0.135739
-0.0170783
-0.325443
-0.0174516
-0.299931
--0.362948
-0.352721
--0.07377
-0.0201471
-0.652708
--0.0378986
-0.190003
-0.198548
--0.0371751
--0.0948908
--0.303625
-0.200897
-0.103754
-0.299804
-0.646412
-0.406586
-0.336997
-0.109028
-0.694243
-0.144471
-0.195307
--0.0902493
-0.186462
-0.150482
-0.333242
-0.539289
-0.0555691
-0.395391
-0.15019
-0.164841
-0.32832
-0.207673
-0.198514
-0.35335
--0.0347132
-0.335854
--0.0897917
-0.0567958
--0.0910911
-0
-0.0530796
--0.132131
--0.130758
-0.364681
-0.211591
-0.302371
--0.0402785
-0.467354
--0.158215
-0.157409
--0.123297
-0.0560471
--0.182921
-0.0568145
-0.0577432
-0.113305
-0.224295
-0.469658
-0.0398582
-0.0554792
--0.0709369
-0.184296
-0.255432
-0.762088
--0.217474
-0.167584
-0.0543294
--0.0391005
-0.148682
-0.298052
--0.178679
--0.0393602
-0.163246
--0.0979827
-0.111713
-0.262854
--0.092475
-0.114097
-0.344963
-0.28944
-0.891244
--0.193259
--0.0384606
--0.230009
-0.302482
--0.135626
--0.0912868
-0
-0.25153
-0.334429
-0.111257
-0.271614
--0.038181
-0.118228
-0.166221
-0.0575116
-0.437285
-0.499696
-0.367377
-0.264444
-0.112326
-0.296294
-0.107654
-0.0395828
--0.0371662
-0.301126
-0.0576024
--0.131694
-0.256087
-0.176566
-0.0163744
-0.207722
--0.037046
--0.324993
-0.342014
--0.427907
-0.586811
-0.41692
-0.196336
-0.0807241
--0.182934
-0.110991
-0.320095
-0.109833
-0.0528049
-0
-0.0564881
-0.151188
--0.303516
--0.0901186
-0.0536705
-0.248975
-0.255681
-0.299008
--0.0743764
--0.134271
-0.163154
-0.11103
--0.0757944
-0
--0.122139
-0.143524
-0.0165921
-0.197482
-0.247358
-0.0713401
-0.0526095
-0.199743
-0.245762
-0.143578
-0.104201
-0.0205587
-0.232412
-0.440867
-0.141541
-0.0614483
-0.148003
--0.0963
--0.0865978
--0.0360536
-0.267314
-0.052991
-0.185981
-0.0530571
-0.240587
-0.0196702
-0.379156
-0.104701
-0.244106
-0.202759
--0.174603
-0.189572
-0
-0.240231
-0.0509845
-0.055564
-0.0983407
-0.291976
-0.0155929
-0.352416
--0.0382137
-0.290401
-0.486123
-0.303011
--0.306878
--0.0385924
-0.397928
--0.0952231
-0.053002
-0.112053
-0.102267
--0.09516
--0.181121
-0.0167362
-0.332331
-0.256009
-0.106859
--0.18674
-0.24656
--0.0390302
-0.337524
-0.0201529
-0.561181
-0.150572
--0.127054
--0.192178
--0.0746357
--0.0218007
--0.17473
--0.227766
-0.199042
--0.0928136
-0.0168508
--0.31045
-0.299296
-0
--0.0400117
-0.204241
-0.0522395
-0.0550984
-0.195258
--0.0383617
--0.0724225
-0.653099
-0.535613
-0.350987
-0.257878
-0.412869
-0.255532
-0
-0.263807
--0.223952
--0.0364748
-0.673887
-0.428889
--0.15414
-0.567174
-0.0569115
-0.595573
--0.19154
--0.0353214
--0.1358
--0.0364839
-0.10235
-0.361442
-0.162911
-0.144622
--0.283615
-0.260031
--0.315522
-0.206058
-0
-0.051989
--0.22701
-0.339096
--0.0370902
-0.0532167
-0.170377
--0.312923
-0.264628
-0.352023
-0.294951
-0.449111
-0.216545
-0.109169
--0.195616
-0.392585
-0.350862
-0.338964
-0.263437
-0.0509029
-0.510461
-0.0552383
-0.139691
--0.178449
--0.0377465
-0.0697528
--0.366549
-0.147853
-0.336768
--0.291746
--0.186509
-0.052456
--0.0413936
--0.0409586
-0.712445
-0.309841
-0.165813
-0.499677
--0.0978084
--0.304554
-0.162253
-0.0568558
--0.146405
-0.306408
-0.0765684
-0.11318
-0.0603802
--0.0410998
--0.148282
--0.128939
--0.521748
--0.190701
-0
--0.0901057
-0.328637
-0.297734
-0.128709
--0.0190388
--0.203547
-0.0596178
-0.0178135
-0.0758514
-0
-0.211883
--0.0767569
-0.149009
-0.332504
--0.0787714
-0
-0.0567993
--0.097405
-0.273273
-0.0817788
--0.191327
-0.162648
-0.360346
-0.186128
--0.0407618
-0.485632
--0.204428
-0.130042
-0.109669
-0.273444
-0.45833
-0.156204
-0.111651
-0.212765
--0.384164
-0.0591624
-0.382379
--0.336729
-0.317301
-0.0190919
--0.0961388
-0.666386
-0.373133
-0.433606
--0.0960685
-0.406661
--0.0769356
-0.659396
-0.117204
--0.018159
-0.0782547
--0.0415133
-0.058148
-0.0592753
-0.222948
-0.0601246
--0.040347
-0.387664
-0.32645
-0.0572674
-0.120059
-0.119272
-0.362376
-0.288594
-0.436096
--0.10001
-0.621897
--0.0389892
-0.646921
-0.275654
-0.0179593
-0.162564
--0.0405705
-0.0615476
-0.0179062
--0.144217
--0.135969
-0.127508
-0.057553
-0.154673
--0.231507
-0.48325
-0
-0.0178897
--0.135052
-0.155961
-0.0568036
-0.351032
-0.148141
--0.0400084
-0.0203192
-0.206906
-0.196922
-0.136673
-0.825192
--0.0399233
--0.132834
-0.0176489
-0.206253
-0.407608
-0.200739
-0.0581324
-0.225839
--0.076253
-0.0567074
--0.0393308
-0.518312
-0.0715682
--0.169305
-0.200687
-0.0468777
-0.049454
-0
-0.313741
--0.0304846
--0.163747
-0.174274
-0.314856
-0.0662771
-0.425149
-0.438754
-0.130626
-0.063032
--0.341693
-0.129416
-0.132433
-0.361642
-0.261623
-0.063955
-0.102584
--0.0157739
-0.336565
-0.547824
-0
-0.1163
-0.13613
--0.204077
-0.150639
-0.0635381
-0.184263
-0.156339
--0.296538
-0.257608
-0.182487
-0.0986212
-0.0513227
-0.04994
-0.103209
--0.0869983
--0.165471
--0.0837367
--0.151932
-0.410155
-0.236458
--0.0741656
-0.0530241
-0.100421
-0.194436
-0.049169
-0.476389
-0
-0.0664073
-0.285876
-0.23869
-0.135781
-0.334099
--0.203666
-0.456372
--0.201058
-0.0531478
--0.122228
--0.0736766
-0.608573
-0.328858
-0.378619
-0.0163806
-0.33082
-0.770489
-0.143023
-0.141987
-0.363872
-0.0667063
--0.107035
--0.27265
-0.608527
--0.179758
--0.162414
--0.0364048
-0.101863
--0.211488
-0.323653
-0.0503701
-0.189738
-0.447577
-0.153379
-0.123978
-0.241835
-0.187571
-0.103959
-0.540665
--0.0885764
-0.191654
-0.0529315
-0.245397
-0.327684
-0.105096
--0.161018
--0.0722409
-0.185787
-0.204157
--0.116547
-0.365661
--0.0359644
--0.0354511
--0.121296
-0.2314
-0.394829
--0.0703038
--0.18244
-0.466249
-0.356408
-0.0731502
--0.0857927
--0.0165544
--0.0855775
--0.0353962
-0.261012
-0.016167
-0.372166
-0.278645
-0.359966
--0.116375
--0.151032
-0.201185
-0.414616
-0.296118
-0.473114
-0.337446
-0.163497
-0.0615148
--0.0911313
-0.0599396
-0.19262
-0.0187056
--0.0368282
-0.124814
--0.0976231
-0.282811
-0.205095
-0.217068
-0.320287
-0.347417
--0.257608
-0.0604825
-0.137334
-0.406715
-0
-0.0599819
-0.055389
-0.0592768
-0.274189
-0.160071
-0.208866
-0
--0.178801
-0.225723
-0.108662
-0.158771
--0.0383113
-0.397312
-0.408797
--0.20576
-0.14602
-0.609779
-0.0561025
-0.482562
--0.0396307
-0.057929
-0
-0.168173
--0.0400275
-0.219087
-0.304096
-0.537597
-0.161589
--0.14296
--0.036968
-0.293434
-0.112659
-0.480427
-0.133584
-0.0620396
-0.160509
-0.328993
-0.36365
-0.0182833
-0.202312
-0.0182392
--0.0183416
-0.220146
-0.294303
-0
-0.0173062
-0
-0.0559563
-0
-0.272728
-0.0177386
-0.268628
-0.0180917
-0.0186176
--0.194875
-0.528397
-0.454702
-0.48612
-0.636364
-0.262546
--0.236893
--0.0899916
--0.0405053
-0.0160521
-0.889375
--0.183637
-0.207363
--0.0939695
-0.0174989
--0.0390626
-0.463868
--0.16711
-0
--0.0178301
-0.159138
--0.380155
-0.281247
--0.0952606
-0.114795
-0.110025
-0
-0
-0.147042
-0.206692
-0
--0.212604
-0.15661
-0.0161706
-0.0588146
-0.109026
-0.0205485
--0.173275
-0.0554776
-0.156864
-0.147079
-0.471487
-0.0171268
-0.397644
-0.208534
-0.278772
-0.444456
-0.478302
-0.355086
-0.0513147
--0.192577
-0.340486
-0
-0.670413
-0.155316
-0.0508449
--0.243094
-0.151331
-0.0186494
-0.0332863
-0.250768
-0.163524
--0.0865747
-0.288395
-0.0159099
--0.0896668
-0.157388
-0.29479
-0.10164
-0.195804
--0.0869963
-0.444547
-0.0520675
--0.0895524
--0.364478
--0.0914471
--0.0368985
-0.0171629
-0.0160242
-0.017306
-0.417509
-0.288675
-0.351638
-0.016233
-0.204704
--0.0400021
-0.426151
-0.317523
--0.0372784
-0.333418
-0.197584
--0.0359942
-0.719759
-0.194587
-0.284868
--0.0903301
--0.0581912
-0.296062
--0.0795553
--0.0751974
-0.336581
-0.195598
-0.107102
-0.353027
-0.391383
--0.0174956
--0.123012
-0.0168623
-0.847764
-0.10595
-0.0737316
-0.0539391
-0.144866
--0.183326
--0.0933479
-0.57541
-0.197317
--0.178311
-0.459207
-0.28854
-0.0552747
-0.297799
-0.16153
--0.100656
-0.199464
-0.416612
-0.0160817
-0.106814
-0.0762737
-0.02038
-0.505589
-0.112967
-0.0165136
-0.298977
-0.244292
-0.121306
-0.0165528
-0.0161197
-0.199797
--0.357189
--0.020109
-0.106867
-0.0501258
--0.0391898
--0.125231
--0.0391674
--0.0705992
-0.0698337
-0.0531084
--0.269512
-0.0545021
-0.491069
-0.105401
--0.177826
--0.284454
-0.0157252
-0.0492591
-0.200931
--0.153768
-0.0737874
--0.212116
-0.279998
-0.309127
-0.146884
-0.278934
--0.0352898
-0.136715
--0.0344939
-0.242287
-0.187471
-0.257662
-0.0506976
-0.243916
--0.269102
-0.277383
--0.086984
--0.168865
-0.518039
--0.127147
-0.0727362
-0.605949
-0.0991658
-0.335605
-0.121755
-0.404235
-0.0614481
--0.287625
-0.325437
--0.0336257
--0.0552229
-0.0502255
-0.0465384
-0.130294
--0.252748
-0.0492743
-0.0889692
-0
-0.0442897
--0.439689
-0.0909556
-0.314664
-0.206579
-0.133294
--0.0323128
--0.195172
-0.577775
-0.134032
-0.220636
-0.136188
-0.305957
--0.0353999
--0.114681
--0.117167
-0.172243
-0.073549
-0.122964
-0.015829
-0.0175166
--0.16448
-0.12441
-0.0506176
-0.412254
-0.237024
-0.0934541
-0.188206
-0.0175448
-0.0506075
-0.0179727
-0.425397
-0.507252
--0.204972
-0.227468
-0.243906
-0.095515
-0.325695
-0.227492
-0.142539
-0.298546
-0.151781
--0.0333981
-0.245432
-0.245346
-0.875194
-0.386468
-0.274341
-0.146086
-0.42108
-0.112068
-0.10146
-0.625416
-0.371736
--0.0338024
-0.0712808
-0.0157143
-0.312102
-0.269462
--0.0357871
--0.115981
-0.185334
--0.169985
-0.130933
-0.348487
-0.188013
-0.217926
--0.199476
-0.0948431
-0.281225
--0.148499
-0.660521
-0.0151217
-0.586651
-0.263295
--0.084882
-0.329632
-0.158451
-0.0152115
-0.267034
-0.109777
--0.0359487
-0.520787
-0.0513008
-0.266577
-0.185574
-0.312792
--0.0687411
-0.369673
-0.0484438
--0.1659
-0.404255
-0.0152687
--0.0879575
-0.0148089
-0
-0.412205
-0.0513138
--0.351849
--0.0660659
-0.195406
-0.152273
-0.173158
-0.0491376
-0.0473521
-0.284214
--0.163849
-0.0989422
-0.0912827
-0.0495231
-0
-0
-0.185105
--0.0867996
-0.27548
-0.0509463
-0.462011
--0.246799
--0.249377
-0.607789
--0.0365153
-0.231937
--0.0879586
-0.67796
--0.169354
--0.126894
--0.0891137
-0.283961
--0.164643
-0.277424
--0.037396
--0.344165
-0.296143
--0.256784
-0.317369
-0
-0.156289
--0.036387
-0.297744
-0.261611
-0.206286
--0.0940005
-0.246279
-0.112654
--0.249937
-0.0560266
-0.512273
-0.146276
-0.412054
-0.0173777
-0.0549133
-0.200393
-0.113553
-0.436723
-0.164179
-0.301944
-0.145492
-0.366834
--0.293239
-0.221241
--0.0973945
--0.37354
-0.0548151
-0.173017
-0.219846
-0.287451
-0.10832
--0.0947248
-0.346682
-0.205431
-0.197013
-0.0569611
-0.146314
--0.0409633
--0.130769
-0.328021
--0.0371144
-0.0700996
-0.359995
--0.0378129
-0.262476
-0.532195
-0.207351
-0.21593
-0.112519
-0.847977
-0.111947
-0.0741191
-0.115149
-0.303527
-0.291773
-0.160944
-0.106094
-0.337107
-0.348546
--0.06951
-0.152992
--0.0367049
-0.0534153
-0.330517
-0.332241
--0.257984
--0.0908069
-0.125934
--0.0908355
--0.0878657
-0.338175
--0.0347881
-0.0743319
-0.39728
--0.0723786
-0.107956
--0.0343675
--0.291393
-0.0494501
-0.0150679
-0.443659
-0.135058
-0.189123
--0.119774
--0.0695087
-0.100286
-0.287816
--0.083471
-0.242036
-0.0469249
--0.066331
--0.239538
--0.0644244
-0.131517
-0
--0.246244
-0.0946576
--0.0785968
--0.0816429
--0.185042
-0.427645
-0.147284
-0.142501
-0.0514861
-0.244003
--0.0982172
-0.148894
--0.0360138
-0.251318
-0.156793
--0.189198
--0.221069
--0.117669
--0.183155
-0.238477
-0
-0.0490345
-0.483677
-0.325975
-0.633246
-0.322806
--0.288349
-0.245722
-0.0157847
-0.177414
--0.325411
-0.281348
-0.41889
-0.689003
-0.144586
-0
-0.148303
-0.380355
-0.169045
-0.105361
-0.27734
-0.583864
--0.0944177
-0.442781
-0.259187
--0.29346
-0.164897
-0.0537891
-0.145901
--0.0378718
-0.254622
-0.0158143
--0.0395375
-0.106645
-0.0201548
--0.13416
-0.43135
-0.121682
-0.358943
-0.0193368
--0.271084
-0.190585
--0.131375
-0.203538
--0.285805
--0.0380047
-0.206632
--0.188255
-0.150313
-0.0167956
--0.134493
-0.35799
-0.0553154
--0.0367581
--0.0934894
-0.107187
-0.363174
-0.109544
--0.13422
-0.0530868
-0.3076
-0.255207
-0.350522
-0.34042
-0
-0
-0.254197
-0.106013
-0.147554
-0.593501
-0.210439
-0.343609
--0.185307
-0.337628
-0.0537002
--0.036793
-0.304178
--0.129196
-0.0569863
--0.0378593
-0.290991
-0.241355
-0.228325
-0.496784
--0.211676
-0.327283
--0.185207
-0.35009
-0.148425
-0.323787
-0.053835
--0.0865996
-0.189886
-0.0530178
-0.186378
-0.183111
-0.0520716
-0.0512446
--0.0359891
-0.279594
-0
-0.048836
-0.615107
-0.0473638
-0.100376
-0.321537
-0.189344
--0.164263
--0.0348157
-0.71251
-0.135016
--0.0804284
--0.0704792
-0.17427
-0.329297
--0.116557
-0.0221281
diff --git a/sasview/test/2d_data/SILIC009.ASC b/sasview/test/2d_data/SILIC009.ASC
deleted file mode 100644
index 730e155..0000000
--- a/sasview/test/2d_data/SILIC009.ASC
+++ /dev/null
@@ -1,16403 +0,0 @@
-FILE: SILIC009.SA3_SRK_S109 CREATED: 22-JAN-2008 02:39:11
-LABEL: Silica 2 pct in D2O Scatt 1.3M
-MON CNT LAMBDA(A) DET_OFF(cm) DET_DIST(m) TRANS THICK(cm)
-7.6329e+06 6 20 1.33 1 0.2
-BCENT(X,Y) A1(mm) A2(mm) A1A2DIST(m) DL/L BSTOP(mm) DET_TYP
-106.8 64.59 50 3 5.4675 0.142 50.8 ORNL
-SAM: RAW Data File: SILIC009.SA3_SRK_S109
-BGD: none
-EMP: none
-DIV: none
-MASK: none
-ABS Parameters (3-6): none
-Average Choices: none
-
-*** Data written from RAW folder and may not be a fully corrected data file ***
-The detector image is a standard X-Y coordinate system
-Data is written by row, starting with Y=1 and X=(1->128)
-ASCII data created Wed, Jan 14, 2009 5:16:36 PM
-
-121
-62
-120
-70
-67
-91
-77
-86
-78
-66
-84
-61
-67
-87
-63
-93
-83
-86
-72
-89
-71
-103
-50
-69
-82
-68
-84
-74
-54
-96
-47
-45
-108
-36
-86
-92
-111
-88
-123
-86
-103
-61
-78
-62
-88
-69
-116
-59
-82
-19
-57
-52
-88
-57
-70
-71
-103
-66
-65
-71
-77
-55
-81
-64
-84
-30
-100
-52
-117
-80
-74
-67
-104
-52
-93
-67
-101
-51
-93
-58
-150
-79
-89
-128
-124
-97
-128
-113
-136
-81
-113
-103
-122
-114
-94
-91
-199
-107
-129
-147
-170
-104
-170
-121
-156
-87
-158
-153
-148
-134
-143
-128
-154
-103
-137
-132
-163
-144
-143
-141
-176
-142
-117
-145
-202
-127
-152
-253
-170
-100
-134
-110
-108
-110
-129
-104
-121
-107
-120
-104
-102
-130
-95
-110
-111
-120
-105
-106
-98
-135
-103
-120
-111
-104
-103
-140
-117
-119
-101
-123
-133
-71
-91
-129
-124
-119
-154
-114
-141
-116
-104
-107
-133
-110
-121
-97
-156
-42
-101
-87
-136
-97
-131
-105
-147
-82
-118
-98
-134
-124
-132
-132
-153
-72
-141
-99
-155
-116
-107
-113
-149
-106
-123
-94
-149
-92
-128
-111
-169
-114
-142
-157
-142
-133
-140
-128
-158
-116
-156
-121
-152
-141
-152
-127
-197
-103
-113
-189
-143
-122
-177
-139
-147
-119
-137
-173
-148
-142
-143
-139
-162
-129
-149
-170
-178
-141
-152
-178
-186
-146
-183
-141
-216
-141
-138
-272
-167
-102
-132
-128
-105
-133
-128
-111
-127
-111
-135
-156
-116
-158
-116
-117
-121
-155
-121
-143
-127
-153
-112
-108
-102
-125
-132
-131
-96
-132
-119
-109
-167
-107
-129
-154
-142
-115
-179
-120
-150
-102
-115
-122
-157
-122
-144
-109
-168
-73
-121
-109
-148
-107
-132
-124
-168
-118
-120
-104
-126
-129
-118
-127
-145
-92
-120
-101
-179
-136
-123
-119
-157
-120
-131
-107
-136
-108
-147
-121
-199
-141
-111
-151
-176
-150
-162
-170
-175
-136
-161
-138
-191
-147
-189
-133
-234
-163
-132
-185
-180
-125
-189
-140
-177
-156
-148
-193
-148
-154
-146
-186
-192
-154
-148
-184
-206
-173
-174
-186
-176
-140
-169
-161
-218
-149
-147
-325
-176
-110
-145
-114
-87
-141
-107
-131
-109
-133
-106
-149
-119
-130
-140
-114
-120
-105
-127
-136
-105
-141
-117
-132
-140
-121
-121
-148
-105
-169
-93
-109
-175
-90
-125
-150
-131
-116
-185
-114
-142
-107
-111
-100
-130
-120
-135
-108
-150
-67
-127
-109
-143
-106
-110
-102
-142
-105
-141
-131
-136
-116
-129
-117
-128
-95
-146
-106
-171
-115
-101
-110
-153
-118
-120
-148
-142
-116
-143
-107
-199
-126
-141
-165
-154
-125
-135
-155
-174
-125
-144
-127
-184
-149
-142
-128
-192
-151
-116
-174
-188
-136
-188
-167
-155
-147
-145
-159
-160
-144
-138
-149
-171
-115
-129
-188
-167
-144
-160
-149
-166
-171
-164
-146
-184
-135
-133
-297
-156
-89
-140
-132
-109
-118
-131
-114
-140
-112
-113
-112
-128
-117
-131
-128
-108
-122
-131
-124
-119
-147
-132
-124
-144
-112
-129
-158
-107
-151
-113
-124
-156
-103
-121
-164
-138
-122
-186
-131
-153
-104
-113
-117
-135
-131
-144
-139
-164
-71
-127
-133
-153
-112
-157
-148
-149
-123
-123
-122
-172
-149
-164
-127
-151
-101
-162
-127
-173
-157
-138
-127
-179
-126
-135
-146
-142
-127
-164
-120
-220
-152
-142
-160
-176
-157
-172
-140
-196
-172
-165
-172
-195
-168
-166
-177
-200
-155
-138
-208
-189
-147
-215
-155
-163
-146
-160
-172
-201
-164
-132
-173
-197
-176
-168
-209
-187
-164
-168
-179
-180
-178
-174
-169
-196
-155
-144
-304
-144
-112
-147
-118
-107
-141
-133
-117
-113
-97
-120
-111
-123
-102
-114
-117
-122
-130
-117
-118
-101
-140
-111
-127
-113
-98
-133
-108
-118
-134
-100
-111
-147
-74
-117
-138
-175
-144
-185
-109
-143
-97
-123
-111
-130
-121
-164
-123
-165
-64
-138
-115
-138
-117
-143
-97
-154
-118
-110
-129
-128
-141
-136
-130
-165
-89
-139
-113
-153
-135
-116
-129
-158
-95
-126
-114
-154
-104
-134
-108
-188
-153
-128
-172
-170
-129
-143
-157
-169
-122
-136
-155
-171
-135
-153
-145
-184
-161
-113
-203
-173
-131
-200
-133
-156
-142
-149
-161
-182
-153
-177
-156
-169
-135
-131
-195
-187
-147
-160
-154
-183
-148
-163
-160
-216
-152
-137
-261
-134
-100
-146
-119
-96
-111
-144
-130
-126
-129
-104
-105
-117
-151
-119
-122
-145
-129
-143
-126
-96
-152
-125
-104
-121
-124
-124
-117
-96
-121
-113
-118
-154
-106
-130
-163
-167
-151
-168
-126
-156
-129
-140
-124
-144
-117
-128
-112
-155
-65
-139
-104
-150
-105
-141
-130
-159
-103
-131
-144
-146
-130
-134
-135
-136
-93
-141
-138
-165
-152
-145
-143
-161
-123
-146
-138
-145
-135
-151
-137
-198
-138
-132
-176
-161
-140
-164
-148
-183
-142
-139
-154
-195
-144
-138
-160
-198
-188
-115
-231
-181
-133
-189
-173
-162
-172
-158
-167
-184
-154
-171
-155
-182
-171
-150
-202
-192
-153
-153
-166
-162
-151
-140
-159
-238
-193
-129
-279
-143
-102
-154
-135
-113
-138
-138
-125
-114
-94
-122
-118
-131
-137
-118
-109
-104
-124
-140
-125
-112
-154
-100
-121
-104
-123
-162
-137
-116
-133
-132
-115
-152
-107
-113
-176
-123
-129
-180
-133
-173
-113
-137
-131
-159
-146
-142
-110
-150
-75
-127
-119
-155
-119
-134
-127
-136
-103
-123
-133
-138
-131
-137
-139
-175
-95
-153
-119
-166
-146
-119
-130
-193
-118
-120
-121
-146
-124
-160
-141
-174
-154
-133
-178
-166
-140
-152
-152
-188
-135
-136
-148
-186
-164
-157
-116
-220
-153
-126
-180
-169
-147
-182
-169
-177
-127
-162
-156
-192
-185
-178
-151
-201
-143
-157
-179
-196
-159
-186
-181
-173
-164
-151
-146
-190
-143
-147
-275
-161
-99
-135
-128
-112
-131
-127
-123
-122
-113
-126
-127
-120
-123
-124
-144
-115
-129
-140
-136
-108
-154
-105
-115
-128
-112
-135
-151
-108
-133
-99
-95
-177
-118
-125
-155
-146
-139
-178
-140
-148
-112
-108
-133
-132
-131
-130
-110
-154
-80
-154
-133
-160
-112
-125
-121
-159
-128
-124
-118
-163
-149
-134
-108
-163
-112
-132
-115
-150
-156
-120
-151
-169
-131
-134
-131
-150
-132
-136
-145
-201
-139
-114
-160
-167
-151
-155
-146
-180
-156
-175
-165
-172
-177
-155
-150
-221
-160
-122
-204
-192
-130
-186
-168
-153
-138
-164
-177
-169
-160
-166
-165
-191
-152
-137
-173
-205
-165
-166
-191
-187
-171
-174
-175
-186
-133
-155
-280
-180
-115
-140
-144
-94
-129
-126
-116
-99
-105
-120
-121
-116
-144
-131
-116
-95
-131
-151
-143
-122
-132
-122
-128
-146
-119
-121
-141
-103
-116
-110
-101
-163
-115
-138
-134
-157
-124
-188
-133
-135
-114
-137
-121
-138
-118
-146
-128
-161
-73
-106
-122
-140
-131
-127
-136
-153
-138
-141
-124
-160
-114
-152
-127
-163
-108
-152
-147
-155
-119
-125
-121
-184
-117
-136
-125
-166
-128
-150
-127
-181
-147
-135
-176
-175
-161
-158
-138
-179
-149
-149
-146
-195
-183
-157
-142
-194
-148
-125
-169
-185
-114
-185
-146
-192
-169
-152
-173
-185
-167
-153
-166
-194
-155
-151
-163
-184
-178
-161
-170
-191
-149
-169
-177
-211
-158
-159
-288
-178
-110
-138
-139
-121
-168
-102
-131
-136
-111
-139
-134
-116
-137
-88
-131
-122
-150
-150
-140
-126
-164
-129
-114
-128
-129
-144
-113
-98
-140
-118
-107
-166
-93
-113
-159
-145
-120
-189
-161
-144
-120
-131
-143
-154
-120
-144
-162
-162
-63
-140
-133
-148
-145
-135
-106
-163
-124
-139
-142
-150
-141
-145
-143
-165
-123
-141
-141
-164
-160
-132
-146
-157
-125
-142
-136
-141
-132
-149
-150
-209
-173
-138
-183
-197
-147
-163
-169
-192
-153
-173
-151
-198
-153
-192
-164
-236
-151
-127
-200
-187
-140
-180
-159
-177
-173
-161
-161
-157
-171
-170
-164
-220
-157
-142
-188
-206
-174
-170
-175
-170
-173
-170
-184
-221
-165
-187
-290
-142
-136
-127
-123
-122
-118
-124
-133
-125
-103
-126
-104
-114
-127
-94
-119
-119
-102
-134
-116
-108
-159
-110
-124
-117
-131
-110
-133
-102
-120
-111
-106
-140
-106
-116
-161
-125
-109
-169
-135
-137
-114
-121
-126
-130
-139
-139
-96
-171
-67
-121
-102
-156
-96
-105
-118
-135
-113
-130
-142
-140
-113
-118
-119
-129
-118
-130
-117
-162
-110
-134
-125
-172
-117
-118
-135
-144
-121
-139
-127
-183
-139
-112
-165
-138
-154
-151
-164
-187
-140
-141
-146
-176
-143
-149
-133
-236
-149
-129
-165
-178
-127
-176
-143
-184
-158
-145
-162
-142
-151
-145
-189
-190
-166
-119
-160
-184
-142
-149
-151
-165
-148
-148
-160
-189
-138
-142
-282
-166
-131
-158
-140
-119
-137
-139
-123
-124
-103
-131
-143
-119
-119
-125
-140
-129
-120
-144
-119
-124
-164
-117
-130
-138
-132
-134
-127
-124
-144
-123
-119
-197
-105
-140
-179
-158
-144
-195
-129
-167
-127
-119
-140
-141
-126
-145
-120
-147
-93
-140
-127
-139
-110
-157
-137
-154
-134
-124
-172
-164
-151
-150
-160
-160
-125
-152
-155
-197
-143
-140
-139
-163
-124
-130
-142
-175
-134
-162
-128
-198
-147
-126
-160
-172
-164
-164
-162
-186
-158
-160
-158
-196
-163
-178
-150
-217
-177
-128
-189
-175
-150
-195
-189
-150
-165
-165
-156
-174
-158
-162
-185
-192
-166
-149
-199
-210
-177
-182
-183
-214
-152
-178
-177
-207
-178
-135
-318
-176
-86
-135
-116
-95
-117
-103
-116
-111
-101
-120
-114
-110
-132
-107
-126
-104
-127
-126
-113
-93
-128
-119
-121
-105
-112
-120
-144
-110
-140
-105
-98
-140
-92
-121
-164
-134
-118
-172
-126
-118
-110
-105
-118
-151
-100
-148
-133
-164
-77
-107
-129
-162
-90
-121
-126
-162
-112
-119
-137
-150
-124
-155
-111
-156
-89
-111
-131
-149
-125
-118
-96
-157
-116
-138
-141
-183
-134
-154
-117
-155
-135
-123
-144
-152
-123
-144
-131
-156
-137
-143
-139
-188
-122
-183
-128
-181
-128
-112
-194
-172
-139
-167
-154
-178
-157
-157
-149
-158
-157
-151
-159
-174
-131
-140
-171
-188
-137
-155
-175
-153
-159
-152
-143
-226
-131
-137
-275
-151
-136
-123
-139
-132
-129
-145
-133
-127
-128
-114
-119
-112
-143
-112
-134
-120
-141
-142
-141
-131
-161
-122
-144
-123
-143
-140
-144
-162
-148
-113
-118
-162
-107
-109
-197
-174
-136
-201
-116
-154
-136
-137
-138
-166
-162
-147
-133
-184
-103
-152
-129
-157
-134
-152
-160
-171
-132
-130
-164
-154
-154
-154
-159
-152
-117
-148
-141
-159
-137
-130
-139
-183
-124
-163
-175
-178
-142
-175
-159
-207
-156
-167
-188
-163
-176
-167
-168
-187
-150
-180
-176
-196
-178
-184
-169
-199
-194
-133
-210
-192
-160
-169
-185
-210
-172
-158
-186
-170
-169
-158
-187
-168
-170
-157
-171
-203
-164
-164
-177
-183
-175
-161
-178
-222
-154
-155
-299
-185
-114
-131
-119
-107
-143
-122
-139
-133
-130
-131
-146
-110
-128
-110
-118
-118
-112
-131
-130
-126
-159
-114
-106
-130
-129
-141
-136
-90
-125
-92
-119
-170
-101
-112
-150
-164
-150
-187
-110
-160
-120
-135
-138
-129
-113
-134
-119
-170
-84
-132
-111
-172
-108
-141
-140
-149
-131
-148
-146
-149
-175
-133
-140
-145
-115
-154
-124
-157
-146
-149
-153
-167
-119
-142
-140
-156
-109
-174
-139
-203
-163
-155
-177
-164
-157
-165
-164
-177
-154
-150
-159
-178
-131
-170
-155
-199
-151
-117
-202
-199
-153
-215
-174
-195
-135
-148
-167
-172
-168
-155
-145
-200
-124
-129
-172
-191
-142
-180
-163
-164
-144
-163
-129
-200
-140
-134
-270
-154
-118
-159
-141
-133
-128
-109
-111
-115
-115
-124
-128
-130
-126
-114
-119
-129
-117
-113
-118
-118
-146
-120
-126
-128
-149
-160
-117
-140
-171
-125
-126
-155
-109
-127
-146
-147
-121
-190
-139
-141
-127
-114
-157
-159
-126
-143
-129
-160
-87
-138
-116
-148
-111
-141
-120
-173
-129
-147
-142
-135
-152
-141
-131
-163
-120
-138
-146
-177
-132
-134
-151
-185
-134
-146
-146
-180
-143
-159
-140
-215
-173
-131
-192
-188
-151
-160
-148
-181
-141
-170
-160
-199
-177
-156
-155
-217
-192
-128
-184
-208
-141
-192
-150
-181
-161
-162
-179
-184
-186
-175
-173
-200
-173
-180
-194
-229
-160
-152
-221
-179
-182
-163
-168
-194
-159
-143
-312
-162
-116
-131
-132
-108
-121
-128
-134
-124
-143
-138
-122
-108
-132
-112
-145
-110
-133
-131
-145
-117
-142
-139
-119
-124
-134
-147
-119
-108
-161
-127
-129
-158
-92
-133
-169
-125
-113
-190
-134
-142
-122
-106
-136
-137
-140
-142
-118
-170
-94
-138
-131
-147
-121
-130
-123
-190
-125
-136
-147
-148
-126
-133
-135
-173
-114
-145
-136
-166
-144
-128
-155
-177
-117
-149
-134
-155
-128
-163
-142
-197
-147
-152
-176
-169
-157
-171
-156
-184
-150
-164
-148
-199
-158
-183
-164
-214
-163
-129
-180
-185
-163
-191
-202
-183
-171
-137
-171
-181
-144
-203
-176
-201
-157
-171
-175
-197
-159
-165
-192
-196
-159
-168
-155
-216
-145
-152
-305
-177
-106
-152
-135
-111
-129
-146
-104
-121
-151
-134
-103
-113
-155
-115
-134
-124
-124
-139
-132
-115
-158
-129
-128
-120
-140
-122
-142
-123
-139
-114
-130
-182
-109
-133
-145
-133
-147
-202
-134
-139
-108
-129
-135
-127
-123
-153
-122
-171
-99
-134
-106
-138
-111
-140
-109
-156
-133
-143
-134
-159
-146
-136
-150
-153
-119
-150
-133
-170
-135
-150
-126
-195
-136
-164
-146
-177
-134
-162
-151
-201
-155
-121
-165
-183
-134
-175
-151
-219
-167
-174
-144
-184
-176
-168
-139
-206
-182
-137
-217
-192
-153
-167
-164
-182
-173
-162
-179
-177
-162
-169
-171
-210
-166
-153
-194
-207
-161
-164
-203
-184
-191
-169
-177
-203
-162
-154
-281
-154
-94
-138
-129
-95
-137
-96
-126
-139
-128
-125
-126
-113
-117
-113
-135
-125
-138
-133
-149
-110
-121
-135
-112
-145
-119
-126
-106
-135
-147
-115
-116
-131
-95
-126
-145
-138
-130
-158
-124
-160
-116
-120
-124
-121
-130
-142
-106
-175
-79
-104
-114
-142
-116
-119
-115
-173
-106
-130
-128
-165
-126
-119
-139
-134
-113
-142
-133
-150
-121
-112
-134
-172
-122
-149
-159
-169
-138
-180
-122
-197
-146
-137
-152
-134
-149
-135
-144
-174
-144
-138
-144
-175
-151
-137
-154
-214
-171
-118
-194
-149
-113
-173
-177
-163
-144
-159
-157
-153
-143
-161
-148
-197
-138
-130
-178
-188
-130
-161
-198
-175
-137
-143
-159
-190
-147
-118
-274
-197
-126
-141
-128
-126
-152
-116
-132
-139
-130
-149
-154
-144
-159
-124
-152
-139
-144
-157
-148
-148
-156
-128
-136
-130
-127
-162
-146
-146
-161
-146
-92
-183
-129
-124
-180
-158
-171
-181
-166
-166
-165
-106
-154
-158
-144
-171
-148
-184
-112
-156
-137
-182
-145
-161
-165
-167
-146
-136
-148
-176
-156
-183
-148
-174
-118
-169
-158
-205
-176
-177
-175
-209
-165
-165
-181
-199
-167
-178
-158
-219
-179
-150
-194
-209
-186
-171
-186
-210
-150
-163
-174
-223
-176
-194
-192
-239
-182
-136
-235
-225
-152
-189
-224
-189
-189
-182
-215
-219
-198
-196
-196
-218
-196
-171
-217
-220
-186
-167
-215
-207
-197
-169
-190
-212
-167
-179
-346
-162
-123
-147
-128
-94
-125
-131
-118
-122
-115
-115
-157
-107
-113
-122
-117
-100
-126
-114
-125
-91
-121
-120
-116
-112
-118
-105
-117
-105
-109
-110
-106
-156
-98
-122
-179
-129
-121
-186
-127
-128
-131
-93
-140
-146
-133
-148
-115
-150
-89
-135
-101
-144
-119
-103
-134
-149
-113
-138
-126
-161
-143
-128
-114
-143
-106
-127
-127
-145
-141
-135
-141
-166
-126
-136
-163
-165
-121
-136
-132
-187
-155
-118
-137
-169
-140
-142
-153
-160
-146
-135
-160
-161
-131
-143
-137
-206
-141
-123
-200
-177
-151
-183
-163
-178
-111
-161
-179
-195
-179
-173
-151
-187
-162
-152
-186
-223
-165
-154
-158
-169
-142
-176
-146
-213
-142
-154
-297
-174
-121
-175
-119
-103
-138
-120
-119
-127
-143
-140
-147
-118
-125
-142
-152
-111
-131
-150
-134
-123
-177
-123
-142
-136
-124
-160
-152
-132
-138
-124
-140
-179
-138
-116
-171
-144
-138
-189
-162
-153
-114
-137
-152
-163
-141
-149
-137
-185
-112
-144
-134
-171
-134
-129
-141
-176
-146
-132
-159
-156
-156
-159
-128
-170
-112
-149
-169
-179
-150
-157
-167
-196
-116
-160
-165
-169
-152
-146
-163
-179
-173
-133
-168
-188
-166
-181
-191
-164
-176
-142
-168
-195
-166
-150
-173
-203
-206
-115
-205
-175
-149
-176
-172
-164
-160
-186
-203
-166
-164
-163
-176
-185
-183
-140
-196
-186
-172
-132
-183
-174
-189
-159
-173
-223
-185
-140
-311
-170
-123
-139
-125
-116
-136
-135
-137
-128
-130
-130
-142
-129
-148
-121
-141
-136
-153
-140
-120
-127
-152
-125
-121
-148
-133
-141
-146
-137
-175
-118
-117
-135
-114
-132
-189
-145
-126
-207
-174
-159
-106
-134
-166
-145
-148
-160
-135
-167
-90
-127
-142
-141
-130
-142
-148
-168
-127
-148
-143
-166
-147
-137
-142
-154
-104
-135
-140
-172
-150
-155
-156
-163
-144
-141
-154
-179
-158
-169
-152
-202
-166
-145
-191
-204
-177
-185
-182
-204
-153
-170
-184
-189
-188
-156
-158
-214
-186
-143
-212
-165
-171
-195
-189
-197
-152
-168
-206
-194
-164
-174
-179
-217
-169
-161
-214
-190
-184
-196
-182
-197
-174
-195
-193
-244
-165
-160
-275
-172
-127
-136
-136
-138
-120
-139
-122
-122
-117
-132
-140
-121
-142
-141
-147
-137
-126
-130
-149
-128
-127
-127
-132
-145
-144
-159
-149
-127
-173
-143
-127
-185
-119
-121
-163
-138
-129
-157
-162
-149
-125
-121
-138
-139
-160
-147
-120
-186
-92
-147
-125
-177
-134
-143
-133
-156
-122
-132
-145
-138
-139
-157
-136
-154
-126
-149
-162
-173
-136
-136
-146
-167
-133
-131
-161
-161
-161
-150
-146
-222
-154
-116
-174
-162
-161
-203
-171
-184
-169
-149
-187
-188
-153
-189
-150
-224
-185
-141
-216
-200
-141
-185
-179
-182
-157
-160
-195
-165
-176
-162
-152
-214
-161
-169
-177
-209
-185
-171
-177
-182
-144
-172
-175
-217
-174
-140
-292
-156
-131
-130
-132
-111
-139
-130
-124
-144
-125
-123
-164
-109
-141
-111
-138
-110
-130
-152
-133
-121
-144
-125
-124
-146
-96
-139
-143
-118
-146
-107
-109
-157
-115
-121
-168
-138
-128
-165
-141
-128
-122
-126
-171
-143
-125
-164
-137
-166
-89
-126
-123
-167
-105
-133
-134
-136
-117
-99
-144
-148
-122
-156
-134
-124
-101
-126
-115
-157
-130
-136
-144
-172
-124
-136
-153
-162
-137
-156
-119
-219
-146
-122
-177
-189
-152
-148
-174
-199
-139
-148
-181
-195
-146
-175
-138
-202
-182
-115
-200
-163
-141
-173
-161
-157
-182
-147
-193
-183
-184
-170
-166
-202
-151
-159
-184
-192
-166
-160
-194
-189
-169
-166
-149
-222
-178
-155
-307
-195
-137
-143
-150
-125
-164
-109
-143
-130
-144
-152
-136
-133
-141
-152
-131
-129
-133
-147
-161
-123
-145
-135
-132
-130
-170
-166
-149
-109
-158
-131
-127
-157
-135
-116
-176
-172
-154
-175
-154
-152
-140
-143
-158
-158
-147
-169
-101
-193
-120
-144
-167
-178
-132
-154
-154
-186
-138
-128
-162
-173
-151
-163
-162
-211
-139
-161
-150
-213
-167
-140
-163
-185
-145
-178
-178
-172
-174
-174
-157
-217
-168
-146
-196
-191
-167
-176
-163
-194
-159
-189
-177
-180
-175
-166
-168
-219
-200
-120
-211
-206
-153
-190
-205
-205
-141
-200
-208
-175
-179
-174
-189
-210
-187
-160
-212
-202
-177
-184
-207
-201
-187
-182
-191
-251
-188
-162
-356
-155
-109
-117
-125
-100
-116
-108
-94
-126
-136
-119
-114
-124
-110
-125
-119
-119
-131
-137
-132
-127
-142
-109
-120
-119
-126
-111
-124
-112
-149
-111
-122
-148
-101
-99
-173
-133
-137
-187
-123
-140
-102
-122
-140
-147
-114
-153
-128
-162
-83
-126
-124
-147
-153
-128
-146
-152
-122
-121
-130
-155
-130
-130
-119
-139
-121
-166
-138
-171
-145
-130
-123
-183
-126
-135
-152
-191
-114
-164
-118
-177
-137
-123
-176
-146
-136
-152
-157
-175
-139
-160
-155
-164
-136
-167
-142
-210
-171
-133
-219
-149
-124
-178
-140
-202
-156
-154
-166
-185
-149
-173
-153
-208
-143
-146
-177
-216
-153
-167
-186
-166
-152
-175
-165
-214
-171
-121
-299
-163
-122
-150
-123
-134
-151
-125
-126
-126
-144
-147
-161
-115
-135
-125
-126
-118
-116
-155
-155
-131
-168
-124
-124
-161
-135
-137
-166
-116
-163
-144
-152
-160
-126
-134
-174
-151
-162
-183
-142
-137
-123
-133
-144
-169
-125
-179
-129
-191
-112
-156
-156
-168
-157
-147
-155
-166
-155
-149
-171
-163
-155
-142
-162
-188
-145
-170
-173
-169
-153
-146
-171
-189
-162
-147
-178
-166
-180
-152
-167
-203
-178
-136
-177
-199
-184
-193
-181
-198
-176
-181
-167
-189
-191
-162
-191
-249
-206
-133
-205
-208
-173
-180
-210
-195
-169
-195
-186
-167
-200
-149
-206
-199
-202
-162
-183
-230
-213
-204
-192
-200
-174
-181
-192
-229
-195
-164
-327
-185
-122
-133
-115
-96
-151
-115
-104
-146
-103
-148
-119
-115
-151
-116
-133
-137
-133
-116
-127
-121
-147
-108
-117
-148
-138
-130
-126
-104
-119
-112
-118
-155
-119
-129
-159
-173
-127
-195
-137
-144
-109
-113
-131
-144
-125
-146
-148
-163
-88
-120
-118
-137
-111
-143
-133
-168
-134
-124
-135
-159
-106
-135
-121
-157
-118
-165
-144
-179
-142
-154
-137
-157
-118
-119
-155
-175
-119
-144
-118
-190
-146
-132
-156
-149
-139
-149
-153
-184
-148
-161
-136
-180
-155
-177
-150
-218
-158
-151
-193
-192
-143
-184
-180
-179
-123
-150
-181
-197
-170
-150
-169
-188
-139
-148
-176
-187
-143
-158
-166
-185
-169
-157
-155
-221
-166
-192
-300
-175
-111
-131
-147
-115
-139
-143
-120
-126
-137
-120
-126
-141
-171
-125
-154
-123
-145
-156
-144
-123
-148
-115
-127
-135
-136
-158
-158
-128
-140
-121
-123
-176
-140
-119
-201
-180
-151
-178
-164
-136
-127
-112
-156
-169
-136
-173
-138
-175
-126
-120
-158
-154
-152
-159
-144
-181
-146
-159
-188
-171
-164
-162
-130
-167
-136
-144
-163
-170
-176
-142
-173
-166
-148
-149
-157
-161
-159
-163
-199
-199
-200
-125
-166
-190
-173
-160
-171
-194
-183
-175
-177
-181
-200
-146
-182
-217
-185
-147
-228
-229
-151
-183
-206
-217
-191
-167
-200
-201
-204
-190
-171
-180
-195
-176
-197
-188
-185
-170
-204
-200
-181
-160
-203
-218
-189
-170
-294
-184
-119
-154
-119
-130
-159
-146
-143
-131
-124
-131
-155
-112
-150
-119
-147
-138
-145
-141
-153
-136
-158
-143
-148
-143
-131
-141
-143
-135
-147
-138
-118
-155
-136
-110
-165
-176
-132
-195
-156
-145
-132
-134
-159
-171
-155
-161
-157
-188
-96
-124
-141
-163
-155
-160
-155
-178
-133
-143
-163
-153
-152
-167
-183
-173
-126
-173
-153
-191
-167
-146
-172
-194
-132
-161
-156
-196
-138
-180
-171
-249
-177
-178
-177
-170
-156
-161
-156
-220
-168
-175
-172
-195
-173
-173
-171
-262
-190
-137
-225
-225
-148
-219
-195
-188
-182
-203
-191
-208
-167
-196
-179
-203
-179
-158
-205
-218
-209
-192
-195
-209
-173
-170
-180
-221
-143
-189
-305
-158
-138
-129
-144
-109
-144
-112
-124
-134
-119
-136
-122
-103
-136
-135
-136
-144
-138
-137
-143
-126
-155
-128
-121
-148
-103
-156
-161
-115
-153
-138
-133
-169
-112
-94
-161
-138
-136
-161
-151
-159
-123
-123
-167
-171
-151
-160
-116
-186
-99
-160
-133
-160
-135
-145
-153
-180
-123
-151
-158
-151
-137
-171
-146
-171
-141
-166
-152
-181
-154
-162
-145
-194
-156
-145
-174
-174
-155
-175
-164
-195
-175
-143
-196
-206
-174
-186
-171
-214
-142
-168
-153
-189
-192
-161
-177
-221
-173
-119
-185
-238
-167
-205
-190
-215
-180
-183
-190
-209
-190
-177
-186
-228
-167
-168
-196
-201
-202
-179
-215
-164
-186
-194
-198
-254
-178
-170
-348
-187
-109
-136
-115
-112
-105
-132
-115
-114
-112
-132
-126
-111
-130
-97
-130
-104
-145
-128
-120
-109
-143
-125
-109
-132
-106
-128
-132
-133
-130
-114
-125
-153
-101
-125
-162
-132
-124
-156
-119
-150
-119
-111
-150
-144
-138
-124
-123
-147
-83
-122
-123
-136
-98
-132
-122
-164
-150
-129
-139
-131
-126
-130
-121
-152
-131
-128
-118
-144
-124
-136
-131
-173
-134
-138
-150
-142
-117
-154
-133
-142
-138
-112
-172
-149
-145
-142
-146
-155
-133
-155
-169
-169
-138
-161
-125
-177
-140
-104
-182
-178
-118
-164
-160
-159
-146
-136
-158
-171
-130
-153
-171
-159
-159
-141
-160
-168
-161
-136
-174
-177
-170
-173
-131
-213
-146
-145
-253
-187
-140
-118
-147
-136
-148
-138
-158
-139
-150
-153
-150
-144
-162
-153
-129
-157
-142
-161
-143
-133
-169
-132
-124
-166
-142
-162
-129
-145
-181
-143
-146
-189
-135
-143
-193
-144
-150
-206
-152
-180
-166
-133
-197
-163
-167
-184
-138
-177
-116
-142
-183
-170
-172
-153
-159
-195
-158
-150
-168
-150
-187
-140
-163
-186
-169
-190
-166
-191
-161
-170
-188
-208
-167
-158
-180
-182
-178
-187
-177
-204
-192
-148
-220
-193
-176
-191
-169
-189
-184
-183
-185
-229
-201
-185
-170
-237
-226
-146
-266
-230
-168
-208
-184
-199
-190
-208
-205
-213
-208
-211
-196
-222
-216
-207
-209
-251
-213
-216
-238
-217
-210
-216
-198
-240
-177
-177
-331
-213
-162
-171
-145
-143
-169
-167
-127
-174
-156
-141
-149
-143
-163
-149
-179
-159
-158
-189
-183
-143
-199
-165
-168
-165
-183
-183
-165
-170
-186
-178
-155
-216
-164
-136
-190
-185
-171
-229
-176
-189
-148
-146
-195
-176
-176
-199
-176
-244
-140
-171
-193
-211
-169
-173
-184
-237
-180
-153
-192
-206
-162
-193
-211
-175
-184
-226
-192
-209
-172
-165
-189
-209
-164
-207
-201
-225
-179
-233
-200
-254
-193
-182
-219
-212
-202
-219
-229
-249
-208
-219
-223
-258
-240
-234
-234
-262
-238
-168
-287
-241
-214
-247
-266
-259
-233
-238
-233
-244
-220
-257
-230
-286
-221
-186
-264
-257
-234
-192
-242
-240
-217
-226
-219
-294
-227
-188
-421
-126
-105
-123
-126
-103
-128
-115
-120
-114
-113
-124
-130
-105
-113
-132
-131
-124
-115
-136
-112
-99
-136
-94
-121
-116
-110
-126
-124
-110
-120
-101
-89
-147
-108
-100
-153
-117
-95
-178
-143
-110
-105
-104
-127
-121
-135
-137
-120
-146
-94
-104
-115
-128
-121
-118
-147
-128
-118
-96
-138
-153
-118
-123
-125
-145
-98
-129
-146
-146
-126
-115
-141
-168
-119
-129
-144
-159
-140
-129
-135
-160
-148
-137
-179
-160
-142
-135
-146
-180
-126
-126
-166
-183
-132
-118
-162
-216
-156
-132
-185
-181
-142
-170
-175
-162
-187
-166
-171
-147
-160
-142
-153
-174
-144
-131
-174
-168
-137
-147
-159
-169
-136
-154
-146
-180
-154
-161
-269
-160
-126
-133
-112
-122
-125
-87
-105
-122
-133
-115
-104
-94
-124
-121
-104
-99
-122
-126
-101
-132
-141
-86
-132
-132
-119
-127
-130
-96
-129
-103
-103
-123
-115
-91
-134
-124
-128
-146
-117
-115
-112
-108
-134
-111
-122
-141
-124
-125
-104
-114
-123
-136
-112
-122
-124
-121
-129
-133
-111
-123
-138
-120
-108
-119
-97
-108
-116
-126
-122
-108
-109
-138
-134
-119
-132
-115
-126
-136
-123
-147
-146
-128
-145
-128
-120
-130
-138
-162
-129
-128
-124
-168
-120
-139
-130
-170
-129
-110
-180
-132
-123
-169
-153
-140
-126
-147
-156
-152
-143
-144
-135
-178
-155
-117
-133
-148
-136
-146
-144
-168
-134
-144
-114
-185
-119
-127
-216
-187
-134
-140
-142
-122
-158
-151
-153
-171
-137
-147
-153
-150
-171
-132
-153
-149
-157
-158
-146
-134
-144
-139
-159
-157
-166
-164
-144
-132
-160
-155
-116
-181
-152
-133
-221
-191
-173
-188
-158
-160
-154
-123
-166
-171
-174
-183
-165
-227
-115
-143
-165
-226
-162
-163
-150
-176
-140
-160
-153
-182
-186
-182
-171
-180
-145
-168
-179
-205
-191
-170
-198
-184
-154
-173
-202
-212
-187
-183
-189
-234
-189
-154
-213
-222
-194
-179
-214
-240
-197
-196
-201
-199
-223
-229
-207
-262
-233
-152
-271
-265
-199
-230
-246
-262
-189
-205
-241
-258
-230
-239
-232
-263
-196
-182
-253
-285
-213
-206
-265
-230
-216
-229
-220
-273
-208
-188
-356
-178
-132
-155
-132
-139
-149
-128
-129
-152
-122
-152
-162
-162
-163
-128
-112
-141
-160
-139
-153
-147
-163
-131
-133
-153
-153
-159
-151
-135
-178
-143
-125
-158
-124
-135
-198
-144
-172
-208
-157
-162
-136
-129
-131
-158
-128
-155
-137
-155
-112
-138
-135
-181
-151
-144
-153
-181
-158
-151
-175
-159
-163
-164
-169
-170
-146
-136
-182
-166
-173
-131
-149
-180
-148
-126
-167
-190
-140
-173
-155
-239
-168
-139
-185
-171
-162
-170
-175
-228
-174
-175
-200
-206
-186
-197
-193
-242
-194
-157
-277
-233
-181
-217
-203
-222
-199
-204
-221
-233
-203
-203
-198
-255
-192
-170
-194
-250
-203
-201
-213
-215
-209
-206
-185
-224
-189
-195
-364
-200
-132
-151
-126
-125
-147
-129
-128
-126
-130
-129
-134
-135
-146
-114
-165
-119
-136
-149
-128
-123
-148
-109
-122
-150
-139
-137
-138
-137
-164
-121
-126
-147
-130
-117
-181
-151
-115
-174
-164
-158
-139
-128
-138
-152
-144
-175
-135
-167
-125
-146
-142
-153
-143
-138
-148
-173
-166
-132
-137
-172
-142
-145
-142
-136
-113
-171
-156
-166
-151
-154
-164
-189
-132
-160
-170
-178
-174
-166
-165
-205
-204
-159
-201
-200
-194
-166
-171
-185
-192
-184
-203
-247
-164
-161
-175
-248
-208
-176
-238
-205
-168
-207
-200
-242
-197
-208
-225
-221
-205
-194
-221
-225
-202
-157
-199
-206
-207
-208
-230
-202
-192
-197
-198
-229
-184
-163
-311
-168
-125
-160
-149
-118
-132
-116
-123
-121
-117
-131
-134
-129
-134
-125
-140
-146
-120
-137
-144
-117
-154
-112
-128
-152
-142
-145
-139
-132
-138
-117
-125
-138
-116
-135
-172
-155
-128
-179
-120
-126
-138
-104
-148
-144
-138
-143
-133
-175
-102
-100
-129
-131
-130
-148
-126
-138
-142
-126
-143
-133
-143
-133
-138
-144
-151
-146
-141
-151
-160
-152
-149
-152
-156
-133
-143
-172
-153
-141
-165
-174
-165
-123
-177
-204
-143
-147
-148
-162
-165
-164
-182
-203
-183
-173
-160
-200
-180
-136
-208
-187
-156
-174
-210
-178
-169
-190
-216
-192
-169
-167
-215
-205
-159
-154
-203
-205
-199
-175
-198
-162
-167
-185
-169
-241
-162
-153
-301
-158
-106
-151
-143
-143
-136
-131
-134
-123
-143
-143
-149
-146
-154
-140
-143
-136
-150
-141
-139
-118
-149
-114
-121
-142
-132
-155
-154
-145
-177
-147
-148
-171
-122
-123
-187
-171
-145
-196
-159
-156
-118
-121
-153
-173
-123
-154
-141
-170
-117
-159
-168
-149
-143
-151
-139
-183
-146
-144
-165
-195
-151
-165
-160
-154
-153
-174
-161
-193
-160
-172
-172
-190
-147
-150
-164
-194
-177
-170
-154
-202
-199
-146
-211
-202
-177
-196
-213
-219
-191
-194
-169
-224
-201
-171
-197
-234
-201
-187
-281
-238
-175
-239
-227
-220
-231
-190
-245
-239
-211
-226
-242
-251
-189
-191
-234
-263
-195
-172
-227
-224
-208
-200
-188
-250
-171
-186
-326
-198
-110
-152
-150
-116
-139
-133
-142
-158
-151
-125
-130
-146
-129
-120
-133
-173
-163
-166
-157
-149
-174
-126
-146
-143
-144
-156
-169
-148
-181
-156
-134
-183
-135
-142
-209
-168
-150
-198
-191
-154
-157
-153
-154
-168
-158
-167
-148
-207
-108
-140
-158
-167
-166
-165
-149
-184
-175
-148
-153
-164
-187
-148
-194
-176
-162
-152
-175
-179
-208
-168
-180
-198
-201
-156
-185
-186
-173
-182
-190
-230
-198
-159
-205
-193
-172
-222
-205
-215
-202
-186
-187
-245
-202
-194
-211
-272
-240
-182
-299
-290
-234
-276
-256
-274
-241
-232
-273
-293
-268
-260
-255
-282
-263
-220
-242
-265
-213
-213
-243
-256
-245
-226
-209
-258
-207
-176
-397
-174
-98
-144
-143
-118
-135
-129
-119
-129
-110
-107
-136
-114
-138
-114
-144
-109
-122
-135
-126
-133
-129
-131
-123
-149
-115
-133
-145
-118
-134
-124
-119
-141
-113
-110
-155
-154
-118
-182
-137
-131
-130
-115
-142
-153
-109
-143
-127
-142
-102
-119
-140
-171
-109
-113
-133
-155
-131
-141
-156
-127
-138
-121
-133
-143
-108
-130
-164
-164
-153
-142
-131
-174
-125
-144
-167
-172
-147
-163
-130
-183
-173
-123
-142
-184
-158
-178
-158
-182
-182
-170
-168
-191
-162
-171
-174
-246
-207
-171
-291
-214
-189
-246
-220
-237
-190
-210
-259
-249
-193
-198
-210
-237
-185
-173
-216
-219
-192
-180
-215
-191
-174
-174
-173
-221
-150
-141
-359
-165
-115
-132
-116
-119
-130
-132
-130
-119
-114
-121
-122
-132
-150
-107
-138
-123
-129
-138
-121
-123
-143
-103
-131
-124
-120
-112
-126
-105
-124
-130
-111
-134
-132
-127
-163
-156
-138
-169
-140
-127
-119
-131
-137
-113
-130
-130
-108
-160
-120
-120
-135
-151
-127
-119
-143
-154
-143
-126
-161
-146
-136
-133
-139
-146
-129
-137
-152
-138
-127
-131
-154
-133
-133
-128
-160
-136
-166
-159
-155
-160
-162
-128
-200
-154
-149
-154
-174
-179
-157
-148
-180
-192
-182
-156
-178
-244
-226
-128
-236
-224
-198
-225
-239
-242
-208
-219
-255
-242
-219
-198
-219
-267
-212
-193
-232
-244
-195
-183
-195
-197
-161
-180
-168
-222
-163
-168
-303
-217
-162
-172
-157
-133
-183
-173
-148
-178
-156
-191
-183
-162
-161
-162
-190
-155
-192
-188
-187
-170
-211
-156
-175
-190
-186
-160
-195
-168
-199
-173
-156
-198
-160
-138
-237
-197
-180
-231
-185
-170
-169
-160
-199
-198
-198
-174
-172
-199
-144
-171
-207
-203
-184
-170
-202
-232
-174
-175
-253
-222
-202
-206
-221
-203
-196
-166
-208
-232
-205
-171
-208
-226
-203
-213
-223
-228
-226
-226
-213
-267
-231
-172
-257
-241
-231
-232
-245
-278
-275
-272
-273
-279
-287
-255
-288
-389
-365
-235
-363
-363
-257
-340
-383
-384
-348
-310
-331
-406
-333
-328
-313
-378
-366
-254
-357
-352
-286
-299
-342
-302
-293
-269
-240
-336
-265
-235
-478
-164
-99
-106
-109
-100
-121
-106
-117
-114
-105
-115
-115
-100
-111
-112
-121
-101
-125
-126
-99
-86
-128
-96
-116
-102
-112
-127
-131
-99
-123
-129
-91
-136
-100
-111
-160
-129
-103
-149
-111
-116
-91
-108
-129
-129
-109
-134
-120
-139
-72
-92
-116
-131
-106
-124
-111
-145
-135
-99
-131
-150
-108
-135
-120
-138
-130
-114
-123
-131
-133
-133
-128
-143
-122
-131
-135
-132
-112
-131
-122
-143
-131
-120
-152
-130
-150
-172
-147
-154
-128
-138
-153
-196
-141
-177
-173
-243
-174
-146
-222
-208
-178
-223
-198
-191
-160
-200
-199
-233
-212
-201
-193
-240
-175
-179
-179
-213
-158
-172
-202
-194
-156
-154
-173
-207
-130
-137
-259
-177
-158
-153
-151
-125
-171
-140
-151
-140
-131
-128
-127
-138
-164
-148
-147
-130
-140
-166
-151
-116
-147
-133
-137
-136
-151
-136
-162
-148
-153
-158
-149
-184
-133
-130
-177
-164
-144
-188
-153
-139
-126
-136
-158
-176
-153
-172
-163
-197
-123
-136
-173
-168
-158
-119
-190
-171
-191
-162
-172
-173
-162
-180
-185
-176
-169
-163
-169
-179
-176
-155
-186
-198
-196
-152
-185
-183
-186
-185
-173
-199
-214
-138
-229
-237
-192
-198
-205
-225
-228
-190
-241
-284
-282
-226
-261
-326
-309
-215
-367
-332
-243
-315
-331
-299
-292
-289
-341
-339
-335
-283
-298
-316
-274
-219
-312
-280
-258
-226
-274
-267
-252
-228
-234
-273
-227
-172
-344
-200
-97
-127
-131
-105
-129
-122
-125
-124
-134
-129
-139
-123
-128
-123
-117
-124
-136
-135
-121
-118
-144
-113
-127
-126
-121
-138
-148
-129
-132
-109
-109
-142
-98
-106
-154
-129
-122
-155
-123
-128
-121
-124
-137
-160
-135
-149
-107
-162
-101
-135
-154
-177
-130
-126
-145
-175
-127
-120
-120
-155
-151
-138
-141
-174
-127
-145
-147
-156
-135
-150
-149
-161
-153
-144
-155
-172
-152
-159
-117
-199
-143
-146
-176
-160
-153
-155
-196
-178
-182
-181
-162
-215
-185
-190
-222
-300
-238
-154
-275
-279
-221
-266
-269
-301
-267
-269
-275
-307
-273
-263
-261
-310
-252
-227
-247
-246
-220
-223
-262
-199
-186
-191
-183
-260
-178
-177
-328
-166
-132
-122
-131
-116
-152
-128
-144
-145
-124
-138
-152
-127
-158
-135
-133
-120
-142
-160
-143
-111
-132
-118
-148
-123
-147
-151
-145
-141
-148
-126
-133
-151
-127
-103
-152
-145
-137
-186
-158
-140
-149
-102
-157
-145
-154
-145
-152
-170
-95
-111
-146
-164
-112
-146
-156
-147
-151
-147
-145
-160
-138
-131
-156
-153
-139
-144
-167
-162
-168
-135
-156
-177
-156
-145
-162
-174
-167
-175
-168
-181
-210
-125
-196
-177
-203
-173
-193
-215
-219
-213
-220
-250
-244
-240
-281
-322
-300
-208
-372
-343
-280
-367
-353
-411
-402
-402
-442
-380
-349
-286
-297
-299
-296
-210
-283
-295
-258
-191
-274
-217
-215
-228
-237
-266
-190
-185
-311
-222
-141
-163
-146
-116
-154
-153
-162
-180
-137
-130
-153
-164
-153
-127
-147
-150
-163
-168
-133
-144
-180
-135
-148
-132
-140
-173
-147
-149
-179
-143
-149
-195
-147
-143
-196
-180
-142
-212
-160
-176
-146
-147
-143
-168
-152
-193
-158
-190
-132
-145
-164
-172
-158
-154
-147
-191
-164
-140
-167
-182
-182
-159
-176
-179
-151
-185
-179
-199
-175
-159
-198
-234
-188
-200
-175
-210
-189
-207
-215
-221
-221
-183
-221
-252
-220
-251
-252
-302
-259
-267
-240
-382
-262
-351
-300
-427
-337
-291
-438
-501
-459
-623
-659
-730
-632
-657
-713
-659
-581
-518
-513
-517
-397
-324
-387
-385
-337
-309
-380
-331
-304
-304
-264
-373
-236
-216
-457
-178
-123
-150
-141
-101
-142
-141
-148
-127
-119
-135
-116
-143
-139
-114
-159
-126
-128
-150
-139
-122
-158
-142
-153
-125
-126
-127
-136
-147
-161
-163
-111
-161
-116
-113
-173
-150
-130
-161
-148
-132
-161
-128
-165
-132
-122
-147
-129
-171
-102
-113
-105
-135
-132
-115
-145
-154
-126
-134
-145
-135
-127
-119
-148
-133
-129
-138
-174
-134
-170
-129
-159
-161
-133
-140
-151
-157
-131
-137
-141
-145
-159
-113
-165
-171
-153
-189
-208
-232
-192
-197
-233
-248
-227
-212
-269
-307
-278
-224
-426
-474
-449
-666
-731
-717
-733
-660
-802
-674
-625
-565
-499
-411
-362
-270
-296
-276
-234
-221
-274
-226
-233
-203
-187
-228
-162
-150
-314
-162
-132
-157
-114
-121
-124
-127
-115
-139
-143
-134
-138
-121
-137
-109
-141
-128
-129
-132
-128
-120
-153
-136
-104
-141
-137
-130
-142
-134
-152
-120
-122
-164
-102
-131
-192
-160
-144
-175
-125
-140
-135
-134
-133
-156
-141
-156
-110
-181
-102
-126
-124
-176
-130
-130
-137
-169
-140
-136
-149
-145
-128
-137
-137
-157
-133
-167
-161
-177
-140
-129
-142
-177
-160
-156
-152
-149
-142
-149
-150
-164
-183
-153
-220
-220
-188
-177
-187
-231
-221
-219
-209
-264
-220
-235
-248
-400
-363
-344
-577
-712
-633
-923
-998
-1203
-1070
-1120
-1173
-1109
-923
-851
-700
-651
-444
-362
-336
-312
-256
-236
-256
-251
-219
-258
-232
-301
-204
-173
-360
-184
-140
-145
-160
-122
-142
-113
-145
-153
-139
-127
-162
-128
-136
-153
-151
-114
-163
-143
-167
-146
-158
-136
-135
-156
-142
-162
-152
-156
-158
-132
-126
-155
-132
-133
-206
-177
-137
-170
-165
-143
-149
-118
-160
-148
-151
-157
-140
-193
-136
-129
-156
-177
-177
-171
-143
-168
-176
-129
-159
-147
-145
-181
-140
-188
-140
-146
-171
-184
-157
-152
-162
-197
-181
-169
-215
-190
-197
-185
-186
-211
-215
-183
-207
-223
-206
-193
-218
-282
-279
-245
-277
-302
-296
-301
-319
-502
-544
-455
-909
-1202
-1051
-1580
-1934
-2072
-1985
-1873
-2123
-2058
-1653
-1376
-1220
-979
-714
-479
-516
-442
-323
-292
-349
-300
-282
-280
-267
-295
-242
-174
-391
-192
-134
-130
-136
-101
-139
-144
-120
-149
-124
-136
-146
-125
-135
-131
-150
-135
-130
-147
-138
-120
-160
-106
-141
-142
-147
-128
-149
-135
-192
-129
-133
-155
-124
-111
-176
-159
-137
-185
-138
-131
-108
-135
-167
-153
-157
-149
-133
-205
-96
-129
-146
-171
-121
-124
-129
-178
-141
-128
-157
-153
-146
-138
-169
-182
-130
-134
-181
-186
-165
-148
-158
-171
-166
-167
-178
-193
-157
-169
-170
-198
-208
-153
-177
-196
-191
-212
-214
-264
-212
-220
-260
-322
-304
-299
-351
-598
-685
-606
-1297
-1561
-1486
-2237
-2531
-2982
-2669
-2760
-3067
-2776
-2375
-1875
-1662
-1450
-929
-636
-654
-477
-327
-306
-306
-299
-260
-249
-251
-301
-234
-199
-363
-208
-118
-174
-153
-123
-175
-149
-158
-154
-134
-119
-140
-142
-169
-138
-143
-143
-145
-152
-153
-116
-153
-154
-146
-155
-161
-164
-193
-163
-167
-158
-129
-172
-144
-129
-205
-178
-137
-202
-144
-169
-155
-119
-173
-169
-140
-153
-162
-197
-118
-122
-163
-175
-141
-140
-172
-187
-163
-150
-175
-174
-152
-165
-172
-170
-178
-173
-185
-188
-181
-164
-201
-211
-179
-158
-193
-180
-175
-202
-200
-202
-185
-166
-249
-217
-212
-230
-222
-260
-234
-249
-287
-298
-349
-347
-463
-825
-997
-901
-1946
-2528
-2385
-3475
-4141
-4527
-4304
-4082
-4677
-4229
-3646
-3006
-2546
-2183
-1434
-912
-828
-621
-449
-327
-351
-312
-293
-261
-248
-357
-228
-217
-395
-172
-122
-138
-136
-106
-129
-135
-134
-138
-128
-130
-138
-110
-127
-103
-117
-118
-152
-144
-130
-113
-140
-133
-141
-126
-138
-138
-152
-126
-152
-130
-110
-158
-143
-127
-175
-161
-142
-171
-143
-135
-163
-128
-148
-161
-151
-144
-134
-166
-109
-110
-134
-163
-138
-136
-155
-156
-143
-131
-146
-158
-134
-171
-145
-149
-144
-123
-155
-157
-150
-159
-156
-186
-139
-127
-193
-170
-146
-180
-150
-226
-173
-131
-186
-198
-178
-216
-216
-240
-235
-203
-236
-286
-292
-312
-478
-945
-999
-970
-2135
-2782
-2657
-3847
-4238
-4131
-3291
-3279
-4027
-4265
-4015
-3387
-2849
-2363
-1495
-1006
-870
-661
-448
-333
-325
-288
-245
-263
-235
-291
-192
-192
-337
-186
-117
-140
-146
-128
-119
-120
-141
-118
-128
-141
-116
-119
-137
-139
-127
-137
-144
-162
-132
-137
-178
-127
-133
-153
-140
-126
-158
-138
-166
-134
-137
-166
-140
-124
-197
-150
-120
-209
-139
-151
-124
-123
-159
-176
-143
-148
-136
-148
-132
-140
-173
-153
-136
-151
-163
-168
-149
-159
-137
-145
-144
-146
-171
-163
-153
-149
-170
-159
-202
-131
-154
-184
-158
-171
-160
-192
-170
-171
-136
-198
-226
-151
-239
-205
-171
-222
-221
-264
-274
-271
-315
-360
-392
-449
-652
-1182
-1467
-1351
-3118
-3894
-3934
-4624
-2766
-1119
-567
-463
-985
-2417
-4050
-4581
-4073
-3422
-2277
-1371
-1298
-951
-523
-379
-356
-308
-287
-250
-273
-299
-234
-190
-395
-187
-134
-177
-116
-115
-145
-158
-141
-149
-150
-146
-162
-127
-152
-119
-138
-156
-141
-162
-142
-160
-180
-143
-150
-148
-121
-141
-157
-153
-174
-152
-155
-160
-144
-126
-179
-146
-149
-209
-181
-154
-142
-143
-167
-132
-135
-174
-155
-186
-120
-130
-148
-190
-141
-145
-162
-178
-158
-146
-181
-152
-168
-162
-168
-173
-146
-143
-180
-181
-171
-127
-183
-210
-189
-158
-200
-190
-166
-185
-205
-225
-226
-178
-225
-218
-243
-240
-244
-289
-267
-281
-319
-379
-454
-590
-871
-1651
-2019
-1840
-4376
-5444
-3446
-1382
-99
-24
-21
-18
-16
-82
-786
-3387
-5229
-4781
-3197
-1999
-1783
-1275
-708
-503
-489
-384
-325
-293
-279
-361
-252
-243
-454
-176
-144
-129
-126
-105
-133
-155
-116
-129
-117
-139
-135
-123
-162
-146
-155
-120
-148
-140
-133
-130
-146
-116
-137
-129
-135
-120
-138
-129
-137
-152
-134
-156
-129
-120
-173
-155
-126
-181
-167
-144
-142
-125
-167
-153
-133
-133
-144
-187
-118
-130
-135
-180
-150
-133
-156
-170
-148
-156
-182
-146
-151
-169
-157
-173
-121
-164
-157
-162
-178
-135
-167
-190
-166
-164
-175
-152
-177
-178
-136
-197
-207
-160
-208
-215
-216
-202
-248
-284
-230
-251
-295
-395
-449
-583
-845
-1723
-2151
-2020
-4519
-4340
-711
-29
-14
-14
-10
-11
-15
-11
-24
-590
-3508
-4949
-3198
-2003
-1789
-1201
-667
-466
-415
-290
-290
-262
-253
-320
-214
-194
-357
-162
-126
-138
-131
-106
-137
-116
-104
-124
-126
-125
-134
-118
-143
-134
-131
-126
-157
-121
-139
-107
-141
-116
-155
-138
-131
-144
-131
-128
-120
-125
-116
-164
-108
-121
-144
-152
-129
-160
-144
-145
-135
-124
-169
-146
-130
-98
-131
-143
-117
-126
-138
-136
-147
-136
-130
-153
-153
-144
-170
-147
-127
-146
-164
-146
-134
-135
-181
-145
-144
-137
-149
-152
-140
-150
-142
-163
-169
-170
-173
-202
-194
-160
-175
-212
-202
-208
-208
-241
-242
-242
-303
-366
-441
-549
-906
-1759
-2325
-2148
-4667
-2345
-51
-12
-11
-7
-4
-7
-5
-6
-12
-49
-1533
-4833
-3525
-2158
-1918
-1370
-713
-488
-383
-302
-278
-256
-235
-312
-218
-169
-407
-225
-131
-162
-161
-146
-165
-140
-134
-162
-139
-154
-127
-145
-151
-145
-150
-132
-157
-156
-147
-140
-167
-156
-180
-156
-150
-178
-170
-156
-165
-165
-148
-180
-158
-127
-171
-174
-171
-215
-186
-176
-164
-131
-180
-188
-167
-161
-161
-191
-122
-170
-150
-181
-153
-160
-169
-179
-175
-184
-169
-199
-208
-162
-174
-183
-183
-138
-182
-173
-195
-158
-191
-209
-190
-158
-198
-204
-180
-187
-205
-229
-237
-187
-230
-268
-258
-249
-251
-316
-295
-298
-361
-449
-558
-761
-1255
-2480
-3307
-2869
-5988
-1274
-18
-12
-13
-14
-14
-11
-10
-15
-15
-17
-682
-5684
-5117
-3180
-2771
-1847
-1035
-689
-563
-456
-340
-319
-352
-382
-278
-246
-513
-175
-107
-150
-123
-115
-125
-122
-107
-140
-118
-130
-134
-131
-141
-128
-137
-119
-126
-107
-118
-124
-164
-141
-154
-145
-107
-123
-137
-120
-116
-148
-104
-151
-142
-106
-179
-149
-127
-148
-158
-140
-146
-121
-154
-125
-137
-154
-172
-176
-132
-125
-122
-154
-125
-109
-111
-168
-138
-124
-161
-130
-135
-134
-131
-160
-128
-110
-147
-148
-165
-126
-159
-148
-143
-146
-150
-155
-150
-147
-120
-169
-179
-124
-166
-191
-180
-198
-193
-255
-230
-224
-266
-376
-450
-611
-979
-1894
-2493
-2402
-4203
-487
-17
-10
-5
-7
-7
-5
-11
-10
-12
-12
-187
-3765
-3780
-2499
-2068
-1412
-816
-486
-412
-292
-288
-233
-206
-257
-192
-185
-370
-184
-121
-154
-140
-120
-154
-146
-144
-174
-128
-145
-153
-143
-163
-133
-159
-157
-142
-183
-198
-123
-151
-141
-155
-155
-157
-144
-182
-145
-169
-138
-144
-205
-139
-118
-213
-156
-165
-208
-173
-140
-159
-126
-186
-161
-174
-173
-168
-190
-128
-137
-181
-174
-157
-158
-156
-214
-165
-169
-168
-201
-181
-185
-173
-199
-193
-163
-201
-215
-194
-163
-183
-198
-178
-181
-194
-219
-201
-202
-218
-217
-224
-179
-230
-275
-226
-252
-296
-293
-252
-286
-352
-487
-581
-834
-1238
-2575
-3409
-3154
-5543
-762
-19
-17
-17
-15
-9
-12
-10
-10
-6
-15
-258
-4764
-5255
-3273
-2906
-1955
-1192
-696
-580
-401
-351
-311
-330
-359
-259
-231
-470
-177
-113
-134
-107
-120
-105
-106
-137
-126
-103
-130
-105
-110
-125
-115
-113
-122
-129
-138
-119
-103
-141
-103
-117
-123
-128
-133
-139
-110
-136
-138
-120
-148
-97
-128
-174
-150
-120
-179
-132
-134
-115
-132
-144
-146
-133
-128
-125
-152
-108
-122
-129
-174
-142
-118
-119
-155
-134
-132
-134
-132
-148
-135
-134
-149
-136
-119
-151
-131
-159
-125
-151
-167
-110
-148
-162
-170
-159
-144
-152
-190
-146
-131
-187
-197
-218
-184
-213
-239
-198
-204
-248
-368
-444
-609
-970
-1983
-2377
-2308
-4325
-824
-9
-10
-10
-6
-8
-8
-9
-7
-10
-10
-315
-4224
-3587
-2430
-1964
-1410
-771
-492
-407
-298
-241
-264
-217
-264
-212
-183
-352
-187
-146
-132
-127
-125
-143
-120
-143
-145
-147
-131
-167
-143
-137
-147
-159
-147
-145
-169
-171
-127
-170
-158
-144
-145
-142
-130
-165
-161
-174
-165
-129
-167
-135
-123
-165
-173
-136
-198
-190
-141
-142
-119
-154
-174
-149
-149
-159
-161
-126
-140
-158
-179
-154
-149
-179
-182
-174
-136
-156
-168
-179
-173
-173
-194
-181
-143
-160
-180
-187
-144
-173
-165
-182
-176
-202
-193
-182
-191
-162
-206
-224
-137
-221
-278
-241
-240
-266
-283
-271
-275
-336
-389
-526
-686
-1156
-2077
-3060
-2540
-5687
-2509
-84
-24
-8
-16
-7
-8
-18
-6
-2
-20
-1582
-5657
-4418
-2617
-2462
-1596
-932
-596
-535
-386
-302
-304
-284
-326
-287
-226
-465
-195
-138
-162
-141
-123
-142
-129
-140
-165
-164
-156
-167
-155
-148
-160
-144
-141
-180
-184
-171
-159
-173
-108
-157
-174
-185
-157
-147
-154
-149
-164
-142
-187
-129
-144
-194
-196
-160
-209
-163
-161
-166
-125
-181
-189
-165
-189
-152
-201
-147
-165
-178
-178
-122
-143
-173
-226
-165
-185
-153
-178
-161
-173
-184
-199
-161
-139
-184
-197
-180
-153
-194
-229
-187
-141
-217
-201
-167
-182
-208
-225
-186
-182
-248
-250
-253
-259
-280
-334
-274
-300
-337
-454
-503
-687
-1003
-2048
-2475
-2439
-5389
-4862
-972
-99
-11
-9
-10
-16
-5
-16
-19
-554
-4123
-6284
-3770
-2571
-2218
-1511
-774
-599
-503
-402
-332
-330
-314
-409
-267
-250
-473
-176
-125
-124
-139
-121
-143
-136
-111
-124
-114
-138
-148
-138
-154
-134
-156
-122
-133
-128
-145
-109
-148
-138
-128
-118
-124
-130
-156
-134
-154
-132
-135
-136
-106
-114
-165
-150
-149
-192
-139
-131
-151
-104
-156
-157
-158
-163
-128
-149
-137
-103
-144
-153
-147
-151
-141
-175
-129
-109
-144
-141
-155
-109
-164
-150
-155
-137
-164
-159
-168
-147
-143
-181
-137
-146
-163
-192
-168
-164
-151
-187
-201
-164
-180
-198
-200
-214
-214
-240
-238
-224
-251
-329
-380
-496
-769
-1308
-1823
-1587
-3625
-4403
-2769
-1085
-156
-13
-11
-16
-15
-44
-587
-2747
-4494
-3905
-2717
-1651
-1472
-977
-575
-393
-355
-308
-244
-223
-224
-255
-214
-182
-343
-168
-136
-139
-126
-118
-148
-122
-119
-147
-138
-146
-157
-132
-142
-139
-148
-126
-142
-151
-120
-118
-153
-136
-119
-152
-123
-117
-152
-123
-144
-121
-122
-154
-121
-138
-185
-150
-120
-195
-135
-161
-134
-112
-178
-146
-149
-171
-136
-142
-115
-95
-154
-175
-157
-140
-149
-175
-163
-115
-142
-168
-151
-133
-135
-163
-134
-136
-169
-145
-178
-142
-162
-185
-152
-136
-189
-167
-146
-171
-166
-185
-197
-135
-201
-231
-183
-217
-216
-245
-224
-219
-292
-308
-362
-415
-593
-1142
-1429
-1355
-3089
-3844
-3553
-3831
-2013
-713
-304
-298
-517
-1508
-3446
-4603
-4100
-3644
-2230
-1561
-1245
-912
-542
-393
-343
-315
-287
-263
-267
-324
-212
-207
-368
-209
-136
-148
-146
-126
-141
-128
-161
-153
-153
-146
-134
-125
-146
-130
-127
-134
-154
-151
-150
-141
-155
-122
-118
-148
-138
-157
-136
-130
-179
-140
-147
-167
-136
-133
-156
-166
-139
-192
-152
-162
-147
-135
-160
-155
-139
-178
-148
-187
-121
-150
-160
-185
-157
-150
-159
-166
-163
-133
-162
-161
-183
-144
-176
-152
-171
-148
-182
-159
-176
-160
-158
-191
-190
-178
-204
-199
-199
-188
-172
-223
-212
-174
-221
-225
-221
-245
-244
-249
-285
-258
-290
-362
-389
-392
-594
-996
-1374
-1198
-2582
-3432
-3189
-4612
-5153
-4539
-3760
-3408
-4562
-5062
-4767
-4080
-3393
-2866
-1923
-1216
-1115
-866
-470
-378
-382
-316
-272
-293
-290
-300
-252
-187
-389
-171
-120
-151
-134
-125
-123
-146
-145
-140
-123
-128
-164
-146
-126
-129
-142
-144
-149
-152
-130
-130
-152
-127
-125
-153
-118
-151
-177
-145
-161
-143
-123
-167
-155
-144
-177
-174
-153
-176
-152
-180
-128
-135
-145
-139
-173
-162
-133
-182
-119
-121
-148
-169
-168
-129
-164
-169
-167
-130
-149
-184
-155
-155
-177
-161
-140
-150
-169
-164
-167
-159
-154
-189
-161
-136
-162
-198
-142
-184
-172
-214
-193
-168
-225
-216
-200
-194
-227
-277
-238
-236
-299
-306
-313
-326
-412
-836
-909
-861
-1859
-2377
-2156
-3309
-3770
-4358
-4029
-4007
-4409
-4180
-3426
-2869
-2456
-2075
-1340
-922
-728
-656
-395
-375
-334
-301
-288
-286
-253
-309
-213
-197
-406
-192
-134
-154
-126
-119
-147
-124
-133
-147
-147
-139
-157
-122
-147
-142
-124
-152
-143
-137
-141
-124
-172
-134
-126
-166
-128
-130
-171
-123
-171
-128
-151
-160
-124
-136
-185
-153
-143
-176
-163
-151
-171
-137
-175
-174
-164
-148
-166
-193
-128
-142
-164
-168
-157
-154
-166
-207
-158
-159
-182
-187
-180
-167
-158
-169
-150
-161
-196
-186
-168
-162
-171
-218
-188
-195
-190
-204
-171
-209
-199
-237
-190
-173
-205
-238
-220
-240
-215
-274
-271
-243
-254
-320
-299
-297
-405
-652
-766
-631
-1412
-1786
-1691
-2453
-2914
-3190
-3035
-2913
-3338
-3150
-2617
-2117
-1843
-1546
-1023
-755
-658
-575
-385
-302
-315
-338
-267
-271
-263
-306
-263
-197
-450
-182
-129
-139
-92
-123
-125
-117
-124
-112
-144
-134
-124
-132
-128
-100
-131
-122
-100
-133
-114
-122
-150
-114
-130
-108
-133
-119
-145
-118
-138
-125
-131
-157
-119
-135
-161
-153
-131
-157
-119
-150
-135
-112
-136
-166
-140
-137
-148
-151
-91
-125
-128
-153
-138
-143
-144
-160
-133
-113
-130
-162
-129
-139
-134
-139
-138
-140
-155
-151
-133
-144
-123
-171
-155
-140
-156
-157
-146
-182
-159
-180
-170
-149
-188
-205
-170
-204
-190
-212
-221
-205
-211
-275
-257
-223
-299
-464
-464
-431
-885
-1096
-970
-1495
-1690
-1733
-1713
-1755
-1932
-1814
-1491
-1310
-1094
-975
-614
-442
-398
-400
-239
-249
-304
-289
-229
-243
-210
-294
-189
-177
-346
-189
-130
-135
-147
-119
-131
-124
-124
-154
-149
-131
-168
-146
-128
-139
-156
-140
-141
-156
-147
-136
-164
-166
-137
-148
-134
-140
-158
-129
-135
-133
-118
-178
-130
-133
-168
-159
-127
-171
-175
-156
-141
-97
-147
-172
-156
-143
-146
-179
-122
-123
-141
-166
-150
-142
-148
-177
-164
-148
-147
-165
-161
-167
-174
-165
-151
-159
-165
-171
-178
-161
-180
-170
-167
-145
-186
-182
-183
-166
-163
-199
-212
-139
-201
-218
-198
-210
-212
-254
-257
-251
-219
-298
-260
-253
-311
-408
-415
-339
-658
-783
-759
-1036
-1267
-1375
-1278
-1307
-1383
-1272
-1063
-953
-876
-684
-512
-382
-379
-334
-256
-270
-311
-261
-237
-250
-263
-309
-191
-181
-416
-204
-128
-157
-135
-121
-141
-150
-140
-150
-133
-135
-122
-134
-136
-147
-160
-144
-129
-138
-158
-130
-170
-119
-131
-140
-146
-152
-164
-149
-150
-131
-117
-165
-128
-130
-184
-171
-146
-180
-173
-141
-152
-132
-174
-179
-142
-170
-146
-174
-113
-136
-152
-174
-146
-145
-156
-150
-176
-147
-161
-160
-151
-190
-181
-171
-163
-163
-170
-171
-184
-142
-173
-183
-175
-184
-174
-193
-148
-186
-173
-224
-223
-153
-214
-226
-208
-208
-237
-252
-250
-238
-268
-299
-283
-250
-261
-426
-401
-288
-601
-588
-546
-752
-881
-988
-906
-863
-1041
-914
-825
-687
-588
-548
-449
-334
-376
-373
-285
-311
-337
-309
-246
-273
-271
-313
-239
-205
-418
-173
-129
-132
-137
-114
-150
-123
-132
-138
-123
-107
-150
-137
-132
-120
-145
-128
-137
-152
-105
-124
-168
-133
-128
-151
-132
-148
-152
-129
-140
-137
-115
-127
-123
-129
-174
-114
-124
-174
-135
-146
-123
-122
-148
-137
-131
-139
-137
-165
-106
-113
-139
-172
-127
-116
-147
-158
-148
-119
-149
-159
-152
-133
-138
-137
-142
-154
-133
-151
-122
-128
-135
-176
-137
-137
-151
-142
-178
-136
-151
-195
-206
-129
-177
-194
-194
-160
-198
-238
-169
-196
-239
-256
-235
-230
-225
-340
-282
-249
-384
-397
-371
-453
-545
-581
-502
-500
-566
-564
-447
-454
-398
-361
-314
-244
-300
-309
-229
-226
-274
-277
-217
-217
-223
-280
-189
-175
-345
-164
-103
-116
-128
-111
-137
-137
-128
-128
-131
-111
-124
-120
-133
-128
-143
-115
-142
-132
-119
-108
-153
-138
-132
-118
-131
-129
-156
-131
-141
-151
-128
-159
-119
-116
-180
-145
-116
-195
-109
-154
-116
-133
-144
-144
-118
-174
-146
-154
-105
-116
-153
-159
-138
-138
-145
-184
-148
-105
-157
-149
-158
-138
-162
-159
-140
-143
-144
-146
-126
-122
-153
-161
-142
-146
-156
-173
-154
-158
-160
-189
-180
-141
-188
-169
-175
-164
-174
-245
-209
-183
-209
-238
-221
-218
-202
-285
-262
-188
-336
-330
-254
-360
-354
-378
-358
-373
-390
-388
-328
-268
-310
-322
-249
-235
-288
-261
-260
-199
-255
-236
-219
-222
-219
-255
-182
-171
-315
-209
-137
-178
-162
-140
-135
-131
-135
-148
-147
-155
-158
-159
-147
-159
-152
-144
-151
-151
-140
-158
-182
-150
-135
-166
-136
-158
-172
-145
-164
-136
-125
-183
-152
-158
-188
-176
-152
-183
-138
-142
-145
-131
-177
-149
-159
-153
-172
-197
-133
-152
-156
-187
-155
-151
-149
-194
-164
-156
-170
-169
-158
-162
-182
-190
-168
-149
-175
-201
-192
-165
-180
-215
-168
-152
-187
-186
-203
-171
-197
-211
-232
-158
-219
-222
-201
-211
-211
-230
-239
-221
-254
-306
-262
-275
-278
-346
-315
-233
-373
-341
-271
-352
-385
-388
-364
-340
-445
-381
-358
-336
-327
-369
-317
-281
-322
-358
-327
-260
-304
-295
-274
-239
-248
-313
-239
-219
-415
-147
-84
-121
-119
-83
-115
-121
-114
-133
-109
-128
-136
-142
-139
-114
-113
-95
-136
-124
-102
-123
-140
-106
-103
-136
-129
-125
-119
-123
-129
-134
-121
-143
-117
-122
-155
-143
-122
-160
-136
-138
-114
-110
-135
-142
-135
-109
-125
-150
-91
-124
-121
-147
-140
-133
-139
-134
-99
-106
-116
-145
-135
-136
-140
-141
-120
-139
-130
-149
-140
-138
-133
-173
-141
-147
-126
-145
-100
-151
-135
-168
-145
-112
-150
-167
-138
-151
-153
-213
-141
-171
-165
-214
-178
-186
-161
-255
-210
-137
-244
-260
-175
-229
-236
-268
-215
-263
-227
-238
-238
-232
-202
-278
-191
-213
-208
-236
-178
-178
-207
-190
-171
-179
-173
-214
-150
-129
-253
-193
-150
-170
-136
-133
-151
-135
-148
-169
-137
-138
-171
-145
-167
-142
-167
-147
-149
-155
-161
-143
-176
-156
-147
-167
-160
-164
-161
-148
-165
-139
-145
-194
-148
-143
-186
-170
-161
-218
-183
-148
-171
-138
-174
-187
-176
-183
-174
-220
-142
-166
-149
-199
-161
-186
-188
-218
-153
-164
-206
-193
-186
-180
-178
-202
-174
-178
-197
-198
-167
-138
-203
-212
-159
-198
-205
-201
-177
-201
-186
-242
-245
-171
-234
-276
-252
-192
-241
-250
-240
-237
-243
-272
-256
-264
-274
-407
-299
-234
-374
-350
-279
-365
-332
-347
-329
-334
-378
-362
-328
-303
-331
-349
-265
-264
-343
-331
-277
-284
-300
-302
-246
-260
-276
-297
-264
-193
-430
-150
-90
-127
-109
-112
-128
-120
-97
-119
-103
-128
-135
-97
-118
-100
-123
-112
-130
-108
-117
-130
-127
-108
-144
-125
-104
-125
-133
-110
-141
-121
-122
-144
-113
-118
-159
-131
-117
-156
-141
-117
-121
-103
-131
-135
-141
-114
-108
-143
-106
-116
-124
-125
-128
-136
-110
-145
-160
-117
-139
-149
-139
-140
-134
-119
-125
-121
-123
-135
-153
-96
-131
-142
-128
-121
-134
-151
-117
-137
-134
-163
-165
-118
-131
-156
-154
-141
-128
-160
-138
-148
-151
-189
-185
-169
-186
-256
-192
-151
-220
-256
-177
-218
-223
-230
-163
-192
-245
-212
-192
-213
-200
-254
-189
-175
-210
-210
-181
-190
-196
-183
-141
-181
-172
-230
-141
-153
-286
-200
-127
-168
-153
-105
-134
-146
-141
-116
-148
-136
-122
-125
-158
-164
-142
-143
-153
-124
-130
-139
-158
-134
-142
-130
-151
-162
-168
-146
-158
-150
-148
-149
-141
-121
-199
-149
-135
-162
-158
-138
-147
-135
-154
-177
-137
-138
-133
-176
-123
-152
-168
-153
-159
-157
-169
-178
-164
-139
-162
-175
-167
-161
-159
-161
-158
-162
-188
-157
-171
-146
-184
-197
-191
-163
-202
-189
-185
-183
-161
-191
-210
-154
-215
-219
-203
-196
-214
-224
-208
-171
-242
-219
-234
-225
-209
-294
-257
-148
-309
-303
-244
-251
-303
-275
-247
-250
-310
-244
-269
-236
-264
-272
-283
-198
-271
-265
-216
-188
-252
-218
-227
-186
-211
-245
-206
-163
-366
-193
-138
-146
-139
-153
-139
-159
-126
-156
-140
-180
-153
-108
-157
-161
-161
-137
-164
-153
-138
-151
-174
-139
-136
-127
-149
-151
-144
-149
-160
-163
-116
-186
-120
-118
-192
-154
-160
-200
-157
-176
-172
-125
-183
-178
-165
-170
-144
-178
-141
-139
-151
-179
-153
-163
-162
-186
-169
-145
-166
-167
-127
-175
-153
-173
-167
-177
-184
-180
-182
-160
-168
-209
-163
-171
-191
-197
-159
-172
-167
-223
-179
-169
-195
-226
-201
-221
-186
-245
-201
-232
-207
-281
-245
-214
-238
-313
-238
-188
-311
-301
-217
-278
-279
-261
-255
-263
-297
-279
-263
-286
-274
-305
-234
-242
-249
-280
-214
-247
-238
-252
-203
-232
-237
-291
-195
-207
-401
-131
-122
-125
-135
-104
-111
-107
-120
-133
-118
-117
-126
-131
-132
-112
-121
-103
-137
-128
-138
-108
-152
-123
-118
-128
-115
-121
-126
-124
-129
-127
-117
-138
-102
-113
-175
-127
-119
-149
-121
-131
-126
-98
-133
-146
-124
-120
-132
-154
-113
-105
-138
-127
-123
-118
-131
-156
-140
-121
-141
-134
-141
-114
-148
-145
-131
-126
-131
-139
-133
-119
-140
-127
-130
-109
-165
-145
-139
-136
-148
-174
-158
-107
-165
-149
-173
-166
-149
-172
-164
-123
-150
-182
-185
-165
-174
-202
-210
-126
-208
-198
-159
-221
-234
-186
-190
-176
-200
-214
-220
-196
-234
-199
-174
-133
-219
-192
-160
-151
-191
-183
-162
-145
-153
-212
-143
-119
-280
-183
-128
-147
-144
-131
-141
-143
-122
-137
-126
-134
-120
-126
-123
-120
-130
-118
-141
-149
-145
-133
-156
-132
-129
-143
-148
-143
-147
-117
-136
-146
-102
-177
-122
-126
-159
-167
-133
-181
-125
-152
-136
-116
-155
-159
-137
-132
-138
-171
-116
-104
-140
-157
-142
-123
-120
-167
-147
-137
-140
-154
-135
-151
-155
-168
-146
-125
-160
-171
-155
-156
-143
-144
-145
-147
-142
-163
-128
-156
-183
-203
-166
-134
-181
-179
-165
-179
-148
-169
-168
-161
-181
-209
-186
-173
-194
-205
-194
-135
-244
-215
-177
-201
-206
-213
-218
-195
-237
-245
-211
-191
-215
-253
-213
-183
-207
-220
-189
-188
-214
-194
-172
-166
-171
-218
-154
-154
-351
-187
-122
-162
-144
-135
-142
-130
-123
-150
-135
-145
-145
-143
-152
-158
-150
-155
-159
-152
-154
-141
-142
-131
-156
-137
-128
-157
-161
-122
-150
-133
-136
-189
-139
-128
-189
-164
-153
-201
-157
-150
-154
-128
-181
-178
-148
-189
-129
-185
-135
-139
-185
-161
-143
-147
-143
-185
-164
-171
-157
-185
-158
-191
-171
-173
-156
-171
-150
-190
-180
-158
-194
-229
-185
-180
-173
-172
-169
-193
-180
-212
-210
-148
-205
-218
-180
-214
-222
-218
-203
-198
-225
-210
-193
-168
-218
-276
-230
-160
-289
-268
-186
-256
-257
-270
-220
-208
-229
-239
-227
-221
-240
-241
-240
-225
-268
-274
-214
-227
-214
-235
-224
-180
-207
-261
-204
-192
-420
-149
-102
-137
-124
-114
-108
-122
-119
-122
-128
-141
-141
-142
-126
-130
-125
-124
-184
-141
-146
-124
-140
-118
-139
-165
-142
-120
-138
-137
-132
-128
-110
-180
-133
-136
-181
-147
-105
-184
-166
-152
-121
-104
-160
-183
-136
-152
-145
-176
-103
-120
-123
-144
-142
-133
-143
-156
-146
-131
-179
-182
-145
-125
-156
-165
-124
-174
-150
-184
-144
-122
-162
-172
-142
-161
-164
-156
-127
-159
-146
-170
-149
-132
-175
-163
-187
-181
-178
-190
-168
-174
-187
-204
-179
-163
-183
-202
-197
-155
-214
-232
-182
-212
-204
-225
-178
-192
-238
-195
-190
-210
-214
-248
-202
-180
-184
-210
-196
-190
-212
-189
-167
-192
-199
-235
-178
-168
-353
-171
-112
-159
-119
-122
-144
-134
-120
-136
-123
-131
-125
-109
-151
-135
-162
-146
-161
-153
-150
-126
-166
-151
-157
-153
-149
-121
-160
-135
-183
-165
-132
-176
-167
-119
-176
-159
-135
-193
-177
-167
-133
-121
-157
-180
-143
-170
-154
-170
-123
-173
-155
-178
-125
-136
-153
-175
-171
-166
-166
-167
-163
-142
-151
-186
-151
-157
-158
-193
-181
-166
-189
-167
-152
-157
-169
-184
-164
-178
-178
-205
-192
-133
-189
-191
-193
-175
-184
-210
-160
-170
-196
-212
-179
-171
-176
-246
-216
-127
-247
-235
-159
-222
-203
-190
-211
-190
-203
-207
-200
-198
-215
-271
-184
-147
-250
-238
-176
-191
-217
-197
-173
-177
-197
-227
-166
-169
-332
-167
-107
-117
-122
-100
-129
-117
-108
-117
-123
-109
-127
-112
-129
-132
-129
-123
-149
-139
-138
-100
-138
-118
-104
-136
-113
-114
-113
-119
-156
-129
-110
-155
-109
-108
-147
-145
-104
-161
-140
-152
-99
-120
-130
-127
-124
-135
-108
-157
-82
-114
-142
-136
-127
-107
-124
-166
-115
-122
-129
-126
-140
-125
-130
-155
-151
-134
-143
-151
-139
-122
-146
-168
-135
-128
-138
-167
-123
-146
-138
-183
-138
-144
-161
-147
-163
-169
-156
-160
-164
-145
-162
-186
-165
-147
-131
-202
-172
-122
-187
-158
-143
-218
-180
-166
-168
-170
-183
-181
-165
-164
-179
-181
-133
-157
-187
-179
-175
-160
-182
-176
-147
-154
-151
-191
-125
-145
-299
-175
-128
-136
-146
-111
-138
-133
-126
-155
-144
-148
-134
-128
-147
-136
-154
-154
-146
-164
-146
-134
-162
-121
-156
-170
-136
-175
-146
-156
-173
-128
-137
-185
-139
-123
-186
-150
-148
-172
-159
-139
-156
-132
-167
-166
-151
-154
-141
-164
-97
-134
-151
-136
-144
-162
-137
-168
-172
-156
-165
-151
-144
-158
-170
-170
-140
-150
-171
-160
-180
-157
-169
-198
-166
-141
-171
-175
-173
-167
-166
-219
-183
-150
-183
-187
-174
-170
-200
-217
-198
-156
-202
-228
-171
-169
-212
-256
-220
-136
-212
-237
-172
-194
-197
-216
-206
-178
-230
-206
-210
-206
-215
-219
-196
-167
-227
-243
-194
-207
-231
-239
-200
-229
-197
-284
-197
-167
-379
-210
-138
-155
-116
-136
-145
-105
-132
-134
-109
-160
-152
-138
-139
-113
-148
-145
-154
-140
-133
-115
-164
-120
-124
-145
-136
-141
-158
-130
-146
-133
-121
-174
-138
-155
-187
-175
-151
-179
-157
-155
-119
-120
-143
-141
-173
-183
-166
-155
-123
-153
-156
-148
-136
-142
-149
-165
-138
-161
-161
-162
-153
-151
-164
-170
-135
-164
-183
-183
-196
-174
-152
-187
-151
-148
-162
-196
-154
-175
-171
-244
-182
-137
-198
-169
-173
-177
-169
-213
-169
-184
-189
-243
-204
-198
-192
-278
-181
-140
-251
-221
-196
-185
-213
-234
-184
-212
-226
-215
-209
-220
-207
-254
-194
-183
-225
-246
-173
-194
-242
-210
-220
-222
-215
-249
-172
-157
-329
-159
-112
-137
-139
-94
-117
-98
-104
-122
-117
-135
-112
-109
-135
-108
-118
-134
-137
-130
-143
-122
-127
-130
-122
-123
-126
-151
-134
-119
-145
-125
-126
-144
-112
-120
-164
-146
-130
-177
-155
-149
-143
-150
-147
-139
-152
-144
-124
-186
-105
-136
-148
-132
-139
-159
-137
-155
-135
-152
-153
-141
-166
-135
-139
-165
-141
-149
-160
-157
-145
-156
-136
-163
-127
-132
-130
-154
-146
-154
-139
-180
-177
-113
-155
-158
-152
-149
-180
-164
-159
-142
-157
-184
-150
-150
-163
-215
-179
-124
-191
-192
-137
-188
-201
-170
-138
-154
-196
-171
-153
-140
-160
-158
-165
-136
-195
-190
-157
-165
-170
-171
-174
-152
-158
-200
-152
-110
-250
-141
-120
-139
-109
-106
-121
-121
-110
-150
-109
-121
-119
-111
-121
-122
-126
-83
-128
-121
-107
-119
-145
-124
-115
-151
-119
-135
-130
-120
-141
-139
-123
-124
-112
-121
-168
-143
-107
-171
-118
-150
-111
-102
-154
-140
-132
-152
-133
-181
-95
-108
-139
-170
-126
-109
-132
-145
-123
-121
-137
-158
-144
-132
-132
-126
-141
-132
-140
-145
-136
-120
-156
-145
-129
-131
-151
-142
-135
-135
-138
-179
-162
-131
-147
-160
-142
-150
-156
-172
-128
-153
-161
-155
-168
-169
-140
-195
-167
-114
-181
-169
-151
-184
-169
-156
-163
-159
-147
-169
-170
-159
-176
-193
-159
-154
-168
-192
-135
-137
-166
-183
-165
-153
-144
-190
-142
-140
-270
-198
-136
-146
-144
-121
-143
-162
-135
-149
-140
-150
-172
-135
-142
-145
-160
-145
-155
-152
-170
-133
-164
-137
-143
-159
-177
-166
-189
-150
-183
-162
-135
-195
-141
-126
-224
-141
-138
-205
-177
-175
-132
-149
-189
-181
-153
-192
-153
-198
-135
-150
-169
-207
-150
-148
-193
-204
-177
-146
-196
-208
-199
-181
-172
-175
-173
-177
-189
-195
-160
-165
-174
-201
-170
-162
-192
-177
-199
-159
-175
-207
-189
-147
-229
-216
-190
-194
-201
-214
-230
-188
-227
-205
-197
-185
-195
-254
-227
-150
-253
-215
-190
-219
-205
-213
-219
-207
-231
-206
-235
-215
-216
-264
-201
-169
-246
-246
-223
-211
-251
-225
-214
-203
-246
-248
-188
-166
-401
-139
-95
-123
-86
-118
-141
-119
-104
-129
-110
-107
-94
-102
-131
-75
-112
-115
-125
-138
-116
-101
-122
-96
-124
-119
-131
-110
-142
-110
-132
-104
-109
-137
-104
-127
-163
-150
-114
-159
-124
-156
-128
-115
-135
-136
-112
-128
-118
-151
-99
-118
-127
-139
-109
-110
-116
-160
-112
-139
-132
-125
-146
-127
-127
-145
-132
-133
-137
-137
-127
-126
-127
-159
-126
-127
-127
-141
-126
-159
-135
-185
-148
-119
-137
-161
-131
-135
-138
-161
-127
-139
-143
-178
-145
-149
-126
-184
-151
-107
-178
-178
-135
-157
-177
-180
-126
-150
-153
-177
-150
-153
-128
-193
-149
-132
-165
-173
-135
-145
-166
-166
-130
-136
-154
-176
-119
-112
-245
-207
-126
-164
-148
-132
-153
-133
-136
-145
-171
-140
-141
-146
-149
-140
-147
-128
-145
-166
-175
-139
-181
-134
-136
-168
-161
-163
-171
-150
-156
-144
-134
-192
-134
-146
-192
-201
-154
-201
-177
-182
-177
-144
-171
-189
-169
-188
-168
-190
-118
-152
-155
-199
-152
-148
-151
-187
-167
-167
-180
-177
-191
-176
-190
-193
-147
-178
-193
-209
-161
-190
-164
-218
-141
-171
-192
-183
-176
-187
-176
-203
-177
-154
-211
-211
-169
-176
-191
-194
-208
-196
-204
-224
-231
-187
-204
-247
-211
-151
-237
-243
-174
-228
-223
-177
-230
-194
-218
-228
-233
-217
-226
-225
-217
-178
-212
-228
-235
-171
-241
-224
-207
-184
-210
-255
-222
-174
-366
-157
-99
-134
-115
-125
-120
-132
-123
-122
-117
-122
-124
-106
-132
-104
-109
-128
-134
-131
-127
-119
-120
-95
-131
-137
-125
-125
-139
-111
-126
-122
-103
-160
-96
-128
-147
-154
-125
-136
-141
-150
-100
-138
-131
-150
-141
-140
-107
-138
-75
-140
-120
-155
-105
-117
-120
-161
-106
-127
-126
-147
-135
-164
-138
-144
-85
-151
-124
-145
-135
-133
-127
-166
-116
-140
-119
-174
-115
-159
-131
-171
-128
-127
-157
-147
-134
-144
-132
-152
-140
-142
-162
-195
-153
-160
-120
-205
-158
-134
-188
-183
-129
-204
-166
-189
-140
-173
-186
-196
-197
-152
-157
-204
-148
-172
-191
-223
-155
-162
-176
-173
-141
-184
-165
-233
-161
-170
-294
-142
-112
-143
-92
-107
-118
-130
-118
-119
-120
-124
-108
-133
-110
-128
-118
-122
-106
-128
-132
-125
-126
-134
-117
-85
-103
-136
-141
-115
-120
-135
-111
-147
-109
-114
-157
-123
-107
-156
-142
-126
-119
-114
-122
-141
-107
-141
-152
-141
-91
-138
-128
-141
-101
-95
-127
-153
-120
-133
-141
-137
-127
-123
-130
-142
-109
-130
-136
-150
-133
-131
-146
-155
-121
-110
-142
-170
-126
-159
-152
-170
-167
-119
-140
-155
-138
-121
-135
-148
-146
-141
-162
-151
-146
-162
-144
-172
-158
-120
-171
-151
-124
-128
-182
-158
-125
-124
-168
-139
-124
-139
-164
-152
-159
-128
-151
-151
-119
-110
-162
-118
-148
-133
-141
-168
-133
-116
-212
-203
-140
-166
-153
-141
-165
-155
-136
-144
-152
-164
-176
-154
-172
-158
-156
-150
-146
-176
-149
-160
-186
-151
-150
-154
-158
-145
-171
-155
-187
-166
-149
-225
-126
-165
-209
-216
-161
-248
-183
-212
-151
-165
-226
-211
-174
-193
-177
-217
-122
-192
-148
-225
-143
-172
-180
-246
-188
-194
-196
-185
-183
-196
-192
-198
-174
-214
-196
-245
-169
-180
-219
-220
-169
-201
-194
-221
-187
-242
-197
-264
-200
-198
-216
-225
-173
-226
-220
-271
-214
-226
-203
-271
-196
-221
-214
-302
-220
-166
-284
-239
-202
-259
-256
-259
-197
-198
-253
-265
-255
-231
-238
-298
-197
-217
-226
-273
-210
-219
-275
-261
-246
-201
-233
-286
-223
-217
-444
-148
-99
-135
-115
-87
-102
-111
-117
-136
-104
-99
-123
-125
-125
-109
-116
-103
-130
-105
-136
-86
-152
-101
-107
-107
-110
-110
-120
-100
-131
-91
-127
-135
-87
-108
-162
-129
-122
-149
-130
-107
-85
-115
-122
-121
-104
-115
-109
-142
-70
-109
-102
-106
-104
-108
-114
-115
-119
-100
-115
-132
-103
-112
-96
-135
-99
-98
-113
-134
-125
-109
-119
-121
-102
-104
-126
-136
-120
-131
-102
-176
-139
-117
-130
-149
-113
-118
-142
-152
-127
-119
-129
-183
-118
-140
-117
-156
-134
-98
-187
-149
-115
-164
-134
-176
-140
-133
-158
-150
-159
-141
-173
-186
-104
-136
-147
-178
-139
-146
-149
-148
-129
-135
-147
-195
-123
-122
-238
-145
-121
-135
-112
-97
-129
-117
-90
-124
-124
-111
-118
-115
-131
-110
-118
-103
-127
-115
-127
-113
-135
-109
-128
-137
-134
-151
-123
-104
-145
-117
-108
-147
-110
-106
-170
-118
-105
-154
-117
-138
-148
-124
-160
-139
-127
-142
-117
-142
-72
-103
-114
-127
-102
-109
-112
-154
-135
-118
-111
-136
-126
-118
-120
-159
-117
-139
-126
-142
-142
-129
-115
-161
-111
-138
-114
-147
-116
-151
-113
-173
-134
-128
-152
-170
-135
-121
-139
-139
-142
-111
-132
-152
-136
-135
-120
-186
-135
-100
-152
-155
-117
-132
-162
-169
-135
-128
-163
-177
-150
-147
-142
-182
-138
-128
-158
-151
-141
-120
-154
-153
-149
-130
-126
-152
-113
-106
-229
-179
-122
-156
-142
-136
-142
-154
-122
-154
-117
-149
-131
-126
-149
-136
-143
-140
-141
-156
-137
-134
-158
-136
-125
-133
-169
-135
-151
-164
-151
-150
-122
-234
-113
-123
-197
-174
-152
-213
-154
-175
-158
-141
-153
-171
-140
-140
-132
-203
-103
-161
-155
-178
-154
-128
-145
-207
-137
-158
-164
-171
-163
-187
-157
-190
-134
-163
-184
-183
-158
-159
-166
-184
-163
-162
-179
-185
-153
-171
-174
-189
-180
-164
-191
-207
-173
-191
-185
-208
-177
-189
-154
-226
-171
-212
-179
-242
-195
-133
-225
-238
-172
-238
-195
-221
-178
-182
-228
-202
-212
-210
-201
-200
-186
-176
-223
-210
-225
-189
-234
-209
-201
-205
-205
-248
-203
-176
-351
-198
-114
-132
-129
-131
-148
-128
-123
-124
-116
-140
-148
-120
-156
-132
-143
-120
-123
-162
-143
-130
-156
-118
-114
-118
-134
-154
-149
-129
-117
-142
-116
-148
-116
-123
-179
-164
-129
-175
-128
-132
-134
-130
-152
-144
-151
-154
-136
-150
-100
-131
-134
-156
-137
-142
-123
-140
-145
-123
-171
-186
-126
-130
-132
-144
-102
-130
-138
-140
-149
-138
-144
-165
-133
-135
-159
-194
-150
-148
-138
-200
-168
-138
-157
-172
-146
-152
-141
-173
-142
-151
-149
-190
-133
-151
-143
-251
-139
-128
-195
-180
-113
-158
-155
-173
-139
-144
-169
-187
-161
-160
-150
-172
-146
-152
-151
-192
-158
-159
-180
-171
-146
-144
-144
-240
-134
-161
-269
-162
-119
-121
-109
-100
-136
-126
-148
-129
-134
-139
-145
-158
-140
-123
-163
-145
-152
-161
-125
-128
-159
-115
-138
-150
-139
-144
-154
-117
-154
-146
-114
-181
-125
-115
-171
-158
-144
-187
-136
-146
-129
-118
-184
-145
-115
-161
-141
-202
-89
-134
-162
-158
-126
-141
-127
-172
-154
-125
-148
-180
-141
-174
-162
-172
-132
-156
-174
-183
-144
-148
-148
-207
-149
-162
-172
-171
-149
-157
-154
-220
-175
-132
-180
-158
-164
-151
-193
-205
-191
-162
-192
-205
-163
-172
-146
-255
-185
-142
-221
-221
-159
-205
-192
-201
-157
-176
-201
-193
-168
-177
-185
-215
-186
-177
-183
-193
-175
-152
-240
-188
-181
-189
-176
-212
-198
-151
-319
-156
-90
-126
-106
-96
-118
-123
-122
-130
-123
-121
-110
-126
-115
-136
-142
-129
-109
-139
-130
-92
-136
-106
-120
-111
-114
-123
-123
-150
-136
-109
-113
-140
-97
-130
-153
-137
-121
-179
-119
-126
-121
-127
-122
-125
-117
-144
-106
-158
-81
-101
-115
-132
-93
-111
-123
-155
-106
-126
-130
-137
-127
-123
-126
-139
-102
-157
-123
-155
-134
-140
-118
-170
-117
-140
-131
-155
-118
-146
-113
-190
-132
-116
-145
-163
-121
-140
-140
-138
-173
-153
-132
-165
-137
-137
-105
-173
-114
-97
-173
-165
-112
-148
-160
-166
-139
-151
-167
-163
-151
-155
-149
-200
-128
-154
-146
-179
-139
-147
-147
-164
-170
-162
-161
-197
-136
-139
-274
-152
-137
-136
-150
-108
-124
-117
-122
-111
-145
-116
-106
-119
-142
-117
-116
-127
-144
-133
-114
-106
-140
-127
-136
-129
-121
-122
-140
-130
-143
-136
-126
-155
-125
-128
-178
-145
-127
-166
-125
-141
-134
-111
-155
-134
-146
-166
-132
-160
-95
-134
-103
-158
-127
-126
-124
-160
-126
-126
-150
-155
-159
-134
-136
-119
-109
-149
-137
-154
-157
-148
-129
-183
-115
-151
-138
-170
-133
-163
-136
-195
-142
-144
-153
-175
-129
-148
-154
-158
-175
-167
-137
-174
-158
-146
-146
-188
-151
-119
-207
-162
-134
-193
-166
-187
-149
-139
-175
-173
-168
-151
-179
-161
-163
-153
-176
-201
-174
-154
-187
-164
-181
-157
-145
-216
-140
-147
-280
-180
-139
-151
-159
-113
-126
-140
-132
-136
-145
-163
-150
-136
-141
-122
-148
-126
-117
-155
-131
-137
-149
-122
-135
-134
-147
-133
-145
-151
-166
-103
-144
-187
-122
-144
-192
-142
-152
-177
-146
-172
-134
-131
-142
-173
-144
-143
-123
-175
-97
-154
-136
-189
-109
-145
-133
-179
-130
-146
-141
-197
-133
-168
-144
-184
-132
-169
-136
-187
-178
-138
-150
-173
-142
-166
-158
-165
-149
-205
-147
-212
-171
-145
-166
-204
-148
-184
-167
-204
-149
-165
-170
-206
-166
-178
-158
-255
-154
-163
-228
-210
-160
-201
-170
-207
-157
-186
-214
-206
-189
-188
-172
-212
-180
-169
-197
-223
-205
-201
-200
-215
-197
-188
-201
-239
-184
-167
-356
-168
-138
-145
-119
-116
-137
-137
-122
-135
-116
-117
-123
-99
-131
-111
-125
-135
-131
-134
-135
-105
-134
-107
-111
-126
-108
-137
-126
-121
-119
-101
-108
-163
-110
-84
-150
-128
-111
-181
-123
-134
-105
-112
-125
-143
-137
-122
-102
-159
-82
-118
-91
-146
-115
-110
-151
-149
-125
-116
-151
-163
-106
-144
-118
-165
-107
-148
-143
-154
-141
-116
-113
-177
-103
-136
-113
-160
-140
-139
-132
-213
-136
-119
-157
-160
-128
-136
-128
-157
-139
-142
-135
-182
-152
-148
-139
-201
-143
-118
-202
-145
-123
-176
-162
-173
-139
-150
-181
-152
-138
-162
-158
-202
-160
-140
-170
-180
-185
-149
-163
-154
-154
-158
-166
-215
-143
-121
-268
-158
-117
-156
-114
-102
-109
-106
-114
-116
-112
-117
-91
-92
-122
-113
-127
-124
-128
-126
-99
-115
-138
-117
-122
-123
-116
-118
-119
-134
-119
-120
-123
-150
-90
-130
-152
-169
-112
-166
-121
-121
-124
-111
-122
-134
-125
-138
-110
-159
-82
-143
-114
-149
-127
-140
-113
-153
-112
-123
-147
-145
-105
-147
-123
-144
-112
-155
-124
-177
-143
-145
-132
-173
-128
-149
-128
-152
-115
-137
-137
-188
-141
-132
-147
-145
-143
-143
-148
-173
-149
-138
-127
-198
-141
-156
-131
-201
-128
-118
-187
-178
-136
-169
-148
-165
-137
-155
-178
-199
-133
-149
-156
-211
-134
-149
-145
-185
-159
-136
-186
-185
-149
-151
-189
-209
-155
-161
-253
-162
-120
-151
-130
-123
-133
-140
-127
-135
-146
-120
-128
-118
-150
-121
-140
-150
-123
-151
-133
-137
-156
-124
-107
-121
-130
-137
-145
-107
-154
-139
-125
-172
-117
-126
-183
-144
-155
-185
-156
-165
-134
-134
-129
-134
-151
-174
-140
-169
-107
-130
-113
-155
-122
-137
-133
-163
-133
-123
-111
-162
-142
-155
-144
-145
-118
-167
-170
-160
-163
-144
-141
-207
-131
-143
-150
-161
-142
-162
-121
-214
-162
-146
-152
-209
-164
-161
-167
-188
-142
-177
-164
-205
-158
-170
-191
-225
-156
-150
-193
-205
-153
-195
-183
-198
-167
-141
-171
-215
-183
-168
-191
-203
-183
-143
-185
-191
-150
-191
-199
-202
-170
-154
-172
-215
-185
-155
-291
-139
-99
-140
-120
-106
-120
-109
-120
-126
-117
-119
-127
-114
-140
-102
-104
-105
-110
-131
-128
-125
-144
-109
-111
-108
-128
-132
-113
-116
-132
-103
-101
-130
-91
-123
-150
-125
-130
-150
-168
-153
-112
-91
-133
-152
-116
-130
-113
-161
-70
-117
-116
-155
-111
-126
-131
-173
-104
-118
-122
-150
-139
-132
-123
-156
-88
-132
-118
-161
-142
-104
-108
-162
-94
-129
-118
-156
-121
-156
-126
-185
-137
-114
-149
-163
-114
-137
-148
-163
-132
-132
-123
-169
-131
-115
-122
-194
-119
-130
-153
-162
-132
-141
-131
-171
-134
-132
-177
-172
-133
-147
-157
-174
-139
-131
-165
-205
-140
-157
-164
-163
-148
-146
-146
-210
-139
-146
-269
-163
-151
-137
-140
-123
-146
-141
-115
-119
-121
-138
-126
-139
-141
-136
-145
-90
-137
-153
-121
-155
-152
-152
-137
-137
-145
-125
-166
-142
-160
-125
-129
-172
-116
-134
-182
-158
-138
-173
-157
-161
-112
-130
-143
-143
-131
-166
-123
-187
-99
-135
-147
-179
-138
-155
-123
-154
-140
-138
-124
-153
-152
-156
-138
-176
-131
-144
-164
-175
-141
-148
-137
-187
-135
-130
-159
-170
-145
-171
-142
-217
-149
-138
-174
-217
-148
-187
-150
-216
-162
-185
-169
-209
-170
-135
-159
-219
-158
-130
-213
-192
-148
-181
-180
-203
-160
-176
-212
-183
-184
-165
-203
-192
-161
-166
-184
-208
-169
-188
-202
-173
-189
-182
-182
-230
-167
-164
-327
-193
-108
-154
-111
-87
-132
-128
-141
-142
-133
-111
-122
-119
-154
-127
-147
-130
-141
-125
-130
-129
-157
-114
-116
-124
-147
-123
-125
-125
-139
-116
-95
-170
-93
-102
-186
-164
-134
-170
-115
-165
-107
-128
-169
-129
-109
-138
-107
-163
-74
-127
-120
-166
-129
-132
-129
-154
-111
-135
-139
-151
-137
-130
-113
-162
-96
-129
-132
-182
-135
-137
-130
-183
-139
-155
-130
-154
-115
-160
-117
-196
-154
-165
-171
-181
-143
-148
-146
-201
-161
-156
-154
-206
-156
-174
-153
-237
-138
-132
-213
-215
-141
-196
-187
-191
-149
-169
-201
-203
-174
-192
-174
-214
-168
-165
-185
-235
-159
-165
-188
-188
-168
-198
-195
-221
-155
-153
-319
-147
-128
-144
-106
-109
-130
-101
-100
-119
-109
-107
-104
-104
-122
-118
-112
-94
-120
-134
-132
-102
-138
-101
-127
-133
-112
-117
-120
-103
-135
-139
-94
-141
-110
-114
-134
-109
-112
-137
-128
-113
-111
-86
-149
-125
-111
-121
-99
-139
-73
-112
-90
-133
-109
-114
-110
-150
-117
-117
-114
-130
-105
-126
-111
-141
-93
-140
-112
-122
-137
-103
-118
-142
-106
-133
-104
-142
-105
-147
-102
-136
-120
-110
-136
-141
-129
-149
-117
-167
-110
-137
-138
-152
-115
-124
-129
-204
-127
-107
-170
-134
-111
-133
-135
-150
-129
-126
-140
-136
-135
-157
-152
-156
-143
-117
-123
-150
-117
-129
-165
-147
-150
-138
-135
-175
-115
-125
-211
-161
-117
-140
-134
-96
-131
-122
-126
-141
-127
-108
-111
-121
-131
-119
-150
-135
-115
-143
-134
-118
-161
-106
-113
-118
-99
-128
-138
-133
-148
-127
-102
-165
-92
-119
-164
-120
-129
-166
-127
-155
-96
-126
-141
-152
-121
-132
-115
-156
-77
-117
-108
-162
-116
-129
-134
-161
-107
-134
-121
-136
-140
-124
-136
-144
-105
-156
-123
-166
-134
-124
-134
-152
-115
-130
-139
-156
-136
-169
-95
-209
-126
-132
-183
-192
-139
-153
-138
-167
-122
-145
-139
-175
-132
-162
-121
-186
-144
-135
-160
-180
-132
-167
-145
-148
-134
-156
-162
-189
-143
-156
-149
-180
-138
-133
-165
-187
-138
-131
-163
-166
-167
-186
-155
-211
-138
-154
-286
-173
-137
-164
-146
-107
-138
-149
-109
-154
-148
-124
-143
-137
-146
-148
-129
-112
-162
-159
-141
-132
-190
-119
-147
-145
-147
-163
-156
-126
-156
-122
-118
-153
-119
-160
-179
-155
-143
-196
-159
-157
-120
-145
-149
-140
-125
-153
-124
-183
-98
-136
-124
-179
-119
-143
-130
-178
-166
-177
-138
-148
-164
-159
-148
-179
-133
-178
-142
-188
-130
-131
-138
-202
-107
-166
-174
-174
-135
-159
-149
-202
-182
-129
-194
-185
-154
-192
-167
-187
-156
-168
-177
-206
-162
-154
-151
-242
-153
-124
-196
-223
-134
-199
-179
-211
-150
-168
-206
-211
-174
-174
-190
-240
-169
-155
-222
-186
-166
-183
-182
-232
-183
-151
-173
-230
-171
-158
-325
-191
-109
-144
-101
-111
-131
-116
-116
-138
-131
-130
-112
-109
-123
-115
-115
-126
-150
-117
-130
-126
-150
-109
-122
-121
-122
-138
-146
-96
-158
-102
-114
-177
-105
-111
-143
-156
-124
-183
-122
-149
-107
-123
-127
-152
-108
-144
-123
-158
-75
-129
-100
-122
-122
-147
-120
-151
-123
-136
-125
-131
-136
-123
-136
-145
-109
-145
-146
-148
-119
-129
-114
-165
-119
-148
-130
-125
-117
-137
-115
-219
-140
-144
-144
-182
-121
-162
-136
-169
-134
-154
-142
-184
-130
-166
-117
-219
-136
-120
-201
-185
-128
-183
-159
-186
-161
-153
-178
-172
-143
-147
-153
-196
-149
-122
-159
-208
-152
-185
-148
-179
-149
-145
-164
-224
-153
-181
-265
-156
-108
-122
-97
-108
-117
-122
-99
-111
-114
-109
-103
-111
-112
-99
-124
-94
-105
-136
-116
-99
-112
-90
-103
-101
-96
-109
-108
-101
-102
-104
-99
-140
-116
-111
-121
-122
-99
-131
-114
-119
-98
-119
-108
-130
-108
-122
-96
-125
-78
-99
-97
-125
-102
-136
-110
-140
-103
-124
-115
-126
-109
-112
-121
-143
-101
-111
-109
-137
-109
-107
-100
-132
-80
-123
-107
-129
-103
-135
-96
-168
-117
-107
-118
-144
-124
-119
-115
-134
-115
-132
-117
-161
-117
-109
-97
-138
-124
-91
-165
-141
-102
-117
-140
-125
-125
-130
-149
-143
-138
-122
-135
-152
-128
-107
-148
-137
-105
-129
-140
-132
-115
-136
-130
-148
-116
-104
-212
-173
-95
-134
-132
-132
-137
-128
-113
-131
-129
-130
-135
-125
-123
-127
-131
-113
-131
-119
-139
-135
-140
-128
-139
-138
-119
-143
-148
-110
-147
-132
-130
-170
-96
-125
-169
-149
-137
-173
-145
-154
-106
-112
-158
-144
-144
-144
-134
-193
-83
-123
-119
-139
-111
-130
-146
-153
-107
-121
-117
-164
-129
-149
-127
-158
-108
-160
-143
-162
-134
-116
-115
-166
-118
-125
-144
-184
-110
-166
-116
-184
-138
-130
-147
-194
-137
-156
-141
-165
-144
-132
-149
-178
-166
-144
-151
-198
-133
-132
-188
-190
-143
-176
-177
-172
-136
-167
-178
-172
-170
-172
-162
-198
-149
-162
-183
-201
-154
-173
-170
-145
-157
-164
-177
-228
-138
-149
-279
-206
-133
-172
-173
-129
-131
-131
-156
-145
-139
-133
-143
-123
-152
-123
-158
-133
-147
-196
-151
-136
-180
-138
-141
-128
-160
-172
-137
-119
-164
-136
-143
-176
-124
-145
-203
-178
-146
-214
-166
-180
-150
-140
-148
-189
-188
-194
-119
-209
-99
-154
-165
-194
-124
-178
-145
-193
-151
-134
-178
-166
-176
-166
-149
-180
-109
-181
-179
-208
-171
-140
-149
-217
-139
-178
-146
-189
-133
-188
-139
-243
-141
-174
-166
-204
-186
-197
-171
-206
-157
-191
-179
-210
-171
-207
-177
-251
-162
-139
-233
-207
-170
-210
-216
-221
-144
-210
-186
-230
-195
-183
-166
-240
-205
-169
-229
-234
-219
-191
-214
-229
-192
-205
-205
-247
-190
-201
-336
-123
-94
-117
-103
-85
-111
-113
-114
-97
-97
-104
-115
-88
-109
-92
-109
-84
-110
-82
-92
-95
-117
-84
-109
-85
-90
-82
-110
-80
-105
-98
-73
-139
-82
-113
-138
-103
-115
-149
-99
-144
-93
-110
-102
-126
-100
-113
-78
-112
-47
-101
-91
-119
-99
-101
-93
-114
-105
-94
-119
-110
-98
-112
-92
-147
-77
-129
-109
-138
-82
-121
-94
-124
-95
-115
-89
-126
-90
-121
-89
-163
-104
-98
-118
-124
-112
-98
-129
-127
-92
-112
-118
-142
-86
-131
-93
-184
-100
-94
-171
-137
-89
-138
-97
-133
-110
-149
-148
-143
-122
-139
-133
-151
-110
-137
-149
-153
-121
-139
-165
-127
-126
-146
-125
-179
-130
-119
-219
-132
-84
-103
-102
-98
-98
-100
-92
-118
-104
-101
-95
-112
-112
-98
-87
-115
-97
-97
-104
-91
-120
-97
-91
-109
-96
-88
-138
-96
-108
-93
-92
-120
-79
-92
-115
-142
-110
-151
-105
-136
-100
-94
-96
-119
-98
-114
-86
-126
-62
-83
-74
-117
-80
-98
-89
-121
-88
-102
-112
-112
-101
-112
-99
-123
-69
-127
-111
-129
-91
-103
-96
-131
-106
-101
-100
-123
-94
-118
-85
-150
-103
-100
-124
-128
-96
-121
-116
-143
-115
-115
-109
-150
-105
-156
-118
-182
-100
-126
-141
-121
-108
-155
-126
-130
-114
-106
-130
-120
-115
-127
-129
-149
-136
-111
-153
-145
-128
-136
-149
-139
-113
-114
-130
-165
-106
-96
-208
-159
-116
-144
-126
-104
-148
-112
-120
-124
-120
-116
-117
-107
-150
-119
-126
-113
-110
-141
-130
-143
-147
-105
-132
-113
-111
-134
-132
-107
-145
-119
-106
-158
-94
-109
-152
-148
-125
-205
-117
-140
-130
-125
-129
-154
-141
-181
-118
-167
-52
-140
-100
-153
-110
-145
-114
-172
-126
-128
-122
-140
-152
-140
-117
-124
-101
-158
-95
-172
-128
-133
-114
-170
-113
-133
-140
-141
-123
-148
-98
-203
-131
-129
-155
-176
-139
-155
-148
-163
-144
-153
-143
-168
-123
-152
-139
-233
-129
-133
-206
-183
-128
-191
-168
-205
-125
-150
-177
-181
-155
-169
-158
-174
-141
-146
-197
-188
-145
-164
-184
-173
-163
-167
-164
-211
-156
-142
-284
-177
-110
-129
-140
-101
-134
-136
-119
-151
-132
-137
-149
-127
-136
-128
-152
-138
-126
-141
-127
-130
-148
-115
-120
-141
-126
-144
-130
-115
-131
-132
-113
-172
-99
-126
-171
-158
-160
-190
-135
-168
-118
-119
-115
-134
-137
-149
-112
-169
-69
-135
-125
-184
-120
-134
-121
-157
-142
-161
-119
-167
-160
-161
-130
-167
-113
-157
-153
-181
-139
-140
-144
-202
-113
-149
-142
-169
-128
-172
-117
-242
-132
-149
-164
-198
-165
-186
-123
-192
-158
-169
-169
-179
-144
-174
-137
-223
-156
-129
-203
-216
-147
-217
-169
-192
-139
-162
-174
-202
-158
-170
-179
-209
-153
-159
-195
-202
-179
-161
-236
-200
-154
-173
-201
-249
-164
-131
-314
-158
-105
-135
-108
-100
-126
-123
-109
-115
-108
-122
-119
-117
-115
-105
-123
-118
-120
-145
-131
-97
-139
-125
-119
-111
-116
-132
-119
-98
-148
-105
-106
-144
-89
-106
-181
-130
-132
-178
-122
-162
-93
-125
-130
-138
-97
-131
-117
-153
-64
-107
-93
-120
-106
-123
-102
-145
-100
-106
-116
-136
-136
-144
-118
-140
-91
-153
-100
-159
-121
-130
-98
-171
-114
-143
-96
-153
-136
-160
-106
-218
-117
-124
-137
-174
-150
-134
-134
-185
-128
-151
-120
-195
-125
-168
-123
-209
-133
-120
-185
-173
-134
-154
-150
-177
-129
-151
-159
-201
-145
-163
-169
-193
-134
-176
-153
-249
-161
-144
-163
-184
-146
-146
-176
-247
-144
-160
-268
-109
-66
-96
-76
-86
-99
-97
-70
-93
-89
-74
-95
-83
-97
-74
-82
-85
-89
-89
-88
-67
-105
-77
-86
-74
-77
-78
-87
-89
-66
-66
-64
-96
-50
-79
-89
-98
-88
-125
-89
-119
-63
-94
-74
-80
-63
-105
-52
-87
-31
-102
-61
-92
-71
-72
-52
-89
-69
-75
-70
-90
-68
-77
-67
-79
-46
-103
-76
-98
-90
-87
-67
-101
-67
-75
-68
-97
-83
-83
-55
-143
-61
-80
-79
-104
-95
-102
-108
-123
-74
-96
-88
-125
-66
-107
-86
-153
-66
-89
-107
-109
-92
-129
-99
-103
-89
-102
-126
-100
-104
-101
-125
-131
-108
-104
-138
-134
-111
-110
-133
-119
-123
-121
-98
-121
-106
-108
-164
-66
-38
-62
-48
-42
-67
-49
-49
-56
-43
-52
-43
-37
-49
-42
-44
-48
-44
-71
-38
-46
-49
-36
-41
-34
-42
-44
-50
-44
-48
-30
-18
-57
-20
-48
-63
-65
-51
-72
-46
-63
-30
-33
-32
-40
-36
-55
-31
-39
-10
-39
-19
-46
-24
-32
-32
-47
-38
-34
-43
-33
-25
-31
-29
-49
-18
-41
-20
-64
-35
-43
-22
-66
-31
-51
-31
-45
-27
-51
-20
-88
-35
-44
-57
-55
-39
-60
-48
-66
-28
-57
-29
-64
-39
-69
-35
-88
-32
-45
-51
-77
-48
-82
-50
-69
-45
-64
-49
-55
-48
-54
-55
-76
-58
-65
-58
-82
-44
-65
-68
-74
-42
-57
-54
-79
-52
-56
-107
diff --git a/sasview/test/sesans_data/sphere2micron.ses b/sasview/test/sesans_data/sphere2micron.ses
deleted file mode 100644
index 21648ee..0000000
--- a/sasview/test/sesans_data/sphere2micron.ses
+++ /dev/null
@@ -1,51 +0,0 @@
-DataFileTitle "Polystyrene of Markus Strobl, Full Sine, ++ only "
-Sample "Polystyrene 2 um in 53% H2O, 47% D2O "
-Settings "D1=D2=20x8 mm,Ds = 16x10 mm (WxH), GF1 =scanning, GF2 = 2.5 A. 2 um polystyrene in 53% H2O, 47% D2O; 8.55% contrast "
-Operator CPD
-Date do 10 jul 2014 16:37:30
-ScanType sine one element scan
-Thickness [cm] 2.00E-01
-Q_zmax [\A^-1] 0.05
-Q_ymax [\A^-1] 0.05
-
-spin echo length [A] Depolarisation [A-2 cm-1] error depol [A-2 cm-1] error SEL [A] wavelength [A] error wavelength [A] polarisation error pol
-391.56 0.0041929 0.0036894 19.578 2.11 0.1055 1.0037 0.0032974
-1564 -0.0046571 0.0038185 78.2 2.11 0.1055 0.99586 0.003386
-2735.6 -0.017007 0.0038132 136.78 2.11 0.1055 0.98497 0.0033444
-3907.9 -0.033462 0.0035068 195.39 2.11 0.1055 0.97064 0.0030309
-5080.2 -0.047483 0.0038208 254.01 2.11 0.1055 0.9586 0.0032613
-6251.8 -0.070375 0.00376 312.59 2.11 0.1055 0.93926 0.0031446
-7423.2 -0.092217 0.0037927 371.16 2.11 0.1055 0.92117 0.0031108
-8595.5 -0.10238 0.004006 429.77 2.11 0.1055 0.91287 0.0032562
-9767.7 -0.12672 0.0038534 488.39 2.11 0.1055 0.8933 0.0030651
-10940 -0.1374 0.004243 546.98 2.11 0.1055 0.88484 0.003343
-12112 -0.16072 0.0045837 605.58 2.11 0.1055 0.86666 0.0035372
-13284 -0.16623 0.0045613 664.2 2.11 0.1055 0.86242 0.0035027
-14456 -0.18468 0.0044918 722.79 2.11 0.1055 0.84837 0.0033931
-15628 -0.19143 0.0048967 781.38 2.11 0.1055 0.84328 0.0036768
-16800 -0.20029 0.0045421 840.02 2.11 0.1055 0.83666 0.0033837
-17971 -0.19798 0.0046642 898.56 2.11 0.1055 0.83838 0.0034819
-19143 -0.21442 0.0047052 957.17 2.11 0.1055 0.82619 0.0034614
-20316 -0.20885 0.0044931 1015.8 2.11 0.1055 0.8303 0.0033218
-21488 -0.21393 0.0049186 1074.4 2.11 0.1055 0.82655 0.00362
-22660 -0.20685 0.004423 1133 2.11 0.1055 0.83179 0.0032758
-23832 -0.20802 0.0046979 1191.6 2.11 0.1055 0.83092 0.0034758
-25003 -0.19848 0.0045953 1250.2 2.11 0.1055 0.838 0.0034289
-26175 -0.21117 0.0044567 1308.8 2.11 0.1055 0.82859 0.0032881
-27347 -0.21283 0.004137 1367.4 2.11 0.1055 0.82736 0.0030477
-28520 -0.2042 0.0044587 1426 2.11 0.1055 0.83375 0.0033101
-29692 -0.2112 0.0042852 1484.6 2.11 0.1055 0.82857 0.0031615
-30864 -0.20319 0.0043483 1543.2 2.11 0.1055 0.8345 0.003231
-32036 -0.20752 0.0044297 1601.8 2.11 0.1055 0.83129 0.0032788
-33207 -0.20654 0.0043188 1660.4 2.11 0.1055 0.83201 0.0031995
-34380 -0.20126 0.0046375 1719 2.11 0.1055 0.83593 0.0034518
-35551 -0.20924 0.0042871 1777.6 2.11 0.1055 0.83001 0.0031684
-36724 -0.21323 0.0045471 1836.2 2.11 0.1055 0.82707 0.0033487
-37895 -0.21324 0.0045354 1894.7 2.11 0.1055 0.82706 0.00334
-39067 -0.19905 0.0044141 1953.4 2.11 0.1055 0.83758 0.003292
-40239 -0.1991 0.0047441 2012 2.11 0.1055 0.83754 0.003538
-41411 -0.20359 0.0050136 2070.5 2.11 0.1055 0.8342 0.003724
-42583 -0.21032 0.0049474 2129.1 2.11 0.1055 0.82922 0.0036529
-43755 -0.20689 0.0048203 2187.8 2.11 0.1055 0.83176 0.00357
-44927 -0.21075 0.0052337 2246.4 2.11 0.1055 0.8289 0.0038628
-46099 -0.19956 0.0047827 2304.9 2.11 0.1055 0.8372 0.0035653
diff --git a/setup.py b/setup.py
index d6093f8..129c1d2 100755
--- a/setup.py
+++ b/setup.py
@@ -1,18 +1,30 @@
+# -*- coding: utf-8 -*-
+#!/usr/bin/env python
+
"""
Setup for SasView
- #TODO: Add checks to see that all the dependencies are on the system
+ TODO: Add checks to see that all the dependencies are on the system
"""
-import sys
+from __future__ import print_function
+
import os
+import subprocess
import shutil
-from setuptools import setup, Extension
+import sys
from distutils.command.build_ext import build_ext
from distutils.core import Command
-import numpy
+
+import numpy as np
+from setuptools import Extension, setup
# Manage version number ######################################
-import sasview
-VERSION = sasview.__version__
+with open(os.path.join("src", "sas", "sasview", "__init__.py")) as fid:
+ for line in fid:
+ if line.startswith('__version__'):
+ VERSION = line.split('"')[1]
+ break
+ else:
+ raise ValueError("Could not find version in src/sas/sasview/__init__.py")
##############################################################
package_dir = {}
@@ -24,7 +36,7 @@ ext_modules = []
# We do this here because application updates these files from .sasview
# except when there is no such file
# Todo : make this list generic
-#plugin_model_list = ['polynominal5.py', 'sph_bessel_jn.py',
+# plugin_model_list = ['polynominal5.py', 'sph_bessel_jn.py',
# 'sum_Ap1_1_Ap2.py', 'sum_p1_p2.py',
# 'testmodel_2.py', 'testmodel.py',
# 'polynominal5.pyc', 'sph_bessel_jn.pyc',
@@ -34,7 +46,8 @@ ext_modules = []
CURRENT_SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
SASVIEW_BUILD = os.path.join(CURRENT_SCRIPT_DIR, "build")
-sas_dir = os.path.join(os.path.expanduser("~"),'.sasview')
+# TODO: build step should not be messing with existing installation!!
+sas_dir = os.path.join(os.path.expanduser("~"), '.sasview')
if os.path.isdir(sas_dir):
f_path = os.path.join(sas_dir, "sasview.log")
if os.path.isfile(f_path):
@@ -46,23 +59,26 @@ if os.path.isdir(sas_dir):
if os.path.isfile(f_path):
os.remove(f_path)
#f_path = os.path.join(sas_dir, 'plugin_models')
- #if os.path.isdir(f_path):
+ # if os.path.isdir(f_path):
# for f in os.listdir(f_path):
# if f in plugin_model_list:
# file_path = os.path.join(f_path, f)
# os.remove(file_path)
- if os.path.exists(SASVIEW_BUILD):
- print "Removing existing build directory", SASVIEW_BUILD, "for a clean build"
- shutil.rmtree(SASVIEW_BUILD)
+
+
+# Optionally clean before build.
+dont_clean = 'update' in sys.argv
+if dont_clean:
+ sys.argv.remove('update')
+elif os.path.exists(SASVIEW_BUILD):
+ print("Removing existing build directory", SASVIEW_BUILD, "for a clean build")
+ shutil.rmtree(SASVIEW_BUILD)
# 'sys.maxsize' and 64bit: Not supported for python2.5
-is_64bits = False
-if sys.version_info >= (2, 6):
- is_64bits = sys.maxsize > 2**32
+is_64bits = sys.maxsize > 2**32
enable_openmp = False
-
-if sys.platform =='darwin':
+if sys.platform == 'darwin':
if not is_64bits:
# Disable OpenMP
enable_openmp = False
@@ -73,28 +89,30 @@ if sys.platform =='darwin':
if darwin_ver >= 12:
enable_openmp = False
except:
- print "PROBLEM determining Darwin version"
+ print("PROBLEM determining Darwin version")
# Options to enable OpenMP
-copt = {'msvc': ['/openmp'],
- 'mingw32' : ['-fopenmp'],
- 'unix' : ['-fopenmp']}
-lopt = {'msvc': ['/MANIFEST'],
- 'mingw32' : ['-fopenmp'],
- 'unix' : ['-lgomp']}
+copt = {'msvc': ['/openmp'],
+ 'mingw32': ['-fopenmp'],
+ 'unix': ['-fopenmp']}
+lopt = {'msvc': ['/MANIFEST'],
+ 'mingw32': ['-fopenmp'],
+ 'unix': ['-lgomp']}
# Platform-specific link options
-platform_lopt = {'msvc' : ['/MANIFEST']}
+platform_lopt = {'msvc': ['/MANIFEST']}
platform_copt = {}
# Set copts to get compile working on OS X >= 10.9 using clang
-if sys.platform =='darwin':
+if sys.platform == 'darwin':
try:
darwin_ver = int(os.uname()[2].split('.')[0])
if darwin_ver >= 13 and darwin_ver < 14:
- platform_copt = {'unix' : ['-Wno-error=unused-command-line-argument-hard-error-in-future']}
+ platform_copt = {
+ 'unix': ['-Wno-error=unused-command-line-argument-hard-error-in-future']}
except:
- print "PROBLEM determining Darwin version"
+ print("PROBLEM determining Darwin version")
+
class DisableOpenMPCommand(Command):
description = "The version of MinGW that comes with Anaconda does not come with OpenMP :( "\
@@ -113,33 +131,34 @@ class DisableOpenMPCommand(Command):
def run(self):
pass
-class build_ext_subclass( build_ext ):
+
+class build_ext_subclass(build_ext):
def build_extensions(self):
# Get 64-bitness
c = self.compiler.compiler_type
- print "Compiling with %s (64bit=%s)" % (c, str(is_64bits))
+ print("Compiling with %s (64bit=%s)" % (c, str(is_64bits)))
# OpenMP build options
if enable_openmp:
- if copt.has_key(c):
+ if c in copt:
for e in self.extensions:
- e.extra_compile_args = copt[ c ]
- if lopt.has_key(c):
+ e.extra_compile_args = copt[c]
+ if c in lopt:
for e in self.extensions:
- e.extra_link_args = lopt[ c ]
+ e.extra_link_args = lopt[c]
# Platform-specific build options
- if platform_lopt.has_key(c):
+ if c in platform_lopt:
for e in self.extensions:
- e.extra_link_args = platform_lopt[ c ]
+ e.extra_link_args = platform_lopt[c]
- if platform_copt.has_key(c):
+ if c in platform_copt:
for e in self.extensions:
- e.extra_compile_args = platform_copt[ c ]
-
+ e.extra_compile_args = platform_copt[c]
build_ext.build_extensions(self)
+
class BuildSphinxCommand(Command):
description = "Build Sphinx documentation."
user_options = []
@@ -151,10 +170,28 @@ class BuildSphinxCommand(Command):
self.cwd = os.getcwd()
def run(self):
+ ''' First builds the sasmodels documentation if the directory
+ is present. Then builds the sasview docs.
+ '''
+ ### AJJ - Add code for building sasmodels docs here:
+ # check for doc path
+ SASMODELS_DOCPATH = os.path.abspath(os.path.join(os.getcwd(), '..', 'sasmodels', 'doc'))
+ print("========= check for sasmodels at", SASMODELS_DOCPATH, "============")
+ if os.path.exists(SASMODELS_DOCPATH):
+ if os.path.isdir(SASMODELS_DOCPATH):
+ # if available, build sasmodels docs
+ print("============= Building sasmodels model documentation ===============")
+ smdocbuild = subprocess.call(["make", "-C", SASMODELS_DOCPATH, "html"])
+ else:
+ # if not available warning message
+ print("== !!WARNING!! sasmodels directory not found. Cannot build model docs. ==")
+
+ #Now build sasview (+sasmodels) docs
sys.path.append("docs/sphinx-docs")
import build_sphinx
build_sphinx.rebuild()
+
# sas module
package_dir["sas"] = os.path.join("src", "sas")
packages.append("sas")
@@ -168,67 +205,80 @@ package_dir["sas.sascalc"] = os.path.join("src", "sas", "sascalc")
packages.append("sas.sascalc")
# sas.sascalc.invariant
-package_dir["sas.sascalc.invariant"] = os.path.join("src", "sas", "sascalc", "invariant")
+package_dir["sas.sascalc.invariant"] = os.path.join(
+ "src", "sas", "sascalc", "invariant")
packages.extend(["sas.sascalc.invariant"])
# sas.sasgui.guiframe
guiframe_path = os.path.join("src", "sas", "sasgui", "guiframe")
package_dir["sas.sasgui.guiframe"] = guiframe_path
-package_dir["sas.sasgui.guiframe.local_perspectives"] = os.path.join(os.path.join(guiframe_path, "local_perspectives"))
+package_dir["sas.sasgui.guiframe.local_perspectives"] = os.path.join(
+ os.path.join(guiframe_path, "local_perspectives"))
package_data["sas.sasgui.guiframe"] = ['images/*', 'media/*']
-packages.extend(["sas.sasgui.guiframe", "sas.sasgui.guiframe.local_perspectives"])
+packages.extend(
+ ["sas.sasgui.guiframe", "sas.sasgui.guiframe.local_perspectives"])
# build local plugin
for d in os.listdir(os.path.join(guiframe_path, "local_perspectives")):
- if d not in ['.svn','__init__.py', '__init__.pyc']:
+ if d not in ['.svn', '__init__.py', '__init__.pyc']:
package_name = "sas.sasgui.guiframe.local_perspectives." + d
packages.append(package_name)
- package_dir[package_name] = os.path.join(guiframe_path, "local_perspectives", d)
+ package_dir[package_name] = os.path.join(
+ guiframe_path, "local_perspectives", d)
# sas.sascalc.dataloader
-package_dir["sas.sascalc.dataloader"] = os.path.join("src", "sas", "sascalc", "dataloader")
-package_data["sas.sascalc.dataloader.readers"] = ['defaults.json','schema/*.xsd']
-packages.extend(["sas.sascalc.dataloader","sas.sascalc.dataloader.readers","sas.sascalc.dataloader.readers.schema"])
+package_dir["sas.sascalc.dataloader"] = os.path.join(
+ "src", "sas", "sascalc", "dataloader")
+package_data["sas.sascalc.dataloader.readers"] = ['schema/*.xsd']
+packages.extend(["sas.sascalc.dataloader", "sas.sascalc.dataloader.readers",
+ "sas.sascalc.dataloader.readers.schema"])
+
# sas.sascalc.calculator
gen_dir = os.path.join("src", "sas", "sascalc", "calculator", "c_extensions")
package_dir["sas.sascalc.calculator.core"] = gen_dir
-package_dir["sas.sascalc.calculator"] = os.path.join("src", "sas", "sascalc", "calculator")
-packages.extend(["sas.sascalc.calculator","sas.sascalc.calculator.core"])
-ext_modules.append( Extension("sas.sascalc.calculator.core.sld2i",
- sources = [
- os.path.join(gen_dir, "sld2i_module.cpp"),
- os.path.join(gen_dir, "sld2i.cpp"),
- os.path.join(gen_dir, "libfunc.c"),
- os.path.join(gen_dir, "librefl.c"),
- ],
- include_dirs=[gen_dir],
- )
-)
+package_dir["sas.sascalc.calculator"] = os.path.join(
+ "src", "sas", "sascalc", "calculator")
+packages.extend(["sas.sascalc.calculator", "sas.sascalc.calculator.core"])
+ext_modules.append(Extension("sas.sascalc.calculator.core.sld2i",
+ sources=[
+ os.path.join(gen_dir, "sld2i_module.cpp"),
+ os.path.join(gen_dir, "sld2i.cpp"),
+ os.path.join(gen_dir, "libfunc.c"),
+ os.path.join(gen_dir, "librefl.c"),
+ ],
+ include_dirs=[gen_dir],
+ )
+ )
# sas.sascalc.pr
-srcdir = os.path.join("src", "sas", "sascalc", "pr", "c_extensions")
+srcdir = os.path.join("src", "sas", "sascalc", "pr", "c_extensions")
package_dir["sas.sascalc.pr.core"] = srcdir
-package_dir["sas.sascalc.pr"] = os.path.join("src","sas", "sascalc", "pr")
-packages.extend(["sas.sascalc.pr","sas.sascalc.pr.core"])
-ext_modules.append( Extension("sas.sascalc.pr.core.pr_inversion",
- sources = [os.path.join(srcdir, "Cinvertor.c"),
- os.path.join(srcdir, "invertor.c"),
- ],
- include_dirs=[],
- ) )
+package_dir["sas.sascalc.pr"] = os.path.join("src", "sas", "sascalc", "pr")
+packages.extend(["sas.sascalc.pr", "sas.sascalc.pr.core"])
+ext_modules.append(Extension("sas.sascalc.pr.core.pr_inversion",
+ sources=[os.path.join(srcdir, "Cinvertor.c"),
+ os.path.join(srcdir, "invertor.c"),
+ ],
+ include_dirs=[],
+ ))
+
# sas.sascalc.file_converter
mydir = os.path.join("src", "sas", "sascalc", "file_converter", "c_ext")
package_dir["sas.sascalc.file_converter.core"] = mydir
-package_dir["sas.sascalc.file_converter"] = os.path.join("src","sas", "sascalc", "file_converter")
-packages.extend(["sas.sascalc.file_converter","sas.sascalc.file_converter.core"])
-ext_modules.append( Extension("sas.sascalc.file_converter.core.bsl_loader",
- sources = [os.path.join(mydir, "bsl_loader.c")],
- include_dirs=[numpy.get_include()],
- ) )
-
-#sas.sascalc.corfunc
-package_dir["sas.sascalc.corfunc"] = os.path.join("src", "sas", "sascalc", "corfunc")
+package_dir["sas.sascalc.file_converter"] = os.path.join(
+ "src", "sas", "sascalc", "file_converter")
+packages.extend(["sas.sascalc.file_converter",
+ "sas.sascalc.file_converter.core"])
+ext_modules.append(Extension("sas.sascalc.file_converter.core.bsl_loader",
+ sources=[os.path.join(mydir, "bsl_loader.c")],
+ include_dirs=[np.get_include()],
+ ))
+
+# sas.sascalc.corfunc
+package_dir["sas.sascalc.corfunc"] = os.path.join(
+ "src", "sas", "sascalc", "corfunc")
+
packages.extend(["sas.sascalc.corfunc"])
# sas.sascalc.fit
@@ -236,37 +286,50 @@ package_dir["sas.sascalc.fit"] = os.path.join("src", "sas", "sascalc", "fit")
packages.append("sas.sascalc.fit")
# Perspectives
-package_dir["sas.sasgui.perspectives"] = os.path.join("src", "sas", "sasgui", "perspectives")
-package_dir["sas.sasgui.perspectives.pr"] = os.path.join("src", "sas", "sasgui", "perspectives", "pr")
-packages.extend(["sas.sasgui.perspectives","sas.sasgui.perspectives.pr"])
+package_dir["sas.sasgui.perspectives"] = os.path.join(
+ "src", "sas", "sasgui", "perspectives")
+package_dir["sas.sasgui.perspectives.pr"] = os.path.join(
+ "src", "sas", "sasgui", "perspectives", "pr")
+packages.extend(["sas.sasgui.perspectives", "sas.sasgui.perspectives.pr"])
package_data["sas.sasgui.perspectives.pr"] = ['media/*']
-package_dir["sas.sasgui.perspectives.invariant"] = os.path.join("src", "sas", "sasgui", "perspectives", "invariant")
+package_dir["sas.sasgui.perspectives.invariant"] = os.path.join(
+ "src", "sas", "sasgui", "perspectives", "invariant")
packages.extend(["sas.sasgui.perspectives.invariant"])
-package_data['sas.sasgui.perspectives.invariant'] = [os.path.join("media",'*')]
-
-package_dir["sas.sasgui.perspectives.fitting"] = os.path.join("src", "sas", "sasgui", "perspectives", "fitting")
-package_dir["sas.sasgui.perspectives.fitting.plugin_models"] = os.path.join("src", "sas", "sasgui", "perspectives", "fitting", "plugin_models")
-packages.extend(["sas.sasgui.perspectives.fitting", "sas.sasgui.perspectives.fitting.plugin_models"])
-package_data['sas.sasgui.perspectives.fitting'] = ['media/*', 'plugin_models/*']
-
-packages.extend(["sas.sasgui.perspectives", "sas.sasgui.perspectives.calculator"])
+package_data['sas.sasgui.perspectives.invariant'] = [
+ os.path.join("media", '*')]
+
+package_dir["sas.sasgui.perspectives.fitting"] = os.path.join(
+ "src", "sas", "sasgui", "perspectives", "fitting")
+package_dir["sas.sasgui.perspectives.fitting.plugin_models"] = os.path.join(
+ "src", "sas", "sasgui", "perspectives", "fitting", "plugin_models")
+packages.extend(["sas.sasgui.perspectives.fitting",
+ "sas.sasgui.perspectives.fitting.plugin_models"])
+package_data['sas.sasgui.perspectives.fitting'] = [
+ 'media/*', 'plugin_models/*']
+
+packages.extend(["sas.sasgui.perspectives",
+ "sas.sasgui.perspectives.calculator"])
package_data['sas.sasgui.perspectives.calculator'] = ['images/*', 'media/*']
-package_dir["sas.sasgui.perspectives.corfunc"] = os.path.join("src", "sas", "sasgui", "perspectives", "corfunc")
+package_dir["sas.sasgui.perspectives.corfunc"] = os.path.join(
+ "src", "sas", "sasgui", "perspectives", "corfunc")
packages.extend(["sas.sasgui.perspectives.corfunc"])
package_data['sas.sasgui.perspectives.corfunc'] = ['media/*']
-package_dir["sas.sasgui.perspectives.file_converter"] = os.path.join("src", "sas", "sasgui", "perspectives", "file_converter")
+package_dir["sas.sasgui.perspectives.file_converter"] = os.path.join(
+ "src", "sas", "sasgui", "perspectives", "file_converter")
packages.extend(["sas.sasgui.perspectives.file_converter"])
package_data['sas.sasgui.perspectives.file_converter'] = ['media/*']
# Data util
-package_dir["sas.sascalc.data_util"] = os.path.join("src", "sas", "sascalc", "data_util")
+package_dir["sas.sascalc.data_util"] = os.path.join(
+ "src", "sas", "sascalc", "data_util")
packages.append("sas.sascalc.data_util")
# Plottools
-package_dir["sas.sasgui.plottools"] = os.path.join("src", "sas", "sasgui", "plottools")
+package_dir["sas.sasgui.plottools"] = os.path.join(
+ "src", "sas", "sasgui", "plottools")
packages.append("sas.sasgui.plottools")
# # Last of the sas.models
@@ -275,6 +338,7 @@ packages.append("sas.sasgui.plottools")
EXTENSIONS = [".c", ".cpp"]
+
def append_file(file_list, dir_path):
"""
Add sources file to sources
@@ -293,12 +357,13 @@ def append_file(file_list, dir_path):
if ext.lower() in EXTENSIONS:
file_list.append(os.path.join(sub_dir, new_f))
+
# Comment out the following to avoid rebuilding all the models
file_sources = []
append_file(file_sources, gen_dir)
-#Wojtek's hacky way to add doc files while bundling egg
-#def add_doc_files(directory):
+# Wojtek's hacky way to add doc files while bundling egg
+# def add_doc_files(directory):
# paths = []
# for (path, directories, filenames) in os.walk(directory):
# for filename in filenames:
@@ -308,7 +373,7 @@ append_file(file_sources, gen_dir)
#doc_files = add_doc_files('doc')
# SasView
-package_dir["sas.sasview"] = "sasview"
+package_data['sas'] = ['logging.ini']
package_data['sas.sasview'] = ['images/*',
'media/*',
'test/*.txt',
@@ -320,23 +385,24 @@ package_data['sas.sasview'] = ['images/*',
'test/media/*',
'test/other_files/*',
'test/save_states/*',
- 'test/sesans_data/*'
+ 'test/sesans_data/*',
+ 'test/upcoming_formats/*',
]
packages.append("sas.sasview")
required = [
- 'bumps>=0.7.5.9', 'periodictable>=1.3.1', 'pyparsing<2.0.0',
+ 'bumps>=0.7.5.9', 'periodictable>=1.5.0', 'pyparsing<2.0.0',
# 'lxml>=2.2.2',
'lxml', 'h5py',
- ## The following dependecies won't install automatically, so assume them
- ## The numbers should be bumped up for matplotlib and wxPython as well.
+ # The following dependecies won't install automatically, so assume them
+ # The numbers should be bumped up for matplotlib and wxPython as well.
# 'numpy>=1.4.1', 'scipy>=0.7.2', 'matplotlib>=0.99.1.1',
# 'wxPython>=2.8.11', 'pil',
- ]
+]
-if os.name=='nt':
+if os.name == 'nt':
required.extend(['html5lib', 'reportlab'])
else:
# 'pil' is now called 'pillow'
@@ -345,26 +411,26 @@ else:
# Set up SasView
setup(
name="sasview",
- version = VERSION,
- description = "SasView application",
- author = "SasView Team",
- author_email = "developers at sasview.org",
- url = "http://sasview.org",
- license = "PSF",
- keywords = "small-angle x-ray and neutron scattering analysis",
- download_url = "https://github.com/SasView/sasview.git",
- package_dir = package_dir,
- packages = packages,
- package_data = package_data,
- ext_modules = ext_modules,
- install_requires = required,
- zip_safe = False,
- entry_points = {
- 'console_scripts':[
- "sasview = sas.sasview.sasview:run",
- ]
- },
- cmdclass = {'build_ext': build_ext_subclass,
- 'docs': BuildSphinxCommand,
- 'disable_openmp': DisableOpenMPCommand}
- )
+ version=VERSION,
+ description="SasView application",
+ author="SasView Team",
+ author_email="developers at sasview.org",
+ url="http://sasview.org",
+ license="PSF",
+ keywords="small-angle x-ray and neutron scattering analysis",
+ download_url="https://github.com/SasView/sasview.git",
+ package_dir=package_dir,
+ packages=packages,
+ package_data=package_data,
+ ext_modules=ext_modules,
+ install_requires=required,
+ zip_safe=False,
+ entry_points={
+ 'console_scripts': [
+ "sasview = sas.sasview.sasview:run",
+ ]
+ },
+ cmdclass={'build_ext': build_ext_subclass,
+ 'docs': BuildSphinxCommand,
+ 'disable_openmp': DisableOpenMPCommand}
+)
diff --git a/src/examples/data_generator/test_transfo.py b/src/examples/data_generator/test_transfo.py
index 8fa40e2..9307860 100644
--- a/src/examples/data_generator/test_transfo.py
+++ b/src/examples/data_generator/test_transfo.py
@@ -1,50 +1,50 @@
-import math
-
-# log(x)
-def from_log10(x, y=0):
- return math.pow(10.0, x)
-def err_log10(x, y, dx, dy):
- return math.pow(10.0, x)*dx
-
-# ln(x)
-def from_lnx(x, y=0):
- return math.exp(x)
-def err_lnx(x, y, dx, dy):
- return math.exp(x)*dx
-
-# x^2
-def from_x2(x, y=0):
- return math.sqrt(x)
-def err_x2(x, y, dx, dy):
- return 0.5*dx/math.sqrt(x)
-
-# 1/x
-def from_inv_x(x, y=0):
- return 1.0/x
-def err_inv_x(x, y, dx, dy):
- return 1.0/(x**2)*dx
-
-# 1/sqrt(y)
-def from_inv_sqrtx(x, y=0):
- return 1.0/x**2
-def err_inv_sqrtx(x, y, dx, dy):
- return 2.0*math.pow(x,-3.0)*dx
-
-# ln(xy)
-def from_lnxy(x, y):
- return math.exp(x)/y
-def err_lnxy(x, y, dx, dy):
- return math.exp(x)/y*dx
-
-# ln(xy2)
-def from_lnx2y(x, y):
- return math.exp(x)/y**2
-def err_lnx2y(x, y, dx, dy):
- return math.exp(x)/y**2*dx
-
-# ln(xy4)
-def from_lnx4y(x, y):
- return math.exp(x)/y**4
-def err_lnx4y(x, y, dx, dy):
- return math.exp(x)/y**4*dx
-
+import math
+
+# log(x)
+def from_log10(x, y=0):
+ return math.pow(10.0, x)
+def err_log10(x, y, dx, dy):
+ return math.pow(10.0, x)*dx
+
+# ln(x)
+def from_lnx(x, y=0):
+ return math.exp(x)
+def err_lnx(x, y, dx, dy):
+ return math.exp(x)*dx
+
+# x^2
+def from_x2(x, y=0):
+ return math.sqrt(x)
+def err_x2(x, y, dx, dy):
+ return 0.5*dx/math.sqrt(x)
+
+# 1/x
+def from_inv_x(x, y=0):
+ return 1.0/x
+def err_inv_x(x, y, dx, dy):
+ return 1.0/(x**2)*dx
+
+# 1/sqrt(y)
+def from_inv_sqrtx(x, y=0):
+ return 1.0/x**2
+def err_inv_sqrtx(x, y, dx, dy):
+ return 2.0*math.pow(x,-3.0)*dx
+
+# ln(xy)
+def from_lnxy(x, y):
+ return math.exp(x)/y
+def err_lnxy(x, y, dx, dy):
+ return math.exp(x)/y*dx
+
+# ln(xy2)
+def from_lnx2y(x, y):
+ return math.exp(x)/y**2
+def err_lnx2y(x, y, dx, dy):
+ return math.exp(x)/y**2*dx
+
+# ln(xy4)
+def from_lnx4y(x, y):
+ return math.exp(x)/y**4
+def err_lnx4y(x, y, dx, dy):
+ return math.exp(x)/y**4*dx
+
diff --git a/src/examples/data_generator/testdata_generator.py b/src/examples/data_generator/testdata_generator.py
index a9fc7c2..c6ec551 100644
--- a/src/examples/data_generator/testdata_generator.py
+++ b/src/examples/data_generator/testdata_generator.py
@@ -1,97 +1,99 @@
-"""
- Generate two correlated sets of data
- 1- A line: y = ax + b
- 2- A constant equal to a of set #1
-
-"""
-
-def get_x(x, y=0, dx=0, dy=0):
- return x
-
-def get_err_x(x, y=0, dx=0, dy=0):
- return dx
-
-
-class Generator:
- ## Parameter A
- constant_a = 2.5
- ## Parameter B
- constant_b = 4.0
- ## Randomness factor
- randomness = 0.07
-
- def __init__(self):
- pass
-
- def create(self, filename, xmin=0.01, xmax=10.0, npts=50,
- xfunc=get_x, yfunc=get_x, errfunc=get_err_x):
- """
- Create files with the generate data
- The file names will be:
- - Set #1: [filename]_line.txt
- - Set #2: [filename]_cst.txt
-
- @param filename: string to prepend to the file name
- @param xmin: minimum x-value
- @param xmax: maximum x-value
- @param npts: number of points to generate
- """
- import random, time
- random.seed(time.time())
-
- # Write line data set
- fd = open(filename, 'w')
- print "Creating ", filename
- fd.write("#y=A*x+B\n#A=%g\n#B=%g\n" % (self.constant_a, self.constant_b))
-
- for i in range(npts):
- x = xmin+(xmax-xmin)/(npts-1)*i
- mu = self.constant_a*x+self.constant_b
- err = self.randomness*mu
- y = random.gauss(mu, err)
- fd.write("%g %g %g\n" % (xfunc(x, y), yfunc(y, xfunc(x, 0)), errfunc(y, xfunc(x,y), err, 0)))
-
- fd.close()
-
-
-
-
-if __name__ == "__main__":
- from test_transfo import *
- gen = Generator()
-
- # Linear x series
- gen.create("linear.txt")
- gen.create("x_y2.txt", yfunc=from_x2, errfunc=err_x2)
- gen.create("x_inv_y.txt", yfunc=from_inv_x, errfunc=err_inv_x)
- gen.create("x_inv_sqrty.txt", yfunc=from_inv_sqrtx, errfunc=err_inv_sqrtx)
- gen.create("x_lny.txt", xmin=0.0001, xmax=3.0, yfunc=from_lnx, errfunc=err_lnx)
- gen.create("x_logy.txt", xmin=0.0001, xmax=3.0, yfunc=from_log10, errfunc=err_log10)
- gen.create("x_lnxy.txt", yfunc=from_lnxy, errfunc=err_lnxy)
- gen.create("x_lnyx2.txt", xmin=0.0001, xmax=10.0, yfunc=from_lnx2y, errfunc=err_lnx2y)
- gen.create("x_lnyx4.txt", xmin=0.0001, xmax=10.0, yfunc=from_lnx4y, errfunc=err_lnx4y)
-
- # Log10(x)
- gen.create("logx_y.txt", xmax=3.0, xfunc=from_log10)
- gen.create("logx_y2.txt", xmax=3.0, xfunc=from_log10, yfunc=from_x2, errfunc=err_x2)
- gen.create("logx_inv_y.txt", xmax=3.0, xfunc=from_log10, yfunc=from_inv_x, errfunc=err_inv_x)
- gen.create("logx_inv_sqrty.txt", xmax=3.0, xfunc=from_log10, yfunc=from_inv_sqrtx, errfunc=err_inv_sqrtx)
- gen.create("logx_lny.txt", xfunc=from_log10, xmin=0.0001, xmax=3.0, yfunc=from_lnx, errfunc=err_lnx)
- gen.create("logx_logy.txt", xfunc=from_log10, xmin=0.0001, xmax=3.0, yfunc=from_log10, errfunc=err_log10)
- gen.create("logx_lnxy.txt", xfunc=from_log10, yfunc=from_lnxy, errfunc=err_lnxy)
- gen.create("logx_lnyx2.txt", xfunc=from_log10, xmin=0.0001, xmax=10.0, yfunc=from_lnx2y, errfunc=err_lnx2y)
- gen.create("logx_lnyx4.txt", xfunc=from_log10, xmin=0.0001, xmax=10.0, yfunc=from_lnx4y, errfunc=err_lnx4y)
-
- # x^2
- gen.create("x2_y.txt", xfunc=from_x2)
- gen.create("x2_y2.txt", xfunc=from_x2, yfunc=from_x2, errfunc=err_x2)
- gen.create("x2_inv_y.txt", xfunc=from_x2, yfunc=from_inv_x, errfunc=err_inv_x)
- gen.create("x2_inv_sqrty.txt", xfunc=from_x2, yfunc=from_inv_sqrtx, errfunc=err_inv_sqrtx)
- gen.create("x2_lny.txt", xfunc=from_x2, xmin=0.0001, xmax=3.0, yfunc=from_lnx, errfunc=err_lnx)
- gen.create("x2_logy.txt", xfunc=from_x2, xmin=0.0001, xmax=3.0, yfunc=from_log10, errfunc=err_log10)
- gen.create("x2_lnxy.txt", xfunc=from_x2, yfunc=from_lnxy, errfunc=err_lnxy)
- gen.create("x2_lnyx2.txt", xfunc=from_x2, xmin=0.0001, xmax=10.0, yfunc=from_lnx2y, errfunc=err_lnx2y)
- gen.create("x2_lnyx4.txt", xfunc=from_x2, xmin=0.0001, xmax=10.0, yfunc=from_lnx4y, errfunc=err_lnx4y)
-
-
+from __future__ import print_function
+
+"""
+ Generate two correlated sets of data
+ 1- A line: y = ax + b
+ 2- A constant equal to a of set #1
+
+"""
+
+def get_x(x, y=0, dx=0, dy=0):
+ return x
+
+def get_err_x(x, y=0, dx=0, dy=0):
+ return dx
+
+
+class Generator:
+ ## Parameter A
+ constant_a = 2.5
+ ## Parameter B
+ constant_b = 4.0
+ ## Randomness factor
+ randomness = 0.07
+
+ def __init__(self):
+ pass
+
+ def create(self, filename, xmin=0.01, xmax=10.0, npts=50,
+ xfunc=get_x, yfunc=get_x, errfunc=get_err_x):
+ """
+ Create files with the generate data
+ The file names will be:
+ - Set #1: [filename]_line.txt
+ - Set #2: [filename]_cst.txt
+
+ @param filename: string to prepend to the file name
+ @param xmin: minimum x-value
+ @param xmax: maximum x-value
+ @param npts: number of points to generate
+ """
+ import random, time
+ random.seed(time.time())
+
+ # Write line data set
+ fd = open(filename, 'w')
+ print("Creating ", filename)
+ fd.write("#y=A*x+B\n#A=%g\n#B=%g\n" % (self.constant_a, self.constant_b))
+
+ for i in range(npts):
+ x = xmin+(xmax-xmin)/(npts-1)*i
+ mu = self.constant_a*x+self.constant_b
+ err = self.randomness*mu
+ y = random.gauss(mu, err)
+ fd.write("%g %g %g\n" % (xfunc(x, y), yfunc(y, xfunc(x, 0)), errfunc(y, xfunc(x,y), err, 0)))
+
+ fd.close()
+
+
+
+
+if __name__ == "__main__":
+ from test_transfo import *
+ gen = Generator()
+
+ # Linear x series
+ gen.create("linear.txt")
+ gen.create("x_y2.txt", yfunc=from_x2, errfunc=err_x2)
+ gen.create("x_inv_y.txt", yfunc=from_inv_x, errfunc=err_inv_x)
+ gen.create("x_inv_sqrty.txt", yfunc=from_inv_sqrtx, errfunc=err_inv_sqrtx)
+ gen.create("x_lny.txt", xmin=0.0001, xmax=3.0, yfunc=from_lnx, errfunc=err_lnx)
+ gen.create("x_logy.txt", xmin=0.0001, xmax=3.0, yfunc=from_log10, errfunc=err_log10)
+ gen.create("x_lnxy.txt", yfunc=from_lnxy, errfunc=err_lnxy)
+ gen.create("x_lnyx2.txt", xmin=0.0001, xmax=10.0, yfunc=from_lnx2y, errfunc=err_lnx2y)
+ gen.create("x_lnyx4.txt", xmin=0.0001, xmax=10.0, yfunc=from_lnx4y, errfunc=err_lnx4y)
+
+ # Log10(x)
+ gen.create("logx_y.txt", xmax=3.0, xfunc=from_log10)
+ gen.create("logx_y2.txt", xmax=3.0, xfunc=from_log10, yfunc=from_x2, errfunc=err_x2)
+ gen.create("logx_inv_y.txt", xmax=3.0, xfunc=from_log10, yfunc=from_inv_x, errfunc=err_inv_x)
+ gen.create("logx_inv_sqrty.txt", xmax=3.0, xfunc=from_log10, yfunc=from_inv_sqrtx, errfunc=err_inv_sqrtx)
+ gen.create("logx_lny.txt", xfunc=from_log10, xmin=0.0001, xmax=3.0, yfunc=from_lnx, errfunc=err_lnx)
+ gen.create("logx_logy.txt", xfunc=from_log10, xmin=0.0001, xmax=3.0, yfunc=from_log10, errfunc=err_log10)
+ gen.create("logx_lnxy.txt", xfunc=from_log10, yfunc=from_lnxy, errfunc=err_lnxy)
+ gen.create("logx_lnyx2.txt", xfunc=from_log10, xmin=0.0001, xmax=10.0, yfunc=from_lnx2y, errfunc=err_lnx2y)
+ gen.create("logx_lnyx4.txt", xfunc=from_log10, xmin=0.0001, xmax=10.0, yfunc=from_lnx4y, errfunc=err_lnx4y)
+
+ # x^2
+ gen.create("x2_y.txt", xfunc=from_x2)
+ gen.create("x2_y2.txt", xfunc=from_x2, yfunc=from_x2, errfunc=err_x2)
+ gen.create("x2_inv_y.txt", xfunc=from_x2, yfunc=from_inv_x, errfunc=err_inv_x)
+ gen.create("x2_inv_sqrty.txt", xfunc=from_x2, yfunc=from_inv_sqrtx, errfunc=err_inv_sqrtx)
+ gen.create("x2_lny.txt", xfunc=from_x2, xmin=0.0001, xmax=3.0, yfunc=from_lnx, errfunc=err_lnx)
+ gen.create("x2_logy.txt", xfunc=from_x2, xmin=0.0001, xmax=3.0, yfunc=from_log10, errfunc=err_log10)
+ gen.create("x2_lnxy.txt", xfunc=from_x2, yfunc=from_lnxy, errfunc=err_lnxy)
+ gen.create("x2_lnyx2.txt", xfunc=from_x2, xmin=0.0001, xmax=10.0, yfunc=from_lnx2y, errfunc=err_lnx2y)
+ gen.create("x2_lnyx4.txt", xfunc=from_x2, xmin=0.0001, xmax=10.0, yfunc=from_lnx4y, errfunc=err_lnx4y)
+
+
\ No newline at end of file
diff --git a/src/examples/test_chisq_panel.py b/src/examples/test_chisq_panel.py
index 1b6a158..6989de4 100755
--- a/src/examples/test_chisq_panel.py
+++ b/src/examples/test_chisq_panel.py
@@ -1,117 +1,117 @@
-"""
-Test application that uses plottools
-
-An application required by the REFL group and mainly test the Chisq class.
-
-The following is a checklist of functionality to look for while testing:
-1- Start the application:
- the graph should have theory curve, experimental data, chisq
- with a white background.
-
-2- Hovering over any plotted data will highlight the whole data set
- or line in yellow.
-
-3- Left-clicking on the graph and dragging will drag the graph.
-
-4- Using the mouse wheel will zoom in and out of the graph.
-
-5- Right-clicking on the graph when no curve is highlighted will
- pop up the context menu:
- - 'Save image' will pop up a save dialog to save an image.
- - 'Reset graph' will reset the graph to its original appearance after it
- has been dragged around or zoomed in or out.
- - 'Change scale' will pop up a scale dialog with which the axes can
- be transformed. Each transformation choice should work.
-
-"""
-
-import wx
-from sas.sasgui.plottools.PlotPanel import PlotPanel
-from sas.sasgui.plottools.plottables import Plottable, Graph, Data1D, Theory1D
-import sys
-import numpy
-
-
-class ReflPlotPanel(PlotPanel):
-
- def __init__(self, parent, id = -1,
- color = None,
- dpi = None,
- **kwargs):
- PlotPanel.__init__(self, parent, id=id, color=color,
- dpi=dpi, **kwargs)
-
- # Keep track of the parent Frame
- self.parent = parent
-
- # Internal list of plottable names (because graph
- # doesn't have a dictionary of handles for the plottables)
- self.plots = {}
-
-
- def onContextMenu(self, event):
- """
- Default context menu for a plot panel
- """
- # Slicer plot popup menu
- id = wx.NewId()
- _menu = wx.Menu()
- _menu.Append(id,'&Save image', 'Save image as PNG')
- wx.EVT_MENU(self, id, self.onSaveImage)
-
- _menu.AppendSeparator()
- id = wx.NewId()
- _menu.Append(id, '&Change scale')
- wx.EVT_MENU(self, id, self._onProperties)
-
- id = wx.NewId()
- _menu.Append(id, '&Reset Graph')
- wx.EVT_MENU(self, id, self.onResetGraph)
-
- pos = event.GetPosition()
- pos = self.ScreenToClient(pos)
- self.PopupMenu(_menu, pos)
-
-
-# ---------------------------------------------------------------
-def sample_graph():
- # Construct a simple graph
- if False:
- x = numpy.array([1,2,3,4,5,6],'d')
- y = numpy.array([4,5,26,5,4,-1],'d')
- dy = numpy.array([0.2, 0.3, 0.1, 0.2, 0.9, 0.3])
- else:
- x = numpy.linspace(0,2.0, 50)
- y = numpy.sin(2*numpy.pi*x*2.8)
- dy = numpy.sqrt(100*numpy.abs(y))/100
-
- from sas.sasgui.plottools.plottables import Data1D, Theory1D, Chisq , Graph
- data = Data1D(x,y,dy=dy)
- data.xaxis('distance', 'm')
- data.yaxis('time', 's')
- graph = Graph()
- graph.title('Walking Results')
- graph.add(data)
- graph.add( Theory1D(x,y,dy=dy))
- graph.add( Chisq( 1.0 ) )
- return graph
-
-
-def demo_plotter(graph):
- # Make a frame to show it
- app = wx.PySimpleApp()
- frame = wx.Frame(None,-1,'Plottables')
- plotter = ReflPlotPanel(frame)
- frame.Show()
-
- # render the graph to the pylab plotter
- graph.render(plotter)
-
- app.MainLoop()
-
-
-if __name__ == "__main__":
- pass
- demo_plotter(sample_graph())
-
-
+"""
+Test application that uses plottools
+
+An application required by the REFL group and mainly test the Chisq class.
+
+The following is a checklist of functionality to look for while testing:
+1- Start the application:
+ the graph should have theory curve, experimental data, chisq
+ with a white background.
+
+2- Hovering over any plotted data will highlight the whole data set
+ or line in yellow.
+
+3- Left-clicking on the graph and dragging will drag the graph.
+
+4- Using the mouse wheel will zoom in and out of the graph.
+
+5- Right-clicking on the graph when no curve is highlighted will
+ pop up the context menu:
+ - 'Save image' will pop up a save dialog to save an image.
+ - 'Reset graph' will reset the graph to its original appearance after it
+ has been dragged around or zoomed in or out.
+ - 'Change scale' will pop up a scale dialog with which the axes can
+ be transformed. Each transformation choice should work.
+
+"""
+
+import wx
+from sas.sasgui.plottools.PlotPanel import PlotPanel
+from sas.sasgui.plottools.plottables import Plottable, Graph, Data1D, Theory1D
+import sys
+import numpy as np
+
+
+class ReflPlotPanel(PlotPanel):
+
+ def __init__(self, parent, id = -1,
+ color = None,
+ dpi = None,
+ **kwargs):
+ PlotPanel.__init__(self, parent, id=id, color=color,
+ dpi=dpi, **kwargs)
+
+ # Keep track of the parent Frame
+ self.parent = parent
+
+ # Internal list of plottable names (because graph
+ # doesn't have a dictionary of handles for the plottables)
+ self.plots = {}
+
+
+ def onContextMenu(self, event):
+ """
+ Default context menu for a plot panel
+ """
+ # Slicer plot popup menu
+ id = wx.NewId()
+ _menu = wx.Menu()
+ _menu.Append(id,'&Save image', 'Save image as PNG')
+ wx.EVT_MENU(self, id, self.onSaveImage)
+
+ _menu.AppendSeparator()
+ id = wx.NewId()
+ _menu.Append(id, '&Change scale')
+ wx.EVT_MENU(self, id, self._onProperties)
+
+ id = wx.NewId()
+ _menu.Append(id, '&Reset Graph')
+ wx.EVT_MENU(self, id, self.onResetGraph)
+
+ pos = event.GetPosition()
+ pos = self.ScreenToClient(pos)
+ self.PopupMenu(_menu, pos)
+
+
+# ---------------------------------------------------------------
+def sample_graph():
+ # Construct a simple graph
+ if False:
+ x = np.array([1,2,3,4,5,6],'d')
+ y = np.array([4,5,26,5,4,-1],'d')
+ dy = np.array([0.2, 0.3, 0.1, 0.2, 0.9, 0.3])
+ else:
+ x = np.linspace(0,2.0, 50)
+ y = np.sin(2*np.pi*x*2.8)
+ dy = np.sqrt(100*np.abs(y))/100
+
+ from sas.sasgui.plottools.plottables import Data1D, Theory1D, Chisq , Graph
+ data = Data1D(x,y,dy=dy)
+ data.xaxis('distance', 'm')
+ data.yaxis('time', 's')
+ graph = Graph()
+ graph.title('Walking Results')
+ graph.add(data)
+ graph.add( Theory1D(x,y,dy=dy))
+ graph.add( Chisq( 1.0 ) )
+ return graph
+
+
+def demo_plotter(graph):
+ # Make a frame to show it
+ app = wx.PySimpleApp()
+ frame = wx.Frame(None,-1,'Plottables')
+ plotter = ReflPlotPanel(frame)
+ frame.Show()
+
+ # render the graph to the pylab plotter
+ graph.render(plotter)
+
+ app.MainLoop()
+
+
+if __name__ == "__main__":
+ pass
+ demo_plotter(sample_graph())
+
+
diff --git a/src/examples/test_copy_print.py b/src/examples/test_copy_print.py
index e2f8b26..432f9f6 100755
--- a/src/examples/test_copy_print.py
+++ b/src/examples/test_copy_print.py
@@ -1,117 +1,117 @@
-"""
-Test application that uses plottools
-
-An application required by the REFL group and mainly test copy and print.
-
-The following is a checklist of functionality to look for while testing:
-1- Start the application:
- the graph should have theory curve, experimental data, chisq
- with a white background.
-
-2- Hovering over any plotted data will highlight the whole data set
- or line in yellow.
-
-3- Left-clicking on the graph and dragging will drag the graph.
-
-4- Using the mouse wheel will zoom in and out of the graph.
-
-5- Right-clicking on the graph when no curve is highlighted will
- pop up the context menu:
- - 'copy image': copy the bitmap of figure to system clipboard
- - 'print Setup': setup the size of figure for printing
- - 'print preview': preview printer page
- - 'print': send figure to system printer.
-
-"""
-
-import wx
-from sas.sasgui.plottools.PlotPanel import PlotPanel
-from sas.sasgui.plottools.plottables import Graph, Data1D, Theory1D
-import sys
-sys.platform = 'win95'
-import numpy
-
-
-class TestPlotPanel(PlotPanel):
-
- def __init__(self, parent, id = -1,
- color = None,
- dpi = None,
- **kwargs):
- PlotPanel.__init__(self, parent, id=id, color=color,
- dpi=dpi, **kwargs)
-
- # Keep track of the parent Frame
- self.parent = parent
-
- # Internal list of plottable names (because graph
- # doesn't have a dictionary of handles for the plottables)
- self.plots = {}
-
-
- def onContextMenu(self, event):
- """
- Default context menu for a plot panel
- """
- wxID_Copy = wx.NewId()
- wxID_Print = wx.NewId()
- wxID_PrintPreview = wx.NewId()
- wxID_PrintSetup = wx.NewId()
-
- _menu = wx.Menu()
- _menu.Append(wxID_Copy,'&Copy Image', 'Copy image to Clipboard')
- wx.EVT_MENU(self, wxID_Copy, self.OnCopyFigureMenu)
-
- _menu.AppendSeparator()
- _menu.Append(wxID_PrintSetup, '&Print setup')
- wx.EVT_MENU(self, wxID_PrintSetup, self.onPrinterSetup)
-
- _menu.Append(wxID_PrintPreview, '&Print preview ')
- wx.EVT_MENU(self, wxID_PrintPreview, self.onPrinterPreview)
-
- _menu.Append(wxID_Print, '&Print ')
- wx.EVT_MENU(self, wxID_Print, self.onPrint)
-
- pos = event.GetPosition()
- pos = self.ScreenToClient(pos)
- self.PopupMenu(_menu, pos)
-
-
-# ---------------------------------------------------------------
-def sample_graph():
- # Construct a simple graph
- x = numpy.linspace(0,2.0, 50)
- y = numpy.sin(2*numpy.pi*x*2.8)
- dy = numpy.sqrt(100*numpy.abs(y))/100
-
- data = Data1D(x,y,dy=dy)
- data.xaxis('distance', 'm')
- data.yaxis('time', 's')
-
- graph = Graph()
-
- graph.add(data)
- graph.add( Theory1D(x,y,dy=dy))
-
- graph.title( 'Test Copy and Print Image' )
- return graph
-
-
-def demo_plotter(graph):
- # Make a frame to show it
- app = wx.PySimpleApp()
- frame = wx.Frame(None,-1,'Plottables')
- plotter = TestPlotPanel(frame)
- frame.Show()
-
- # render the graph to the pylab plotter
- graph.render(plotter)
-
- app.MainLoop()
-
-
-if __name__ == "__main__":
- pass
- demo_plotter(sample_graph())
-
-
+"""
+Test application that uses plottools
+
+An application required by the REFL group and mainly test copy and print.
+
+The following is a checklist of functionality to look for while testing:
+1- Start the application:
+ the graph should have theory curve, experimental data, chisq
+ with a white background.
+
+2- Hovering over any plotted data will highlight the whole data set
+ or line in yellow.
+
+3- Left-clicking on the graph and dragging will drag the graph.
+
+4- Using the mouse wheel will zoom in and out of the graph.
+
+5- Right-clicking on the graph when no curve is highlighted will
+ pop up the context menu:
+ - 'copy image': copy the bitmap of figure to system clipboard
+ - 'print Setup': setup the size of figure for printing
+ - 'print preview': preview printer page
+ - 'print': send figure to system printer.
+
+"""
+
+import wx
+from sas.sasgui.plottools.PlotPanel import PlotPanel
+from sas.sasgui.plottools.plottables import Graph, Data1D, Theory1D
+import sys
+sys.platform = 'win95'
+import numpy as np
+
+
+class TestPlotPanel(PlotPanel):
+
+ def __init__(self, parent, id = -1,
+ color = None,
+ dpi = None,
+ **kwargs):
+ PlotPanel.__init__(self, parent, id=id, color=color,
+ dpi=dpi, **kwargs)
+
+ # Keep track of the parent Frame
+ self.parent = parent
+
+ # Internal list of plottable names (because graph
+ # doesn't have a dictionary of handles for the plottables)
+ self.plots = {}
+
+
+ def onContextMenu(self, event):
+ """
+ Default context menu for a plot panel
+ """
+ wxID_Copy = wx.NewId()
+ wxID_Print = wx.NewId()
+ wxID_PrintPreview = wx.NewId()
+ wxID_PrintSetup = wx.NewId()
+
+ _menu = wx.Menu()
+ _menu.Append(wxID_Copy,'&Copy Image', 'Copy image to Clipboard')
+ wx.EVT_MENU(self, wxID_Copy, self.OnCopyFigureMenu)
+
+ _menu.AppendSeparator()
+ _menu.Append(wxID_PrintSetup, '&Print setup')
+ wx.EVT_MENU(self, wxID_PrintSetup, self.onPrinterSetup)
+
+ _menu.Append(wxID_PrintPreview, '&Print preview ')
+ wx.EVT_MENU(self, wxID_PrintPreview, self.onPrinterPreview)
+
+ _menu.Append(wxID_Print, '&Print ')
+ wx.EVT_MENU(self, wxID_Print, self.onPrint)
+
+ pos = event.GetPosition()
+ pos = self.ScreenToClient(pos)
+ self.PopupMenu(_menu, pos)
+
+
+# ---------------------------------------------------------------
+def sample_graph():
+ # Construct a simple graph
+ x = np.linspace(0,2.0, 50)
+ y = np.sin(2*np.pi*x*2.8)
+ dy = np.sqrt(100*np.abs(y))/100
+
+ data = Data1D(x,y,dy=dy)
+ data.xaxis('distance', 'm')
+ data.yaxis('time', 's')
+
+ graph = Graph()
+
+ graph.add(data)
+ graph.add( Theory1D(x,y,dy=dy))
+
+ graph.title( 'Test Copy and Print Image' )
+ return graph
+
+
+def demo_plotter(graph):
+ # Make a frame to show it
+ app = wx.PySimpleApp()
+ frame = wx.Frame(None,-1,'Plottables')
+ plotter = TestPlotPanel(frame)
+ frame.Show()
+
+ # render the graph to the pylab plotter
+ graph.render(plotter)
+
+ app.MainLoop()
+
+
+if __name__ == "__main__":
+ pass
+ demo_plotter(sample_graph())
+
+
diff --git a/src/examples/test_panel.py b/src/examples/test_panel.py
index 80fac47..dc49066 100644
--- a/src/examples/test_panel.py
+++ b/src/examples/test_panel.py
@@ -38,8 +38,8 @@
import wx
from sas.sasgui.plottools.PlotPanel import PlotPanel
from sas.sasgui.plottools.plottables import Data1D
-import sys
-import numpy
+import sys
+import numpy as np
import random, math
@@ -156,14 +156,14 @@ class ViewerFrame(wx.Frame):
def _add_data(self, event):
data_len = 50
- x = numpy.zeros(data_len)
- y = numpy.zeros(data_len)
- x2 = numpy.zeros(data_len)
- y2 = numpy.zeros(data_len)
- dy2 = numpy.zeros(data_len)
- x3 = numpy.zeros(data_len)
- y3 = numpy.zeros(data_len)
- dy3 = numpy.zeros(data_len)
+ x = np.zeros(data_len)
+ y = np.zeros(data_len)
+ x2 = np.zeros(data_len)
+ y2 = np.zeros(data_len)
+ dy2 = np.zeros(data_len)
+ x3 = np.zeros(data_len)
+ y3 = np.zeros(data_len)
+ dy3 = np.zeros(data_len)
for i in range(len(x)):
x[i] = i
x2[i] = i-0.1+0.2*random.random()
diff --git a/src/examples/test_panel2D.py b/src/examples/test_panel2D.py
index 0b48e70..cf02293 100644
--- a/src/examples/test_panel2D.py
+++ b/src/examples/test_panel2D.py
@@ -39,7 +39,7 @@ import wx
from sas.sasgui.plottools.PlotPanel import PlotPanel
from sas.sasgui.plottools.plottables import Data1D, Theory1D, Data2D
import sys,os
-import numpy
+import numpy as np
import random, math
@@ -225,14 +225,14 @@ class ViewerFrame(wx.Frame):
def _add_data(self, event):
data_len = 50
- x = numpy.zeros(data_len)
- y = numpy.zeros(data_len)
- x2 = numpy.zeros(data_len)
- y2 = numpy.zeros(data_len)
- dy2 = numpy.zeros(data_len)
- x3 = numpy.zeros(data_len)
- y3 = numpy.zeros(data_len)
- dy3 = numpy.zeros(data_len)
+ x = np.zeros(data_len)
+ y = np.zeros(data_len)
+ x2 = np.zeros(data_len)
+ y2 = np.zeros(data_len)
+ dy2 = np.zeros(data_len)
+ x3 = np.zeros(data_len)
+ y3 = np.zeros(data_len)
+ dy3 = np.zeros(data_len)
for i in range(len(x)):
x[i] = i
x2[i] = i-0.1+0.2*random.random()
diff --git a/src/examples/test_text_panel.py b/src/examples/test_text_panel.py
index 7d97c53..3dc4e29 100755
--- a/src/examples/test_text_panel.py
+++ b/src/examples/test_text_panel.py
@@ -1,105 +1,105 @@
-"""
-Test application that uses plottools
-
-An application required by the REFL group and mainly test the Chisq class.
-
-The following is a checklist of functionality to look for while testing:
-1- Start the application:
- the graph should have theory curve, experimental data, chisq
- with a white background.
-
-2- Hovering over any plotted data will highlight the whole data set
- or line in yellow.
-
-3- Left-clicking on the graph and dragging will drag the graph.
-
-4- Using the mouse wheel will zoom in and out of the graph.
-
-5- Right-clicking on the graph when no curve is highlighted will
- pop up the context menu:
- - 'Save image' will pop up a save dialog to save an image.
- - 'Reset graph' will reset the graph to its original appearance after it
- has been dragged around or zoomed in or out.
- - 'Change scale' will pop up a scale dialog with which the axes can
- be transformed. Each transformation choice should work.
-
-"""
-
-import wx
-from sas.sasgui.plottools.PlotPanel import PlotPanel
-from sas.sasgui.plottools.plottables import Text, Graph
-
-class TestPlotPanel(PlotPanel):
-
- def __init__(self, parent, id = -1,
- color = None,
- dpi = None,
- **kwargs):
- PlotPanel.__init__(self, parent, id=id, color=color,
- dpi=dpi, **kwargs)
-
- # Keep track of the parent Frame
- self.parent = parent
-
- # Internal list of plottable names (because graph
- # doesn't have a dictionary of handles for the plottables)
- self.plots = {}
-
-
- def onContextMenu(self, event):
- """
- Default context menu for a plot panel
- """
- # Slicer plot popup menu
- id = wx.NewId()
- _menu = wx.Menu()
- _menu.Append(id,'&Save image', 'Save image as PNG')
- wx.EVT_MENU(self, id, self.onSaveImage)
-
- _menu.AppendSeparator()
- id = wx.NewId()
- _menu.Append(id, '&Change scale')
- wx.EVT_MENU(self, id, self._onProperties)
-
- id = wx.NewId()
- _menu.Append(id, '&Reset Graph')
- wx.EVT_MENU(self, id, self.onResetGraph)
-
- pos = event.GetPosition()
- pos = self.ScreenToClient(pos)
- self.PopupMenu(slicerpop, pos)
-
-
-# ---------------------------------------------------------------
-def sample_graph():
- # Construct a simple graph
-
- T1 = Text(text='text example 1', xpos=0.2, ypos=0.2)
- T2 = Text(text='text example 2', xpos=0.5, ypos=0.5)
- T3 = Text(text=r'$\chi^2=1.2$', xpos=0.8, ypos=0.8)
-
- graph = Graph()
- graph.title( 'Test Text Class' )
- graph.add( T1 )
- graph.add( T2 )
- graph.add( T3 )
- return graph
-
-
-def demo_plotter(graph):
- # Make a frame to show it
- app = wx.PySimpleApp()
- frame = wx.Frame(None,-1,'Plottables')
- plotter = TestPlotPanel(frame)
- frame.Show()
-
- # render the graph to the pylab plotter
- graph.render(plotter)
-
- app.MainLoop()
-
-
-if __name__ == "__main__":
- demo_plotter(sample_graph())
-
-
+"""
+Test application that uses plottools
+
+An application required by the REFL group and mainly test the Chisq class.
+
+The following is a checklist of functionality to look for while testing:
+1- Start the application:
+ the graph should have theory curve, experimental data, chisq
+ with a white background.
+
+2- Hovering over any plotted data will highlight the whole data set
+ or line in yellow.
+
+3- Left-clicking on the graph and dragging will drag the graph.
+
+4- Using the mouse wheel will zoom in and out of the graph.
+
+5- Right-clicking on the graph when no curve is highlighted will
+ pop up the context menu:
+ - 'Save image' will pop up a save dialog to save an image.
+ - 'Reset graph' will reset the graph to its original appearance after it
+ has been dragged around or zoomed in or out.
+ - 'Change scale' will pop up a scale dialog with which the axes can
+ be transformed. Each transformation choice should work.
+
+"""
+
+import wx
+from sas.sasgui.plottools.PlotPanel import PlotPanel
+from sas.sasgui.plottools.plottables import Text, Graph
+
+class TestPlotPanel(PlotPanel):
+
+ def __init__(self, parent, id = -1,
+ color = None,
+ dpi = None,
+ **kwargs):
+ PlotPanel.__init__(self, parent, id=id, color=color,
+ dpi=dpi, **kwargs)
+
+ # Keep track of the parent Frame
+ self.parent = parent
+
+ # Internal list of plottable names (because graph
+ # doesn't have a dictionary of handles for the plottables)
+ self.plots = {}
+
+
+ def onContextMenu(self, event):
+ """
+ Default context menu for a plot panel
+ """
+ # Slicer plot popup menu
+ id = wx.NewId()
+ _menu = wx.Menu()
+ _menu.Append(id,'&Save image', 'Save image as PNG')
+ wx.EVT_MENU(self, id, self.onSaveImage)
+
+ _menu.AppendSeparator()
+ id = wx.NewId()
+ _menu.Append(id, '&Change scale')
+ wx.EVT_MENU(self, id, self._onProperties)
+
+ id = wx.NewId()
+ _menu.Append(id, '&Reset Graph')
+ wx.EVT_MENU(self, id, self.onResetGraph)
+
+ pos = event.GetPosition()
+ pos = self.ScreenToClient(pos)
+ self.PopupMenu(slicerpop, pos)
+
+
+# ---------------------------------------------------------------
+def sample_graph():
+ # Construct a simple graph
+
+ T1 = Text(text='text example 1', xpos=0.2, ypos=0.2)
+ T2 = Text(text='text example 2', xpos=0.5, ypos=0.5)
+ T3 = Text(text=r'$\chi^2=1.2$', xpos=0.8, ypos=0.8)
+
+ graph = Graph()
+ graph.title( 'Test Text Class' )
+ graph.add( T1 )
+ graph.add( T2 )
+ graph.add( T3 )
+ return graph
+
+
+def demo_plotter(graph):
+ # Make a frame to show it
+ app = wx.PySimpleApp()
+ frame = wx.Frame(None,-1,'Plottables')
+ plotter = TestPlotPanel(frame)
+ frame.Show()
+
+ # render the graph to the pylab plotter
+ graph.render(plotter)
+
+ app.MainLoop()
+
+
+if __name__ == "__main__":
+ demo_plotter(sample_graph())
+
+
diff --git a/src/sas/__init__.py b/src/sas/__init__.py
index e69de29..261f1cf 100644
--- a/src/sas/__init__.py
+++ b/src/sas/__init__.py
@@ -0,0 +1,57 @@
+__all__ = ['get_app_dir', 'get_user_dir',
+ 'get_local_config', 'get_custom_config']
+
+_APP_DIR = None
+def get_app_dir():
+ """
+ The directory where the sasview application is found.
+
+ Returns the path to sasview if running in place or installed with setup.
+ If the application is frozen, returns the parent directory of the
+ application resources such as test files and images.
+ """
+ global _APP_DIR
+ if not _APP_DIR:
+ from ._config import find_app_dir
+ _APP_DIR = find_app_dir()
+ return _APP_DIR
+
+_USER_DIR = None
+def get_user_dir():
+ """
+ The directory where the per-user configuration is stored.
+
+ Returns ~/.sasview, creating it if it does not already exist.
+ """
+ global _USER_DIR
+ if not _USER_DIR:
+ from ._config import make_user_dir
+ _USER_DIR = make_user_dir()
+ return _USER_DIR
+
+def make_custom_config_path():
+ from ._config import make_custom_config_path as _make_path
+ return _make_path(get_user_dir())
+
+_CUSTOM_CONFIG = None
+def get_custom_config():
+ """
+ Setup the custom config dir and cat file
+ """
+ global _CUSTOM_CONFIG
+ if not _CUSTOM_CONFIG:
+ from ._config import setup_custom_config
+ _CUSTOM_CONFIG = setup_custom_config(get_app_dir(), get_user_dir())
+ return _CUSTOM_CONFIG
+
+
+_LOCAL_CONFIG = None
+def get_local_config():
+ """
+ Loads the local config file.
+ """
+ global _LOCAL_CONFIG
+ if not _LOCAL_CONFIG:
+ from ._config import load_local_config
+ _LOCAL_CONFIG = load_local_config(get_app_dir())
+ return _LOCAL_CONFIG
diff --git a/src/sas/_config.py b/src/sas/_config.py
new file mode 100644
index 0000000..ece08fd
--- /dev/null
+++ b/src/sas/_config.py
@@ -0,0 +1,119 @@
+# Setup and find Custom config dir
+from __future__ import print_function
+
+import sys
+import os
+from os.path import exists, expanduser, dirname, realpath, join as joinpath
+import logging
+import shutil
+
+from sasmodels.custom import load_module_from_path
+
+logger = logging.getLogger(__name__)
+
+def dirn(path, n):
+ """
+ Return the directory n up from the current path
+ """
+ path = realpath(path)
+ for _ in range(n):
+ path = dirname(path)
+ return path
+
+def find_app_dir():
+ """
+ Locate the parent directory of the sasview resources. For the normal
+ application this will be the directory containing sasview.py. For the
+ frozen application this will be the path where the resources are installed.
+ """
+ # We are starting out with the following info:
+ # __file__ = .../sas/__init__.pyc
+ # Check if the path .../sas/sasview exists, and use it as the
+ # app directory. This will only be the case if the app is not frozen.
+ path = joinpath(dirname(__file__), 'sasview')
+ if exists(path):
+ return path
+
+ # If we are running frozen, then root is a parent directory
+ if sys.platform == 'darwin':
+ # Here is the path to the file on the mac:
+ # .../Sasview.app/Contents/Resources/lib/python2.7/site-packages.zip/sas/__init__.pyc
+ # We want the path to the Resources directory.
+ path = dirn(__file__, 5)
+ elif os.name == 'nt':
+ # Here is the path to the file on windows:
+ # ../Sasview/library.zip/sas/__init__.pyc
+ # We want the path to the Sasview directory.
+ path = dirn(__file__, 3)
+ else:
+ raise RuntimeError("Couldn't find the app directory")
+ return path
+
+def make_user_dir():
+ """
+ Create the user directory ~/.sasview if it doesn't already exist.
+ """
+ path = joinpath(expanduser("~"),'.sasview')
+ if not exists(path):
+ os.mkdir(path)
+ return path
+
+def load_local_config(app_dir):
+ logger = logging.getLogger(__name__)
+ filename = 'local_config.py'
+ path = os.path.join(app_dir, filename)
+ try:
+ module = load_module_from_path('sas.local_config', path)
+ logger.info("GuiManager loaded %s", path)
+ return module
+ except Exception as exc:
+ logger.critical("Error loading %s: %s", path, exc)
+ sys.exit()
+
+def make_custom_config_path(user_dir):
+ """
+ The location of the cusstom config file.
+
+ Returns ~/.sasview/config/custom_config.py
+ """
+ dirname = os.path.join(user_dir, 'config')
+ # If the directory doesn't exist, create it
+ if not os.path.exists(dirname):
+ os.makedirs(dirname)
+ path = os.path.join(dirname, "custom_config.py")
+ return path
+
+def setup_custom_config(app_dir, user_dir):
+ path = make_custom_config_path(user_dir)
+ if not os.path.isfile(path):
+ try:
+ # if the custom config file does not exist, copy the default from
+ # the app dir
+ shutil.copyfile(os.path.join(app_dir, "custom_config.py"), path)
+ except Exception:
+ logger.error("Could not copy default custom config.")
+
+ #Adding SAS_OPENCL if it doesn't exist in the config file
+ # - to support backcompability
+ if not "SAS_OPENCL" in open(path).read():
+ try:
+ open(config_file, "a+").write("SAS_OPENCL = \"None\"\n")
+ except Exception:
+ logger.error("Could not update custom config with SAS_OPENCL.")
+
+ custom_config = load_custom_config(path)
+ return custom_config
+
+
+def load_custom_config(path):
+ if os.path.exists(path):
+ try:
+ module = load_module_from_path('sas.custom_config', path)
+ logger.info("GuiManager loaded %s", path)
+ return module
+ except Exception as exc:
+ logger.error("Error loading %s: %s", path, exc)
+
+ from sas.sasview import custom_config
+ logger.info("GuiManager custom_config defaults to sas.sasview.custom_config")
+ return custom_config
\ No newline at end of file
diff --git a/src/sas/logger_config.py b/src/sas/logger_config.py
new file mode 100644
index 0000000..22fe7bb
--- /dev/null
+++ b/src/sas/logger_config.py
@@ -0,0 +1,84 @@
+from __future__ import print_function
+
+import logging
+import logging.config
+import os
+import os.path
+
+
+'''
+Module that manages the global logging
+'''
+
+
+class SetupLogger(object):
+ '''
+ Called at the beginning of run.py or sasview.py
+ '''
+
+ def __init__(self, logger_name):
+ self._find_config_file()
+ self.name = logger_name
+
+ def config_production(self):
+ logger = logging.getLogger(self.name)
+ if not logger.root.handlers:
+ self._read_config_file()
+ logging.captureWarnings(True)
+ logger = logging.getLogger(self.name)
+ return logger
+
+ def config_development(self):
+ '''
+ '''
+ self._read_config_file()
+ logger = logging.getLogger(self.name)
+ self._update_all_logs_to_debug(logger)
+ logging.captureWarnings(True)
+ return logger
+
+ def _read_config_file(self):
+ if self.config_file is not None:
+ logging.config.fileConfig(self.config_file)
+
+ def _update_all_logs_to_debug(self, logger):
+ '''
+ This updates all loggers and respective handlers to DEBUG
+ '''
+ for handler in logger.handlers or logger.parent.handlers:
+ handler.setLevel(logging.DEBUG)
+ for name, _ in logging.Logger.manager.loggerDict.items():
+ logging.getLogger(name).setLevel(logging.DEBUG)
+
+ def _find_config_file(self, filename="logging.ini"):
+ '''
+ The config file is in:
+ Debug ./sasview/
+ Packaging: sas/sasview/
+ Packaging / production does not work well with absolute paths
+ thus the multiple paths below
+ '''
+ places_to_look_for_conf_file = [
+ os.path.join(os.path.abspath(os.path.dirname(__file__)), filename),
+ filename,
+ os.path.join("sas", "sasview", filename),
+ os.path.join(os.getcwd(), "sas", "sasview", filename),
+ ]
+
+ # To avoid the exception in OSx
+ # NotImplementedError: resource_filename() only supported for .egg, not .zip
+ try:
+ import pkg_resources
+ places_to_look_for_conf_file.append(
+ pkg_resources.resource_filename(__name__, filename))
+ except ImportError:
+ pass
+ except NotImplementedError:
+ pass
+
+ for filepath in places_to_look_for_conf_file:
+ if os.path.exists(filepath):
+ self.config_file = filepath
+ return
+ print("ERROR: Logging.ini not found...")
+ self.config_file = None
diff --git a/src/sas/logging.ini b/src/sas/logging.ini
new file mode 100644
index 0000000..9a98225
--- /dev/null
+++ b/src/sas/logging.ini
@@ -0,0 +1,73 @@
+
+###############################################################################
+################################### LOGGING ###################################
+###############################################################################
+# Main logger for SASView
+
+# SEE: https://docs.python.org/2/library/logging.html#logrecord-attributes
+[formatters]
+keys=simple,detailed
+
+[formatter_simple]
+#format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
+#format=%(asctime)s - %(levelname)s : %(name)s:%(pathname)s:%(lineno)4d: %(message)s
+format=%(asctime)s - %(levelname)s : %(name)s:%(lineno)4d: %(message)s
+datefmt=%H:%M:%S
+
+[formatter_detailed]
+#format=%(asctime)s : %(levelname)s : %(name)s: %(lineno)d: %(message)s
+format=%(asctime)s : %(levelname)s : %(name)s (%(filename)s:%(lineno)s) :: %(message)s
+
+###############################################################################
+# Handlers
+
+[handlers]
+keys=console,log_file
+
+[handler_console]
+class=logging.StreamHandler
+formatter=simple
+level=WARNING
+args=tuple()
+
+[handler_log_file]
+class=logging.FileHandler
+level=DEBUG
+formatter=detailed
+args=(os.path.join(os.path.expanduser("~"),'sasview.log'),"a")
+
+###############################################################################
+# Loggers
+
+[loggers]
+keys=root,saspr,sasgui,sascalc,sasmodels
+
+[logger_root]
+level=DEBUG
+formatter=default
+handlers=console,log_file
+
+[logger_sasmodels]
+level=INFO
+qualname=sas.models
+handlers=console,log_file
+propagate=0
+
+[logger_saspr]
+level=INFO
+qualname=sas.pr
+handlers=console,log_file
+propagate=0
+
+[logger_sasgui]
+level=DEBUG
+qualname=sas.sasgui
+handlers=console,log_file
+propagate=0
+
+[logger_sascalc]
+level=INFO
+qualname=sas.sascalc
+handlers=console,log_file
+propagate=0
+
diff --git a/src/sas/sascalc/calculator/BaseComponent.py b/src/sas/sascalc/calculator/BaseComponent.py
index c34fd7b..62ffe3e 100644
--- a/src/sas/sascalc/calculator/BaseComponent.py
+++ b/src/sas/sascalc/calculator/BaseComponent.py
@@ -8,7 +8,7 @@ Provide base functionality for all model components
import copy
from collections import OrderedDict
-import numpy
+import numpy as np
#TO DO: that about a way to make the parameter
#is self return if it is fittable or not
@@ -118,7 +118,7 @@ class BaseComponent:
Then get ::
- q = numpy.sqrt(qx_prime^2+qy_prime^2)
+ q = np.sqrt(qx_prime^2+qy_prime^2)
that is a qr in 1D array; ::
@@ -142,16 +142,16 @@ class BaseComponent:
qdist[0].__class__.__name__ != 'ndarray' or \
qdist[1].__class__.__name__ != 'ndarray':
msg = "evalDistribution expects a list of 2 ndarrays"
- raise RuntimeError, msg
+ raise RuntimeError(msg)
# Extract qx and qy for code clarity
qx = qdist[0]
qy = qdist[1]
# calculate q_r component for 2D isotropic
- q = numpy.sqrt(qx**2+qy**2)
+ q = np.sqrt(qx**2+qy**2)
# vectorize the model function runXY
- v_model = numpy.vectorize(self.runXY, otypes=[float])
+ v_model = np.vectorize(self.runXY, otypes=[float])
# calculate the scattering
iq_array = v_model(q)
@@ -159,14 +159,14 @@ class BaseComponent:
elif qdist.__class__.__name__ == 'ndarray':
# We have a simple 1D distribution of q-values
- v_model = numpy.vectorize(self.runXY, otypes=[float])
+ v_model = np.vectorize(self.runXY, otypes=[float])
iq_array = v_model(qdist)
return iq_array
else:
mesg = "evalDistribution is expecting an ndarray of scalar q-values"
mesg += " or a list [qx,qy] where qx,qy are 2D ndarrays."
- raise RuntimeError, mesg
+ raise RuntimeError(mesg)
@@ -227,7 +227,7 @@ class BaseComponent:
self.params[item] = value
return
- raise ValueError, "Model does not contain parameter %s" % name
+ raise ValueError("Model does not contain parameter %s" % name)
def getParam(self, name):
"""
@@ -249,7 +249,7 @@ class BaseComponent:
if item.lower()==name.lower():
return self.params[item]
- raise ValueError, "Model does not contain parameter %s" % name
+ raise ValueError("Model does not contain parameter %s" % name)
def getParamList(self):
"""
@@ -293,22 +293,22 @@ class BaseComponent:
"""
add
"""
- raise ValueError, "Model operation are no longer supported"
+ raise ValueError("Model operation are no longer supported")
def __sub__(self, other):
"""
sub
"""
- raise ValueError, "Model operation are no longer supported"
+ raise ValueError("Model operation are no longer supported")
def __mul__(self, other):
"""
mul
"""
- raise ValueError, "Model operation are no longer supported"
+ raise ValueError("Model operation are no longer supported")
def __div__(self, other):
"""
div
"""
- raise ValueError, "Model operation are no longer supported"
+ raise ValueError("Model operation are no longer supported")
def _ordered_keys(d):
diff --git a/src/sas/sascalc/calculator/c_extensions/sld2i_module.cpp b/src/sas/sascalc/calculator/c_extensions/sld2i_module.cpp
index 15545fb..ea88a41 100644
--- a/src/sas/sascalc/calculator/c_extensions/sld2i_module.cpp
+++ b/src/sas/sascalc/calculator/c_extensions/sld2i_module.cpp
@@ -5,6 +5,14 @@
#include <stdio.h>
#include <sld2i.hh>
+#if PY_MAJOR_VERSION < 3
+typedef void (*PyCapsule_Destructor)(PyObject *);
+typedef void (*PyCObject_Destructor)(void *);
+#define PyCapsule_New(pointer, name, destructor) (PyCObject_FromVoidPtr(pointer, (PyCObject_Destructor)destructor))
+#define PyCapsule_GetPointer(capsule, name) (PyCObject_AsVoidPtr(capsule))
+#endif
+
+
// Utilities
#define INVECTOR(obj,buf,len) \
do { \
@@ -24,8 +32,9 @@
/**
* Delete a GenI object
*/
-void del_sld2i(void *ptr){
- GenI* sld2i = static_cast<GenI *>(ptr);
+void
+del_sld2i(PyObject *obj){
+ GenI* sld2i = static_cast<GenI *>(PyCapsule_GetPointer(obj, "GenI"));
delete sld2i;
return;
}
@@ -70,7 +79,7 @@ PyObject * new_GenI(PyObject *, PyObject *args) {
OUTVECTOR(mz_val_obj, mz_val, n_x);
OUTVECTOR(vol_pix_obj, vol_pix, n_x);
GenI* sld2i = new GenI(n_pix,x_val,y_val,z_val,sldn_val,mx_val,my_val,mz_val,vol_pix,inspin,outspin,stheta);
- return PyCObject_FromVoidPtr(sld2i, del_sld2i);
+ return PyCapsule_New(sld2i, "GenI", del_sld2i);
}
/**
@@ -96,7 +105,7 @@ PyObject * genicom_inputXY(PyObject *, PyObject *args) {
//if(n_in!=n_out) return Py_BuildValue("i",-1);
// Set the array pointers
- void *temp = PyCObject_AsVoidPtr(gen_obj);
+ void *temp = PyCapsule_GetPointer(gen_obj, "GenI");
GenI* s = static_cast<GenI *>(temp);
s->genicomXY(npoints, qx, qy, I_out);
@@ -124,7 +133,7 @@ PyObject * genicom_input(PyObject *, PyObject *args) {
//if(n_in!=n_out) return Py_BuildValue("i",-1);
// Set the array pointers
- void *temp = PyCObject_AsVoidPtr(gen_obj);
+ void *temp = PyCapsule_GetPointer(gen_obj, "GenI");
GenI* s = static_cast<GenI *>(temp);
s->genicom(npoints, q, I_out);
@@ -145,12 +154,49 @@ static PyMethodDef module_methods[] = {
{NULL}
};
+#define MODULE_DOC "Sld2i C Library"
+#define MODULE_NAME "sld2i"
+#define MODULE_INIT2 initsld2i
+#define MODULE_INIT3 PyInit_sld2i
+#define MODULE_METHODS module_methods
+
+/* ==== boilerplate python 2/3 interface bootstrap ==== */
-#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */
-#define PyMODINIT_FUNC void
+
+#if defined(WIN32) && !defined(__MINGW32__)
+ #define DLL_EXPORT __declspec(dllexport)
+#else
+ #define DLL_EXPORT
#endif
-PyMODINIT_FUNC
-initsld2i(void)
-{
- Py_InitModule3("sld2i", module_methods, "Sld2i module");
-}
+
+#if PY_MAJOR_VERSION >= 3
+
+ DLL_EXPORT PyMODINIT_FUNC MODULE_INIT3(void)
+ {
+ static struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT,
+ MODULE_NAME, /* m_name */
+ MODULE_DOC, /* m_doc */
+ -1, /* m_size */
+ MODULE_METHODS, /* m_methods */
+ NULL, /* m_reload */
+ NULL, /* m_traverse */
+ NULL, /* m_clear */
+ NULL, /* m_free */
+ };
+ return PyModule_Create(&moduledef);
+ }
+
+#else /* !PY_MAJOR_VERSION >= 3 */
+
+ DLL_EXPORT PyMODINIT_FUNC MODULE_INIT2(void)
+ {
+ Py_InitModule4(MODULE_NAME,
+ MODULE_METHODS,
+ MODULE_DOC,
+ 0,
+ PYTHON_API_VERSION
+ );
+ }
+
+#endif /* !PY_MAJOR_VERSION >= 3 */
\ No newline at end of file
diff --git a/src/sas/sascalc/calculator/instrument.py b/src/sas/sascalc/calculator/instrument.py
index d26cabf..39201c7 100644
--- a/src/sas/sascalc/calculator/instrument.py
+++ b/src/sas/sascalc/calculator/instrument.py
@@ -2,7 +2,7 @@
This module is a small tool to allow user to
control instrumental parameters
"""
-import numpy
+import numpy as np
# defaults in cgs unit
_SAMPLE_A_SIZE = [1.27]
@@ -167,7 +167,7 @@ class Neutron(object):
# wavelength spectrum
self.spectrum = self.get_default_spectrum()
# intensity in counts/sec
- self.intensity = numpy.interp(self.wavelength,
+ self.intensity = np.interp(self.wavelength,
self.spectrum[0],
self.spectrum[1],
0.0,
@@ -202,7 +202,7 @@ class Neutron(object):
wavelength is already within the spectrum
"""
spectrum = self.spectrum
- intensity = numpy.interp(self.wavelength,
+ intensity = np.interp(self.wavelength,
spectrum[0],
spectrum[1],
0.0,
@@ -221,9 +221,8 @@ class Neutron(object):
:param band: array of [min, max]
"""
# check if the wavelength is in range
- if min(band) < self.min or\
- max(band) > self.max:
- raise
+ if min(band) < self.min or max(band) > self.max:
+ raise ValueError("band out of range")
self.band = band
def set_intensity(self, intensity=368428):
@@ -238,12 +237,11 @@ class Neutron(object):
Sets the wavelength
"""
# check if the wavelength is in range
- if wavelength < min(self.band) or\
- wavelength > max(self.band):
- raise
+ if wavelength < min(self.band) or wavelength > max(self.band):
+ raise ValueError("wavelength out of range")
self.wavelength = wavelength
validate(wavelength)
- self.intensity = numpy.interp(self.wavelength,
+ self.intensity = np.interp(self.wavelength,
self.spectrum[0],
self.spectrum[1],
0.0,
@@ -304,7 +302,7 @@ class Neutron(object):
"""
get default spectrum
"""
- return numpy.array(_LAMBDA_ARRAY)
+ return np.array(_LAMBDA_ARRAY)
def get_band(self):
"""
@@ -323,7 +321,7 @@ class Neutron(object):
plt.legend(['Spectrum'], loc='best')
plt.show()
except:
- raise RuntimeError, "Can't import matplotlib required to plot..."
+ raise RuntimeError("Can't import matplotlib required to plot...")
class TOF(Neutron):
@@ -344,7 +342,7 @@ class TOF(Neutron):
"""
get list of the intensity wrt wavelength_list
"""
- out = numpy.interp(self.wavelength_list,
+ out = np.interp(self.wavelength_list,
self.spectrum[0],
self.spectrum[1],
0.0,
diff --git a/src/sas/sascalc/calculator/kiessig_calculator.py b/src/sas/sascalc/calculator/kiessig_calculator.py
index e44cdb9..026881b 100644
--- a/src/sas/sascalc/calculator/kiessig_calculator.py
+++ b/src/sas/sascalc/calculator/kiessig_calculator.py
@@ -48,7 +48,7 @@ class KiessigThicknessCalculator(object):
except:
return None
# check if delta_q is zero
- if dq == 0.0 or dq == None:
+ if dq == 0.0 or dq is None:
return None
else:
# calculate thickness
diff --git a/src/sas/sascalc/calculator/resolution_calculator.py b/src/sas/sascalc/calculator/resolution_calculator.py
index 5e42445..5acf6cd 100644
--- a/src/sas/sascalc/calculator/resolution_calculator.py
+++ b/src/sas/sascalc/calculator/resolution_calculator.py
@@ -3,18 +3,20 @@ This object is a small tool to allow user to quickly
determine the variance in q from the
instrumental parameters.
"""
-from instrument import Sample
-from instrument import Detector
-from instrument import TOF as Neutron
-from instrument import Aperture
-# import math stuffs
-from math import pi
-from math import sqrt
-import math
-import numpy
import sys
+from math import pi, sqrt
+import math
import logging
+import numpy as np
+
+from .instrument import Sample
+from .instrument import Detector
+from .instrument import TOF as Neutron
+from .instrument import Aperture
+
+logger = logging.getLogger(__name__)
+
#Plank's constant in cgs unit
_PLANK_H = 6.62606896E-27
#Gravitational acc. in cgs unit
@@ -205,7 +207,7 @@ class ResolutionCalculator(object):
if wavelength == 0:
msg = "Can't compute the resolution: the wavelength is zero..."
- raise RuntimeError, msg
+ raise RuntimeError(msg)
return self.intensity
def compute(self, wavelength, wavelength_spread, qx_value, qy_value,
@@ -376,25 +378,25 @@ class ResolutionCalculator(object):
# Check whether the q value is within the detector range
if qx_min < self.qx_min:
self.qx_min = qx_min
- #raise ValueError, msg
+ #raise ValueError(msg)
if qx_max > self.qx_max:
self.qx_max = qx_max
- #raise ValueError, msg
+ #raise ValueError(msg)
if qy_min < self.qy_min:
self.qy_min = qy_min
- #raise ValueError, msg
+ #raise ValueError(msg)
if qy_max > self.qy_max:
self.qy_max = qy_max
- #raise ValueError, msg
+ #raise ValueError(msg)
if not full_cal:
return None
# Make an empty graph in the detector scale
dx_size = (self.qx_max - self.qx_min) / (1000 - 1)
dy_size = (self.qy_max - self.qy_min) / (1000 - 1)
- x_val = numpy.arange(self.qx_min, self.qx_max, dx_size)
- y_val = numpy.arange(self.qy_max, self.qy_min, -dy_size)
- q_1, q_2 = numpy.meshgrid(x_val, y_val)
+ x_val = np.arange(self.qx_min, self.qx_max, dx_size)
+ y_val = np.arange(self.qy_max, self.qy_min, -dy_size)
+ q_1, q_2 = np.meshgrid(x_val, y_val)
#q_phi = numpy.arctan(q_1,q_2)
# check whether polar or cartesian
if coord == 'polar':
@@ -500,7 +502,7 @@ class ResolutionCalculator(object):
y_comp = size[1] * phi_y
# otherwise
else:
- raise ValueError, " Improper input..."
+ raise ValueError(" Improper input...")
# get them squared
sigma = x_comp * x_comp
sigma += y_comp * y_comp
@@ -605,7 +607,7 @@ class ResolutionCalculator(object):
# unit correction (1/cm to 1/A) for A and d_distance below
a_value *= 1.0E-16
# if lamda is give (broad meanning of A) return 2* lamda^2 * A
- if lamda != None:
+ if lamda is not None:
a_value *= (4 * lamda * lamda)
return a_value
@@ -703,7 +705,7 @@ class ResolutionCalculator(object):
self.wave.set_wave_list([wavelength])
#self.set_wavelength(wavelength)
else:
- raise
+ raise TypeError("invalid wavlength---should be list or float")
def set_wave_spread(self, wavelength_spread):
"""
@@ -714,7 +716,7 @@ class ResolutionCalculator(object):
elif wavelength_spread.__class__.__name__ == 'float':
self.wave.set_wave_spread_list([wavelength_spread])
else:
- raise
+ raise TypeError("invalid wavelength spread---should be list or float")
def set_wavelength(self, wavelength):
"""
@@ -763,7 +765,7 @@ class ResolutionCalculator(object):
: param size: [dia_value] or [x_value, y_value]
"""
if len(size) < 1 or len(size) > 2:
- raise RuntimeError, "The length of the size must be one or two."
+ raise RuntimeError("The length of the size must be one or two.")
self.aperture.set_source_size(size)
def set_neutron_mass(self, mass):
@@ -780,7 +782,7 @@ class ResolutionCalculator(object):
: param size: [dia_value] or [xheight_value, yheight_value]
"""
if len(size) < 1 or len(size) > 2:
- raise RuntimeError, "The length of the size must be one or two."
+ raise RuntimeError("The length of the size must be one or two.")
self.aperture.set_sample_size(size)
def set_detector_pix_size(self, size):
@@ -803,7 +805,7 @@ class ResolutionCalculator(object):
: param distance: [distance, x_offset]
"""
if len(distance) < 1 or len(distance) > 2:
- raise RuntimeError, "The length of the size must be one or two."
+ raise RuntimeError("The length of the size must be one or two.")
self.aperture.set_sample_distance(distance)
def set_sample2sample_distance(self, distance):
@@ -813,7 +815,7 @@ class ResolutionCalculator(object):
: param distance: [distance, x_offset]
"""
if len(distance) < 1 or len(distance) > 2:
- raise RuntimeError, "The length of the size must be one or two."
+ raise RuntimeError("The length of the size must be one or two.")
self.sample.set_distance(distance)
def set_sample2detector_distance(self, distance):
@@ -823,7 +825,7 @@ class ResolutionCalculator(object):
: param distance: [distance, x_offset]
"""
if len(distance) < 1 or len(distance) > 2:
- raise RuntimeError, "The length of the size must be one or two."
+ raise RuntimeError("The length of the size must be one or two.")
self.detector.set_distance(distance)
def get_all_instrument_params(self):
@@ -886,14 +888,14 @@ class ResolutionCalculator(object):
# phi values at each points (not at the center)
x_value = x_val - x0_val
y_value = y_val - y0_val
- phi_i = numpy.arctan2(y_val, x_val)
+ phi_i = np.arctan2(y_val, x_val)
# phi correction due to the gravity shift (in phi)
phi_0 = math.atan2(y0_val, x0_val)
phi_i = phi_i - phi_0 + self.gravity_phi
- sin_phi = numpy.sin(self.gravity_phi)
- cos_phi = numpy.cos(self.gravity_phi)
+ sin_phi = np.sin(self.gravity_phi)
+ cos_phi = np.cos(self.gravity_phi)
x_p = x_value * cos_phi + y_value * sin_phi
y_p = -x_value * sin_phi + y_value * cos_phi
@@ -907,7 +909,7 @@ class ResolutionCalculator(object):
nu_value = -0.5 * (new_x * new_x + new_y * new_y)
- gaussian = numpy.exp(nu_value)
+ gaussian = np.exp(nu_value)
# normalizing factor correction
gaussian /= gaussian.sum()
@@ -953,7 +955,7 @@ class ResolutionCalculator(object):
nu_value = (value - mean) / sigma
nu_value *= nu_value
nu_value *= -0.5
- gaussian *= numpy.exp(nu_value)
+ gaussian *= np.exp(nu_value)
gaussian /= sigma
# normalize
gaussian /= sqrt(2 * pi)
@@ -995,7 +997,7 @@ class ResolutionCalculator(object):
pix_x_size = detector_pix_size[0]
pix_y_size = detector_pix_size[1]
else:
- raise ValueError, " Input value format error..."
+ raise ValueError(" Input value format error...")
# Sample to detector distance = sample slit to detector
# minus sample offset
sample2detector_distance = self.sample2detector_distance[0] - \
@@ -1005,7 +1007,7 @@ class ResolutionCalculator(object):
try:
detector_offset = self.sample2detector_distance[1]
except:
- logging.error(sys.exc_value)
+ logger.error(sys.exc_value)
# detector size in [no of pix_x,no of pix_y]
detector_pix_nums_x = self.detector_size[0]
@@ -1025,8 +1027,8 @@ class ResolutionCalculator(object):
detector_pix_nums_y,
offset_x, offset_y)
# distance [cm] from the beam center on detector plane
- detector_ind_x = numpy.arange(detector_pix_nums_x)
- detector_ind_y = numpy.arange(detector_pix_nums_y)
+ detector_ind_x = np.arange(detector_pix_nums_x)
+ detector_ind_y = np.arange(detector_pix_nums_y)
# shif 0.5 pixel so that pix position is at the center of the pixel
detector_ind_x = detector_ind_x + 0.5
@@ -1040,8 +1042,8 @@ class ResolutionCalculator(object):
detector_ind_x = detector_ind_x * pix_x_size
detector_ind_y = detector_ind_y * pix_y_size
- qx_value = numpy.zeros(len(detector_ind_x))
- qy_value = numpy.zeros(len(detector_ind_y))
+ qx_value = np.zeros(len(detector_ind_x))
+ qy_value = np.zeros(len(detector_ind_y))
i = 0
for indx in detector_ind_x:
@@ -1060,10 +1062,10 @@ class ResolutionCalculator(object):
qy_value = qy_value.transpose()
# p min and max values among the center of pixels
- self.qx_min = numpy.min(qx_value)
- self.qx_max = numpy.max(qx_value)
- self.qy_min = numpy.min(qy_value)
- self.qy_max = numpy.max(qy_value)
+ self.qx_min = np.min(qx_value)
+ self.qx_max = np.max(qx_value)
+ self.qy_min = np.min(qy_value)
+ self.qy_max = np.max(qy_value)
# Appr. min and max values of the detector display limits
# i.e., edges of the last pixels.
@@ -1087,12 +1089,12 @@ class ResolutionCalculator(object):
try:
from sas.sascalc.dataloader.data_info import Data2D
output = Data2D()
- inten = numpy.zeros_like(qx_value)
+ inten = np.zeros_like(qx_value)
output.data = inten
output.qx_data = qx_value
output.qy_data = qy_value
except:
- logging.error(sys.exc_value)
+ logger.error(sys.exc_value)
return output
@@ -1106,8 +1108,8 @@ class ResolutionCalculator(object):
# Distance from beam center in the plane of detector
plane_dist = dx_size
# full scattering angle on the x-axis
- theta = numpy.arctan(plane_dist / det_dist)
- qx_value = (2.0 * pi / wavelength) * numpy.sin(theta)
+ theta = np.arctan(plane_dist / det_dist)
+ qx_value = (2.0 * pi / wavelength) * np.sin(theta)
return qx_value
def _get_polar_value(self, qx_value, qy_value):
diff --git a/src/sas/sascalc/calculator/sas_gen.py b/src/sas/sascalc/calculator/sas_gen.py
index 01350de..3557a63 100644
--- a/src/sas/sascalc/calculator/sas_gen.py
+++ b/src/sas/sascalc/calculator/sas_gen.py
@@ -2,16 +2,29 @@
"""
SAS generic computation and sld file readers
"""
-import sas.sascalc.calculator.core.sld2i as mod
-from sas.sascalc.calculator.BaseComponent import BaseComponent
-from periodictable import formula
-from periodictable import nsf
-import numpy
+from __future__ import print_function
+
import os
-import copy
import sys
+import copy
import logging
+from periodictable import formula
+from periodictable import nsf
+import numpy as np
+
+from .core import sld2i as mod
+from .BaseComponent import BaseComponent
+
+logger = logging.getLogger(__name__)
+
+if sys.version_info[0] < 3:
+ def decode(s):
+ return s
+else:
+ def decode(s):
+ return s.decode() if isinstance(s, bytes) else s
+
MFACTOR_AM = 2.853E-12
MFACTOR_MT = 2.3164E-9
METER2ANG = 1.0E+10
@@ -29,7 +42,7 @@ def mag2sld(mag, v_unit=None):
elif v_unit == "mT":
factor = MFACTOR_MT
else:
- raise ValueError, "Invalid valueunit"
+ raise ValueError("Invalid valueunit")
sld_m = factor * mag
return sld_m
@@ -79,13 +92,13 @@ class GenSAS(BaseComponent):
self.description = 'GenSAS'
## Parameter details [units, min, max]
self.details = {}
- self.details['scale'] = ['', 0.0, numpy.inf]
- self.details['background'] = ['[1/cm]', 0.0, numpy.inf]
- self.details['solvent_SLD'] = ['1/A^(2)', -numpy.inf, numpy.inf]
- self.details['total_volume'] = ['A^(3)', 0.0, numpy.inf]
+ self.details['scale'] = ['', 0.0, np.inf]
+ self.details['background'] = ['[1/cm]', 0.0, np.inf]
+ self.details['solvent_SLD'] = ['1/A^(2)', -np.inf, np.inf]
+ self.details['total_volume'] = ['A^(3)', 0.0, np.inf]
self.details['Up_frac_in'] = ['[u/(u+d)]', 0.0, 1.0]
self.details['Up_frac_out'] = ['[u/(u+d)]', 0.0, 1.0]
- self.details['Up_theta'] = ['[deg]', -numpy.inf, numpy.inf]
+ self.details['Up_theta'] = ['[deg]', -np.inf, np.inf]
# fixed parameters
self.fixed = []
@@ -94,8 +107,8 @@ class GenSAS(BaseComponent):
Set the volume of a pixel in (A^3) unit
:Param volume: pixel volume [float]
"""
- if self.data_vol == None:
- raise
+ if self.data_vol is None:
+ raise TypeError("data_vol is missing")
self.data_vol = volume
def set_is_avg(self, is_avg=False):
@@ -116,7 +129,7 @@ class GenSAS(BaseComponent):
pos_y = self.data_y
pos_z = self.data_z
len_x = len(pos_x)
- if self.is_avg == None:
+ if self.is_avg is None:
len_x *= -1
pos_x, pos_y, pos_z = transform_center(pos_x, pos_y, pos_z)
len_q = len(x)
@@ -169,14 +182,14 @@ class GenSAS(BaseComponent):
if x.__class__.__name__ == 'list':
if len(x[1]) > 0:
msg = "Not a 1D."
- raise ValueError, msg
- i_out = numpy.zeros_like(x[0])
+ raise ValueError(msg)
+ i_out = np.zeros_like(x[0])
# 1D I is found at y =0 in the 2D pattern
out = self._gen(x[0], [], i_out)
return out
else:
msg = "Q must be given as list of qx's and qy's"
- raise ValueError, msg
+ raise ValueError(msg)
def runXY(self, x=0.0):
"""
@@ -186,12 +199,12 @@ class GenSAS(BaseComponent):
:Use this runXY() for the computation
"""
if x.__class__.__name__ == 'list':
- i_out = numpy.zeros_like(x[0])
+ i_out = np.zeros_like(x[0])
out = self._gen(x[0], x[1], i_out)
return out
else:
msg = "Q must be given as list of qx's and qy's"
- raise ValueError, msg
+ raise ValueError(msg)
def evalDistribution(self, qdist):
"""
@@ -209,7 +222,7 @@ class GenSAS(BaseComponent):
else:
mesg = "evalDistribution is expecting an ndarray of "
mesg += "a list [qx,qy] where qx,qy are arrays."
- raise RuntimeError, mesg
+ raise RuntimeError(mesg)
class OMF2SLD(object):
"""
@@ -236,34 +249,34 @@ class OMF2SLD(object):
"""
self.omfdata = omfdata
length = int(omfdata.xnodes * omfdata.ynodes * omfdata.znodes)
- pos_x = numpy.arange(omfdata.xmin,
+ pos_x = np.arange(omfdata.xmin,
omfdata.xnodes*omfdata.xstepsize + omfdata.xmin,
omfdata.xstepsize)
- pos_y = numpy.arange(omfdata.ymin,
+ pos_y = np.arange(omfdata.ymin,
omfdata.ynodes*omfdata.ystepsize + omfdata.ymin,
omfdata.ystepsize)
- pos_z = numpy.arange(omfdata.zmin,
+ pos_z = np.arange(omfdata.zmin,
omfdata.znodes*omfdata.zstepsize + omfdata.zmin,
omfdata.zstepsize)
- self.pos_x = numpy.tile(pos_x, int(omfdata.ynodes * omfdata.znodes))
+ self.pos_x = np.tile(pos_x, int(omfdata.ynodes * omfdata.znodes))
self.pos_y = pos_y.repeat(int(omfdata.xnodes))
- self.pos_y = numpy.tile(self.pos_y, int(omfdata.znodes))
+ self.pos_y = np.tile(self.pos_y, int(omfdata.znodes))
self.pos_z = pos_z.repeat(int(omfdata.xnodes * omfdata.ynodes))
self.mx = omfdata.mx
self.my = omfdata.my
self.mz = omfdata.mz
- self.sld_n = numpy.zeros(length)
+ self.sld_n = np.zeros(length)
- if omfdata.mx == None:
- self.mx = numpy.zeros(length)
- if omfdata.my == None:
- self.my = numpy.zeros(length)
- if omfdata.mz == None:
- self.mz = numpy.zeros(length)
+ if omfdata.mx is None:
+ self.mx = np.zeros(length)
+ if omfdata.my is None:
+ self.my = np.zeros(length)
+ if omfdata.mz is None:
+ self.mz = np.zeros(length)
self._check_data_length(length)
self.remove_null_points(False, False)
- mask = numpy.ones(len(self.sld_n), dtype=bool)
+ mask = np.ones(len(self.sld_n), dtype=bool)
if shape.lower() == 'ellipsoid':
try:
# Pixel (step) size included
@@ -283,8 +296,8 @@ class OMF2SLD(object):
z_dir2 = ((self.pos_z - z_c / 2.0) / z_r)
z_dir2 *= z_dir2
mask = (x_dir2 + y_dir2 + z_dir2) <= 1.0
- except:
- logging.error(sys.exc_value)
+ except Exception:
+ logger.error(sys.exc_value)
self.output = MagSLD(self.pos_x[mask], self.pos_y[mask],
self.pos_z[mask], self.sld_n[mask],
self.mx[mask], self.my[mask], self.mz[mask])
@@ -308,27 +321,17 @@ class OMF2SLD(object):
Check if the data lengths are consistent
:Params length: data length
"""
- msg = "Error: Inconsistent data length."
- if len(self.pos_x) != length:
- raise ValueError, msg
- if len(self.pos_y) != length:
- raise ValueError, msg
- if len(self.pos_z) != length:
- raise ValueError, msg
- if len(self.mx) != length:
- raise ValueError, msg
- if len(self.my) != length:
- raise ValueError, msg
- if len(self.mz) != length:
- raise ValueError, msg
+ parts = (self.pos_x, self.pos_y, self.pos_z, self.mx, self.my, self.mz)
+ if any(len(v) != length for v in parts):
+ raise ValueError("Error: Inconsistent data length.")
def remove_null_points(self, remove=False, recenter=False):
"""
Removes any mx, my, and mz = 0 points
"""
if remove:
- is_nonzero = (numpy.fabs(self.mx) + numpy.fabs(self.my) +
- numpy.fabs(self.mz)).nonzero()
+ is_nonzero = (np.fabs(self.mx) + np.fabs(self.my) +
+ np.fabs(self.mz)).nonzero()
if len(is_nonzero[0]) > 0:
self.pos_x = self.pos_x[is_nonzero]
self.pos_y = self.pos_y[is_nonzero]
@@ -368,32 +371,34 @@ class OMFReader(object):
:return: x, y, z, sld_n, sld_mx, sld_my, sld_mz
"""
desc = ""
- mx = numpy.zeros(0)
- my = numpy.zeros(0)
- mz = numpy.zeros(0)
+ mx = np.zeros(0)
+ my = np.zeros(0)
+ mz = np.zeros(0)
try:
input_f = open(path, 'rb')
- buff = input_f.read()
+ buff = decode(input_f.read())
lines = buff.split('\n')
input_f.close()
output = OMFData()
valueunit = None
for line in lines:
- toks = line.split()
+ line = line.strip()
# Read data
- try:
- _mx = float(toks[0])
- _my = float(toks[1])
- _mz = float(toks[2])
- _mx = mag2sld(_mx, valueunit)
- _my = mag2sld(_my, valueunit)
- _mz = mag2sld(_mz, valueunit)
- mx = numpy.append(mx, _mx)
- my = numpy.append(my, _my)
- mz = numpy.append(mz, _mz)
- except:
- # Skip non-data lines
- logging.error(sys.exc_value)
+ if line and not line.startswith('#'):
+ try:
+ toks = line.split()
+ _mx = float(toks[0])
+ _my = float(toks[1])
+ _mz = float(toks[2])
+ _mx = mag2sld(_mx, valueunit)
+ _my = mag2sld(_my, valueunit)
+ _mz = mag2sld(_mz, valueunit)
+ mx = np.append(mx, _mx)
+ my = np.append(my, _my)
+ mz = np.append(mz, _mz)
+ except Exception as exc:
+ # Skip non-data lines
+ logger.error(str(exc)+" when processing %r"%line)
#Reading Header; Segment count ignored
s_line = line.split(":", 1)
if s_line[0].lower().count("oommf") > 0:
@@ -410,7 +415,7 @@ class OMFReader(object):
if meshunit.count("m") < 1:
msg = "Error: \n"
msg += "We accept only m as meshunit"
- raise ValueError, msg
+ raise ValueError(msg)
if s_line[0].lower().count("xbase") > 0:
xbase = s_line[1].lstrip()
if s_line[0].lower().count("ybase") > 0:
@@ -477,10 +482,10 @@ class OMFReader(object):
valueunit)
output.set_m(mx, my, mz)
return output
- except:
+ except Exception:
msg = "%s is not supported: \n" % path
msg += "We accept only Text format OMF file."
- raise RuntimeError, msg
+ raise RuntimeError(msg)
class PDBReader(object):
"""
@@ -500,15 +505,15 @@ class PDBReader(object):
:return: MagSLD
:raise RuntimeError: when the file can't be opened
"""
- pos_x = numpy.zeros(0)
- pos_y = numpy.zeros(0)
- pos_z = numpy.zeros(0)
- sld_n = numpy.zeros(0)
- sld_mx = numpy.zeros(0)
- sld_my = numpy.zeros(0)
- sld_mz = numpy.zeros(0)
- vol_pix = numpy.zeros(0)
- pix_symbol = numpy.zeros(0)
+ pos_x = np.zeros(0)
+ pos_y = np.zeros(0)
+ pos_z = np.zeros(0)
+ sld_n = np.zeros(0)
+ sld_mx = np.zeros(0)
+ sld_my = np.zeros(0)
+ sld_mz = np.zeros(0)
+ vol_pix = np.zeros(0)
+ pix_symbol = np.zeros(0)
x_line = []
y_line = []
z_line = []
@@ -517,7 +522,7 @@ class PDBReader(object):
z_lines = []
try:
input_f = open(path, 'rb')
- buff = input_f.read()
+ buff = decode(input_f.read())
lines = buff.split('\n')
input_f.close()
num = 0
@@ -531,7 +536,7 @@ class PDBReader(object):
try:
float(line[12])
atom_name = atom_name[1].upper()
- except:
+ except Exception:
if len(atom_name) == 4:
atom_name = atom_name[0].upper()
elif line[12] != ' ':
@@ -542,25 +547,25 @@ class PDBReader(object):
_pos_x = float(line[30:38].strip())
_pos_y = float(line[38:46].strip())
_pos_z = float(line[46:54].strip())
- pos_x = numpy.append(pos_x, _pos_x)
- pos_y = numpy.append(pos_y, _pos_y)
- pos_z = numpy.append(pos_z, _pos_z)
+ pos_x = np.append(pos_x, _pos_x)
+ pos_y = np.append(pos_y, _pos_y)
+ pos_z = np.append(pos_z, _pos_z)
try:
val = nsf.neutron_sld(atom_name)[0]
# sld in Ang^-2 unit
val *= 1.0e-6
- sld_n = numpy.append(sld_n, val)
+ sld_n = np.append(sld_n, val)
atom = formula(atom_name)
# cm to A units
vol = 1.0e+24 * atom.mass / atom.density / NA
- vol_pix = numpy.append(vol_pix, vol)
- except:
- print "Error: set the sld of %s to zero"% atom_name
- sld_n = numpy.append(sld_n, 0.0)
- sld_mx = numpy.append(sld_mx, 0)
- sld_my = numpy.append(sld_my, 0)
- sld_mz = numpy.append(sld_mz, 0)
- pix_symbol = numpy.append(pix_symbol, atom_name)
+ vol_pix = np.append(vol_pix, vol)
+ except Exception:
+ logger.error("Error: set the sld of %s to zero"% atom_name)
+ sld_n = np.append(sld_n, 0.0)
+ sld_mx = np.append(sld_mx, 0)
+ sld_my = np.append(sld_my, 0)
+ sld_mz = np.append(sld_mz, 0)
+ pix_symbol = np.append(pix_symbol, atom_name)
elif line[0:6].strip().count('CONECT') > 0:
toks = line.split()
num = int(toks[1]) - 1
@@ -568,7 +573,7 @@ class PDBReader(object):
for val in toks[2:]:
try:
int_val = int(val)
- except:
+ except Exception:
break
if int_val == 0:
break
@@ -587,8 +592,8 @@ class PDBReader(object):
x_lines.append(x_line)
y_lines.append(y_line)
z_lines.append(z_line)
- except:
- logging.error(sys.exc_value)
+ except Exception:
+ logger.error(sys.exc_value)
output = MagSLD(pos_x, pos_y, pos_z, sld_n, sld_mx, sld_my, sld_mz)
output.set_conect_lines(x_line, y_line, z_line)
@@ -599,14 +604,14 @@ class PDBReader(object):
output.set_pixel_volumes(vol_pix)
output.sld_unit = '1/A^(2)'
return output
- except:
- raise RuntimeError, "%s is not a sld file" % path
+ except Exception:
+ raise RuntimeError("%s is not a sld file" % path)
def write(self, path, data):
"""
Write
"""
- print "Not implemented... "
+ print("Not implemented... ")
class SLDReader(object):
"""
@@ -629,33 +634,33 @@ class SLDReader(object):
:raise ValueError: when the length of the data vectors are inconsistent
"""
try:
- pos_x = numpy.zeros(0)
- pos_y = numpy.zeros(0)
- pos_z = numpy.zeros(0)
- sld_n = numpy.zeros(0)
- sld_mx = numpy.zeros(0)
- sld_my = numpy.zeros(0)
- sld_mz = numpy.zeros(0)
+ pos_x = np.zeros(0)
+ pos_y = np.zeros(0)
+ pos_z = np.zeros(0)
+ sld_n = np.zeros(0)
+ sld_mx = np.zeros(0)
+ sld_my = np.zeros(0)
+ sld_mz = np.zeros(0)
try:
# Use numpy to speed up loading
- input_f = numpy.loadtxt(path, dtype='float', skiprows=1,
+ input_f = np.loadtxt(path, dtype='float', skiprows=1,
ndmin=1, unpack=True)
- pos_x = numpy.array(input_f[0])
- pos_y = numpy.array(input_f[1])
- pos_z = numpy.array(input_f[2])
- sld_n = numpy.array(input_f[3])
- sld_mx = numpy.array(input_f[4])
- sld_my = numpy.array(input_f[5])
- sld_mz = numpy.array(input_f[6])
+ pos_x = np.array(input_f[0])
+ pos_y = np.array(input_f[1])
+ pos_z = np.array(input_f[2])
+ sld_n = np.array(input_f[3])
+ sld_mx = np.array(input_f[4])
+ sld_my = np.array(input_f[5])
+ sld_mz = np.array(input_f[6])
ncols = len(input_f)
if ncols == 8:
- vol_pix = numpy.array(input_f[7])
+ vol_pix = np.array(input_f[7])
elif ncols == 7:
vol_pix = None
- except:
+ except Exception:
# For older version of numpy
input_f = open(path, 'rb')
- buff = input_f.read()
+ buff = decode(input_f.read())
lines = buff.split('\n')
input_f.close()
for line in lines:
@@ -668,31 +673,31 @@ class SLDReader(object):
_sld_mx = float(toks[4])
_sld_my = float(toks[5])
_sld_mz = float(toks[6])
- pos_x = numpy.append(pos_x, _pos_x)
- pos_y = numpy.append(pos_y, _pos_y)
- pos_z = numpy.append(pos_z, _pos_z)
- sld_n = numpy.append(sld_n, _sld_n)
- sld_mx = numpy.append(sld_mx, _sld_mx)
- sld_my = numpy.append(sld_my, _sld_my)
- sld_mz = numpy.append(sld_mz, _sld_mz)
+ pos_x = np.append(pos_x, _pos_x)
+ pos_y = np.append(pos_y, _pos_y)
+ pos_z = np.append(pos_z, _pos_z)
+ sld_n = np.append(sld_n, _sld_n)
+ sld_mx = np.append(sld_mx, _sld_mx)
+ sld_my = np.append(sld_my, _sld_my)
+ sld_mz = np.append(sld_mz, _sld_mz)
try:
_vol_pix = float(toks[7])
- vol_pix = numpy.append(vol_pix, _vol_pix)
- except:
+ vol_pix = np.append(vol_pix, _vol_pix)
+ except Exception:
vol_pix = None
- except:
+ except Exception:
# Skip non-data lines
- logging.error(sys.exc_value)
+ logger.error(sys.exc_value)
output = MagSLD(pos_x, pos_y, pos_z, sld_n,
sld_mx, sld_my, sld_mz)
output.filename = os.path.basename(path)
output.set_pix_type('pixel')
output.set_pixel_symbols('pixel')
- if vol_pix != None:
+ if vol_pix is not None:
output.set_pixel_volumes(vol_pix)
return output
- except:
- raise RuntimeError, "%s is not a sld file" % path
+ except Exception:
+ raise RuntimeError("%s is not a sld file" % path)
def write(self, path, data):
"""
@@ -700,23 +705,23 @@ class SLDReader(object):
:Param path: file path
:Param data: MagSLD data object
"""
- if path == None:
- raise ValueError, "Missing the file path."
- if data == None:
- raise ValueError, "Missing the data to save."
+ if path is None:
+ raise ValueError("Missing the file path.")
+ if data is None:
+ raise ValueError("Missing the data to save.")
x_val = data.pos_x
y_val = data.pos_y
z_val = data.pos_z
vol_pix = data.vol_pix
length = len(x_val)
sld_n = data.sld_n
- if sld_n == None:
- sld_n = numpy.zeros(length)
+ if sld_n is None:
+ sld_n = np.zeros(length)
sld_mx = data.sld_mx
- if sld_mx == None:
- sld_mx = numpy.zeros(length)
- sld_my = numpy.zeros(length)
- sld_mz = numpy.zeros(length)
+ if sld_mx is None:
+ sld_mx = np.zeros(length)
+ sld_my = np.zeros(length)
+ sld_mz = np.zeros(length)
else:
sld_my = data.sld_my
sld_mz = data.sld_mz
@@ -864,7 +869,7 @@ class MagSLD(object):
self.sld_phi = None
self.sld_theta = None
self.pix_symbol = None
- if sld_mx != None and sld_my != None and sld_mz != None:
+ if sld_mx is not None and sld_my is not None and sld_mz is not None:
self.set_sldms(sld_mx, sld_my, sld_mz)
self.set_nodes()
@@ -892,38 +897,38 @@ class MagSLD(object):
if sld_n.__class__.__name__ == 'float':
if self.is_data:
# For data, put the value to only the pixels w non-zero M
- is_nonzero = (numpy.fabs(self.sld_mx) +
- numpy.fabs(self.sld_my) +
- numpy.fabs(self.sld_mz)).nonzero()
- self.sld_n = numpy.zeros(len(self.pos_x))
+ is_nonzero = (np.fabs(self.sld_mx) +
+ np.fabs(self.sld_my) +
+ np.fabs(self.sld_mz)).nonzero()
+ self.sld_n = np.zeros(len(self.pos_x))
if len(self.sld_n[is_nonzero]) > 0:
self.sld_n[is_nonzero] = sld_n
else:
self.sld_n.fill(sld_n)
else:
# For non-data, put the value to all the pixels
- self.sld_n = numpy.ones(len(self.pos_x)) * sld_n
+ self.sld_n = np.ones(len(self.pos_x)) * sld_n
else:
self.sld_n = sld_n
def set_sldms(self, sld_mx, sld_my, sld_mz):
r"""
- Sets (\|m\|, m_theta, m_phi)
- """
+ Sets mx, my, mz and abs(m).
+ """ # Note: escaping
if sld_mx.__class__.__name__ == 'float':
- self.sld_mx = numpy.ones(len(self.pos_x)) * sld_mx
+ self.sld_mx = np.ones(len(self.pos_x)) * sld_mx
else:
self.sld_mx = sld_mx
if sld_my.__class__.__name__ == 'float':
- self.sld_my = numpy.ones(len(self.pos_x)) * sld_my
+ self.sld_my = np.ones(len(self.pos_x)) * sld_my
else:
self.sld_my = sld_my
if sld_mz.__class__.__name__ == 'float':
- self.sld_mz = numpy.ones(len(self.pos_x)) * sld_mz
+ self.sld_mz = np.ones(len(self.pos_x)) * sld_mz
else:
self.sld_mz = sld_mz
- sld_m = numpy.sqrt(sld_mx * sld_mx + sld_my * sld_my + \
+ sld_m = np.sqrt(sld_mx * sld_mx + sld_my * sld_my + \
sld_mz * sld_mz)
self.sld_m = sld_m
@@ -932,10 +937,10 @@ class MagSLD(object):
Set pixel
:Params pixel: str; pixel or atomic symbol, or array of strings
"""
- if self.sld_n == None:
+ if self.sld_n is None:
return
if symbol.__class__.__name__ == 'str':
- self.pix_symbol = numpy.repeat(symbol, len(self.sld_n))
+ self.pix_symbol = np.repeat(symbol, len(self.sld_n))
else:
self.pix_symbol = symbol
@@ -944,12 +949,12 @@ class MagSLD(object):
Set pixel volumes
:Params pixel: str; pixel or atomic symbol, or array of strings
"""
- if self.sld_n == None:
+ if self.sld_n is None:
return
if vol.__class__.__name__ == 'ndarray':
self.vol_pix = vol
elif vol.__class__.__name__.count('float') > 0:
- self.vol_pix = numpy.repeat(vol, len(self.sld_n))
+ self.vol_pix = np.repeat(vol, len(self.sld_n))
else:
self.vol_pix = None
@@ -972,7 +977,7 @@ class MagSLD(object):
self.xnodes = int(xdist) + 1
self.ynodes = int(ydist) + 1
self.znodes = int(zdist) + 1
- except:
+ except Exception:
self.xnodes = None
self.ynodes = None
self.znodes = None
@@ -992,22 +997,22 @@ class MagSLD(object):
zpos_pre = self.pos_z[0]
for x_pos in self.pos_x:
if xpos_pre != x_pos:
- self.xstepsize = numpy.fabs(x_pos - xpos_pre)
+ self.xstepsize = np.fabs(x_pos - xpos_pre)
break
for y_pos in self.pos_y:
if ypos_pre != y_pos:
- self.ystepsize = numpy.fabs(y_pos - ypos_pre)
+ self.ystepsize = np.fabs(y_pos - ypos_pre)
break
for z_pos in self.pos_z:
if zpos_pre != z_pos:
- self.zstepsize = numpy.fabs(z_pos - zpos_pre)
+ self.zstepsize = np.fabs(z_pos - zpos_pre)
break
#default pix volume
- self.vol_pix = numpy.ones(len(self.pos_x))
+ self.vol_pix = np.ones(len(self.pos_x))
vol = self.xstepsize * self.ystepsize * self.zstepsize
self.set_pixel_volumes(vol)
self.has_stepsize = True
- except:
+ except Exception:
self.xstepsize = None
self.ystepsize = None
self.zstepsize = None
@@ -1041,7 +1046,7 @@ def test_load():
"""
from mpl_toolkits.mplot3d import Axes3D
current_dir = os.path.abspath(os.path.curdir)
- print current_dir
+ print(current_dir)
for i in range(6):
current_dir, _ = os.path.split(current_dir)
tfile = os.path.join(current_dir, "test", "CoreXY_ShellZ.txt")
@@ -1052,8 +1057,8 @@ def test_load():
break
reader = SLDReader()
oreader = OMFReader()
- output = reader.read(tfpath)
- ooutput = oreader.read(ofpath)
+ output = decode(reader.read(tfpath))
+ ooutput = decode(oreader.read(ofpath))
foutput = OMF2SLD()
foutput.set_data(ooutput)
@@ -1070,16 +1075,16 @@ def test_load():
x2 = output.pos_x+output.sld_mx/max_m * gap
y2 = output.pos_y+output.sld_my/max_m * gap
z2 = output.pos_z+output.sld_mz/max_m * gap
- x_arrow = numpy.column_stack((output.pos_x, x2))
- y_arrow = numpy.column_stack((output.pos_y, y2))
- z_arrow = numpy.column_stack((output.pos_z, z2))
+ x_arrow = np.column_stack((output.pos_x, x2))
+ y_arrow = np.column_stack((output.pos_y, y2))
+ z_arrow = np.column_stack((output.pos_z, z2))
unit_x2 = output.sld_mx / max_m
unit_y2 = output.sld_my / max_m
unit_z2 = output.sld_mz / max_m
- color_x = numpy.fabs(unit_x2 * 0.8)
- color_y = numpy.fabs(unit_y2 * 0.8)
- color_z = numpy.fabs(unit_z2 * 0.8)
- colors = numpy.column_stack((color_x, color_y, color_z))
+ color_x = np.fabs(unit_x2 * 0.8)
+ color_y = np.fabs(unit_y2 * 0.8)
+ color_z = np.fabs(unit_z2 * 0.8)
+ colors = np.column_stack((color_x, color_y, color_z))
plt.show()
def test():
@@ -1094,7 +1099,7 @@ def test():
ofpath = ofile
break
oreader = OMFReader()
- ooutput = oreader.read(ofpath)
+ ooutput = decode(oreader.read(ofpath))
foutput = OMF2SLD()
foutput.set_data(ooutput)
writer = SLDReader()
@@ -1102,9 +1107,9 @@ def test():
foutput.output)
model = GenSAS()
model.set_sld_data(foutput.output)
- x = numpy.arange(1000)/10000. + 1e-5
- y = numpy.arange(1000)/10000. + 1e-5
- i = numpy.zeros(1000)
+ x = np.arange(1000)/10000. + 1e-5
+ y = np.arange(1000)/10000. + 1e-5
+ i = np.zeros(1000)
model.runXY([x, y, i])
if __name__ == "__main__":
diff --git a/src/sas/sascalc/corfunc/corfunc_calculator.py b/src/sas/sascalc/corfunc/corfunc_calculator.py
index 90522af..6ceca0b 100644
--- a/src/sas/sascalc/corfunc/corfunc_calculator.py
+++ b/src/sas/sascalc/corfunc/corfunc_calculator.py
@@ -33,7 +33,15 @@ class CorfuncCalculator(object):
self._lasty = []
def __call__(self, x):
- if self._lastx == [] or x.tolist() != self._lastx.tolist():
+ # If input is a single number, evaluate the function at that number
+ # and return a single number
+ if type(x) == float or type(x) == int:
+ return self._smoothed_function(np.array([x]))[0]
+ # If input is a list, and is different to the last input, evaluate
+ # the function at each point. If the input is the same as last time
+ # the function was called, return the result that was calculated
+ # last time instead of explicity evaluating the function again.
+ elif self._lastx == [] or x.tolist() != self._lastx.tolist():
self._lasty = self._smoothed_function(x)
self._lastx = x
return self._lasty
@@ -79,7 +87,7 @@ class CorfuncCalculator(object):
return
# Only process data of the class Data1D
if not issubclass(data.__class__, Data1D):
- raise ValueError, "Data must be of the type DataLoader.Data1D"
+ raise ValueError("Data must be of the type DataLoader.Data1D")
# Prepare the data
new_data = Data1D(x=data.x, y=data.y)
@@ -115,12 +123,13 @@ class CorfuncCalculator(object):
iq = self._data.y
params, s2 = self._fit_data(q, iq)
+ # Extrapolate to 100*Qmax in experimental data
qs = np.arange(0, q[-1]*100, (q[1]-q[0]))
iqs = s2(qs)
extrapolation = Data1D(qs, iqs)
- return params, extrapolation
+ return params, extrapolation, s2
def compute_transform(self, extrapolation, trans_type, background=None,
completefn=None, updatefn=None):
@@ -130,8 +139,9 @@ class CorfuncCalculator(object):
:param extrapolation: The extrapolated data
:param background: The background value (if not provided, previously
calculated value will be used)
+ :param extrap_fn: A callable function representing the extraoplated data
:param completefn: The function to call when the transform calculation
- is complete`
+ is complete
:param updatefn: The function to call to update the GUI with the status
of the transform calculation
:return: The transformed data
@@ -143,14 +153,15 @@ class CorfuncCalculator(object):
if trans_type == 'fourier':
self._transform_thread = FourierThread(self._data, extrapolation,
- background, completefn=completefn, updatefn=updatefn)
+ background, completefn=completefn,
+ updatefn=updatefn)
elif trans_type == 'hilbert':
self._transform_thread = HilbertThread(self._data, extrapolation,
background, completefn=completefn, updatefn=updatefn)
else:
err = ("Incorrect transform type supplied, must be 'fourier'",
" or 'hilbert'")
- raise ValueError, err
+ raise ValueError(err)
self._transform_thread.queue()
@@ -165,8 +176,8 @@ class CorfuncCalculator(object):
def extract_parameters(self, transformed_data):
"""
Extract the interesting measurements from a correlation function
- :param transformed_data: Fourier transformation of the
- extrapolated data
+
+ :param transformed_data: Fourier transformation of the extrapolated data
"""
# Calculate indexes of maxima and minima
x = transformed_data.x
diff --git a/src/sas/sascalc/corfunc/transform_thread.py b/src/sas/sascalc/corfunc/transform_thread.py
index ac1cef8..4a40e92 100644
--- a/src/sas/sascalc/corfunc/transform_thread.py
+++ b/src/sas/sascalc/corfunc/transform_thread.py
@@ -1,6 +1,7 @@
from sas.sascalc.data_util.calcthread import CalcThread
from sas.sascalc.dataloader.data_info import Data1D
from scipy.fftpack import dct
+from scipy.integrate import trapz, cumtrapz
import numpy as np
from time import sleep
@@ -12,32 +13,77 @@ class FourierThread(CalcThread):
self.background = bg
self.extrapolation = extrapolated_data
+ def check_if_cancelled(self):
+ if self.isquit():
+ self.update("Fourier transform cancelled.")
+ self.complete(transforms=None)
+ return True
+ return False
+
def compute(self):
qs = self.extrapolation.x
iqs = self.extrapolation.y
q = self.data.x
background = self.background
+ xs = np.pi*np.arange(len(qs),dtype=np.float32)/(q[1]-q[0])/len(qs)
+
self.ready(delay=0.0)
- self.update(msg="Starting Fourier transform.")
+ self.update(msg="Fourier transform in progress.")
self.ready(delay=0.0)
- if self.isquit():
- return
+
+ if self.check_if_cancelled(): return
try:
- gamma = dct((iqs-background)*qs**2)
- gamma = gamma / gamma.max()
- except:
+ # ----- 1D Correlation Function -----
+ gamma1 = dct((iqs-background)*qs**2)
+ Q = gamma1.max()
+ gamma1 /= Q
+
+ if self.check_if_cancelled(): return
+
+ # ----- 3D Correlation Function -----
+ # gamma3(R) = 1/R int_{0}^{R} gamma1(x) dx
+ # trapz uses the trapezium rule to calculate the integral
+ mask = xs <= 200.0 # Only calculate gamma3 up to x=200 (as this is all that's plotted)
+ # gamma3 = [trapz(gamma1[:n], xs[:n])/xs[n-1] for n in range(2, len(xs[mask]) + 1)]j
+ # gamma3.insert(0, 1.0) # Gamma_3(0) is defined as 1
+ n = len(xs[mask])
+ gamma3 = cumtrapz(gamma1[:n], xs[:n])/xs[1:n]
+ gamma3 = np.hstack((1.0, gamma3)) # Gamma_3(0) is defined as 1
+
+ if self.check_if_cancelled(): return
+
+ # ----- Interface Distribution function -----
+ idf = dct(-qs**4 * (iqs-background))
+
+ if self.check_if_cancelled(): return
+
+ # Manually calculate IDF(0.0), since scipy DCT tends to give us a
+ # very large negative value.
+ # IDF(x) = int_0^inf q^4 * I(q) * cos(q*x) * dq
+ # => IDF(0) = int_0^inf q^4 * I(q) * dq
+ idf[0] = trapz(-qs**4 * (iqs-background), qs)
+ idf /= Q # Normalise using scattering invariant
+
+ except Exception as e:
+ import logging
+ logger = logging.getLogger(__name__)
+ logger.error(e)
+
self.update(msg="Fourier transform failed.")
- self.complete(transform=None)
+ self.complete(transforms=None)
return
if self.isquit():
return
self.update(msg="Fourier transform completed.")
- xs = np.pi*np.arange(len(qs),dtype=np.float32)/(q[1]-q[0])/len(qs)
- transform = Data1D(xs, gamma)
+ transform1 = Data1D(xs, gamma1)
+ transform3 = Data1D(xs[xs <= 200], gamma3)
+ idf = Data1D(xs, idf)
+
+ transforms = (transform1, transform3, idf)
- self.complete(transform=transform)
+ self.complete(transforms=transforms)
class HilbertThread(CalcThread):
def __init__(self, raw_data, extrapolated_data, bg, updatefn=None,
@@ -63,4 +109,4 @@ class HilbertThread(CalcThread):
self.update(msg="Hilbert transform completed.")
- self.complete(transform=None)
+ self.complete(transforms=None)
diff --git a/src/sas/sascalc/data_util/calcthread.py b/src/sas/sascalc/data_util/calcthread.py
index b92ab8a..bea2fe3 100644
--- a/src/sas/sascalc/data_util/calcthread.py
+++ b/src/sas/sascalc/data_util/calcthread.py
@@ -3,24 +3,31 @@
## \file
# \brief Abstract class for defining calculation threads.
#
+from __future__ import print_function
-import thread
import traceback
import sys
+import logging
+try:
+ import _thread as thread
+except ImportError: # CRUFT: python 2 support
+ import thread
if sys.platform.count("darwin") > 0:
import time
stime = time.time()
-
+
def clock():
return time.time() - stime
-
+
def sleep(t):
return time.sleep(t)
else:
from time import clock
from time import sleep
+logger = logging.getLogger(__name__)
+
class CalcThread:
"""Threaded calculation class. Inherit from here and specialize
@@ -30,7 +37,7 @@ class CalcThread:
If you specialize the __init__ method be sure to call
CalcThread.__init__, passing it the keyword arguments for
yieldtime, worktime, update and complete.
-
+
When defining the compute() method you need to include code which
allows the GUI to run. They are as follows: ::
@@ -201,12 +208,12 @@ class CalcThread:
def update(self, **kwargs):
"""Update GUI with the lastest results from the current work unit."""
- if self.updatefn != None and clock() > self._time_for_update:
+ if self.updatefn is not None and clock() > self._time_for_update:
self._lock.acquire()
self._time_for_update = clock() + self._delay
self._lock.release()
self._time_for_update += 1e6 # No more updates
-
+
self.updatefn(**kwargs)
sleep(self.yieldtime)
if self._interrupting:
@@ -217,7 +224,7 @@ class CalcThread:
def complete(self, **kwargs):
"""Update the GUI with the completed results from a work unit."""
- if self.completefn != None:
+ if self.completefn is not None:
self.completefn(**kwargs)
sleep(self.yieldtime)
return
@@ -242,8 +249,7 @@ class CalcThread:
return
except Exception:
pass
- import logging
- logging.error(traceback.format_exc())
+ logger.error(traceback.format_exc())
#print 'CalcThread exception',
def _run(self):
@@ -292,7 +298,7 @@ class CalcCommandline:
Test method
"""
def __init__(self, n=20000):
- print thread.get_ident()
+ print(thread.get_ident())
self.starttime = clock()
self.done = False
self.work = CalcDemo(completefn=self.complete,
@@ -304,21 +310,21 @@ class CalcCommandline:
self.work.queue(n)
self.work2.queue(n)
self.work3.queue(n)
- print "Expect updates from Main every second and from thread every 2.5 seconds"
- print ""
+ print("Expect updates from Main every second and from thread every 2.5 seconds")
+ print("")
self.work.ready(.5)
while not self.done:
sleep(1)
- print "Main thread %d at %.2f" % (thread.get_ident(),
- clock() - self.starttime)
+ print("Main thread %d at %.2f" % (thread.get_ident(),
+ clock() - self.starttime))
def update(self, i=0):
- print "Update i=%d from thread %d at %.2f" % (i, thread.get_ident(),
- clock() - self.starttime)
+ print("Update i=%d from thread %d at %.2f" % (i, thread.get_ident(),
+ clock() - self.starttime))
self.work.ready(2.5)
def complete(self, total=0.0):
- print "Complete total=%g from thread %d at %.2f" % (total,
+ print("Complete total=%g from thread %d at %.2f" % (total,
thread.get_ident(),
- clock() - self.starttime)
+ clock() - self.starttime))
self.done = True
diff --git a/src/sas/sascalc/data_util/err1d.py b/src/sas/sascalc/data_util/err1d.py
index 68fd269..7b7f649 100644
--- a/src/sas/sascalc/data_util/err1d.py
+++ b/src/sas/sascalc/data_util/err1d.py
@@ -7,7 +7,7 @@ may return values of the wrong type if some of the arguments are
integers, so be sure to create them with floating point inputs.
"""
from __future__ import division # Get true division
-import numpy
+import numpy as np
def div(X, varX, Y, varY):
@@ -58,21 +58,21 @@ def add(X, varX, Y, varY):
def exp(X, varX):
"""Exponentiation with error propagation"""
- Z = numpy.exp(X)
+ Z = np.exp(X)
varZ = varX * Z**2
return Z, varZ
def log(X, varX):
"""Logarithm with error propagation"""
- Z = numpy.log(X)
+ Z = np.log(X)
varZ = varX / X**2
return Z, varZ
# Confirm this formula before using it
# def pow(X,varX, Y,varY):
# Z = X**Y
-# varZ = (Y**2 * varX/X**2 + varY * numpy.log(X)**2) * Z**2
+# varZ = (Y**2 * varX/X**2 + varY * np.log(X)**2) * Z**2
# return Z,varZ
#
diff --git a/src/sas/sascalc/data_util/formatnum.py b/src/sas/sascalc/data_util/formatnum.py
index 78f1b76..debbecc 100644
--- a/src/sas/sascalc/data_util/formatnum.py
+++ b/src/sas/sascalc/data_util/formatnum.py
@@ -36,10 +36,10 @@ Example::
UncertaintyFormatter() returns a private formatter with its own
formatter.compact flag.
"""
-from __future__ import division
+from __future__ import division, print_function
import math
-import numpy
+import numpy as np
__all__ = ['format_uncertainty', 'format_uncertainty_pm',
'format_uncertainty_compact']
@@ -101,15 +101,15 @@ def _format_uncertainty(value, uncertainty, compact):
Implementation of both the compact and the +/- formats.
"""
# Handle indefinite value
- if numpy.isinf(value):
+ if np.isinf(value):
return "inf" if value > 0 else "-inf"
- if numpy.isnan(value):
+ if np.isnan(value):
return "NaN"
# Handle indefinite uncertainty
- if uncertainty is None or uncertainty <= 0 or numpy.isnan(uncertainty):
+ if uncertainty is None or uncertainty <= 0 or np.isnan(uncertainty):
return "%g" % value
- if numpy.isinf(uncertainty):
+ if np.isinf(uncertainty):
if compact:
return "%.2g(inf)" % value
else:
@@ -278,17 +278,17 @@ def test_compact():
assert value_str(-0.0001,0.764) == "-0.00(76)"
# non-finite values
- assert value_str(-numpy.inf,None) == "-inf"
- assert value_str(numpy.inf,None) == "inf"
- assert value_str(numpy.NaN,None) == "NaN"
+ assert value_str(-np.inf,None) == "-inf"
+ assert value_str(np.inf,None) == "inf"
+ assert value_str(np.NaN,None) == "NaN"
# bad or missing uncertainty
- assert value_str(-1.23567,numpy.NaN) == "-1.23567"
- assert value_str(-1.23567,-numpy.inf) == "-1.23567"
+ assert value_str(-1.23567,np.NaN) == "-1.23567"
+ assert value_str(-1.23567,-np.inf) == "-1.23567"
assert value_str(-1.23567,-0.1) == "-1.23567"
assert value_str(-1.23567,0) == "-1.23567"
assert value_str(-1.23567,None) == "-1.23567"
- assert value_str(-1.23567,numpy.inf) == "-1.2(inf)"
+ assert value_str(-1.23567,np.inf) == "-1.2(inf)"
def test_pm():
# Oops... renamed function after writing tests
@@ -409,17 +409,17 @@ def test_pm():
assert value_str(-0.0001,0.764) == "-0.00 +/- 0.76"
# non-finite values
- assert value_str(-numpy.inf,None) == "-inf"
- assert value_str(numpy.inf,None) == "inf"
- assert value_str(numpy.NaN,None) == "NaN"
+ assert value_str(-np.inf,None) == "-inf"
+ assert value_str(np.inf,None) == "inf"
+ assert value_str(np.NaN,None) == "NaN"
# bad or missing uncertainty
- assert value_str(-1.23567,numpy.NaN) == "-1.23567"
- assert value_str(-1.23567,-numpy.inf) == "-1.23567"
+ assert value_str(-1.23567,np.NaN) == "-1.23567"
+ assert value_str(-1.23567,-np.inf) == "-1.23567"
assert value_str(-1.23567,-0.1) == "-1.23567"
assert value_str(-1.23567,0) == "-1.23567"
assert value_str(-1.23567,None) == "-1.23567"
- assert value_str(-1.23567,numpy.inf) == "-1.2 +/- inf"
+ assert value_str(-1.23567,np.inf) == "-1.2 +/- inf"
def test_default():
# Check that the default is the compact format
diff --git a/src/sas/sascalc/data_util/nxsunit.py b/src/sas/sascalc/data_util/nxsunit.py
index ddc5ebd..a948cc7 100644
--- a/src/sas/sascalc/data_util/nxsunit.py
+++ b/src/sas/sascalc/data_util/nxsunit.py
@@ -12,7 +12,7 @@ need now. It does not support the complete dimensional analysis provided
by the package udunits on which NeXus is based, or even the units used
in the NeXus definition files.
-Unlike other units packages, this package does not carry the units along with
+Unlike other units packages, this package does not carry the units along with
the value but merely provides a conversion function for transforming values.
Usage example::
@@ -67,7 +67,7 @@ def _build_metric_units(unit,abbr):
Ack! Allows, e.g., Coulomb and coulomb even though Coulomb is not
a unit because some NeXus files store it that way!
-
+
Returns a dictionary of names and scales.
"""
prefix = dict(peta=1e15,tera=1e12,giga=1e9,mega=1e6,kilo=1e3,
@@ -77,12 +77,12 @@ def _build_metric_units(unit,abbr):
d=1e-1,c=1e-2,m=1e-3,u=1e-6,
n=1e-9,p=1e-12,f=1e-15)
map = {abbr:1}
- map.update([(P+abbr,scale) for (P,scale) in short_prefix.iteritems()])
+ map.update([(P+abbr,scale) for (P,scale) in short_prefix.items()])
for name in [unit,unit.capitalize()]:
map.update({name:1,name+'s':1})
- map.update([(P+name,scale) for (P,scale) in prefix.iteritems()])
- map.update([(P+'*'+name,scale) for (P,scale) in prefix.iteritems()])
- map.update([(P+name+'s',scale) for (P,scale) in prefix.iteritems()])
+ map.update([(P+name,scale) for (P,scale) in prefix.items()])
+ map.update([(P+'*'+name,scale) for (P,scale) in prefix.items()])
+ map.update([(P+name+'s',scale) for (P,scale) in prefix.items()])
return map
def _build_plural_units(**kw):
@@ -90,8 +90,8 @@ def _build_plural_units(**kw):
Construct names for the given units. Builds singular and plural form.
"""
map = {}
- map.update([(name,scale) for name,scale in kw.iteritems()])
- map.update([(name+'s',scale) for name,scale in kw.iteritems()])
+ map.update([(name,scale) for name,scale in kw.items()])
+ map.update([(name+'s',scale) for name,scale in kw.items()])
return map
def _caret_optional(s):
@@ -100,8 +100,8 @@ def _caret_optional(s):
* WARNING * this will incorrect transform 10^3 to 103.
"""
- s.update((k.replace('^',''),v)
- for k,v in s.items()
+ s.update((k.replace('^',''),v)
+ for k, v in list(s.items())
if '^' in k)
def _build_all_units():
@@ -129,13 +129,13 @@ def _build_all_units():
temperature.update(_build_metric_units('Kelvin','K'))
temperature.update(_build_metric_units('Celcius', 'C'))
temperature.update(_build_metric_units('celcius', 'C'))
-
+
charge = _build_metric_units('coulomb','C')
charge.update({'microAmp*hour':0.0036})
sld = { '10^-6 Angstrom^-2': 1e-6, 'Angstrom^-2': 1 }
- Q = { 'invA': 1, 'invAng': 1, 'invAngstroms': 1, '1/A': 1,
- '10^-3 Angstrom^-1': 1e-3, '1/cm': 1e-8,
+ Q = { 'invA': 1, 'invAng': 1, 'invAngstroms': 1, '1/A': 1,
+ '10^-3 Angstrom^-1': 1e-3, '1/cm': 1e-8, '1/m': 1e-10,
'nm^-1': 0.1, '1/nm': 0.1, 'n_m^-1': 0.1 }
_caret_optional(sld)
@@ -188,21 +188,26 @@ class Converter(object):
raise KeyError("%s not in %s"%(units,possible_units))
def _check(expect,get):
- if expect != get: raise ValueError, "Expected %s but got %s"%(expect,get)
+ if expect != get:
+ raise ValueError("Expected %s but got %s"%(expect, get))
#print expect,"==",get
def test():
_check(1,Converter('n_m^-1')(10,'invA')) # 10 nm^-1 = 1 inv Angstroms
_check(2,Converter('mm')(2000,'m')) # 2000 mm -> 2 m
+ _check(2.011e10,Converter('1/A')(2.011,"1/m")) # 2.011 1/A -> 2.011 * 10^10 1/m
_check(0.003,Converter('microseconds')(3,units='ms')) # 3 us -> 0.003 ms
_check(45,Converter('nanokelvin')(45)) # 45 nK -> 45 nK
_check(0.5,Converter('seconds')(1800,units='hours')) # 1800 s -> 0.5 hr
_check(123,Converter('a.u.')(123,units='mm')) # arbitrary units always returns the same value
_check(123,Converter('a.u.')(123,units='s')) # arbitrary units always returns the same value
_check(123,Converter('a.u.')(123,units='')) # arbitrary units always returns the same value
- try: Converter('help')
- except KeyError: pass
- else: raise Exception("unknown unit did not raise an error")
+ try:
+ Converter('help')
+ except KeyError:
+ pass
+ else:
+ raise Exception("unknown unit did not raise an error")
# TODO: more tests
diff --git a/src/sas/sascalc/data_util/odict.py b/src/sas/sascalc/data_util/odict.py
index bebe530..6971148 100644
--- a/src/sas/sascalc/data_util/odict.py
+++ b/src/sas/sascalc/data_util/odict.py
@@ -38,40 +38,40 @@ import types, warnings
class OrderedDict(dict):
"""
A class of dictionary that keeps the insertion order of keys.
-
+
All appropriate methods return keys, items, or values in an ordered way.
-
+
All normal dictionary methods are available. Update and comparison is
restricted to other OrderedDict objects.
-
+
Various sequence methods are available, including the ability to explicitly
mutate the key ordering.
-
+
__contains__ tests:
-
+
>>> d = OrderedDict(((1, 3),))
>>> 1 in d
1
>>> 4 in d
0
-
+
__getitem__ tests:
-
+
>>> OrderedDict(((1, 3), (3, 2), (2, 1)))[2]
1
>>> OrderedDict(((1, 3), (3, 2), (2, 1)))[4]
Traceback (most recent call last):
KeyError: 4
-
+
__len__ tests:
-
+
>>> len(OrderedDict())
0
>>> len(OrderedDict(((1, 3), (3, 2), (2, 1))))
3
-
+
get tests:
-
+
>>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
>>> d.get(1)
3
@@ -81,9 +81,9 @@ class OrderedDict(dict):
5
>>> d
OrderedDict([(1, 3), (3, 2), (2, 1)])
-
+
has_key tests:
-
+
>>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
>>> d.has_key(1)
1
@@ -95,11 +95,11 @@ class OrderedDict(dict):
"""
Create a new ordered dictionary. Cannot init from a normal dict,
nor from kwargs, since items order is undefined in those cases.
-
+
If the ``strict`` keyword argument is ``True`` (``False`` is the
default) then when doing slice assignment - the ``OrderedDict`` you are
assigning from *must not* contain any keys in the remaining dict.
-
+
>>> OrderedDict()
OrderedDict([])
>>> OrderedDict({1: 1})
@@ -282,7 +282,7 @@ class OrderedDict(dict):
def __repr__(self):
"""
Used for __repr__ and __str__
-
+
>>> r1 = repr(OrderedDict((('a', 'b'), ('c', 'd'), ('e', 'f'))))
>>> r1
"OrderedDict([('a', 'b'), ('c', 'd'), ('e', 'f')])"
@@ -320,7 +320,7 @@ class OrderedDict(dict):
>>> d[1:3] = OrderedDict(((1, 2), (5, 6), (7, 8)))
>>> d
OrderedDict([(0, 1), (1, 2), (5, 6), (7, 8), (3, 4)])
-
+
>>> a = OrderedDict(((0, 1), (1, 2), (2, 3)), strict=True)
>>> a[3] = 4
>>> a
@@ -344,12 +344,12 @@ class OrderedDict(dict):
>>> a[::-1] = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
>>> a
OrderedDict([(3, 4), (2, 3), (1, 2), (0, 1)])
-
+
>>> d = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
>>> d[:1] = 3
Traceback (most recent call last):
TypeError: slice assignment requires an OrderedDict
-
+
>>> d = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
>>> d[:1] = OrderedDict([(9, 8)])
>>> d
@@ -443,7 +443,7 @@ class OrderedDict(dict):
def __getattr__(self, name):
"""
Implemented so that access to ``sequence`` raises a warning.
-
+
>>> d = OrderedDict()
>>> d.sequence
[]
@@ -462,7 +462,7 @@ class OrderedDict(dict):
def __deepcopy__(self, memo):
"""
To allow deepcopy to work with OrderedDict.
-
+
>>> from copy import deepcopy
>>> a = OrderedDict([(1, 1), (2, 2), (3, 3)])
>>> a['test'] = {}
@@ -489,9 +489,9 @@ class OrderedDict(dict):
def items(self):
"""
- ``items`` returns a list of tuples representing all the
+ ``items`` returns a list of tuples representing all the
``(key, value)`` pairs in the dictionary.
-
+
>>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
>>> d.items()
[(1, 3), (3, 2), (2, 1)]
@@ -504,7 +504,7 @@ class OrderedDict(dict):
def keys(self):
"""
Return a list of keys in the ``OrderedDict``.
-
+
>>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
>>> d.keys()
[1, 3, 2]
@@ -514,10 +514,10 @@ class OrderedDict(dict):
def values(self, values=None):
"""
Return a list of all the values in the OrderedDict.
-
+
Optionally you can pass in a list of values, which will replace the
current list. The value list must be the same len as the OrderedDict.
-
+
>>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
>>> d.values()
[3, 2, 1]
@@ -595,7 +595,7 @@ class OrderedDict(dict):
def pop(self, key, *args):
"""
No dict.pop in Python 2.2, gotta reimplement it
-
+
>>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
>>> d.pop(3)
2
@@ -611,7 +611,7 @@ class OrderedDict(dict):
TypeError: pop expected at most 2 arguments, got 3
"""
if len(args) > 1:
- raise TypeError, ('pop expected at most 2 arguments, got %s' %
+ raise TypeError('pop expected at most 2 arguments, got %s' %
(len(args) + 1))
if key in self:
val = self[key]
@@ -627,7 +627,7 @@ class OrderedDict(dict):
"""
Delete and return an item specified by index, not a random one as in
dict. The index is -1 by default (the last item).
-
+
>>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
>>> d.popitem()
(2, 1)
@@ -673,7 +673,7 @@ class OrderedDict(dict):
def update(self, from_od):
"""
Update from another OrderedDict or sequence of (key, value) pairs
-
+
>>> d = OrderedDict(((1, 0), (0, 1)))
>>> d.update(OrderedDict(((1, 3), (3, 2), (2, 1))))
>>> d
@@ -705,11 +705,11 @@ class OrderedDict(dict):
def rename(self, old_key, new_key):
"""
Rename the key for a given value, without modifying sequence order.
-
+
For the case where new_key already exists this raise an exception,
since if new_key exists, it is ambiguous as to what happens to the
associated values, and the position of new_key in the sequence.
-
+
>>> od = OrderedDict()
>>> od['a'] = 1
>>> od['b'] = 2
@@ -731,7 +731,7 @@ class OrderedDict(dict):
if new_key in self:
raise ValueError("New key already exists: %r" % new_key)
# rename sequence entry
- value = self[old_key]
+ value = self[old_key]
old_idx = self._sequence.index(old_key)
self._sequence[old_idx] = new_key
# rename internal dict entry
@@ -741,10 +741,10 @@ class OrderedDict(dict):
def setitems(self, items):
"""
This method allows you to set the items in the dict.
-
+
It takes a list of tuples - of the same sort returned by the ``items``
method.
-
+
>>> d = OrderedDict()
>>> d.setitems(((3, 1), (2, 3), (1, 2)))
>>> d
@@ -759,10 +759,10 @@ class OrderedDict(dict):
``setkeys`` all ows you to pass in a new list of keys which will
replace the current set. This must contain the same set of keys, but
need not be in the same order.
-
+
If you pass in new keys that don't match, a ``KeyError`` will be
raised.
-
+
>>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
>>> d.keys()
[1, 3, 2]
@@ -790,9 +790,9 @@ class OrderedDict(dict):
"""
You can pass in a list of values, which will replace the
current list. The value list must be the same len as the OrderedDict.
-
+
(Or a ``ValueError`` is raised.)
-
+
>>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
>>> d.setvalues((1, 2, 3))
>>> d
@@ -812,7 +812,7 @@ class OrderedDict(dict):
def index(self, key):
"""
Return the position of the specified key in the OrderedDict.
-
+
>>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
>>> d.index(3)
1
@@ -825,10 +825,10 @@ class OrderedDict(dict):
def insert(self, index, key, value):
"""
Takes ``index``, ``key``, and ``value`` as arguments.
-
+
Sets ``key`` to ``value``, so that ``key`` is at position ``index`` in
the OrderedDict.
-
+
>>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
>>> d.insert(0, 4, 0)
>>> d
@@ -849,7 +849,7 @@ class OrderedDict(dict):
def reverse(self):
"""
Reverse the order of the OrderedDict.
-
+
>>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
>>> d.reverse()
>>> d
@@ -860,10 +860,10 @@ class OrderedDict(dict):
def sort(self, *args, **kwargs):
"""
Sort the key order in the OrderedDict.
-
+
This method takes the same arguments as the ``list.sort`` method on
your version of Python.
-
+
>>> d = OrderedDict(((4, 1), (2, 2), (3, 3), (1, 4)))
>>> d.sort()
>>> d
@@ -875,7 +875,7 @@ class Keys(object):
# FIXME: should this object be a subclass of list?
"""
Custom object for accessing the keys of an OrderedDict.
-
+
Can be called like the normal ``OrderedDict.keys`` method, but also
supports indexing and sequence methods.
"""
@@ -896,7 +896,7 @@ class Keys(object):
"""
You cannot assign to keys, but you can do slice assignment to re-order
them.
-
+
You can only do slice assignment if the new set of keys is a reordering
of the original set.
"""
@@ -966,7 +966,7 @@ class Keys(object):
class Items(object):
"""
Custom object for accessing the items of an OrderedDict.
-
+
Can be called like the normal ``OrderedDict.items`` method, but also
supports indexing and sequence methods.
"""
@@ -1076,7 +1076,7 @@ class Items(object):
class Values(object):
"""
Custom object for accessing the values of an OrderedDict.
-
+
Can be called like the normal ``OrderedDict.values`` method, but also
supports indexing and sequence methods.
"""
@@ -1098,7 +1098,7 @@ class Values(object):
def __setitem__(self, index, value):
"""
Set the value at position i to value.
-
+
You can only do slice assignment to values if you supply a sequence of
equal length to the slice you are replacing.
"""
@@ -1167,12 +1167,12 @@ class SequenceOrderedDict(OrderedDict):
"""
Experimental version of OrderedDict that has a custom object for ``keys``,
``values``, and ``items``.
-
+
These are callable sequence objects that work as methods, or can be
manipulated directly as sequences.
-
+
Test for ``keys``, ``items`` and ``values``.
-
+
>>> d = SequenceOrderedDict(((1, 2), (2, 3), (3, 4)))
>>> d
SequenceOrderedDict([(1, 2), (2, 3), (3, 4)])
@@ -1292,7 +1292,7 @@ class SequenceOrderedDict(OrderedDict):
>>> d.values = (1, 2, 3)
>>> d
SequenceOrderedDict([(1, 1), (2, 2), (3, 3)])
-
+
>>> d = SequenceOrderedDict(((1, 2), (2, 3), (3, 4)))
>>> d
SequenceOrderedDict([(1, 2), (2, 3), (3, 4)])
diff --git a/src/sas/sascalc/data_util/registry.py b/src/sas/sascalc/data_util/registry.py
index 19a8d0f..f20077f 100644
--- a/src/sas/sascalc/data_util/registry.py
+++ b/src/sas/sascalc/data_util/registry.py
@@ -1,12 +1,13 @@
-# This program is public domain
"""
File extension registry.
This provides routines for opening files based on extension,
and registers the built-in file extensions.
"""
+from __future__ import print_function
+
+from sas.sascalc.dataloader.loader_exceptions import NoKnownLoaderException
-import os.path
class ExtensionRegistry(object):
"""
@@ -20,12 +21,12 @@ class ExtensionRegistry(object):
# Add an association by setting an element
registry['.zip'] = unzip
-
+
# Multiple extensions for one loader
registry['.tgz'] = untar
registry['.tar.gz'] = untar
- # Generic extensions to use after trying more specific extensions;
+ # Generic extensions to use after trying more specific extensions;
# these will be checked after the more specific extensions fail.
registry['.gz'] = gunzip
@@ -36,7 +37,7 @@ class ExtensionRegistry(object):
# Show registered extensions
print registry.extensions()
-
+
# Can also register a format name for explicit control from caller
registry['cx3'] = cx3
print registry.formats()
@@ -60,14 +61,18 @@ class ExtensionRegistry(object):
"""
def __init__(self, **kw):
self.loaders = {}
+
def __setitem__(self, ext, loader):
if ext not in self.loaders:
self.loaders[ext] = []
self.loaders[ext].insert(0,loader)
+
def __getitem__(self, ext):
return self.loaders[ext]
+
def __contains__(self, ext):
return ext in self.loaders
+
def formats(self):
"""
Return a sorted list of the registered formats.
@@ -75,6 +80,7 @@ class ExtensionRegistry(object):
names = [a for a in self.loaders.keys() if not a.startswith('.')]
names.sort()
return names
+
def extensions(self):
"""
Return a sorted list of registered extensions.
@@ -82,16 +88,19 @@ class ExtensionRegistry(object):
exts = [a for a in self.loaders.keys() if a.startswith('.')]
exts.sort()
return exts
+
def lookup(self, path):
"""
Return the loader associated with the file type of path.
-
- Raises ValueError if file type is not known.
- """
+
+ :param path: Data file path
+ :raises ValueError: When no loaders are found for the file.
+ :return: List of available readers for the file extension
+ """
# Find matching extensions
extlist = [ext for ext in self.extensions() if path.endswith(ext)]
# Sort matching extensions by decreasing order of length
- extlist.sort(lambda a,b: len(a)<len(b))
+ extlist.sort(key=len)
# Combine loaders for matching extensions into one big list
loaders = []
for L in [self.loaders[ext] for ext in extlist]:
@@ -104,71 +113,38 @@ class ExtensionRegistry(object):
loaders = L
# Raise an error if there are no matching extensions
if len(loaders) == 0:
- raise ValueError, "Unknown file type for "+path
- # All done
+ raise ValueError("Unknown file type for "+path)
return loaders
+
def load(self, path, format=None):
"""
Call the loader for the file type of path.
- Raises ValueError if no loader is available.
- Raises KeyError if format is not available.
- May raise a loader-defined exception if loader fails.
+ :raises ValueError: if no loader is available.
+ :raises KeyError: if format is not available.
+
+ May raise a loader-defined exception if loader fails.
"""
+ loaders = []
if format is None:
- loaders = self.lookup(path)
+ try:
+ loaders = self.lookup(path)
+ except ValueError as e:
+ pass
else:
- loaders = self.loaders[format]
+ try:
+ loaders = self.loaders[format]
+ except KeyError as e:
+ pass
+ last_exc = None
for fn in loaders:
try:
return fn(path)
- except:
- pass # give other loaders a chance to succeed
+ except Exception as e:
+ last_exc = e
+ pass # give other loaders a chance to succeed
# If we get here it is because all loaders failed
- raise # reraises last exception
-
-def test():
- reg = ExtensionRegistry()
- class CxError(Exception): pass
- def cx(file): return 'cx'
- def new_cx(file): return 'new_cx'
- def fail_cx(file): raise CxError
- def cat(file): return 'cat'
- def gunzip(file): return 'gunzip'
- reg['.cx'] = cx
- reg['.cx1'] = cx
- reg['.cx'] = new_cx
- reg['.gz'] = gunzip
- reg['.cx.gz'] = new_cx
- reg['.cx1.gz'] = fail_cx
- reg['.cx1'] = fail_cx
- reg['.cx2'] = fail_cx
- reg['new_cx'] = new_cx
-
- # Two loaders associated with .cx
- assert reg.lookup('hello.cx') == [new_cx,cx]
- # Make sure the last loader applies first
- assert reg.load('hello.cx') == 'new_cx'
- # Make sure the next loader applies if the first fails
- assert reg.load('hello.cx1') == 'cx'
- # Make sure the format override works
- assert reg.load('hello.cx1',format='.cx.gz') == 'new_cx'
- # Make sure the format override works
- assert reg.load('hello.cx1',format='new_cx') == 'new_cx'
- # Make sure the case of all loaders failing is correct
- try: reg.load('hello.cx2')
- except CxError: pass # correct failure
- else: raise AssertError,"Incorrect error on load failure"
- # Make sure the case of no loaders fails correctly
- try: reg.load('hello.missing')
- except ValueError,msg:
- assert str(msg)=="Unknown file type for hello.missing",'Message: <%s>'%(msg)
- else: raise AssertError,"No error raised for missing extension"
- assert reg.formats() == ['new_cx']
- assert reg.extensions() == ['.cx','.cx.gz','.cx1','.cx1.gz','.cx2','.gz']
- # make sure that it supports multiple '.' in filename
- assert reg.load('hello.extra.cx1') == 'cx'
- assert reg.load('hello.gz') == 'gunzip'
- assert reg.load('hello.cx1.gz') == 'gunzip' # Since .cx1.gz fails
-
-if __name__ == "__main__": test()
+ if last_exc is not None and len(loaders) != 0:
+ # If file has associated loader(s) and they;ve failed
+ raise last_exc
+ raise NoKnownLoaderException(e.message) # raise generic exception
diff --git a/src/sas/sascalc/data_util/uncertainty.py b/src/sas/sascalc/data_util/uncertainty.py
index 8fccbbe..13e0592 100644
--- a/src/sas/sascalc/data_util/uncertainty.py
+++ b/src/sas/sascalc/data_util/uncertainty.py
@@ -1,12 +1,12 @@
r"""
Uncertainty propagation class for arithmetic, log and exp.
-Based on scalars or numpy vectors, this class allows you to store and
+Based on scalars or numpy vectors, this class allows you to store and
manipulate values+uncertainties, with propagation of gaussian error for
addition, subtraction, multiplication, division, power, exp and log.
Storage properties are determined by the numbers used to set the value
-and uncertainty. Be sure to use floating point uncertainty vectors
+and uncertainty. Be sure to use floating point uncertainty vectors
for inplace operations since numpy does not do automatic type conversion.
Normal operations can use mixed integer and floating point. In place
operations such as *a \*= b* create at most one extra copy for each operation.
@@ -16,9 +16,10 @@ for huge arrays.
from __future__ import division
-import numpy
-import err1d
-from formatnum import format_uncertainty
+import numpy as np
+
+from .import err1d
+from .formatnum import format_uncertainty
__all__ = ['Uncertainty']
@@ -26,8 +27,8 @@ __all__ = ['Uncertainty']
# TODO: C implementation of *,/,**?
class Uncertainty(object):
# Make standard deviation available
- def _getdx(self): return numpy.sqrt(self.variance)
- def _setdx(self,dx):
+ def _getdx(self): return np.sqrt(self.variance)
+ def _setdx(self,dx):
# Direct operation
# variance = dx**2
# Indirect operation to avoid temporaries
@@ -37,12 +38,12 @@ class Uncertainty(object):
# Constructor
def __init__(self, x, variance=None):
- self.x, self.variance = x, variance
-
+ self.x, self.variance = x, variance
+
# Numpy array slicing operations
- def __len__(self):
+ def __len__(self):
return len(self.x)
- def __getitem__(self,key):
+ def __getitem__(self,key):
return Uncertainty(self.x[key],self.variance[key])
def __setitem__(self,key,value):
self.x[key] = value.x
@@ -136,22 +137,22 @@ class Uncertainty(object):
def __rdiv__(self, other): return self.__rtruediv__(other)
def __idiv__(self, other): return self.__itruediv__(other)
-
+
# Unary ops
def __neg__(self):
return Uncertainty(-self.x,self.variance)
def __pos__(self):
return self
def __abs__(self):
- return Uncertainty(numpy.abs(self.x),self.variance)
+ return Uncertainty(np.abs(self.x),self.variance)
def __str__(self):
- #return str(self.x)+" +/- "+str(numpy.sqrt(self.variance))
- if numpy.isscalar(self.x):
- return format_uncertainty(self.x,numpy.sqrt(self.variance))
+ #return str(self.x)+" +/- "+str(np.sqrt(self.variance))
+ if np.isscalar(self.x):
+ return format_uncertainty(self.x,np.sqrt(self.variance))
else:
- return [format_uncertainty(v,dv)
- for v,dv in zip(self.x,numpy.sqrt(self.variance))]
+ return [format_uncertainty(v,dv)
+ for v,dv in zip(self.x,np.sqrt(self.variance))]
def __repr__(self):
return "Uncertainty(%s,%s)"%(str(self.x),str(self.variance))
@@ -218,7 +219,7 @@ def test():
assert z.x == 5*4 and z.variance == 3*4**2
z = a/4
assert z.x == 5./4 and z.variance == 3./4**2
-
+
# Reverse scalar operations
z = 4+a
assert z.x == 4+5 and z.variance == 3
@@ -228,7 +229,7 @@ def test():
assert z.x == 4*5 and z.variance == 3*4**2
z = 4/a
assert z.x == 4./5 and abs(z.variance - 3./5**4 * 4**2) < 1e-15
-
+
# Power operations
z = a**2
assert z.x == 5**2 and z.variance == 4*3*5**2
@@ -249,7 +250,7 @@ def test():
z = a/b
assert z.x == 5./4 and abs(z.variance - (3./5**2 + 2./4**2)*(5./4)**2) < 1e-15
- # ===== Inplace operations =====
+ # ===== Inplace operations =====
# Scalar operations
y = a+0; y += 4
z = a+4
@@ -286,14 +287,14 @@ def test():
# =============== vector operations ================
# Slicing
- z = Uncertainty(numpy.array([1,2,3,4,5]),numpy.array([2,1,2,3,2]))
+ z = Uncertainty(np.array([1,2,3,4,5]),np.array([2,1,2,3,2]))
assert z[2].x == 3 and z[2].variance == 2
assert (z[2:4].x == [3,4]).all()
assert (z[2:4].variance == [2,3]).all()
- z[2:4] = Uncertainty(numpy.array([8,7]),numpy.array([4,5]))
+ z[2:4] = Uncertainty(np.array([8,7]),np.array([4,5]))
assert z[2].x == 8 and z[2].variance == 4
- A = Uncertainty(numpy.array([a.x]*2),numpy.array([a.variance]*2))
- B = Uncertainty(numpy.array([b.x]*2),numpy.array([b.variance]*2))
+ A = Uncertainty(np.array([a.x]*2),np.array([a.variance]*2))
+ B = Uncertainty(np.array([b.x]*2),np.array([b.variance]*2))
# TODO complete tests of copy and inplace operations for vectors and slices.
@@ -307,7 +308,7 @@ def test():
z = A/B
assert (z.x == 5./4).all()
assert (abs(z.variance - (3./5**2 + 2./4**2)*(5./4)**2) < 1e-15).all()
-
+
# printing; note that sqrt(3) ~ 1.7
assert str(Uncertainty(5,3)) == "5.0(17)"
assert str(Uncertainty(15,3)) == "15.0(17)"
diff --git a/src/sas/sascalc/dataloader/__init__.py b/src/sas/sascalc/dataloader/__init__.py
index 089a25f..6f797d3 100644
--- a/src/sas/sascalc/dataloader/__init__.py
+++ b/src/sas/sascalc/dataloader/__init__.py
@@ -1,3 +1,3 @@
-from data_info import *
-from manipulations import *
-from readers import *
+from .data_info import *
+from .manipulations import *
+from .readers import *
diff --git a/src/sas/sascalc/dataloader/data_info.py b/src/sas/sascalc/dataloader/data_info.py
index e87b8ef..052fb7f 100644
--- a/src/sas/sascalc/dataloader/data_info.py
+++ b/src/sas/sascalc/dataloader/data_info.py
@@ -1,1200 +1,1210 @@
-"""
- Module that contains classes to hold information read from
- reduced data files.
-
- A good description of the data members can be found in
- the CanSAS 1D XML data format:
-
- http://www.smallangles.net/wgwiki/index.php/cansas1d_documentation
-"""
-#####################################################################
-#This software was developed by the University of Tennessee as part of the
-#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
-#project funded by the US National Science Foundation.
-#See the license text in license.txt
-#copyright 2008, University of Tennessee
-######################################################################
-
-
-#TODO: Keep track of data manipulation in the 'process' data structure.
-#TODO: This module should be independent of plottables. We should write
-# an adapter class for plottables when needed.
-
-#from sas.guitools.plottables import Data1D as plottable_1D
-from sas.sascalc.data_util.uncertainty import Uncertainty
-import numpy
-import math
-
-class plottable_1D(object):
- """
- Data1D is a place holder for 1D plottables.
- """
- # The presence of these should be mutually
- # exclusive with the presence of Qdev (dx)
- x = None
- y = None
- dx = None
- dy = None
- ## Slit smearing length
- dxl = None
- ## Slit smearing width
- dxw = None
- ## SESANS specific params (wavelengths for spin echo length calculation)
- lam = None
- dlam = None
-
- # Units
- _xaxis = ''
- _xunit = ''
- _yaxis = ''
- _yunit = ''
-
- def __init__(self, x, y, dx=None, dy=None, dxl=None, dxw=None, lam=None, dlam=None):
- self.x = numpy.asarray(x)
- self.y = numpy.asarray(y)
- if dx is not None:
- self.dx = numpy.asarray(dx)
- if dy is not None:
- self.dy = numpy.asarray(dy)
- if dxl is not None:
- self.dxl = numpy.asarray(dxl)
- if dxw is not None:
- self.dxw = numpy.asarray(dxw)
- if lam is not None:
- self.lam = numpy.asarray(lam)
- if dlam is not None:
- self.dlam = numpy.asarray(dlam)
-
- def xaxis(self, label, unit):
- """
- set the x axis label and unit
- """
- self._xaxis = label
- self._xunit = unit
-
- def yaxis(self, label, unit):
- """
- set the y axis label and unit
- """
- self._yaxis = label
- self._yunit = unit
-
-
-class plottable_2D(object):
- """
- Data2D is a place holder for 2D plottables.
- """
- xmin = None
- xmax = None
- ymin = None
- ymax = None
- data = None
- qx_data = None
- qy_data = None
- q_data = None
- err_data = None
- dqx_data = None
- dqy_data = None
- mask = None
-
- # Units
- _xaxis = ''
- _xunit = ''
- _yaxis = ''
- _yunit = ''
- _zaxis = ''
- _zunit = ''
-
- def __init__(self, data=None, err_data=None, qx_data=None,
- qy_data=None, q_data=None, mask=None,
- dqx_data=None, dqy_data=None):
- self.data = numpy.asarray(data)
- self.qx_data = numpy.asarray(qx_data)
- self.qy_data = numpy.asarray(qy_data)
- self.q_data = numpy.asarray(q_data)
- self.mask = numpy.asarray(mask)
- self.err_data = numpy.asarray(err_data)
- if dqx_data is not None:
- self.dqx_data = numpy.asarray(dqx_data)
- if dqy_data is not None:
- self.dqy_data = numpy.asarray(dqy_data)
-
- def xaxis(self, label, unit):
- """
- set the x axis label and unit
- """
- self._xaxis = label
- self._xunit = unit
-
- def yaxis(self, label, unit):
- """
- set the y axis label and unit
- """
- self._yaxis = label
- self._yunit = unit
-
- def zaxis(self, label, unit):
- """
- set the z axis label and unit
- """
- self._zaxis = label
- self._zunit = unit
-
-
-class Vector(object):
- """
- Vector class to hold multi-dimensional objects
- """
- ## x component
- x = None
- ## y component
- y = None
- ## z component
- z = None
-
- def __init__(self, x=None, y=None, z=None):
- """
- Initialization. Components that are not
- set a set to None by default.
-
- :param x: x component
- :param y: y component
- :param z: z component
- """
- self.x = x
- self.y = y
- self.z = z
-
- def __str__(self):
- msg = "x = %s\ty = %s\tz = %s" % (str(self.x), str(self.y), str(self.z))
- return msg
-
-
-class Detector(object):
- """
- Class to hold detector information
- """
- ## Name of the instrument [string]
- name = None
- ## Sample to detector distance [float] [mm]
- distance = None
- distance_unit = 'mm'
- ## Offset of this detector position in X, Y,
- #(and Z if necessary) [Vector] [mm]
- offset = None
- offset_unit = 'm'
- ## Orientation (rotation) of this detector in roll,
- # pitch, and yaw [Vector] [degrees]
- orientation = None
- orientation_unit = 'degree'
- ## Center of the beam on the detector in X and Y
- #(and Z if necessary) [Vector] [mm]
- beam_center = None
- beam_center_unit = 'mm'
- ## Pixel size in X, Y, (and Z if necessary) [Vector] [mm]
- pixel_size = None
- pixel_size_unit = 'mm'
- ## Slit length of the instrument for this detector.[float] [mm]
- slit_length = None
- slit_length_unit = 'mm'
-
- def __init__(self):
- """
- Initialize class attribute that are objects...
- """
- self.offset = Vector()
- self.orientation = Vector()
- self.beam_center = Vector()
- self.pixel_size = Vector()
-
- def __str__(self):
- _str = "Detector:\n"
- _str += " Name: %s\n" % self.name
- _str += " Distance: %s [%s]\n" % \
- (str(self.distance), str(self.distance_unit))
- _str += " Offset: %s [%s]\n" % \
- (str(self.offset), str(self.offset_unit))
- _str += " Orientation: %s [%s]\n" % \
- (str(self.orientation), str(self.orientation_unit))
- _str += " Beam center: %s [%s]\n" % \
- (str(self.beam_center), str(self.beam_center_unit))
- _str += " Pixel size: %s [%s]\n" % \
- (str(self.pixel_size), str(self.pixel_size_unit))
- _str += " Slit length: %s [%s]\n" % \
- (str(self.slit_length), str(self.slit_length_unit))
- return _str
-
-
-class Aperture(object):
- ## Name
- name = None
- ## Type
- type = None
- ## Size name
- size_name = None
- ## Aperture size [Vector]
- size = None
- size_unit = 'mm'
- ## Aperture distance [float]
- distance = None
- distance_unit = 'mm'
-
- def __init__(self):
- self.size = Vector()
-
-
-class Collimation(object):
- """
- Class to hold collimation information
- """
- ## Name
- name = None
- ## Length [float] [mm]
- length = None
- length_unit = 'mm'
- ## Aperture
- aperture = None
-
- def __init__(self):
- self.aperture = []
-
- def __str__(self):
- _str = "Collimation:\n"
- _str += " Length: %s [%s]\n" % \
- (str(self.length), str(self.length_unit))
- for item in self.aperture:
- _str += " Aperture size:%s [%s]\n" % \
- (str(item.size), str(item.size_unit))
- _str += " Aperture_dist:%s [%s]\n" % \
- (str(item.distance), str(item.distance_unit))
- return _str
-
-
-class Source(object):
- """
- Class to hold source information
- """
- ## Name
- name = None
- ## Radiation type [string]
- radiation = None
- ## Beam size name
- beam_size_name = None
- ## Beam size [Vector] [mm]
- beam_size = None
- beam_size_unit = 'mm'
- ## Beam shape [string]
- beam_shape = None
- ## Wavelength [float] [Angstrom]
- wavelength = None
- wavelength_unit = 'A'
- ## Minimum wavelength [float] [Angstrom]
- wavelength_min = None
- wavelength_min_unit = 'nm'
- ## Maximum wavelength [float] [Angstrom]
- wavelength_max = None
- wavelength_max_unit = 'nm'
- ## Wavelength spread [float] [Angstrom]
- wavelength_spread = None
- wavelength_spread_unit = 'percent'
-
- def __init__(self):
- self.beam_size = Vector()
-
- def __str__(self):
- _str = "Source:\n"
- _str += " Radiation: %s\n" % str(self.radiation)
- _str += " Shape: %s\n" % str(self.beam_shape)
- _str += " Wavelength: %s [%s]\n" % \
- (str(self.wavelength), str(self.wavelength_unit))
- _str += " Waveln_min: %s [%s]\n" % \
- (str(self.wavelength_min), str(self.wavelength_min_unit))
- _str += " Waveln_max: %s [%s]\n" % \
- (str(self.wavelength_max), str(self.wavelength_max_unit))
- _str += " Waveln_spread:%s [%s]\n" % \
- (str(self.wavelength_spread), str(self.wavelength_spread_unit))
- _str += " Beam_size: %s [%s]\n" % \
- (str(self.beam_size), str(self.beam_size_unit))
- return _str
-
-
-"""
-Definitions of radiation types
-"""
-NEUTRON = 'neutron'
-XRAY = 'x-ray'
-MUON = 'muon'
-ELECTRON = 'electron'
-
-
-class Sample(object):
- """
- Class to hold the sample description
- """
- ## Short name for sample
- name = ''
- ## ID
- ID = ''
- ## Thickness [float] [mm]
- thickness = None
- thickness_unit = 'mm'
- ## Transmission [float] [fraction]
- transmission = None
- ## Temperature [float] [No Default]
- temperature = None
- temperature_unit = None
- ## Position [Vector] [mm]
- position = None
- position_unit = 'mm'
- ## Orientation [Vector] [degrees]
- orientation = None
- orientation_unit = 'degree'
- ## Details
- details = None
- ## SESANS zacceptance
- zacceptance = None
-
- def __init__(self):
- self.position = Vector()
- self.orientation = Vector()
- self.details = []
-
- def __str__(self):
- _str = "Sample:\n"
- _str += " ID: %s\n" % str(self.ID)
- _str += " Transmission: %s\n" % str(self.transmission)
- _str += " Thickness: %s [%s]\n" % \
- (str(self.thickness), str(self.thickness_unit))
- _str += " Temperature: %s [%s]\n" % \
- (str(self.temperature), str(self.temperature_unit))
- _str += " Position: %s [%s]\n" % \
- (str(self.position), str(self.position_unit))
- _str += " Orientation: %s [%s]\n" % \
- (str(self.orientation), str(self.orientation_unit))
-
- _str += " Details:\n"
- for item in self.details:
- _str += " %s\n" % item
-
- return _str
-
-
-class Process(object):
- """
- Class that holds information about the processes
- performed on the data.
- """
- name = ''
- date = ''
- description = ''
- term = None
- notes = None
-
- def __init__(self):
- self.term = []
- self.notes = []
-
- def is_empty(self):
- """
- Return True if the object is empty
- """
- return len(self.name) == 0 and len(self.date) == 0 and len(self.description) == 0 \
- and len(self.term) == 0 and len(self.notes) == 0
-
- def single_line_desc(self):
- """
- Return a single line string representing the process
- """
- return "%s %s %s" % (self.name, self.date, self.description)
-
- def __str__(self):
- _str = "Process:\n"
- _str += " Name: %s\n" % self.name
- _str += " Date: %s\n" % self.date
- _str += " Description: %s\n" % self.description
- for item in self.term:
- _str += " Term: %s\n" % item
- for item in self.notes:
- _str += " Note: %s\n" % item
- return _str
-
-
-class TransmissionSpectrum(object):
- """
- Class that holds information about transmission spectrum
- for white beams and spallation sources.
- """
- name = ''
- timestamp = ''
- ## Wavelength (float) [A]
- wavelength = None
- wavelength_unit = 'A'
- ## Transmission (float) [unit less]
- transmission = None
- transmission_unit = ''
- ## Transmission Deviation (float) [unit less]
- transmission_deviation = None
- transmission_deviation_unit = ''
-
- def __init__(self):
- self.wavelength = []
- self.transmission = []
- self.transmission_deviation = []
-
- def __str__(self):
- _str = "Transmission Spectrum:\n"
- _str += " Name: \t{0}\n".format(self.name)
- _str += " Timestamp: \t{0}\n".format(self.timestamp)
- _str += " Wavelength unit: \t{0}\n".format(self.wavelength_unit)
- _str += " Transmission unit:\t{0}\n".format(self.transmission_unit)
- _str += " Trans. Dev. unit: \t{0}\n".format(\
- self.transmission_deviation_unit)
- length_list = [len(self.wavelength), len(self.transmission), \
- len(self.transmission_deviation)]
- _str += " Number of Pts: \t{0}\n".format(max(length_list))
- return _str
-
-
-class DataInfo(object):
- """
- Class to hold the data read from a file.
- It includes four blocks of data for the
- instrument description, the sample description,
- the data itself and any other meta data.
- """
- ## Title
- title = ''
- ## Run number
- run = None
- ## Run name
- run_name = None
- ## File name
- filename = ''
- ## Notes
- notes = None
- ## Processes (Action on the data)
- process = None
- ## Instrument name
- instrument = ''
- ## Detector information
- detector = None
- ## Sample information
- sample = None
- ## Source information
- source = None
- ## Collimation information
- collimation = None
- ## Transmission Spectrum INfo
- trans_spectrum = None
- ## Additional meta-data
- meta_data = None
- ## Loading errors
- errors = None
- ## SESANS data check
- isSesans = None
-
-
- def __init__(self):
- """
- Initialization
- """
- ## Title
- self.title = ''
- ## Run number
- self.run = []
- self.run_name = {}
- ## File name
- self.filename = ''
- ## Notes
- self.notes = []
- ## Processes (Action on the data)
- self.process = []
- ## Instrument name
- self.instrument = ''
- ## Detector information
- self.detector = []
- ## Sample information
- self.sample = Sample()
- ## Source information
- self.source = Source()
- ## Collimation information
- self.collimation = []
- ## Transmission Spectrum
- self.trans_spectrum = []
- ## Additional meta-data
- self.meta_data = {}
- ## Loading errors
- self.errors = []
- ## SESANS data check
- self.isSesans = False
-
- def append_empty_process(self):
- """
- """
- self.process.append(Process())
-
- def add_notes(self, message=""):
- """
- Add notes to datainfo
- """
- self.notes.append(message)
-
- def __str__(self):
- """
- Nice printout
- """
- _str = "File: %s\n" % self.filename
- _str += "Title: %s\n" % self.title
- _str += "Run: %s\n" % str(self.run)
- _str += "SESANS: %s\n" % str(self.isSesans)
- _str += "Instrument: %s\n" % str(self.instrument)
- _str += "%s\n" % str(self.sample)
- _str += "%s\n" % str(self.source)
- for item in self.detector:
- _str += "%s\n" % str(item)
- for item in self.collimation:
- _str += "%s\n" % str(item)
- for item in self.process:
- _str += "%s\n" % str(item)
- for item in self.notes:
- _str += "%s\n" % str(item)
- for item in self.trans_spectrum:
- _str += "%s\n" % str(item)
- return _str
-
- # Private method to perform operation. Not implemented for DataInfo,
- # but should be implemented for each data class inherited from DataInfo
- # that holds actual data (ex.: Data1D)
- def _perform_operation(self, other, operation):
- """
- Private method to perform operation. Not implemented for DataInfo,
- but should be implemented for each data class inherited from DataInfo
- that holds actual data (ex.: Data1D)
- """
- return NotImplemented
-
- def _perform_union(self, other):
- """
- Private method to perform union operation. Not implemented for DataInfo,
- but should be implemented for each data class inherited from DataInfo
- that holds actual data (ex.: Data1D)
- """
- return NotImplemented
-
- def __add__(self, other):
- """
- Add two data sets
-
- :param other: data set to add to the current one
- :return: new data set
- :raise ValueError: raised when two data sets are incompatible
- """
- def operation(a, b):
- return a + b
- return self._perform_operation(other, operation)
-
- def __radd__(self, other):
- """
- Add two data sets
-
- :param other: data set to add to the current one
- :return: new data set
- :raise ValueError: raised when two data sets are incompatible
- """
- def operation(a, b):
- return b + a
- return self._perform_operation(other, operation)
-
- def __sub__(self, other):
- """
- Subtract two data sets
-
- :param other: data set to subtract from the current one
- :return: new data set
- :raise ValueError: raised when two data sets are incompatible
- """
- def operation(a, b):
- return a - b
- return self._perform_operation(other, operation)
-
- def __rsub__(self, other):
- """
- Subtract two data sets
-
- :param other: data set to subtract from the current one
- :return: new data set
- :raise ValueError: raised when two data sets are incompatible
- """
- def operation(a, b):
- return b - a
- return self._perform_operation(other, operation)
-
- def __mul__(self, other):
- """
- Multiply two data sets
-
- :param other: data set to subtract from the current one
- :return: new data set
- :raise ValueError: raised when two data sets are incompatible
- """
- def operation(a, b):
- return a * b
- return self._perform_operation(other, operation)
-
- def __rmul__(self, other):
- """
- Multiply two data sets
-
- :param other: data set to subtract from the current one
- :return: new data set
- :raise ValueError: raised when two data sets are incompatible
- """
- def operation(a, b):
- return b * a
- return self._perform_operation(other, operation)
-
- def __div__(self, other):
- """
- Divided a data set by another
-
- :param other: data set that the current one is divided by
- :return: new data set
- :raise ValueError: raised when two data sets are incompatible
- """
- def operation(a, b):
- return a/b
- return self._perform_operation(other, operation)
-
- def __rdiv__(self, other):
- """
- Divided a data set by another
-
- :param other: data set that the current one is divided by
- :return: new data set
- :raise ValueError: raised when two data sets are incompatible
- """
- def operation(a, b):
- return b/a
- return self._perform_operation(other, operation)
-
- def __or__(self, other):
- """
- Union a data set with another
-
- :param other: data set to be unified
- :return: new data set
- :raise ValueError: raised when two data sets are incompatible
- """
- return self._perform_union(other)
-
- def __ror__(self, other):
- """
- Union a data set with another
-
- :param other: data set to be unified
- :return: new data set
- :raise ValueError: raised when two data sets are incompatible
- """
- return self._perform_union(other)
-
-class Data1D(plottable_1D, DataInfo):
- """
- 1D data class
- """
- def __init__(self, x=None, y=None, dx=None, dy=None, lam=None, dlam=None, isSesans=None):
- DataInfo.__init__(self)
- plottable_1D.__init__(self, x, y, dx, dy,None, None, lam, dlam)
- self.isSesans = isSesans
- try:
- if self.isSesans: # the data is SESANS
- self.x_unit = 'A'
- self.y_unit = 'pol'
- elif not self.isSesans: # the data is SANS
- self.x_unit = '1/A'
- self.y_unit = '1/cm'
- except: # the data is not recognized/supported, and the user is notified
- raise(TypeError, 'data not recognized, check documentation for supported 1D data formats')
-
- def __str__(self):
- """
- Nice printout
- """
- _str = "%s\n" % DataInfo.__str__(self)
- _str += "Data:\n"
- _str += " Type: %s\n" % self.__class__.__name__
- _str += " X-axis: %s\t[%s]\n" % (self._xaxis, self._xunit)
- _str += " Y-axis: %s\t[%s]\n" % (self._yaxis, self._yunit)
- _str += " Length: %g\n" % len(self.x)
- return _str
-
- def is_slit_smeared(self):
- """
- Check whether the data has slit smearing information
- :return: True is slit smearing info is present, False otherwise
- """
- def _check(v):
- if (v.__class__ == list or v.__class__ == numpy.ndarray) \
- and len(v) > 0 and min(v) > 0:
- return True
- return False
- return _check(self.dxl) or _check(self.dxw)
-
- def clone_without_data(self, length=0, clone=None):
- """
- Clone the current object, without copying the data (which
- will be filled out by a subsequent operation).
- The data arrays will be initialized to zero.
-
- :param length: length of the data array to be initialized
- :param clone: if provided, the data will be copied to clone
- """
- from copy import deepcopy
-
- if clone is None or not issubclass(clone.__class__, Data1D):
- x = numpy.zeros(length)
- dx = numpy.zeros(length)
- y = numpy.zeros(length)
- dy = numpy.zeros(length)
- lam = numpy.zeros(length)
- dlam = numpy.zeros(length)
- clone = Data1D(x, y, lam=lam, dx=dx, dy=dy, dlam=dlam)
-
- clone.title = self.title
- clone.run = self.run
- clone.filename = self.filename
- clone.instrument = self.instrument
- clone.notes = deepcopy(self.notes)
- clone.process = deepcopy(self.process)
- clone.detector = deepcopy(self.detector)
- clone.sample = deepcopy(self.sample)
- clone.source = deepcopy(self.source)
- clone.collimation = deepcopy(self.collimation)
- clone.trans_spectrum = deepcopy(self.trans_spectrum)
- clone.meta_data = deepcopy(self.meta_data)
- clone.errors = deepcopy(self.errors)
-
- return clone
-
- def _validity_check(self, other):
- """
- Checks that the data lengths are compatible.
- Checks that the x vectors are compatible.
- Returns errors vectors equal to original
- errors vectors if they were present or vectors
- of zeros when none was found.
-
- :param other: other data set for operation
- :return: dy for self, dy for other [numpy arrays]
- :raise ValueError: when lengths are not compatible
- """
- dy_other = None
- if isinstance(other, Data1D):
- # Check that data lengths are the same
- if len(self.x) != len(other.x) or \
- len(self.y) != len(other.y):
- msg = "Unable to perform operation: data length are not equal"
- raise ValueError, msg
- # Here we could also extrapolate between data points
- TOLERANCE = 0.01
- for i in range(len(self.x)):
- if math.fabs((self.x[i] - other.x[i])/self.x[i]) > TOLERANCE:
- msg = "Incompatible data sets: x-values do not match"
- raise ValueError, msg
-
- # Check that the other data set has errors, otherwise
- # create zero vector
- dy_other = other.dy
- if other.dy == None or (len(other.dy) != len(other.y)):
- dy_other = numpy.zeros(len(other.y))
-
- # Check that we have errors, otherwise create zero vector
- dy = self.dy
- if self.dy == None or (len(self.dy) != len(self.y)):
- dy = numpy.zeros(len(self.y))
-
- return dy, dy_other
-
- def _perform_operation(self, other, operation):
- """
- """
- # First, check the data compatibility
- dy, dy_other = self._validity_check(other)
- result = self.clone_without_data(len(self.x))
- if self.dxw == None:
- result.dxw = None
- else:
- result.dxw = numpy.zeros(len(self.x))
- if self.dxl == None:
- result.dxl = None
- else:
- result.dxl = numpy.zeros(len(self.x))
-
- for i in range(len(self.x)):
- result.x[i] = self.x[i]
- if self.dx is not None and len(self.x) == len(self.dx):
- result.dx[i] = self.dx[i]
- if self.dxw is not None and len(self.x) == len(self.dxw):
- result.dxw[i] = self.dxw[i]
- if self.dxl is not None and len(self.x) == len(self.dxl):
- result.dxl[i] = self.dxl[i]
-
- a = Uncertainty(self.y[i], dy[i]**2)
- if isinstance(other, Data1D):
- b = Uncertainty(other.y[i], dy_other[i]**2)
- if other.dx is not None:
- result.dx[i] *= self.dx[i]
- result.dx[i] += (other.dx[i]**2)
- result.dx[i] /= 2
- result.dx[i] = math.sqrt(result.dx[i])
- if result.dxl is not None and other.dxl is not None:
- result.dxl[i] *= self.dxl[i]
- result.dxl[i] += (other.dxl[i]**2)
- result.dxl[i] /= 2
- result.dxl[i] = math.sqrt(result.dxl[i])
- else:
- b = other
-
- output = operation(a, b)
- result.y[i] = output.x
- result.dy[i] = math.sqrt(math.fabs(output.variance))
- return result
-
- def _validity_check_union(self, other):
- """
- Checks that the data lengths are compatible.
- Checks that the x vectors are compatible.
- Returns errors vectors equal to original
- errors vectors if they were present or vectors
- of zeros when none was found.
-
- :param other: other data set for operation
- :return: bool
- :raise ValueError: when data types are not compatible
- """
- if not isinstance(other, Data1D):
- msg = "Unable to perform operation: different types of data set"
- raise ValueError, msg
- return True
-
- def _perform_union(self, other):
- """
- """
- # First, check the data compatibility
- self._validity_check_union(other)
- result = self.clone_without_data(len(self.x) + len(other.x))
- if self.dy == None or other.dy is None:
- result.dy = None
- else:
- result.dy = numpy.zeros(len(self.x) + len(other.x))
- if self.dx == None or other.dx is None:
- result.dx = None
- else:
- result.dx = numpy.zeros(len(self.x) + len(other.x))
- if self.dxw == None or other.dxw is None:
- result.dxw = None
- else:
- result.dxw = numpy.zeros(len(self.x) + len(other.x))
- if self.dxl == None or other.dxl is None:
- result.dxl = None
- else:
- result.dxl = numpy.zeros(len(self.x) + len(other.x))
-
- result.x = numpy.append(self.x, other.x)
- #argsorting
- ind = numpy.argsort(result.x)
- result.x = result.x[ind]
- result.y = numpy.append(self.y, other.y)
- result.y = result.y[ind]
- if result.dy != None:
- result.dy = numpy.append(self.dy, other.dy)
- result.dy = result.dy[ind]
- if result.dx is not None:
- result.dx = numpy.append(self.dx, other.dx)
- result.dx = result.dx[ind]
- if result.dxw is not None:
- result.dxw = numpy.append(self.dxw, other.dxw)
- result.dxw = result.dxw[ind]
- if result.dxl is not None:
- result.dxl = numpy.append(self.dxl, other.dxl)
- result.dxl = result.dxl[ind]
- return result
-
-
-class Data2D(plottable_2D, DataInfo):
- """
- 2D data class
- """
- ## Units for Q-values
- Q_unit = '1/A'
- ## Units for I(Q) values
- I_unit = '1/cm'
- ## Vector of Q-values at the center of each bin in x
- x_bins = None
- ## Vector of Q-values at the center of each bin in y
- y_bins = None
- ## No 2D SESANS data as of yet. Always set it to False
- isSesans = False
-
- def __init__(self, data=None, err_data=None, qx_data=None,
- qy_data=None, q_data=None, mask=None,
- dqx_data=None, dqy_data=None):
- DataInfo.__init__(self)
- plottable_2D.__init__(self, data, err_data, qx_data,
- qy_data, q_data, mask, dqx_data, dqy_data)
- self.y_bins = []
- self.x_bins = []
-
- if len(self.detector) > 0:
- raise RuntimeError, "Data2D: Detector bank already filled at init"
-
- def __str__(self):
- _str = "%s\n" % DataInfo.__str__(self)
- _str += "Data:\n"
- _str += " Type: %s\n" % self.__class__.__name__
- _str += " X- & Y-axis: %s\t[%s]\n" % (self._yaxis, self._yunit)
- _str += " Z-axis: %s\t[%s]\n" % (self._zaxis, self._zunit)
- _str += " Length: %g \n" % (len(self.data))
- _str += " Shape: (%d, %d)\n" % (len(self.y_bins), len(self.x_bins))
- return _str
-
- def clone_without_data(self, length=0, clone=None):
- """
- Clone the current object, without copying the data (which
- will be filled out by a subsequent operation).
- The data arrays will be initialized to zero.
-
- :param length: length of the data array to be initialized
- :param clone: if provided, the data will be copied to clone
- """
- from copy import deepcopy
-
- if clone is None or not issubclass(clone.__class__, Data2D):
- data = numpy.zeros(length)
- err_data = numpy.zeros(length)
- qx_data = numpy.zeros(length)
- qy_data = numpy.zeros(length)
- q_data = numpy.zeros(length)
- mask = numpy.zeros(length)
- dqx_data = None
- dqy_data = None
- clone = Data2D(data=data, err_data=err_data,
- qx_data=qx_data, qy_data=qy_data,
- q_data=q_data, mask=mask)
-
- clone.title = self.title
- clone.run = self.run
- clone.filename = self.filename
- clone.instrument = self.instrument
- clone.notes = deepcopy(self.notes)
- clone.process = deepcopy(self.process)
- clone.detector = deepcopy(self.detector)
- clone.sample = deepcopy(self.sample)
- clone.source = deepcopy(self.source)
- clone.collimation = deepcopy(self.collimation)
- clone.trans_spectrum = deepcopy(self.trans_spectrum)
- clone.meta_data = deepcopy(self.meta_data)
- clone.errors = deepcopy(self.errors)
-
- return clone
-
- def _validity_check(self, other):
- """
- Checks that the data lengths are compatible.
- Checks that the x vectors are compatible.
- Returns errors vectors equal to original
- errors vectors if they were present or vectors
- of zeros when none was found.
-
- :param other: other data set for operation
- :return: dy for self, dy for other [numpy arrays]
- :raise ValueError: when lengths are not compatible
- """
- err_other = None
- TOLERANCE = 0.01
- if isinstance(other, Data2D):
- # Check that data lengths are the same
- if len(self.data) != len(other.data) or \
- len(self.qx_data) != len(other.qx_data) or \
- len(self.qy_data) != len(other.qy_data):
- msg = "Unable to perform operation: data length are not equal"
- raise ValueError, msg
- for ind in range(len(self.data)):
- if math.fabs((self.qx_data[ind] - other.qx_data[ind])/self.qx_data[ind]) > TOLERANCE:
- msg = "Incompatible data sets: qx-values do not match: %s %s" % (self.qx_data[ind], other.qx_data[ind])
- raise ValueError, msg
- if math.fabs((self.qy_data[ind] - other.qy_data[ind])/self.qy_data[ind]) > TOLERANCE:
- msg = "Incompatible data sets: qy-values do not match: %s %s" % (self.qy_data[ind], other.qy_data[ind])
- raise ValueError, msg
-
- # Check that the scales match
- err_other = other.err_data
- if other.err_data == None or \
- (len(other.err_data) != len(other.data)):
- err_other = numpy.zeros(len(other.data))
-
- # Check that we have errors, otherwise create zero vector
- err = self.err_data
- if self.err_data == None or \
- (len(self.err_data) != len(self.data)):
- err = numpy.zeros(len(other.data))
- return err, err_other
-
- def _perform_operation(self, other, operation):
- """
- Perform 2D operations between data sets
-
- :param other: other data set
- :param operation: function defining the operation
- """
- # First, check the data compatibility
- dy, dy_other = self._validity_check(other)
- result = self.clone_without_data(numpy.size(self.data))
- if self.dqx_data == None or self.dqy_data == None:
- result.dqx_data = None
- result.dqy_data = None
- else:
- result.dqx_data = numpy.zeros(len(self.data))
- result.dqy_data = numpy.zeros(len(self.data))
- for i in range(numpy.size(self.data)):
- result.data[i] = self.data[i]
- if self.err_data is not None and \
- numpy.size(self.data) == numpy.size(self.err_data):
- result.err_data[i] = self.err_data[i]
- if self.dqx_data is not None:
- result.dqx_data[i] = self.dqx_data[i]
- if self.dqy_data is not None:
- result.dqy_data[i] = self.dqy_data[i]
- result.qx_data[i] = self.qx_data[i]
- result.qy_data[i] = self.qy_data[i]
- result.q_data[i] = self.q_data[i]
- result.mask[i] = self.mask[i]
-
- a = Uncertainty(self.data[i], dy[i]**2)
- if isinstance(other, Data2D):
- b = Uncertainty(other.data[i], dy_other[i]**2)
- if other.dqx_data is not None and \
- result.dqx_data is not None:
- result.dqx_data[i] *= self.dqx_data[i]
- result.dqx_data[i] += (other.dqx_data[i]**2)
- result.dqx_data[i] /= 2
- result.dqx_data[i] = math.sqrt(result.dqx_data[i])
- if other.dqy_data is not None and \
- result.dqy_data is not None:
- result.dqy_data[i] *= self.dqy_data[i]
- result.dqy_data[i] += (other.dqy_data[i]**2)
- result.dqy_data[i] /= 2
- result.dqy_data[i] = math.sqrt(result.dqy_data[i])
- else:
- b = other
- output = operation(a, b)
- result.data[i] = output.x
- result.err_data[i] = math.sqrt(math.fabs(output.variance))
- return result
-
- def _validity_check_union(self, other):
- """
- Checks that the data lengths are compatible.
- Checks that the x vectors are compatible.
- Returns errors vectors equal to original
- errors vectors if they were present or vectors
- of zeros when none was found.
-
- :param other: other data set for operation
- :return: bool
- :raise ValueError: when data types are not compatible
- """
- if not isinstance(other, Data2D):
- msg = "Unable to perform operation: different types of data set"
- raise ValueError, msg
- return True
-
- def _perform_union(self, other):
- """
- Perform 2D operations between data sets
-
- :param other: other data set
- :param operation: function defining the operation
- """
- # First, check the data compatibility
- self._validity_check_union(other)
- result = self.clone_without_data(numpy.size(self.data) + \
- numpy.size(other.data))
- result.xmin = self.xmin
- result.xmax = self.xmax
- result.ymin = self.ymin
- result.ymax = self.ymax
- if self.dqx_data == None or self.dqy_data == None or \
- other.dqx_data == None or other.dqy_data == None:
- result.dqx_data = None
- result.dqy_data = None
- else:
- result.dqx_data = numpy.zeros(len(self.data) + \
- numpy.size(other.data))
- result.dqy_data = numpy.zeros(len(self.data) + \
- numpy.size(other.data))
-
- result.data = numpy.append(self.data, other.data)
- result.qx_data = numpy.append(self.qx_data, other.qx_data)
- result.qy_data = numpy.append(self.qy_data, other.qy_data)
- result.q_data = numpy.append(self.q_data, other.q_data)
- result.mask = numpy.append(self.mask, other.mask)
- if result.err_data is not None:
- result.err_data = numpy.append(self.err_data, other.err_data)
- if self.dqx_data is not None:
- result.dqx_data = numpy.append(self.dqx_data, other.dqx_data)
- if self.dqy_data is not None:
- result.dqy_data = numpy.append(self.dqy_data, other.dqy_data)
-
- return result
-
-
-def combine_data_info_with_plottable(data, datainfo):
- """
- A function that combines the DataInfo data in self.current_datainto with a plottable_1D or 2D data object.
-
- :param data: A plottable_1D or plottable_2D data object
- :return: A fully specified Data1D or Data2D object
- """
-
- final_dataset = None
- if isinstance(data, plottable_1D):
- final_dataset = Data1D(data.x, data.y)
- final_dataset.dx = data.dx
- final_dataset.dy = data.dy
- final_dataset.dxl = data.dxl
- final_dataset.dxw = data.dxw
- final_dataset.xaxis(data._xaxis, data._xunit)
- final_dataset.yaxis(data._yaxis, data._yunit)
- elif isinstance(data, plottable_2D):
- final_dataset = Data2D(data.data, data.err_data, data.qx_data, data.qy_data, data.q_data,
- data.mask, data.dqx_data, data.dqy_data)
- final_dataset.xaxis(data._xaxis, data._xunit)
- final_dataset.yaxis(data._yaxis, data._yunit)
- final_dataset.zaxis(data._zaxis, data._zunit)
- final_dataset.x_bins = data.x_bins
- final_dataset.y_bins = data.y_bins
- else:
- return_string = "Should Never Happen: _combine_data_info_with_plottable input is not a plottable1d or " + \
- "plottable2d data object"
- return return_string
-
- final_dataset.xmax = data.xmax
- final_dataset.ymax = data.ymax
- final_dataset.xmin = data.xmin
- final_dataset.ymin = data.ymin
- final_dataset.isSesans = datainfo.isSesans
- final_dataset.title = datainfo.title
- final_dataset.run = datainfo.run
- final_dataset.run_name = datainfo.run_name
- final_dataset.filename = datainfo.filename
- final_dataset.notes = datainfo.notes
- final_dataset.process = datainfo.process
- final_dataset.instrument = datainfo.instrument
- final_dataset.detector = datainfo.detector
- final_dataset.sample = datainfo.sample
- final_dataset.source = datainfo.source
- final_dataset.collimation = datainfo.collimation
- final_dataset.trans_spectrum = datainfo.trans_spectrum
- final_dataset.meta_data = datainfo.meta_data
- final_dataset.errors = datainfo.errors
- return final_dataset
+"""
+ Module that contains classes to hold information read from
+ reduced data files.
+
+ A good description of the data members can be found in
+ the CanSAS 1D XML data format:
+
+ http://www.smallangles.net/wgwiki/index.php/cansas1d_documentation
+"""
+#####################################################################
+#This software was developed by the University of Tennessee as part of the
+#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
+#project funded by the US National Science Foundation.
+#See the license text in license.txt
+#copyright 2008, University of Tennessee
+######################################################################
+
+from __future__ import print_function
+
+#TODO: Keep track of data manipulation in the 'process' data structure.
+#TODO: This module should be independent of plottables. We should write
+# an adapter class for plottables when needed.
+
+#from sas.guitools.plottables import Data1D as plottable_1D
+from sas.sascalc.data_util.uncertainty import Uncertainty
+import numpy as np
+import math
+
+class plottable_1D(object):
+ """
+ Data1D is a place holder for 1D plottables.
+ """
+ # The presence of these should be mutually
+ # exclusive with the presence of Qdev (dx)
+ x = None
+ y = None
+ dx = None
+ dy = None
+ ## Slit smearing length
+ dxl = None
+ ## Slit smearing width
+ dxw = None
+ ## SESANS specific params (wavelengths for spin echo length calculation)
+ lam = None
+ dlam = None
+
+ # Units
+ _xaxis = ''
+ _xunit = ''
+ _yaxis = ''
+ _yunit = ''
+
+ def __init__(self, x, y, dx=None, dy=None, dxl=None, dxw=None, lam=None, dlam=None):
+ self.x = np.asarray(x)
+ self.y = np.asarray(y)
+ if dx is not None:
+ self.dx = np.asarray(dx)
+ if dy is not None:
+ self.dy = np.asarray(dy)
+ if dxl is not None:
+ self.dxl = np.asarray(dxl)
+ if dxw is not None:
+ self.dxw = np.asarray(dxw)
+ if lam is not None:
+ self.lam = np.asarray(lam)
+ if dlam is not None:
+ self.dlam = np.asarray(dlam)
+
+ def xaxis(self, label, unit):
+ """
+ set the x axis label and unit
+ """
+ self._xaxis = label
+ self._xunit = unit
+
+ def yaxis(self, label, unit):
+ """
+ set the y axis label and unit
+ """
+ self._yaxis = label
+ self._yunit = unit
+
+
+class plottable_2D(object):
+ """
+ Data2D is a place holder for 2D plottables.
+ """
+ xmin = None
+ xmax = None
+ ymin = None
+ ymax = None
+ data = None
+ qx_data = None
+ qy_data = None
+ q_data = None
+ err_data = None
+ dqx_data = None
+ dqy_data = None
+ mask = None
+
+ # Units
+ _xaxis = ''
+ _xunit = ''
+ _yaxis = ''
+ _yunit = ''
+ _zaxis = ''
+ _zunit = ''
+
+ def __init__(self, data=None, err_data=None, qx_data=None,
+ qy_data=None, q_data=None, mask=None,
+ dqx_data=None, dqy_data=None):
+ self.data = np.asarray(data)
+ self.qx_data = np.asarray(qx_data)
+ self.qy_data = np.asarray(qy_data)
+ self.q_data = np.asarray(q_data)
+ self.mask = np.asarray(mask)
+ self.err_data = np.asarray(err_data)
+ if dqx_data is not None:
+ self.dqx_data = np.asarray(dqx_data)
+ if dqy_data is not None:
+ self.dqy_data = np.asarray(dqy_data)
+
+ def xaxis(self, label, unit):
+ """
+ set the x axis label and unit
+ """
+ self._xaxis = label
+ self._xunit = unit
+
+ def yaxis(self, label, unit):
+ """
+ set the y axis label and unit
+ """
+ self._yaxis = label
+ self._yunit = unit
+
+ def zaxis(self, label, unit):
+ """
+ set the z axis label and unit
+ """
+ self._zaxis = label
+ self._zunit = unit
+
+
+class Vector(object):
+ """
+ Vector class to hold multi-dimensional objects
+ """
+ ## x component
+ x = None
+ ## y component
+ y = None
+ ## z component
+ z = None
+
+ def __init__(self, x=None, y=None, z=None):
+ """
+ Initialization. Components that are not
+ set a set to None by default.
+
+ :param x: x component
+ :param y: y component
+ :param z: z component
+ """
+ self.x = x
+ self.y = y
+ self.z = z
+
+ def __str__(self):
+ msg = "x = %s\ty = %s\tz = %s" % (str(self.x), str(self.y), str(self.z))
+ return msg
+
+
+class Detector(object):
+ """
+ Class to hold detector information
+ """
+ ## Name of the instrument [string]
+ name = None
+ ## Sample to detector distance [float] [mm]
+ distance = None
+ distance_unit = 'mm'
+ ## Offset of this detector position in X, Y,
+ #(and Z if necessary) [Vector] [mm]
+ offset = None
+ offset_unit = 'm'
+ ## Orientation (rotation) of this detector in roll,
+ # pitch, and yaw [Vector] [degrees]
+ orientation = None
+ orientation_unit = 'degree'
+ ## Center of the beam on the detector in X and Y
+ #(and Z if necessary) [Vector] [mm]
+ beam_center = None
+ beam_center_unit = 'mm'
+ ## Pixel size in X, Y, (and Z if necessary) [Vector] [mm]
+ pixel_size = None
+ pixel_size_unit = 'mm'
+ ## Slit length of the instrument for this detector.[float] [mm]
+ slit_length = None
+ slit_length_unit = 'mm'
+
+ def __init__(self):
+ """
+ Initialize class attribute that are objects...
+ """
+ self.offset = Vector()
+ self.orientation = Vector()
+ self.beam_center = Vector()
+ self.pixel_size = Vector()
+
+ def __str__(self):
+ _str = "Detector:\n"
+ _str += " Name: %s\n" % self.name
+ _str += " Distance: %s [%s]\n" % \
+ (str(self.distance), str(self.distance_unit))
+ _str += " Offset: %s [%s]\n" % \
+ (str(self.offset), str(self.offset_unit))
+ _str += " Orientation: %s [%s]\n" % \
+ (str(self.orientation), str(self.orientation_unit))
+ _str += " Beam center: %s [%s]\n" % \
+ (str(self.beam_center), str(self.beam_center_unit))
+ _str += " Pixel size: %s [%s]\n" % \
+ (str(self.pixel_size), str(self.pixel_size_unit))
+ _str += " Slit length: %s [%s]\n" % \
+ (str(self.slit_length), str(self.slit_length_unit))
+ return _str
+
+
+class Aperture(object):
+ ## Name
+ name = None
+ ## Type
+ type = None
+ ## Size name
+ size_name = None
+ ## Aperture size [Vector]
+ size = None
+ size_unit = 'mm'
+ ## Aperture distance [float]
+ distance = None
+ distance_unit = 'mm'
+
+ def __init__(self):
+ self.size = Vector()
+
+
+class Collimation(object):
+ """
+ Class to hold collimation information
+ """
+ ## Name
+ name = None
+ ## Length [float] [mm]
+ length = None
+ length_unit = 'mm'
+ ## Aperture
+ aperture = None
+
+ def __init__(self):
+ self.aperture = []
+
+ def __str__(self):
+ _str = "Collimation:\n"
+ _str += " Length: %s [%s]\n" % \
+ (str(self.length), str(self.length_unit))
+ for item in self.aperture:
+ _str += " Aperture size:%s [%s]\n" % \
+ (str(item.size), str(item.size_unit))
+ _str += " Aperture_dist:%s [%s]\n" % \
+ (str(item.distance), str(item.distance_unit))
+ return _str
+
+
+class Source(object):
+ """
+ Class to hold source information
+ """
+ ## Name
+ name = None
+ ## Radiation type [string]
+ radiation = None
+ ## Beam size name
+ beam_size_name = None
+ ## Beam size [Vector] [mm]
+ beam_size = None
+ beam_size_unit = 'mm'
+ ## Beam shape [string]
+ beam_shape = None
+ ## Wavelength [float] [Angstrom]
+ wavelength = None
+ wavelength_unit = 'A'
+ ## Minimum wavelength [float] [Angstrom]
+ wavelength_min = None
+ wavelength_min_unit = 'nm'
+ ## Maximum wavelength [float] [Angstrom]
+ wavelength_max = None
+ wavelength_max_unit = 'nm'
+ ## Wavelength spread [float] [Angstrom]
+ wavelength_spread = None
+ wavelength_spread_unit = 'percent'
+
+ def __init__(self):
+ self.beam_size = Vector()
+
+ def __str__(self):
+ _str = "Source:\n"
+ _str += " Radiation: %s\n" % str(self.radiation)
+ _str += " Shape: %s\n" % str(self.beam_shape)
+ _str += " Wavelength: %s [%s]\n" % \
+ (str(self.wavelength), str(self.wavelength_unit))
+ _str += " Waveln_min: %s [%s]\n" % \
+ (str(self.wavelength_min), str(self.wavelength_min_unit))
+ _str += " Waveln_max: %s [%s]\n" % \
+ (str(self.wavelength_max), str(self.wavelength_max_unit))
+ _str += " Waveln_spread:%s [%s]\n" % \
+ (str(self.wavelength_spread), str(self.wavelength_spread_unit))
+ _str += " Beam_size: %s [%s]\n" % \
+ (str(self.beam_size), str(self.beam_size_unit))
+ return _str
+
+
+"""
+Definitions of radiation types
+"""
+NEUTRON = 'neutron'
+XRAY = 'x-ray'
+MUON = 'muon'
+ELECTRON = 'electron'
+
+
+class Sample(object):
+ """
+ Class to hold the sample description
+ """
+ ## Short name for sample
+ name = ''
+ ## ID
+ ID = ''
+ ## Thickness [float] [mm]
+ thickness = None
+ thickness_unit = 'mm'
+ ## Transmission [float] [fraction]
+ transmission = None
+ ## Temperature [float] [No Default]
+ temperature = None
+ temperature_unit = None
+ ## Position [Vector] [mm]
+ position = None
+ position_unit = 'mm'
+ ## Orientation [Vector] [degrees]
+ orientation = None
+ orientation_unit = 'degree'
+ ## Details
+ details = None
+ ## SESANS zacceptance
+ zacceptance = (0,"")
+ yacceptance = (0,"")
+
+ def __init__(self):
+ self.position = Vector()
+ self.orientation = Vector()
+ self.details = []
+
+ def __str__(self):
+ _str = "Sample:\n"
+ _str += " ID: %s\n" % str(self.ID)
+ _str += " Transmission: %s\n" % str(self.transmission)
+ _str += " Thickness: %s [%s]\n" % \
+ (str(self.thickness), str(self.thickness_unit))
+ _str += " Temperature: %s [%s]\n" % \
+ (str(self.temperature), str(self.temperature_unit))
+ _str += " Position: %s [%s]\n" % \
+ (str(self.position), str(self.position_unit))
+ _str += " Orientation: %s [%s]\n" % \
+ (str(self.orientation), str(self.orientation_unit))
+
+ _str += " Details:\n"
+ for item in self.details:
+ _str += " %s\n" % item
+
+ return _str
+
+
+class Process(object):
+ """
+ Class that holds information about the processes
+ performed on the data.
+ """
+ name = ''
+ date = ''
+ description = ''
+ term = None
+ notes = None
+
+ def __init__(self):
+ self.term = []
+ self.notes = []
+
+ def is_empty(self):
+ """
+ Return True if the object is empty
+ """
+ return len(self.name) == 0 and len(self.date) == 0 and len(self.description) == 0 \
+ and len(self.term) == 0 and len(self.notes) == 0
+
+ def single_line_desc(self):
+ """
+ Return a single line string representing the process
+ """
+ return "%s %s %s" % (self.name, self.date, self.description)
+
+ def __str__(self):
+ _str = "Process:\n"
+ _str += " Name: %s\n" % self.name
+ _str += " Date: %s\n" % self.date
+ _str += " Description: %s\n" % self.description
+ for item in self.term:
+ _str += " Term: %s\n" % item
+ for item in self.notes:
+ _str += " Note: %s\n" % item
+ return _str
+
+
+class TransmissionSpectrum(object):
+ """
+ Class that holds information about transmission spectrum
+ for white beams and spallation sources.
+ """
+ name = ''
+ timestamp = ''
+ ## Wavelength (float) [A]
+ wavelength = None
+ wavelength_unit = 'A'
+ ## Transmission (float) [unit less]
+ transmission = None
+ transmission_unit = ''
+ ## Transmission Deviation (float) [unit less]
+ transmission_deviation = None
+ transmission_deviation_unit = ''
+
+ def __init__(self):
+ self.wavelength = []
+ self.transmission = []
+ self.transmission_deviation = []
+
+ def __str__(self):
+ _str = "Transmission Spectrum:\n"
+ _str += " Name: \t{0}\n".format(self.name)
+ _str += " Timestamp: \t{0}\n".format(self.timestamp)
+ _str += " Wavelength unit: \t{0}\n".format(self.wavelength_unit)
+ _str += " Transmission unit:\t{0}\n".format(self.transmission_unit)
+ _str += " Trans. Dev. unit: \t{0}\n".format(\
+ self.transmission_deviation_unit)
+ length_list = [len(self.wavelength), len(self.transmission), \
+ len(self.transmission_deviation)]
+ _str += " Number of Pts: \t{0}\n".format(max(length_list))
+ return _str
+
+
+class DataInfo(object):
+ """
+ Class to hold the data read from a file.
+ It includes four blocks of data for the
+ instrument description, the sample description,
+ the data itself and any other meta data.
+ """
+ ## Title
+ title = ''
+ ## Run number
+ run = None
+ ## Run name
+ run_name = None
+ ## File name
+ filename = ''
+ ## Notes
+ notes = None
+ ## Processes (Action on the data)
+ process = None
+ ## Instrument name
+ instrument = ''
+ ## Detector information
+ detector = None
+ ## Sample information
+ sample = None
+ ## Source information
+ source = None
+ ## Collimation information
+ collimation = None
+ ## Transmission Spectrum INfo
+ trans_spectrum = None
+ ## Additional meta-data
+ meta_data = None
+ ## Loading errors
+ errors = None
+ ## SESANS data check
+ isSesans = None
+
+
+ def __init__(self):
+ """
+ Initialization
+ """
+ ## Title
+ self.title = ''
+ ## Run number
+ self.run = []
+ self.run_name = {}
+ ## File name
+ self.filename = ''
+ ## Notes
+ self.notes = []
+ ## Processes (Action on the data)
+ self.process = []
+ ## Instrument name
+ self.instrument = ''
+ ## Detector information
+ self.detector = []
+ ## Sample information
+ self.sample = Sample()
+ ## Source information
+ self.source = Source()
+ ## Collimation information
+ self.collimation = []
+ ## Transmission Spectrum
+ self.trans_spectrum = []
+ ## Additional meta-data
+ self.meta_data = {}
+ ## Loading errors
+ self.errors = []
+ ## SESANS data check
+ self.isSesans = False
+
+ def append_empty_process(self):
+ """
+ """
+ self.process.append(Process())
+
+ def add_notes(self, message=""):
+ """
+ Add notes to datainfo
+ """
+ self.notes.append(message)
+
+ def __str__(self):
+ """
+ Nice printout
+ """
+ _str = "File: %s\n" % self.filename
+ _str += "Title: %s\n" % self.title
+ _str += "Run: %s\n" % str(self.run)
+ _str += "SESANS: %s\n" % str(self.isSesans)
+ _str += "Instrument: %s\n" % str(self.instrument)
+ _str += "%s\n" % str(self.sample)
+ _str += "%s\n" % str(self.source)
+ for item in self.detector:
+ _str += "%s\n" % str(item)
+ for item in self.collimation:
+ _str += "%s\n" % str(item)
+ for item in self.process:
+ _str += "%s\n" % str(item)
+ for item in self.notes:
+ _str += "%s\n" % str(item)
+ for item in self.trans_spectrum:
+ _str += "%s\n" % str(item)
+ return _str
+
+ # Private method to perform operation. Not implemented for DataInfo,
+ # but should be implemented for each data class inherited from DataInfo
+ # that holds actual data (ex.: Data1D)
+ def _perform_operation(self, other, operation):
+ """
+ Private method to perform operation. Not implemented for DataInfo,
+ but should be implemented for each data class inherited from DataInfo
+ that holds actual data (ex.: Data1D)
+ """
+ return NotImplemented
+
+ def _perform_union(self, other):
+ """
+ Private method to perform union operation. Not implemented for DataInfo,
+ but should be implemented for each data class inherited from DataInfo
+ that holds actual data (ex.: Data1D)
+ """
+ return NotImplemented
+
+ def __add__(self, other):
+ """
+ Add two data sets
+
+ :param other: data set to add to the current one
+ :return: new data set
+ :raise ValueError: raised when two data sets are incompatible
+ """
+ def operation(a, b):
+ return a + b
+ return self._perform_operation(other, operation)
+
+ def __radd__(self, other):
+ """
+ Add two data sets
+
+ :param other: data set to add to the current one
+ :return: new data set
+ :raise ValueError: raised when two data sets are incompatible
+ """
+ def operation(a, b):
+ return b + a
+ return self._perform_operation(other, operation)
+
+ def __sub__(self, other):
+ """
+ Subtract two data sets
+
+ :param other: data set to subtract from the current one
+ :return: new data set
+ :raise ValueError: raised when two data sets are incompatible
+ """
+ def operation(a, b):
+ return a - b
+ return self._perform_operation(other, operation)
+
+ def __rsub__(self, other):
+ """
+ Subtract two data sets
+
+ :param other: data set to subtract from the current one
+ :return: new data set
+ :raise ValueError: raised when two data sets are incompatible
+ """
+ def operation(a, b):
+ return b - a
+ return self._perform_operation(other, operation)
+
+ def __mul__(self, other):
+ """
+ Multiply two data sets
+
+ :param other: data set to subtract from the current one
+ :return: new data set
+ :raise ValueError: raised when two data sets are incompatible
+ """
+ def operation(a, b):
+ return a * b
+ return self._perform_operation(other, operation)
+
+ def __rmul__(self, other):
+ """
+ Multiply two data sets
+
+ :param other: data set to subtract from the current one
+ :return: new data set
+ :raise ValueError: raised when two data sets are incompatible
+ """
+ def operation(a, b):
+ return b * a
+ return self._perform_operation(other, operation)
+
+ def __div__(self, other):
+ """
+ Divided a data set by another
+
+ :param other: data set that the current one is divided by
+ :return: new data set
+ :raise ValueError: raised when two data sets are incompatible
+ """
+ def operation(a, b):
+ return a/b
+ return self._perform_operation(other, operation)
+
+ def __rdiv__(self, other):
+ """
+ Divided a data set by another
+
+ :param other: data set that the current one is divided by
+ :return: new data set
+ :raise ValueError: raised when two data sets are incompatible
+ """
+ def operation(a, b):
+ return b/a
+ return self._perform_operation(other, operation)
+
+ def __or__(self, other):
+ """
+ Union a data set with another
+
+ :param other: data set to be unified
+ :return: new data set
+ :raise ValueError: raised when two data sets are incompatible
+ """
+ return self._perform_union(other)
+
+ def __ror__(self, other):
+ """
+ Union a data set with another
+
+ :param other: data set to be unified
+ :return: new data set
+ :raise ValueError: raised when two data sets are incompatible
+ """
+ return self._perform_union(other)
+
+class Data1D(plottable_1D, DataInfo):
+ """
+ 1D data class
+ """
+ def __init__(self, x=None, y=None, dx=None, dy=None, lam=None, dlam=None, isSesans=None):
+ DataInfo.__init__(self)
+ plottable_1D.__init__(self, x, y, dx, dy,None, None, lam, dlam)
+ self.isSesans = isSesans
+ try:
+ if self.isSesans: # the data is SESANS
+ self.x_unit = 'A'
+ self.y_unit = 'pol'
+ elif not self.isSesans: # the data is SANS
+ self.x_unit = '1/A'
+ self.y_unit = '1/cm'
+ except: # the data is not recognized/supported, and the user is notified
+ raise TypeError('data not recognized, check documentation for supported 1D data formats')
+
+ def __str__(self):
+ """
+ Nice printout
+ """
+ _str = "%s\n" % DataInfo.__str__(self)
+ _str += "Data:\n"
+ _str += " Type: %s\n" % self.__class__.__name__
+ _str += " X-axis: %s\t[%s]\n" % (self._xaxis, self._xunit)
+ _str += " Y-axis: %s\t[%s]\n" % (self._yaxis, self._yunit)
+ _str += " Length: %g\n" % len(self.x)
+ return _str
+
+ def is_slit_smeared(self):
+ """
+ Check whether the data has slit smearing information
+ :return: True is slit smearing info is present, False otherwise
+ """
+ def _check(v):
+ if (v.__class__ == list or v.__class__ == np.ndarray) \
+ and len(v) > 0 and min(v) > 0:
+ return True
+ return False
+ return _check(self.dxl) or _check(self.dxw)
+
+ def clone_without_data(self, length=0, clone=None):
+ """
+ Clone the current object, without copying the data (which
+ will be filled out by a subsequent operation).
+ The data arrays will be initialized to zero.
+
+ :param length: length of the data array to be initialized
+ :param clone: if provided, the data will be copied to clone
+ """
+ from copy import deepcopy
+
+ if clone is None or not issubclass(clone.__class__, Data1D):
+ x = np.zeros(length)
+ dx = np.zeros(length)
+ y = np.zeros(length)
+ dy = np.zeros(length)
+ lam = np.zeros(length)
+ dlam = np.zeros(length)
+ clone = Data1D(x, y, lam=lam, dx=dx, dy=dy, dlam=dlam)
+
+ clone.title = self.title
+ clone.run = self.run
+ clone.filename = self.filename
+ clone.instrument = self.instrument
+ clone.notes = deepcopy(self.notes)
+ clone.process = deepcopy(self.process)
+ clone.detector = deepcopy(self.detector)
+ clone.sample = deepcopy(self.sample)
+ clone.source = deepcopy(self.source)
+ clone.collimation = deepcopy(self.collimation)
+ clone.trans_spectrum = deepcopy(self.trans_spectrum)
+ clone.meta_data = deepcopy(self.meta_data)
+ clone.errors = deepcopy(self.errors)
+
+ return clone
+
+ def _validity_check(self, other):
+ """
+ Checks that the data lengths are compatible.
+ Checks that the x vectors are compatible.
+ Returns errors vectors equal to original
+ errors vectors if they were present or vectors
+ of zeros when none was found.
+
+ :param other: other data set for operation
+ :return: dy for self, dy for other [numpy arrays]
+ :raise ValueError: when lengths are not compatible
+ """
+ dy_other = None
+ if isinstance(other, Data1D):
+ # Check that data lengths are the same
+ if len(self.x) != len(other.x) or \
+ len(self.y) != len(other.y):
+ msg = "Unable to perform operation: data length are not equal"
+ raise ValueError(msg)
+ # Here we could also extrapolate between data points
+ TOLERANCE = 0.01
+ for i in range(len(self.x)):
+ if math.fabs((self.x[i] - other.x[i])/self.x[i]) > TOLERANCE:
+ msg = "Incompatible data sets: x-values do not match"
+ raise ValueError(msg)
+
+ # Check that the other data set has errors, otherwise
+ # create zero vector
+ dy_other = other.dy
+ if other.dy is None or (len(other.dy) != len(other.y)):
+ dy_other = np.zeros(len(other.y))
+
+ # Check that we have errors, otherwise create zero vector
+ dy = self.dy
+ if self.dy is None or (len(self.dy) != len(self.y)):
+ dy = np.zeros(len(self.y))
+
+ return dy, dy_other
+
+ def _perform_operation(self, other, operation):
+ """
+ """
+ # First, check the data compatibility
+ dy, dy_other = self._validity_check(other)
+ result = self.clone_without_data(len(self.x))
+ if self.dxw is None:
+ result.dxw = None
+ else:
+ result.dxw = np.zeros(len(self.x))
+ if self.dxl is None:
+ result.dxl = None
+ else:
+ result.dxl = np.zeros(len(self.x))
+
+ for i in range(len(self.x)):
+ result.x[i] = self.x[i]
+ if self.dx is not None and len(self.x) == len(self.dx):
+ result.dx[i] = self.dx[i]
+ if self.dxw is not None and len(self.x) == len(self.dxw):
+ result.dxw[i] = self.dxw[i]
+ if self.dxl is not None and len(self.x) == len(self.dxl):
+ result.dxl[i] = self.dxl[i]
+
+ a = Uncertainty(self.y[i], dy[i]**2)
+ if isinstance(other, Data1D):
+ b = Uncertainty(other.y[i], dy_other[i]**2)
+ if other.dx is not None:
+ result.dx[i] *= self.dx[i]
+ result.dx[i] += (other.dx[i]**2)
+ result.dx[i] /= 2
+ result.dx[i] = math.sqrt(result.dx[i])
+ if result.dxl is not None and other.dxl is not None:
+ result.dxl[i] *= self.dxl[i]
+ result.dxl[i] += (other.dxl[i]**2)
+ result.dxl[i] /= 2
+ result.dxl[i] = math.sqrt(result.dxl[i])
+ else:
+ b = other
+
+ output = operation(a, b)
+ result.y[i] = output.x
+ result.dy[i] = math.sqrt(math.fabs(output.variance))
+ return result
+
+ def _validity_check_union(self, other):
+ """
+ Checks that the data lengths are compatible.
+ Checks that the x vectors are compatible.
+ Returns errors vectors equal to original
+ errors vectors if they were present or vectors
+ of zeros when none was found.
+
+ :param other: other data set for operation
+ :return: bool
+ :raise ValueError: when data types are not compatible
+ """
+ if not isinstance(other, Data1D):
+ msg = "Unable to perform operation: different types of data set"
+ raise ValueError(msg)
+ return True
+
+ def _perform_union(self, other):
+ """
+ """
+ # First, check the data compatibility
+ self._validity_check_union(other)
+ result = self.clone_without_data(len(self.x) + len(other.x))
+ if self.dy is None or other.dy is None:
+ result.dy = None
+ else:
+ result.dy = np.zeros(len(self.x) + len(other.x))
+ if self.dx is None or other.dx is None:
+ result.dx = None
+ else:
+ result.dx = np.zeros(len(self.x) + len(other.x))
+ if self.dxw is None or other.dxw is None:
+ result.dxw = None
+ else:
+ result.dxw = np.zeros(len(self.x) + len(other.x))
+ if self.dxl is None or other.dxl is None:
+ result.dxl = None
+ else:
+ result.dxl = np.zeros(len(self.x) + len(other.x))
+
+ result.x = np.append(self.x, other.x)
+ #argsorting
+ ind = np.argsort(result.x)
+ result.x = result.x[ind]
+ result.y = np.append(self.y, other.y)
+ result.y = result.y[ind]
+ if result.dy is not None:
+ result.dy = np.append(self.dy, other.dy)
+ result.dy = result.dy[ind]
+ if result.dx is not None:
+ result.dx = np.append(self.dx, other.dx)
+ result.dx = result.dx[ind]
+ if result.dxw is not None:
+ result.dxw = np.append(self.dxw, other.dxw)
+ result.dxw = result.dxw[ind]
+ if result.dxl is not None:
+ result.dxl = np.append(self.dxl, other.dxl)
+ result.dxl = result.dxl[ind]
+ return result
+
+
+class Data2D(plottable_2D, DataInfo):
+ """
+ 2D data class
+ """
+ ## Units for Q-values
+ Q_unit = '1/A'
+ ## Units for I(Q) values
+ I_unit = '1/cm'
+ ## Vector of Q-values at the center of each bin in x
+ x_bins = None
+ ## Vector of Q-values at the center of each bin in y
+ y_bins = None
+ ## No 2D SESANS data as of yet. Always set it to False
+ isSesans = False
+
+ def __init__(self, data=None, err_data=None, qx_data=None,
+ qy_data=None, q_data=None, mask=None,
+ dqx_data=None, dqy_data=None):
+ DataInfo.__init__(self)
+ plottable_2D.__init__(self, data, err_data, qx_data,
+ qy_data, q_data, mask, dqx_data, dqy_data)
+ self.y_bins = []
+ self.x_bins = []
+
+ if len(self.detector) > 0:
+ raise RuntimeError("Data2D: Detector bank already filled at init")
+
+ def __str__(self):
+ _str = "%s\n" % DataInfo.__str__(self)
+ _str += "Data:\n"
+ _str += " Type: %s\n" % self.__class__.__name__
+ _str += " X- & Y-axis: %s\t[%s]\n" % (self._yaxis, self._yunit)
+ _str += " Z-axis: %s\t[%s]\n" % (self._zaxis, self._zunit)
+ _str += " Length: %g \n" % (len(self.data))
+ _str += " Shape: (%d, %d)\n" % (len(self.y_bins), len(self.x_bins))
+ return _str
+
+ def clone_without_data(self, length=0, clone=None):
+ """
+ Clone the current object, without copying the data (which
+ will be filled out by a subsequent operation).
+ The data arrays will be initialized to zero.
+
+ :param length: length of the data array to be initialized
+ :param clone: if provided, the data will be copied to clone
+ """
+ from copy import deepcopy
+
+ if clone is None or not issubclass(clone.__class__, Data2D):
+ data = np.zeros(length)
+ err_data = np.zeros(length)
+ qx_data = np.zeros(length)
+ qy_data = np.zeros(length)
+ q_data = np.zeros(length)
+ mask = np.zeros(length)
+ dqx_data = None
+ dqy_data = None
+ clone = Data2D(data=data, err_data=err_data,
+ qx_data=qx_data, qy_data=qy_data,
+ q_data=q_data, mask=mask)
+
+ clone.title = self.title
+ clone.run = self.run
+ clone.filename = self.filename
+ clone.instrument = self.instrument
+ clone.notes = deepcopy(self.notes)
+ clone.process = deepcopy(self.process)
+ clone.detector = deepcopy(self.detector)
+ clone.sample = deepcopy(self.sample)
+ clone.source = deepcopy(self.source)
+ clone.collimation = deepcopy(self.collimation)
+ clone.trans_spectrum = deepcopy(self.trans_spectrum)
+ clone.meta_data = deepcopy(self.meta_data)
+ clone.errors = deepcopy(self.errors)
+
+ return clone
+
+ def _validity_check(self, other):
+ """
+ Checks that the data lengths are compatible.
+ Checks that the x vectors are compatible.
+ Returns errors vectors equal to original
+ errors vectors if they were present or vectors
+ of zeros when none was found.
+
+ :param other: other data set for operation
+ :return: dy for self, dy for other [numpy arrays]
+ :raise ValueError: when lengths are not compatible
+ """
+ err_other = None
+ TOLERANCE = 0.01
+ if isinstance(other, Data2D):
+ # Check that data lengths are the same
+ if len(self.data) != len(other.data) or \
+ len(self.qx_data) != len(other.qx_data) or \
+ len(self.qy_data) != len(other.qy_data):
+ msg = "Unable to perform operation: data length are not equal"
+ raise ValueError(msg)
+ for ind in range(len(self.data)):
+ if math.fabs((self.qx_data[ind] - other.qx_data[ind])/self.qx_data[ind]) > TOLERANCE:
+ msg = "Incompatible data sets: qx-values do not match: %s %s" % (self.qx_data[ind], other.qx_data[ind])
+ raise ValueError(msg)
+ if math.fabs((self.qy_data[ind] - other.qy_data[ind])/self.qy_data[ind]) > TOLERANCE:
+ msg = "Incompatible data sets: qy-values do not match: %s %s" % (self.qy_data[ind], other.qy_data[ind])
+ raise ValueError(msg)
+
+ # Check that the scales match
+ err_other = other.err_data
+ if other.err_data is None or \
+ (len(other.err_data) != len(other.data)):
+ err_other = np.zeros(len(other.data))
+
+ # Check that we have errors, otherwise create zero vector
+ err = self.err_data
+ if self.err_data is None or \
+ (len(self.err_data) != len(self.data)):
+ err = np.zeros(len(other.data))
+ return err, err_other
+
+ def _perform_operation(self, other, operation):
+ """
+ Perform 2D operations between data sets
+
+ :param other: other data set
+ :param operation: function defining the operation
+ """
+ # First, check the data compatibility
+ dy, dy_other = self._validity_check(other)
+ result = self.clone_without_data(np.size(self.data))
+ if self.dqx_data is None or self.dqy_data is None:
+ result.dqx_data = None
+ result.dqy_data = None
+ else:
+ result.dqx_data = np.zeros(len(self.data))
+ result.dqy_data = np.zeros(len(self.data))
+ for i in range(np.size(self.data)):
+ result.data[i] = self.data[i]
+ if self.err_data is not None and \
+ np.size(self.data) == np.size(self.err_data):
+ result.err_data[i] = self.err_data[i]
+ if self.dqx_data is not None:
+ result.dqx_data[i] = self.dqx_data[i]
+ if self.dqy_data is not None:
+ result.dqy_data[i] = self.dqy_data[i]
+ result.qx_data[i] = self.qx_data[i]
+ result.qy_data[i] = self.qy_data[i]
+ result.q_data[i] = self.q_data[i]
+ result.mask[i] = self.mask[i]
+
+ a = Uncertainty(self.data[i], dy[i]**2)
+ if isinstance(other, Data2D):
+ b = Uncertainty(other.data[i], dy_other[i]**2)
+ if other.dqx_data is not None and \
+ result.dqx_data is not None:
+ result.dqx_data[i] *= self.dqx_data[i]
+ result.dqx_data[i] += (other.dqx_data[i]**2)
+ result.dqx_data[i] /= 2
+ result.dqx_data[i] = math.sqrt(result.dqx_data[i])
+ if other.dqy_data is not None and \
+ result.dqy_data is not None:
+ result.dqy_data[i] *= self.dqy_data[i]
+ result.dqy_data[i] += (other.dqy_data[i]**2)
+ result.dqy_data[i] /= 2
+ result.dqy_data[i] = math.sqrt(result.dqy_data[i])
+ else:
+ b = other
+ output = operation(a, b)
+ result.data[i] = output.x
+ result.err_data[i] = math.sqrt(math.fabs(output.variance))
+ return result
+
+ def _validity_check_union(self, other):
+ """
+ Checks that the data lengths are compatible.
+ Checks that the x vectors are compatible.
+ Returns errors vectors equal to original
+ errors vectors if they were present or vectors
+ of zeros when none was found.
+
+ :param other: other data set for operation
+ :return: bool
+ :raise ValueError: when data types are not compatible
+ """
+ if not isinstance(other, Data2D):
+ msg = "Unable to perform operation: different types of data set"
+ raise ValueError(msg)
+ return True
+
+ def _perform_union(self, other):
+ """
+ Perform 2D operations between data sets
+
+ :param other: other data set
+ :param operation: function defining the operation
+ """
+ # First, check the data compatibility
+ self._validity_check_union(other)
+ result = self.clone_without_data(np.size(self.data) + \
+ np.size(other.data))
+ result.xmin = self.xmin
+ result.xmax = self.xmax
+ result.ymin = self.ymin
+ result.ymax = self.ymax
+ if self.dqx_data is None or self.dqy_data is None or \
+ other.dqx_data is None or other.dqy_data is None:
+ result.dqx_data = None
+ result.dqy_data = None
+ else:
+ result.dqx_data = np.zeros(len(self.data) + \
+ np.size(other.data))
+ result.dqy_data = np.zeros(len(self.data) + \
+ np.size(other.data))
+
+ result.data = np.append(self.data, other.data)
+ result.qx_data = np.append(self.qx_data, other.qx_data)
+ result.qy_data = np.append(self.qy_data, other.qy_data)
+ result.q_data = np.append(self.q_data, other.q_data)
+ result.mask = np.append(self.mask, other.mask)
+ if result.err_data is not None:
+ result.err_data = np.append(self.err_data, other.err_data)
+ if self.dqx_data is not None:
+ result.dqx_data = np.append(self.dqx_data, other.dqx_data)
+ if self.dqy_data is not None:
+ result.dqy_data = np.append(self.dqy_data, other.dqy_data)
+
+ return result
+
+
+def combine_data_info_with_plottable(data, datainfo):
+ """
+ A function that combines the DataInfo data in self.current_datainto with a plottable_1D or 2D data object.
+
+ :param data: A plottable_1D or plottable_2D data object
+ :return: A fully specified Data1D or Data2D object
+ """
+
+ final_dataset = None
+ if isinstance(data, plottable_1D):
+ final_dataset = Data1D(data.x, data.y, isSesans=datainfo.isSesans)
+ final_dataset.dx = data.dx
+ final_dataset.dy = data.dy
+ final_dataset.dxl = data.dxl
+ final_dataset.dxw = data.dxw
+ final_dataset.x_unit = data._xunit
+ final_dataset.y_unit = data._yunit
+ final_dataset.xaxis(data._xaxis, data._xunit)
+ final_dataset.yaxis(data._yaxis, data._yunit)
+ elif isinstance(data, plottable_2D):
+ final_dataset = Data2D(data.data, data.err_data, data.qx_data, data.qy_data, data.q_data,
+ data.mask, data.dqx_data, data.dqy_data)
+ final_dataset.xaxis(data._xaxis, data._xunit)
+ final_dataset.yaxis(data._yaxis, data._yunit)
+ final_dataset.zaxis(data._zaxis, data._zunit)
+ if len(data.data.shape) == 2:
+ n_rows, n_cols = data.data.shape
+ final_dataset.y_bins = data.qy_data[0::int(n_cols)]
+ final_dataset.x_bins = data.qx_data[:int(n_cols)]
+ else:
+ return_string = "Should Never Happen: _combine_data_info_with_plottable input is not a plottable1d or " + \
+ "plottable2d data object"
+ return return_string
+
+ if hasattr(data, "xmax"):
+ final_dataset.xmax = data.xmax
+ if hasattr(data, "ymax"):
+ final_dataset.ymax = data.ymax
+ if hasattr(data, "xmin"):
+ final_dataset.xmin = data.xmin
+ if hasattr(data, "ymin"):
+ final_dataset.ymin = data.ymin
+ final_dataset.isSesans = datainfo.isSesans
+ final_dataset.title = datainfo.title
+ final_dataset.run = datainfo.run
+ final_dataset.run_name = datainfo.run_name
+ final_dataset.filename = datainfo.filename
+ final_dataset.notes = datainfo.notes
+ final_dataset.process = datainfo.process
+ final_dataset.instrument = datainfo.instrument
+ final_dataset.detector = datainfo.detector
+ final_dataset.sample = datainfo.sample
+ final_dataset.source = datainfo.source
+ final_dataset.collimation = datainfo.collimation
+ final_dataset.trans_spectrum = datainfo.trans_spectrum
+ final_dataset.meta_data = datainfo.meta_data
+ final_dataset.errors = datainfo.errors
+ return final_dataset
diff --git a/src/sas/sascalc/dataloader/file_reader_base_class.py b/src/sas/sascalc/dataloader/file_reader_base_class.py
new file mode 100644
index 0000000..6504096
--- /dev/null
+++ b/src/sas/sascalc/dataloader/file_reader_base_class.py
@@ -0,0 +1,347 @@
+"""
+This is the base file reader class most file readers should inherit from.
+All generic functionality required for a file loader/reader is built into this
+class
+"""
+
+import os
+import sys
+import re
+import logging
+from abc import abstractmethod
+
+import numpy as np
+from .loader_exceptions import NoKnownLoaderException, FileContentsException,\
+ DataReaderException, DefaultReaderException
+from .data_info import Data1D, Data2D, DataInfo, plottable_1D, plottable_2D,\
+ combine_data_info_with_plottable
+
+logger = logging.getLogger(__name__)
+
+if sys.version_info[0] < 3:
+ def decode(s):
+ return s
+else:
+ def decode(s):
+ return s.decode() if isinstance(s, bytes) else s
+
+class FileReader(object):
+ # List of Data1D and Data2D objects to be sent back to data_loader
+ output = []
+ # Current plottable_(1D/2D) object being loaded in
+ current_dataset = None
+ # Current DataInfo object being loaded in
+ current_datainfo = None
+ # String to describe the type of data this reader can load
+ type_name = "ASCII"
+ # Wildcards to display
+ type = ["Text files (*.txt|*.TXT)"]
+ # List of allowed extensions
+ ext = ['.txt']
+ # Bypass extension check and try to load anyway
+ allow_all = False
+ # Able to import the unit converter
+ has_converter = True
+ # Open file handle
+ f_open = None
+ # Default value of zero
+ _ZERO = 1e-16
+
+ def read(self, filepath):
+ """
+ Basic file reader
+
+ :param filepath: The full or relative path to a file to be loaded
+ """
+ if os.path.isfile(filepath):
+ basename, extension = os.path.splitext(os.path.basename(filepath))
+ self.extension = extension.lower()
+ # If the file type is not allowed, return nothing
+ if self.extension in self.ext or self.allow_all:
+ # Try to load the file, but raise an error if unable to.
+ try:
+ self.f_open = open(filepath, 'rb')
+ self.get_file_contents()
+
+ except DataReaderException as e:
+ self.handle_error_message(e.message)
+ except OSError as e:
+ # If the file cannot be opened
+ msg = "Unable to open file: {}\n".format(filepath)
+ msg += e.message
+ self.handle_error_message(msg)
+ finally:
+ # Close the file handle if it is open
+ if not self.f_open.closed:
+ self.f_open.close()
+ if len(self.output) > 0:
+ # Sort the data that's been loaded
+ self.sort_one_d_data()
+ self.sort_two_d_data()
+ else:
+ msg = "Unable to find file at: {}\n".format(filepath)
+ msg += "Please check your file path and try again."
+ self.handle_error_message(msg)
+
+ # Return a list of parsed entries that data_loader can manage
+ final_data = self.output
+ self.reset_state()
+ return final_data
+
+ def reset_state(self):
+ """
+ Resets the class state to a base case when loading a new data file so previous
+ data files do not appear a second time
+ """
+ self.current_datainfo = None
+ self.current_dataset = None
+ self.output = []
+
+ def nextline(self):
+ """
+ Returns the next line in the file as a string.
+ """
+ #return self.f_open.readline()
+ return decode(self.f_open.readline())
+
+ def nextlines(self):
+ """
+ Returns the next line in the file as a string.
+ """
+ for line in self.f_open:
+ #yield line
+ yield decode(line)
+
+ def readall(self):
+ """
+ Returns the entire file as a string.
+ """
+ #return self.f_open.read()
+ return decode(self.f_open.read())
+
+ def handle_error_message(self, msg):
+ """
+ Generic error handler to add an error to the current datainfo to
+ propogate the error up the error chain.
+ :param msg: Error message
+ """
+ if len(self.output) > 0:
+ self.output[-1].errors.append(msg)
+ elif isinstance(self.current_datainfo, DataInfo):
+ self.current_datainfo.errors.append(msg)
+ else:
+ logger.warning(msg)
+
+ def send_to_output(self):
+ """
+ Helper that automatically combines the info and set and then appends it
+ to output
+ """
+ data_obj = combine_data_info_with_plottable(self.current_dataset,
+ self.current_datainfo)
+ self.output.append(data_obj)
+
+ def sort_one_d_data(self):
+ """
+ Sort 1D data along the X axis for consistency
+ """
+ for data in self.output:
+ if isinstance(data, Data1D):
+ # Normalize the units for
+ data.x_unit = self.format_unit(data.x_unit)
+ data.y_unit = self.format_unit(data.y_unit)
+ # Sort data by increasing x and remove 1st point
+ ind = np.lexsort((data.y, data.x))
+ data.x = np.asarray([data.x[i] for i in ind]).astype(np.float64)
+ data.y = np.asarray([data.y[i] for i in ind]).astype(np.float64)
+ if data.dx is not None:
+ if len(data.dx) == 0:
+ data.dx = None
+ continue
+ data.dx = np.asarray([data.dx[i] for i in ind]).astype(np.float64)
+ if data.dxl is not None:
+ data.dxl = np.asarray([data.dxl[i] for i in ind]).astype(np.float64)
+ if data.dxw is not None:
+ data.dxw = np.asarray([data.dxw[i] for i in ind]).astype(np.float64)
+ if data.dy is not None:
+ if len(data.dy) == 0:
+ data.dy = None
+ continue
+ data.dy = np.asarray([data.dy[i] for i in ind]).astype(np.float64)
+ if data.lam is not None:
+ data.lam = np.asarray([data.lam[i] for i in ind]).astype(np.float64)
+ if data.dlam is not None:
+ data.dlam = np.asarray([data.dlam[i] for i in ind]).astype(np.float64)
+ if len(data.x) > 0:
+ data.xmin = np.min(data.x)
+ data.xmax = np.max(data.x)
+ data.ymin = np.min(data.y)
+ data.ymax = np.max(data.y)
+
+ def sort_two_d_data(self):
+ for dataset in self.output:
+ if isinstance(dataset, Data2D):
+ # Normalize the units for
+ dataset.x_unit = self.format_unit(dataset.Q_unit)
+ dataset.y_unit = self.format_unit(dataset.I_unit)
+ dataset.data = dataset.data.astype(np.float64)
+ dataset.qx_data = dataset.qx_data.astype(np.float64)
+ dataset.xmin = np.min(dataset.qx_data)
+ dataset.xmax = np.max(dataset.qx_data)
+ dataset.qy_data = dataset.qy_data.astype(np.float64)
+ dataset.ymin = np.min(dataset.qy_data)
+ dataset.ymax = np.max(dataset.qy_data)
+ dataset.q_data = np.sqrt(dataset.qx_data * dataset.qx_data
+ + dataset.qy_data * dataset.qy_data)
+ if dataset.err_data is not None:
+ dataset.err_data = dataset.err_data.astype(np.float64)
+ if dataset.dqx_data is not None:
+ dataset.dqx_data = dataset.dqx_data.astype(np.float64)
+ if dataset.dqy_data is not None:
+ dataset.dqy_data = dataset.dqy_data.astype(np.float64)
+ if dataset.mask is not None:
+ dataset.mask = dataset.mask.astype(dtype=bool)
+
+ if len(dataset.data.shape) == 2:
+ n_rows, n_cols = dataset.data.shape
+ dataset.y_bins = dataset.qy_data[0::int(n_cols)]
+ dataset.x_bins = dataset.qx_data[:int(n_cols)]
+ dataset.data = dataset.data.flatten()
+ if len(dataset.data) > 0:
+ dataset.xmin = np.min(dataset.qx_data)
+ dataset.xmax = np.max(dataset.qx_data)
+ dataset.ymin = np.min(dataset.qy_data)
+ dataset.ymax = np.max(dataset.qx_data)
+
+ def format_unit(self, unit=None):
+ """
+ Format units a common way
+ :param unit:
+ :return:
+ """
+ if unit:
+ split = unit.split("/")
+ if len(split) == 1:
+ return unit
+ elif split[0] == '1':
+ return "{0}^".format(split[1]) + "{-1}"
+ else:
+ return "{0}*{1}^".format(split[0], split[1]) + "{-1}"
+
+ def set_all_to_none(self):
+ """
+ Set all mutable values to None for error handling purposes
+ """
+ self.current_dataset = None
+ self.current_datainfo = None
+ self.output = []
+
+ def data_cleanup(self):
+ """
+ Clean up the data sets and refresh everything
+ :return: None
+ """
+ self.remove_empty_q_values()
+ self.send_to_output() # Combine datasets with DataInfo
+ self.current_datainfo = DataInfo() # Reset DataInfo
+
+ def remove_empty_q_values(self):
+ """
+ Remove any point where Q == 0
+ """
+ if isinstance(self.current_dataset, plottable_1D):
+ # Booleans for resolutions
+ has_error_dx = self.current_dataset.dx is not None
+ has_error_dxl = self.current_dataset.dxl is not None
+ has_error_dxw = self.current_dataset.dxw is not None
+ has_error_dy = self.current_dataset.dy is not None
+ # Create arrays of zeros for non-existent resolutions
+ if has_error_dxw and not has_error_dxl:
+ array_size = self.current_dataset.dxw.size - 1
+ self.current_dataset.dxl = np.append(self.current_dataset.dxl,
+ np.zeros([array_size]))
+ has_error_dxl = True
+ elif has_error_dxl and not has_error_dxw:
+ array_size = self.current_dataset.dxl.size - 1
+ self.current_dataset.dxw = np.append(self.current_dataset.dxw,
+ np.zeros([array_size]))
+ has_error_dxw = True
+ elif not has_error_dxl and not has_error_dxw and not has_error_dx:
+ array_size = self.current_dataset.x.size - 1
+ self.current_dataset.dx = np.append(self.current_dataset.dx,
+ np.zeros([array_size]))
+ has_error_dx = True
+ if not has_error_dy:
+ array_size = self.current_dataset.y.size - 1
+ self.current_dataset.dy = np.append(self.current_dataset.dy,
+ np.zeros([array_size]))
+ has_error_dy = True
+
+ # Remove points where q = 0
+ x = self.current_dataset.x
+ self.current_dataset.x = self.current_dataset.x[x != 0]
+ self.current_dataset.y = self.current_dataset.y[x != 0]
+ if has_error_dy:
+ self.current_dataset.dy = self.current_dataset.dy[x != 0]
+ if has_error_dx:
+ self.current_dataset.dx = self.current_dataset.dx[x != 0]
+ if has_error_dxl:
+ self.current_dataset.dxl = self.current_dataset.dxl[x != 0]
+ if has_error_dxw:
+ self.current_dataset.dxw = self.current_dataset.dxw[x != 0]
+ elif isinstance(self.current_dataset, plottable_2D):
+ has_error_dqx = self.current_dataset.dqx_data is not None
+ has_error_dqy = self.current_dataset.dqy_data is not None
+ has_error_dy = self.current_dataset.err_data is not None
+ has_mask = self.current_dataset.mask is not None
+ x = self.current_dataset.qx_data
+ self.current_dataset.data = self.current_dataset.data[x != 0]
+ self.current_dataset.qx_data = self.current_dataset.qx_data[x != 0]
+ self.current_dataset.qy_data = self.current_dataset.qy_data[x != 0]
+ self.current_dataset.q_data = np.sqrt(
+ np.square(self.current_dataset.qx_data) + np.square(
+ self.current_dataset.qy_data))
+ if has_error_dy:
+ self.current_dataset.err_data = self.current_dataset.err_data[x != 0]
+ if has_error_dqx:
+ self.current_dataset.dqx_data = self.current_dataset.dqx_data[x != 0]
+ if has_error_dqy:
+ self.current_dataset.dqy_data = self.current_dataset.dqy_data[x != 0]
+ if has_mask:
+ self.current_dataset.mask = self.current_dataset.mask[x != 0]
+
+ def reset_data_list(self, no_lines=0):
+ """
+ Reset the plottable_1D object
+ """
+ # Initialize data sets with arrays the maximum possible size
+ x = np.zeros(no_lines)
+ y = np.zeros(no_lines)
+ dx = np.zeros(no_lines)
+ dy = np.zeros(no_lines)
+ self.current_dataset = plottable_1D(x, y, dx, dy)
+
+ @staticmethod
+ def splitline(line):
+ """
+ Splits a line into pieces based on common delimeters
+ :param line: A single line of text
+ :return: list of values
+ """
+ # Initial try for CSV (split on ,)
+ toks = line.split(',')
+ # Now try SCSV (split on ;)
+ if len(toks) < 2:
+ toks = line.split(';')
+ # Now go for whitespace
+ if len(toks) < 2:
+ toks = line.split()
+ return toks
+
+ @abstractmethod
+ def get_file_contents(self):
+ """
+ Reader specific class to access the contents of the file
+ All reader classes that inherit from FileReader must implement
+ """
+ pass
diff --git a/src/sas/sascalc/dataloader/loader.py b/src/sas/sascalc/dataloader/loader.py
index b43af08..800c473 100644
--- a/src/sas/sascalc/dataloader/loader.py
+++ b/src/sas/sascalc/dataloader/loader.py
@@ -1,6 +1,6 @@
"""
File handler to support different file extensions.
- Uses reflectometry's registry utility.
+ Uses reflectometer registry utility.
The default readers are found in the 'readers' sub-module
and registered by default at initialization time.
@@ -13,11 +13,11 @@
look for new readers/writers.
"""
#####################################################################
-#This software was developed by the University of Tennessee as part of the
-#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
-#project funded by the US National Science Foundation.
-#See the license text in license.txt
-#copyright 2008, University of Tennessee
+# This software was developed by the University of Tennessee as part of the
+# Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
+# project funded by the US National Science Foundation.
+# See the license text in license.txt
+# copyright 2008, University of Tennessee
######################################################################
import os
@@ -25,28 +25,35 @@ import sys
import logging
import time
from zipfile import ZipFile
+
from sas.sascalc.data_util.registry import ExtensionRegistry
+
# Default readers are defined in the readers sub-module
-import readers
-from readers import ascii_reader
-from readers import cansas_reader
+from . import readers
+from .loader_exceptions import NoKnownLoaderException, FileContentsException,\
+ DefaultReaderException
+from .readers import ascii_reader
+from .readers import cansas_reader
+from .readers import cansas_reader_HDF5
+
+logger = logging.getLogger(__name__)
+
class Registry(ExtensionRegistry):
"""
Registry class for file format extensions.
Readers and writers are supported.
"""
-
def __init__(self):
super(Registry, self).__init__()
- ## Writers
+ # Writers
self.writers = {}
- ## List of wildcards
+ # List of wildcards
self.wildcards = ['All (*.*)|*.*']
- ## Creation time, for testing
+ # Creation time, for testing
self._created = time.time()
# Register default readers
@@ -60,20 +67,64 @@ class Registry(ExtensionRegistry):
:param format: explicit extension, to force the use
of a particular reader
- Defaults to the ascii (multi-column) reader
- if no reader was registered for the file's
- extension.
+ Defaults to the ascii (multi-column), cansas XML, and cansas NeXuS
+ readers if no reader was registered for the file's extension.
"""
+ # Gets set to a string if the file has an associated reader that fails
+ msg_from_reader = None
try:
return super(Registry, self).load(path, format=format)
- except:
- try:
- # No reader was found. Default to the ascii reader.
- ascii_loader = ascii_reader.Reader()
- return ascii_loader.read(path)
- except:
- cansas_loader = cansas_reader.Reader()
- return cansas_loader.read(path)
+ #except Exception: raise # for debugging, don't use fallback loader
+ except NoKnownLoaderException as nkl_e:
+ pass # Try the ASCII reader
+ except FileContentsException as fc_exc:
+ # File has an associated reader but it failed.
+ # Save the error message to display later, but try the 3 default loaders
+ msg_from_reader = fc_exc.message
+ except Exception:
+ pass
+
+ # File has no associated reader, or the associated reader failed.
+ # Try the ASCII reader
+ try:
+ ascii_loader = ascii_reader.Reader()
+ return ascii_loader.read(path)
+ except DefaultReaderException:
+ pass # Loader specific error to try the cansas XML reader
+ except FileContentsException as e:
+ if msg_from_reader is None:
+ raise RuntimeError(e.message)
+
+ # ASCII reader failed - try CanSAS xML reader
+ try:
+ cansas_loader = cansas_reader.Reader()
+ return cansas_loader.read(path)
+ except DefaultReaderException:
+ pass # Loader specific error to try the NXcanSAS reader
+ except FileContentsException as e:
+ if msg_from_reader is None:
+ raise RuntimeError(e.message)
+ except Exception:
+ pass
+
+ # CanSAS XML reader failed - try NXcanSAS reader
+ try:
+ cansas_nexus_loader = cansas_reader_HDF5.Reader()
+ return cansas_nexus_loader.read(path)
+ except DefaultReaderException as e:
+ logging.error("No default loader can load the data")
+ # No known reader available. Give up and throw an error
+ if msg_from_reader is None:
+ msg = "\nUnknown data format: {}.\nThe file is not a ".format(path)
+ msg += "known format that can be loaded by SasView.\n"
+ raise NoKnownLoaderException(msg)
+ else:
+ # Associated reader and default readers all failed.
+ # Show error message from associated reader
+ raise RuntimeError(msg_from_reader)
+ except FileContentsException as e:
+ err_msg = msg_from_reader if msg_from_reader is not None else e.message
+ raise RuntimeError(err_msg)
def find_plugins(self, dir):
"""
@@ -98,7 +149,7 @@ class Registry(ExtensionRegistry):
if not os.path.isdir(dir):
msg = "DataLoader couldn't locate DataLoader plugin folder."
msg += """ "%s" does not exist""" % dir
- logging.warning(msg)
+ logger.warning(msg)
return readers_found
for item in os.listdir(dir):
@@ -116,7 +167,7 @@ class Registry(ExtensionRegistry):
except:
msg = "Loader: Error importing "
msg += "%s\n %s" % (item, sys.exc_value)
- logging.error(msg)
+ logger.error(msg)
# Process zip files
elif item.endswith('.zip'):
@@ -138,12 +189,12 @@ class Registry(ExtensionRegistry):
except:
msg = "Loader: Error importing"
msg += " %s\n %s" % (mfile, sys.exc_value)
- logging.error(msg)
+ logger.error(msg)
except:
msg = "Loader: Error importing "
msg += " %s\n %s" % (item, sys.exc_value)
- logging.error(msg)
+ logger.error(msg)
return readers_found
@@ -189,7 +240,7 @@ class Registry(ExtensionRegistry):
except:
msg = "Loader: Error accessing"
msg += " Reader in %s\n %s" % (module.__name__, sys.exc_value)
- logging.error(msg)
+ logger.error(msg)
return reader_found
def associate_file_reader(self, ext, loader):
@@ -222,7 +273,7 @@ class Registry(ExtensionRegistry):
except:
msg = "Loader: Error accessing Reader "
msg += "in %s\n %s" % (loader.__name__, sys.exc_value)
- logging.error(msg)
+ logger.error(msg)
return reader_found
def _identify_plugin(self, module):
@@ -267,7 +318,7 @@ class Registry(ExtensionRegistry):
except:
msg = "Loader: Error accessing Reader"
msg += " in %s\n %s" % (module.__name__, sys.exc_value)
- logging.error(msg)
+ logger.error(msg)
return reader_found
def lookup_writers(self, path):
@@ -278,7 +329,7 @@ class Registry(ExtensionRegistry):
# Find matching extensions
extlist = [ext for ext in self.extensions() if path.endswith(ext)]
# Sort matching extensions by decreasing order of length
- extlist.sort(lambda a, b: len(a) < len(b))
+ extlist.sort(key=len)
# Combine loaders for matching extensions into one big list
writers = []
for L in [self.writers[ext] for ext in extlist]:
@@ -292,7 +343,7 @@ class Registry(ExtensionRegistry):
writers = L
# Raise an error if there are no matching extensions
if len(writers) == 0:
- raise ValueError, "Unknown file type for " + path
+ raise ValueError("Unknown file type for " + path)
# All done
return writers
@@ -311,7 +362,7 @@ class Registry(ExtensionRegistry):
for fn in writers:
try:
return fn(path, data)
- except:
+ except Exception:
pass # give other loaders a chance to succeed
# If we get here it is because all loaders failed
raise # reraises last exception
diff --git a/src/sas/sascalc/dataloader/loader_exceptions.py b/src/sas/sascalc/dataloader/loader_exceptions.py
new file mode 100644
index 0000000..840e6dd
--- /dev/null
+++ b/src/sas/sascalc/dataloader/loader_exceptions.py
@@ -0,0 +1,41 @@
+"""
+Exceptions specific to loading data.
+"""
+
+
+class NoKnownLoaderException(Exception):
+ """
+ Exception for files with no associated reader based on the file
+ extension of the loaded file. This exception should only be thrown by
+ loader.py.
+ """
+ def __init__(self, e=None):
+ self.message = e
+
+
+class DefaultReaderException(Exception):
+ """
+ Exception for files with no associated reader. This should be thrown by
+ default readers only to tell Loader to try the next reader.
+ """
+ def __init__(self, e=None):
+ self.message = e
+
+
+class FileContentsException(Exception):
+ """
+ Exception for files with an associated reader, but with no loadable data.
+ This is useful for catching loader or file format issues.
+ """
+ def __init__(self, e=None):
+ self.message = e
+
+
+class DataReaderException(Exception):
+ """
+ Exception for files that were able to mostly load, but had minor issues
+ along the way.
+ Any exceptions of this type should be put into the datainfo.errors
+ """
+ def __init__(self, e=None):
+ self.message = e
diff --git a/src/sas/sascalc/dataloader/manipulations.py b/src/sas/sascalc/dataloader/manipulations.py
index b7f2e73..7b5f32a 100644
--- a/src/sas/sascalc/dataloader/manipulations.py
+++ b/src/sas/sascalc/dataloader/manipulations.py
@@ -1,1140 +1,1172 @@
-"""
-Data manipulations for 2D data sets.
-Using the meta data information, various types of averaging
-are performed in Q-space
-"""
-#####################################################################
-#This software was developed by the University of Tennessee as part of the
-#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
-#project funded by the US National Science Foundation.
-#See the license text in license.txt
-#copyright 2008, University of Tennessee
-######################################################################
-
-#TODO: copy the meta data from the 2D object to the resulting 1D object
-import math
-import numpy
-
-#from data_info import plottable_2D
-from data_info import Data1D
-
-
-def get_q(dx, dy, det_dist, wavelength):
- """
- :param dx: x-distance from beam center [mm]
- :param dy: y-distance from beam center [mm]
- :return: q-value at the given position
- """
- # Distance from beam center in the plane of detector
- plane_dist = math.sqrt(dx * dx + dy * dy)
- # Half of the scattering angle
- theta = 0.5 * math.atan(plane_dist / det_dist)
- return (4.0 * math.pi / wavelength) * math.sin(theta)
-
-
-def get_q_compo(dx, dy, det_dist, wavelength, compo=None):
- """
- This reduces tiny error at very large q.
- Implementation of this func is not started yet.<--ToDo
- """
- if dy == 0:
- if dx >= 0:
- angle_xy = 0
- else:
- angle_xy = math.pi
- else:
- angle_xy = math.atan(dx / dy)
-
- if compo == "x":
- out = get_q(dx, dy, det_dist, wavelength) * math.cos(angle_xy)
- elif compo == "y":
- out = get_q(dx, dy, det_dist, wavelength) * math.sin(angle_xy)
- else:
- out = get_q(dx, dy, det_dist, wavelength)
- return out
-
-
-def flip_phi(phi):
- """
- Correct phi to within the 0 <= to <= 2pi range
-
- :return: phi in >=0 and <=2Pi
- """
- Pi = math.pi
- if phi < 0:
- phi_out = phi + (2 * Pi)
- elif phi > (2 * Pi):
- phi_out = phi - (2 * Pi)
- else:
- phi_out = phi
- return phi_out
-
-
-def reader2D_converter(data2d=None):
- """
- convert old 2d format opened by IhorReader or danse_reader
- to new Data2D format
-
- :param data2d: 2d array of Data2D object
- :return: 1d arrays of Data2D object
-
- """
- if data2d.data == None or data2d.x_bins == None or data2d.y_bins == None:
- raise ValueError, "Can't convert this data: data=None..."
- new_x = numpy.tile(data2d.x_bins, (len(data2d.y_bins), 1))
- new_y = numpy.tile(data2d.y_bins, (len(data2d.x_bins), 1))
- new_y = new_y.swapaxes(0, 1)
-
- new_data = data2d.data.flatten()
- qx_data = new_x.flatten()
- qy_data = new_y.flatten()
- q_data = numpy.sqrt(qx_data * qx_data + qy_data * qy_data)
- if data2d.err_data == None or numpy.any(data2d.err_data <= 0):
- new_err_data = numpy.sqrt(numpy.abs(new_data))
- else:
- new_err_data = data2d.err_data.flatten()
- mask = numpy.ones(len(new_data), dtype=bool)
-
- #TODO: make sense of the following two lines...
- #from sas.sascalc.dataloader.data_info import Data2D
- #output = Data2D()
- output = data2d
- output.data = new_data
- output.err_data = new_err_data
- output.qx_data = qx_data
- output.qy_data = qy_data
- output.q_data = q_data
- output.mask = mask
-
- return output
-
-
-class _Slab(object):
- """
- Compute average I(Q) for a region of interest
- """
- def __init__(self, x_min=0.0, x_max=0.0, y_min=0.0,
- y_max=0.0, bin_width=0.001):
- # Minimum Qx value [A-1]
- self.x_min = x_min
- # Maximum Qx value [A-1]
- self.x_max = x_max
- # Minimum Qy value [A-1]
- self.y_min = y_min
- # Maximum Qy value [A-1]
- self.y_max = y_max
- # Bin width (step size) [A-1]
- self.bin_width = bin_width
- # If True, I(|Q|) will be return, otherwise,
- # negative q-values are allowed
- self.fold = False
-
- def __call__(self, data2D):
- return NotImplemented
-
- def _avg(self, data2D, maj):
- """
- Compute average I(Q_maj) for a region of interest.
- The major axis is defined as the axis of Q_maj.
- The minor axis is the axis that we average over.
-
- :param data2D: Data2D object
- :param maj_min: min value on the major axis
- :return: Data1D object
- """
- if len(data2D.detector) > 1:
- msg = "_Slab._avg: invalid number of "
- msg += " detectors: %g" % len(data2D.detector)
- raise RuntimeError, msg
-
- # Get data
- data = data2D.data[numpy.isfinite(data2D.data)]
- err_data = data2D.err_data[numpy.isfinite(data2D.data)]
- qx_data = data2D.qx_data[numpy.isfinite(data2D.data)]
- qy_data = data2D.qy_data[numpy.isfinite(data2D.data)]
-
- # Build array of Q intervals
- if maj == 'x':
- if self.fold:
- x_min = 0
- else:
- x_min = self.x_min
- nbins = int(math.ceil((self.x_max - x_min) / self.bin_width))
- elif maj == 'y':
- if self.fold:
- y_min = 0
- else:
- y_min = self.y_min
- nbins = int(math.ceil((self.y_max - y_min) / self.bin_width))
- else:
- raise RuntimeError, "_Slab._avg: unrecognized axis %s" % str(maj)
-
- x = numpy.zeros(nbins)
- y = numpy.zeros(nbins)
- err_y = numpy.zeros(nbins)
- y_counts = numpy.zeros(nbins)
-
- # Average pixelsize in q space
- for npts in range(len(data)):
- # default frac
- frac_x = 0
- frac_y = 0
- # get ROI
- if self.x_min <= qx_data[npts] and self.x_max > qx_data[npts]:
- frac_x = 1
- if self.y_min <= qy_data[npts] and self.y_max > qy_data[npts]:
- frac_y = 1
- frac = frac_x * frac_y
-
- if frac == 0:
- continue
- # binning: find axis of q
- if maj == 'x':
- q_value = qx_data[npts]
- min_value = x_min
- if maj == 'y':
- q_value = qy_data[npts]
- min_value = y_min
- if self.fold and q_value < 0:
- q_value = -q_value
- # bin
- i_q = int(math.ceil((q_value - min_value) / self.bin_width)) - 1
-
- # skip outside of max bins
- if i_q < 0 or i_q >= nbins:
- continue
-
- #TODO: find better definition of x[i_q] based on q_data
- # min_value + (i_q + 1) * self.bin_width / 2.0
- x[i_q] += frac * q_value
- y[i_q] += frac * data[npts]
-
- if err_data == None or err_data[npts] == 0.0:
- if data[npts] < 0:
- data[npts] = -data[npts]
- err_y[i_q] += frac * frac * data[npts]
- else:
- err_y[i_q] += frac * frac * err_data[npts] * err_data[npts]
- y_counts[i_q] += frac
-
- # Average the sums
- for n in range(nbins):
- err_y[n] = math.sqrt(err_y[n])
-
- err_y = err_y / y_counts
- y = y / y_counts
- x = x / y_counts
- idx = (numpy.isfinite(y) & numpy.isfinite(x))
-
- if not idx.any():
- msg = "Average Error: No points inside ROI to average..."
- raise ValueError, msg
- return Data1D(x=x[idx], y=y[idx], dy=err_y[idx])
-
-
-class SlabY(_Slab):
- """
- Compute average I(Qy) for a region of interest
- """
- def __call__(self, data2D):
- """
- Compute average I(Qy) for a region of interest
-
- :param data2D: Data2D object
- :return: Data1D object
- """
- return self._avg(data2D, 'y')
-
-
-class SlabX(_Slab):
- """
- Compute average I(Qx) for a region of interest
- """
- def __call__(self, data2D):
- """
- Compute average I(Qx) for a region of interest
- :param data2D: Data2D object
- :return: Data1D object
- """
- return self._avg(data2D, 'x')
-
-
-class Boxsum(object):
- """
- Perform the sum of counts in a 2D region of interest.
- """
- def __init__(self, x_min=0.0, x_max=0.0, y_min=0.0, y_max=0.0):
- # Minimum Qx value [A-1]
- self.x_min = x_min
- # Maximum Qx value [A-1]
- self.x_max = x_max
- # Minimum Qy value [A-1]
- self.y_min = y_min
- # Maximum Qy value [A-1]
- self.y_max = y_max
-
- def __call__(self, data2D):
- """
- Perform the sum in the region of interest
-
- :param data2D: Data2D object
- :return: number of counts, error on number of counts,
- number of points summed
- """
- y, err_y, y_counts = self._sum(data2D)
-
- # Average the sums
- counts = 0 if y_counts == 0 else y
- error = 0 if y_counts == 0 else math.sqrt(err_y)
-
- # Added y_counts to return, SMK & PDB, 04/03/2013
- return counts, error, y_counts
-
- def _sum(self, data2D):
- """
- Perform the sum in the region of interest
-
- :param data2D: Data2D object
- :return: number of counts,
- error on number of counts, number of entries summed
- """
- if len(data2D.detector) > 1:
- msg = "Circular averaging: invalid number "
- msg += "of detectors: %g" % len(data2D.detector)
- raise RuntimeError, msg
- # Get data
- data = data2D.data[numpy.isfinite(data2D.data)]
- err_data = data2D.err_data[numpy.isfinite(data2D.data)]
- qx_data = data2D.qx_data[numpy.isfinite(data2D.data)]
- qy_data = data2D.qy_data[numpy.isfinite(data2D.data)]
-
- y = 0.0
- err_y = 0.0
- y_counts = 0.0
-
- # Average pixelsize in q space
- for npts in range(len(data)):
- # default frac
- frac_x = 0
- frac_y = 0
-
- # get min and max at each points
- qx = qx_data[npts]
- qy = qy_data[npts]
-
- # get the ROI
- if self.x_min <= qx and self.x_max > qx:
- frac_x = 1
- if self.y_min <= qy and self.y_max > qy:
- frac_y = 1
- #Find the fraction along each directions
- frac = frac_x * frac_y
- if frac == 0:
- continue
- y += frac * data[npts]
- if err_data == None or err_data[npts] == 0.0:
- if data[npts] < 0:
- data[npts] = -data[npts]
- err_y += frac * frac * data[npts]
- else:
- err_y += frac * frac * err_data[npts] * err_data[npts]
- y_counts += frac
- return y, err_y, y_counts
-
-
-class Boxavg(Boxsum):
- """
- Perform the average of counts in a 2D region of interest.
- """
- def __init__(self, x_min=0.0, x_max=0.0, y_min=0.0, y_max=0.0):
- super(Boxavg, self).__init__(x_min=x_min, x_max=x_max,
- y_min=y_min, y_max=y_max)
-
- def __call__(self, data2D):
- """
- Perform the sum in the region of interest
-
- :param data2D: Data2D object
- :return: average counts, error on average counts
-
- """
- y, err_y, y_counts = self._sum(data2D)
-
- # Average the sums
- counts = 0 if y_counts == 0 else y / y_counts
- error = 0 if y_counts == 0 else math.sqrt(err_y) / y_counts
-
- return counts, error
-
-
-def get_pixel_fraction_square(x, xmin, xmax):
- """
- Return the fraction of the length
- from xmin to x.::
-
- A B
- +-----------+---------+
- xmin x xmax
-
- :param x: x-value
- :param xmin: minimum x for the length considered
- :param xmax: minimum x for the length considered
- :return: (x-xmin)/(xmax-xmin) when xmin < x < xmax
-
- """
- if x <= xmin:
- return 0.0
- if x > xmin and x < xmax:
- return (x - xmin) / (xmax - xmin)
- else:
- return 1.0
-
-
-class CircularAverage(object):
- """
- Perform circular averaging on 2D data
-
- The data returned is the distribution of counts
- as a function of Q
- """
- def __init__(self, r_min=0.0, r_max=0.0, bin_width=0.0005):
- # Minimum radius included in the average [A-1]
- self.r_min = r_min
- # Maximum radius included in the average [A-1]
- self.r_max = r_max
- # Bin width (step size) [A-1]
- self.bin_width = bin_width
-
- def __call__(self, data2D, ismask=False):
- """
- Perform circular averaging on the data
-
- :param data2D: Data2D object
- :return: Data1D object
- """
- # Get data W/ finite values
- data = data2D.data[numpy.isfinite(data2D.data)]
- q_data = data2D.q_data[numpy.isfinite(data2D.data)]
- err_data = data2D.err_data[numpy.isfinite(data2D.data)]
- mask_data = data2D.mask[numpy.isfinite(data2D.data)]
-
- dq_data = None
-
- # Get the dq for resolution averaging
- if data2D.dqx_data != None and data2D.dqy_data != None:
- # The pinholes and det. pix contribution present
- # in both direction of the 2D which must be subtracted when
- # converting to 1D: dq_overlap should calculated ideally at
- # q = 0. Note This method works on only pinhole geometry.
- # Extrapolate dqx(r) and dqy(phi) at q = 0, and take an average.
- z_max = max(data2D.q_data)
- z_min = min(data2D.q_data)
- x_max = data2D.dqx_data[data2D.q_data[z_max]]
- x_min = data2D.dqx_data[data2D.q_data[z_min]]
- y_max = data2D.dqy_data[data2D.q_data[z_max]]
- y_min = data2D.dqy_data[data2D.q_data[z_min]]
- # Find qdx at q = 0
- dq_overlap_x = (x_min * z_max - x_max * z_min) / (z_max - z_min)
- # when extrapolation goes wrong
- if dq_overlap_x > min(data2D.dqx_data):
- dq_overlap_x = min(data2D.dqx_data)
- dq_overlap_x *= dq_overlap_x
- # Find qdx at q = 0
- dq_overlap_y = (y_min * z_max - y_max * z_min) / (z_max - z_min)
- # when extrapolation goes wrong
- if dq_overlap_y > min(data2D.dqy_data):
- dq_overlap_y = min(data2D.dqy_data)
- # get dq at q=0.
- dq_overlap_y *= dq_overlap_y
-
- dq_overlap = numpy.sqrt((dq_overlap_x + dq_overlap_y) / 2.0)
- # Final protection of dq
- if dq_overlap < 0:
- dq_overlap = y_min
- dqx_data = data2D.dqx_data[numpy.isfinite(data2D.data)]
- dqy_data = data2D.dqy_data[numpy.isfinite(data2D.data)] - dq_overlap
- # def; dqx_data = dq_r dqy_data = dq_phi
- # Convert dq 2D to 1D here
- dqx = dqx_data * dqx_data
- dqy = dqy_data * dqy_data
- dq_data = numpy.add(dqx, dqy)
- dq_data = numpy.sqrt(dq_data)
-
- #q_data_max = numpy.max(q_data)
- if len(data2D.q_data) == None:
- msg = "Circular averaging: invalid q_data: %g" % data2D.q_data
- raise RuntimeError, msg
-
- # Build array of Q intervals
- nbins = int(math.ceil((self.r_max - self.r_min) / self.bin_width))
-
- x = numpy.zeros(nbins)
- y = numpy.zeros(nbins)
- err_y = numpy.zeros(nbins)
- err_x = numpy.zeros(nbins)
- y_counts = numpy.zeros(nbins)
-
- for npt in range(len(data)):
-
- if ismask and not mask_data[npt]:
- continue
-
- frac = 0
-
- # q-value at the pixel (j,i)
- q_value = q_data[npt]
- data_n = data[npt]
-
- ## No need to calculate the frac when all data are within range
- if self.r_min >= self.r_max:
- raise ValueError, "Limit Error: min > max"
-
- if self.r_min <= q_value and q_value <= self.r_max:
- frac = 1
- if frac == 0:
- continue
- i_q = int(math.floor((q_value - self.r_min) / self.bin_width))
-
- # Take care of the edge case at phi = 2pi.
- if i_q == nbins:
- i_q = nbins - 1
- y[i_q] += frac * data_n
- # Take dqs from data to get the q_average
- x[i_q] += frac * q_value
- if err_data == None or err_data[npt] == 0.0:
- if data_n < 0:
- data_n = -data_n
- err_y[i_q] += frac * frac * data_n
- else:
- err_y[i_q] += frac * frac * err_data[npt] * err_data[npt]
- if dq_data != None:
- # To be consistent with dq calculation in 1d reduction,
- # we need just the averages (not quadratures) because
- # it should not depend on the number of the q points
- # in the qr bins.
- err_x[i_q] += frac * dq_data[npt]
- else:
- err_x = None
- y_counts[i_q] += frac
-
- # Average the sums
- for n in range(nbins):
- if err_y[n] < 0:
- err_y[n] = -err_y[n]
- err_y[n] = math.sqrt(err_y[n])
- #if err_x != None:
- # err_x[n] = math.sqrt(err_x[n])
-
- err_y = err_y / y_counts
- err_y[err_y == 0] = numpy.average(err_y)
- y = y / y_counts
- x = x / y_counts
- idx = (numpy.isfinite(y)) & (numpy.isfinite(x))
-
- if err_x != None:
- d_x = err_x[idx] / y_counts[idx]
- else:
- d_x = None
-
- if not idx.any():
- msg = "Average Error: No points inside ROI to average..."
- raise ValueError, msg
-
- return Data1D(x=x[idx], y=y[idx], dy=err_y[idx], dx=d_x)
-
-
-class Ring(object):
- """
- Defines a ring on a 2D data set.
- The ring is defined by r_min, r_max, and
- the position of the center of the ring.
-
- The data returned is the distribution of counts
- around the ring as a function of phi.
-
- Phi_min and phi_max should be defined between 0 and 2*pi
- in anti-clockwise starting from the x- axis on the left-hand side
- """
- #Todo: remove center.
- def __init__(self, r_min=0, r_max=0, center_x=0, center_y=0, nbins=36):
- # Minimum radius
- self.r_min = r_min
- # Maximum radius
- self.r_max = r_max
- # Center of the ring in x
- self.center_x = center_x
- # Center of the ring in y
- self.center_y = center_y
- # Number of angular bins
- self.nbins_phi = nbins
-
-
- def __call__(self, data2D):
- """
- Apply the ring to the data set.
- Returns the angular distribution for a given q range
-
- :param data2D: Data2D object
-
- :return: Data1D object
- """
- if data2D.__class__.__name__ not in ["Data2D", "plottable_2D"]:
- raise RuntimeError, "Ring averaging only take plottable_2D objects"
-
- Pi = math.pi
-
- # Get data
- data = data2D.data[numpy.isfinite(data2D.data)]
- q_data = data2D.q_data[numpy.isfinite(data2D.data)]
- err_data = data2D.err_data[numpy.isfinite(data2D.data)]
- qx_data = data2D.qx_data[numpy.isfinite(data2D.data)]
- qy_data = data2D.qy_data[numpy.isfinite(data2D.data)]
-
- # Set space for 1d outputs
- phi_bins = numpy.zeros(self.nbins_phi)
- phi_counts = numpy.zeros(self.nbins_phi)
- phi_values = numpy.zeros(self.nbins_phi)
- phi_err = numpy.zeros(self.nbins_phi)
-
- # Shift to apply to calculated phi values in order
- # to center first bin at zero
- phi_shift = Pi / self.nbins_phi
-
- for npt in range(len(data)):
- frac = 0
- # q-value at the point (npt)
- q_value = q_data[npt]
- data_n = data[npt]
-
- # phi-value at the point (npt)
- phi_value = math.atan2(qy_data[npt], qx_data[npt]) + Pi
-
- if self.r_min <= q_value and q_value <= self.r_max:
- frac = 1
- if frac == 0:
- continue
- # binning
- i_phi = int(math.floor((self.nbins_phi) * \
- (phi_value + phi_shift) / (2 * Pi)))
-
- # Take care of the edge case at phi = 2pi.
- if i_phi >= self.nbins_phi:
- i_phi = 0
- phi_bins[i_phi] += frac * data[npt]
-
- if err_data == None or err_data[npt] == 0.0:
- if data_n < 0:
- data_n = -data_n
- phi_err[i_phi] += frac * frac * math.fabs(data_n)
- else:
- phi_err[i_phi] += frac * frac * err_data[npt] * err_data[npt]
- phi_counts[i_phi] += frac
-
- for i in range(self.nbins_phi):
- phi_bins[i] = phi_bins[i] / phi_counts[i]
- phi_err[i] = math.sqrt(phi_err[i]) / phi_counts[i]
- phi_values[i] = 2.0 * math.pi / self.nbins_phi * (1.0 * i)
-
- idx = (numpy.isfinite(phi_bins))
-
- if not idx.any():
- msg = "Average Error: No points inside ROI to average..."
- raise ValueError, msg
- #elif len(phi_bins[idx])!= self.nbins_phi:
- # print "resulted",self.nbins_phi- len(phi_bins[idx])
- #,"empty bin(s) due to tight binning..."
- return Data1D(x=phi_values[idx], y=phi_bins[idx], dy=phi_err[idx])
-
-
-def get_pixel_fraction(qmax, q_00, q_01, q_10, q_11):
- """
- Returns the fraction of the pixel defined by
- the four corners (q_00, q_01, q_10, q_11) that
- has q < qmax.::
-
- q_01 q_11
- y=1 +--------------+
- | |
- | |
- | |
- y=0 +--------------+
- q_00 q_10
-
- x=0 x=1
-
- """
- # y side for x = minx
- x_0 = get_intercept(qmax, q_00, q_01)
- # y side for x = maxx
- x_1 = get_intercept(qmax, q_10, q_11)
-
- # x side for y = miny
- y_0 = get_intercept(qmax, q_00, q_10)
- # x side for y = maxy
- y_1 = get_intercept(qmax, q_01, q_11)
-
- # surface fraction for a 1x1 pixel
- frac_max = 0
-
- if x_0 and x_1:
- frac_max = (x_0 + x_1) / 2.0
- elif y_0 and y_1:
- frac_max = (y_0 + y_1) / 2.0
- elif x_0 and y_0:
- if q_00 < q_10:
- frac_max = x_0 * y_0 / 2.0
- else:
- frac_max = 1.0 - x_0 * y_0 / 2.0
- elif x_0 and y_1:
- if q_00 < q_10:
- frac_max = x_0 * y_1 / 2.0
- else:
- frac_max = 1.0 - x_0 * y_1 / 2.0
- elif x_1 and y_0:
- if q_00 > q_10:
- frac_max = x_1 * y_0 / 2.0
- else:
- frac_max = 1.0 - x_1 * y_0 / 2.0
- elif x_1 and y_1:
- if q_00 < q_10:
- frac_max = 1.0 - (1.0 - x_1) * (1.0 - y_1) / 2.0
- else:
- frac_max = (1.0 - x_1) * (1.0 - y_1) / 2.0
-
- # If we make it here, there is no intercept between
- # this pixel and the constant-q ring. We only need
- # to know if we have to include it or exclude it.
- elif (q_00 + q_01 + q_10 + q_11) / 4.0 < qmax:
- frac_max = 1.0
-
- return frac_max
-
-
-def get_intercept(q, q_0, q_1):
- """
- Returns the fraction of the side at which the
- q-value intercept the pixel, None otherwise.
- The values returned is the fraction ON THE SIDE
- OF THE LOWEST Q. ::
-
- A B
- +-----------+--------+ <--- pixel size
- 0 1
- Q_0 -------- Q ----- Q_1 <--- equivalent Q range
- if Q_1 > Q_0, A is returned
- if Q_1 < Q_0, B is returned
- if Q is outside the range of [Q_0, Q_1], None is returned
-
- """
- if q_1 > q_0:
- if q > q_0 and q <= q_1:
- return (q - q_0) / (q_1 - q_0)
- else:
- if q > q_1 and q <= q_0:
- return (q - q_1) / (q_0 - q_1)
- return None
-
-
-class _Sector(object):
- """
- Defines a sector region on a 2D data set.
- The sector is defined by r_min, r_max, phi_min, phi_max,
- and the position of the center of the ring
- where phi_min and phi_max are defined by the right
- and left lines wrt central line
- and phi_max could be less than phi_min.
-
- Phi is defined between 0 and 2*pi in anti-clockwise
- starting from the x- axis on the left-hand side
- """
- def __init__(self, r_min, r_max, phi_min=0, phi_max=2 * math.pi, nbins=20):
- self.r_min = r_min
- self.r_max = r_max
- self.phi_min = phi_min
- self.phi_max = phi_max
- self.nbins = nbins
-
- def _agv(self, data2D, run='phi'):
- """
- Perform sector averaging.
-
- :param data2D: Data2D object
- :param run: define the varying parameter ('phi' , 'q' , or 'q2')
-
- :return: Data1D object
- """
- if data2D.__class__.__name__ not in ["Data2D", "plottable_2D"]:
- raise RuntimeError, "Ring averaging only take plottable_2D objects"
- Pi = math.pi
-
- # Get the all data & info
- data = data2D.data[numpy.isfinite(data2D.data)]
- q_data = data2D.q_data[numpy.isfinite(data2D.data)]
- err_data = data2D.err_data[numpy.isfinite(data2D.data)]
- qx_data = data2D.qx_data[numpy.isfinite(data2D.data)]
- qy_data = data2D.qy_data[numpy.isfinite(data2D.data)]
- dq_data = None
-
- # Get the dq for resolution averaging
- if data2D.dqx_data != None and data2D.dqy_data != None:
- # The pinholes and det. pix contribution present
- # in both direction of the 2D which must be subtracted when
- # converting to 1D: dq_overlap should calculated ideally at
- # q = 0.
- # Extrapolate dqy(perp) at q = 0
- z_max = max(data2D.q_data)
- z_min = min(data2D.q_data)
- x_max = data2D.dqx_data[data2D.q_data[z_max]]
- x_min = data2D.dqx_data[data2D.q_data[z_min]]
- y_max = data2D.dqy_data[data2D.q_data[z_max]]
- y_min = data2D.dqy_data[data2D.q_data[z_min]]
- # Find qdx at q = 0
- dq_overlap_x = (x_min * z_max - x_max * z_min) / (z_max - z_min)
- # when extrapolation goes wrong
- if dq_overlap_x > min(data2D.dqx_data):
- dq_overlap_x = min(data2D.dqx_data)
- dq_overlap_x *= dq_overlap_x
- # Find qdx at q = 0
- dq_overlap_y = (y_min * z_max - y_max * z_min) / (z_max - z_min)
- # when extrapolation goes wrong
- if dq_overlap_y > min(data2D.dqy_data):
- dq_overlap_y = min(data2D.dqy_data)
- # get dq at q=0.
- dq_overlap_y *= dq_overlap_y
-
- dq_overlap = numpy.sqrt((dq_overlap_x + dq_overlap_y) / 2.0)
- if dq_overlap < 0:
- dq_overlap = y_min
- dqx_data = data2D.dqx_data[numpy.isfinite(data2D.data)]
- dqy_data = data2D.dqy_data[numpy.isfinite(data2D.data)] - dq_overlap
- # def; dqx_data = dq_r dqy_data = dq_phi
- # Convert dq 2D to 1D here
- dqx = dqx_data * dqx_data
- dqy = dqy_data * dqy_data
- dq_data = numpy.add(dqx, dqy)
- dq_data = numpy.sqrt(dq_data)
-
- #set space for 1d outputs
- x = numpy.zeros(self.nbins)
- y = numpy.zeros(self.nbins)
- y_err = numpy.zeros(self.nbins)
- x_err = numpy.zeros(self.nbins)
- y_counts = numpy.zeros(self.nbins)
-
- # Get the min and max into the region: 0 <= phi < 2Pi
- phi_min = flip_phi(self.phi_min)
- phi_max = flip_phi(self.phi_max)
-
- for n in range(len(data)):
- frac = 0
-
- # q-value at the pixel (j,i)
- q_value = q_data[n]
- data_n = data[n]
-
- # Is pixel within range?
- is_in = False
-
- # phi-value of the pixel (j,i)
- phi_value = math.atan2(qy_data[n], qx_data[n]) + Pi
-
- ## No need to calculate the frac when all data are within range
- if self.r_min <= q_value and q_value <= self.r_max:
- frac = 1
- if frac == 0:
- continue
- #In case of two ROIs (symmetric major and minor regions)(for 'q2')
- if run.lower() == 'q2':
- ## For minor sector wing
- # Calculate the minor wing phis
- phi_min_minor = flip_phi(phi_min - Pi)
- phi_max_minor = flip_phi(phi_max - Pi)
- # Check if phis of the minor ring is within 0 to 2pi
- if phi_min_minor > phi_max_minor:
- is_in = (phi_value > phi_min_minor or \
- phi_value < phi_max_minor)
- else:
- is_in = (phi_value > phi_min_minor and \
- phi_value < phi_max_minor)
-
- #For all cases(i.e.,for 'q', 'q2', and 'phi')
- #Find pixels within ROI
- if phi_min > phi_max:
- is_in = is_in or (phi_value > phi_min or \
- phi_value < phi_max)
- else:
- is_in = is_in or (phi_value >= phi_min and \
- phi_value < phi_max)
-
- if not is_in:
- frac = 0
- if frac == 0:
- continue
- # Check which type of averaging we need
- if run.lower() == 'phi':
- temp_x = (self.nbins) * (phi_value - self.phi_min)
- temp_y = (self.phi_max - self.phi_min)
- i_bin = int(math.floor(temp_x / temp_y))
- else:
- temp_x = (self.nbins) * (q_value - self.r_min)
- temp_y = (self.r_max - self.r_min)
- i_bin = int(math.floor(temp_x / temp_y))
-
- # Take care of the edge case at phi = 2pi.
- if i_bin == self.nbins:
- i_bin = self.nbins - 1
-
- ## Get the total y
- y[i_bin] += frac * data_n
- x[i_bin] += frac * q_value
- if err_data[n] == None or err_data[n] == 0.0:
- if data_n < 0:
- data_n = -data_n
- y_err[i_bin] += frac * frac * data_n
- else:
- y_err[i_bin] += frac * frac * err_data[n] * err_data[n]
-
- if dq_data != None:
- # To be consistent with dq calculation in 1d reduction,
- # we need just the averages (not quadratures) because
- # it should not depend on the number of the q points
- # in the qr bins.
- x_err[i_bin] += frac * dq_data[n]
- else:
- x_err = None
- y_counts[i_bin] += frac
-
- # Organize the results
- for i in range(self.nbins):
- y[i] = y[i] / y_counts[i]
- y_err[i] = math.sqrt(y_err[i]) / y_counts[i]
-
- # The type of averaging: phi,q2, or q
- # Calculate x[i]should be at the center of the bin
- if run.lower() == 'phi':
- x[i] = (self.phi_max - self.phi_min) / self.nbins * \
- (1.0 * i + 0.5) + self.phi_min
- else:
- # We take the center of ring area, not radius.
- # This is more accurate than taking the radial center of ring.
- #delta_r = (self.r_max - self.r_min) / self.nbins
- #r_inner = self.r_min + delta_r * i
- #r_outer = r_inner + delta_r
- #x[i] = math.sqrt((r_inner * r_inner + r_outer * r_outer) / 2)
- x[i] = x[i] / y_counts[i]
- y_err[y_err == 0] = numpy.average(y_err)
- idx = (numpy.isfinite(y) & numpy.isfinite(y_err))
- if x_err != None:
- d_x = x_err[idx] / y_counts[idx]
- else:
- d_x = None
- if not idx.any():
- msg = "Average Error: No points inside sector of ROI to average..."
- raise ValueError, msg
- #elif len(y[idx])!= self.nbins:
- # print "resulted",self.nbins- len(y[idx]),
- #"empty bin(s) due to tight binning..."
- return Data1D(x=x[idx], y=y[idx], dy=y_err[idx], dx=d_x)
-
-
-class SectorPhi(_Sector):
- """
- Sector average as a function of phi.
- I(phi) is return and the data is averaged over Q.
-
- A sector is defined by r_min, r_max, phi_min, phi_max.
- The number of bin in phi also has to be defined.
- """
- def __call__(self, data2D):
- """
- Perform sector average and return I(phi).
-
- :param data2D: Data2D object
- :return: Data1D object
- """
- return self._agv(data2D, 'phi')
-
-
-class SectorQ(_Sector):
- """
- Sector average as a function of Q for both symatric wings.
- I(Q) is return and the data is averaged over phi.
-
- A sector is defined by r_min, r_max, phi_min, phi_max.
- r_min, r_max, phi_min, phi_max >0.
- The number of bin in Q also has to be defined.
- """
- def __call__(self, data2D):
- """
- Perform sector average and return I(Q).
-
- :param data2D: Data2D object
-
- :return: Data1D object
- """
- return self._agv(data2D, 'q2')
-
-
-class Ringcut(object):
- """
- Defines a ring on a 2D data set.
- The ring is defined by r_min, r_max, and
- the position of the center of the ring.
-
- The data returned is the region inside the ring
-
- Phi_min and phi_max should be defined between 0 and 2*pi
- in anti-clockwise starting from the x- axis on the left-hand side
- """
- def __init__(self, r_min=0, r_max=0, center_x=0, center_y=0):
- # Minimum radius
- self.r_min = r_min
- # Maximum radius
- self.r_max = r_max
- # Center of the ring in x
- self.center_x = center_x
- # Center of the ring in y
- self.center_y = center_y
-
- def __call__(self, data2D):
- """
- Apply the ring to the data set.
- Returns the angular distribution for a given q range
-
- :param data2D: Data2D object
-
- :return: index array in the range
- """
- if data2D.__class__.__name__ not in ["Data2D", "plottable_2D"]:
- raise RuntimeError, "Ring cut only take plottable_2D objects"
-
- # Get data
- qx_data = data2D.qx_data
- qy_data = data2D.qy_data
- q_data = numpy.sqrt(qx_data * qx_data + qy_data * qy_data)
-
- # check whether or not the data point is inside ROI
- out = (self.r_min <= q_data) & (self.r_max >= q_data)
- return out
-
-
-class Boxcut(object):
- """
- Find a rectangular 2D region of interest.
- """
- def __init__(self, x_min=0.0, x_max=0.0, y_min=0.0, y_max=0.0):
- # Minimum Qx value [A-1]
- self.x_min = x_min
- # Maximum Qx value [A-1]
- self.x_max = x_max
- # Minimum Qy value [A-1]
- self.y_min = y_min
- # Maximum Qy value [A-1]
- self.y_max = y_max
-
- def __call__(self, data2D):
- """
- Find a rectangular 2D region of interest.
-
- :param data2D: Data2D object
- :return: mask, 1d array (len = len(data))
- with Trues where the data points are inside ROI, otherwise False
- """
- mask = self._find(data2D)
-
- return mask
-
- def _find(self, data2D):
- """
- Find a rectangular 2D region of interest.
-
- :param data2D: Data2D object
-
- :return: out, 1d array (length = len(data))
- with Trues where the data points are inside ROI, otherwise Falses
- """
- if data2D.__class__.__name__ not in ["Data2D", "plottable_2D"]:
- raise RuntimeError, "Boxcut take only plottable_2D objects"
- # Get qx_ and qy_data
- qx_data = data2D.qx_data
- qy_data = data2D.qy_data
-
- # check whether or not the data point is inside ROI
- outx = (self.x_min <= qx_data) & (self.x_max > qx_data)
- outy = (self.y_min <= qy_data) & (self.y_max > qy_data)
-
- return outx & outy
-
-
-class Sectorcut(object):
- """
- Defines a sector (major + minor) region on a 2D data set.
- The sector is defined by phi_min, phi_max,
- where phi_min and phi_max are defined by the right
- and left lines wrt central line.
-
- Phi_min and phi_max are given in units of radian
- and (phi_max-phi_min) should not be larger than pi
- """
- def __init__(self, phi_min=0, phi_max=math.pi):
- self.phi_min = phi_min
- self.phi_max = phi_max
-
- def __call__(self, data2D):
- """
- Find a rectangular 2D region of interest.
-
- :param data2D: Data2D object
-
- :return: mask, 1d array (len = len(data))
-
- with Trues where the data points are inside ROI, otherwise False
- """
- mask = self._find(data2D)
-
- return mask
-
- def _find(self, data2D):
- """
- Find a rectangular 2D region of interest.
-
- :param data2D: Data2D object
-
- :return: out, 1d array (length = len(data))
-
- with Trues where the data points are inside ROI, otherwise Falses
- """
- if data2D.__class__.__name__ not in ["Data2D", "plottable_2D"]:
- raise RuntimeError, "Sectorcut take only plottable_2D objects"
- Pi = math.pi
- # Get data
- qx_data = data2D.qx_data
- qy_data = data2D.qy_data
-
- # get phi from data
- phi_data = numpy.arctan2(qy_data, qx_data)
-
- # Get the min and max into the region: -pi <= phi < Pi
- phi_min_major = flip_phi(self.phi_min + Pi) - Pi
- phi_max_major = flip_phi(self.phi_max + Pi) - Pi
- # check for major sector
- if phi_min_major > phi_max_major:
- out_major = (phi_min_major <= phi_data) + (phi_max_major > phi_data)
- else:
- out_major = (phi_min_major <= phi_data) & (phi_max_major > phi_data)
-
- # minor sector
- # Get the min and max into the region: -pi <= phi < Pi
- phi_min_minor = flip_phi(self.phi_min) - Pi
- phi_max_minor = flip_phi(self.phi_max) - Pi
-
- # check for minor sector
- if phi_min_minor > phi_max_minor:
- out_minor = (phi_min_minor <= phi_data) + \
- (phi_max_minor >= phi_data)
- else:
- out_minor = (phi_min_minor <= phi_data) & \
- (phi_max_minor >= phi_data)
- out = out_major + out_minor
-
- return out
+from __future__ import division
+"""
+Data manipulations for 2D data sets.
+Using the meta data information, various types of averaging
+are performed in Q-space
+
+To test this module use:
+```
+cd test
+PYTHONPATH=../src/ python2 -m sasdataloader.test.utest_averaging DataInfoTests.test_sectorphi_quarter
+```
+"""
+#####################################################################
+# This software was developed by the University of Tennessee as part of the
+# Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
+# project funded by the US National Science Foundation.
+# See the license text in license.txt
+# copyright 2008, University of Tennessee
+######################################################################
+
+
+# TODO: copy the meta data from the 2D object to the resulting 1D object
+import math
+import numpy as np
+import sys
+
+#from data_info import plottable_2D
+from .data_info import Data1D
+
+
+def get_q(dx, dy, det_dist, wavelength):
+ """
+ :param dx: x-distance from beam center [mm]
+ :param dy: y-distance from beam center [mm]
+ :return: q-value at the given position
+ """
+ # Distance from beam center in the plane of detector
+ plane_dist = math.sqrt(dx * dx + dy * dy)
+ # Half of the scattering angle
+ theta = 0.5 * math.atan(plane_dist / det_dist)
+ return (4.0 * math.pi / wavelength) * math.sin(theta)
+
+
+def get_q_compo(dx, dy, det_dist, wavelength, compo=None):
+ """
+ This reduces tiny error at very large q.
+ Implementation of this func is not started yet.<--ToDo
+ """
+ if dy == 0:
+ if dx >= 0:
+ angle_xy = 0
+ else:
+ angle_xy = math.pi
+ else:
+ angle_xy = math.atan(dx / dy)
+
+ if compo == "x":
+ out = get_q(dx, dy, det_dist, wavelength) * math.cos(angle_xy)
+ elif compo == "y":
+ out = get_q(dx, dy, det_dist, wavelength) * math.sin(angle_xy)
+ else:
+ out = get_q(dx, dy, det_dist, wavelength)
+ return out
+
+
+def flip_phi(phi):
+ """
+ Correct phi to within the 0 <= to <= 2pi range
+
+ :return: phi in >=0 and <=2Pi
+ """
+ Pi = math.pi
+ if phi < 0:
+ phi_out = phi + (2 * Pi)
+ elif phi > (2 * Pi):
+ phi_out = phi - (2 * Pi)
+ else:
+ phi_out = phi
+ return phi_out
+
+def get_pixel_fraction_square(x, xmin, xmax):
+ """
+ Return the fraction of the length
+ from xmin to x.::
+
+ A B
+ +-----------+---------+
+ xmin x xmax
+
+ :param x: x-value
+ :param xmin: minimum x for the length considered
+ :param xmax: minimum x for the length considered
+ :return: (x-xmin)/(xmax-xmin) when xmin < x < xmax
+
+ """
+ if x <= xmin:
+ return 0.0
+ if x > xmin and x < xmax:
+ return (x - xmin) / (xmax - xmin)
+ else:
+ return 1.0
+
+def get_intercept(q, q_0, q_1):
+ """
+ Returns the fraction of the side at which the
+ q-value intercept the pixel, None otherwise.
+ The values returned is the fraction ON THE SIDE
+ OF THE LOWEST Q. ::
+
+ A B
+ +-----------+--------+ <--- pixel size
+ 0 1
+ Q_0 -------- Q ----- Q_1 <--- equivalent Q range
+ if Q_1 > Q_0, A is returned
+ if Q_1 < Q_0, B is returned
+ if Q is outside the range of [Q_0, Q_1], None is returned
+
+ """
+ if q_1 > q_0:
+ if q > q_0 and q <= q_1:
+ return (q - q_0) / (q_1 - q_0)
+ else:
+ if q > q_1 and q <= q_0:
+ return (q - q_1) / (q_0 - q_1)
+ return None
+
+def get_pixel_fraction(qmax, q_00, q_01, q_10, q_11):
+ """
+ Returns the fraction of the pixel defined by
+ the four corners (q_00, q_01, q_10, q_11) that
+ has q < qmax.::
+
+ q_01 q_11
+ y=1 +--------------+
+ | |
+ | |
+ | |
+ y=0 +--------------+
+ q_00 q_10
+
+ x=0 x=1
+
+ """
+ # y side for x = minx
+ x_0 = get_intercept(qmax, q_00, q_01)
+ # y side for x = maxx
+ x_1 = get_intercept(qmax, q_10, q_11)
+
+ # x side for y = miny
+ y_0 = get_intercept(qmax, q_00, q_10)
+ # x side for y = maxy
+ y_1 = get_intercept(qmax, q_01, q_11)
+
+ # surface fraction for a 1x1 pixel
+ frac_max = 0
+
+ if x_0 and x_1:
+ frac_max = (x_0 + x_1) / 2.0
+ elif y_0 and y_1:
+ frac_max = (y_0 + y_1) / 2.0
+ elif x_0 and y_0:
+ if q_00 < q_10:
+ frac_max = x_0 * y_0 / 2.0
+ else:
+ frac_max = 1.0 - x_0 * y_0 / 2.0
+ elif x_0 and y_1:
+ if q_00 < q_10:
+ frac_max = x_0 * y_1 / 2.0
+ else:
+ frac_max = 1.0 - x_0 * y_1 / 2.0
+ elif x_1 and y_0:
+ if q_00 > q_10:
+ frac_max = x_1 * y_0 / 2.0
+ else:
+ frac_max = 1.0 - x_1 * y_0 / 2.0
+ elif x_1 and y_1:
+ if q_00 < q_10:
+ frac_max = 1.0 - (1.0 - x_1) * (1.0 - y_1) / 2.0
+ else:
+ frac_max = (1.0 - x_1) * (1.0 - y_1) / 2.0
+
+ # If we make it here, there is no intercept between
+ # this pixel and the constant-q ring. We only need
+ # to know if we have to include it or exclude it.
+ elif (q_00 + q_01 + q_10 + q_11) / 4.0 < qmax:
+ frac_max = 1.0
+
+ return frac_max
+
+def get_dq_data(data2D):
+ '''
+ Get the dq for resolution averaging
+ The pinholes and det. pix contribution present
+ in both direction of the 2D which must be subtracted when
+ converting to 1D: dq_overlap should calculated ideally at
+ q = 0. Note This method works on only pinhole geometry.
+ Extrapolate dqx(r) and dqy(phi) at q = 0, and take an average.
+ '''
+ z_max = max(data2D.q_data)
+ z_min = min(data2D.q_data)
+ dqx_at_z_max = data2D.dqx_data[np.argmax(data2D.q_data)]
+ dqx_at_z_min = data2D.dqx_data[np.argmin(data2D.q_data)]
+ dqy_at_z_max = data2D.dqy_data[np.argmax(data2D.q_data)]
+ dqy_at_z_min = data2D.dqy_data[np.argmin(data2D.q_data)]
+ # Find qdx at q = 0
+ dq_overlap_x = (dqx_at_z_min * z_max - dqx_at_z_max * z_min) / (z_max - z_min)
+ # when extrapolation goes wrong
+ if dq_overlap_x > min(data2D.dqx_data):
+ dq_overlap_x = min(data2D.dqx_data)
+ dq_overlap_x *= dq_overlap_x
+ # Find qdx at q = 0
+ dq_overlap_y = (dqy_at_z_min * z_max - dqy_at_z_max * z_min) / (z_max - z_min)
+ # when extrapolation goes wrong
+ if dq_overlap_y > min(data2D.dqy_data):
+ dq_overlap_y = min(data2D.dqy_data)
+ # get dq at q=0.
+ dq_overlap_y *= dq_overlap_y
+
+ dq_overlap = np.sqrt((dq_overlap_x + dq_overlap_y) / 2.0)
+ # Final protection of dq
+ if dq_overlap < 0:
+ dq_overlap = dqy_at_z_min
+ dqx_data = data2D.dqx_data[np.isfinite(data2D.data)]
+ dqy_data = data2D.dqy_data[np.isfinite(
+ data2D.data)] - dq_overlap
+ # def; dqx_data = dq_r dqy_data = dq_phi
+ # Convert dq 2D to 1D here
+ dq_data = np.sqrt(dqx_data**2 + dqx_data**2)
+ return dq_data
+
+################################################################################
+
+def reader2D_converter(data2d=None):
+ """
+ convert old 2d format opened by IhorReader or danse_reader
+ to new Data2D format
+ This is mainly used by the Readers
+
+ :param data2d: 2d array of Data2D object
+ :return: 1d arrays of Data2D object
+
+ """
+ if data2d.data is None or data2d.x_bins is None or data2d.y_bins is None:
+ raise ValueError("Can't convert this data: data=None...")
+ new_x = np.tile(data2d.x_bins, (len(data2d.y_bins), 1))
+ new_y = np.tile(data2d.y_bins, (len(data2d.x_bins), 1))
+ new_y = new_y.swapaxes(0, 1)
+
+ new_data = data2d.data.flatten()
+ qx_data = new_x.flatten()
+ qy_data = new_y.flatten()
+ q_data = np.sqrt(qx_data * qx_data + qy_data * qy_data)
+ if data2d.err_data is None or np.any(data2d.err_data <= 0):
+ new_err_data = np.sqrt(np.abs(new_data))
+ else:
+ new_err_data = data2d.err_data.flatten()
+ mask = np.ones(len(new_data), dtype=bool)
+
+ # TODO: make sense of the following two lines...
+ #from sas.sascalc.dataloader.data_info import Data2D
+ #output = Data2D()
+ output = data2d
+ output.data = new_data
+ output.err_data = new_err_data
+ output.qx_data = qx_data
+ output.qy_data = qy_data
+ output.q_data = q_data
+ output.mask = mask
+
+ return output
+
+################################################################################
+
+class Binning(object):
+ '''
+ This class just creates a binning object
+ either linear or log
+ '''
+
+ def __init__(self, min_value, max_value, n_bins, base=None):
+ '''
+ if base is None: Linear binning
+ '''
+ self.min = min_value if min_value > 0 else 0.0001
+ self.max = max_value
+ self.n_bins = n_bins
+ self.base = base
+
+ def get_bin_index(self, value):
+ '''
+ The general formula logarithm binning is:
+ bin = floor(N * (log(x) - log(min)) / (log(max) - log(min)))
+ '''
+ if self.base:
+ temp_x = self.n_bins * (math.log(value, self.base) - math.log(self.min, self.base))
+ temp_y = math.log(self.max, self.base) - math.log(self.min, self.base)
+ else:
+ temp_x = self.n_bins * (value - self.min)
+ temp_y = self.max - self.min
+ # Bin index calulation
+ return int(math.floor(temp_x / temp_y))
+
+
+################################################################################
+
+class _Slab(object):
+ """
+ Compute average I(Q) for a region of interest
+ """
+
+ def __init__(self, x_min=0.0, x_max=0.0, y_min=0.0,
+ y_max=0.0, bin_width=0.001):
+ # Minimum Qx value [A-1]
+ self.x_min = x_min
+ # Maximum Qx value [A-1]
+ self.x_max = x_max
+ # Minimum Qy value [A-1]
+ self.y_min = y_min
+ # Maximum Qy value [A-1]
+ self.y_max = y_max
+ # Bin width (step size) [A-1]
+ self.bin_width = bin_width
+ # If True, I(|Q|) will be return, otherwise,
+ # negative q-values are allowed
+ self.fold = False
+
+ def __call__(self, data2D):
+ return NotImplemented
+
+ def _avg(self, data2D, maj):
+ """
+ Compute average I(Q_maj) for a region of interest.
+ The major axis is defined as the axis of Q_maj.
+ The minor axis is the axis that we average over.
+
+ :param data2D: Data2D object
+ :param maj_min: min value on the major axis
+ :return: Data1D object
+ """
+ if len(data2D.detector) > 1:
+ msg = "_Slab._avg: invalid number of "
+ msg += " detectors: %g" % len(data2D.detector)
+ raise RuntimeError(msg)
+
+ # Get data
+ data = data2D.data[np.isfinite(data2D.data)]
+ err_data = data2D.err_data[np.isfinite(data2D.data)]
+ qx_data = data2D.qx_data[np.isfinite(data2D.data)]
+ qy_data = data2D.qy_data[np.isfinite(data2D.data)]
+
+ # Build array of Q intervals
+ if maj == 'x':
+ if self.fold:
+ x_min = 0
+ else:
+ x_min = self.x_min
+ nbins = int(math.ceil((self.x_max - x_min) / self.bin_width))
+ elif maj == 'y':
+ if self.fold:
+ y_min = 0
+ else:
+ y_min = self.y_min
+ nbins = int(math.ceil((self.y_max - y_min) / self.bin_width))
+ else:
+ raise RuntimeError("_Slab._avg: unrecognized axis %s" % str(maj))
+
+ x = np.zeros(nbins)
+ y = np.zeros(nbins)
+ err_y = np.zeros(nbins)
+ y_counts = np.zeros(nbins)
+
+ # Average pixelsize in q space
+ for npts in range(len(data)):
+ # default frac
+ frac_x = 0
+ frac_y = 0
+ # get ROI
+ if self.x_min <= qx_data[npts] and self.x_max > qx_data[npts]:
+ frac_x = 1
+ if self.y_min <= qy_data[npts] and self.y_max > qy_data[npts]:
+ frac_y = 1
+ frac = frac_x * frac_y
+
+ if frac == 0:
+ continue
+ # binning: find axis of q
+ if maj == 'x':
+ q_value = qx_data[npts]
+ min_value = x_min
+ if maj == 'y':
+ q_value = qy_data[npts]
+ min_value = y_min
+ if self.fold and q_value < 0:
+ q_value = -q_value
+ # bin
+ i_q = int(math.ceil((q_value - min_value) / self.bin_width)) - 1
+
+ # skip outside of max bins
+ if i_q < 0 or i_q >= nbins:
+ continue
+
+ # TODO: find better definition of x[i_q] based on q_data
+ # min_value + (i_q + 1) * self.bin_width / 2.0
+ x[i_q] += frac * q_value
+ y[i_q] += frac * data[npts]
+
+ if err_data is None or err_data[npts] == 0.0:
+ if data[npts] < 0:
+ data[npts] = -data[npts]
+ err_y[i_q] += frac * frac * data[npts]
+ else:
+ err_y[i_q] += frac * frac * err_data[npts] * err_data[npts]
+ y_counts[i_q] += frac
+
+ # Average the sums
+ for n in range(nbins):
+ err_y[n] = math.sqrt(err_y[n])
+
+ err_y = err_y / y_counts
+ y = y / y_counts
+ x = x / y_counts
+ idx = (np.isfinite(y) & np.isfinite(x))
+
+ if not idx.any():
+ msg = "Average Error: No points inside ROI to average..."
+ raise ValueError(msg)
+ return Data1D(x=x[idx], y=y[idx], dy=err_y[idx])
+
+
+class SlabY(_Slab):
+ """
+ Compute average I(Qy) for a region of interest
+ """
+
+ def __call__(self, data2D):
+ """
+ Compute average I(Qy) for a region of interest
+
+ :param data2D: Data2D object
+ :return: Data1D object
+ """
+ return self._avg(data2D, 'y')
+
+
+class SlabX(_Slab):
+ """
+ Compute average I(Qx) for a region of interest
+ """
+
+ def __call__(self, data2D):
+ """
+ Compute average I(Qx) for a region of interest
+ :param data2D: Data2D object
+ :return: Data1D object
+ """
+ return self._avg(data2D, 'x')
+
+################################################################################
+
+class Boxsum(object):
+ """
+ Perform the sum of counts in a 2D region of interest.
+ """
+
+ def __init__(self, x_min=0.0, x_max=0.0, y_min=0.0, y_max=0.0):
+ # Minimum Qx value [A-1]
+ self.x_min = x_min
+ # Maximum Qx value [A-1]
+ self.x_max = x_max
+ # Minimum Qy value [A-1]
+ self.y_min = y_min
+ # Maximum Qy value [A-1]
+ self.y_max = y_max
+
+ def __call__(self, data2D):
+ """
+ Perform the sum in the region of interest
+
+ :param data2D: Data2D object
+ :return: number of counts, error on number of counts,
+ number of points summed
+ """
+ y, err_y, y_counts = self._sum(data2D)
+
+ # Average the sums
+ counts = 0 if y_counts == 0 else y
+ error = 0 if y_counts == 0 else math.sqrt(err_y)
+
+ # Added y_counts to return, SMK & PDB, 04/03/2013
+ return counts, error, y_counts
+
+ def _sum(self, data2D):
+ """
+ Perform the sum in the region of interest
+
+ :param data2D: Data2D object
+ :return: number of counts,
+ error on number of counts, number of entries summed
+ """
+ if len(data2D.detector) > 1:
+ msg = "Circular averaging: invalid number "
+ msg += "of detectors: %g" % len(data2D.detector)
+ raise RuntimeError(msg)
+ # Get data
+ data = data2D.data[np.isfinite(data2D.data)]
+ err_data = data2D.err_data[np.isfinite(data2D.data)]
+ qx_data = data2D.qx_data[np.isfinite(data2D.data)]
+ qy_data = data2D.qy_data[np.isfinite(data2D.data)]
+
+ y = 0.0
+ err_y = 0.0
+ y_counts = 0.0
+
+ # Average pixelsize in q space
+ for npts in range(len(data)):
+ # default frac
+ frac_x = 0
+ frac_y = 0
+
+ # get min and max at each points
+ qx = qx_data[npts]
+ qy = qy_data[npts]
+
+ # get the ROI
+ if self.x_min <= qx and self.x_max > qx:
+ frac_x = 1
+ if self.y_min <= qy and self.y_max > qy:
+ frac_y = 1
+ # Find the fraction along each directions
+ frac = frac_x * frac_y
+ if frac == 0:
+ continue
+ y += frac * data[npts]
+ if err_data is None or err_data[npts] == 0.0:
+ if data[npts] < 0:
+ data[npts] = -data[npts]
+ err_y += frac * frac * data[npts]
+ else:
+ err_y += frac * frac * err_data[npts] * err_data[npts]
+ y_counts += frac
+ return y, err_y, y_counts
+
+
+class Boxavg(Boxsum):
+ """
+ Perform the average of counts in a 2D region of interest.
+ """
+
+ def __init__(self, x_min=0.0, x_max=0.0, y_min=0.0, y_max=0.0):
+ super(Boxavg, self).__init__(x_min=x_min, x_max=x_max,
+ y_min=y_min, y_max=y_max)
+
+ def __call__(self, data2D):
+ """
+ Perform the sum in the region of interest
+
+ :param data2D: Data2D object
+ :return: average counts, error on average counts
+
+ """
+ y, err_y, y_counts = self._sum(data2D)
+
+ # Average the sums
+ counts = 0 if y_counts == 0 else y / y_counts
+ error = 0 if y_counts == 0 else math.sqrt(err_y) / y_counts
+
+ return counts, error
+
+################################################################################
+
+class CircularAverage(object):
+ """
+ Perform circular averaging on 2D data
+
+ The data returned is the distribution of counts
+ as a function of Q
+ """
+
+ def __init__(self, r_min=0.0, r_max=0.0, bin_width=0.0005):
+ # Minimum radius included in the average [A-1]
+ self.r_min = r_min
+ # Maximum radius included in the average [A-1]
+ self.r_max = r_max
+ # Bin width (step size) [A-1]
+ self.bin_width = bin_width
+
+ def __call__(self, data2D, ismask=False):
+ """
+ Perform circular averaging on the data
+
+ :param data2D: Data2D object
+ :return: Data1D object
+ """
+ # Get data W/ finite values
+ data = data2D.data[np.isfinite(data2D.data)]
+ q_data = data2D.q_data[np.isfinite(data2D.data)]
+ err_data = data2D.err_data[np.isfinite(data2D.data)]
+ mask_data = data2D.mask[np.isfinite(data2D.data)]
+
+ dq_data = None
+ if data2D.dqx_data is not None and data2D.dqy_data is not None:
+ dq_data = get_dq_data(data2D)
+
+ if len(q_data) == 0:
+ msg = "Circular averaging: invalid q_data: %g" % data2D.q_data
+ raise RuntimeError(msg)
+
+ # Build array of Q intervals
+ nbins = int(math.ceil((self.r_max - self.r_min) / self.bin_width))
+
+ x = np.zeros(nbins)
+ y = np.zeros(nbins)
+ err_y = np.zeros(nbins)
+ err_x = np.zeros(nbins)
+ y_counts = np.zeros(nbins)
+
+ for npt in range(len(data)):
+
+ if ismask and not mask_data[npt]:
+ continue
+
+ frac = 0
+
+ # q-value at the pixel (j,i)
+ q_value = q_data[npt]
+ data_n = data[npt]
+
+ # No need to calculate the frac when all data are within range
+ if self.r_min >= self.r_max:
+ raise ValueError("Limit Error: min > max")
+
+ if self.r_min <= q_value and q_value <= self.r_max:
+ frac = 1
+ if frac == 0:
+ continue
+ i_q = int(math.floor((q_value - self.r_min) / self.bin_width))
+
+ # Take care of the edge case at phi = 2pi.
+ if i_q == nbins:
+ i_q = nbins - 1
+ y[i_q] += frac * data_n
+ # Take dqs from data to get the q_average
+ x[i_q] += frac * q_value
+ if err_data is None or err_data[npt] == 0.0:
+ if data_n < 0:
+ data_n = -data_n
+ err_y[i_q] += frac * frac * data_n
+ else:
+ err_y[i_q] += frac * frac * err_data[npt] * err_data[npt]
+ if dq_data is not None:
+ # To be consistent with dq calculation in 1d reduction,
+ # we need just the averages (not quadratures) because
+ # it should not depend on the number of the q points
+ # in the qr bins.
+ err_x[i_q] += frac * dq_data[npt]
+ else:
+ err_x = None
+ y_counts[i_q] += frac
+
+ # Average the sums
+ for n in range(nbins):
+ if err_y[n] < 0:
+ err_y[n] = -err_y[n]
+ err_y[n] = math.sqrt(err_y[n])
+ # if err_x is not None:
+ # err_x[n] = math.sqrt(err_x[n])
+
+ err_y = err_y / y_counts
+ err_y[err_y == 0] = np.average(err_y)
+ y = y / y_counts
+ x = x / y_counts
+ idx = (np.isfinite(y)) & (np.isfinite(x))
+
+ if err_x is not None:
+ d_x = err_x[idx] / y_counts[idx]
+ else:
+ d_x = None
+
+ if not idx.any():
+ msg = "Average Error: No points inside ROI to average..."
+ raise ValueError(msg)
+
+ return Data1D(x=x[idx], y=y[idx], dy=err_y[idx], dx=d_x)
+
+################################################################################
+
+class Ring(object):
+ """
+ Defines a ring on a 2D data set.
+ The ring is defined by r_min, r_max, and
+ the position of the center of the ring.
+
+ The data returned is the distribution of counts
+ around the ring as a function of phi.
+
+ Phi_min and phi_max should be defined between 0 and 2*pi
+ in anti-clockwise starting from the x- axis on the left-hand side
+ """
+ # Todo: remove center.
+
+ def __init__(self, r_min=0, r_max=0, center_x=0, center_y=0, nbins=36):
+ # Minimum radius
+ self.r_min = r_min
+ # Maximum radius
+ self.r_max = r_max
+ # Center of the ring in x
+ self.center_x = center_x
+ # Center of the ring in y
+ self.center_y = center_y
+ # Number of angular bins
+ self.nbins_phi = nbins
+
+ def __call__(self, data2D):
+ """
+ Apply the ring to the data set.
+ Returns the angular distribution for a given q range
+
+ :param data2D: Data2D object
+
+ :return: Data1D object
+ """
+ if data2D.__class__.__name__ not in ["Data2D", "plottable_2D"]:
+ raise RuntimeError("Ring averaging only take plottable_2D objects")
+
+ Pi = math.pi
+
+ # Get data
+ data = data2D.data[np.isfinite(data2D.data)]
+ q_data = data2D.q_data[np.isfinite(data2D.data)]
+ err_data = data2D.err_data[np.isfinite(data2D.data)]
+ qx_data = data2D.qx_data[np.isfinite(data2D.data)]
+ qy_data = data2D.qy_data[np.isfinite(data2D.data)]
+
+ # Set space for 1d outputs
+ phi_bins = np.zeros(self.nbins_phi)
+ phi_counts = np.zeros(self.nbins_phi)
+ phi_values = np.zeros(self.nbins_phi)
+ phi_err = np.zeros(self.nbins_phi)
+
+ # Shift to apply to calculated phi values in order
+ # to center first bin at zero
+ phi_shift = Pi / self.nbins_phi
+
+ for npt in range(len(data)):
+ frac = 0
+ # q-value at the point (npt)
+ q_value = q_data[npt]
+ data_n = data[npt]
+
+ # phi-value at the point (npt)
+ phi_value = math.atan2(qy_data[npt], qx_data[npt]) + Pi
+
+ if self.r_min <= q_value and q_value <= self.r_max:
+ frac = 1
+ if frac == 0:
+ continue
+ # binning
+ i_phi = int(math.floor((self.nbins_phi) *
+ (phi_value + phi_shift) / (2 * Pi)))
+
+ # Take care of the edge case at phi = 2pi.
+ if i_phi >= self.nbins_phi:
+ i_phi = 0
+ phi_bins[i_phi] += frac * data[npt]
+
+ if err_data is None or err_data[npt] == 0.0:
+ if data_n < 0:
+ data_n = -data_n
+ phi_err[i_phi] += frac * frac * math.fabs(data_n)
+ else:
+ phi_err[i_phi] += frac * frac * err_data[npt] * err_data[npt]
+ phi_counts[i_phi] += frac
+
+ for i in range(self.nbins_phi):
+ phi_bins[i] = phi_bins[i] / phi_counts[i]
+ phi_err[i] = math.sqrt(phi_err[i]) / phi_counts[i]
+ phi_values[i] = 2.0 * math.pi / self.nbins_phi * (1.0 * i)
+
+ idx = (np.isfinite(phi_bins))
+
+ if not idx.any():
+ msg = "Average Error: No points inside ROI to average..."
+ raise ValueError(msg)
+ # elif len(phi_bins[idx])!= self.nbins_phi:
+ # print "resulted",self.nbins_phi- len(phi_bins[idx])
+ #,"empty bin(s) due to tight binning..."
+ return Data1D(x=phi_values[idx], y=phi_bins[idx], dy=phi_err[idx])
+
+
+class _Sector(object):
+ """
+ Defines a sector region on a 2D data set.
+ The sector is defined by r_min, r_max, phi_min, phi_max,
+ and the position of the center of the ring
+ where phi_min and phi_max are defined by the right
+ and left lines wrt central line
+ and phi_max could be less than phi_min.
+
+ Phi is defined between 0 and 2*pi in anti-clockwise
+ starting from the x- axis on the left-hand side
+ """
+
+ def __init__(self, r_min, r_max, phi_min=0, phi_max=2 * math.pi, nbins=20,
+ base=None):
+ '''
+ :param base: must be a valid base for an algorithm, i.e.,
+ a positive number
+ '''
+ self.r_min = r_min
+ self.r_max = r_max
+ self.phi_min = phi_min
+ self.phi_max = phi_max
+ self.nbins = nbins
+ self.base = base
+
+ def _agv(self, data2D, run='phi'):
+ """
+ Perform sector averaging.
+
+ :param data2D: Data2D object
+ :param run: define the varying parameter ('phi' , 'q' , or 'q2')
+
+ :return: Data1D object
+ """
+ if data2D.__class__.__name__ not in ["Data2D", "plottable_2D"]:
+ raise RuntimeError("Ring averaging only take plottable_2D objects")
+
+ # Get the all data & info
+ data = data2D.data[np.isfinite(data2D.data)]
+ q_data = data2D.q_data[np.isfinite(data2D.data)]
+ err_data = data2D.err_data[np.isfinite(data2D.data)]
+ qx_data = data2D.qx_data[np.isfinite(data2D.data)]
+ qy_data = data2D.qy_data[np.isfinite(data2D.data)]
+
+ dq_data = None
+ if data2D.dqx_data is not None and data2D.dqy_data is not None:
+ dq_data = get_dq_data(data2D)
+
+ # set space for 1d outputs
+ x = np.zeros(self.nbins)
+ y = np.zeros(self.nbins)
+ y_err = np.zeros(self.nbins)
+ x_err = np.zeros(self.nbins)
+ y_counts = np.zeros(self.nbins) # Cycle counts (for the mean)
+
+ # Get the min and max into the region: 0 <= phi < 2Pi
+ phi_min = flip_phi(self.phi_min)
+ phi_max = flip_phi(self.phi_max)
+
+ # binning object
+ if run.lower() == 'phi':
+ binning = Binning(self.phi_min, self.phi_max, self.nbins, self.base)
+ else:
+ binning = Binning(self.r_min, self.r_max, self.nbins, self.base)
+
+ for n in range(len(data)):
+
+ # q-value at the pixel (j,i)
+ q_value = q_data[n]
+ data_n = data[n]
+
+ # Is pixel within range?
+ is_in = False
+
+ # phi-value of the pixel (j,i)
+ phi_value = math.atan2(qy_data[n], qx_data[n]) + math.pi
+
+ # No need to calculate: data outside of the radius
+ if self.r_min > q_value or q_value > self.r_max:
+ continue
+
+ # In case of two ROIs (symmetric major and minor regions)(for 'q2')
+ if run.lower() == 'q2':
+ # For minor sector wing
+ # Calculate the minor wing phis
+ phi_min_minor = flip_phi(phi_min - math.pi)
+ phi_max_minor = flip_phi(phi_max - math.pi)
+ # Check if phis of the minor ring is within 0 to 2pi
+ if phi_min_minor > phi_max_minor:
+ is_in = (phi_value > phi_min_minor or
+ phi_value < phi_max_minor)
+ else:
+ is_in = (phi_value > phi_min_minor and
+ phi_value < phi_max_minor)
+
+ # For all cases(i.e.,for 'q', 'q2', and 'phi')
+ # Find pixels within ROI
+ if phi_min > phi_max:
+ is_in = is_in or (phi_value > phi_min or
+ phi_value < phi_max)
+ else:
+ is_in = is_in or (phi_value >= phi_min and
+ phi_value < phi_max)
+
+ # data oustide of the phi range
+ if not is_in:
+ continue
+
+ # Get the binning index
+ if run.lower() == 'phi':
+ i_bin = binning.get_bin_index(phi_value)
+ else:
+ i_bin = binning.get_bin_index(q_value)
+
+ # Take care of the edge case at phi = 2pi.
+ if i_bin == self.nbins:
+ i_bin = self.nbins - 1
+
+ # Get the total y
+ y[i_bin] += data_n
+ x[i_bin] += q_value
+ if err_data[n] is None or err_data[n] == 0.0:
+ if data_n < 0:
+ data_n = -data_n
+ y_err[i_bin] += data_n
+ else:
+ y_err[i_bin] += err_data[n]**2
+
+ if dq_data is not None:
+ # To be consistent with dq calculation in 1d reduction,
+ # we need just the averages (not quadratures) because
+ # it should not depend on the number of the q points
+ # in the qr bins.
+ x_err[i_bin] += dq_data[n]
+ else:
+ x_err = None
+ y_counts[i_bin] += 1
+
+ # Organize the results
+ for i in range(self.nbins):
+ y[i] = y[i] / y_counts[i]
+ y_err[i] = math.sqrt(y_err[i]) / y_counts[i]
+
+ # The type of averaging: phi,q2, or q
+ # Calculate x[i]should be at the center of the bin
+ if run.lower() == 'phi':
+ x[i] = (self.phi_max - self.phi_min) / self.nbins * \
+ (1.0 * i + 0.5) + self.phi_min
+ else:
+ # We take the center of ring area, not radius.
+ # This is more accurate than taking the radial center of ring.
+ # delta_r = (self.r_max - self.r_min) / self.nbins
+ # r_inner = self.r_min + delta_r * i
+ # r_outer = r_inner + delta_r
+ # x[i] = math.sqrt((r_inner * r_inner + r_outer * r_outer) / 2)
+ x[i] = x[i] / y_counts[i]
+ y_err[y_err == 0] = np.average(y_err)
+ idx = (np.isfinite(y) & np.isfinite(y_err))
+ if x_err is not None:
+ d_x = x_err[idx] / y_counts[idx]
+ else:
+ d_x = None
+ if not idx.any():
+ msg = "Average Error: No points inside sector of ROI to average..."
+ raise ValueError(msg)
+ # elif len(y[idx])!= self.nbins:
+ # print "resulted",self.nbins- len(y[idx]),
+ # "empty bin(s) due to tight binning..."
+ return Data1D(x=x[idx], y=y[idx], dy=y_err[idx], dx=d_x)
+
+
+class SectorPhi(_Sector):
+ """
+ Sector average as a function of phi.
+ I(phi) is return and the data is averaged over Q.
+
+ A sector is defined by r_min, r_max, phi_min, phi_max.
+ The number of bin in phi also has to be defined.
+ """
+
+ def __call__(self, data2D):
+ """
+ Perform sector average and return I(phi).
+
+ :param data2D: Data2D object
+ :return: Data1D object
+ """
+ return self._agv(data2D, 'phi')
+
+
+class SectorQ(_Sector):
+ """
+ Sector average as a function of Q for both symatric wings.
+ I(Q) is return and the data is averaged over phi.
+
+ A sector is defined by r_min, r_max, phi_min, phi_max.
+ r_min, r_max, phi_min, phi_max >0.
+ The number of bin in Q also has to be defined.
+ """
+
+ def __call__(self, data2D):
+ """
+ Perform sector average and return I(Q).
+
+ :param data2D: Data2D object
+
+ :return: Data1D object
+ """
+ return self._agv(data2D, 'q2')
+
+################################################################################
+
+class Ringcut(object):
+ """
+ Defines a ring on a 2D data set.
+ The ring is defined by r_min, r_max, and
+ the position of the center of the ring.
+
+ The data returned is the region inside the ring
+
+ Phi_min and phi_max should be defined between 0 and 2*pi
+ in anti-clockwise starting from the x- axis on the left-hand side
+ """
+
+ def __init__(self, r_min=0, r_max=0, center_x=0, center_y=0):
+ # Minimum radius
+ self.r_min = r_min
+ # Maximum radius
+ self.r_max = r_max
+ # Center of the ring in x
+ self.center_x = center_x
+ # Center of the ring in y
+ self.center_y = center_y
+
+ def __call__(self, data2D):
+ """
+ Apply the ring to the data set.
+ Returns the angular distribution for a given q range
+
+ :param data2D: Data2D object
+
+ :return: index array in the range
+ """
+ if data2D.__class__.__name__ not in ["Data2D", "plottable_2D"]:
+ raise RuntimeError("Ring cut only take plottable_2D objects")
+
+ # Get data
+ qx_data = data2D.qx_data
+ qy_data = data2D.qy_data
+ q_data = np.sqrt(qx_data * qx_data + qy_data * qy_data)
+
+ # check whether or not the data point is inside ROI
+ out = (self.r_min <= q_data) & (self.r_max >= q_data)
+ return out
+
+################################################################################
+
+class Boxcut(object):
+ """
+ Find a rectangular 2D region of interest.
+ """
+
+ def __init__(self, x_min=0.0, x_max=0.0, y_min=0.0, y_max=0.0):
+ # Minimum Qx value [A-1]
+ self.x_min = x_min
+ # Maximum Qx value [A-1]
+ self.x_max = x_max
+ # Minimum Qy value [A-1]
+ self.y_min = y_min
+ # Maximum Qy value [A-1]
+ self.y_max = y_max
+
+ def __call__(self, data2D):
+ """
+ Find a rectangular 2D region of interest.
+
+ :param data2D: Data2D object
+ :return: mask, 1d array (len = len(data))
+ with Trues where the data points are inside ROI, otherwise False
+ """
+ mask = self._find(data2D)
+
+ return mask
+
+ def _find(self, data2D):
+ """
+ Find a rectangular 2D region of interest.
+
+ :param data2D: Data2D object
+
+ :return: out, 1d array (length = len(data))
+ with Trues where the data points are inside ROI, otherwise Falses
+ """
+ if data2D.__class__.__name__ not in ["Data2D", "plottable_2D"]:
+ raise RuntimeError("Boxcut take only plottable_2D objects")
+ # Get qx_ and qy_data
+ qx_data = data2D.qx_data
+ qy_data = data2D.qy_data
+
+ # check whether or not the data point is inside ROI
+ outx = (self.x_min <= qx_data) & (self.x_max > qx_data)
+ outy = (self.y_min <= qy_data) & (self.y_max > qy_data)
+
+ return outx & outy
+
+################################################################################
+
+class Sectorcut(object):
+ """
+ Defines a sector (major + minor) region on a 2D data set.
+ The sector is defined by phi_min, phi_max,
+ where phi_min and phi_max are defined by the right
+ and left lines wrt central line.
+
+ Phi_min and phi_max are given in units of radian
+ and (phi_max-phi_min) should not be larger than pi
+ """
+
+ def __init__(self, phi_min=0, phi_max=math.pi):
+ self.phi_min = phi_min
+ self.phi_max = phi_max
+
+ def __call__(self, data2D):
+ """
+ Find a rectangular 2D region of interest.
+
+ :param data2D: Data2D object
+
+ :return: mask, 1d array (len = len(data))
+
+ with Trues where the data points are inside ROI, otherwise False
+ """
+ mask = self._find(data2D)
+
+ return mask
+
+ def _find(self, data2D):
+ """
+ Find a rectangular 2D region of interest.
+
+ :param data2D: Data2D object
+
+ :return: out, 1d array (length = len(data))
+
+ with Trues where the data points are inside ROI, otherwise Falses
+ """
+ if data2D.__class__.__name__ not in ["Data2D", "plottable_2D"]:
+ raise RuntimeError("Sectorcut take only plottable_2D objects")
+ Pi = math.pi
+ # Get data
+ qx_data = data2D.qx_data
+ qy_data = data2D.qy_data
+
+ # get phi from data
+ phi_data = np.arctan2(qy_data, qx_data)
+
+ # Get the min and max into the region: -pi <= phi < Pi
+ phi_min_major = flip_phi(self.phi_min + Pi) - Pi
+ phi_max_major = flip_phi(self.phi_max + Pi) - Pi
+ # check for major sector
+ if phi_min_major > phi_max_major:
+ out_major = (phi_min_major <= phi_data) + \
+ (phi_max_major > phi_data)
+ else:
+ out_major = (phi_min_major <= phi_data) & (
+ phi_max_major > phi_data)
+
+ # minor sector
+ # Get the min and max into the region: -pi <= phi < Pi
+ phi_min_minor = flip_phi(self.phi_min) - Pi
+ phi_max_minor = flip_phi(self.phi_max) - Pi
+
+ # check for minor sector
+ if phi_min_minor > phi_max_minor:
+ out_minor = (phi_min_minor <= phi_data) + \
+ (phi_max_minor >= phi_data)
+ else:
+ out_minor = (phi_min_minor <= phi_data) & \
+ (phi_max_minor >= phi_data)
+ out = out_major + out_minor
+
+ return out
diff --git a/src/sas/sascalc/dataloader/readers/IgorReader.py b/src/sas/sascalc/dataloader/readers/IgorReader.py
deleted file mode 100644
index c461691..0000000
--- a/src/sas/sascalc/dataloader/readers/IgorReader.py
+++ /dev/null
@@ -1,304 +0,0 @@
-"""
- IGOR 2D reduced file reader
-"""
-############################################################################
-#This software was developed by the University of Tennessee as part of the
-#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
-#project funded by the US National Science Foundation.
-#If you use DANSE applications to do scientific research that leads to
-#publication, we ask that you acknowledge the use of the software with the
-#following sentence:
-#This work benefited from DANSE software developed under NSF award DMR-0520547.
-#copyright 2008, University of Tennessee
-#############################################################################
-import os
-import numpy
-import math
-#import logging
-from sas.sascalc.dataloader.data_info import Data2D
-from sas.sascalc.dataloader.data_info import Detector
-from sas.sascalc.dataloader.manipulations import reader2D_converter
-
-# Look for unit converter
-has_converter = True
-try:
- from sas.sascalc.data_util.nxsunit import Converter
-except:
- has_converter = False
-
-
-class Reader:
- """ Simple data reader for Igor data files """
- ## File type
- type_name = "IGOR 2D"
- ## Wildcards
- type = ["IGOR 2D files (*.ASC)|*.ASC"]
- ## Extension
- ext=['.ASC', '.asc']
-
- def read(self, filename=None):
- """ Read file """
- if not os.path.isfile(filename):
- raise ValueError, \
- "Specified file %s is not a regular file" % filename
-
- # Read file
- f = open(filename, 'r')
- buf = f.read()
-
- # Instantiate data object
- output = Data2D()
- output.filename = os.path.basename(filename)
- detector = Detector()
- if len(output.detector) > 0:
- print str(output.detector[0])
- output.detector.append(detector)
-
- # Get content
- dataStarted = False
-
- lines = buf.split('\n')
- itot = 0
- x = []
- y = []
-
- ncounts = 0
-
- xmin = None
- xmax = None
- ymin = None
- ymax = None
-
- i_x = 0
- i_y = -1
- i_tot_row = 0
-
- isInfo = False
- isCenter = False
-
- data_conv_q = None
- data_conv_i = None
-
- if has_converter == True and output.Q_unit != '1/A':
- data_conv_q = Converter('1/A')
- # Test it
- data_conv_q(1.0, output.Q_unit)
-
- if has_converter == True and output.I_unit != '1/cm':
- data_conv_i = Converter('1/cm')
- # Test it
- data_conv_i(1.0, output.I_unit)
-
- for line in lines:
-
- # Find setup info line
- if isInfo:
- isInfo = False
- line_toks = line.split()
- # Wavelength in Angstrom
- try:
- wavelength = float(line_toks[1])
- except:
- msg = "IgorReader: can't read this file, missing wavelength"
- raise ValueError, msg
-
- #Find # of bins in a row assuming the detector is square.
- if dataStarted == True:
- try:
- value = float(line)
- except:
- # Found a non-float entry, skip it
- continue
-
- # Get total bin number
-
- i_tot_row += 1
- i_tot_row = math.ceil(math.sqrt(i_tot_row)) - 1
- #print "i_tot", i_tot_row
- size_x = i_tot_row # 192#128
- size_y = i_tot_row # 192#128
- output.data = numpy.zeros([size_x, size_y])
- output.err_data = numpy.zeros([size_x, size_y])
-
- #Read Header and 2D data
- for line in lines:
- # Find setup info line
- if isInfo:
- isInfo = False
- line_toks = line.split()
- # Wavelength in Angstrom
- try:
- wavelength = float(line_toks[1])
- except:
- msg = "IgorReader: can't read this file, missing wavelength"
- raise ValueError, msg
- # Distance in meters
- try:
- distance = float(line_toks[3])
- except:
- msg = "IgorReader: can't read this file, missing distance"
- raise ValueError, msg
-
- # Distance in meters
- try:
- transmission = float(line_toks[4])
- except:
- msg = "IgorReader: can't read this file, "
- msg += "missing transmission"
- raise ValueError, msg
-
- if line.count("LAMBDA") > 0:
- isInfo = True
-
- # Find center info line
- if isCenter:
- isCenter = False
- line_toks = line.split()
-
- # Center in bin number: Must substrate 1 because
- #the index starts from 1
- center_x = float(line_toks[0]) - 1
- center_y = float(line_toks[1]) - 1
-
- if line.count("BCENT") > 0:
- isCenter = True
-
- # Find data start
- if line.count("***")>0:
- dataStarted = True
-
- # Check that we have all the info
- if wavelength == None \
- or distance == None \
- or center_x == None \
- or center_y == None:
- msg = "IgorReader:Missing information in data file"
- raise ValueError, msg
-
- if dataStarted == True:
- try:
- value = float(line)
- except:
- # Found a non-float entry, skip it
- continue
-
- # Get bin number
- if math.fmod(itot, i_tot_row) == 0:
- i_x = 0
- i_y += 1
- else:
- i_x += 1
-
- output.data[i_y][i_x] = value
- ncounts += 1
-
- # Det 640 x 640 mm
- # Q = 4pi/lambda sin(theta/2)
- # Bin size is 0.5 cm
- #REmoved +1 from theta = (i_x-center_x+1)*0.5 / distance
- # / 100.0 and
- #REmoved +1 from theta = (i_y-center_y+1)*0.5 /
- # distance / 100.0
- #ToDo: Need complete check if the following
- # covert process is consistent with fitting.py.
- theta = (i_x - center_x) * 0.5 / distance / 100.0
- qx = 4.0 * math.pi / wavelength * math.sin(theta/2.0)
-
- if has_converter == True and output.Q_unit != '1/A':
- qx = data_conv_q(qx, units=output.Q_unit)
-
- if xmin == None or qx < xmin:
- xmin = qx
- if xmax == None or qx > xmax:
- xmax = qx
-
- theta = (i_y - center_y) * 0.5 / distance / 100.0
- qy = 4.0 * math.pi / wavelength * math.sin(theta / 2.0)
-
- if has_converter == True and output.Q_unit != '1/A':
- qy = data_conv_q(qy, units=output.Q_unit)
-
- if ymin == None or qy < ymin:
- ymin = qy
- if ymax == None or qy > ymax:
- ymax = qy
-
- if not qx in x:
- x.append(qx)
- if not qy in y:
- y.append(qy)
-
- itot += 1
-
-
- theta = 0.25 / distance / 100.0
- xstep = 4.0 * math.pi / wavelength * math.sin(theta / 2.0)
-
- theta = 0.25 / distance / 100.0
- ystep = 4.0 * math.pi/ wavelength * math.sin(theta / 2.0)
-
- # Store all data ######################################
- # Store wavelength
- if has_converter == True and output.source.wavelength_unit != 'A':
- conv = Converter('A')
- wavelength = conv(wavelength, units=output.source.wavelength_unit)
- output.source.wavelength = wavelength
-
- # Store distance
- if has_converter == True and detector.distance_unit != 'm':
- conv = Converter('m')
- distance = conv(distance, units=detector.distance_unit)
- detector.distance = distance
-
- # Store transmission
- output.sample.transmission = transmission
-
- # Store pixel size
- pixel = 5.0
- if has_converter == True and detector.pixel_size_unit != 'mm':
- conv = Converter('mm')
- pixel = conv(pixel, units=detector.pixel_size_unit)
- detector.pixel_size.x = pixel
- detector.pixel_size.y = pixel
-
- # Store beam center in distance units
- detector.beam_center.x = center_x * pixel
- detector.beam_center.y = center_y * pixel
-
- # Store limits of the image (2D array)
- xmin = xmin - xstep / 2.0
- xmax = xmax + xstep / 2.0
- ymin = ymin - ystep / 2.0
- ymax = ymax + ystep / 2.0
- if has_converter == True and output.Q_unit != '1/A':
- xmin = data_conv_q(xmin, units=output.Q_unit)
- xmax = data_conv_q(xmax, units=output.Q_unit)
- ymin = data_conv_q(ymin, units=output.Q_unit)
- ymax = data_conv_q(ymax, units=output.Q_unit)
- output.xmin = xmin
- output.xmax = xmax
- output.ymin = ymin
- output.ymax = ymax
-
- # Store x and y axis bin centers
- output.x_bins = x
- output.y_bins = y
-
- # Units
- if data_conv_q is not None:
- output.xaxis("\\rm{Q_{x}}", output.Q_unit)
- output.yaxis("\\rm{Q_{y}}", output.Q_unit)
- else:
- output.xaxis("\\rm{Q_{x}}", 'A^{-1}')
- output.yaxis("\\rm{Q_{y}}", 'A^{-1}')
-
- if data_conv_i is not None:
- output.zaxis("\\rm{Intensity}", output.I_unit)
- else:
- output.zaxis("\\rm{Intensity}", "cm^{-1}")
-
- # Store loading process information
- output.meta_data['loader'] = self.type_name
- output = reader2D_converter(output)
-
- return output
diff --git a/src/sas/sascalc/dataloader/readers/__init__.py b/src/sas/sascalc/dataloader/readers/__init__.py
index 564bc7a..a297c80 100644
--- a/src/sas/sascalc/dataloader/readers/__init__.py
+++ b/src/sas/sascalc/dataloader/readers/__init__.py
@@ -1,13 +1,2 @@
-# Backward compatibility with the previous implementation of the default readers
-from associations import register_readers
-
-# Method to associate extensions to default readers
-from associations import read_associations
-
-# Method to return the location of the XML settings file
-def get_data_path():
- """
- Return the location of the settings file for the data readers.
- """
- import os
- return os.path.dirname(__file__)
\ No newline at end of file
+# Method to associate extensions to default readers
+from .associations import read_associations
diff --git a/src/sas/sascalc/dataloader/readers/abs_reader.py b/src/sas/sascalc/dataloader/readers/abs_reader.py
index 5906df7..19898f5 100644
--- a/src/sas/sascalc/dataloader/readers/abs_reader.py
+++ b/src/sas/sascalc/dataloader/readers/abs_reader.py
@@ -1,249 +1,228 @@
-"""
-"""
-#####################################################################
-#This software was developed by the University of Tennessee as part of the
-#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
-#project funded by the US National Science Foundation.
-#See the license text in license.txt
-#copyright 2008, University of Tennessee
-######################################################################
-
-import numpy
-import os
-from sas.sascalc.dataloader.data_info import Data1D
-from sas.sascalc.dataloader.data_info import Detector
-
-has_converter = True
-try:
- from sas.sascalc.data_util.nxsunit import Converter
-except:
- has_converter = False
-
-
-class Reader:
- """
- Class to load IGOR reduced .ABS files
- """
- ## File type
- type_name = "IGOR 1D"
- ## Wildcards
- type = ["IGOR 1D files (*.abs)|*.abs"]
- ## List of allowed extensions
- ext = ['.abs', '.ABS']
-
- def read(self, path):
- """
- Load data file.
-
- :param path: file path
-
- :return: Data1D object, or None
-
- :raise RuntimeError: when the file can't be opened
- :raise ValueError: when the length of the data vectors are inconsistent
- """
- if os.path.isfile(path):
- basename = os.path.basename(path)
- root, extension = os.path.splitext(basename)
- if extension.lower() in self.ext:
- try:
- input_f = open(path,'r')
- except:
- raise RuntimeError, "abs_reader: cannot open %s" % path
- buff = input_f.read()
- lines = buff.split('\n')
- x = numpy.zeros(0)
- y = numpy.zeros(0)
- dy = numpy.zeros(0)
- dx = numpy.zeros(0)
- output = Data1D(x, y, dy=dy, dx=dx)
- detector = Detector()
- output.detector.append(detector)
- output.filename = basename
-
- is_info = False
- is_center = False
- is_data_started = False
-
- data_conv_q = None
- data_conv_i = None
-
- if has_converter == True and output.x_unit != '1/A':
- data_conv_q = Converter('1/A')
- # Test it
- data_conv_q(1.0, output.x_unit)
-
- if has_converter == True and output.y_unit != '1/cm':
- data_conv_i = Converter('1/cm')
- # Test it
- data_conv_i(1.0, output.y_unit)
-
- for line in lines:
-
- # Information line 1
- if is_info == True:
- is_info = False
- line_toks = line.split()
-
- # Wavelength in Angstrom
- try:
- value = float(line_toks[1])
- if has_converter == True and \
- output.source.wavelength_unit != 'A':
- conv = Converter('A')
- output.source.wavelength = conv(value,
- units=output.source.wavelength_unit)
- else:
- output.source.wavelength = value
- except:
- #goes to ASC reader
- msg = "abs_reader: cannot open %s" % path
- raise RuntimeError, msg
-
- # Distance in meters
- try:
- value = float(line_toks[3])
- if has_converter == True and \
- detector.distance_unit != 'm':
- conv = Converter('m')
- detector.distance = conv(value,
- units=detector.distance_unit)
- else:
- detector.distance = value
- except:
- #goes to ASC reader
- msg = "abs_reader: cannot open %s" % path
- raise RuntimeError, msg
- # Transmission
- try:
- output.sample.transmission = float(line_toks[4])
- except:
- # Transmission is not a mandatory entry
- pass
-
- # Thickness in mm
- try:
- value = float(line_toks[5])
- if has_converter == True and \
- output.sample.thickness_unit != 'cm':
- conv = Converter('cm')
- output.sample.thickness = conv(value,
- units=output.sample.thickness_unit)
- else:
- output.sample.thickness = value
- except:
- # Thickness is not a mandatory entry
- pass
-
- #MON CNT LAMBDA DET ANG DET DIST TRANS THICK
- # AVE STEP
- if line.count("LAMBDA") > 0:
- is_info = True
-
- # Find center info line
- if is_center == True:
- is_center = False
- line_toks = line.split()
- # Center in bin number
- center_x = float(line_toks[0])
- center_y = float(line_toks[1])
-
- # Bin size
- if has_converter == True and \
- detector.pixel_size_unit != 'mm':
- conv = Converter('mm')
- detector.pixel_size.x = conv(5.0,
- units=detector.pixel_size_unit)
- detector.pixel_size.y = conv(5.0,
- units=detector.pixel_size_unit)
- else:
- detector.pixel_size.x = 5.0
- detector.pixel_size.y = 5.0
-
- # Store beam center in distance units
- # Det 640 x 640 mm
- if has_converter == True and \
- detector.beam_center_unit != 'mm':
- conv = Converter('mm')
- detector.beam_center.x = conv(center_x * 5.0,
- units=detector.beam_center_unit)
- detector.beam_center.y = conv(center_y * 5.0,
- units=detector.beam_center_unit)
- else:
- detector.beam_center.x = center_x * 5.0
- detector.beam_center.y = center_y * 5.0
-
- # Detector type
- try:
- detector.name = line_toks[7]
- except:
- # Detector name is not a mandatory entry
- pass
-
- #BCENT(X,Y) A1(mm) A2(mm) A1A2DIST(m) DL/L
- # BSTOP(mm) DET_TYP
- if line.count("BCENT") > 0:
- is_center = True
-
- # Parse the data
- if is_data_started == True:
- toks = line.split()
-
- try:
- _x = float(toks[0])
- _y = float(toks[1])
- _dy = float(toks[2])
- _dx = float(toks[3])
-
- if data_conv_q is not None:
- _x = data_conv_q(_x, units=output.x_unit)
- _dx = data_conv_i(_dx, units=output.x_unit)
-
- if data_conv_i is not None:
- _y = data_conv_i(_y, units=output.y_unit)
- _dy = data_conv_i(_dy, units=output.y_unit)
-
- x = numpy.append(x, _x)
- y = numpy.append(y, _y)
- dy = numpy.append(dy, _dy)
- dx = numpy.append(dx, _dx)
-
- except:
- # Could not read this data line. If we are here
- # it is because we are in the data section. Just
- # skip it.
- pass
-
- #The 6 columns are | Q (1/A) | I(Q) (1/cm) | std. dev.
- # I(Q) (1/cm) | sigmaQ | meanQ | ShadowFactor|
- if line.count("The 6 columns") > 0:
- is_data_started = True
-
- # Sanity check
- if not len(y) == len(dy):
- msg = "abs_reader: y and dy have different length"
- raise ValueError, msg
- # If the data length is zero, consider this as
- # though we were not able to read the file.
- if len(x) == 0:
- raise ValueError, "ascii_reader: could not load file"
-
- output.x = x[x != 0]
- output.y = y[x != 0]
- output.dy = dy[x != 0]
- output.dx = dx[x != 0]
- if data_conv_q is not None:
- output.xaxis("\\rm{Q}", output.x_unit)
- else:
- output.xaxis("\\rm{Q}", 'A^{-1}')
- if data_conv_i is not None:
- output.yaxis("\\rm{Intensity}", output.y_unit)
- else:
- output.yaxis("\\rm{Intensity}", "cm^{-1}")
-
- # Store loading process information
- output.meta_data['loader'] = self.type_name
- return output
- else:
- raise RuntimeError, "%s is not a file" % path
- return None
+"""
+ IGOR 1D data reader
+"""
+#####################################################################
+# This software was developed by the University of Tennessee as part of the
+# Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
+# project funded by the US National Science Foundation.
+# See the license text in license.txt
+# copyright 2008, University of Tennessee
+######################################################################
+
+import logging
+
+import numpy as np
+
+from sas.sascalc.data_util.nxsunit import Converter
+from ..file_reader_base_class import FileReader
+from ..data_info import DataInfo, plottable_1D, Data1D, Detector
+from ..loader_exceptions import FileContentsException, DefaultReaderException
+
+logger = logging.getLogger(__name__)
+
+
+class Reader(FileReader):
+ """
+ Class to load IGOR reduced .ABS files
+ """
+ # File type
+ type_name = "IGOR 1D"
+ # Wildcards
+ type = ["IGOR 1D files (*.abs)|*.abs"]
+ # List of allowed extensions
+ ext = ['.abs']
+
+ def get_file_contents(self):
+ """
+ Get the contents of the file
+
+ :raise RuntimeError: when the file can't be opened
+ :raise ValueError: when the length of the data vectors are inconsistent
+ """
+ buff = self.readall()
+ filepath = self.f_open.name
+ lines = buff.splitlines()
+ self.output = []
+ self.current_datainfo = DataInfo()
+ self.current_datainfo.filename = filepath
+ self.reset_data_list(len(lines))
+ detector = Detector()
+ data_line = 0
+ self.reset_data_list(len(lines))
+ self.current_datainfo.detector.append(detector)
+ self.current_datainfo.filename = filepath
+
+ is_info = False
+ is_center = False
+ is_data_started = False
+
+ base_q_unit = '1/A'
+ base_i_unit = '1/cm'
+ data_conv_q = Converter(base_q_unit)
+ data_conv_i = Converter(base_i_unit)
+
+ for line in lines:
+ # Information line 1
+ if is_info:
+ is_info = False
+ line_toks = line.split()
+
+ # Wavelength in Angstrom
+ try:
+ value = float(line_toks[1])
+ if self.current_datainfo.source.wavelength_unit != 'A':
+ conv = Converter('A')
+ self.current_datainfo.source.wavelength = conv(value,
+ units=self.current_datainfo.source.wavelength_unit)
+ else:
+ self.current_datainfo.source.wavelength = value
+ except KeyError:
+ msg = "ABSReader cannot read wavelength from %s" % filepath
+ self.current_datainfo.errors.append(msg)
+
+ # Detector distance in meters
+ try:
+ value = float(line_toks[3])
+ if detector.distance_unit != 'm':
+ conv = Converter('m')
+ detector.distance = conv(value,
+ units=detector.distance_unit)
+ else:
+ detector.distance = value
+ except Exception:
+ msg = "ABSReader cannot read SDD from %s" % filepath
+ self.current_datainfo.errors.append(msg)
+
+ # Transmission
+ try:
+ self.current_datainfo.sample.transmission = \
+ float(line_toks[4])
+ except ValueError:
+ # Transmission isn't always in the header
+ pass
+
+ # Sample thickness in mm
+ try:
+ # ABS writer adds 'C' with no space to the end of the
+ # thickness column. Remove it if it is there before
+ # converting the thickness.
+ if line_toks[5][-1] not in '012345679.':
+ value = float(line_toks[5][:-1])
+ else:
+ value = float(line_toks[5])
+ if self.current_datainfo.sample.thickness_unit != 'cm':
+ conv = Converter('cm')
+ self.current_datainfo.sample.thickness = conv(value,
+ units=self.current_datainfo.sample.thickness_unit)
+ else:
+ self.current_datainfo.sample.thickness = value
+ except ValueError:
+ # Thickness is not a mandatory entry
+ pass
+
+ # MON CNT LAMBDA DET ANG DET DIST TRANS THICK AVE STEP
+ if line.count("LAMBDA") > 0:
+ is_info = True
+
+ # Find center info line
+ if is_center:
+ is_center = False
+ line_toks = line.split()
+ # Center in bin number
+ center_x = float(line_toks[0])
+ center_y = float(line_toks[1])
+
+ # Bin size
+ if detector.pixel_size_unit != 'mm':
+ conv = Converter('mm')
+ detector.pixel_size.x = conv(5.08,
+ units=detector.pixel_size_unit)
+ detector.pixel_size.y = conv(5.08,
+ units=detector.pixel_size_unit)
+ else:
+ detector.pixel_size.x = 5.08
+ detector.pixel_size.y = 5.08
+
+ # Store beam center in distance units
+ # Det 640 x 640 mm
+ if detector.beam_center_unit != 'mm':
+ conv = Converter('mm')
+ detector.beam_center.x = conv(center_x * 5.08,
+ units=detector.beam_center_unit)
+ detector.beam_center.y = conv(center_y * 5.08,
+ units=detector.beam_center_unit)
+ else:
+ detector.beam_center.x = center_x * 5.08
+ detector.beam_center.y = center_y * 5.08
+
+ # Detector type
+ try:
+ detector.name = line_toks[7]
+ except:
+ # Detector name is not a mandatory entry
+ pass
+
+ # BCENT(X,Y) A1(mm) A2(mm) A1A2DIST(m) DL/L BSTOP(mm) DET_TYP
+ if line.count("BCENT") > 0:
+ is_center = True
+
+ # Parse the data
+ if is_data_started:
+ toks = line.split()
+
+ try:
+ _x = float(toks[0])
+ _y = float(toks[1])
+ _dy = float(toks[2])
+ _dx = float(toks[3])
+
+ if data_conv_q is not None:
+ _x = data_conv_q(_x, units=base_q_unit)
+ _dx = data_conv_q(_dx, units=base_q_unit)
+
+ if data_conv_i is not None:
+ _y = data_conv_i(_y, units=base_i_unit)
+ _dy = data_conv_i(_dy, units=base_i_unit)
+
+ self.current_dataset.x[data_line] = _x
+ self.current_dataset.y[data_line] = _y
+ self.current_dataset.dy[data_line] = _dy
+ self.current_dataset.dx[data_line] = _dx
+ data_line += 1
+
+ except ValueError:
+ # Could not read this data line. If we are here
+ # it is because we are in the data section. Just
+ # skip it.
+ pass
+
+ # The 6 columns are | Q (1/A) | I(Q) (1/cm) | std. dev.
+ # I(Q) (1/cm) | sigmaQ | meanQ | ShadowFactor|
+ if line.count("The 6 columns") > 0:
+ is_data_started = True
+
+ self.remove_empty_q_values()
+
+ # Sanity check
+ if not len(self.current_dataset.y) == len(self.current_dataset.dy):
+ self.set_all_to_none()
+ msg = "abs_reader: y and dy have different length"
+ raise ValueError(msg)
+ # If the data length is zero, consider this as
+ # though we were not able to read the file.
+ if len(self.current_dataset.x) == 0:
+ self.set_all_to_none()
+ raise ValueError("ascii_reader: could not load file")
+
+ if data_conv_q is not None:
+ self.current_dataset.xaxis("\\rm{Q}", base_q_unit)
+ else:
+ self.current_dataset.xaxis("\\rm{Q}", 'A^{-1}')
+ if data_conv_i is not None:
+ self.current_dataset.yaxis("\\rm{Intensity}", base_i_unit)
+ else:
+ self.current_dataset.yaxis("\\rm{Intensity}", "cm^{-1}")
+
+ # Store loading process information
+ self.current_datainfo.meta_data['loader'] = self.type_name
+ self.send_to_output()
diff --git a/src/sas/sascalc/dataloader/readers/anton_paar_saxs_reader.py b/src/sas/sascalc/dataloader/readers/anton_paar_saxs_reader.py
index 1f118a6..eabb397 100644
--- a/src/sas/sascalc/dataloader/readers/anton_paar_saxs_reader.py
+++ b/src/sas/sascalc/dataloader/readers/anton_paar_saxs_reader.py
@@ -8,19 +8,13 @@ import os
import sys
from sas.sascalc.dataloader.readers.xml_reader import XMLreader
-from sas.sascalc.dataloader.data_info import plottable_1D, Data1D, Sample, Source
+from sas.sascalc.dataloader.data_info import plottable_1D, Data1D, DataInfo, Sample, Source
from sas.sascalc.dataloader.data_info import Process, Aperture, Collimation, TransmissionSpectrum, Detector
-
+from sas.sascalc.dataloader.loader_exceptions import FileContentsException, DataReaderException
class Reader(XMLreader):
"""
- A class for reading in CanSAS v2.0 data files. The existing iteration opens Mantid generated HDF5 formatted files
- with file extension .h5/.H5. Any number of data sets may be present within the file and any dimensionality of data
- may be used. Currently 1D and 2D SAS data sets are supported, but future implementations will include 1D and 2D
- SESANS data. This class assumes a single data set for each sasentry.
-
- :Dependencies:
- The CanSAS HDF5 reader requires h5py v2.5.0 or later.
+ A class for reading in Anton Paar .pdh files
"""
## Logged warnings or messages
@@ -29,8 +23,6 @@ class Reader(XMLreader):
errors = None
## Raw file contents to be processed
raw_data = None
- ## Data set being modified
- current_dataset = None
## For recursion and saving purposes, remember parent objects
parent_list = None
## Data type name
@@ -41,12 +33,10 @@ class Reader(XMLreader):
ext = ['.pdh', '.PDH']
## Flag to bypass extension check
allow_all = False
- ## List of files to return
- output = None
def reset_state(self):
- self.current_dataset = Data1D(np.empty(0), np.empty(0),
- np.empty(0), np.empty(0))
+ self.current_dataset = plottable_1D(np.empty(0), np.empty(0), np.empty(0), np.empty(0))
+ self.current_datainfo = DataInfo()
self.datasets = []
self.raw_data = None
self.errors = set()
@@ -62,7 +52,7 @@ class Reader(XMLreader):
self.upper = 5
self.lower = 5
- def read(self, filename):
+ def get_file_contents(self):
"""
This is the general read method that all SasView data_loaders must have.
@@ -72,65 +62,72 @@ class Reader(XMLreader):
## Reinitialize the class when loading a new data file to reset all class variables
self.reset_state()
- ## Check that the file exists
- if os.path.isfile(filename):
- basename = os.path.basename(filename)
- _, extension = os.path.splitext(basename)
- # If the file type is not allowed, return empty list
- if extension in self.ext or self.allow_all:
- ## Load the data file
- input_f = open(filename, 'r')
- buff = input_f.read()
- self.raw_data = buff.splitlines()
- self.read_data()
- return self.output
+ buff = self.readall()
+ self.raw_data = buff.splitlines()
+ self.read_data()
def read_data(self):
+ correctly_loaded = True
+ error_message = ""
+
q_unit = "1/nm"
i_unit = "1/um^2"
- self.current_dataset.title = self.raw_data[0]
- self.current_dataset.meta_data["Keywords"] = self.raw_data[1]
- line3 = self.raw_data[2].split()
- line4 = self.raw_data[3].split()
- line5 = self.raw_data[4].split()
- self.data_points = int(line3[0])
- self.lower = 5
- self.upper = self.lower + self.data_points
- self.source.radiation = 'x-ray'
- normal = float(line4[3])
- self.current_dataset.source.radiation = "x-ray"
- self.current_dataset.source.name = "Anton Paar SAXSess Instrument"
- self.current_dataset.source.wavelength = float(line4[4])
- xvals = []
- yvals = []
- dyvals = []
- for i in range(self.lower, self.upper):
- index = i - self.lower
- data = self.raw_data[i].split()
- xvals.insert(index, normal * float(data[0]))
- yvals.insert(index, normal * float(data[1]))
- dyvals.insert(index, normal * float(data[2]))
+ try:
+ self.current_datainfo.title = self.raw_data[0]
+ self.current_datainfo.meta_data["Keywords"] = self.raw_data[1]
+ line3 = self.raw_data[2].split()
+ line4 = self.raw_data[3].split()
+ line5 = self.raw_data[4].split()
+ self.data_points = int(line3[0])
+ self.lower = 5
+ self.upper = self.lower + self.data_points
+ self.source.radiation = 'x-ray'
+ normal = float(line4[3])
+ self.current_datainfo.source.radiation = "x-ray"
+ self.current_datainfo.source.name = "Anton Paar SAXSess Instrument"
+ self.current_datainfo.source.wavelength = float(line4[4])
+ xvals = []
+ yvals = []
+ dyvals = []
+ for i in range(self.lower, self.upper):
+ index = i - self.lower
+ data = self.raw_data[i].split()
+ xvals.insert(index, normal * float(data[0]))
+ yvals.insert(index, normal * float(data[1]))
+ dyvals.insert(index, normal * float(data[2]))
+ except Exception as e:
+ error_message = "Couldn't load {}.\n".format(self.f_open.name)
+ error_message += e.message
+ raise FileContentsException(error_message)
self.current_dataset.x = np.append(self.current_dataset.x, xvals)
self.current_dataset.y = np.append(self.current_dataset.y, yvals)
self.current_dataset.dy = np.append(self.current_dataset.dy, dyvals)
if self.data_points != self.current_dataset.x.size:
- self.errors.add("Not all data was loaded properly.")
- if self.current_dataset.dx.size != self.current_dataset.x.size:
- dxvals = np.zeros(self.current_dataset.x.size)
- self.current_dataset.dx = dxvals
+ error_message += "Not all data points could be loaded.\n"
+ correctly_loaded = False
if self.current_dataset.x.size != self.current_dataset.y.size:
- self.errors.add("The x and y data sets are not the same size.")
+ error_message += "The x and y data sets are not the same size.\n"
+ correctly_loaded = False
if self.current_dataset.y.size != self.current_dataset.dy.size:
- self.errors.add("The y and dy datasets are not the same size.")
- self.current_dataset.errors = self.errors
+ error_message += "The y and dy datasets are not the same size.\n"
+ correctly_loaded = False
+
self.current_dataset.xaxis("Q", q_unit)
self.current_dataset.yaxis("Intensity", i_unit)
xml_intermediate = self.raw_data[self.upper:]
xml = ''.join(xml_intermediate)
- self.set_xml_string(xml)
- dom = self.xmlroot.xpath('/fileinfo')
- self._parse_child(dom)
- self.output.append(self.current_dataset)
+ try:
+ self.set_xml_string(xml)
+ dom = self.xmlroot.xpath('/fileinfo')
+ self._parse_child(dom)
+ except Exception as e:
+ # Data loaded but XML metadata has an error
+ error_message += "Data points have been loaded but there was an "
+ error_message += "error reading XML metadata: " + e.message
+ correctly_loaded = False
+ self.send_to_output()
+ if not correctly_loaded:
+ raise DataReaderException(error_message)
def _parse_child(self, dom, parent=''):
"""
@@ -145,22 +142,22 @@ class Reader(XMLreader):
if len(node.getchildren()) > 1:
self._parse_child(node, key)
if key == "SampleDetector":
- self.current_dataset.detector.append(self.detector)
+ self.current_datainfo.detector.append(self.detector)
self.detector = Detector()
else:
if key == "value":
if parent == "Wavelength":
- self.current_dataset.source.wavelength = value
+ self.current_datainfo.source.wavelength = value
elif parent == "SampleDetector":
self.detector.distance = value
elif parent == "Temperature":
- self.current_dataset.sample.temperature = value
+ self.current_datainfo.sample.temperature = value
elif parent == "CounterSlitLength":
self.detector.slit_length = value
elif key == "unit":
value = value.replace("_", "")
if parent == "Wavelength":
- self.current_dataset.source.wavelength_unit = value
+ self.current_datainfo.source.wavelength_unit = value
elif parent == "SampleDetector":
self.detector.distance_unit = value
elif parent == "X":
@@ -168,7 +165,7 @@ class Reader(XMLreader):
elif parent == "Y":
self.current_dataset.yaxis(self.current_dataset._yaxis, value)
elif parent == "Temperature":
- self.current_dataset.sample.temperature_unit = value
+ self.current_datainfo.sample.temperature_unit = value
elif parent == "CounterSlitLength":
self.detector.slit_length_unit = value
elif key == "quantity":
diff --git a/src/sas/sascalc/dataloader/readers/ascii_reader.py b/src/sas/sascalc/dataloader/readers/ascii_reader.py
index 731d820..2fc5435 100644
--- a/src/sas/sascalc/dataloader/readers/ascii_reader.py
+++ b/src/sas/sascalc/dataloader/readers/ascii_reader.py
@@ -1,245 +1,164 @@
-"""
- ASCII reader
-"""
-############################################################################
-#This software was developed by the University of Tennessee as part of the
-#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
-#project funded by the US National Science Foundation.
-#If you use DANSE applications to do scientific research that leads to
-#publication, we ask that you acknowledge the use of the software with the
-#following sentence:
-#This work benefited from DANSE software developed under NSF award DMR-0520547.
-#copyright 2008, University of Tennessee
-#############################################################################
-
-
-import numpy
-import os
-from sas.sascalc.dataloader.data_info import Data1D
-
-# Check whether we have a converter available
-has_converter = True
-try:
- from sas.sascalc.data_util.nxsunit import Converter
-except:
- has_converter = False
-_ZERO = 1e-16
-
-
-class Reader:
- """
- Class to load ascii files (2, 3 or 4 columns).
- """
- ## File type
- type_name = "ASCII"
-
- ## Wildcards
- type = ["ASCII files (*.txt)|*.txt",
- "ASCII files (*.dat)|*.dat",
- "ASCII files (*.abs)|*.abs",
- "CSV files (*.csv)|*.csv"]
- ## List of allowed extensions
- ext = ['.txt', '.TXT', '.dat', '.DAT', '.abs', '.ABS', 'csv', 'CSV']
-
- ## Flag to bypass extension check
- allow_all = True
-
- def read(self, path):
- """
- Load data file
-
- :param path: file path
- :return: Data1D object, or None
-
- :raise RuntimeError: when the file can't be opened
- :raise ValueError: when the length of the data vectors are inconsistent
- """
- if os.path.isfile(path):
- basename = os.path.basename(path)
- _, extension = os.path.splitext(basename)
- if self.allow_all or extension.lower() in self.ext:
- try:
- # Read in binary mode since GRASP frequently has no-ascii
- # characters that breaks the open operation
- input_f = open(path,'rb')
- except:
- raise RuntimeError, "ascii_reader: cannot open %s" % path
- buff = input_f.read()
- lines = buff.splitlines()
-
- # Arrays for data storage
- tx = numpy.zeros(0)
- ty = numpy.zeros(0)
- tdy = numpy.zeros(0)
- tdx = numpy.zeros(0)
-
- # The first good line of data will define whether
- # we have 2-column or 3-column ascii
- has_error_dx = None
- has_error_dy = None
-
- #Initialize counters for data lines and header lines.
- is_data = False
- # More than "5" lines of data is considered as actual
- # data unless that is the only data
- min_data_pts = 5
- # To count # of current data candidate lines
- candidate_lines = 0
- # To count total # of previous data candidate lines
- candidate_lines_previous = 0
- #minimum required number of columns of data
- lentoks = 2
- for line in lines:
- toks = self.splitline(line)
- # To remember the # of columns in the current line of data
- new_lentoks = len(toks)
- try:
- if new_lentoks == 1 and not is_data:
- ## If only one item in list, no longer data
- raise ValueError
- elif new_lentoks == 0:
- ## If the line is blank, skip and continue on
- ## In case of breaks within data sets.
- continue
- elif new_lentoks != lentoks and is_data:
- ## If a footer is found, break the loop and save the data
- break
- elif new_lentoks != lentoks and not is_data:
- ## If header lines are numerical
- candidate_lines = 0
- candidate_lines_previous = 0
-
- #Make sure that all columns are numbers.
- for colnum in range(len(toks)):
- # Any non-floating point values throw ValueError
- float(toks[colnum])
-
- candidate_lines += 1
- _x = float(toks[0])
- _y = float(toks[1])
- _dx = None
- _dy = None
-
- #If 5 or more lines, this is considering the set data
- if candidate_lines >= min_data_pts:
- is_data = True
-
- # If a 3rd row is present, consider it dy
- if new_lentoks > 2:
- _dy = float(toks[2])
- has_error_dy = False if _dy == None else True
-
- # If a 4th row is present, consider it dx
- if new_lentoks > 3:
- _dx = float(toks[3])
- has_error_dx = False if _dx == None else True
-
- # Delete the previously stored lines of data candidates if
- # the list is not data
- if candidate_lines == 1 and -1 < candidate_lines_previous < min_data_pts and \
- is_data == False:
- try:
- tx = numpy.zeros(0)
- ty = numpy.zeros(0)
- tdy = numpy.zeros(0)
- tdx = numpy.zeros(0)
- except:
- pass
-
- if has_error_dy == True:
- tdy = numpy.append(tdy, _dy)
- if has_error_dx == True:
- tdx = numpy.append(tdx, _dx)
- tx = numpy.append(tx, _x)
- ty = numpy.append(ty, _y)
-
- #To remember the # of columns on the current line
- # for the next line of data
- lentoks = new_lentoks
- candidate_lines_previous = candidate_lines
- except ValueError:
- # It is data and meet non - number, then stop reading
- if is_data == True:
- break
- lentoks = 2
- has_error_dx = None
- has_error_dy = None
- #Reset # of lines of data candidates
- candidate_lines = 0
- except:
- pass
-
- input_f.close()
- if not is_data:
- msg = "ascii_reader: x has no data"
- raise RuntimeError, msg
- # Sanity check
- if has_error_dy == True and not len(ty) == len(tdy):
- msg = "ascii_reader: y and dy have different length"
- raise RuntimeError, msg
- if has_error_dx == True and not len(tx) == len(tdx):
- msg = "ascii_reader: y and dy have different length"
- raise RuntimeError, msg
- # If the data length is zero, consider this as
- # though we were not able to read the file.
- if len(tx) == 0:
- raise RuntimeError, "ascii_reader: could not load file"
-
- #Let's re-order the data to make cal.
- # curve look better some cases
- ind = numpy.lexsort((ty, tx))
- x = numpy.zeros(len(tx))
- y = numpy.zeros(len(ty))
- dy = numpy.zeros(len(tdy))
- dx = numpy.zeros(len(tdx))
- output = Data1D(x, y, dy=dy, dx=dx)
- self.filename = output.filename = basename
-
- for i in ind:
- x[i] = tx[ind[i]]
- y[i] = ty[ind[i]]
- if has_error_dy == True:
- dy[i] = tdy[ind[i]]
- if has_error_dx == True:
- dx[i] = tdx[ind[i]]
- # Zeros in dx, dy
- if has_error_dx:
- dx[dx == 0] = _ZERO
- if has_error_dy:
- dy[dy == 0] = _ZERO
- #Data
- output.x = x[x != 0]
- output.y = y[x != 0]
- output.dy = dy[x != 0] if has_error_dy == True\
- else numpy.zeros(len(output.y))
- output.dx = dx[x != 0] if has_error_dx == True\
- else numpy.zeros(len(output.x))
-
- output.xaxis("\\rm{Q}", 'A^{-1}')
- output.yaxis("\\rm{Intensity}", "cm^{-1}")
-
- # Store loading process information
- output.meta_data['loader'] = self.type_name
- if len(output.x) < 1:
- raise RuntimeError, "%s is empty" % path
- return output
-
- else:
- raise RuntimeError, "%s is not a file" % path
- return None
-
- def splitline(self, line):
- """
- Splits a line into pieces based on common delimeters
- :param line: A single line of text
- :return: list of values
- """
- # Initial try for CSV (split on ,)
- toks = line.split(',')
- # Now try SCSV (split on ;)
- if len(toks) < 2:
- toks = line.split(';')
- # Now go for whitespace
- if len(toks) < 2:
- toks = line.split()
- return toks
\ No newline at end of file
+"""
+ Generic multi-column ASCII data reader
+"""
+############################################################################
+# This software was developed by the University of Tennessee as part of the
+# Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
+# project funded by the US National Science Foundation.
+# If you use DANSE applications to do scientific research that leads to
+# publication, we ask that you acknowledge the use of the software with the
+# following sentence:
+# This work benefited from DANSE software developed under NSF award DMR-0520547.
+# copyright 2008, University of Tennessee
+#############################################################################
+
+import logging
+from sas.sascalc.dataloader.file_reader_base_class import FileReader
+from sas.sascalc.dataloader.data_info import DataInfo, plottable_1D
+from sas.sascalc.dataloader.loader_exceptions import FileContentsException,\
+ DefaultReaderException
+
+logger = logging.getLogger(__name__)
+
+
+class Reader(FileReader):
+ """
+ Class to load ascii files (2, 3 or 4 columns).
+ """
+ # File type
+ type_name = "ASCII"
+ # Wildcards
+ type = ["ASCII files (*.txt)|*.txt",
+ "ASCII files (*.dat)|*.dat",
+ "ASCII files (*.abs)|*.abs",
+ "CSV files (*.csv)|*.csv"]
+ # List of allowed extensions
+ ext = ['.txt', '.dat', '.abs', '.csv']
+ # Flag to bypass extension check
+ allow_all = True
+ # data unless that is the only data
+ min_data_pts = 5
+
+ def get_file_contents(self):
+ """
+ Get the contents of the file
+ """
+
+ buff = self.readall()
+ filepath = self.f_open.name
+ lines = buff.splitlines()
+ self.output = []
+ self.current_datainfo = DataInfo()
+ self.current_datainfo.filename = filepath
+ self.reset_data_list(len(lines))
+
+ # The first good line of data will define whether
+ # we have 2-column or 3-column ascii
+ has_error_dx = None
+ has_error_dy = None
+
+ # Initialize counters for data lines and header lines.
+ is_data = False
+ # More than "5" lines of data is considered as actual
+ # To count # of current data candidate lines
+ candidate_lines = 0
+ # To count total # of previous data candidate lines
+ candidate_lines_previous = 0
+ # Current line number
+ line_no = 0
+ # minimum required number of columns of data
+ lentoks = 2
+ for line in lines:
+ toks = self.splitline(line.strip())
+ # To remember the number of columns in the current line of data
+ new_lentoks = len(toks)
+ try:
+ if new_lentoks == 0:
+ # If the line is blank, skip and continue on
+ # In case of breaks within data sets.
+ continue
+ elif new_lentoks != lentoks and is_data:
+ # If a footer is found, break the loop and save the data
+ break
+ elif new_lentoks != lentoks and not is_data:
+ # If header lines are numerical
+ candidate_lines = 0
+ self.reset_data_list(len(lines) - line_no)
+
+ self.current_dataset.x[candidate_lines] = float(toks[0])
+
+ if new_lentoks > 1:
+ self.current_dataset.y[candidate_lines] = float(toks[1])
+
+ # If a 3rd row is present, consider it dy
+ if new_lentoks > 2:
+ self.current_dataset.dy[candidate_lines] = \
+ float(toks[2])
+ has_error_dy = True
+
+ # If a 4th row is present, consider it dx
+ if new_lentoks > 3:
+ self.current_dataset.dx[candidate_lines] = \
+ float(toks[3])
+ has_error_dx = True
+
+ candidate_lines += 1
+ # If 5 or more lines, this is considering the set data
+ if candidate_lines >= self.min_data_pts:
+ is_data = True
+
+ if is_data and new_lentoks >= 8:
+ msg = "This data looks like 2D ASCII data. Use the file "
+ msg += "converter tool to convert it to NXcanSAS."
+ raise FileContentsException(msg)
+
+ # To remember the # of columns on the current line
+ # for the next line of data
+ lentoks = new_lentoks
+ line_no += 1
+ except ValueError:
+ # ValueError is raised when non numeric strings conv. to float
+ # It is data and meet non - number, then stop reading
+ if is_data:
+ break
+ # Delete the previously stored lines of data candidates if
+ # the list is not data
+ self.reset_data_list(len(lines) - line_no)
+ lentoks = 2
+ has_error_dx = None
+ has_error_dy = None
+ # Reset # of lines of data candidates
+ candidate_lines = 0
+
+ if not is_data:
+ self.set_all_to_none()
+ if self.extension in self.ext:
+ msg = "ASCII Reader error: Fewer than five Q data points found "
+ msg += "in {}.".format(filepath)
+ raise FileContentsException(msg)
+ else:
+ msg = "ASCII Reader could not load the file {}".format(filepath)
+ raise DefaultReaderException(msg)
+ # Sanity check
+ if has_error_dy and not len(self.current_dataset.y) == \
+ len(self.current_dataset.dy):
+ msg = "ASCII Reader error: Number of I and dI data points are"
+ msg += " different in {}.".format(filepath)
+ # TODO: Add error to self.current_datainfo.errors instead?
+ self.set_all_to_none()
+ raise FileContentsException(msg)
+ if has_error_dx and not len(self.current_dataset.x) == \
+ len(self.current_dataset.dx):
+ msg = "ASCII Reader error: Number of Q and dQ data points are"
+ msg += " different in {}.".format(filepath)
+ # TODO: Add error to self.current_datainfo.errors instead?
+ self.set_all_to_none()
+ raise FileContentsException(msg)
+
+ self.remove_empty_q_values()
+ self.current_dataset.xaxis("\\rm{Q}", 'A^{-1}')
+ self.current_dataset.yaxis("\\rm{Intensity}", "cm^{-1}")
+
+ # Store loading process information
+ self.current_datainfo.meta_data['loader'] = self.type_name
+ self.send_to_output()
diff --git a/src/sas/sascalc/dataloader/readers/associations.py b/src/sas/sascalc/dataloader/readers/associations.py
index 5d19e46..c8a9770 100644
--- a/src/sas/sascalc/dataloader/readers/associations.py
+++ b/src/sas/sascalc/dataloader/readers/associations.py
@@ -1,108 +1,57 @@
-"""
-Module to associate default readers to file extensions.
-The module reads an xml file to get the readers for each file extension.
-The readers are tried in order they appear when reading a file.
-"""
-############################################################################
-#This software was developed by the University of Tennessee as part of the
-#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
-#project funded by the US National Science Foundation.
-#If you use DANSE applications to do scientific research that leads to
-#publication, we ask that you acknowledge the use of the software with the
-#following sentence:
-#This work benefited from DANSE software developed under NSF award DMR-0520547.
-#copyright 2009, University of Tennessee
-#############################################################################
-import os
-import sys
-import logging
-import json
-
-FILE_NAME = 'defaults.json'
-
-def read_associations(loader, settings=FILE_NAME):
- """
- Read the specified settings file to associate
- default readers to file extension.
-
- :param loader: Loader object
- :param settings: path to the json settings file [string]
- """
- reader_dir = os.path.dirname(__file__)
- path = os.path.join(reader_dir, settings)
-
- # If we can't find the file in the installation
- # directory, look into the execution directory.
- if not os.path.isfile(path):
- path = os.path.join(os.getcwd(), settings)
- if not os.path.isfile(path):
- path = os.path.join(sys.path[0], settings)
- if not os.path.isfile(path):
- path = settings
- if not os.path.isfile(path):
- path = "./%s" % settings
- if os.path.isfile(path):
- with open(path) as fh:
- json_tree = json.load(fh)
-
- # Read in the file extension associations
- entry_list = json_tree['SasLoader']['FileType']
-
- # For each FileType entry, get the associated reader and extension
- for entry in entry_list:
- reader = entry['-reader']
- ext = entry['-extension']
-
- if reader is not None and ext is not None:
- # Associate the extension with a particular reader
- # TODO: Modify the Register code to be case-insensitive
- # and remove the extra line below.
- try:
- exec "import %s" % reader
- exec "loader.associate_file_type('%s', %s)" % (ext.lower(),
- reader)
- exec "loader.associate_file_type('%s', %s)" % (ext.upper(),
- reader)
- except:
- msg = "read_associations: skipping association"
- msg += " for %s\n %s" % (ext.lower(), sys.exc_value)
- logging.error(msg)
- else:
- print "Could not find reader association settings\n %s [%s]" % (__file__, os.getcwd())
-
-
-def register_readers(registry_function):
- """
- Function called by the registry/loader object to register
- all default readers using a call back function.
-
- :WARNING: this method is now obsolete
-
- :param registry_function: function to be called to register each reader
- """
- logging.info("register_readers is now obsolete: use read_associations()")
- import abs_reader
- import ascii_reader
- import cansas_reader
- import danse_reader
- import hfir1d_reader
- import IgorReader
- import red2d_reader
- #import tiff_reader
- import nexus_reader
- import sesans_reader
- import cansas_reader_HDF5
- import anton_paar_saxs_reader
- registry_function(sesans_reader)
- registry_function(abs_reader)
- registry_function(ascii_reader)
- registry_function(cansas_reader)
- registry_function(danse_reader)
- registry_function(hfir1d_reader)
- registry_function(IgorReader)
- registry_function(red2d_reader)
- #registry_function(tiff_reader)
- registry_function(nexus_reader)
- registry_function(cansas_reader_HDF5)
- registry_function(anton_paar_saxs_reader)
- return True
+"""
+Module to associate default readers to file extensions.
+The module reads an xml file to get the readers for each file extension.
+The readers are tried in order they appear when reading a file.
+"""
+############################################################################
+#This software was developed by the University of Tennessee as part of the
+#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
+#project funded by the US National Science Foundation.
+#If you use DANSE applications to do scientific research that leads to
+#publication, we ask that you acknowledge the use of the software with the
+#following sentence:
+#This work benefited from DANSE software developed under NSF award DMR-0520547.
+#copyright 2009, University of Tennessee
+#############################################################################
+import sys
+import logging
+
+logger = logging.getLogger(__name__)
+
+FILE_ASSOCIATIONS = {
+ ".xml": "cansas_reader",
+ ".ses": "sesans_reader",
+ ".h5": "cansas_reader_HDF5",
+ ".txt": "ascii_reader",
+ ".dat": "red2d_reader",
+ ".abs": "abs_reader",
+ ".sans": "danse_reader",
+ ".pdh": "anton_paar_saxs_reader"
+}
+
+
+def read_associations(loader, settings=FILE_ASSOCIATIONS):
+ """
+ Read the specified settings file to associate
+ default readers to file extension.
+
+ :param loader: Loader object
+ :param settings: path to the json settings file [string]
+ """
+ # For each FileType entry, get the associated reader and extension
+ for ext, reader in settings.items():
+ if reader is not None and ext is not None:
+ # Associate the extension with a particular reader
+ # TODO: Modify the Register code to be case-insensitive
+ # FIXME: Remove exec statements
+ # and remove the extra line below.
+ try:
+ exec("from . import %s" % reader)
+ exec("loader.associate_file_type('%s', %s)"
+ % (ext.lower(), reader))
+ exec("loader.associate_file_type('%s', %s)"
+ % (ext.upper(), reader))
+ except:
+ msg = "read_associations: skipping association"
+ msg += " for %s\n %s" % (ext.lower(), sys.exc_value)
+ logger.error(msg)
diff --git a/src/sas/sascalc/dataloader/readers/cansas_constants.py b/src/sas/sascalc/dataloader/readers/cansas_constants.py
index 0354719..58b6dac 100644
--- a/src/sas/sascalc/dataloader/readers/cansas_constants.py
+++ b/src/sas/sascalc/dataloader/readers/cansas_constants.py
@@ -134,6 +134,7 @@ class CansasConstants(object):
"children" : {"Idata" : SASDATA_IDATA,
"Sesans": {"storeas": "content"},
"zacceptance": {"storeas": "float"},
+ "yacceptance": {"storeas": "float"},
"<any>" : ANY
}
}
diff --git a/src/sas/sascalc/dataloader/readers/cansas_reader.py b/src/sas/sascalc/dataloader/readers/cansas_reader.py
index 06f4cdf..00220da 100644
--- a/src/sas/sascalc/dataloader/readers/cansas_reader.py
+++ b/src/sas/sascalc/dataloader/readers/cansas_reader.py
@@ -1,38 +1,31 @@
-"""
- CanSAS data reader - new recursive cansas_version.
-"""
-############################################################################
-#This software was developed by the University of Tennessee as part of the
-#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
-#project funded by the US National Science Foundation.
-#If you use DANSE applications to do scientific research that leads to
-#publication, we ask that you acknowledge the use of the software with the
-#following sentence:
-#This work benefited from DANSE software developed under NSF award DMR-0520547.
-#copyright 2008,2009 University of Tennessee
-#############################################################################
-
import logging
-import numpy as np
import os
import sys
import datetime
import inspect
-# For saving individual sections of data
-from sas.sascalc.dataloader.data_info import Data1D, Data2D, DataInfo, \
- plottable_1D, plottable_2D
-from sas.sascalc.dataloader.data_info import Collimation, TransmissionSpectrum, \
- Detector, Process, Aperture
-from sas.sascalc.dataloader.data_info import \
- combine_data_info_with_plottable as combine_data
-import sas.sascalc.dataloader.readers.xml_reader as xml_reader
-from sas.sascalc.dataloader.readers.xml_reader import XMLreader
-from sas.sascalc.dataloader.readers.cansas_constants import CansasConstants, CurrentLevel
+
+import numpy as np
# The following 2 imports *ARE* used. Do not remove either.
import xml.dom.minidom
from xml.dom.minidom import parseString
+from lxml import etree
+
+from sas.sascalc.data_util.nxsunit import Converter
+
+# For saving individual sections of data
+from ..data_info import Data1D, Data2D, DataInfo, plottable_1D, plottable_2D, \
+ Collimation, TransmissionSpectrum, Detector, Process, Aperture, \
+ combine_data_info_with_plottable as combine_data
+from ..loader_exceptions import FileContentsException, DefaultReaderException, \
+ DataReaderException
+from . import xml_reader
+from .xml_reader import XMLreader
+from .cansas_constants import CansasConstants, CurrentLevel
+
+logger = logging.getLogger(__name__)
+
PREPROCESS = "xmlpreprocess"
ENCODING = "encoding"
RUN_NAME_DEFAULT = "None"
@@ -40,11 +33,6 @@ INVALID_SCHEMA_PATH_1_1 = "{0}/sas/sascalc/dataloader/readers/schema/cansas1d_in
INVALID_SCHEMA_PATH_1_0 = "{0}/sas/sascalc/dataloader/readers/schema/cansas1d_invalid_v1_0.xsd"
INVALID_XML = "\n\nThe loaded xml file, {0} does not fully meet the CanSAS v1.x specification. SasView loaded " + \
"as much of the data as possible.\n\n"
-HAS_CONVERTER = True
-try:
- from sas.sascalc.data_util.nxsunit import Converter
-except ImportError:
- HAS_CONVERTER = False
CONSTANTS = CansasConstants()
CANSAS_FORMAT = CONSTANTS.format
@@ -52,13 +40,6 @@ CANSAS_NS = CONSTANTS.names
ALLOW_ALL = True
class Reader(XMLreader):
- """
- Class to load cansas 1D XML files
-
- :Dependencies:
- The CanSAS reader requires PyXML 0.8.4 or later.
- """
- # CanSAS version - defaults to version 1.0
cansas_version = "1.0"
base_ns = "{cansas1d/1.0}"
cansas_defaults = None
@@ -72,12 +53,8 @@ class Reader(XMLreader):
names = None
ns_list = None
# Temporary storage location for loading multiple data sets in a single file
- current_datainfo = None
- current_dataset = None
current_data1d = None
data = None
- # List of data1D objects to be sent back to SasView
- output = None
# Wildcards
type = ["XML files (*.xml)|*.xml", "SasView Save Files (*.svs)|*.svs"]
# List of allowed extensions
@@ -90,9 +67,7 @@ class Reader(XMLreader):
Resets the class state to a base case when loading a new data file so previous
data files do not appear a second time
"""
- self.current_datainfo = None
- self.current_dataset = None
- self.current_data1d = None
+ super(Reader, self).reset_state()
self.data = []
self.process = Process()
self.transspectrum = TransmissionSpectrum()
@@ -101,110 +76,142 @@ class Reader(XMLreader):
self.detector = Detector()
self.names = []
self.cansas_defaults = {}
- self.output = []
self.ns_list = None
self.logging = []
self.encoding = None
def read(self, xml_file, schema_path="", invalid=True):
- """
- Validate and read in an xml_file file in the canSAS format.
+ if schema_path != "" or invalid != True:
+ # read has been called from self.get_file_contents because xml file doens't conform to schema
+ _, self.extension = os.path.splitext(os.path.basename(xml_file))
+ return self.get_file_contents(xml_file=xml_file, schema_path=schema_path, invalid=invalid)
- :param xml_file: A canSAS file path in proper XML format
- :param schema_path: A file path to an XML schema to validate the xml_file against
- """
- # For every file loaded, reset everything to a base state
+ # Otherwise, read has been called by the data loader - file_reader_base_class handles this
+ return super(XMLreader, self).read(xml_file)
+
+ def get_file_contents(self, xml_file=None, schema_path="", invalid=True):
+ # Reset everything since we're loading a new file
self.reset_state()
self.invalid = invalid
- # Check that the file exists
- if os.path.isfile(xml_file):
- basename, extension = os.path.splitext(os.path.basename(xml_file))
- # If the file type is not allowed, return nothing
- if extension in self.ext or self.allow_all:
- # Get the file location of
- self.load_file_and_schema(xml_file, schema_path)
- self.add_data_set()
- # Try to load the file, but raise an error if unable to.
- # Check the file matches the XML schema
+ if xml_file is None:
+ xml_file = self.f_open.name
+ # We don't sure f_open since lxml handles opnening/closing files
+ try:
+ # Raises FileContentsException
+ self.load_file_and_schema(xml_file, schema_path)
+ # Parse each SASentry
+ entry_list = self.xmlroot.xpath('/ns:SASroot/ns:SASentry',
+ namespaces={
+ 'ns': self.cansas_defaults.get(
+ "ns")
+ })
+ self.is_cansas(self.extension)
+ self.set_processing_instructions()
+ for entry in entry_list:
+ self._parse_entry(entry)
+ self.data_cleanup()
+ except FileContentsException as fc_exc:
+ # File doesn't meet schema - try loading with a less strict schema
+ base_name = xml_reader.__file__
+ base_name = base_name.replace("\\", "/")
+ base = base_name.split("/sas/")[0]
+ if self.cansas_version == "1.1":
+ invalid_schema = INVALID_SCHEMA_PATH_1_1.format(base, self.cansas_defaults.get("schema"))
+ else:
+ invalid_schema = INVALID_SCHEMA_PATH_1_0.format(base, self.cansas_defaults.get("schema"))
+ self.set_schema(invalid_schema)
+ if self.invalid:
try:
- self.is_cansas(extension)
- self.invalid = False
- # Get each SASentry from XML file and add it to a list.
- entry_list = self.xmlroot.xpath(
- '/ns:SASroot/ns:SASentry',
- namespaces={'ns': self.cansas_defaults.get("ns")})
- self.names.append("SASentry")
-
- # Get all preprocessing events and encoding
- self.set_processing_instructions()
-
- # Parse each <SASentry> item
- for entry in entry_list:
- # Create a new DataInfo object for every <SASentry>
-
- # Set the file name and then parse the entry.
- self.current_datainfo.filename = basename + extension
- self.current_datainfo.meta_data["loader"] = "CanSAS XML 1D"
- self.current_datainfo.meta_data[PREPROCESS] = \
- self.processing_instructions
-
- # Parse the XML SASentry
- self._parse_entry(entry)
- # Combine datasets with datainfo
- self.add_data_set()
- except RuntimeError:
- # If the file does not match the schema, raise this error
+ # Load data with less strict schema
+ self.read(xml_file, invalid_schema, False)
+
+ # File can still be read but doesn't match schema, so raise exception
+ self.load_file_and_schema(xml_file) # Reload strict schema so we can find where error are in file
invalid_xml = self.find_invalid_xml()
if invalid_xml != "":
- invalid_xml = INVALID_XML.format(basename + extension) + invalid_xml
- self.errors.add(invalid_xml)
- # Try again with an invalid CanSAS schema, that requires only a data set in each
- base_name = xml_reader.__file__
- base_name = base_name.replace("\\", "/")
- base = base_name.split("/sas/")[0]
- if self.cansas_version == "1.1":
- invalid_schema = INVALID_SCHEMA_PATH_1_1.format(base, self.cansas_defaults.get("schema"))
- else:
- invalid_schema = INVALID_SCHEMA_PATH_1_0.format(base, self.cansas_defaults.get("schema"))
- self.set_schema(invalid_schema)
- try:
- if self.invalid:
- if self.is_cansas():
- self.output = self.read(xml_file, invalid_schema, False)
- else:
- raise RuntimeError
- else:
- raise RuntimeError
- except RuntimeError:
- x = np.zeros(1)
- y = np.zeros(1)
- self.current_data1d = Data1D(x,y)
- self.current_data1d.errors = self.errors
- return [self.current_data1d]
- else:
- self.output.append("Not a valid file path.")
- # Return a list of parsed entries that dataloader can manage
- return self.output
+ basename, _ = os.path.splitext(
+ os.path.basename(self.f_open.name))
+ invalid_xml = INVALID_XML.format(basename + self.extension) + invalid_xml
+ raise DataReaderException(invalid_xml) # Handled by base class
+ except FileContentsException as fc_exc:
+ msg = "CanSAS Reader could not load the file {}".format(xml_file)
+ if fc_exc.message is not None: # Propagate error messages from earlier
+ msg = fc_exc.message
+ if not self.extension in self.ext: # If the file has no associated loader
+ raise DefaultReaderException(msg)
+ raise FileContentsException(msg)
+ pass
+ else:
+ raise fc_exc
+ except Exception as e: # Convert all other exceptions to FileContentsExceptions
+ raise FileContentsException(str(e))
+ finally:
+ if not self.f_open.closed:
+ self.f_open.close()
- def _parse_entry(self, dom, recurse=False):
+ def load_file_and_schema(self, xml_file, schema_path=""):
+ base_name = xml_reader.__file__
+ base_name = base_name.replace("\\", "/")
+ base = base_name.split("/sas/")[0]
+
+ # Try and parse the XML file
+ try:
+ self.set_xml_file(xml_file)
+ except etree.XMLSyntaxError: # File isn't valid XML so can't be loaded
+ msg = "SasView cannot load {}.\nInvalid XML syntax".format(xml_file)
+ raise FileContentsException(msg)
+
+ self.cansas_version = self.xmlroot.get("version", "1.0")
+ self.cansas_defaults = CANSAS_NS.get(self.cansas_version, "1.0")
+
+ if schema_path == "":
+ schema_path = "{}/sas/sascalc/dataloader/readers/schema/{}".format(
+ base, self.cansas_defaults.get("schema").replace("\\", "/")
+ )
+ self.set_schema(schema_path)
+
+ def is_cansas(self, ext="xml"):
"""
- Parse a SASEntry - new recursive method for parsing the dom of
- the CanSAS data format. This will allow multiple data files
- and extra nodes to be read in simultaneously.
+ Checks to see if the XML file is a CanSAS file
- :param dom: dom object with a namespace base of names
+ :param ext: The file extension of the data file
+ :raises FileContentsException: Raised if XML file isn't valid CanSAS
"""
+ if self.validate_xml(): # Check file is valid XML
+ name = "{http://www.w3.org/2001/XMLSchema-instance}schemaLocation"
+ value = self.xmlroot.get(name)
+ # Check schema CanSAS version matches file CanSAS version
+ if CANSAS_NS.get(self.cansas_version).get("ns") == value.rsplit(" ")[0]:
+ return True
+ if ext == "svs":
+ return True # Why is this required?
+ # If we get to this point then file isn't valid CanSAS
+ logger.warning("File doesn't meet CanSAS schema. Trying to load anyway.")
+ raise FileContentsException("The file is not valid CanSAS")
+ def _parse_entry(self, dom, recurse=False):
if not self._is_call_local() and not recurse:
self.reset_state()
- self.add_data_set()
- self.names.append("SASentry")
+ if not recurse:
+ self.current_datainfo = DataInfo()
+ # Raises FileContentsException if file doesn't meet CanSAS schema
+ self.invalid = False
+ # Look for a SASentry
+ self.data = []
self.parent_class = "SASentry"
- self._check_for_empty_data()
- self.base_ns = "{0}{1}{2}".format("{", \
- CANSAS_NS.get(self.cansas_version).get("ns"), "}")
-
- # Go through each child in the parent element
+ self.names.append("SASentry")
+ self.current_datainfo.meta_data["loader"] = "CanSAS XML 1D"
+ self.current_datainfo.meta_data[
+ PREPROCESS] = self.processing_instructions
+ if self._is_call_local() and not recurse:
+ basename, _ = os.path.splitext(os.path.basename(self.f_open.name))
+ self.current_datainfo.filename = basename + self.extension
+ # Create an empty dataset if no data has been passed to the reader
+ if self.current_dataset is None:
+ self._initialize_new_data_set(dom)
+ self.base_ns = "{" + CANSAS_NS.get(self.cansas_version).get("ns") + "}"
+
+ # Loop through each child in the parent element
for node in dom:
attr = node.attrib
name = attr.get("name", "")
@@ -213,9 +220,8 @@ class Reader(XMLreader):
tagname = node.tag.replace(self.base_ns, "")
tagname_original = tagname
# Skip this iteration when loading in save state information
- if tagname == "fitting_plug_in" or tagname == "pr_inversion" or tagname == "invariant":
+ if tagname in ["fitting_plug_in", "pr_inversion", "invariant", "corfunc"]:
continue
-
# Get where to store content
self.names.append(tagname_original)
self.ns_list = CONSTANTS.iterate_namespace(self.names)
@@ -231,8 +237,8 @@ class Reader(XMLreader):
self.current_dataset.shape = (x_bins, y_bins)
else:
self.current_dataset.shape = ()
- # Recursion step to access data within the group
- self._parse_entry(node, True)
+ # Recurse to access data within the group
+ self._parse_entry(node, recurse=True)
if tagname == "SASsample":
self.current_datainfo.sample.name = name
elif tagname == "beam_size":
@@ -242,8 +248,9 @@ class Reader(XMLreader):
elif tagname == "aperture":
self.aperture.name = name
self.aperture.type = type
- self.add_intermediate()
+ self._add_intermediate()
else:
+ # TODO: Clean this up to make it faster (fewer if/elifs)
if isinstance(self.current_dataset, plottable_2D):
data_point = node.text
unit = attr.get('unit', '')
@@ -259,7 +266,7 @@ class Reader(XMLreader):
elif tagname == 'SASnote':
self.current_datainfo.notes.append(data_point)
- # I and Q - 1D data
+ # I and Q points
elif tagname == 'I' and isinstance(self.current_dataset, plottable_1D):
self.current_dataset.yaxis("Intensity", unit)
self.current_dataset.y = np.append(self.current_dataset.y, data_point)
@@ -271,7 +278,7 @@ class Reader(XMLreader):
elif tagname == 'Qdev':
self.current_dataset.dx = np.append(self.current_dataset.dx, data_point)
elif tagname == 'dQw':
- self.current_dataset.dxw = np.append(self.current_dataset.dxw, data_point)
+ self.current_dataset.dxw = np.append(self.current_dataset.dxw, data_point)
elif tagname == 'dQl':
self.current_dataset.dxl = np.append(self.current_dataset.dxl, data_point)
elif tagname == 'Qmean':
@@ -284,6 +291,8 @@ class Reader(XMLreader):
attr.get('x_unit'))
self.current_dataset.yaxis(attr.get('y_axis'),
attr.get('y_unit'))
+ elif tagname == 'yacceptance':
+ self.current_datainfo.sample.yacceptance = (data_point, unit)
elif tagname == 'zacceptance':
self.current_datainfo.sample.zacceptance = (data_point, unit)
@@ -346,6 +355,7 @@ class Reader(XMLreader):
# Instrumental Information
elif tagname == 'name' and self.parent_class == 'SASinstrument':
self.current_datainfo.instrument = data_point
+
# Detector Information
elif tagname == 'name' and self.parent_class == 'SASdetector':
self.detector.name = data_point
@@ -391,6 +401,7 @@ class Reader(XMLreader):
elif tagname == 'yaw' and self.parent_class == 'orientation' and 'SASdetector' in self.names:
self.detector.orientation.z = data_point
self.detector.orientation_unit = unit
+
# Collimation and Aperture
elif tagname == 'length' and self.parent_class == 'SAScollimation':
self.collimation.length = data_point
@@ -424,10 +435,7 @@ class Reader(XMLreader):
self.process.notes.append(data_point)
elif tagname == 'term' and self.parent_class == 'SASprocess':
unit = attr.get("unit", "")
- dic = {}
- dic["name"] = name
- dic["value"] = data_point
- dic["unit"] = unit
+ dic = { "name": name, "value": data_point, "unit": unit }
self.process.term.append(dic)
# Transmission Spectrum
@@ -480,15 +488,16 @@ class Reader(XMLreader):
self.parent_class = self.names[length]
if not self._is_call_local() and not recurse:
self.frm = ""
- self.add_data_set()
- empty = None
- return self.output[0], empty
-
+ self.current_datainfo.errors = set()
+ for error in self.errors:
+ self.current_datainfo.errors.add(error)
+ self.data_cleanup()
+ self.sort_one_d_data()
+ self.sort_two_d_data()
+ self.reset_data_list()
+ return self.output[0], None
def _is_call_local(self):
- """
-
- """
if self.frm == "":
inter = inspect.stack()
self.frm = inter[2]
@@ -500,83 +509,10 @@ class Reader(XMLreader):
return False
return True
- def is_cansas(self, ext="xml"):
- """
- Checks to see if the xml file is a CanSAS file
-
- :param ext: The file extension of the data file
- """
- if self.validate_xml():
- name = "{http://www.w3.org/2001/XMLSchema-instance}schemaLocation"
- value = self.xmlroot.get(name)
- if CANSAS_NS.get(self.cansas_version).get("ns") == \
- value.rsplit(" ")[0]:
- return True
- if ext == "svs":
- return True
- raise RuntimeError
-
- def load_file_and_schema(self, xml_file, schema_path=""):
- """
- Loads the file and associates a schema, if a schema is passed in or if one already exists
-
- :param xml_file: The xml file path sent to Reader.read
- :param schema_path: The path to a schema associated with the xml_file, or find one based on the file
- """
- base_name = xml_reader.__file__
- base_name = base_name.replace("\\", "/")
- base = base_name.split("/sas/")[0]
-
- # Load in xml file and get the cansas version from the header
- self.set_xml_file(xml_file)
- self.cansas_version = self.xmlroot.get("version", "1.0")
-
- # Generic values for the cansas file based on the version
- self.cansas_defaults = CANSAS_NS.get(self.cansas_version, "1.0")
- if schema_path == "":
- schema_path = "{0}/sas/sascalc/dataloader/readers/schema/{1}".format \
- (base, self.cansas_defaults.get("schema")).replace("\\", "/")
-
- # Link a schema to the XML file.
- self.set_schema(schema_path)
-
- def add_data_set(self):
- """
- Adds the current_dataset to the list of outputs after preforming final processing on the data and then calls a
- private method to generate a new data set.
-
- :param key: NeXus group name for current tree level
- """
-
- if self.current_datainfo and self.current_dataset:
- self._final_cleanup()
- self.data = []
- self.current_datainfo = DataInfo()
-
- def _initialize_new_data_set(self, node=None):
- """
- A private class method to generate a new 1D data object.
- Outside methods should call add_data_set() to be sure any existing data is stored properly.
-
- :param node: XML node to determine if 1D or 2D data
- """
- x = np.array(0)
- y = np.array(0)
- for child in node:
- if child.tag.replace(self.base_ns, "") == "Idata":
- for i_child in child:
- if i_child.tag.replace(self.base_ns, "") == "Qx":
- self.current_dataset = plottable_2D()
- return
- self.current_dataset = plottable_1D(x, y)
-
- def add_intermediate(self):
+ def _add_intermediate(self):
"""
This method stores any intermediate objects within the final data set after fully reading the set.
-
- :param parent: The NXclass name for the h5py Group object that just finished being processed
"""
-
if self.parent_class == 'SASprocess':
self.current_datainfo.process.append(self.process)
self.process = Process()
@@ -593,98 +529,8 @@ class Reader(XMLreader):
self.collimation.aperture.append(self.aperture)
self.aperture = Aperture()
elif self.parent_class == 'SASdata':
- self._check_for_empty_resolution()
self.data.append(self.current_dataset)
- def _final_cleanup(self):
- """
- Final cleanup of the Data1D object to be sure it has all the
- appropriate information needed for perspectives
- """
-
- # Append errors to dataset and reset class errors
- self.current_datainfo.errors = set()
- for error in self.errors:
- self.current_datainfo.errors.add(error)
- self.errors.clear()
-
- # Combine all plottables with datainfo and append each to output
- # Type cast data arrays to float64 and find min/max as appropriate
- for dataset in self.data:
- if isinstance(dataset, plottable_1D):
- if dataset.x is not None:
- dataset.x = np.delete(dataset.x, [0])
- dataset.x = dataset.x.astype(np.float64)
- dataset.xmin = np.min(dataset.x)
- dataset.xmax = np.max(dataset.x)
- if dataset.y is not None:
- dataset.y = np.delete(dataset.y, [0])
- dataset.y = dataset.y.astype(np.float64)
- dataset.ymin = np.min(dataset.y)
- dataset.ymax = np.max(dataset.y)
- if dataset.dx is not None:
- dataset.dx = np.delete(dataset.dx, [0])
- dataset.dx = dataset.dx.astype(np.float64)
- if dataset.dxl is not None:
- dataset.dxl = np.delete(dataset.dxl, [0])
- dataset.dxl = dataset.dxl.astype(np.float64)
- if dataset.dxw is not None:
- dataset.dxw = np.delete(dataset.dxw, [0])
- dataset.dxw = dataset.dxw.astype(np.float64)
- if dataset.dy is not None:
- dataset.dy = np.delete(dataset.dy, [0])
- dataset.dy = dataset.dy.astype(np.float64)
- np.trim_zeros(dataset.x)
- np.trim_zeros(dataset.y)
- np.trim_zeros(dataset.dy)
- elif isinstance(dataset, plottable_2D):
- dataset.data = dataset.data.astype(np.float64)
- dataset.qx_data = dataset.qx_data.astype(np.float64)
- dataset.xmin = np.min(dataset.qx_data)
- dataset.xmax = np.max(dataset.qx_data)
- dataset.qy_data = dataset.qy_data.astype(np.float64)
- dataset.ymin = np.min(dataset.qy_data)
- dataset.ymax = np.max(dataset.qy_data)
- dataset.q_data = np.sqrt(dataset.qx_data * dataset.qx_data
- + dataset.qy_data * dataset.qy_data)
- if dataset.err_data is not None:
- dataset.err_data = dataset.err_data.astype(np.float64)
- if dataset.dqx_data is not None:
- dataset.dqx_data = dataset.dqx_data.astype(np.float64)
- if dataset.dqy_data is not None:
- dataset.dqy_data = dataset.dqy_data.astype(np.float64)
- if dataset.mask is not None:
- dataset.mask = dataset.mask.astype(dtype=bool)
-
- if len(dataset.shape) == 2:
- n_rows, n_cols = dataset.shape
- dataset.y_bins = dataset.qy_data[0::int(n_cols)]
- dataset.x_bins = dataset.qx_data[:int(n_cols)]
- dataset.data = dataset.data.flatten()
- else:
- dataset.y_bins = []
- dataset.x_bins = []
- dataset.data = dataset.data.flatten()
-
- final_dataset = combine_data(dataset, self.current_datainfo)
- self.output.append(final_dataset)
-
- def _create_unique_key(self, dictionary, name, numb=0):
- """
- Create a unique key value for any dictionary to prevent overwriting
- Recurse until a unique key value is found.
-
- :param dictionary: A dictionary with any number of entries
- :param name: The index of the item to be added to dictionary
- :param numb: The number to be appended to the name, starts at 0
- """
- if dictionary.get(name) is not None:
- numb += 1
- name = name.split("_")[0]
- name += "_{0}".format(numb)
- name = self._create_unique_key(dictionary, name, numb)
- return name
-
def _get_node_value(self, node, tagname):
"""
Get the value of a node and any applicable units
@@ -738,7 +584,14 @@ class Reader(XMLreader):
node_value = float(node_value)
if 'unit' in attr and attr.get('unit') is not None:
try:
- local_unit = attr['unit']
+ unit = attr['unit']
+ # Split the units to retain backwards compatibility with
+ # projects, analyses, and saved data from v4.1.0
+ unit_list = unit.split("|")
+ if len(unit_list) > 1:
+ local_unit = unit_list[1]
+ else:
+ local_unit = unit
unitname = self.ns_list.current_level.get("unit", "")
if "SASdetector" in self.names:
save_in = "detector"
@@ -761,17 +614,15 @@ class Reader(XMLreader):
save_in = "process"
else:
save_in = "current_datainfo"
- exec "default_unit = self.{0}.{1}".format(save_in, unitname)
- if local_unit and default_unit and local_unit.lower() != default_unit.lower() \
- and local_unit.lower() != "none":
- if HAS_CONVERTER == True:
- # Check local units - bad units raise KeyError
- data_conv_q = Converter(local_unit)
- value_unit = default_unit
- node_value = data_conv_q(node_value, units=default_unit)
- else:
- value_unit = local_unit
- err_msg = "Unit converter is not available.\n"
+ default_unit = getattrchain(self, '.'.join((save_in, unitname)))
+ if (local_unit and default_unit
+ and local_unit.lower() != default_unit.lower()
+ and local_unit.lower() != "none"):
+ # Check local units - bad units raise KeyError
+ #print("loading", tagname, node_value, local_unit, default_unit)
+ data_conv_q = Converter(local_unit)
+ value_unit = default_unit
+ node_value = data_conv_q(node_value, units=default_unit)
else:
value_unit = local_unit
except KeyError:
@@ -783,7 +634,7 @@ class Reader(XMLreader):
err_msg = err_msg.format(tagname, local_unit)
err_msg += "expecting [{0}]".format(default_unit)
value_unit = local_unit
- except:
+ except Exception:
err_msg = "CanSAS reader: unknown error converting "
err_msg += "\"{0}\" unit [{1}]"
err_msg = err_msg.format(tagname, local_unit)
@@ -794,89 +645,17 @@ class Reader(XMLreader):
self.errors.add(err_msg)
return node_value, value_unit
- def _check_for_empty_data(self):
- """
- Creates an empty data set if no data is passed to the reader
-
- :param data1d: presumably a Data1D object
- """
- if self.current_dataset == None:
- x_vals = np.empty(0)
- y_vals = np.empty(0)
- dx_vals = np.empty(0)
- dy_vals = np.empty(0)
- dxl = np.empty(0)
- dxw = np.empty(0)
- self.current_dataset = plottable_1D(x_vals, y_vals, dx_vals, dy_vals)
- self.current_dataset.dxl = dxl
- self.current_dataset.dxw = dxw
-
- def _check_for_empty_resolution(self):
- """
- A method to check all resolution data sets are the same size as I and Q
- """
- if isinstance(self.current_dataset, plottable_1D):
- dql_exists = False
- dqw_exists = False
- dq_exists = False
- di_exists = False
- if self.current_dataset.dxl is not None:
- dql_exists = True
- if self.current_dataset.dxw is not None:
- dqw_exists = True
- if self.current_dataset.dx is not None:
- dq_exists = True
- if self.current_dataset.dy is not None:
- di_exists = True
- if dqw_exists and not dql_exists:
- array_size = self.current_dataset.dxw.size - 1
- self.current_dataset.dxl = np.append(self.current_dataset.dxl,
- np.zeros([array_size]))
- elif dql_exists and not dqw_exists:
- array_size = self.current_dataset.dxl.size - 1
- self.current_dataset.dxw = np.append(self.current_dataset.dxw,
- np.zeros([array_size]))
- elif not dql_exists and not dqw_exists and not dq_exists:
- array_size = self.current_dataset.x.size - 1
- self.current_dataset.dx = np.append(self.current_dataset.dx,
- np.zeros([array_size]))
- if not di_exists:
- array_size = self.current_dataset.y.size - 1
- self.current_dataset.dy = np.append(self.current_dataset.dy,
- np.zeros([array_size]))
- elif isinstance(self.current_dataset, plottable_2D):
- dqx_exists = False
- dqy_exists = False
- di_exists = False
- mask_exists = False
- if self.current_dataset.dqx_data is not None:
- dqx_exists = True
- if self.current_dataset.dqy_data is not None:
- dqy_exists = True
- if self.current_dataset.err_data is not None:
- di_exists = True
- if self.current_dataset.mask is not None:
- mask_exists = True
- if not dqy_exists:
- array_size = self.current_dataset.qy_data.size - 1
- self.current_dataset.dqy_data = np.append(
- self.current_dataset.dqy_data, np.zeros([array_size]))
- if not dqx_exists:
- array_size = self.current_dataset.qx_data.size - 1
- self.current_dataset.dqx_data = np.append(
- self.current_dataset.dqx_data, np.zeros([array_size]))
- if not di_exists:
- array_size = self.current_dataset.data.size - 1
- self.current_dataset.err_data = np.append(
- self.current_dataset.err_data, np.zeros([array_size]))
- if not mask_exists:
- array_size = self.current_dataset.data.size - 1
- self.current_dataset.mask = np.append(
- self.current_dataset.mask,
- np.ones([array_size] ,dtype=bool))
-
- ####### All methods below are for writing CanSAS XML files #######
-
+ def _initialize_new_data_set(self, node=None):
+ if node is not None:
+ for child in node:
+ if child.tag.replace(self.base_ns, "") == "Idata":
+ for i_child in child:
+ if i_child.tag.replace(self.base_ns, "") == "Qx":
+ self.current_dataset = plottable_2D()
+ return
+ self.current_dataset = plottable_1D(np.array(0), np.array(0))
+
+ ## Writing Methods
def write(self, filename, datainfo):
"""
Write the content of a Data1D as a CanSAS XML file
@@ -887,8 +666,8 @@ class Reader(XMLreader):
# Create XML document
doc, _ = self._to_xml_doc(datainfo)
# Write the file
- file_ref = open(filename, 'w')
- if self.encoding == None:
+ file_ref = open(filename, 'wb')
+ if self.encoding is None:
self.encoding = "UTF-8"
doc.write(file_ref, encoding=self.encoding,
pretty_print=True, xml_declaration=True)
@@ -1008,7 +787,7 @@ class Reader(XMLreader):
:param datainfo: The Data1D object the information is coming from
:param entry_node: lxml node ElementTree object to be appended to
"""
- if datainfo.run == None or datainfo.run == []:
+ if datainfo.run is None or datainfo.run == []:
datainfo.run.append(RUN_NAME_DEFAULT)
datainfo.run_name[RUN_NAME_DEFAULT] = RUN_NAME_DEFAULT
for item in datainfo.run:
@@ -1056,6 +835,8 @@ class Reader(XMLreader):
sesans = self.create_element("Sesans", attrib=sesans_attrib)
sesans.text = str(datainfo.isSesans)
entry_node.append(sesans)
+ self.write_node(entry_node, "yacceptance", datainfo.sample.yacceptance[0],
+ {'unit': datainfo.sample.yacceptance[1]})
self.write_node(entry_node, "zacceptance", datainfo.sample.zacceptance[0],
{'unit': datainfo.sample.zacceptance[1]})
@@ -1076,9 +857,9 @@ class Reader(XMLreader):
point = self.create_element("Idata")
node.append(point)
- qx = ','.join([str(datainfo.qx_data[i]) for i in xrange(len(datainfo.qx_data))])
- qy = ','.join([str(datainfo.qy_data[i]) for i in xrange(len(datainfo.qy_data))])
- intensity = ','.join([str(datainfo.data[i]) for i in xrange(len(datainfo.data))])
+ qx = ','.join(str(v) for v in datainfo.qx_data)
+ qy = ','.join(str(v) for v in datainfo.qy_data)
+ intensity = ','.join(str(v) for v in datainfo.data)
self.write_node(point, "Qx", qx,
{'unit': datainfo._xunit})
@@ -1087,24 +868,19 @@ class Reader(XMLreader):
self.write_node(point, "I", intensity,
{'unit': datainfo._zunit})
if datainfo.err_data is not None:
- err = ','.join([str(datainfo.err_data[i]) for i in
- xrange(len(datainfo.err_data))])
+ err = ','.join(str(v) for v in datainfo.err_data)
self.write_node(point, "Idev", err,
{'unit': datainfo._zunit})
if datainfo.dqy_data is not None:
- dqy = ','.join([str(datainfo.dqy_data[i]) for i in
- xrange(len(datainfo.dqy_data))])
+ dqy = ','.join(str(v) for v in datainfo.dqy_data)
self.write_node(point, "Qydev", dqy,
{'unit': datainfo._yunit})
if datainfo.dqx_data is not None:
- dqx = ','.join([str(datainfo.dqx_data[i]) for i in
- xrange(len(datainfo.dqx_data))])
+ dqx = ','.join(str(v) for v in datainfo.dqx_data)
self.write_node(point, "Qxdev", dqx,
{'unit': datainfo._xunit})
if datainfo.mask is not None:
- mask = ','.join(
- ["1" if datainfo.mask[i] else "0"
- for i in xrange(len(datainfo.mask))])
+ mask = ','.join("1" if v else "0" for v in datainfo.mask)
self.write_node(point, "Mask", mask)
def _write_trans_spectrum(self, datainfo, entry_node):
@@ -1128,7 +904,7 @@ class Reader(XMLreader):
{'unit': spectrum.wavelength_unit})
self.write_node(point, "T", spectrum.transmission[i],
{'unit': spectrum.transmission_unit})
- if spectrum.transmission_deviation != None \
+ if spectrum.transmission_deviation is not None \
and len(spectrum.transmission_deviation) >= i:
self.write_node(point, "Tdev",
spectrum.transmission_deviation[i],
@@ -1208,7 +984,7 @@ class Reader(XMLreader):
self.write_attribute(source, "name",
str(datainfo.source.name))
self.append(source, instr)
- if datainfo.source.radiation == None or datainfo.source.radiation == '':
+ if datainfo.source.radiation is None or datainfo.source.radiation == '':
datainfo.source.radiation = "neutron"
self.write_node(source, "radiation", datainfo.source.radiation)
@@ -1249,7 +1025,7 @@ class Reader(XMLreader):
:param datainfo: The Data1D object the information is coming from
:param instr: lxml node ElementTree object to be appended to
"""
- if datainfo.collimation == [] or datainfo.collimation == None:
+ if datainfo.collimation == [] or datainfo.collimation is None:
coll = Collimation()
datainfo.collimation.append(coll)
for item in datainfo.collimation:
@@ -1294,7 +1070,7 @@ class Reader(XMLreader):
:param datainfo: The Data1D object the information is coming from
:param inst: lxml instrument node to be appended to
"""
- if datainfo.detector == None or datainfo.detector == []:
+ if datainfo.detector is None or datainfo.detector == []:
det = Detector()
det.name = ""
datainfo.detector.append(det)
@@ -1448,7 +1224,7 @@ class Reader(XMLreader):
entry = get_content(location, node)
try:
value = float(entry.text)
- except:
+ except ValueError:
value = None
if value is not None:
@@ -1457,37 +1233,25 @@ class Reader(XMLreader):
units = entry.get('unit')
if units is not None:
toks = variable.split('.')
- local_unit = None
- exec "local_unit = storage.%s_unit" % toks[0]
- if local_unit != None and units.lower() != local_unit.lower():
- if HAS_CONVERTER == True:
- try:
- conv = Converter(units)
- exec "storage.%s = %g" % \
- (variable, conv(value, units=local_unit))
- except:
- _, exc_value, _ = sys.exc_info()
- err_mess = "CanSAS reader: could not convert"
- err_mess += " %s unit [%s]; expecting [%s]\n %s" \
- % (variable, units, local_unit, exc_value)
- self.errors.add(err_mess)
- if optional:
- logging.info(err_mess)
- else:
- raise ValueError, err_mess
- else:
- err_mess = "CanSAS reader: unrecognized %s unit [%s];"\
- % (variable, units)
- err_mess += " expecting [%s]" % local_unit
+ local_unit = getattr(storage, toks[0]+"_unit")
+ if local_unit is not None and units.lower() != local_unit.lower():
+ try:
+ conv = Converter(units)
+ setattrchain(storage, variable, conv(value, units=local_unit))
+ except Exception:
+ _, exc_value, _ = sys.exc_info()
+ err_mess = "CanSAS reader: could not convert"
+ err_mess += " %s unit [%s]; expecting [%s]\n %s" \
+ % (variable, units, local_unit, exc_value)
self.errors.add(err_mess)
if optional:
- logging.info(err_mess)
+ logger.info(err_mess)
else:
- raise ValueError, err_mess
+ raise ValueError(err_mess)
else:
- exec "storage.%s = value" % variable
+ setattrchain(storage, variable, value)
else:
- exec "storage.%s = value" % variable
+ setattrchain(storage, variable, value)
# DO NOT REMOVE - used in saving and loading panel states.
def _store_content(self, location, node, variable, storage):
@@ -1507,8 +1271,7 @@ class Reader(XMLreader):
"""
entry = get_content(location, node)
if entry is not None and entry.text is not None:
- exec "storage.%s = entry.text.strip()" % variable
-
+ setattrchain(storage, variable, entry.text.strip())
# DO NOT REMOVE Called by outside packages:
# sas.sasgui.perspectives.invariant.invariant_state
@@ -1551,3 +1314,21 @@ def write_node(doc, parent, name, value, attr=None):
parent.appendChild(node)
return True
return False
+
+def getattrchain(obj, chain, default=None):
+ """Like getattr, but the attr may contain multiple parts separated by '.'"""
+ for part in chain.split('.'):
+ if hasattr(obj, part):
+ obj = getattr(obj, part, None)
+ else:
+ return default
+ return obj
+
+def setattrchain(obj, chain, value):
+ """Like setattr, but the attr may contain multiple parts separated by '.'"""
+ parts = list(chain.split('.'))
+ for part in parts[-1]:
+ obj = getattr(obj, part, None)
+ if obj is None:
+ raise ValueError("missing parent object "+part)
+ setattr(obj, value)
diff --git a/src/sas/sascalc/dataloader/readers/cansas_reader_HDF5.py b/src/sas/sascalc/dataloader/readers/cansas_reader_HDF5.py
index 9874f0e..f234770 100644
--- a/src/sas/sascalc/dataloader/readers/cansas_reader_HDF5.py
+++ b/src/sas/sascalc/dataloader/readers/cansas_reader_HDF5.py
@@ -8,13 +8,17 @@ import re
import os
import sys
-from sas.sascalc.dataloader.data_info import plottable_1D, plottable_2D,\
+from ..data_info import plottable_1D, plottable_2D,\
Data1D, Data2D, DataInfo, Process, Aperture, Collimation, \
TransmissionSpectrum, Detector
-from sas.sascalc.dataloader.data_info import combine_data_info_with_plottable
+from ..data_info import combine_data_info_with_plottable
+from ..loader_exceptions import FileContentsException, DefaultReaderException
+from ..file_reader_base_class import FileReader, decode
+def h5attr(node, key, default=None):
+ return decode(node.attrs.get(key, default))
-class Reader():
+class Reader(FileReader):
"""
A class for reading in CanSAS v2.0 data files. The existing iteration opens
Mantid generated HDF5 formatted files with file extension .h5/.H5. Any
@@ -39,10 +43,6 @@ class Reader():
errors = None
# Raw file contents to be processed
raw_data = None
- # Data info currently being read in
- current_datainfo = None
- # SASdata set currently being read in
- current_dataset = None
# List of plottable1D objects that should be linked to the current_datainfo
data1d = None
# List of plottable2D objects that should be linked to the current_datainfo
@@ -55,10 +55,8 @@ class Reader():
ext = ['.h5', '.H5']
# Flag to bypass extension check
allow_all = True
- # List of files to return
- output = None
- def read(self, filename):
+ def get_file_contents(self):
"""
This is the general read method that all SasView data_loaders must have.
@@ -66,7 +64,11 @@ class Reader():
:return: List of Data1D/2D objects and/or a list of errors.
"""
# Reinitialize when loading a new data file to reset all class variables
- self.reset_class_variables()
+ self.reset_state()
+
+ filename = self.f_open.name
+ self.f_open.close() # IO handled by h5py
+
# Check that the file exists
if os.path.isfile(filename):
basename = os.path.basename(filename)
@@ -74,28 +76,40 @@ class Reader():
# If the file type is not allowed, return empty list
if extension in self.ext or self.allow_all:
# Load the data file
- self.raw_data = h5py.File(filename, 'r')
- # Read in all child elements of top level SASroot
- self.read_children(self.raw_data, [])
- # Add the last data set to the list of outputs
- self.add_data_set()
- # Close the data file
- self.raw_data.close()
- # Return data set(s)
- return self.output
-
- def reset_class_variables(self):
+ try:
+ self.raw_data = h5py.File(filename, 'r')
+ except Exception as e:
+ if extension not in self.ext:
+ msg = "CanSAS2.0 HDF5 Reader could not load file {}".format(basename + extension)
+ raise DefaultReaderException(msg)
+ raise FileContentsException(e.message)
+ try:
+ # Read in all child elements of top level SASroot
+ self.read_children(self.raw_data, [])
+ # Add the last data set to the list of outputs
+ self.add_data_set()
+ except Exception as exc:
+ raise FileContentsException(exc.message)
+ finally:
+ # Close the data file
+ self.raw_data.close()
+
+ for dataset in self.output:
+ if isinstance(dataset, Data1D):
+ if dataset.x.size < 5:
+ self.output = []
+ raise FileContentsException("Fewer than 5 data points found.")
+
+ def reset_state(self):
"""
Create the reader object and define initial states for class variables
"""
- self.current_datainfo = None
- self.current_dataset = None
+ super(Reader, self).reset_state()
self.data1d = []
self.data2d = []
self.raw_data = None
self.errors = set()
self.logging = []
- self.output = []
self.parent_class = u''
self.detector = Detector()
self.collimation = Collimation()
@@ -115,17 +129,16 @@ class Reader():
for key in data.keys():
# Get all information for the current key
value = data.get(key)
- if value.attrs.get(u'canSAS_class') is not None:
- class_name = value.attrs.get(u'canSAS_class')
- else:
- class_name = value.attrs.get(u'NX_class')
+ class_name = h5attr(value, u'canSAS_class')
+ if class_name is None:
+ class_name = h5attr(value, u'NX_class')
if class_name is not None:
class_prog = re.compile(class_name)
else:
class_prog = re.compile(value.name)
if isinstance(value, h5py.Group):
- parent_class = class_name
+ # Set parent class before recursion
self.parent_class = class_name
parent_list.append(key)
# If a new sasentry, store the current data sets and create
@@ -136,7 +149,8 @@ class Reader():
self._initialize_new_data_set(parent_list)
# Recursion step to access data within the group
self.read_children(value, parent_list)
- self.parent_class = parent_class
+ # Reset parent class when returning from recursive method
+ self.parent_class = class_name
self.add_intermediate()
parent_list.remove(key)
@@ -209,16 +223,21 @@ class Reader():
continue
for data_point in data_set:
+ if isinstance(data_point, np.ndarray):
+ if data_point.dtype.char == 'S':
+ data_point = decode(bytes(data_point))
+ else:
+ data_point = decode(data_point)
# Top Level Meta Data
if key == u'definition':
self.current_datainfo.meta_data['reader'] = data_point
elif key == u'run':
self.current_datainfo.run.append(data_point)
try:
- run_name = value.attrs['name']
+ run_name = h5attr(value, 'name')
run_dict = {data_point: run_name}
self.current_datainfo.run_name = run_dict
- except:
+ except Exception:
pass
elif key == u'title':
self.current_datainfo.title = data_point
@@ -428,7 +447,6 @@ class Reader():
all data1D and data2D objects and then combines the data and info into
Data1D and Data2D objects
"""
-
# Type cast data arrays to float64
if len(self.current_datainfo.trans_spectrum) > 0:
spectrum_list = []
@@ -452,22 +470,6 @@ class Reader():
# Combine all plottables with datainfo and append each to output
# Type cast data arrays to float64 and find min/max as appropriate
for dataset in self.data2d:
- dataset.data = dataset.data.astype(np.float64)
- dataset.err_data = dataset.err_data.astype(np.float64)
- if dataset.qx_data is not None:
- dataset.xmin = np.min(dataset.qx_data)
- dataset.xmax = np.max(dataset.qx_data)
- dataset.qx_data = dataset.qx_data.astype(np.float64)
- if dataset.dqx_data is not None:
- dataset.dqx_data = dataset.dqx_data.astype(np.float64)
- if dataset.qy_data is not None:
- dataset.ymin = np.min(dataset.qy_data)
- dataset.ymax = np.max(dataset.qy_data)
- dataset.qy_data = dataset.qy_data.astype(np.float64)
- if dataset.dqy_data is not None:
- dataset.dqy_data = dataset.dqy_data.astype(np.float64)
- if dataset.q_data is not None:
- dataset.q_data = dataset.q_data.astype(np.float64)
zeros = np.ones(dataset.data.size, dtype=bool)
try:
for i in range(0, dataset.mask.size - 1):
@@ -490,31 +492,12 @@ class Reader():
dataset.y_bins = dataset.qy_data[0::n_cols]
dataset.x_bins = dataset.qx_data[:n_cols]
dataset.data = dataset.data.flatten()
-
- final_dataset = combine_data_info_with_plottable(
- dataset, self.current_datainfo)
- self.output.append(final_dataset)
+ self.current_dataset = dataset
+ self.send_to_output()
for dataset in self.data1d:
- if dataset.x is not None:
- dataset.x = dataset.x.astype(np.float64)
- dataset.xmin = np.min(dataset.x)
- dataset.xmax = np.max(dataset.x)
- if dataset.y is not None:
- dataset.y = dataset.y.astype(np.float64)
- dataset.ymin = np.min(dataset.y)
- dataset.ymax = np.max(dataset.y)
- if dataset.dx is not None:
- dataset.dx = dataset.dx.astype(np.float64)
- if dataset.dxl is not None:
- dataset.dxl = dataset.dxl.astype(np.float64)
- if dataset.dxw is not None:
- dataset.dxw = dataset.dxw.astype(np.float64)
- if dataset.dy is not None:
- dataset.dy = dataset.dy.astype(np.float64)
- final_dataset = combine_data_info_with_plottable(
- dataset, self.current_datainfo)
- self.output.append(final_dataset)
+ self.current_dataset = dataset
+ self.send_to_output()
def add_data_set(self, key=""):
"""
@@ -596,9 +579,9 @@ class Reader():
:param value: attribute dictionary for a particular value set
:return: unit for the value passed to the method
"""
- unit = value.attrs.get(u'units')
+ unit = h5attr(value, u'units')
if unit is None:
- unit = value.attrs.get(u'unit')
+ unit = h5attr(value, u'unit')
# Convert the unit formats
if unit == "1/A":
unit = "A^{-1}"
diff --git a/src/sas/sascalc/dataloader/readers/danse_reader.py b/src/sas/sascalc/dataloader/readers/danse_reader.py
index 3c6086b..3030288 100644
--- a/src/sas/sascalc/dataloader/readers/danse_reader.py
+++ b/src/sas/sascalc/dataloader/readers/danse_reader.py
@@ -1,280 +1,211 @@
-"""
- DANSE/SANS file reader
-"""
-############################################################################
-#This software was developed by the University of Tennessee as part of the
-#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
-#project funded by the US National Science Foundation.
-#If you use DANSE applications to do scientific research that leads to
-#publication, we ask that you acknowledge the use of the software with the
-#following sentence:
-#This work benefited from DANSE software developed under NSF award DMR-0520547.
-#copyright 2008, University of Tennessee
-#############################################################################
-import math
-import os
-import sys
-import numpy
-import logging
-from sas.sascalc.dataloader.data_info import Data2D, Detector
-from sas.sascalc.dataloader.manipulations import reader2D_converter
-
-# Look for unit converter
-has_converter = True
-try:
- from sas.sascalc.data_util.nxsunit import Converter
-except:
- has_converter = False
-
-
-class Reader:
- """
- Example data manipulation
- """
- ## File type
- type_name = "DANSE"
- ## Wildcards
- type = ["DANSE files (*.sans)|*.sans"]
- ## Extension
- ext = ['.sans', '.SANS']
-
- def read(self, filename=None):
- """
- Open and read the data in a file
- @param file: path of the file
- """
-
- read_it = False
- for item in self.ext:
- if filename.lower().find(item) >= 0:
- read_it = True
-
- if read_it:
- try:
- datafile = open(filename, 'r')
- except:
- raise RuntimeError,"danse_reader cannot open %s" % (filename)
-
- # defaults
- # wavelength in Angstrom
- wavelength = 10.0
- # Distance in meter
- distance = 11.0
- # Pixel number of center in x
- center_x = 65
- # Pixel number of center in y
- center_y = 65
- # Pixel size [mm]
- pixel = 5.0
- # Size in x, in pixels
- size_x = 128
- # Size in y, in pixels
- size_y = 128
- # Format version
- fversion = 1.0
-
- output = Data2D()
- output.filename = os.path.basename(filename)
- detector = Detector()
- output.detector.append(detector)
-
- output.data = numpy.zeros([size_x,size_y])
- output.err_data = numpy.zeros([size_x, size_y])
-
- data_conv_q = None
- data_conv_i = None
-
- if has_converter == True and output.Q_unit != '1/A':
- data_conv_q = Converter('1/A')
- # Test it
- data_conv_q(1.0, output.Q_unit)
-
- if has_converter == True and output.I_unit != '1/cm':
- data_conv_i = Converter('1/cm')
- # Test it
- data_conv_i(1.0, output.I_unit)
-
- read_on = True
- while read_on:
- line = datafile.readline()
- if line.find("DATA:") >= 0:
- read_on = False
- break
- toks = line.split(':')
- if toks[0] == "FORMATVERSION":
- fversion = float(toks[1])
- if toks[0] == "WAVELENGTH":
- wavelength = float(toks[1])
- elif toks[0] == "DISTANCE":
- distance = float(toks[1])
- elif toks[0] == "CENTER_X":
- center_x = float(toks[1])
- elif toks[0] == "CENTER_Y":
- center_y = float(toks[1])
- elif toks[0] == "PIXELSIZE":
- pixel = float(toks[1])
- elif toks[0] == "SIZE_X":
- size_x = int(toks[1])
- elif toks[0] == "SIZE_Y":
- size_y = int(toks[1])
-
- # Read the data
- data = []
- error = []
- if fversion == 1.0:
- data_str = datafile.readline()
- data = data_str.split(' ')
- else:
- read_on = True
- while read_on:
- data_str = datafile.readline()
- if len(data_str) == 0:
- read_on = False
- else:
- toks = data_str.split()
- try:
- val = float(toks[0])
- err = float(toks[1])
- if data_conv_i is not None:
- val = data_conv_i(val, units=output._yunit)
- err = data_conv_i(err, units=output._yunit)
- data.append(val)
- error.append(err)
- except:
- logging.info("Skipping line:%s,%s" %(data_str,
- sys.exc_value))
-
- # Initialize
- x_vals = []
- y_vals = []
- ymin = None
- ymax = None
- xmin = None
- xmax = None
-
- # Qx and Qy vectors
- theta = pixel / distance / 100.0
- stepq = 4.0 * math.pi / wavelength * math.sin(theta / 2.0)
- for i_x in range(size_x):
- theta = (i_x - center_x + 1) * pixel / distance / 100.0
- qx = 4.0 * math.pi / wavelength * math.sin(theta / 2.0)
-
- if has_converter == True and output.Q_unit != '1/A':
- qx = data_conv_q(qx, units=output.Q_unit)
-
- x_vals.append(qx)
- if xmin == None or qx < xmin:
- xmin = qx
- if xmax == None or qx > xmax:
- xmax = qx
-
- ymin = None
- ymax = None
- for i_y in range(size_y):
- theta = (i_y - center_y + 1) * pixel / distance / 100.0
- qy = 4.0 * math.pi / wavelength * math.sin(theta/2.0)
-
- if has_converter == True and output.Q_unit != '1/A':
- qy = data_conv_q(qy, units=output.Q_unit)
-
- y_vals.append(qy)
- if ymin == None or qy < ymin:
- ymin = qy
- if ymax == None or qy > ymax:
- ymax = qy
-
- # Store the data in the 2D array
- i_x = 0
- i_y = -1
-
- for i_pt in range(len(data)):
- try:
- value = float(data[i_pt])
- except:
- # For version 1.0, the data were still
- # stored as strings at this point.
- msg = "Skipping entry (v1.0):%s,%s" % (str(data[i_pt]),
- sys.exc_value)
- logging.info(msg)
-
- # Get bin number
- if math.fmod(i_pt, size_x) == 0:
- i_x = 0
- i_y += 1
- else:
- i_x += 1
-
- output.data[i_y][i_x] = value
- if fversion>1.0:
- output.err_data[i_y][i_x] = error[i_pt]
-
- # Store all data
- # Store wavelength
- if has_converter == True and output.source.wavelength_unit != 'A':
- conv = Converter('A')
- wavelength = conv(wavelength,
- units=output.source.wavelength_unit)
- output.source.wavelength = wavelength
-
- # Store distance
- if has_converter == True and detector.distance_unit != 'm':
- conv = Converter('m')
- distance = conv(distance, units=detector.distance_unit)
- detector.distance = distance
-
- # Store pixel size
- if has_converter == True and detector.pixel_size_unit != 'mm':
- conv = Converter('mm')
- pixel = conv(pixel, units=detector.pixel_size_unit)
- detector.pixel_size.x = pixel
- detector.pixel_size.y = pixel
-
- # Store beam center in distance units
- detector.beam_center.x = center_x * pixel
- detector.beam_center.y = center_y * pixel
-
- # Store limits of the image (2D array)
- xmin = xmin - stepq / 2.0
- xmax = xmax + stepq / 2.0
- ymin = ymin - stepq /2.0
- ymax = ymax + stepq / 2.0
-
- if has_converter == True and output.Q_unit != '1/A':
- xmin = data_conv_q(xmin, units=output.Q_unit)
- xmax = data_conv_q(xmax, units=output.Q_unit)
- ymin = data_conv_q(ymin, units=output.Q_unit)
- ymax = data_conv_q(ymax, units=output.Q_unit)
- output.xmin = xmin
- output.xmax = xmax
- output.ymin = ymin
- output.ymax = ymax
-
- # Store x and y axis bin centers
- output.x_bins = x_vals
- output.y_bins = y_vals
-
- # Units
- if data_conv_q is not None:
- output.xaxis("\\rm{Q_{x}}", output.Q_unit)
- output.yaxis("\\rm{Q_{y}}", output.Q_unit)
- else:
- output.xaxis("\\rm{Q_{x}}", 'A^{-1}')
- output.yaxis("\\rm{Q_{y}}", 'A^{-1}')
-
- if data_conv_i is not None:
- output.zaxis("\\rm{Intensity}", output.I_unit)
- else:
- output.zaxis("\\rm{Intensity}", "cm^{-1}")
-
- if not fversion >= 1.0:
- msg = "Danse_reader can't read this file %s" % filename
- raise ValueError, msg
- else:
- logging.info("Danse_reader Reading %s \n" % filename)
-
- # Store loading process information
- output.meta_data['loader'] = self.type_name
- output = reader2D_converter(output)
- return output
-
- return None
+"""
+ DANSE/SANS file reader
+"""
+############################################################################
+#This software was developed by the University of Tennessee as part of the
+#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
+#project funded by the US National Science Foundation.
+#If you use DANSE applications to do scientific research that leads to
+#publication, we ask that you acknowledge the use of the software with the
+#following sentence:
+#This work benefited from DANSE software developed under NSF award DMR-0520547.
+#copyright 2008, University of Tennessee
+#############################################################################
+import math
+import os
+import logging
+
+import numpy as np
+
+from ..data_info import plottable_2D, DataInfo, Detector
+from ..manipulations import reader2D_converter
+from ..file_reader_base_class import FileReader
+from ..loader_exceptions import FileContentsException, DataReaderException
+
+logger = logging.getLogger(__name__)
+
+# Look for unit converter
+has_converter = True
+try:
+ from sas.sascalc.data_util.nxsunit import Converter
+except:
+ has_converter = False
+
+
+class Reader(FileReader):
+ """
+ Example data manipulation
+ """
+ ## File type
+ type_name = "DANSE"
+ ## Wildcards
+ type = ["DANSE files (*.sans)|*.sans"]
+ ## Extension
+ ext = ['.sans', '.SANS']
+
+ def get_file_contents(self):
+ self.current_datainfo = DataInfo()
+ self.current_dataset = plottable_2D()
+ self.output = []
+
+ loaded_correctly = True
+ error_message = ""
+
+ # defaults
+ # wavelength in Angstrom
+ wavelength = 10.0
+ # Distance in meter
+ distance = 11.0
+ # Pixel number of center in x
+ center_x = 65
+ # Pixel number of center in y
+ center_y = 65
+ # Pixel size [mm]
+ pixel = 5.0
+ # Size in x, in pixels
+ size_x = 128
+ # Size in y, in pixels
+ size_y = 128
+ # Format version
+ fversion = 1.0
+
+ self.current_datainfo.filename = os.path.basename(self.f_open.name)
+ detector = Detector()
+ self.current_datainfo.detector.append(detector)
+
+ self.current_dataset.data = np.zeros([size_x, size_y])
+ self.current_dataset.err_data = np.zeros([size_x, size_y])
+
+ read_on = True
+ data_start_line = 1
+ while read_on:
+ line = self.nextline()
+ data_start_line += 1
+ if line.find("DATA:") >= 0:
+ read_on = False
+ break
+ toks = line.split(':')
+ try:
+ if toks[0] == "FORMATVERSION":
+ fversion = float(toks[1])
+ elif toks[0] == "WAVELENGTH":
+ wavelength = float(toks[1])
+ elif toks[0] == "DISTANCE":
+ distance = float(toks[1])
+ elif toks[0] == "CENTER_X":
+ center_x = float(toks[1])
+ elif toks[0] == "CENTER_Y":
+ center_y = float(toks[1])
+ elif toks[0] == "PIXELSIZE":
+ pixel = float(toks[1])
+ elif toks[0] == "SIZE_X":
+ size_x = int(toks[1])
+ elif toks[0] == "SIZE_Y":
+ size_y = int(toks[1])
+ except ValueError as e:
+ error_message += "Unable to parse {}. Default value used.\n".format(toks[0])
+ loaded_correctly = False
+
+ # Read the data
+ data = []
+ error = []
+ if not fversion >= 1.0:
+ msg = "danse_reader can't read this file {}".format(self.f_open.name)
+ raise FileContentsException(msg)
+
+ for line_num, data_str in enumerate(self.nextlines()):
+ toks = data_str.split()
+ try:
+ val = float(toks[0])
+ err = float(toks[1])
+ data.append(val)
+ error.append(err)
+ except ValueError as exc:
+ msg = "Unable to parse line {}: {}".format(line_num + data_start_line, data_str.strip())
+ raise FileContentsException(msg)
+
+ num_pts = size_x * size_y
+ if len(data) < num_pts:
+ msg = "Not enough data points provided. Expected {} but got {}".format(
+ size_x * size_y, len(data))
+ raise FileContentsException(msg)
+ elif len(data) > num_pts:
+ error_message += ("Too many data points provided. Expected {0} but"
+ " got {1}. Only the first {0} will be used.\n").format(num_pts, len(data))
+ loaded_correctly = False
+ data = data[:num_pts]
+ error = error[:num_pts]
+
+ # Qx and Qy vectors
+ theta = pixel / distance / 100.0
+ i_x = np.arange(size_x)
+ theta = (i_x - center_x + 1) * pixel / distance / 100.0
+ x_vals = 4.0 * np.pi / wavelength * np.sin(theta / 2.0)
+ xmin = x_vals.min()
+ xmax = x_vals.max()
+
+ i_y = np.arange(size_y)
+ theta = (i_y - center_y + 1) * pixel / distance / 100.0
+ y_vals = 4.0 * np.pi / wavelength * np.sin(theta / 2.0)
+ ymin = y_vals.min()
+ ymax = y_vals.max()
+
+ self.current_dataset.data = np.array(data, dtype=np.float64).reshape((size_y, size_x))
+ if fversion > 1.0:
+ self.current_dataset.err_data = np.array(error, dtype=np.float64).reshape((size_y, size_x))
+
+ # Store all data
+ # Store wavelength
+ if has_converter == True and self.current_datainfo.source.wavelength_unit != 'A':
+ conv = Converter('A')
+ wavelength = conv(wavelength,
+ units=self.current_datainfo.source.wavelength_unit)
+ self.current_datainfo.source.wavelength = wavelength
+
+ # Store distance
+ if has_converter == True and detector.distance_unit != 'm':
+ conv = Converter('m')
+ distance = conv(distance, units=detector.distance_unit)
+ detector.distance = distance
+
+ # Store pixel size
+ if has_converter == True and detector.pixel_size_unit != 'mm':
+ conv = Converter('mm')
+ pixel = conv(pixel, units=detector.pixel_size_unit)
+ detector.pixel_size.x = pixel
+ detector.pixel_size.y = pixel
+
+ # Store beam center in distance units
+ detector.beam_center.x = center_x * pixel
+ detector.beam_center.y = center_y * pixel
+
+
+ self.current_dataset.xaxis("\\rm{Q_{x}}", 'A^{-1}')
+ self.current_dataset.yaxis("\\rm{Q_{y}}", 'A^{-1}')
+ self.current_dataset.zaxis("\\rm{Intensity}", "cm^{-1}")
+
+ self.current_dataset.x_bins = x_vals
+ self.current_dataset.y_bins = y_vals
+
+ # Reshape data
+ x_vals = np.tile(x_vals, (size_y, 1)).flatten()
+ y_vals = np.tile(y_vals, (size_x, 1)).T.flatten()
+ if (np.all(self.current_dataset.err_data == None)
+ or np.any(self.current_dataset.err_data <= 0)):
+ new_err_data = np.sqrt(np.abs(self.current_dataset.data))
+ else:
+ new_err_data = self.current_dataset.err_data.flatten()
+
+ self.current_dataset.err_data = new_err_data
+ self.current_dataset.qx_data = x_vals
+ self.current_dataset.qy_data = y_vals
+ self.current_dataset.q_data = np.sqrt(x_vals**2 + y_vals**2)
+ self.current_dataset.mask = np.ones(len(x_vals), dtype=bool)
+
+ # Store loading process information
+ self.current_datainfo.meta_data['loader'] = self.type_name
+
+ self.send_to_output()
+
+ if not loaded_correctly:
+ raise DataReaderException(error_message)
diff --git a/src/sas/sascalc/dataloader/readers/defaults.json b/src/sas/sascalc/dataloader/readers/defaults.json
deleted file mode 100644
index 613855d..0000000
--- a/src/sas/sascalc/dataloader/readers/defaults.json
+++ /dev/null
@@ -1,50 +0,0 @@
-{
- "SasLoader":{
- "FileType":[
- {
- "-extension":".xml",
- "-reader":"cansas_reader"
- },
- {
- "-extension":".ses",
- "-reader":"sesans_reader"
- },
- {
- "-extension":".h5",
- "-reader":"cansas_reader_HDF5"
- },
- {
- "-extension":".txt",
- "-reader":"ascii_reader"
- },
- {
- "-extension":".asc",
- "-reader":"IgorReader"
- },
- {
- "-extension":".dat",
- "-reader":"red2d_reader"
- },
- {
- "-extension":".abs",
- "-reader":"abs_reader"
- },
- {
- "-extension":".d1d",
- "-reader":"hfir1d_reader"
- },
- {
- "-extension":".sans",
- "-reader":"danse_reader"
- },
- {
- "-extension":".nxs",
- "-reader":"nexus_reader"
- },
- {
- "-extension":".pdh",
- "-reader":"anton_paar_saxs_reader"
- }
- ]
- }
-}
\ No newline at end of file
diff --git a/src/sas/sascalc/dataloader/readers/hfir1d_reader.py b/src/sas/sascalc/dataloader/readers/hfir1d_reader.py
deleted file mode 100644
index 6049437..0000000
--- a/src/sas/sascalc/dataloader/readers/hfir1d_reader.py
+++ /dev/null
@@ -1,129 +0,0 @@
-"""
- HFIR 1D 4-column data reader
-"""
-#####################################################################
-#This software was developed by the University of Tennessee as part of the
-#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
-#project funded by the US National Science Foundation.
-#See the license text in license.txt
-#copyright 2008, University of Tennessee
-######################################################################
-import numpy
-import os
-from sas.sascalc.dataloader.data_info import Data1D
-
-# Check whether we have a converter available
-has_converter = True
-try:
- from sas.sascalc.data_util.nxsunit import Converter
-except:
- has_converter = False
-
-class Reader(object):
- """
- Class to load HFIR 1D 4-column files
- """
- ## File type
- type_name = "HFIR 1D"
- ## Wildcards
- type = ["HFIR 1D files (*.d1d)|*.d1d"]
- ## List of allowed extensions
- ext = ['.d1d']
-
- def read(self, path):
- """
- Load data file
-
- :param path: file path
-
- :return: Data1D object, or None
-
- :raise RuntimeError: when the file can't be opened
- :raise ValueError: when the length of the data vectors are inconsistent
- """
- if os.path.isfile(path):
- basename = os.path.basename(path)
- root, extension = os.path.splitext(basename)
- if extension.lower() in self.ext:
- try:
- input_f = open(path,'r')
- except:
- raise RuntimeError, "hfir1d_reader: cannot open %s" % path
- buff = input_f.read()
- lines = buff.split('\n')
- x = numpy.zeros(0)
- y = numpy.zeros(0)
- dx = numpy.zeros(0)
- dy = numpy.zeros(0)
- output = Data1D(x, y, dx=dx, dy=dy)
- self.filename = output.filename = basename
-
- data_conv_q = None
- data_conv_i = None
-
- if has_converter == True and output.x_unit != '1/A':
- data_conv_q = Converter('1/A')
- # Test it
- data_conv_q(1.0, output.x_unit)
-
- if has_converter == True and output.y_unit != '1/cm':
- data_conv_i = Converter('1/cm')
- # Test it
- data_conv_i(1.0, output.y_unit)
-
- for line in lines:
- toks = line.split()
- try:
- _x = float(toks[0])
- _y = float(toks[1])
- _dx = float(toks[3])
- _dy = float(toks[2])
-
- if data_conv_q is not None:
- _x = data_conv_q(_x, units=output.x_unit)
- _dx = data_conv_q(_dx, units=output.x_unit)
-
- if data_conv_i is not None:
- _y = data_conv_i(_y, units=output.y_unit)
- _dy = data_conv_i(_dy, units=output.y_unit)
-
- x = numpy.append(x, _x)
- y = numpy.append(y, _y)
- dx = numpy.append(dx, _dx)
- dy = numpy.append(dy, _dy)
- except:
- # Couldn't parse this line, skip it
- pass
-
- # Sanity check
- if not len(y) == len(dy):
- msg = "hfir1d_reader: y and dy have different length"
- raise RuntimeError, msg
- if not len(x) == len(dx):
- msg = "hfir1d_reader: x and dx have different length"
- raise RuntimeError, msg
-
- # If the data length is zero, consider this as
- # though we were not able to read the file.
- if len(x) == 0:
- raise RuntimeError, "hfir1d_reader: could not load file"
-
- output.x = x
- output.y = y
- output.dy = dy
- output.dx = dx
- if data_conv_q is not None:
- output.xaxis("\\rm{Q}", output.x_unit)
- else:
- output.xaxis("\\rm{Q}", 'A^{-1}')
- if data_conv_i is not None:
- output.yaxis("\\rm{Intensity}", output.y_unit)
- else:
- output.yaxis("\\rm{Intensity}", "cm^{-1}")
-
- # Store loading process information
- output.meta_data['loader'] = self.type_name
- return output
- else:
- raise RuntimeError, "%s is not a file" % path
- return None
diff --git a/src/sas/sascalc/dataloader/readers/nexus_reader.py b/src/sas/sascalc/dataloader/readers/nexus_reader.py
deleted file mode 100644
index 4c305dc..0000000
--- a/src/sas/sascalc/dataloader/readers/nexus_reader.py
+++ /dev/null
@@ -1,96 +0,0 @@
-#####################################################################
-#This software was developed by the University of Tennessee as part of the
-#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
-#project funded by the US National Science Foundation.
-#See the license text in license.txt
-#copyright 2012, University of Tennessee
-######################################################################
-"""
- Nexus reader for 2D data reduced by Mantid
-"""
-import os
-from sas.sascalc.dataloader.data_info import Data2D
-
-
-class Reader:
- """
- Nexus reader for 2D data reduced by Mantid
- """
- ## File type
- type_name = "NXS"
- ## Wildcards
- type = ["Nexus files (*.nxs)|*.nxs"]
- ## Extension
- ext = ['.nxs']
-
- def read(self, filename=None):
- """
- Open and read the data in a file
-
- :param filename: path of the file
- """
- try:
- import nxs
- except:
- msg = "Error reading Nexus file: Nexus package is missing.\n"
- msg += " Get it from http://http://www.nexusformat.org/"
- raise RuntimeError, msg
-
- # Instantiate data object
- output = Data2D()
- output.filename = os.path.basename(filename)
-
- fd = nxs.open(filename, 'rw')
-
- # Read in the 2D data
- fd.opengroup('mantid_workspace_1')
- fd.opengroup('workspace')
- fd.opendata('values')
- output.data = fd.getdata().copy()
- fd.closedata()
-
- # Read in the errors
- fd.opendata('errors')
- output.err_data = fd.getdata().copy()
- fd.closedata()
-
- # Read in the values on each axis
- fd.opendata('axis1')
- output.x_bins = fd.getdata().copy()
- fd.closedata()
-
- fd.opendata('axis2')
- output.y_bins = fd.getdata().copy()
- fd.closedata()
- fd.closegroup()
-
- output.xmin = min(output.x_bins)
- output.xmax = max(output.x_bins)
- output.ymin = min(output.y_bins)
- output.ymax = max(output.y_bins)
-
- output.xaxis("\\rm{Q_{x}}", 'A^{-1}')
- output.yaxis("\\rm{Q_{y}}", 'A^{-1}')
- output.zaxis("\\rm{Intensity}", "cm^{-1}")
-
- # Meta data
- fd.opendata('title')
- output.title = fd.getdata()
- fd.closedata()
-
- fd.opengroup('instrument')
- fd.opendata('name')
- output.instrument = fd.getdata()
- fd.closedata()
- fd.closegroup()
-
- fd.opengroup('logs')
- fd.opengroup('run_number')
- fd.opendata('value')
- output.run = fd.getdata()
-
- fd.close()
-
- # Store loading process information
- output.meta_data['loader'] = self.type_name
- return output
diff --git a/src/sas/sascalc/dataloader/readers/red2d_reader.py b/src/sas/sascalc/dataloader/readers/red2d_reader.py
index 5b0397b..c0fb2c7 100644
--- a/src/sas/sascalc/dataloader/readers/red2d_reader.py
+++ b/src/sas/sascalc/dataloader/readers/red2d_reader.py
@@ -1,367 +1,326 @@
-"""
- TXT/IGOR 2D Q Map file reader
-"""
-#####################################################################
-#This software was developed by the University of Tennessee as part of the
-#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
-#project funded by the US National Science Foundation.
-#See the license text in license.txt
-#copyright 2008, University of Tennessee
-######################################################################
-import os
-import numpy
-import math
-from sas.sascalc.dataloader.data_info import Data2D, Detector
-
-# Look for unit converter
-has_converter = True
-try:
- from sas.sascalc.data_util.nxsunit import Converter
-except:
- has_converter = False
-
-
-def check_point(x_point):
- """
- check point validity
- """
- # set zero for non_floats
- try:
- return float(x_point)
- except:
- return 0
-
-
-class Reader:
- """ Simple data reader for Igor data files """
- ## File type
- type_name = "IGOR/DAT 2D Q_map"
- ## Wildcards
- type = ["IGOR/DAT 2D file in Q_map (*.dat)|*.DAT"]
- ## Extension
- ext = ['.DAT', '.dat']
-
- def write(self, filename, data):
- """
- Write to .dat
-
- :param filename: file name to write
- :param data: data2D
- """
- import time
- # Write the file
- fd = open(filename, 'w')
- t = time.localtime()
- time_str = time.strftime("%H:%M on %b %d %y", t)
-
- header_str = "Data columns are Qx - Qy - I(Qx,Qy)\n\nASCII data"
- header_str += " created at %s \n\n" % time_str
- # simple 2D header
- fd.write(header_str)
- # write qx qy I values
- for i in range(len(data.data)):
- fd.write("%g %g %g\n" % (data.qx_data[i],
- data.qy_data[i],
- data.data[i]))
- # close
- fd.close()
-
- def read(self, filename=None):
- """ Read file """
- if not os.path.isfile(filename):
- raise ValueError, \
- "Specified file %s is not a regular file" % filename
-
- # Read file
- f = open(filename, 'r')
- buf = f.read()
- f.close()
- # Instantiate data object
- output = Data2D()
- output.filename = os.path.basename(filename)
- detector = Detector()
- if len(output.detector) > 0:
- print str(output.detector[0])
- output.detector.append(detector)
-
- # Get content
- dataStarted = False
-
- ## Defaults
- lines = buf.split('\n')
- x = []
- y = []
-
- wavelength = None
- distance = None
- transmission = None
-
- pixel_x = None
- pixel_y = None
-
- isInfo = False
- isCenter = False
-
- data_conv_q = None
- data_conv_i = None
-
- # Set units: This is the unit assumed for Q and I in the data file.
- if has_converter == True and output.Q_unit != '1/A':
- data_conv_q = Converter('1/A')
- # Test it
- data_conv_q(1.0, output.Q_unit)
-
- if has_converter == True and output.I_unit != '1/cm':
- data_conv_i = Converter('1/cm')
- # Test it
- data_conv_i(1.0, output.I_unit)
-
-
- # Remove the last lines before the for loop if the lines are empty
- # to calculate the exact number of data points
- count = 0
- while (len(lines[len(lines) - (count + 1)].lstrip().rstrip()) < 1):
- del lines[len(lines) - (count + 1)]
- count = count + 1
-
- #Read Header and find the dimensions of 2D data
- line_num = 0
- # Old version NIST files: 0
- ver = 0
- for line in lines:
- line_num += 1
- ## Reading the header applies only to IGOR/NIST 2D q_map data files
- # Find setup info line
- if isInfo:
- isInfo = False
- line_toks = line.split()
- # Wavelength in Angstrom
- try:
- wavelength = float(line_toks[1])
- # Units
- if has_converter == True and \
- output.source.wavelength_unit != 'A':
- conv = Converter('A')
- wavelength = conv(wavelength,
- units=output.source.wavelength_unit)
- except:
- #Not required
- pass
- # Distance in mm
- try:
- distance = float(line_toks[3])
- # Units
- if has_converter == True and detector.distance_unit != 'm':
- conv = Converter('m')
- distance = conv(distance, units=detector.distance_unit)
- except:
- #Not required
- pass
-
- # Distance in meters
- try:
- transmission = float(line_toks[4])
- except:
- #Not required
- pass
-
- if line.count("LAMBDA") > 0:
- isInfo = True
-
- # Find center info line
- if isCenter:
- isCenter = False
- line_toks = line.split()
- # Center in bin number
- center_x = float(line_toks[0])
- center_y = float(line_toks[1])
-
- if line.count("BCENT") > 0:
- isCenter = True
- # Check version
- if line.count("Data columns") > 0:
- if line.count("err(I)") > 0:
- ver = 1
- # Find data start
- if line.count("ASCII data") > 0:
- dataStarted = True
- continue
-
- ## Read and get data.
- if dataStarted == True:
- line_toks = line.split()
- if len(line_toks) == 0:
- #empty line
- continue
- # the number of columns must be stayed same
- col_num = len(line_toks)
- break
- # Make numpy array to remove header lines using index
- lines_array = numpy.array(lines)
-
- # index for lines_array
- lines_index = numpy.arange(len(lines))
-
- # get the data lines
- data_lines = lines_array[lines_index >= (line_num - 1)]
- # Now we get the total number of rows (i.e., # of data points)
- row_num = len(data_lines)
- # make it as list again to control the separators
- data_list = " ".join(data_lines.tolist())
- # split all data to one big list w/" "separator
- data_list = data_list.split()
-
- # Check if the size is consistent with data, otherwise
- #try the tab(\t) separator
- # (this may be removed once get the confidence
- #the former working all cases).
- if len(data_list) != (len(data_lines)) * col_num:
- data_list = "\t".join(data_lines.tolist())
- data_list = data_list.split()
-
- # Change it(string) into float
- #data_list = map(float,data_list)
- data_list1 = map(check_point, data_list)
-
- # numpy array form
- data_array = numpy.array(data_list1)
- # Redimesion based on the row_num and col_num,
- #otherwise raise an error.
- try:
- data_point = data_array.reshape(row_num, col_num).transpose()
- except:
- msg = "red2d_reader: Can't read this file: Not a proper file format"
- raise ValueError, msg
- ## Get the all data: Let's HARDcoding; Todo find better way
- # Defaults
- dqx_data = numpy.zeros(0)
- dqy_data = numpy.zeros(0)
- err_data = numpy.ones(row_num)
- qz_data = numpy.zeros(row_num)
- mask = numpy.ones(row_num, dtype=bool)
- # Get from the array
- qx_data = data_point[0]
- qy_data = data_point[1]
- data = data_point[2]
- if ver == 1:
- if col_num > (2 + ver):
- err_data = data_point[(2 + ver)]
- if col_num > (3 + ver):
- qz_data = data_point[(3 + ver)]
- if col_num > (4 + ver):
- dqx_data = data_point[(4 + ver)]
- if col_num > (5 + ver):
- dqy_data = data_point[(5 + ver)]
- #if col_num > (6 + ver): mask[data_point[(6 + ver)] < 1] = False
- q_data = numpy.sqrt(qx_data*qx_data+qy_data*qy_data+qz_data*qz_data)
-
- # Extra protection(it is needed for some data files):
- # If all mask elements are False, put all True
- if not mask.any():
- mask[mask == False] = True
-
- # Store limits of the image in q space
- xmin = numpy.min(qx_data)
- xmax = numpy.max(qx_data)
- ymin = numpy.min(qy_data)
- ymax = numpy.max(qy_data)
-
- # units
- if has_converter == True and output.Q_unit != '1/A':
- xmin = data_conv_q(xmin, units=output.Q_unit)
- xmax = data_conv_q(xmax, units=output.Q_unit)
- ymin = data_conv_q(ymin, units=output.Q_unit)
- ymax = data_conv_q(ymax, units=output.Q_unit)
-
- ## calculate the range of the qx and qy_data
- x_size = math.fabs(xmax - xmin)
- y_size = math.fabs(ymax - ymin)
-
- # calculate the number of pixels in the each axes
- npix_y = math.floor(math.sqrt(len(data)))
- npix_x = math.floor(len(data) / npix_y)
-
- # calculate the size of bins
- xstep = x_size / (npix_x - 1)
- ystep = y_size / (npix_y - 1)
-
- # store x and y axis bin centers in q space
- x_bins = numpy.arange(xmin, xmax + xstep, xstep)
- y_bins = numpy.arange(ymin, ymax + ystep, ystep)
-
- # get the limits of q values
- xmin = xmin - xstep / 2
- xmax = xmax + xstep / 2
- ymin = ymin - ystep / 2
- ymax = ymax + ystep / 2
-
- #Store data in outputs
- #TODO: Check the lengths
- output.data = data
- if (err_data == 1).all():
- output.err_data = numpy.sqrt(numpy.abs(data))
- output.err_data[output.err_data == 0.0] = 1.0
- else:
- output.err_data = err_data
-
- output.qx_data = qx_data
- output.qy_data = qy_data
- output.q_data = q_data
- output.mask = mask
-
- output.x_bins = x_bins
- output.y_bins = y_bins
-
- output.xmin = xmin
- output.xmax = xmax
- output.ymin = ymin
- output.ymax = ymax
-
- output.source.wavelength = wavelength
-
- # Store pixel size in mm
- detector.pixel_size.x = pixel_x
- detector.pixel_size.y = pixel_y
-
- # Store the sample to detector distance
- detector.distance = distance
-
- # optional data: if all of dq data == 0, do not pass to output
- if len(dqx_data) == len(qx_data) and dqx_data.any() != 0:
- # if no dqx_data, do not pass dqy_data.
- #(1 axis dq is not supported yet).
- if len(dqy_data) == len(qy_data) and dqy_data.any() != 0:
- # Currently we do not support dq parr, perp.
- # tranfer the comp. to cartesian coord. for newer version.
- if ver != 1:
- diag = numpy.sqrt(qx_data * qx_data + qy_data * qy_data)
- cos_th = qx_data / diag
- sin_th = qy_data / diag
- output.dqx_data = numpy.sqrt((dqx_data * cos_th) * \
- (dqx_data * cos_th) \
- + (dqy_data * sin_th) * \
- (dqy_data * sin_th))
- output.dqy_data = numpy.sqrt((dqx_data * sin_th) * \
- (dqx_data * sin_th) \
- + (dqy_data * cos_th) * \
- (dqy_data * cos_th))
- else:
- output.dqx_data = dqx_data
- output.dqy_data = dqy_data
-
- # Units of axes
- if data_conv_q is not None:
- output.xaxis("\\rm{Q_{x}}", output.Q_unit)
- output.yaxis("\\rm{Q_{y}}", output.Q_unit)
- else:
- output.xaxis("\\rm{Q_{x}}", 'A^{-1}')
- output.yaxis("\\rm{Q_{y}}", 'A^{-1}')
- if data_conv_i is not None:
- output.zaxis("\\rm{Intensity}", output.I_unit)
- else:
- output.zaxis("\\rm{Intensity}", "cm^{-1}")
-
- # Store loading process information
- output.meta_data['loader'] = self.type_name
-
- return output
+"""
+ TXT/IGOR 2D Q Map file reader
+"""
+#####################################################################
+#This software was developed by the University of Tennessee as part of the
+#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
+#project funded by the US National Science Foundation.
+#See the license text in license.txt
+#copyright 2008, University of Tennessee
+######################################################################
+import os
+import math
+import time
+
+import numpy as np
+
+from sas.sascalc.data_util.nxsunit import Converter
+
+from ..data_info import plottable_2D, DataInfo, Detector
+from ..file_reader_base_class import FileReader
+from ..loader_exceptions import FileContentsException
+
+
+def check_point(x_point):
+ """
+ check point validity
+ """
+ # set zero for non_floats
+ try:
+ return float(x_point)
+ except Exception:
+ return 0
+
+
+class Reader(FileReader):
+ """ Simple data reader for Igor data files """
+ ## File type
+ type_name = "IGOR/DAT 2D Q_map"
+ ## Wildcards
+ type = ["IGOR/DAT 2D file in Q_map (*.dat)|*.DAT"]
+ ## Extension
+ ext = ['.DAT', '.dat']
+
+ def write(self, filename, data):
+ """
+ Write to .dat
+
+ :param filename: file name to write
+ :param data: data2D
+ """
+ # Write the file
+ try:
+ fd = open(filename, 'w')
+ t = time.localtime()
+ time_str = time.strftime("%H:%M on %b %d %y", t)
+
+ header_str = "Data columns are Qx - Qy - I(Qx,Qy)\n\nASCII data"
+ header_str += " created at %s \n\n" % time_str
+ # simple 2D header
+ fd.write(header_str)
+ # write qx qy I values
+ for i in range(len(data.data)):
+ fd.write("%g %g %g\n" % (data.qx_data[i],
+ data.qy_data[i],
+ data.data[i]))
+ finally:
+ fd.close()
+
+ def get_file_contents(self):
+ # Read file
+ buf = self.readall()
+ self.f_open.close()
+ # Instantiate data object
+ self.current_dataset = plottable_2D()
+ self.current_datainfo = DataInfo()
+ self.current_datainfo.filename = os.path.basename(self.f_open.name)
+ self.current_datainfo.detector.append(Detector())
+
+ # Get content
+ data_started = False
+
+ ## Defaults
+ lines = buf.split('\n')
+ x = []
+ y = []
+
+ wavelength = None
+ distance = None
+ transmission = None
+
+ pixel_x = None
+ pixel_y = None
+
+ is_info = False
+ is_center = False
+
+ # Remove the last lines before the for loop if the lines are empty
+ # to calculate the exact number of data points
+ count = 0
+ while (len(lines[len(lines) - (count + 1)].lstrip().rstrip()) < 1):
+ del lines[len(lines) - (count + 1)]
+ count = count + 1
+
+ #Read Header and find the dimensions of 2D data
+ line_num = 0
+ # Old version NIST files: 0
+ ver = 0
+ for line in lines:
+ line_num += 1
+ ## Reading the header applies only to IGOR/NIST 2D q_map data files
+ # Find setup info line
+ if is_info:
+ is_info = False
+ line_toks = line.split()
+ # Wavelength in Angstrom
+ try:
+ wavelength = float(line_toks[1])
+ # Wavelength is stored in angstroms; convert if necessary
+ if self.current_datainfo.source.wavelength_unit != 'A':
+ conv = Converter('A')
+ wavelength = conv(wavelength,
+ units=self.current_datainfo.source.wavelength_unit)
+ except Exception:
+ pass # Not required
+ try:
+ distance = float(line_toks[3])
+ # Distance is stored in meters; convert if necessary
+ if self.current_datainfo.detector[0].distance_unit != 'm':
+ conv = Converter('m')
+ distance = conv(distance,
+ units=self.current_datainfo.detector[0].distance_unit)
+ except Exception:
+ pass # Not required
+
+ try:
+ transmission = float(line_toks[4])
+ except Exception:
+ pass # Not required
+
+ if line.count("LAMBDA") > 0:
+ is_info = True
+
+ # Find center info line
+ if is_center:
+ is_center = False
+ line_toks = line.split()
+ # Center in bin number
+ center_x = float(line_toks[0])
+ center_y = float(line_toks[1])
+
+ if line.count("BCENT") > 0:
+ is_center = True
+ # Check version
+ if line.count("Data columns") > 0:
+ if line.count("err(I)") > 0:
+ ver = 1
+ # Find data start
+ if line.count("ASCII data") > 0:
+ data_started = True
+ continue
+
+ ## Read and get data.
+ if data_started:
+ line_toks = line.split()
+ if len(line_toks) == 0:
+ #empty line
+ continue
+ # the number of columns must be stayed same
+ col_num = len(line_toks)
+ break
+
+ # Make numpy array to remove header lines using index
+ lines_array = np.array(lines)
+
+ # index for lines_array
+ lines_index = np.arange(len(lines))
+
+ # get the data lines
+ data_lines = lines_array[lines_index >= (line_num - 1)]
+ # Now we get the total number of rows (i.e., # of data points)
+ row_num = len(data_lines)
+ # make it as list again to control the separators
+ data_list = " ".join(data_lines.tolist())
+ # split all data to one big list w/" "separator
+ data_list = data_list.split()
+
+ # Check if the size is consistent with data, otherwise
+ #try the tab(\t) separator
+ # (this may be removed once get the confidence
+ #the former working all cases).
+ if len(data_list) != (len(data_lines)) * col_num:
+ data_list = "\t".join(data_lines.tolist())
+ data_list = data_list.split()
+
+ # Change it(string) into float
+ #data_list = map(float,data_list)
+ data_list1 = list(map(check_point, data_list))
+
+ # numpy array form
+ data_array = np.array(data_list1)
+ # Redimesion based on the row_num and col_num,
+ #otherwise raise an error.
+ try:
+ data_point = data_array.reshape(row_num, col_num).transpose()
+ except Exception:
+ msg = "red2d_reader can't read this file: Incorrect number of data points provided."
+ raise FileContentsException(msg)
+ ## Get the all data: Let's HARDcoding; Todo find better way
+ # Defaults
+ dqx_data = np.zeros(0)
+ dqy_data = np.zeros(0)
+ err_data = np.ones(row_num)
+ qz_data = np.zeros(row_num)
+ mask = np.ones(row_num, dtype=bool)
+ # Get from the array
+ qx_data = data_point[0]
+ qy_data = data_point[1]
+ data = data_point[2]
+ if ver == 1:
+ if col_num > (2 + ver):
+ err_data = data_point[(2 + ver)]
+ if col_num > (3 + ver):
+ qz_data = data_point[(3 + ver)]
+ if col_num > (4 + ver):
+ dqx_data = data_point[(4 + ver)]
+ if col_num > (5 + ver):
+ dqy_data = data_point[(5 + ver)]
+ #if col_num > (6 + ver): mask[data_point[(6 + ver)] < 1] = False
+ q_data = np.sqrt(qx_data*qx_data+qy_data*qy_data+qz_data*qz_data)
+
+ # Extra protection(it is needed for some data files):
+ # If all mask elements are False, put all True
+ if not mask.any():
+ mask[mask == False] = True
+
+ # Store limits of the image in q space
+ xmin = np.min(qx_data)
+ xmax = np.max(qx_data)
+ ymin = np.min(qy_data)
+ ymax = np.max(qy_data)
+
+ ## calculate the range of the qx and qy_data
+ x_size = math.fabs(xmax - xmin)
+ y_size = math.fabs(ymax - ymin)
+
+ # calculate the number of pixels in the each axes
+ npix_y = math.floor(math.sqrt(len(data)))
+ npix_x = math.floor(len(data) / npix_y)
+
+ # calculate the size of bins
+ xstep = x_size / (npix_x - 1)
+ ystep = y_size / (npix_y - 1)
+
+ # store x and y axis bin centers in q space
+ x_bins = np.arange(xmin, xmax + xstep, xstep)
+ y_bins = np.arange(ymin, ymax + ystep, ystep)
+
+ # get the limits of q values
+ xmin = xmin - xstep / 2
+ xmax = xmax + xstep / 2
+ ymin = ymin - ystep / 2
+ ymax = ymax + ystep / 2
+
+ #Store data in outputs
+ #TODO: Check the lengths
+ self.current_dataset.data = data
+ if (err_data == 1).all():
+ self.current_dataset.err_data = np.sqrt(np.abs(data))
+ self.current_dataset.err_data[self.current_dataset.err_data == 0.0] = 1.0
+ else:
+ self.current_dataset.err_data = err_data
+
+ self.current_dataset.qx_data = qx_data
+ self.current_dataset.qy_data = qy_data
+ self.current_dataset.q_data = q_data
+ self.current_dataset.mask = mask
+
+ self.current_dataset.x_bins = x_bins
+ self.current_dataset.y_bins = y_bins
+
+ self.current_dataset.xmin = xmin
+ self.current_dataset.xmax = xmax
+ self.current_dataset.ymin = ymin
+ self.current_dataset.ymax = ymax
+
+ self.current_datainfo.source.wavelength = wavelength
+
+ # Store pixel size in mm
+ self.current_datainfo.detector[0].pixel_size.x = pixel_x
+ self.current_datainfo.detector[0].pixel_size.y = pixel_y
+
+ # Store the sample to detector distance
+ self.current_datainfo.detector[0].distance = distance
+
+ # optional data: if all of dq data == 0, do not pass to output
+ if len(dqx_data) == len(qx_data) and dqx_data.any() != 0:
+ # if no dqx_data, do not pass dqy_data.
+ #(1 axis dq is not supported yet).
+ if len(dqy_data) == len(qy_data) and dqy_data.any() != 0:
+ # Currently we do not support dq parr, perp.
+ # tranfer the comp. to cartesian coord. for newer version.
+ if ver != 1:
+ diag = np.sqrt(qx_data * qx_data + qy_data * qy_data)
+ cos_th = qx_data / diag
+ sin_th = qy_data / diag
+ self.current_dataset.dqx_data = np.sqrt((dqx_data * cos_th) * \
+ (dqx_data * cos_th) \
+ + (dqy_data * sin_th) * \
+ (dqy_data * sin_th))
+ self.current_dataset.dqy_data = np.sqrt((dqx_data * sin_th) * \
+ (dqx_data * sin_th) \
+ + (dqy_data * cos_th) * \
+ (dqy_data * cos_th))
+ else:
+ self.current_dataset.dqx_data = dqx_data
+ self.current_dataset.dqy_data = dqy_data
+
+ # Units of axes
+ self.current_dataset.xaxis(r"\rm{Q_{x}}", 'A^{-1}')
+ self.current_dataset.yaxis(r"\rm{Q_{y}}", 'A^{-1}')
+ self.current_dataset.zaxis(r"\rm{Intensity}", "cm^{-1}")
+
+ # Store loading process information
+ self.current_datainfo.meta_data['loader'] = self.type_name
+
+ self.send_to_output()
diff --git a/src/sas/sascalc/dataloader/readers/sesans_reader.py b/src/sas/sascalc/dataloader/readers/sesans_reader.py
index c5e2bcd..d8e28e5 100644
--- a/src/sas/sascalc/dataloader/readers/sesans_reader.py
+++ b/src/sas/sascalc/dataloader/readers/sesans_reader.py
@@ -1,13 +1,17 @@
"""
SESANS reader (based on ASCII reader)
-
+
Reader for .ses or .sesans file format
-
- Jurrian Bakker
+
+ Jurrian Bakker
"""
-import numpy
import os
-from sas.sascalc.dataloader.data_info import Data1D
+
+import numpy as np
+
+from ..file_reader_base_class import FileReader
+from ..data_info import plottable_1D, DataInfo
+from ..loader_exceptions import FileContentsException, DataReaderException
# Check whether we have a converter available
has_converter = True
@@ -17,158 +21,154 @@ except:
has_converter = False
_ZERO = 1e-16
-class Reader:
+class Reader(FileReader):
"""
Class to load sesans files (6 columns).
"""
- ## File type
+ # File type
type_name = "SESANS"
-
+
## Wildcards
type = ["SESANS files (*.ses)|*.ses",
"SESANS files (*..sesans)|*.sesans"]
- ## List of allowed extensions
+ # List of allowed extensions
ext = ['.ses', '.SES', '.sesans', '.SESANS']
-
- ## Flag to bypass extension check
+
+ # Flag to bypass extension check
allow_all = True
-
- def read(self, path):
-
-# print "reader triggered"
-
- """
- Load data file
-
- :param path: file path
-
- :return: SESANSData1D object, or None
-
- :raise RuntimeError: when the file can't be opened
- :raise ValueError: when the length of the data vectors are inconsistent
- """
- if os.path.isfile(path):
- basename = os.path.basename(path)
- _, extension = os.path.splitext(basename)
- if self.allow_all or extension.lower() in self.ext:
- try:
- # Read in binary mode since GRASP frequently has no-ascii
- # characters that brakes the open operation
- input_f = open(path,'rb')
- except:
- raise RuntimeError, "sesans_reader: cannot open %s" % path
- buff = input_f.read()
- lines = buff.splitlines()
- x = numpy.zeros(0)
- y = numpy.zeros(0)
- dy = numpy.zeros(0)
- lam = numpy.zeros(0)
- dlam = numpy.zeros(0)
- dx = numpy.zeros(0)
-
- #temp. space to sort data
- tx = numpy.zeros(0)
- ty = numpy.zeros(0)
- tdy = numpy.zeros(0)
- tlam = numpy.zeros(0)
- tdlam = numpy.zeros(0)
- tdx = numpy.zeros(0)
- output = Data1D(x=x, y=y, lam=lam, dy=dy, dx=dx, dlam=dlam, isSesans=True)
- self.filename = output.filename = basename
-
- paramnames=[]
- paramvals=[]
- zvals=[]
- dzvals=[]
- lamvals=[]
- dlamvals=[]
- Pvals=[]
- dPvals=[]
-
- for line in lines:
- # Initial try for CSV (split on ,)
- line=line.strip()
- toks = line.split('\t')
- if len(toks)==2:
- paramnames.append(toks[0])
- paramvals.append(toks[1])
- if len(toks)>5:
- zvals.append(toks[0])
- dzvals.append(toks[3])
- lamvals.append(toks[4])
- dlamvals.append(toks[5])
- Pvals.append(toks[1])
- dPvals.append(toks[2])
- else:
- continue
-
- x=[]
- y=[]
- lam=[]
- dx=[]
- dy=[]
- dlam=[]
- lam_header = lamvals[0].split()
- data_conv_z = None
- default_z_unit = "A"
- data_conv_P = None
- default_p_unit = " " # Adjust unit for axis (L^-3)
- lam_unit = lam_header[1].replace("[","").replace("]","")
- if lam_unit == 'AA':
- lam_unit = 'A'
- varheader=[zvals[0],dzvals[0],lamvals[0],dlamvals[0],Pvals[0],dPvals[0]]
- valrange=range(1, len(zvals))
- for i in valrange:
- x.append(float(zvals[i]))
- y.append(float(Pvals[i]))
- lam.append(float(lamvals[i]))
- dy.append(float(dPvals[i]))
- dx.append(float(dzvals[i]))
- dlam.append(float(dlamvals[i]))
-
- x,y,lam,dy,dx,dlam = [
- numpy.asarray(v, 'double')
- for v in (x,y,lam,dy,dx,dlam)
- ]
-
- input_f.close()
-
- output.x, output.x_unit = self._unit_conversion(x, lam_unit, default_z_unit)
- output.y = y
- output.y_unit = r'\AA^{-2} cm^{-1}' # output y_unit added
- output.dx, output.dx_unit = self._unit_conversion(dx, lam_unit, default_z_unit)
- output.dy = dy
- output.lam, output.lam_unit = self._unit_conversion(lam, lam_unit, default_z_unit)
- output.dlam, output.dlam_unit = self._unit_conversion(dlam, lam_unit, default_z_unit)
-
- output.xaxis(r"\rm{z}", output.x_unit)
- output.yaxis(r"\rm{ln(P)/(t \lambda^2)}", output.y_unit) # Adjust label to ln P/(lam^2 t), remove lam column refs
-
- # Store loading process information
- output.meta_data['loader'] = self.type_name
- #output.sample.thickness = float(paramvals[6])
- output.sample.name = paramvals[1]
- output.sample.ID = paramvals[0]
- zaccept_unit_split = paramnames[7].split("[")
- zaccept_unit = zaccept_unit_split[1].replace("]","")
- if zaccept_unit.strip() == r'\AA^-1' or zaccept_unit.strip() == r'\A^-1':
- zaccept_unit = "1/A"
- output.sample.zacceptance=(float(paramvals[7]),zaccept_unit)
- output.vars = varheader
-
- if len(output.x) < 1:
- raise RuntimeError, "%s is empty" % path
- return output
+ def get_file_contents(self):
+ self.current_datainfo = DataInfo()
+ self.current_dataset = plottable_1D(np.array([]), np.array([]))
+ self.current_datainfo.isSesans = True
+ self.output = []
+
+ line = self.nextline()
+ params = {}
+ while not line.startswith("BEGIN_DATA"):
+ terms = line.split()
+ if len(terms) >= 2:
+ params[terms[0]] = " ".join(terms[1:])
+ line = self.nextline()
+ self.params = params
+
+ if "FileFormatVersion" not in self.params:
+ raise FileContentsException("SES file missing FileFormatVersion")
+ if float(self.params["FileFormatVersion"]) >= 2.0:
+ raise FileContentsException("SASView only supports SES version 1")
+
+ if "SpinEchoLength_unit" not in self.params:
+ raise FileContentsException("SpinEchoLength has no units")
+ if "Wavelength_unit" not in self.params:
+ raise FileContentsException("Wavelength has no units")
+ if params["SpinEchoLength_unit"] != params["Wavelength_unit"]:
+ raise FileContentsException("The spin echo data has rudely used "
+ "different units for the spin echo length "
+ "and the wavelength. While sasview could "
+ "handle this instance, it is a violation "
+ "of the file format and will not be "
+ "handled by other software.")
+
+ headers = self.nextline().split()
+
+ self._insist_header(headers, "SpinEchoLength")
+ self._insist_header(headers, "Depolarisation")
+ self._insist_header(headers, "Depolarisation_error")
+ self._insist_header(headers, "Wavelength")
+
+ data = np.loadtxt(self.f_open)
+
+ if data.shape[1] != len(headers):
+ raise FileContentsException(
+ "File has {} headers, but {} columns".format(
+ len(headers),
+ data.shape[1]))
+
+ if not data.size:
+ raise FileContentsException("{} is empty".format(path))
+ x = data[:, headers.index("SpinEchoLength")]
+ if "SpinEchoLength_error" in headers:
+ dx = data[:, headers.index("SpinEchoLength_error")]
else:
- raise RuntimeError, "%s is not a file" % path
- return None
+ dx = x * 0.05
+ lam = data[:, headers.index("Wavelength")]
+ if "Wavelength_error" in headers:
+ dlam = data[:, headers.index("Wavelength_error")]
+ else:
+ dlam = lam * 0.05
+ y = data[:, headers.index("Depolarisation")]
+ dy = data[:, headers.index("Depolarisation_error")]
+
+ lam_unit = self._unit_fetch("Wavelength")
+ x, x_unit = self._unit_conversion(x, "A",
+ self._unit_fetch(
+ "SpinEchoLength"))
+ dx, dx_unit = self._unit_conversion(
+ dx, lam_unit,
+ self._unit_fetch("SpinEchoLength"))
+ dlam, dlam_unit = self._unit_conversion(
+ dlam, lam_unit,
+ self._unit_fetch("Wavelength"))
+ y_unit = self._unit_fetch("Depolarisation")
+
+ self.current_dataset.x = x
+ self.current_dataset.y = y
+ self.current_dataset.lam = lam
+ self.current_dataset.dy = dy
+ self.current_dataset.dx = dx
+ self.current_dataset.dlam = dlam
+ self.current_datainfo.isSesans = True
+
+ self.current_datainfo._yunit = y_unit
+ self.current_datainfo._xunit = x_unit
+ self.current_datainfo.source.wavelength_unit = lam_unit
+ self.current_datainfo.source.wavelength = lam
+ self.current_datainfo.filename = os.path.basename(self.f_open.name)
+ self.current_dataset.xaxis(r"\rm{z}", x_unit)
+ # Adjust label to ln P/(lam^2 t), remove lam column refs
+ self.current_dataset.yaxis(r"\rm{ln(P)/(t \lambda^2)}", y_unit)
+ # Store loading process information
+ self.current_datainfo.meta_data['loader'] = self.type_name
+ self.current_datainfo.sample.name = params["Sample"]
+ self.current_datainfo.sample.ID = params["DataFileTitle"]
+ self.current_datainfo.sample.thickness = self._unit_conversion(
+ float(params["Thickness"]), "cm",
+ self._unit_fetch("Thickness"))[0]
+
+ self.current_datainfo.sample.zacceptance = (
+ float(params["Theta_zmax"]),
+ self._unit_fetch("Theta_zmax"))
- def _unit_conversion(self, value, value_unit, default_unit):
- if has_converter == True and value_unit != default_unit:
- data_conv_q = Converter(value_unit)
- value = data_conv_q(value, units=default_unit)
+ self.current_datainfo.sample.yacceptance = (
+ float(params["Theta_ymax"]),
+ self._unit_fetch("Theta_ymax"))
+
+ self.send_to_output()
+
+ @staticmethod
+ def _insist_header(headers, name):
+ if name not in headers:
+ raise FileContentsException(
+ "Missing {} column in spin echo data".format(name))
+
+ @staticmethod
+ def _unit_conversion(value, value_unit, default_unit):
+ """
+ Performs unit conversion on a measurement.
+
+ :param value: The magnitude of the measurement
+ :param value_unit: a string containing the final desired unit
+ :param default_unit: string with the units of the original measurement
+ :return: The magnitude of the measurement in the new units
+ """
+ # (float, string, string) -> float
+ if has_converter and value_unit != default_unit:
+ data_conv_q = Converter(default_unit)
+ value = data_conv_q(value, units=value_unit)
new_unit = default_unit
else:
new_unit = value_unit
- return value, new_unit
\ No newline at end of file
+ return value, new_unit
+
+ def _unit_fetch(self, unit):
+ return self.params[unit+"_unit"]
diff --git a/src/sas/sascalc/dataloader/readers/tiff_reader.py b/src/sas/sascalc/dataloader/readers/tiff_reader.py
index 1b9b020..9dd42d3 100644
--- a/src/sas/sascalc/dataloader/readers/tiff_reader.py
+++ b/src/sas/sascalc/dataloader/readers/tiff_reader.py
@@ -1,106 +1,108 @@
-#####################################################################
-#This software was developed by the University of Tennessee as part of the
-#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
-#project funded by the US National Science Foundation.
-#See the license text in license.txt
-#copyright 2008, University of Tennessee
-######################################################################
-"""
- Image reader. Untested.
-"""
-#TODO: load and check data and orientation of the image (needs rendering)
-import math
-import logging
-import os
-import numpy
-from sas.sascalc.dataloader.data_info import Data2D
-from sas.sascalc.dataloader.manipulations import reader2D_converter
-
-class Reader:
- """
- Example data manipulation
- """
- ## File type
- type_name = "TIF"
- ## Wildcards
- type = ["TIF files (*.tif)|*.tif",
- "TIFF files (*.tiff)|*.tiff",
- ]
- ## Extension
- ext = ['.tif', '.tiff']
-
- def read(self, filename=None):
- """
- Open and read the data in a file
-
- :param file: path of the file
- """
- try:
- import Image
- import TiffImagePlugin
- Image._initialized=2
- except:
- msg = "tiff_reader: could not load file. Missing Image module."
- raise RuntimeError, msg
-
- # Instantiate data object
- output = Data2D()
- output.filename = os.path.basename(filename)
-
- # Read in the image
- try:
- im = Image.open(filename)
- except:
- raise RuntimeError, "cannot open %s"%(filename)
- data = im.getdata()
-
- # Initiazed the output data object
- output.data = numpy.zeros([im.size[0], im.size[1]])
- output.err_data = numpy.zeros([im.size[0], im.size[1]])
- output.mask = numpy.ones([im.size[0], im.size[1]], dtype=bool)
-
- # Initialize
- x_vals = []
- y_vals = []
-
- # x and y vectors
- for i_x in range(im.size[0]):
- x_vals.append(i_x)
-
- itot = 0
- for i_y in range(im.size[1]):
- y_vals.append(i_y)
-
- for val in data:
- try:
- value = float(val)
- except:
- logging.error("tiff_reader: had to skip a non-float point")
- continue
-
- # Get bin number
- if math.fmod(itot, im.size[0]) == 0:
- i_x = 0
- i_y += 1
- else:
- i_x += 1
-
- output.data[im.size[1] - 1 - i_y][i_x] = value
-
- itot += 1
-
- output.xbins = im.size[0]
- output.ybins = im.size[1]
- output.x_bins = x_vals
- output.y_bins = y_vals
- output.qx_data = numpy.array(x_vals)
- output.qy_data = numpy.array(y_vals)
- output.xmin = 0
- output.xmax = im.size[0] - 1
- output.ymin = 0
- output.ymax = im.size[0] - 1
-
- # Store loading process information
- output.meta_data['loader'] = self.type_name
- output = reader2D_converter(output)
- return output
+#####################################################################
+#This software was developed by the University of Tennessee as part of the
+#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
+#project funded by the US National Science Foundation.
+#See the license text in license.txt
+#copyright 2008, University of Tennessee
+######################################################################
+"""
+ Image reader. Untested.
+"""
+#TODO: load and check data and orientation of the image (needs rendering)
+import math
+import logging
+import os
+import numpy as np
+from sas.sascalc.dataloader.data_info import Data2D
+from sas.sascalc.dataloader.manipulations import reader2D_converter
+
+logger = logging.getLogger(__name__)
+
+class Reader:
+ """
+ Example data manipulation
+ """
+ ## File type
+ type_name = "TIF"
+ ## Wildcards
+ type = ["TIF files (*.tif)|*.tif",
+ "TIFF files (*.tiff)|*.tiff",
+ ]
+ ## Extension
+ ext = ['.tif', '.tiff']
+
+ def read(self, filename=None):
+ """
+ Open and read the data in a file
+
+ :param file: path of the file
+ """
+ try:
+ import Image
+ import TiffImagePlugin
+ Image._initialized=2
+ except:
+ msg = "tiff_reader: could not load file. Missing Image module."
+ raise RuntimeError(msg)
+
+ # Instantiate data object
+ output = Data2D()
+ output.filename = os.path.basename(filename)
+
+ # Read in the image
+ try:
+ im = Image.open(filename)
+ except:
+ raise RuntimeError("cannot open %s"%(filename))
+ data = im.getdata()
+
+ # Initiazed the output data object
+ output.data = np.zeros([im.size[0], im.size[1]])
+ output.err_data = np.zeros([im.size[0], im.size[1]])
+ output.mask = np.ones([im.size[0], im.size[1]], dtype=bool)
+
+ # Initialize
+ x_vals = []
+ y_vals = []
+
+ # x and y vectors
+ for i_x in range(im.size[0]):
+ x_vals.append(i_x)
+
+ itot = 0
+ for i_y in range(im.size[1]):
+ y_vals.append(i_y)
+
+ for val in data:
+ try:
+ value = float(val)
+ except:
+ logger.error("tiff_reader: had to skip a non-float point")
+ continue
+
+ # Get bin number
+ if math.fmod(itot, im.size[0]) == 0:
+ i_x = 0
+ i_y += 1
+ else:
+ i_x += 1
+
+ output.data[im.size[1] - 1 - i_y][i_x] = value
+
+ itot += 1
+
+ output.xbins = im.size[0]
+ output.ybins = im.size[1]
+ output.x_bins = x_vals
+ output.y_bins = y_vals
+ output.qx_data = np.array(x_vals)
+ output.qy_data = np.array(y_vals)
+ output.xmin = 0
+ output.xmax = im.size[0] - 1
+ output.ymin = 0
+ output.ymax = im.size[0] - 1
+
+ # Store loading process information
+ output.meta_data['loader'] = self.type_name
+ output = reader2D_converter(output)
+ return output
diff --git a/src/sas/sascalc/dataloader/readers/xml_reader.py b/src/sas/sascalc/dataloader/readers/xml_reader.py
index 20f4e60..0f9587d 100644
--- a/src/sas/sascalc/dataloader/readers/xml_reader.py
+++ b/src/sas/sascalc/dataloader/readers/xml_reader.py
@@ -15,12 +15,17 @@
#############################################################################
import logging
+
from lxml import etree
from lxml.builder import E
+from ..file_reader_base_class import FileReader, decode
+
+logger = logging.getLogger(__name__)
+
PARSER = etree.ETCompatXMLParser(remove_comments=True, remove_pis=False)
-class XMLreader():
+class XMLreader(FileReader):
"""
Generic XML read and write class. Mostly helper functions.
Makes reading/writing XML a bit easier than calling lxml libraries directly.
@@ -70,7 +75,8 @@ class XMLreader():
self.xmldoc = etree.parse(self.xml, parser=PARSER)
self.xmlroot = self.xmldoc.getroot()
except etree.XMLSyntaxError as xml_error:
- logging.info(xml_error)
+ logger.info(xml_error)
+ raise xml_error
except Exception:
self.xml = None
self.xmldoc = None
@@ -87,11 +93,13 @@ class XMLreader():
self.xmldoc = tag_soup
self.xmlroot = etree.fromstring(tag_soup)
except etree.XMLSyntaxError as xml_error:
- logging.info(xml_error)
- except Exception:
+ logger.info(xml_error)
+ raise xml_error
+ except Exception as exc:
self.xml = None
self.xmldoc = None
self.xmlroot = None
+ raise exc
def set_schema(self, schema):
"""
@@ -101,7 +109,7 @@ class XMLreader():
self.schema = schema
self.schemadoc = etree.parse(self.schema, parser=PARSER)
except etree.XMLSyntaxError as xml_error:
- logging.info(xml_error)
+ logger.info(xml_error)
except Exception:
self.schema = None
self.schemadoc = None
@@ -144,8 +152,8 @@ class XMLreader():
"""
Converts an etree element into a string
"""
- return etree.tostring(elem, pretty_print=pretty_print, \
- encoding=encoding)
+ return decode(etree.tostring(elem, pretty_print=pretty_print,
+ encoding=encoding))
def break_processing_instructions(self, string, dic):
"""
@@ -206,7 +214,7 @@ class XMLreader():
"""
Create a unique key value for any dictionary to prevent overwriting
Recurses until a unique key value is found.
-
+
:param dictionary: A dictionary with any number of entries
:param name: The index of the item to be added to dictionary
:param numb: The number to be appended to the name, starts at 0
@@ -222,7 +230,7 @@ class XMLreader():
"""
Create an element tree for processing from an etree element
- :param root: etree Element(s)
+ :param root: etree Element(s)
"""
return etree.ElementTree(root)
@@ -240,7 +248,7 @@ class XMLreader():
:param name: The name of the element to be created
"""
- if attrib == None:
+ if attrib is None:
attrib = {}
return etree.Element(name, attrib, nsmap)
@@ -299,8 +307,8 @@ class XMLreader():
:param attrib: A dictionary of attribute names to attribute values
"""
text = str(text)
- if attrib == None:
+ if attrib is None:
attrib = {}
elem = E(elementname, attrib, text)
parent = parent.append(elem)
- return parent
\ No newline at end of file
+ return parent
diff --git a/src/sas/sascalc/file_converter/ascii2d_loader.py b/src/sas/sascalc/file_converter/ascii2d_loader.py
new file mode 100644
index 0000000..b515691
--- /dev/null
+++ b/src/sas/sascalc/file_converter/ascii2d_loader.py
@@ -0,0 +1,150 @@
+"""
+ASCII 2D Loader
+"""
+from sas.sascalc.dataloader.data_info import Data2D
+from sas.sascalc.file_converter.nxcansas_writer import NXcanSASWriter
+import numpy as np
+
+# ISIS 2D ASCII File Format
+# http://www.isis.stfc.ac.uk/instruments/loq/software/colette-ascii-file-format-descriptions9808.pdf
+# line: property
+# 0: File header
+# 1: q_x axis label and units
+# 2: q_y axis label and units
+# 3: Intensity axis label and units
+# 4: n_use_rec - number of lines of user content following this line
+# 5 to (5+n_use_rec): user content
+# Number of qx points
+# List of qx points
+# Number of qy points
+# List of qy points
+# numqx numqy scale
+
+class ASCII2DLoader(object):
+
+ def __init__(self, data_path):
+ """
+ :param data_path: The path to the file to load
+ """
+ self.data_path = data_path
+
+ def load(self):
+ """
+ Load the data from the file into a Data2D object
+
+ :return: A Data2D instance containing data from the file
+ :raises ValueError: Raises a ValueError if the file is incorrectly
+ formatted
+ """
+ with open(self.data_path, 'r') as file_handle:
+ file_buffer = file_handle.read()
+ all_lines = file_buffer.splitlines()
+
+ # Load num_points line-by-line from lines into a numpy array,
+ # starting on line number start_line
+ def _load_points(lines, start_line, num_points):
+ qs = np.zeros(num_points)
+ n = start_line
+ filled = 0
+ while filled < num_points:
+ row = np.fromstring(lines[n], dtype=np.float32, sep=' ')
+ qs[filled:filled+len(row)] = row
+ filled += len(row)
+ n += 1
+ return n, qs
+
+ current_line = 4
+ try:
+ # Skip n_use_rec lines
+ n_use_rec = int(all_lines[current_line].strip()[0])
+ current_line += n_use_rec + 1
+ # Read qx data
+ num_qs = int(all_lines[current_line].strip())
+ current_line += 1
+ current_line, qx = _load_points(all_lines, current_line, num_qs)
+
+ # Read qy data
+ num_qs = int(all_lines[current_line].strip())
+ current_line += 1
+ current_line, qy = _load_points(all_lines, current_line, num_qs)
+ except ValueError as e:
+ err_msg = "File incorrectly formatted.\n"
+ if str(e).find('broadcast') != -1:
+ err_msg += "Incorrect number of q data points provided. "
+ err_msg += "Expected {}.".format(num_qs)
+ elif str(e).find('invalid literal') != -1:
+ err_msg += ("Expected integer on line {}. "
+ "Instead got '{}'").format(current_line + 1,
+ all_lines[current_line])
+ else:
+ err_msg += str(e)
+ raise ValueError(err_msg)
+
+ # dimensions: [width, height, scale]
+ try:
+ dimensions = np.fromstring(all_lines[current_line],
+ dtype=np.float32, sep=' ')
+ if len(dimensions) != 3: raise ValueError()
+ width = int(dimensions[0])
+ height = int(dimensions[1])
+ except ValueError as e:
+ err_msg = "File incorrectly formatted.\n"
+ err_msg += ("Expected line {} to be of the form: <num_qx> "
+ "<num_qy> <scale>.").format(current_line + 1)
+ err_msg += " Instead got '{}'.".format(all_lines[current_line])
+ raise ValueError(err_msg)
+
+ if width > len(qx) or height > len(qy):
+ err_msg = "File incorrectly formatted.\n"
+ err_msg += ("Line {} says to use {}x{} points. "
+ "Only {}x{} provided.").format(current_line + 1, width,
+ height, len(qx), len(qy))
+ raise ValueError(err_msg)
+
+ # More qx and/or qy points can be provided than are actually used
+ qx = qx[:width]
+ qy = qy[:height]
+
+ current_line += 1
+ # iflag = 1 => Only intensity data (not dealt with here)
+ # iflag = 2 => q axis and intensity data
+ # iflag = 3 => q axis, intensity and error data
+ try:
+ iflag = int(all_lines[current_line].strip()[0])
+ if iflag <= 0 or iflag > 3: raise ValueError()
+ except:
+ err_msg = "File incorrectly formatted.\n"
+ iflag = all_lines[current_line].strip()[0]
+ err_msg += ("Expected iflag on line {} to be 1, 2 or 3. "
+ "Instead got '{}'.").format(current_line+1, iflag)
+ raise ValueError(err_msg)
+
+ current_line += 1
+
+ try:
+ current_line, I = _load_points(all_lines, current_line,
+ width * height)
+ dI = np.zeros(width*height)
+
+ # Load error data if it's provided
+ if iflag == 3:
+ _, dI = _load_points(all_lines, current_line, width*height)
+ except Exception as e:
+ err_msg = "File incorrectly formatted.\n"
+ if str(e).find("list index") != -1:
+ err_msg += ("Incorrect number of data points. Expected {}"
+ " intensity").format(width * height)
+ if iflag == 3:
+ err_msg += " and error"
+ err_msg += " points."
+ else:
+ err_msg += str(e)
+ raise ValueError(err_msg)
+
+ # Format data for use with Data2D
+ qx = list(qx) * height
+ qy = np.array([[y] * width for y in qy]).flatten()
+
+ data = Data2D(qx_data=qx, qy_data=qy, data=I, err_data=dI)
+
+ return data
diff --git a/src/sas/sascalc/file_converter/c_ext/__init__.py b/src/sas/sascalc/file_converter/c_ext/__init__.py
index e69de29..56ee607 100644
--- a/src/sas/sascalc/file_converter/c_ext/__init__.py
+++ b/src/sas/sascalc/file_converter/c_ext/__init__.py
@@ -0,0 +1,3 @@
+"""
+ Data loader for the Diamond BSL beamline.
+"""
diff --git a/src/sas/sascalc/file_converter/c_ext/bsl_loader.c b/src/sas/sascalc/file_converter/c_ext/bsl_loader.c
index 7db5b08..d8b5289 100644
--- a/src/sas/sascalc/file_converter/c_ext/bsl_loader.c
+++ b/src/sas/sascalc/file_converter/c_ext/bsl_loader.c
@@ -1,5 +1,5 @@
#include <Python.h>
-//#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
+#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
#include <numpy/arrayobject.h>
#include <stdio.h>
#include <stdlib.h>
@@ -43,7 +43,7 @@ static PyObject *CLoader_init(CLoader *self, PyObject *args, PyObject *kwds) {
static void CLoader_dealloc(CLoader *self) {
free(self->params.filename);
- self->ob_type->tp_free((PyObject *)self);
+ Py_TYPE(self)->tp_free((PyObject *)self);
}
static PyObject *to_string(CLoader *self, PyObject *params) {
@@ -236,8 +236,9 @@ static PyMemberDef CLoader_members[] = {
};
static PyTypeObject CLoaderType = {
- PyObject_HEAD_INIT(NULL)
- 0, /*ob_size*/
+ //PyObject_HEAD_INIT(NULL)
+ //0, /*ob_size*/
+ PyVarObject_HEAD_INIT(NULL, 0)
"CLoader", /*tp_name*/
sizeof(CLoader), /*tp_basicsize*/
0, /*tp_itemsize*/
@@ -277,16 +278,65 @@ static PyTypeObject CLoaderType = {
CLoader_new, /* tp_new */
};
-PyMODINIT_FUNC
-initbsl_loader(void)
+/**
+ * Function used to add the model class to a module
+ * @param module: module to add the class to
+ */
+void addCLoader(PyObject *module)
{
- PyObject *module;
- module = Py_InitModule("bsl_loader", NULL);
- import_array();
-
if (PyType_Ready(&CLoaderType) < 0)
return;
-
Py_INCREF(&CLoaderType);
PyModule_AddObject(module, "CLoader", (PyObject *)&CLoaderType);
}
+
+#define MODULE_DOC "C module for loading bsl."
+#define MODULE_NAME "bsl_loader"
+#define MODULE_INIT2 initbsl_loader
+#define MODULE_INIT3 PyInit_bsl_loader
+#define MODULE_METHODS module_methods
+
+/* ==== boilerplate python 2/3 interface bootstrap ==== */
+
+
+#if defined(WIN32) && !defined(__MINGW32__)
+ #define DLL_EXPORT __declspec(dllexport)
+#else
+ #define DLL_EXPORT
+#endif
+
+#if PY_MAJOR_VERSION >= 3
+
+ static PyMethodDef module_methods[] = {
+ {NULL}
+ };
+
+ DLL_EXPORT PyMODINIT_FUNC MODULE_INIT3(void)
+ {
+ static struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT,
+ MODULE_NAME, /* m_name */
+ MODULE_DOC, /* m_doc */
+ -1, /* m_size */
+ MODULE_METHODS, /* m_methods */
+ NULL, /* m_reload */
+ NULL, /* m_traverse */
+ NULL, /* m_clear */
+ NULL, /* m_free */
+ };
+ PyObject* m = PyModule_Create(&moduledef);
+ import_array();
+ addCLoader(m);
+ return m;
+ }
+
+#else /* !PY_MAJOR_VERSION >= 3 */
+
+ DLL_EXPORT PyMODINIT_FUNC MODULE_INIT2(void)
+ {
+ PyObject* m = Py_InitModule(MODULE_NAME, NULL);
+ import_array();
+ addCLoader(m);
+ }
+
+#endif /* !PY_MAJOR_VERSION >= 3 */
\ No newline at end of file
diff --git a/src/sas/sascalc/file_converter/cansas_writer.py b/src/sas/sascalc/file_converter/cansas_writer.py
index 8fd7ab2..b519d4d 100644
--- a/src/sas/sascalc/file_converter/cansas_writer.py
+++ b/src/sas/sascalc/file_converter/cansas_writer.py
@@ -16,7 +16,7 @@ class CansasWriter(CansasReader):
doc, _ = self._to_xml_doc(frame_data, sasentry_attrs)
# Write the file
file_ref = open(filename, 'w')
- if self.encoding == None:
+ if self.encoding is None:
self.encoding = "UTF-8"
doc.write(file_ref, encoding=self.encoding,
pretty_print=True, xml_declaration=True)
@@ -31,7 +31,7 @@ class CansasWriter(CansasReader):
"""
valid_class = all([issubclass(data.__class__, Data1D) for data in frame_data])
if not valid_class:
- raise RuntimeError, ("The cansas writer expects an array of "
+ raise RuntimeError("The cansas writer expects an array of "
"Data1D instances")
# Get PIs and create root element
@@ -95,15 +95,15 @@ class CansasWriter(CansasReader):
if len(datainfo.y) >= i:
self.write_node(point, "I", datainfo.y[i],
{'unit': datainfo.y_unit})
- if datainfo.dy != None and len(datainfo.dy) > i:
+ if datainfo.dy is not None and len(datainfo.dy) > i:
self.write_node(point, "Idev", datainfo.dy[i],
{'unit': datainfo.y_unit})
- if datainfo.dx != None and len(datainfo.dx) > i:
+ if datainfo.dx is not None and len(datainfo.dx) > i:
self.write_node(point, "Qdev", datainfo.dx[i],
{'unit': datainfo.x_unit})
- if datainfo.dxw != None and len(datainfo.dxw) > i:
+ if datainfo.dxw is not None and len(datainfo.dxw) > i:
self.write_node(point, "dQw", datainfo.dxw[i],
{'unit': datainfo.x_unit})
- if datainfo.dxl != None and len(datainfo.dxl) > i:
+ if datainfo.dxl is not None and len(datainfo.dxl) > i:
self.write_node(point, "dQl", datainfo.dxl[i],
{'unit': datainfo.x_unit})
diff --git a/src/sas/sascalc/file_converter/nxcansas_writer.py b/src/sas/sascalc/file_converter/nxcansas_writer.py
index ea9da53..b0d8b50 100644
--- a/src/sas/sascalc/file_converter/nxcansas_writer.py
+++ b/src/sas/sascalc/file_converter/nxcansas_writer.py
@@ -165,7 +165,7 @@ class NXcanSASWriter(Cansas2Reader):
'wavelength_min':'wavelength_min',
'wavelength_max': 'wavelength_max',
'wavelength_spread': 'incident_wavelength_spread' }
- for sasname, nxname in wavelength_keys.iteritems():
+ for sasname, nxname in wavelength_keys.items():
value = getattr(data_info.source, sasname)
units = getattr(data_info.source, sasname + '_unit')
if value is not None:
diff --git a/src/sas/sascalc/fit/AbstractFitEngine.py b/src/sas/sascalc/fit/AbstractFitEngine.py
index 85e2d99..b4833d8 100644
--- a/src/sas/sascalc/fit/AbstractFitEngine.py
+++ b/src/sas/sascalc/fit/AbstractFitEngine.py
@@ -1,9 +1,10 @@
+from __future__ import print_function
import copy
#import logging
import sys
import math
-import numpy
+import numpy as np
from sas.sascalc.dataloader.data_info import Data1D
from sas.sascalc.dataloader.data_info import Data2D
@@ -135,21 +136,21 @@ class FitData1D(Data1D):
:param smearer: is an object of class QSmearer or SlitSmearer
that will smear the theory data (slit smearing or resolution
smearing) when set.
-
+
The proper way to set the smearing object would be to
do the following: ::
-
- from sas.sascalc.data_util.qsmearing import smear_selection
+
+ from sas.sascalc.fit.qsmearing import smear_selection
smearer = smear_selection(some_data)
fitdata1d = FitData1D( x= [1,3,..,],
y= [3,4,..,8],
dx=None,
dy=[1,2...], smearer= smearer)
-
+
:Note: that some_data _HAS_ to be of
class DataLoader.data_info.Data1D
Setting it back to None will turn smearing off.
-
+
"""
Data1D.__init__(self, x=x, y=y, dx=dx, dy=dy, lam=lam, dlam=dlam)
self.num_points = len(x)
@@ -161,20 +162,20 @@ class FitData1D(Data1D):
# TODO: Should provide an option for users to set it like percent,
# constant, or dy data
if dy is None or dy == [] or dy.all() == 0:
- self.dy = numpy.ones(len(y))
+ self.dy = np.ones(len(y))
else:
- self.dy = numpy.asarray(dy).copy()
+ self.dy = np.asarray(dy).copy()
## Min Q-value
#Skip the Q=0 point, especially when y(q=0)=None at x[0].
if min(self.x) == 0.0 and self.x[0] == 0 and\
- not numpy.isfinite(self.y[0]):
+ not np.isfinite(self.y[0]):
self.qmin = min(self.x[self.x != 0])
else:
self.qmin = min(self.x)
## Max Q-value
self.qmax = max(self.x)
-
+
# Range used for input to smearing
self._qmin_unsmeared = self.qmin
self._qmax_unsmeared = self.qmax
@@ -182,31 +183,31 @@ class FitData1D(Data1D):
self.idx = (self.x >= self.qmin) & (self.x <= self.qmax)
self.idx_unsmeared = (self.x >= self._qmin_unsmeared) \
& (self.x <= self._qmax_unsmeared)
-
+
def set_fit_range(self, qmin=None, qmax=None):
""" to set the fit range"""
# Skip Q=0 point, (especially for y(q=0)=None at x[0]).
# ToDo: Find better way to do it.
- if qmin == 0.0 and not numpy.isfinite(self.y[qmin]):
+ if qmin == 0.0 and not np.isfinite(self.y[qmin]):
self.qmin = min(self.x[self.x != 0])
- elif qmin != None:
+ elif qmin is not None:
self.qmin = qmin
- if qmax != None:
+ if qmax is not None:
self.qmax = qmax
# Determine the range needed in unsmeared-Q to cover
# the smeared Q range
self._qmin_unsmeared = self.qmin
self._qmax_unsmeared = self.qmax
-
+
self._first_unsmeared_bin = 0
self._last_unsmeared_bin = len(self.x) - 1
-
- if self.smearer != None:
+
+ if self.smearer is not None:
self._first_unsmeared_bin, self._last_unsmeared_bin = \
self.smearer.get_bin_range(self.qmin, self.qmax)
self._qmin_unsmeared = self.x[self._first_unsmeared_bin]
self._qmax_unsmeared = self.x[self._last_unsmeared_bin]
-
+
# Identify the bin range for the unsmeared and smeared spaces
self.idx = (self.x >= self.qmin) & (self.x <= self.qmax)
## zero error can not participate for fitting
@@ -229,34 +230,34 @@ class FitData1D(Data1D):
def residuals(self, fn):
"""
Compute residuals.
-
+
If self.smearer has been set, use if to smear
the data before computing chi squared.
-
+
:param fn: function that return model value
-
+
:return: residuals
"""
# Compute theory data f(x)
- fx = numpy.zeros(len(self.x))
+ fx = np.zeros(len(self.x))
fx[self.idx_unsmeared] = fn(self.x[self.idx_unsmeared])
-
+
## Smear theory data
if self.smearer is not None:
fx = self.smearer(fx, self._first_unsmeared_bin,
self._last_unsmeared_bin)
## Sanity check
- if numpy.size(self.dy) != numpy.size(fx):
+ if np.size(self.dy) != np.size(fx):
msg = "FitData1D: invalid error array "
- msg += "%d <> %d" % (numpy.shape(self.dy), numpy.size(fx))
- raise RuntimeError, msg
+ msg += "%d <> %d" % (np.shape(self.dy), np.size(fx))
+ raise RuntimeError(msg)
return (self.y[self.idx] - fx[self.idx]) / self.dy[self.idx], fx[self.idx]
-
+
def residuals_deriv(self, model, pars=[]):
"""
:return: residuals derivatives .
-
- :note: in this case just return empty array
+
+ :note: in this case just return empty array
"""
return []
@@ -291,33 +292,33 @@ class FitData2D(Data2D):
x_max = max(math.fabs(sas_data2d.xmin), math.fabs(sas_data2d.xmax))
y_max = max(math.fabs(sas_data2d.ymin), math.fabs(sas_data2d.ymax))
-
+
## fitting range
- if qmin == None:
+ if qmin is None:
self.qmin = 1e-16
- if qmax == None:
+ if qmax is None:
self.qmax = math.sqrt(x_max * x_max + y_max * y_max)
## new error image for fitting purpose
- if self.err_data == None or self.err_data == []:
- self.res_err_data = numpy.ones(len(self.data))
+ if self.err_data is None or self.err_data == []:
+ self.res_err_data = np.ones(len(self.data))
else:
self.res_err_data = copy.deepcopy(self.err_data)
#self.res_err_data[self.res_err_data==0]=1
-
- self.radius = numpy.sqrt(self.qx_data**2 + self.qy_data**2)
-
+
+ self.radius = np.sqrt(self.qx_data**2 + self.qy_data**2)
+
# Note: mask = True: for MASK while mask = False for NOT to mask
self.idx = ((self.qmin <= self.radius) &\
(self.radius <= self.qmax))
self.idx = (self.idx) & (self.mask)
- self.idx = (self.idx) & (numpy.isfinite(self.data))
- self.num_points = numpy.sum(self.idx)
+ self.idx = (self.idx) & (np.isfinite(self.data))
+ self.num_points = np.sum(self.idx)
def set_smearer(self, smearer):
"""
Set smearer
"""
- if smearer == None:
+ if smearer is None:
return
self.smearer = smearer
self.smearer.set_index(self.idx)
@@ -329,15 +330,15 @@ class FitData2D(Data2D):
"""
if qmin == 0.0:
self.qmin = 1e-16
- elif qmin != None:
+ elif qmin is not None:
self.qmin = qmin
- if qmax != None:
+ if qmax is not None:
self.qmax = qmax
- self.radius = numpy.sqrt(self.qx_data**2 + self.qy_data**2)
+ self.radius = np.sqrt(self.qx_data**2 + self.qy_data**2)
self.idx = ((self.qmin <= self.radius) &\
(self.radius <= self.qmax))
self.idx = (self.idx) & (self.mask)
- self.idx = (self.idx) & (numpy.isfinite(self.data))
+ self.idx = (self.idx) & (np.isfinite(self.data))
self.idx = (self.idx) & (self.res_err_data != 0)
def get_fit_range(self):
@@ -350,13 +351,13 @@ class FitData2D(Data2D):
"""
Number of measurement points in data set after masking, etc.
"""
- return numpy.sum(self.idx)
+ return np.sum(self.idx)
def residuals(self, fn):
"""
return the residuals
"""
- if self.smearer != None:
+ if self.smearer is not None:
fn.set_index(self.idx)
gn = fn.get_value()
else:
@@ -366,17 +367,17 @@ class FitData2D(Data2D):
res = (self.data[self.idx] - gn) / self.res_err_data[self.idx]
return res, gn
-
+
def residuals_deriv(self, model, pars=[]):
"""
:return: residuals derivatives .
-
+
:note: in this case just return empty array
-
+
"""
return []
-
-
+
+
class FitAbort(Exception):
"""
Exception raise to stop the fit
@@ -394,25 +395,25 @@ class FitEngine:
#Dictionnary of fitArrange element (fit problems)
self.fit_arrange_dict = {}
self.fitter_id = None
-
+
def set_model(self, model, id, pars=[], constraints=[], data=None):
"""
set a model on a given in the fit engine.
-
- :param model: sas.models type
+
+ :param model: sas.models type
:param id: is the key of the fitArrange dictionary where model is saved as a value
- :param pars: the list of parameters to fit
- :param constraints: list of
+ :param pars: the list of parameters to fit
+ :param constraints: list of
tuple (name of parameter, value of parameters)
the value of parameter must be a string to constraint 2 different
parameters.
- Example:
+ Example:
we want to fit 2 model M1 and M2 both have parameters A and B.
constraints can be ``constraints = [(M1.A, M2.B+2), (M1.B= M2.A *5),...,]``
-
-
+
+
:note: pars must contains only name of existing model's parameters
-
+
"""
if not pars:
raise ValueError("no fitting parameters")
@@ -443,7 +444,7 @@ class FitEngine:
Receives plottable, creates a list of data to fit,set data
in a FitArrange object and adds that object in a dictionary
with key id.
-
+
:param data: data added
:param id: unique key corresponding to a fitArrange object with data
"""
@@ -454,7 +455,7 @@ class FitEngine:
fitdata = FitData1D(x=data.x, y=data.y,
dx=data.dx, dy=data.dy, smearer=smearer)
fitdata.sas_data = data
-
+
fitdata.set_fit_range(qmin=qmin, qmax=qmax)
#A fitArrange is already created but contains model only at id
if id in self.fit_arrange_dict:
@@ -464,11 +465,11 @@ class FitEngine:
fitproblem = FitArrange()
fitproblem.add_data(fitdata)
self.fit_arrange_dict[id] = fitproblem
-
+
def get_model(self, id):
"""
:param id: id is key in the dictionary containing the model to return
-
+
:return: a model at this id or None if no FitArrange element was
created with this id
"""
@@ -476,43 +477,43 @@ class FitEngine:
return self.fit_arrange_dict[id].get_model()
else:
return None
-
+
def remove_fit_problem(self, id):
"""remove fitarrange in id"""
if id in self.fit_arrange_dict:
del self.fit_arrange_dict[id]
-
+
def select_problem_for_fit(self, id, value):
"""
select a couple of model and data at the id position in dictionary
and set in self.selected value to value
-
+
:param value: the value to allow fitting.
can only have the value one or zero
"""
if id in self.fit_arrange_dict:
self.fit_arrange_dict[id].set_to_fit(value)
-
+
def get_problem_to_fit(self, id):
"""
return the self.selected value of the fit problem of id
-
+
:param id: the id of the problem
"""
if id in self.fit_arrange_dict:
self.fit_arrange_dict[id].get_to_fit()
-
-
+
+
class FitArrange:
def __init__(self):
"""
Class FitArrange contains a set of data for a given model
to perform the Fit.FitArrange must contain exactly one model
and at least one data for the fit to be performed.
-
+
model: the model selected by the user
Ldata: a list of data what the user wants to fit
-
+
"""
self.model = None
self.data_list = []
@@ -523,49 +524,49 @@ class FitArrange:
def set_model(self, model):
"""
set_model save a copy of the model
-
+
:param model: the model being set
"""
self.model = model
-
+
def add_data(self, data):
"""
add_data fill a self.data_list with data to fit
-
+
:param data: Data to add in the list
"""
if not data in self.data_list:
self.data_list.append(data)
-
+
def get_model(self):
"""
:return: saved model
"""
return self.model
-
+
def get_data(self):
"""
:return: list of data data_list
"""
return self.data_list[0]
-
+
def remove_data(self, data):
"""
Remove one element from the list
-
+
:param data: Data to remove from data_list
"""
if data in self.data_list:
self.data_list.remove(data)
-
+
def set_to_fit(self, value=0):
"""
set self.selected to 0 or 1 for other values raise an exception
-
+
:param value: integer between 0 or 1
"""
self.selected = value
-
+
def get_to_fit(self):
"""
return self.selected value
@@ -597,21 +598,21 @@ class FResult(object):
self.fitter_id = None
if self.model is not None and self.data is not None:
self.inputs = [(self.model, self.data)]
-
+
def set_model(self, model):
"""
"""
self.model = model
-
+
def set_fitness(self, fitness):
"""
"""
self.fitness = fitness
-
+
def __str__(self):
"""
"""
- if self.pvec == None and self.model is None and self.param_list is None:
+ if self.pvec is None and self.model is None and self.param_list is None:
return "No results"
sasmodel = self.model.model
@@ -622,8 +623,8 @@ class FResult(object):
for i,v in pars if v in self.param_list]
msg = [msg1, msg3] + msg2
return "\n".join(msg)
-
+
def print_summary(self):
"""
"""
- print str(self)
+ print(str(self))
diff --git a/src/sas/sascalc/fit/BumpsFitting.py b/src/sas/sascalc/fit/BumpsFitting.py
index 17ab77f..e617340 100644
--- a/src/sas/sascalc/fit/BumpsFitting.py
+++ b/src/sas/sascalc/fit/BumpsFitting.py
@@ -5,7 +5,7 @@ import os
from datetime import timedelta, datetime
import traceback
-import numpy
+import numpy as np
from bumps import fitters
try:
@@ -14,7 +14,7 @@ try:
FIT_CONFIG.selected_id = fitters.LevenbergMarquardtFit.id
def get_fitter():
return FIT_CONFIG.selected_fitter, FIT_CONFIG.selected_values
-except:
+except ImportError:
# CRUFT: Bumps changed its handling of fit options around 0.7.5.6
# Default bumps to use the Levenberg-Marquardt optimizer
fitters.FIT_DEFAULT = 'lm'
@@ -55,7 +55,7 @@ class Progress(object):
step = "%d of %d"%(history.step[0], max_step)
header = "=== Steps: %s chisq: %s ETA: %s\n"%(step, chisq, time)
parameters = ["%15s: %-10.3g%s"%(k,v,("\n" if i%3==2 else " | "))
- for i,(k,v) in enumerate(zip(pars,history.point[0]))]
+ for i, (k, v) in enumerate(zip(pars, history.point[0]))]
self.msg = "".join([header]+parameters)
def __str__(self):
@@ -76,7 +76,7 @@ class BumpsMonitor(object):
if self.handler is None: return
self.handler.set_result(Progress(history, self.max_step, self.pars, self.dof))
self.handler.progress(history.step[0], self.max_step)
- if len(history.step)>1 and history.step[1] > history.step[0]:
+ if len(history.step) > 1 and history.step[1] > history.step[0]:
self.handler.improvement()
self.handler.update_fit()
@@ -96,11 +96,11 @@ class ConvergenceMonitor(object):
best = history.value[0]
try:
p = history.population_values[0]
- n,p = len(p), numpy.sort(p)
- QI,Qmid, = int(0.2*n),int(0.5*n)
- self.convergence.append((best, p[0],p[QI],p[Qmid],p[-1-QI],p[-1]))
- except:
- self.convergence.append((best, best,best,best,best,best))
+ n, p = len(p), np.sort(p)
+ QI, Qmid = int(0.2*n), int(0.5*n)
+ self.convergence.append((best, p[0], p[QI], p[Qmid], p[-1-QI], p[-1]))
+ except Exception:
+ self.convergence.append((best, best, best, best, best, best))
# Note: currently using bumps parameters for each parameter object so that
@@ -130,26 +130,30 @@ class SasFitness(object):
self.update()
def _reset_pars(self, names, values):
- for k,v in zip(names, values):
+ for k, v in zip(names, values):
self._pars[k].value = v
def _define_pars(self):
self._pars = {}
for k in self.model.getParamList():
- name = ".".join((self.name,k))
+ name = ".".join((self.name, k))
value = self.model.getParam(k)
- bounds = self.model.details.get(k,["",None,None])[1:3]
+ bounds = self.model.details.get(k, ["", None, None])[1:3]
self._pars[k] = parameter.Parameter(value=value, bounds=bounds,
fixed=True, name=name)
#print parameter.summarize(self._pars.values())
def _init_pars(self, kw):
- for k,v in kw.items():
+ for k, v in kw.items():
# dispersion parameters initialized with _field instead of .field
- if k.endswith('_width'): k = k[:-6]+'.width'
- elif k.endswith('_npts'): k = k[:-5]+'.npts'
- elif k.endswith('_nsigmas'): k = k[:-7]+'.nsigmas'
- elif k.endswith('_type'): k = k[:-5]+'.type'
+ if k.endswith('_width'):
+ k = k[:-6]+'.width'
+ elif k.endswith('_npts'):
+ k = k[:-5]+'.npts'
+ elif k.endswith('_nsigmas'):
+ k = k[:-7]+'.nsigmas'
+ elif k.endswith('_type'):
+ k = k[:-5]+'.type'
if k not in self._pars:
formatted_pars = ", ".join(sorted(self._pars.keys()))
raise KeyError("invalid parameter %r for %s--use one of: %s"
@@ -158,10 +162,10 @@ class SasFitness(object):
self.model.setParam(k, v)
elif isinstance(v, parameter.BaseParameter):
self._pars[k] = v
- elif isinstance(v, (tuple,list)):
+ elif isinstance(v, (tuple, list)):
low, high = v
self._pars[k].value = (low+high)/2
- self._pars[k].range(low,high)
+ self._pars[k].range(low, high)
else:
self._pars[k].value = v
@@ -169,7 +173,7 @@ class SasFitness(object):
"""
Flag a set of parameters as fitted parameters.
"""
- for k,p in self._pars.items():
+ for k, p in self._pars.items():
p.fixed = (k not in param_list or k in self.constraints)
self.fitted_par_names = [k for k in param_list if k not in self.constraints]
self.computed_par_names = [k for k in param_list if k in self.constraints]
@@ -181,9 +185,9 @@ class SasFitness(object):
return self._pars
def update(self):
- for k,v in self._pars.items():
+ for k, v in self._pars.items():
#print "updating",k,v,v.value
- self.model.setParam(k,v.value)
+ self.model.setParam(k, v.value)
self._dirty = True
def _recalculate(self):
@@ -193,10 +197,10 @@ class SasFitness(object):
self._dirty = False
def numpoints(self):
- return numpy.sum(self.data.idx) # number of fitted points
+ return np.sum(self.data.idx) # number of fitted points
def nllf(self):
- return 0.5*numpy.sum(self.residuals()**2)
+ return 0.5*np.sum(self.residuals()**2)
def theory(self):
self._recalculate()
@@ -222,7 +226,7 @@ class ParameterExpressions(object):
if exprs:
symtab = dict((".".join((M.name, k)), p)
for M in self.models
- for k,p in M.parameters().items())
+ for k, p in M.parameters().items())
self.update = compile_constraints(symtab, exprs)
else:
self.update = lambda: 0
@@ -294,17 +298,17 @@ class BumpsFit(FitEngine):
R.success = result['success']
if R.success:
if result['stderr'] is None:
- R.stderr = numpy.NaN*numpy.ones(len(param_list))
+ R.stderr = np.NaN*np.ones(len(param_list))
else:
- R.stderr = numpy.hstack((result['stderr'][fitted_index],
- numpy.NaN*numpy.ones(len(fitness.computed_pars))))
- R.pvec = numpy.hstack((result['value'][fitted_index],
- [p.value for p in fitness.computed_pars]))
- R.fitness = numpy.sum(R.residuals**2)/(fitness.numpoints() - len(fitted_index))
+ R.stderr = np.hstack((result['stderr'][fitted_index],
+ np.NaN*np.ones(len(fitness.computed_pars))))
+ R.pvec = np.hstack((result['value'][fitted_index],
+ [p.value for p in fitness.computed_pars]))
+ R.fitness = np.sum(R.residuals**2)/(fitness.numpoints() - len(fitted_index))
else:
- R.stderr = numpy.NaN*numpy.ones(len(param_list))
- R.pvec = numpy.asarray( [p.value for p in fitness.fitted_pars+fitness.computed_pars])
- R.fitness = numpy.NaN
+ R.stderr = np.NaN*np.ones(len(param_list))
+ R.pvec = np.asarray([p.value for p in fitness.fitted_pars+fitness.computed_pars])
+ R.fitness = np.NaN
R.convergence = result['convergence']
if result['uncertainty'] is not None:
R.uncertainty_state = result['uncertainty']
@@ -330,19 +334,19 @@ def run_bumps(problem, handler, curr_thread):
fitclass, options = get_fitter()
steps = options.get('steps', 0)
if steps == 0:
- pop = options.get('pop',0)*len(problem._parameters)
+ pop = options.get('pop', 0)*len(problem._parameters)
samples = options.get('samples', 0)
steps = (samples+pop-1)/pop if pop != 0 else samples
max_step = steps + options.get('burn', 0)
pars = [p.name for p in problem._parameters]
- #x0 = numpy.asarray([p.value for p in problem._parameters])
+ #x0 = np.asarray([p.value for p in problem._parameters])
options['monitors'] = [
BumpsMonitor(handler, max_step, pars, problem.dof),
ConvergenceMonitor(),
]
fitdriver = fitters.FitDriver(fitclass, problem=problem,
abort_test=abort_test, **options)
- omp_threads = int(os.environ.get('OMP_NUM_THREADS','0'))
+ omp_threads = int(os.environ.get('OMP_NUM_THREADS', '0'))
mapper = MPMapper if omp_threads == 1 else SerialMapper
fitdriver.mapper = mapper.start_mapper(problem, None)
#import time; T0 = time.time()
@@ -350,15 +354,15 @@ def run_bumps(problem, handler, curr_thread):
best, fbest = fitdriver.fit()
errors = []
except Exception as exc:
- best, fbest = None, numpy.NaN
+ best, fbest = None, np.NaN
errors = [str(exc), traceback.format_exc()]
finally:
mapper.stop_mapper(fitdriver.mapper)
convergence_list = options['monitors'][-1].convergence
- convergence = (2*numpy.asarray(convergence_list)/problem.dof
- if convergence_list else numpy.empty((0,1),'d'))
+ convergence = (2*np.asarray(convergence_list)/problem.dof
+ if convergence_list else np.empty((0, 1), 'd'))
success = best is not None
try:
@@ -375,4 +379,3 @@ def run_bumps(problem, handler, curr_thread):
'uncertainty': getattr(fitdriver.fitter, 'state', None),
'errors': '\n'.join(errors),
}
-
diff --git a/src/sas/sascalc/fit/Loader.py b/src/sas/sascalc/fit/Loader.py
index 18bada0..f2a9987 100644
--- a/src/sas/sascalc/fit/Loader.py
+++ b/src/sas/sascalc/fit/Loader.py
@@ -1,86 +1,87 @@
-# class Loader to load any king of file
-#import wx
-#import string
-import numpy
-
-class Load:
- """
- This class is loading values from given file or value giving by the user
- """
- def __init__(self, x=None, y=None, dx=None, dy=None):
- raise NotImplementedError("a code search shows that this code is not active, and you are not seeing this message")
- # variable to store loaded values
- self.x = x
- self.y = y
- self.dx = dx
- self.dy = dy
- self.filename = None
-
- def set_filename(self, path=None):
- """
- Store path into a variable.If the user doesn't give
- a path as a parameter a pop-up
- window appears to select the file.
-
- :param path: the path given by the user
-
- """
- self.filename = path
-
- def get_filename(self):
- """ return the file's path"""
- return self.filename
-
- def set_values(self):
- """ Store the values loaded from file in local variables"""
- if not self.filename == None:
- input_f = open(self.filename, 'r')
- buff = input_f.read()
- lines = buff.split('\n')
- self.x = []
- self.y = []
- self.dx = []
- self.dy = []
- for line in lines:
- try:
- toks = line.split()
- x = float(toks[0])
- y = float(toks[1])
- dy = float(toks[2])
-
- self.x.append(x)
- self.y.append(y)
- self.dy.append(dy)
- self.dx = numpy.zeros(len(self.x))
- except:
- print "READ ERROR", line
- # Sanity check
- if not len(self.x) == len(self.dx):
- raise ValueError, "x and dx have different length"
- if not len(self.y) == len(self.dy):
- raise ValueError, "y and dy have different length"
-
-
- def get_values(self):
- """ Return x, y, dx, dy"""
- return self.x, self.y, self.dx, self.dy
-
- def load_data(self, data):
- """ Return plottable"""
- #load data
- data.x = self.x
- data.y = self.y
- data.dx = self.dx
- data.dy = self.dy
- #Load its View class
- #plottable.reset_view()
-
-
-if __name__ == "__main__":
- load = Load()
- load.set_filename("testdata_line.txt")
- print load.get_filename()
- load.set_values()
- print load.get_values()
-
-
\ No newline at end of file
+from __future__ import print_function
+
+# class Loader to load any king of file
+#import wx
+#import string
+import numpy as np
+
+class Load:
+ """
+ This class is loading values from given file or value giving by the user
+ """
+ def __init__(self, x=None, y=None, dx=None, dy=None):
+ raise NotImplementedError("a code search shows that this code is not active, and you are not seeing this message")
+ # variable to store loaded values
+ self.x = x
+ self.y = y
+ self.dx = dx
+ self.dy = dy
+ self.filename = None
+
+ def set_filename(self, path=None):
+ """
+ Store path into a variable.If the user doesn't give
+ a path as a parameter a pop-up
+ window appears to select the file.
+
+ :param path: the path given by the user
+
+ """
+ self.filename = path
+
+ def get_filename(self):
+ """ return the file's path"""
+ return self.filename
+
+ def set_values(self):
+ """ Store the values loaded from file in local variables"""
+ if self.filename is not None:
+ input_f = open(self.filename, 'r')
+ buff = input_f.read()
+ lines = buff.split('\n')
+ self.x = []
+ self.y = []
+ self.dx = []
+ self.dy = []
+ for line in lines:
+ try:
+ toks = line.split()
+ x = float(toks[0])
+ y = float(toks[1])
+ dy = float(toks[2])
+
+ self.x.append(x)
+ self.y.append(y)
+ self.dy.append(dy)
+ self.dx = np.zeros(len(self.x))
+ except:
+ print("READ ERROR", line)
+ # Sanity check
+ if not len(self.x) == len(self.dx):
+ raise ValueError("x and dx have different length")
+ if not len(self.y) == len(self.dy):
+ raise ValueError("y and dy have different length")
+
+
+ def get_values(self):
+ """ Return x, y, dx, dy"""
+ return self.x, self.y, self.dx, self.dy
+
+ def load_data(self, data):
+ """ Return plottable"""
+ #load data
+ data.x = self.x
+ data.y = self.y
+ data.dx = self.dx
+ data.dy = self.dy
+ #Load its View class
+ #plottable.reset_view()
+
+
+if __name__ == "__main__":
+ load = Load()
+ load.set_filename("testdata_line.txt")
+ print(load.get_filename())
+ load.set_values()
+ print(load.get_values())
+
diff --git a/src/sas/sascalc/fit/MultiplicationModel.py b/src/sas/sascalc/fit/MultiplicationModel.py
index 1f5319f..b84e298 100644
--- a/src/sas/sascalc/fit/MultiplicationModel.py
+++ b/src/sas/sascalc/fit/MultiplicationModel.py
@@ -1,6 +1,6 @@
import copy
-import numpy
+import numpy as np
from sas.sascalc.calculator.BaseComponent import BaseComponent
@@ -51,8 +51,8 @@ class MultiplicationModel(BaseComponent):
## Parameter details [units, min, max]
self._set_details()
- self.details['scale_factor'] = ['', 0.0, numpy.inf]
- self.details['background'] = ['',-numpy.inf,numpy.inf]
+ self.details['scale_factor'] = ['', 0.0, np.inf]
+ self.details['background'] = ['',-np.inf,np.inf]
#list of parameter that can be fitted
self._set_fixed_params()
@@ -108,7 +108,7 @@ class MultiplicationModel(BaseComponent):
applied to s_model
"""
##set dispersion only from p_model
- for name , value in self.p_model.dispersion.iteritems():
+ for name , value in self.p_model.dispersion.items():
self.dispersion[name] = value
def getProfile(self):
@@ -134,11 +134,11 @@ class MultiplicationModel(BaseComponent):
these model parameters
"""
- for name , value in self.p_model.params.iteritems():
+ for name , value in self.p_model.params.items():
if not name in self.params.keys() and name not in self.excluded_params:
self.params[name] = value
- for name , value in self.s_model.params.iteritems():
+ for name , value in self.s_model.params.items():
#Remove the radius_effective from the (P*S) model parameters.
if not name in self.params.keys() and name not in self.excluded_params:
self.params[name] = value
@@ -154,11 +154,11 @@ class MultiplicationModel(BaseComponent):
Concatenate details of the two models to create
this model's details
"""
- for name, detail in self.p_model.details.iteritems():
+ for name, detail in self.p_model.details.items():
if name not in self.excluded_params:
self.details[name] = detail
- for name , detail in self.s_model.details.iteritems():
+ for name , detail in self.s_model.details.items():
if not name in self.details.keys() or name not in self.exluded_params:
self.details[name] = detail
@@ -177,9 +177,9 @@ class MultiplicationModel(BaseComponent):
Set scale=volfraction for P model
"""
value = self.params['volfraction']
- if value != None:
+ if value is not None:
factor = self.p_model.calculate_VR()
- if factor == None or factor == NotImplemented or factor == 0.0:
+ if factor is None or factor == NotImplemented or factor == 0.0:
val = value
else:
val = value / factor
@@ -194,7 +194,7 @@ class MultiplicationModel(BaseComponent):
return
effective_radius = self.p_model.calculate_ER()
#Reset the effective_radius of s_model just before the run
- if effective_radius != None and effective_radius != NotImplemented:
+ if effective_radius is not None and effective_radius != NotImplemented:
self.s_model.setParam('radius_effective', effective_radius)
def setParam(self, name, value):
@@ -244,7 +244,7 @@ class MultiplicationModel(BaseComponent):
self.params[item] = value
return
- raise ValueError, "Model does not contain parameter %s" % name
+ raise ValueError("Model does not contain parameter %s" % name)
def _set_fixed_params(self):
diff --git a/src/sas/sascalc/fit/expression.py b/src/sas/sascalc/fit/expression.py
index 21bd9dd..f913319 100644
--- a/src/sas/sascalc/fit/expression.py
+++ b/src/sas/sascalc/fit/expression.py
@@ -42,6 +42,8 @@ is out of date::
Ideally, this interface will change
"""
+from __future__ import print_function
+
import math
import re
@@ -56,7 +58,7 @@ def _symbols(expr,symtab):
used in the expression. Symbols are only returned once even if they
occur multiple times. The return value is a set with the elements in
no particular order.
-
+
This is the first step in computing a dependency graph.
"""
matches = [m.group(0) for m in _symbol_pattern.finditer(expr)]
@@ -78,14 +80,14 @@ def _substitute(expr,mapping):
pieces += [expr[offset:start],text]
offset = end
pieces.append(expr[offset:])
-
+
# Join the pieces and return them
return "".join(pieces)
def _find_dependencies(symtab, exprs):
"""
Returns a list of pair-wise dependencies from the parameter expressions.
-
+
For example, if p3 = p1+p2, then find_dependencies([p1,p2,p3]) will
return [(p3,p1),(p3,p2)]. For base expressions without dependencies,
such as p4 = 2*pi, this should return [(p4, None)]
@@ -107,7 +109,7 @@ def _symbols_or_none(expr,symtab):
def _parameter_mapping(pairs):
"""
Find the parameter substitution we need so that expressions can
- be evaluated without having to traverse a chain of
+ be evaluated without having to traverse a chain of
model.layer.parameter.value
"""
left,right = zip(*pairs)
@@ -119,7 +121,7 @@ def _parameter_mapping(pairs):
if p is not None)
return definition, substitution
-def no_constraints():
+def no_constraints():
"""
This parameter set has no constraints between the parameters.
"""
@@ -160,12 +162,12 @@ def compile_constraints(symtab, exprs, context={}):
evaluations. Unauthenticated users should not be running this code.
Parameter names are assumed to contain only _.a-zA-Z0-9#[]
-
+
Both names are provided for inverse functions, e.g., acos and arccos.
Should try running the function to identify syntax errors before
running it in a fit.
-
+
Use help(fn) to see the code generated for the returned function fn.
dis.dis(fn) will show the corresponding python vm instructions.
"""
@@ -236,7 +238,7 @@ def order_dependencies(pairs):
independent = right - left
if independent == emptyset:
cycleset = ", ".join(str(s) for s in left)
- raise ValueError,"Cyclic dependencies amongst %s"%cycleset
+ raise ValueError("Cyclic dependencies amongst %s"%cycleset)
# The possibly resolvable items are those that depend on the independents
dependent = set([a for a,b in pairs if b in independent])
@@ -264,13 +266,13 @@ def _check(msg,pairs):
if set(n) != items or len(n) != len(items):
n.sort()
items = list(items); items.sort()
- raise Exception,"%s expect %s to contain %s for %s"%(msg,n,items,pairs)
+ raise ValueError("%s expect %s to contain %s for %s"%(msg,n,items,pairs))
for lo,hi in pairs:
if lo in n and hi in n and n.index(lo) >= n.index(hi):
- raise Exception,"%s expect %s before %s in %s for %s"%(msg,lo,hi,n,pairs)
+ raise ValueError("%s expect %s before %s in %s for %s"%(msg,lo,hi,n,pairs))
def test_deps():
- import numpy
+ import numpy as np
# Null case
_check("test empty",[])
@@ -278,37 +280,40 @@ def test_deps():
# Some dependencies
_check("test1",[(2,7),(1,5),(1,4),(2,1),(3,1),(5,6)])
_check("test1 renumbered",[(6,1),(7,3),(7,4),(6,7),(5,7),(3,2)])
- _check("test1 numpy",numpy.array([(2,7),(1,5),(1,4),(2,1),(3,1),(5,6)]))
+ _check("test1 numpy",np.array([(2,7),(1,5),(1,4),(2,1),(3,1),(5,6)]))
# No dependencies
_check("test2",[(4,1),(3,2),(8,4)])
# Cycle test
pairs = [(1,4),(4,3),(4,5),(5,1)]
- try: n = order_dependencies(pairs)
- except ValueError: pass
- else: raise Exception,"test3 expect ValueError exception for %s"%(pairs,)
+ try:
+ n = order_dependencies(pairs)
+ except ValueError:
+ pass
+ else:
+ raise ValueError("test3 expect ValueError exception for %s"%(pairs,))
# large test for gross speed check
- A = numpy.random.randint(4000,size=(1000,2))
+ A = np.random.randint(4000,size=(1000,2))
A[:,1] += 4000 # Avoid cycles
_check("test-large",A)
# depth tests
k = 200
- A = numpy.array([range(0,k),range(1,k+1)]).T
+ A = np.array([range(0,k),range(1,k+1)]).T
_check("depth-1",A)
- A = numpy.array([range(1,k+1),range(0,k)]).T
+ A = np.array([range(1,k+1),range(0,k)]).T
_check("depth-2",A)
def test_expr():
import inspect, dis
import math
-
+
symtab = {'a.b.x':1, 'a.c':2, 'a.b':3, 'b.x':4}
expr = 'a.b.x + sin(4*pi*a.c) + a.b.x/a.b'
-
+
# Check symbol lookup
assert _symbols(expr, symtab) == set([1,2,3])
@@ -354,7 +359,7 @@ def test_expr():
fn()
expected = 2*math.pi*math.sin(5/.1875) + 6
assert p2.value == expected,"Value was %s, not %s"%(p2.value,expected)
-
+
# Check empty dependency set doesn't crash
fn = compile_constraints(*world(p1,p3))
fn()
@@ -378,10 +383,10 @@ def test_expr():
fn = compile_constraints(*world(p1,p2,p3,p5),context=dict(tbl=tbl))
fn()
assert p5.value == 2.07,"Value for %s was %s"%(p5.expression,p5.value)
-
+
# Verify that we capture invalid expressions
- for expr in ['G4.cage', 'M0.cage', 'M1.G1 + *2',
+ for expr in ['G4.cage', 'M0.cage', 'M1.G1 + *2',
'piddle',
'5; import sys; print "p0wned"',
'__import__("sys").argv']:
diff --git a/src/sas/sascalc/fit/models.py b/src/sas/sascalc/fit/models.py
new file mode 100644
index 0000000..3f9b4aa
--- /dev/null
+++ b/src/sas/sascalc/fit/models.py
@@ -0,0 +1,336 @@
+"""
+ Utilities to manage models
+"""
+from __future__ import print_function
+
+import os
+import sys
+import time
+import datetime
+import logging
+import traceback
+import py_compile
+import shutil
+
+from sasmodels.sasview_model import load_custom_model, load_standard_models
+
+from sas import get_user_dir
+
+# Explicitly import from the pluginmodel module so that py2exe
+# places it in the distribution. The Model1DPlugin class is used
+# as the base class of plug-in models.
+from .pluginmodel import Model1DPlugin
+
+logger = logging.getLogger(__name__)
+
+
+PLUGIN_DIR = 'plugin_models'
+PLUGIN_LOG = os.path.join(get_user_dir(), PLUGIN_DIR, "plugins.log")
+PLUGIN_NAME_BASE = '[plug-in] '
+
+
+def plugin_log(message):
+ """
+ Log a message in a file located in the user's home directory
+ """
+ out = open(PLUGIN_LOG, 'a')
+ now = time.time()
+ stamp = datetime.datetime.fromtimestamp(now).strftime('%Y-%m-%d %H:%M:%S')
+ out.write("%s: %s\n" % (stamp, message))
+ out.close()
+
+
+def _check_plugin(model, name):
+ """
+ Do some checking before model adding plugins in the list
+
+ :param model: class model to add into the plugin list
+ :param name:name of the module plugin
+
+ :return model: model if valid model or None if not valid
+
+ """
+ #Check if the plugin is of type Model1DPlugin
+ if not issubclass(model, Model1DPlugin):
+ msg = "Plugin %s must be of type Model1DPlugin \n" % str(name)
+ plugin_log(msg)
+ return None
+ if model.__name__ != "Model":
+ msg = "Plugin %s class name must be Model \n" % str(name)
+ plugin_log(msg)
+ return None
+ try:
+ new_instance = model()
+ except Exception:
+ msg = "Plugin %s error in __init__ \n\t: %s %s\n" % (str(name),
+ str(sys.exc_type),
+ sys.exc_info()[1])
+ plugin_log(msg)
+ return None
+
+ if hasattr(new_instance, "function"):
+ try:
+ value = new_instance.function()
+ except Exception:
+ msg = "Plugin %s: error writing function \n\t :%s %s\n " % \
+ (str(name), str(sys.exc_type), sys.exc_info()[1])
+ plugin_log(msg)
+ return None
+ else:
+ msg = "Plugin %s needs a method called function \n" % str(name)
+ plugin_log(msg)
+ return None
+ return model
+
+
+def find_plugins_dir():
+ """
+ Find path of the plugins directory.
+ The plugin directory is located in the user's home directory.
+ """
+ path = os.path.join(os.path.expanduser("~"), '.sasview', PLUGIN_DIR)
+
+ # TODO: trigger initialization of plugins dir from installer or startup
+ # If the plugin directory doesn't exist, create it
+ if not os.path.isdir(path):
+ os.makedirs(path)
+ # TODO: should we be checking for new default models every time?
+ # TODO: restore support for default plugins
+ #initialize_plugins_dir(path)
+ return path
+
+
+def initialize_plugins_dir(path):
+ # TODO: There are no default plugins
+ # TODO: Default plugins directory is in sasgui, but models.py is in sascalc
+ # TODO: Move default plugins beside sample data files
+ # TODO: Should not look for defaults above the root of the sasview install
+
+ # Walk up the tree looking for default plugin_models directory
+ base = os.path.abspath(os.path.dirname(__file__))
+ for _ in range(12):
+ default_plugins_path = os.path.join(base, PLUGIN_DIR)
+ if os.path.isdir(default_plugins_path):
+ break
+ base, _ = os.path.split(base)
+ else:
+ logger.error("default plugins directory not found")
+ return
+
+ # Copy files from default plugins to the .sasview directory
+ # This may include c files, depending on the example.
+ # Note: files are never replaced, even if the default plugins are updated
+ for filename in os.listdir(default_plugins_path):
+ # skip __init__.py and all pyc files
+ if filename == "__init__.py" or filename.endswith('.pyc'):
+ continue
+ source = os.path.join(default_plugins_path, filename)
+ target = os.path.join(path, filename)
+ if os.path.isfile(source) and not os.path.isfile(target):
+ shutil.copy(source, target)
+
+
+class ReportProblem(object):
+ """
+ Class to check for problems with specific values
+ """
+ def __nonzero__(self):
+ type, value, tb = sys.exc_info()
+ if type is not None and issubclass(type, py_compile.PyCompileError):
+ print("Problem with", repr(value))
+ raise type, value, tb
+ return 1
+
+report_problem = ReportProblem()
+
+
+def compile_file(dir):
+ """
+ Compile a py file
+ """
+ try:
+ import compileall
+ compileall.compile_dir(dir=dir, ddir=dir, force=0,
+ quiet=report_problem)
+ except Exception:
+ return sys.exc_info()[1]
+ return None
+
+
+def find_plugin_models():
+ """
+ Find custom models
+ """
+ # List of plugin objects
+ plugins_dir = find_plugins_dir()
+ # Go through files in plug-in directory
+ if not os.path.isdir(plugins_dir):
+ msg = "SasView couldn't locate Model plugin folder %r." % plugins_dir
+ logger.warning(msg)
+ return {}
+
+ plugin_log("looking for models in: %s" % plugins_dir)
+ # compile_file(plugins_dir) #always recompile the folder plugin
+ logger.info("plugin model dir: %s", plugins_dir)
+
+ plugins = {}
+ for filename in os.listdir(plugins_dir):
+ name, ext = os.path.splitext(filename)
+ if ext == '.py' and not name == '__init__':
+ path = os.path.abspath(os.path.join(plugins_dir, filename))
+ try:
+ model = load_custom_model(path)
+ # TODO: add [plug-in] tag to model name in sasview_model
+ if not model.name.startswith(PLUGIN_NAME_BASE):
+ model.name = PLUGIN_NAME_BASE + model.name
+ plugins[model.name] = model
+ except Exception:
+ msg = traceback.format_exc()
+ msg += "\nwhile accessing model in %r" % path
+ plugin_log(msg)
+ logger.warning("Failed to load plugin %r. See %s for details",
+ path, PLUGIN_LOG)
+
+ return plugins
+
+
+class ModelManagerBase(object):
+ """
+ Base class for the model manager
+ """
+ #: mutable dictionary of models, continually updated to reflect the
+ #: current set of plugins
+ model_dictionary = None # type: Dict[str, Model]
+ #: constant list of standard models
+ standard_models = None # type: Dict[str, Model]
+ #: list of plugin models reset each time the plugin directory is queried
+ plugin_models = None # type: Dict[str, Model]
+ #: timestamp on the plugin directory at the last plugin update
+ last_time_dir_modified = 0 # type: int
+
+ def __init__(self):
+ # the model dictionary is allocated at the start and updated to
+ # reflect the current list of models. Be sure to clear it rather
+ # than reassign to it.
+ self.model_dictionary = {}
+
+ #Build list automagically from sasmodels package
+ self.standard_models = {model.name: model
+ for model in load_standard_models()}
+ # Look for plugins
+ self.plugins_reset()
+
+ def _is_plugin_dir_changed(self):
+ """
+ check the last time the plugin dir has changed and return true
+ is the directory was modified else return false
+ """
+ is_modified = False
+ plugin_dir = find_plugins_dir()
+ if os.path.isdir(plugin_dir):
+ mod_time = os.path.getmtime(plugin_dir)
+ if self.last_time_dir_modified != mod_time:
+ is_modified = True
+ self.last_time_dir_modified = mod_time
+
+ return is_modified
+
+ def composable_models(self):
+ """
+ return list of standard models that can be used in sum/multiply
+ """
+ # TODO: should scan plugin models in addition to standard models
+ # and update model_editor so that it doesn't add plugins to the list
+ return [model.name for model in self.standard_models.values()
+ if not model.is_multiplicity_model]
+
+ def plugins_update(self):
+ """
+ return a dictionary of model if
+ new models were added else return empty dictionary
+ """
+ return self.plugins_reset()
+ #if self._is_plugin_dir_changed():
+ # return self.plugins_reset()
+ #else:
+ # return {}
+
+ def plugins_reset(self):
+ """
+ return a dictionary of model
+ """
+ self.plugin_models = find_plugin_models()
+ self.model_dictionary.clear()
+ self.model_dictionary.update(self.standard_models)
+ self.model_dictionary.update(self.plugin_models)
+ return self.get_model_list()
+
+ def get_model_list(self):
+ """
+ return dictionary of classified models
+
+ *Structure Factors* are the structure factor models
+ *Multi-Functions* are the multiplicity models
+ *Plugin Models* are the plugin models
+
+ Note that a model can be both a plugin and a structure factor or
+ multiplicity model.
+ """
+ ## Model_list now only contains attribute lists not category list.
+ ## Eventually this should be in one master list -- read in category
+ ## list then pull those models that exist and get attributes then add
+ ## to list ..and if model does not exist remove from list as now
+ ## and update json file.
+ ##
+ ## -PDB April 26, 2014
+
+
+ # Classify models
+ structure_factors = []
+ form_factors = []
+ multiplicity_models = []
+ for model in self.model_dictionary.values():
+ # Old style models don't have is_structure_factor attribute
+ if getattr(model, 'is_structure_factor', False):
+ structure_factors.append(model)
+ if getattr(model, 'is_form_factor', False):
+ form_factors.append(model)
+ if model.is_multiplicity_model:
+ multiplicity_models.append(model)
+ plugin_models = list(self.plugin_models.values())
+
+ return {
+ "Structure Factors": structure_factors,
+ "Form Factors": form_factors,
+ "Plugin Models": plugin_models,
+ "Multi-Functions": multiplicity_models,
+ }
+
+
+class ModelManager(object):
+ """
+ manage the list of available models
+ """
+ base = None # type: ModelManagerBase()
+
+ def __init__(self):
+ if ModelManager.base is None:
+ ModelManager.base = ModelManagerBase()
+
+ def cat_model_list(self):
+ return list(self.base.standard_models.values())
+
+ def update(self):
+ return self.base.plugins_update()
+
+ def plugins_reset(self):
+ return self.base.plugins_reset()
+
+ def get_model_list(self):
+ return self.base.get_model_list()
+
+ def composable_models(self):
+ return self.base.composable_models()
+
+ def get_model_dictionary(self):
+ return self.base.model_dictionary
diff --git a/src/sas/sasgui/perspectives/fitting/pagestate.py b/src/sas/sascalc/fit/pagestate.py
similarity index 81%
rename from src/sas/sasgui/perspectives/fitting/pagestate.py
rename to src/sas/sascalc/fit/pagestate.py
index d977ce4..95ccee8 100644
--- a/src/sas/sasgui/perspectives/fitting/pagestate.py
+++ b/src/sas/sascalc/fit/pagestate.py
@@ -1,1449 +1,1379 @@
-"""
- Class that holds a fit page state
-"""
-# TODO: Refactor code so we don't need to use getattr/setattr
-################################################################################
-# This software was developed by the University of Tennessee as part of the
-# Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
-# project funded by the US National Science Foundation.
-#
-# See the license text in license.txt
-#
-# copyright 2009, University of Tennessee
-################################################################################
-import time
-import os
-import sys
-import wx
-import copy
-import logging
-import numpy
-import traceback
-
-import xml.dom.minidom
-from xml.dom.minidom import parseString
-from lxml import etree
-
-from sasmodels import convert
-import sasmodels.weights
-
-import sas.sascalc.dataloader
-from sas.sascalc.dataloader.readers.cansas_reader import Reader as CansasReader
-from sas.sascalc.dataloader.readers.cansas_reader import get_content, write_node
-from sas.sascalc.dataloader.data_info import Data2D, Collimation, Detector
-from sas.sascalc.dataloader.data_info import Process, Aperture
-
-# Information to read/write state as xml
-FITTING_NODE_NAME = 'fitting_plug_in'
-CANSAS_NS = "cansas1d/1.0"
-
-CUSTOM_MODEL = 'Plugin Models'
-CUSTOM_MODEL_OLD = 'Customized Models'
-
-LIST_OF_DATA_ATTRIBUTES = [["is_data", "is_data", "bool"],
- ["group_id", "data_group_id", "string"],
- ["data_name", "data_name", "string"],
- ["data_id", "data_id", "string"],
- ["name", "name", "string"],
- ["data_name", "data_name", "string"]]
-LIST_OF_STATE_ATTRIBUTES = [["qmin", "qmin", "float"],
- ["qmax", "qmax", "float"],
- ["npts", "npts", "float"],
- ["categorycombobox", "categorycombobox", "string"],
- ["formfactorcombobox", "formfactorcombobox",
- "string"],
- ["structurecombobox", "structurecombobox",
- "string"],
- ["multi_factor", "multi_factor", "float"],
- ["magnetic_on", "magnetic_on", "bool"],
- ["enable_smearer", "enable_smearer", "bool"],
- ["disable_smearer", "disable_smearer", "bool"],
- ["pinhole_smearer", "pinhole_smearer", "bool"],
- ["slit_smearer", "slit_smearer", "bool"],
- ["enable_disp", "enable_disp", "bool"],
- ["disable_disp", "disable_disp", "bool"],
- ["dI_noweight", "dI_noweight", "bool"],
- ["dI_didata", "dI_didata", "bool"],
- ["dI_sqrdata", "dI_sqrdata", "bool"],
- ["dI_idata", "dI_idata", "bool"],
- ["enable2D", "enable2D", "bool"],
- ["cb1", "cb1", "bool"],
- ["tcChi", "tcChi", "float"],
- ["smearer", "smearer", "float"],
- ["smear_type", "smear_type", "string"],
- ["dq_l", "dq_l", "float"],
- ["dq_r", "dq_r", "float"],
- ["dx_percent", "dx_percent", "float"],
- ["dxl", "dxl", "float"],
- ["dxw", "dxw", "float"]]
-
-LIST_OF_MODEL_ATTRIBUTES = [["values", "values"],
- ["weights", "weights"]]
-
-DISPERSION_LIST = [["disp_obj_dict", "_disp_obj_dict", "string"]]
-
-LIST_OF_STATE_PARAMETERS = [["parameters", "parameters"],
- ["str_parameters", "str_parameters"],
- ["orientation_parameters", "orientation_params"],
- ["dispersity_parameters",
- "orientation_params_disp"],
- ["fixed_param", "fixed_param"],
- ["fittable_param", "fittable_param"]]
-LIST_OF_DATA_2D_ATTR = [["xmin", "xmin", "float"],
- ["xmax", "xmax", "float"],
- ["ymin", "ymin", "float"],
- ["ymax", "ymax", "float"],
- ["_xaxis", "_xaxis", "string"],
- ["_xunit", "_xunit", "string"],
- ["_yaxis", "_yaxis", "string"],
- ["_yunit", "_yunit", "string"],
- ["_zaxis", "_zaxis", "string"],
- ["_zunit", "_zunit", "string"]]
-LIST_OF_DATA_2D_VALUES = [["qx_data", "qx_data", "float"],
- ["qy_data", "qy_data", "float"],
- ["dqx_data", "dqx_data", "float"],
- ["dqy_data", "dqy_data", "float"],
- ["data", "data", "float"],
- ["q_data", "q_data", "float"],
- ["err_data", "err_data", "float"],
- ["mask", "mask", "bool"]]
-
-
-def parse_entry_helper(node, item):
- """
- Create a numpy list from value extrated from the node
-
- :param node: node from each the value is stored
- :param item: list name of three strings.the two first are name of data
- attribute and the third one is the type of the value of that
- attribute. type can be string, float, bool, etc.
-
- : return: numpy array
- """
- if node is not None:
- if item[2] == "string":
- return str(node.get(item[0]).strip())
- elif item[2] == "bool":
- try:
- return node.get(item[0]).strip() == "True"
- except Exception:
- return None
- else:
- try:
- return float(node.get(item[0]))
- except Exception:
- return None
-
-
-class PageState(object):
- """
- Contains information to reconstruct a page of the fitpanel.
- """
- def __init__(self, parent=None, model=None, data=None):
- """
- Initialize the current state
-
- :param model: a selected model within a page
- :param data:
-
- """
- self.file = None
- # Time of state creation
- self.timestamp = time.time()
- # Data member to store the dispersion object created
- self._disp_obj_dict = {}
- # ------------------------
- # Data used for fitting
- self.data = data
- # model data
- self.theory_data = None
- # Is 2D
- self.is_2D = False
- self.images = None
-
- # save additional information on data that dataloader.reader
- # does not read
- self.is_data = None
- self.data_name = ""
-
- if self.data is not None:
- self.data_name = self.data.name
- self.data_id = None
- if self.data is not None and hasattr(self.data, "id"):
- self.data_id = self.data.id
- self.data_group_id = None
- if self.data is not None and hasattr(self.data, "group_id"):
- self.data_group_id = self.data.group_id
-
- # reset True change the state of existing button
- self.reset = False
-
- # flag to allow data2D plot
- self.enable2D = False
- # model on which the fit would be performed
- self.model = model
- self.m_name = None
- # list of process done to model
- self.process = []
- # fit page manager
- self.manager = None
- # Store the parent of this panel parent
- # For this application fitpanel is the parent
- self.parent = parent
- # Event_owner is the owner of model event
- self.event_owner = None
- # page name
- self.page_name = ""
- # Contains link between model, its parameters, and panel organization
- self.parameters = []
- # String parameter list that can not be fitted
- self.str_parameters = []
- # Contains list of parameters that cannot be fitted and reference to
- # panel objects
- self.fixed_param = []
- # Contains list of parameters with dispersity and reference to
- # panel objects
- self.fittable_param = []
- # orientation parameters
- self.orientation_params = []
- # orientation parameters for gaussian dispersity
- self.orientation_params_disp = []
- # smearer info
- self.smearer = None
- self.smear_type = None
- self.dq_l = None
- self.dq_r = None
- self.dx_percent = None
- self.dx_old = False
- self.dxl = None
- self.dxw = None
- # list of dispersion parameters
- self.disp_list = []
- if self.model is not None:
- self.disp_list = self.model.getDispParamList()
-
- self.disp_cb_dict = {}
- self.values = {}
- self.weights = {}
-
- # contains link between a model and selected parameters to fit
- self.param_toFit = []
- # dictionary of model type and model class
- self.model_list_box = None
- # save the state of the context menu
- self.saved_states = {}
- # save selection of combobox
- self.formfactorcombobox = None
- self.categorycombobox = None
- self.structurecombobox = None
-
- # radio box to select type of model
- # self.shape_rbutton = False
- # self.shape_indep_rbutton = False
- # self.struct_rbutton = False
- # self.plugin_rbutton = False
- # the indice of the current selection
- self.disp_box = 0
- # Qrange
- # Q range
- self.qmin = 0.001
- self.qmax = 0.1
- # reset data range
- self.qmax_x = None
- self.qmin_x = None
-
- self.npts = None
- self.name = ""
- self.multi_factor = None
- self.magnetic_on = False
- # enable smearering state
- self.enable_smearer = False
- self.disable_smearer = True
- self.pinhole_smearer = False
- self.slit_smearer = False
- # weighting options
- self.dI_noweight = False
- self.dI_didata = True
- self.dI_sqrdata = False
- self.dI_idata = False
- # disperity selection
- self.enable_disp = False
- self.disable_disp = True
-
- # state of selected all check button
- self.cb1 = False
- # store value of chisqr
- self.tcChi = None
- self.version = (1,0,0)
-
- def clone(self):
- """
- Create a new copy of the current object
- """
- model = None
- if self.model is not None:
- model = self.model.clone()
- model.name = self.model.name
- obj = PageState(self.parent, model=model)
- obj.file = copy.deepcopy(self.file)
- obj.data = copy.deepcopy(self.data)
- if self.data is not None:
- self.data_name = self.data.name
- obj.data_name = self.data_name
- obj.is_data = self.is_data
- obj.model_list_box = copy.deepcopy(self.model_list_box)
-
- obj.categorycombobox = self.categorycombobox
- obj.formfactorcombobox = self.formfactorcombobox
- obj.structurecombobox = self.structurecombobox
-
- # obj.shape_rbutton = self.shape_rbutton
- # obj.shape_indep_rbutton = self.shape_indep_rbutton
- # obj.struct_rbutton = self.struct_rbutton
- # obj.plugin_rbutton = self.plugin_rbutton
-
- obj.manager = self.manager
- obj.event_owner = self.event_owner
- obj.disp_list = copy.deepcopy(self.disp_list)
-
- obj.enable2D = copy.deepcopy(self.enable2D)
- obj.parameters = copy.deepcopy(self.parameters)
- obj.str_parameters = copy.deepcopy(self.str_parameters)
- obj.fixed_param = copy.deepcopy(self.fixed_param)
- obj.fittable_param = copy.deepcopy(self.fittable_param)
- obj.orientation_params = copy.deepcopy(self.orientation_params)
- obj.orientation_params_disp = \
- copy.deepcopy(self.orientation_params_disp)
- obj.enable_disp = copy.deepcopy(self.enable_disp)
- obj.disable_disp = copy.deepcopy(self.disable_disp)
- obj.tcChi = self.tcChi
-
- if len(self._disp_obj_dict) > 0:
- for k, v in self._disp_obj_dict.iteritems():
- obj._disp_obj_dict[k] = v
- if len(self.disp_cb_dict) > 0:
- for k, v in self.disp_cb_dict.iteritems():
- obj.disp_cb_dict[k] = v
- if len(self.values) > 0:
- for k, v in self.values.iteritems():
- obj.values[k] = v
- if len(self.weights) > 0:
- for k, v in self.weights.iteritems():
- obj.weights[k] = v
- obj.enable_smearer = copy.deepcopy(self.enable_smearer)
- obj.disable_smearer = copy.deepcopy(self.disable_smearer)
- obj.pinhole_smearer = copy.deepcopy(self.pinhole_smearer)
- obj.slit_smearer = copy.deepcopy(self.slit_smearer)
- obj.smear_type = copy.deepcopy(self.smear_type)
- obj.dI_noweight = copy.deepcopy(self.dI_noweight)
- obj.dI_didata = copy.deepcopy(self.dI_didata)
- obj.dI_sqrdata = copy.deepcopy(self.dI_sqrdata)
- obj.dI_idata = copy.deepcopy(self.dI_idata)
- obj.dq_l = copy.deepcopy(self.dq_l)
- obj.dq_r = copy.deepcopy(self.dq_r)
- obj.dx_percent = copy.deepcopy(self.dx_percent)
- obj.dx_old = copy.deepcopy(self.dx_old)
- obj.dxl = copy.deepcopy(self.dxl)
- obj.dxw = copy.deepcopy(self.dxw)
- obj.disp_box = copy.deepcopy(self.disp_box)
- obj.qmin = copy.deepcopy(self.qmin)
- obj.qmax = copy.deepcopy(self.qmax)
- obj.multi_factor = self.multi_factor
- obj.magnetic_on = self.magnetic_on
- obj.npts = copy.deepcopy(self.npts)
- obj.cb1 = copy.deepcopy(self.cb1)
- obj.smearer = copy.deepcopy(self.smearer)
- obj.version = copy.deepcopy(self.version)
-
- for name, state in self.saved_states.iteritems():
- copy_name = copy.deepcopy(name)
- copy_state = state.clone()
- obj.saved_states[copy_name] = copy_state
- return obj
-
- def _old_first_model(self):
- """
- Handle save states from 4.0.1 and before where the first item in the
- selection boxes of category, formfactor and structurefactor were not
- saved.
- :return: None
- """
- if self.categorycombobox == CUSTOM_MODEL_OLD:
- self.categorycombobox = CUSTOM_MODEL
- if self.formfactorcombobox == '':
- FIRST_FORM = {
- 'Shapes' : 'BCCrystalModel',
- 'Uncategorized' : 'LineModel',
- 'StructureFactor' : 'HardsphereStructure',
- 'Ellipsoid' : 'core_shell_ellipsoid',
- 'Lamellae' : 'lamellar',
- 'Paracrystal' : 'bcc_paracrystal',
- 'Parallelepiped' : 'core_shell_parallelepiped',
- 'Shape Independent' : 'be_polyelectrolyte',
- 'Sphere' : 'adsorbed_layer',
- 'Structure Factor' : 'hardsphere',
- CUSTOM_MODEL : ''
- }
- if self.categorycombobox == '':
- if len(self.parameters) == 3:
- self.categorycombobox = "Shape-Independent"
- self.formfactorcombobox = 'PowerLawAbsModel'
- elif len(self.parameters) == 9:
- self.categorycombobox = 'Cylinder'
- self.formfactorcombobox = 'barbell'
- else:
- msg = "Save state does not have enough information to load"
- msg += " the all of the data."
- logging.warning(msg=msg)
- else:
- self.formfactorcombobox = FIRST_FORM[self.categorycombobox]
-
- @staticmethod
- def param_remap_to_sasmodels_convert(params, is_string=False):
- """
- Remaps the parameters for sasmodels conversion
-
- :param params: list of parameters (likely self.parameters)
- :return: remapped dictionary of parameters
- """
- p = dict()
- for fittable, name, value, _, uncert, lower, upper, units in params:
- if not value:
- value = numpy.nan
- if not uncert or uncert[1] == '' or uncert[1] == 'None':
- uncert[0] = False
- uncert[1] = numpy.nan
- if not upper or upper[1] == '' or upper[1] == 'None':
- upper[0] = False
- upper[1] = numpy.nan
- if not lower or lower[1] == '' or lower[1] == 'None':
- lower[0] = False
- lower[1] = numpy.nan
- if is_string:
- p[name] = str(value)
- else:
- p[name] = float(value)
- p[name + ".fittable"] = bool(fittable)
- p[name + ".std"] = float(uncert[1])
- p[name + ".upper"] = float(upper[1])
- p[name + ".lower"] = float(lower[1])
- p[name + ".units"] = units
- return p
-
- @staticmethod
- def param_remap_from_sasmodels_convert(params):
- """
- Converts {name : value} map back to [] param list
- :param params: parameter map returned from sasmodels
- :return: None
- """
- p_map = []
- for name, info in params.iteritems():
- if ".fittable" in name or ".std" in name or ".upper" in name or \
- ".lower" in name or ".units" in name:
- pass
- else:
- fittable = params.get(name + ".fittable", True)
- std = params.get(name + ".std", '0.0')
- upper = params.get(name + ".upper", 'inf')
- lower = params.get(name + ".lower", '-inf')
- units = params.get(name + ".units")
- if std is not None and std is not numpy.nan:
- std = [True, str(std)]
- else:
- std = [False, '']
- if lower is not None and lower is not numpy.nan:
- lower = [True, str(lower)]
- else:
- lower = [True, '-inf']
- if upper is not None and upper is not numpy.nan:
- upper = [True, str(upper)]
- else:
- upper = [True, 'inf']
- param_list = [bool(fittable), str(name), str(info),
- "+/-", std, lower, upper, str(units)]
- p_map.append(param_list)
- return p_map
-
- def _convert_to_sasmodels(self):
- """
- Convert parameters to a form usable by sasmodels converter
-
- :return: None
- """
- # Create conversion dictionary to send to sasmodels
- self._old_first_model()
- p = self.param_remap_to_sasmodels_convert(self.parameters)
- structurefactor, params = convert.convert_model(self.structurecombobox,
- p, False, self.version)
- formfactor, params = convert.convert_model(self.formfactorcombobox,
- params, False, self.version)
- if len(self.str_parameters) > 0:
- str_pars = self.param_remap_to_sasmodels_convert(
- self.str_parameters, True)
- formfactor, str_params = convert.convert_model(
- self.formfactorcombobox, str_pars, False, self.version)
- for key, value in str_params.iteritems():
- params[key] = value
-
- if self.formfactorcombobox == 'SphericalSLDModel':
- self.multi_factor += 1
- self.formfactorcombobox = formfactor
- self.structurecombobox = structurefactor
- self.parameters = []
- self.parameters = self.param_remap_from_sasmodels_convert(params)
-
- def _repr_helper(self, list, rep):
- """
- Helper method to print a state
- """
- for item in list:
- rep += "parameter name: %s \n" % str(item[1])
- rep += "value: %s\n" % str(item[2])
- rep += "selected: %s\n" % str(item[0])
- rep += "error displayed : %s \n" % str(item[4][0])
- rep += "error value:%s \n" % str(item[4][1])
- rep += "minimum displayed : %s \n" % str(item[5][0])
- rep += "minimum value : %s \n" % str(item[5][1])
- rep += "maximum displayed : %s \n" % str(item[6][0])
- rep += "maximum value : %s \n" % str(item[6][1])
- rep += "parameter unit: %s\n\n" % str(item[7])
- return rep
-
- def __repr__(self):
- """
- output string for printing
- """
- rep = "\nState name: %s\n" % self.file
- t = time.localtime(self.timestamp)
- time_str = time.strftime("%b %d %Y %H;%M;%S ", t)
-
- rep += "State created: %s\n" % time_str
- rep += "State form factor combobox selection: %s\n" % \
- self.formfactorcombobox
- rep += "State structure factor combobox selection: %s\n" % \
- self.structurecombobox
- rep += "is data : %s\n" % self.is_data
- rep += "data's name : %s\n" % self.data_name
- rep += "data's id : %s\n" % self.data_id
- if self.model is not None:
- m_name = self.model.__class__.__name__
- if m_name == 'Model':
- m_name = self.m_name
- rep += "model name : %s\n" % m_name
- else:
- rep += "model name : None\n"
- rep += "multi_factor : %s\n" % str(self.multi_factor)
- rep += "magnetic_on : %s\n" % str(self.magnetic_on)
- rep += "model type (Category) selected: %s\n" % self.categorycombobox
- rep += "data : %s\n" % str(self.data)
- rep += "Plotting Range: min: %s, max: %s, steps: %s\n" % \
- (str(self.qmin), str(self.qmax), str(self.npts))
- rep += "Dispersion selection : %s\n" % str(self.disp_box)
- rep += "Smearing enable : %s\n" % str(self.enable_smearer)
- rep += "Smearing disable : %s\n" % str(self.disable_smearer)
- rep += "Pinhole smearer enable : %s\n" % str(self.pinhole_smearer)
- rep += "Slit smearer enable : %s\n" % str(self.slit_smearer)
- rep += "Dispersity enable : %s\n" % str(self.enable_disp)
- rep += "Dispersity disable : %s\n" % str(self.disable_disp)
- rep += "Slit smearer enable: %s\n" % str(self.slit_smearer)
-
- rep += "dI_noweight : %s\n" % str(self.dI_noweight)
- rep += "dI_didata : %s\n" % str(self.dI_didata)
- rep += "dI_sqrdata : %s\n" % str(self.dI_sqrdata)
- rep += "dI_idata : %s\n" % str(self.dI_idata)
-
- rep += "2D enable : %s\n" % str(self.enable2D)
- rep += "All parameters checkbox selected: %s\n" % self.cb1
- rep += "Value of Chisqr : %s\n" % str(self.tcChi)
- rep += "Smear object : %s\n" % self.smearer
- rep += "Smear type : %s\n" % self.smear_type
- rep += "dq_l : %s\n" % self.dq_l
- rep += "dq_r : %s\n" % self.dq_r
- rep += "dx_percent : %s\n" % str(self.dx_percent)
- rep += "dxl : %s\n" % str(self.dxl)
- rep += "dxw : %s\n" % str(self.dxw)
- rep += "model : %s\n\n" % str(self.model)
- temp_parameters = []
- temp_fittable_param = []
- if self.data.__class__.__name__ == "Data2D":
- self.is_2D = True
- else:
- self.is_2D = False
- if self.data is not None:
- if not self.is_2D:
- for item in self.parameters:
- if item not in self.orientation_params:
- temp_parameters.append(item)
- for item in self.fittable_param:
- if item not in self.orientation_params_disp:
- temp_fittable_param.append(item)
- else:
- temp_parameters = self.parameters
- temp_fittable_param = self.fittable_param
-
- rep += "number parameters(self.parameters): %s\n" % \
- len(temp_parameters)
- rep = self._repr_helper(list=temp_parameters, rep=rep)
- rep += "number str_parameters(self.str_parameters): %s\n" % \
- len(self.str_parameters)
- rep = self._repr_helper(list=self.str_parameters, rep=rep)
- rep += "number fittable_param(self.fittable_param): %s\n" % \
- len(temp_fittable_param)
- rep = self._repr_helper(list=temp_fittable_param, rep=rep)
- return rep
-
- def set_report_string(self):
- """
- Get the values (strings) from __str__ for report
- """
- # Dictionary of the report strings
- repo_time = ""
- model_name = ""
- title = ""
- title_name = ""
- file_name = ""
- param_string = ""
- paramval_string = ""
- chi2_string = ""
- q_range = ""
- strings = self.__repr__()
- lines = strings.split('\n')
-
- # get all string values from __str__()
- for line in lines:
- value = ""
- content = line.split(":")
- name = content[0]
- try:
- value = content[1]
- except Exception:
- msg = "Report string expected 'name: value' but got %r" % line
- logging.error(msg)
- if name.count("State created"):
- repo_time = "" + value
- if name.count("parameter name"):
- val_name = value.split(".")
- if len(val_name) > 1:
- if val_name[1].count("width"):
- param_string += value + ','
- else:
- continue
- else:
- param_string += value + ','
- if name == "value":
- param_string += value + ','
- fixed_parameter = False
- if name == "selected":
- if value == u' False':
- fixed_parameter = True
- if name == "error value":
- if fixed_parameter:
- param_string += '(fixed),'
- else:
- param_string += value + ','
- if name == "parameter unit":
- param_string += value + ':'
- if name == "Value of Chisqr ":
- chi2 = ("Chi2/Npts = " + value)
- chi2_string = CENTRE % chi2
- if name == "Title":
- if len(value.strip()) == 0:
- continue
- title = value + " [" + repo_time + "]"
- title_name = HEADER % title
- if name == "data ":
- try:
- file_value = ("File name:" + content[2])
- file_name = CENTRE % file_value
- if len(title) == 0:
- title = content[2] + " [" + repo_time + "]"
- title_name = HEADER % title
- except Exception:
- msg = "While parsing 'data: ...'\n"
- logging.error(msg + traceback.format_exc())
- if name == "model name ":
- try:
- modelname = "Model name:" + content[1]
- except:
- modelname = "Model name:" + " NAN"
- model_name = CENTRE % modelname
-
- if name == "Plotting Range":
- try:
- q_range = content[1] + " = " + content[2] \
- + " = " + content[3].split(",")[0]
- q_name = ("Q Range: " + q_range)
- q_range = CENTRE % q_name
- except Exception:
- msg = "While parsing 'Plotting Range: ...'\n"
- logging.error(msg + traceback.format_exc())
- paramval = ""
- for lines in param_string.split(":"):
- line = lines.split(",")
- if len(lines) > 0:
- param = line[0]
- param += " = " + line[1]
- if len(line[2].split()) > 0 and not line[2].count("None"):
- param += " +- " + line[2]
- if len(line[3].split()) > 0 and not line[3].count("None"):
- param += " " + line[3]
- if not paramval.count(param):
- paramval += param + "\n"
- paramval_string += CENTRE % param + "\n"
-
- text_string = "\n\n\n%s\n\n%s\n%s\n%s\n\n%s" % \
- (title, file, q_name, chi2, paramval)
-
- title_name = self._check_html_format(title_name)
- file_name = self._check_html_format(file_name)
- title = self._check_html_format(title)
-
- html_string = title_name + "\n" + file_name + \
- "\n" + model_name + \
- "\n" + q_range + \
- "\n" + chi2_string + \
- "\n" + ELINE + \
- "\n" + paramval_string + \
- "\n" + ELINE + \
- "\n" + FEET_1 % title + \
- "\n" + FEET_2
-
- return html_string, text_string, title
-
- def _check_html_format(self, name):
- """
- Check string '%' for html format
- """
- if name.count('%'):
- name = name.replace('%', '%')
-
- return name
-
- def report(self, figs=None, canvases=None):
- """
- Invoke report dialog panel
-
- : param figs: list of pylab figures [list]
- """
- from sas.sasgui.perspectives.fitting.report_dialog import ReportDialog
- # get the strings for report
- html_str, text_str, title = self.set_report_string()
- # Allow 2 figures to append
- if len(figs) == 1:
- add_str = FEET_3
- elif len(figs) == 2:
- add_str = ELINE
- add_str += FEET_2 % ("%s")
- add_str += ELINE
- add_str += FEET_3
- elif len(figs) > 2:
- add_str = ELINE
- add_str += FEET_2 % ("%s")
- add_str += ELINE
- add_str += FEET_2 % ("%s")
- add_str += ELINE
- add_str += FEET_3
- else:
- add_str = ""
-
- # final report html strings
- report_str = html_str % ("%s") + add_str
-
- # make plot image
- images = self.set_plot_state(figs, canvases)
- report_list = [report_str, text_str, images]
- dialog = ReportDialog(report_list, None, wx.ID_ANY, "")
- dialog.Show()
-
- def _to_xml_helper(self, thelist, element, newdoc):
- """
- Helper method to create xml file for saving state
- """
- for item in thelist:
- sub_element = newdoc.createElement('parameter')
- sub_element.setAttribute('name', str(item[1]))
- sub_element.setAttribute('value', str(item[2]))
- sub_element.setAttribute('selected_to_fit', str(item[0]))
- sub_element.setAttribute('error_displayed', str(item[4][0]))
- sub_element.setAttribute('error_value', str(item[4][1]))
- sub_element.setAttribute('minimum_displayed', str(item[5][0]))
- sub_element.setAttribute('minimum_value', str(item[5][1]))
- sub_element.setAttribute('maximum_displayed', str(item[6][0]))
- sub_element.setAttribute('maximum_value', str(item[6][1]))
- sub_element.setAttribute('unit', str(item[7]))
- element.appendChild(sub_element)
-
- def to_xml(self, file="fitting_state.fitv", doc=None,
- entry_node=None, batch_fit_state=None):
- """
- Writes the state of the fit panel to file, as XML.
-
- Compatible with standalone writing, or appending to an
- already existing XML document. In that case, the XML document is
- required. An optional entry node in the XML document may also be given.
-
- :param file: file to write to
- :param doc: XML document object [optional]
- :param entry_node: XML node within the XML document at which we
- will append the data [optional]
- :param batch_fit_state: simultaneous fit state
- """
- from xml.dom.minidom import getDOMImplementation
-
- # Check whether we have to write a standalone XML file
- if doc is None:
- impl = getDOMImplementation()
- doc_type = impl.createDocumentType(FITTING_NODE_NAME, "1.0", "1.0")
- newdoc = impl.createDocument(None, FITTING_NODE_NAME, doc_type)
- top_element = newdoc.documentElement
- else:
- # We are appending to an existing document
- newdoc = doc
- try:
- top_element = newdoc.createElement(FITTING_NODE_NAME)
- except:
- string = etree.tostring(doc, pretty_print=True)
- newdoc = parseString(string)
- top_element = newdoc.createElement(FITTING_NODE_NAME)
- if entry_node is None:
- newdoc.documentElement.appendChild(top_element)
- else:
- try:
- entry_node.appendChild(top_element)
- except:
- node_name = entry_node.tag
- node_list = newdoc.getElementsByTagName(node_name)
- entry_node = node_list.item(0)
- entry_node.appendChild(top_element)
-
- attr = newdoc.createAttribute("version")
- from sas import sasview
- attr.nodeValue = sasview.__version__
- # attr.nodeValue = '1.0'
- top_element.setAttributeNode(attr)
-
- # File name
- element = newdoc.createElement("filename")
- if self.file is not None:
- element.appendChild(newdoc.createTextNode(str(self.file)))
- else:
- element.appendChild(newdoc.createTextNode(str(file)))
- top_element.appendChild(element)
-
- element = newdoc.createElement("timestamp")
- element.appendChild(newdoc.createTextNode(time.ctime(self.timestamp)))
- attr = newdoc.createAttribute("epoch")
- attr.nodeValue = str(self.timestamp)
- element.setAttributeNode(attr)
- top_element.appendChild(element)
-
- # Inputs
- inputs = newdoc.createElement("Attributes")
- top_element.appendChild(inputs)
-
- if self.data is not None and hasattr(self.data, "group_id"):
- self.data_group_id = self.data.group_id
- if self.data is not None and hasattr(self.data, "is_data"):
- self.is_data = self.data.is_data
- if self.data is not None:
- self.data_name = self.data.name
- if self.data is not None and hasattr(self.data, "id"):
- self.data_id = self.data.id
-
- for item in LIST_OF_DATA_ATTRIBUTES:
- element = newdoc.createElement(item[0])
- element.setAttribute(item[0], str(getattr(self, item[1])))
- inputs.appendChild(element)
-
- for item in LIST_OF_STATE_ATTRIBUTES:
- element = newdoc.createElement(item[0])
- element.setAttribute(item[0], str(getattr(self, item[1])))
- inputs.appendChild(element)
-
- # For self.values ={ disp_param_name: [vals,...],...}
- # and for self.weights ={ disp_param_name: [weights,...],...}
- for item in LIST_OF_MODEL_ATTRIBUTES:
- element = newdoc.createElement(item[0])
- value_list = getattr(self, item[1])
- for key, value in value_list.iteritems():
- sub_element = newdoc.createElement(key)
- sub_element.setAttribute('name', str(key))
- for val in value:
- sub_element.appendChild(newdoc.createTextNode(str(val)))
-
- element.appendChild(sub_element)
- inputs.appendChild(element)
-
- # Create doc for the dictionary of self._disp_obj_dic
- for tagname, varname, tagtype in DISPERSION_LIST:
- element = newdoc.createElement(tagname)
- value_list = getattr(self, varname)
- for key, value in value_list.iteritems():
- sub_element = newdoc.createElement(key)
- sub_element.setAttribute('name', str(key))
- sub_element.setAttribute('value', str(value))
- element.appendChild(sub_element)
- inputs.appendChild(element)
-
- for item in LIST_OF_STATE_PARAMETERS:
- element = newdoc.createElement(item[0])
- self._to_xml_helper(thelist=getattr(self, item[1]),
- element=element, newdoc=newdoc)
- inputs.appendChild(element)
-
- # Combined and Simultaneous Fit Parameters
- if batch_fit_state is not None:
- batch_combo = newdoc.createElement('simultaneous_fit')
- top_element.appendChild(batch_combo)
-
- # Simultaneous Fit Number For Linking Later
- element = newdoc.createElement('sim_fit_number')
- element.setAttribute('fit_number', str(batch_fit_state.fit_page_no))
- batch_combo.appendChild(element)
-
- # Save constraints
- constraints = newdoc.createElement('constraints')
- batch_combo.appendChild(constraints)
- for constraint in batch_fit_state.constraints_list:
- if constraint.model_cbox.GetValue() != "":
- # model_cbox, param_cbox, egal_txt, constraint,
- # btRemove, sizer
- doc_cons = newdoc.createElement('constraint')
- doc_cons.setAttribute('model_cbox',
- str(constraint.model_cbox.GetValue()))
- doc_cons.setAttribute('param_cbox',
- str(constraint.param_cbox.GetValue()))
- doc_cons.setAttribute('egal_txt',
- str(constraint.egal_txt.GetLabel()))
- doc_cons.setAttribute('constraint',
- str(constraint.constraint.GetValue()))
- constraints.appendChild(doc_cons)
-
- # Save all models
- models = newdoc.createElement('model_list')
- batch_combo.appendChild(models)
- for model in batch_fit_state.model_list:
- doc_model = newdoc.createElement('model_list_item')
- doc_model.setAttribute('checked', str(model[0].GetValue()))
- keys = model[1].keys()
- doc_model.setAttribute('name', str(keys[0]))
- values = model[1].get(keys[0])
- doc_model.setAttribute('fit_number', str(model[2]))
- doc_model.setAttribute('fit_page_source', str(model[3]))
- doc_model.setAttribute('model_name', str(values.model.id))
- models.appendChild(doc_model)
-
- # Select All Checkbox
- element = newdoc.createElement('select_all')
- if batch_fit_state.select_all:
- element.setAttribute('checked', 'True')
- else:
- element.setAttribute('checked', 'False')
- batch_combo.appendChild(element)
-
- # Save the file
- if doc is None:
- fd = open(file, 'w')
- fd.write(newdoc.toprettyxml())
- fd.close()
- return None
- else:
- return newdoc
-
- def _from_xml_helper(self, node, list):
- """
- Helper function to write state to xml
- """
- for item in node:
- try:
- name = item.get('name')
- except:
- name = None
- try:
- value = item.get('value')
- except:
- value = None
- try:
- selected_to_fit = (item.get('selected_to_fit') == "True")
- except:
- selected_to_fit = None
- try:
- error_displayed = (item.get('error_displayed') == "True")
- except:
- error_displayed = None
- try:
- error_value = item.get('error_value')
- except:
- error_value = None
- try:
- minimum_displayed = (item.get('minimum_displayed') == "True")
- except:
- minimum_displayed = None
- try:
- minimum_value = item.get('minimum_value')
- except:
- minimum_value = None
- try:
- maximum_displayed = (item.get('maximum_displayed') == "True")
- except:
- maximum_displayed = None
- try:
- maximum_value = item.get('maximum_value')
- except:
- maximum_value = None
- try:
- unit = item.get('unit')
- except:
- unit = None
- list.append([selected_to_fit, name, value, "+/-",
- [error_displayed, error_value],
- [minimum_displayed, minimum_value],
- [maximum_displayed, maximum_value], unit])
-
- def from_xml(self, file=None, node=None):
- """
- Load fitting state from a file
-
- :param file: .fitv file
- :param node: node of a XML document to read from
- """
- if file is not None:
- msg = "PageState no longer supports non-CanSAS"
- msg += " format for fitting files"
- raise RuntimeError, msg
-
- if node.get('version'):
- # Get the version for model conversion purposes
- self.version = tuple(int(e) for e in
- str.split(node.get('version'), "."))
- # The tuple must be at least 3 items long
- while len(self.version) < 3:
- ver_list = list(self.version)
- ver_list.append(0)
- self.version = tuple(ver_list)
-
- # Get file name
- entry = get_content('ns:filename', node)
- if entry is not None:
- self.file = entry.text.strip()
-
- # Get time stamp
- entry = get_content('ns:timestamp', node)
- if entry is not None and entry.get('epoch'):
- try:
- self.timestamp = float(entry.get('epoch'))
- except:
- msg = "PageState.fromXML: Could not"
- msg += " read timestamp\n %s" % sys.exc_value
- logging.error(msg)
-
- if entry is not None:
- # Parse fitting attributes
- entry = get_content('ns:Attributes', node)
- for item in LIST_OF_DATA_ATTRIBUTES:
- node = get_content('ns:%s' % item[0], entry)
- setattr(self, item[0], parse_entry_helper(node, item))
-
- dx_old_node = get_content('ns:%s' % 'dx_min', entry)
- for item in LIST_OF_STATE_ATTRIBUTES:
- if item[0] == "dx_percent" and dx_old_node is not None:
- dxmin = ["dx_min", "dx_min", "float"]
- setattr(self, item[0], parse_entry_helper(dx_old_node,
- dxmin))
- self.dx_old = True
- else:
- node = get_content('ns:%s' % item[0], entry)
- setattr(self, item[0], parse_entry_helper(node, item))
-
- for item in LIST_OF_STATE_PARAMETERS:
- node = get_content("ns:%s" % item[0], entry)
- self._from_xml_helper(node=node,
- list=getattr(self, item[1]))
-
- # Recover _disp_obj_dict from xml file
- self._disp_obj_dict = {}
- for tagname, varname, tagtype in DISPERSION_LIST:
- node = get_content("ns:%s" % tagname, entry)
- for attr in node:
- parameter = str(attr.get('name'))
- value = attr.get('value')
- if value.startswith("<"):
- try:
- # <path.to.NamedDistribution object/instance...>
- cls_name = value[1:].split()[0].split('.')[-1]
- cls = getattr(sasmodels.weights, cls_name)
- value = cls.type
- except Exception:
- base = "unable to load distribution %r for %s"
- logging.error(base % (value, parameter))
- continue
- _disp_obj_dict = getattr(self, varname)
- _disp_obj_dict[parameter] = value
-
- # get self.values and self.weights dic. if exists
- for tagname, varname in LIST_OF_MODEL_ATTRIBUTES:
- node = get_content("ns:%s" % tagname, entry)
- dic = {}
- value_list = []
- for par in node:
- name = par.get('name')
- values = par.text.split()
- # Get lines only with numbers
- for line in values:
- try:
- val = float(line)
- value_list.append(val)
- except Exception:
- # pass if line is empty (it happens)
- msg = ("Error reading %r from %s %s\n"
- % (line, tagname, name))
- logging.error(msg + traceback.format_exc())
- dic[name] = numpy.array(value_list)
- setattr(self, varname, dic)
-
- def set_plot_state(self, figs, canvases):
- """
- Build image state that wx.html understand
- by plotting, putting it into wx.FileSystem image object
-
- """
- images = []
-
- # Reset memory
- self.imgRAM = None
- wx.MemoryFSHandler()
-
- # For no figures in the list, prepare empty plot
- if figs is None or len(figs) == 0:
- figs = [None]
-
- # Loop over the list of figures
- # use wx.MemoryFSHandler
- self.imgRAM = wx.MemoryFSHandler()
- for fig in figs:
- if fig is not None:
- ind = figs.index(fig)
- canvas = canvases[ind]
-
- # store the image in wx.FileSystem Object
- wx.FileSystem.AddHandler(wx.MemoryFSHandler())
-
- # index of the fig
- ind = figs.index(fig)
-
- # AddFile, image can be retrieved with 'memory:filename'
- self.imgRAM.AddFile('img_fit%s.png' % ind,
- canvas.bitmap, wx.BITMAP_TYPE_PNG)
-
- # append figs
- images.append(fig)
-
- return images
-
-
-class Reader(CansasReader):
- """
- Class to load a .fitv fitting file
- """
- # File type
- type_name = "Fitting"
-
- # Wildcards
- type = ["Fitting files (*.fitv)|*.fitv"
- "SASView file (*.svs)|*.svs"]
- # List of allowed extensions
- ext = ['.fitv', '.FITV', '.svs', 'SVS']
-
- def __init__(self, call_back=None, cansas=True):
- CansasReader.__init__(self)
- """
- Initialize the call-back method to be called
- after we load a file
-
- :param call_back: call-back method
- :param cansas: True = files will be written/read in CanSAS format
- False = write CanSAS format
-
- """
- # Call back method to be executed after a file is read
- self.call_back = call_back
- # CanSAS format flag
- self.cansas = cansas
- self.state = None
- # batch fitting params for saving
- self.batchfit_params = []
-
- def get_state(self):
- return self.state
-
- def read(self, path):
- """
- Load a new P(r) inversion state from file
-
- :param path: file path
-
- """
- if self.cansas:
- return self._read_cansas(path)
-
- def _parse_state(self, entry):
- """
- Read a fit result from an XML node
-
- :param entry: XML node to read from
- :return: PageState object
- """
- # Create an empty state
- state = None
- # Locate the P(r) node
- try:
- nodes = entry.xpath('ns:%s' % FITTING_NODE_NAME,
- namespaces={'ns': CANSAS_NS})
- if nodes:
- # Create an empty state
- state = PageState()
- state.from_xml(node=nodes[0])
-
- except:
- logging.info("XML document does not contain fitting information.\n"
- + traceback.format_exc())
-
- return state
-
- def _parse_simfit_state(self, entry):
- """
- Parses the saved data for a simultaneous fit
- :param entry: XML object to read from
- :return: XML object for a simultaneous fit or None
- """
- nodes = entry.xpath('ns:%s' % FITTING_NODE_NAME,
- namespaces={'ns': CANSAS_NS})
- if nodes:
- simfitstate = nodes[0].xpath('ns:simultaneous_fit',
- namespaces={'ns': CANSAS_NS})
- if simfitstate:
- from simfitpage import SimFitPageState
- sim_fit_state = SimFitPageState()
- simfitstate_0 = simfitstate[0]
- all = simfitstate_0.xpath('ns:select_all',
- namespaces={'ns': CANSAS_NS})
- atts = all[0].attrib
- checked = atts.get('checked')
- sim_fit_state.select_all = bool(checked)
- model_list = simfitstate_0.xpath('ns:model_list',
- namespaces={'ns': CANSAS_NS})
- model_list_items = model_list[0].xpath('ns:model_list_item',
- namespaces={'ns':
- CANSAS_NS})
- for model in model_list_items:
- attrs = model.attrib
- sim_fit_state.model_list.append(attrs)
-
- constraints = simfitstate_0.xpath('ns:constraints',
- namespaces={'ns': CANSAS_NS})
- constraint_list = constraints[0].xpath('ns:constraint',
- namespaces={'ns': CANSAS_NS})
- for constraint in constraint_list:
- attrs = constraint.attrib
- sim_fit_state.constraints_list.append(attrs)
-
- return sim_fit_state
- else:
- return None
-
- def _parse_save_state_entry(self, dom):
- """
- Parse a SASentry
-
- :param node: SASentry node
-
- :return: Data1D/Data2D object
-
- """
- node = dom.xpath('ns:data_class', namespaces={'ns': CANSAS_NS})
- return_value, _ = self._parse_entry(dom)
- return return_value, _
-
- def _read_cansas(self, path):
- """
- Load data and fitting information from a CanSAS XML file.
-
- :param path: file path
- :return: Data1D object if a single SASentry was found,
- or a list of Data1D objects if multiple entries were found,
- or None of nothing was found
- :raise RuntimeError: when the file can't be opened
- :raise ValueError: when the length of the data vectors are inconsistent
- """
- output = []
- simfitstate = None
- basename = os.path.basename(path)
- root, extension = os.path.splitext(basename)
- ext = extension.lower()
- try:
- if os.path.isfile(path):
- if ext in self.ext or ext == '.xml':
- tree = etree.parse(path, parser=etree.ETCompatXMLParser())
- # Check the format version number
- # Specifying the namespace will take care of the file
- # format version
- root = tree.getroot()
- entry_list = root.xpath('ns:SASentry',
- namespaces={'ns': CANSAS_NS})
- for entry in entry_list:
- try:
- sas_entry, _ = self._parse_save_state_entry(entry)
- except:
- raise
- fitstate = self._parse_state(entry)
-
- # state could be None when .svs file is loaded
- # in this case, skip appending to output
- if fitstate is not None:
- sas_entry.meta_data['fitstate'] = fitstate
- sas_entry.filename = fitstate.file
- output.append(sas_entry)
-
- else:
- self.call_back(format=ext)
- raise RuntimeError, "%s is not a file" % path
-
- # Return output consistent with the loader's api
- if len(output) == 0:
- self.call_back(state=None, datainfo=None, format=ext)
- return None
- else:
- for ind in range(len(output)):
- # Call back to post the new state
- state = output[ind].meta_data['fitstate']
- t = time.localtime(state.timestamp)
- time_str = time.strftime("%b %d %H:%M", t)
- # Check that no time stamp is already appended
- max_char = state.file.find("[")
- if max_char < 0:
- max_char = len(state.file)
- original_fname = state.file[0:max_char]
- state.file = original_fname + ' [' + time_str + ']'
-
- if state is not None and state.is_data is not None:
- output[ind].is_data = state.is_data
-
- output[ind].filename = state.file
- state.data = output[ind]
- state.data.name = output[ind].filename # state.data_name
- state.data.id = state.data_id
- if state.is_data is not None:
- state.data.is_data = state.is_data
- if output[ind].run_name is not None\
- and len(output[ind].run_name) != 0:
- if isinstance(output[ind].run_name, dict):
- name = output[ind].run_name.keys()[0]
- else:
- name = output[ind].run_name
- else:
- name = original_fname
- state.data.group_id = name
- state.version = fitstate.version
- # store state in fitting
- self.call_back(state=state,
- datainfo=output[ind], format=ext)
- self.state = state
- simfitstate = self._parse_simfit_state(entry)
- if simfitstate is not None:
- self.call_back(state=simfitstate)
-
- return output
- except:
- self.call_back(format=ext)
- raise
-
- def write(self, filename, datainfo=None, fitstate=None):
- """
- Write the content of a Data1D as a CanSAS XML file only for standalone
-
- :param filename: name of the file to write
- :param datainfo: Data1D object
- :param fitstate: PageState object
-
- """
- # Sanity check
- if self.cansas:
- # Add fitting information to the XML document
- doc = self.write_toXML(datainfo, fitstate)
- # Write the XML document
- else:
- doc = fitstate.to_xml(file=filename)
-
- # Save the document no matter the type
- fd = open(filename, 'w')
- fd.write(doc.toprettyxml())
- fd.close()
-
- def write_toXML(self, datainfo=None, state=None, batchfit=None):
- """
- Write toXML, a helper for write(),
- could be used by guimanager._on_save()
-
- : return: xml doc
- """
-
- self.batchfit_params = batchfit
- if state.data is None or not state.data.is_data:
- return None
- # make sure title and data run are filled.
- if state.data.title is None or state.data.title == '':
- state.data.title = state.data.name
- if state.data.run_name is None or state.data.run_name == {}:
- state.data.run = [str(state.data.name)]
- state.data.run_name[0] = state.data.name
-
- data = state.data
- doc, sasentry = self._to_xml_doc(data)
-
- if state is not None:
- doc = state.to_xml(doc=doc, file=data.filename, entry_node=sasentry,
- batch_fit_state=self.batchfit_params)
-
- return doc
-
-# Simple html report templet
-HEADER = "<html>\n"
-HEADER += "<head>\n"
-HEADER += "<meta http-equiv=Content-Type content='text/html; "
-HEADER += "charset=windows-1252'> \n"
-HEADER += "<meta name=Generator >\n"
-HEADER += "</head>\n"
-HEADER += "<body lang=EN-US>\n"
-HEADER += "<div class=WordSection1>\n"
-HEADER += "<p class=MsoNormal><b><span ><center><font size='4' >"
-HEADER += "%s</font></center></span></center></b></p>"
-HEADER += "<p class=MsoNormal> </p>"
-PARA = "<p class=MsoNormal><font size='4' > %s \n"
-PARA += "</font></p>"
-CENTRE = "<p class=MsoNormal><center><font size='4' > %s \n"
-CENTRE += "</font></center></p>"
-FEET_1 = \
-"""
-<p class=MsoNormal> </p>
-<br>
-<p class=MsoNormal><b><span ><center> <font size='4' > Graph
-</font></span></center></b></p>
-<p class=MsoNormal> </p>
-<center>
-<br><font size='4' >Model Computation</font>
-<br><font size='4' >Data: "%s"</font><br>
-"""
-FEET_2 = \
-"""
-<img src="%s" >
-</img>
-"""
-FEET_3 = \
-"""
-</center>
-</div>
-</body>
-</html>
-"""
-ELINE = "<p class=MsoNormal> </p>"
+"""
+Class that holds a fit page state
+"""
+# TODO: Refactor code so we don't need to use getattr/setattr
+################################################################################
+# This software was developed by the University of Tennessee as part of the
+# Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
+# project funded by the US National Science Foundation.
+#
+# See the license text in license.txt
+#
+# copyright 2009, University of Tennessee
+################################################################################
+import time
+import os
+import sys
+import copy
+import logging
+import numpy as np
+import traceback
+
+import xml.dom.minidom
+from xml.dom.minidom import parseString
+from xml.dom.minidom import getDOMImplementation
+from lxml import etree
+
+from sasmodels import convert
+import sasmodels.weights
+
+from sas.sasview import __version__ as SASVIEW_VERSION
+
+import sas.sascalc.dataloader
+from sas.sascalc.dataloader.readers.cansas_reader import Reader as CansasReader
+from sas.sascalc.dataloader.readers.cansas_reader import get_content, write_node
+from sas.sascalc.dataloader.data_info import Data2D, Collimation, Detector
+from sas.sascalc.dataloader.data_info import Process, Aperture
+
+logger = logging.getLogger(__name__)
+
+# Information to read/write state as xml
+FITTING_NODE_NAME = 'fitting_plug_in'
+CANSAS_NS = {"ns": "cansas1d/1.0"}
+
+CUSTOM_MODEL = 'Plugin Models'
+CUSTOM_MODEL_OLD = 'Customized Models'
+
+LIST_OF_DATA_ATTRIBUTES = [["is_data", "is_data", "bool"],
+ ["group_id", "data_group_id", "string"],
+ ["data_name", "data_name", "string"],
+ ["data_id", "data_id", "string"],
+ ["name", "name", "string"],
+ ["data_name", "data_name", "string"]]
+LIST_OF_STATE_ATTRIBUTES = [["qmin", "qmin", "float"],
+ ["qmax", "qmax", "float"],
+ ["npts", "npts", "float"],
+ ["categorycombobox", "categorycombobox", "string"],
+ ["formfactorcombobox", "formfactorcombobox",
+ "string"],
+ ["structurecombobox", "structurecombobox",
+ "string"],
+ ["multi_factor", "multi_factor", "float"],
+ ["magnetic_on", "magnetic_on", "bool"],
+ ["enable_smearer", "enable_smearer", "bool"],
+ ["disable_smearer", "disable_smearer", "bool"],
+ ["pinhole_smearer", "pinhole_smearer", "bool"],
+ ["slit_smearer", "slit_smearer", "bool"],
+ ["enable_disp", "enable_disp", "bool"],
+ ["disable_disp", "disable_disp", "bool"],
+ ["dI_noweight", "dI_noweight", "bool"],
+ ["dI_didata", "dI_didata", "bool"],
+ ["dI_sqrdata", "dI_sqrdata", "bool"],
+ ["dI_idata", "dI_idata", "bool"],
+ ["enable2D", "enable2D", "bool"],
+ ["cb1", "cb1", "bool"],
+ ["tcChi", "tcChi", "float"],
+ ["dq_l", "dq_l", "float"],
+ ["dq_r", "dq_r", "float"],
+ ["dx_percent", "dx_percent", "float"],
+ ["dxl", "dxl", "float"],
+ ["dxw", "dxw", "float"]]
+
+LIST_OF_MODEL_ATTRIBUTES = [["values", "values"],
+ ["weights", "weights"]]
+
+DISPERSION_LIST = [["disp_obj_dict", "disp_obj_dict", "string"]]
+
+LIST_OF_STATE_PARAMETERS = [["parameters", "parameters"],
+ ["str_parameters", "str_parameters"],
+ ["orientation_parameters", "orientation_params"],
+ ["dispersity_parameters",
+ "orientation_params_disp"],
+ ["fixed_param", "fixed_param"],
+ ["fittable_param", "fittable_param"]]
+LIST_OF_DATA_2D_ATTR = [["xmin", "xmin", "float"],
+ ["xmax", "xmax", "float"],
+ ["ymin", "ymin", "float"],
+ ["ymax", "ymax", "float"],
+ ["_xaxis", "_xaxis", "string"],
+ ["_xunit", "_xunit", "string"],
+ ["_yaxis", "_yaxis", "string"],
+ ["_yunit", "_yunit", "string"],
+ ["_zaxis", "_zaxis", "string"],
+ ["_zunit", "_zunit", "string"]]
+LIST_OF_DATA_2D_VALUES = [["qx_data", "qx_data", "float"],
+ ["qy_data", "qy_data", "float"],
+ ["dqx_data", "dqx_data", "float"],
+ ["dqy_data", "dqy_data", "float"],
+ ["data", "data", "float"],
+ ["q_data", "q_data", "float"],
+ ["err_data", "err_data", "float"],
+ ["mask", "mask", "bool"]]
+
+
+def parse_entry_helper(node, item):
+ """
+ Create a numpy list from value extrated from the node
+
+ :param node: node from each the value is stored
+ :param item: list name of three strings.the two first are name of data
+ attribute and the third one is the type of the value of that
+ attribute. type can be string, float, bool, etc.
+
+ : return: numpy array
+ """
+ if node is not None:
+ if item[2] == "string":
+ return str(node.get(item[0]).strip())
+ elif item[2] == "bool":
+ try:
+ return node.get(item[0]).strip() == "True"
+ except Exception:
+ return None
+ else:
+ try:
+ return float(node.get(item[0]))
+ except Exception:
+ return None
+
+
+class PageState(object):
+ """
+ Contains information to reconstruct a page of the fitpanel.
+ """
+ def __init__(self, model=None, data=None):
+ """
+ Initialize the current state
+
+ :param model: a selected model within a page
+ :param data:
+
+ """
+ self.file = None
+ # Time of state creation
+ self.timestamp = time.time()
+ # Data member to store the dispersion object created
+ self.disp_obj_dict = {}
+ # ------------------------
+ # Data used for fitting
+ self.data = data
+ # model data
+ self.theory_data = None
+ # Is 2D
+ self.is_2D = False
+ self.images = None
+
+ # save additional information on data that dataloader.reader
+ # does not read
+ self.is_data = None
+ self.data_name = ""
+
+ if self.data is not None:
+ self.data_name = self.data.name
+ self.data_id = None
+ if self.data is not None and hasattr(self.data, "id"):
+ self.data_id = self.data.id
+ self.data_group_id = None
+ if self.data is not None and hasattr(self.data, "group_id"):
+ self.data_group_id = self.data.group_id
+
+ # reset True change the state of existing button
+ self.reset = False
+
+ # flag to allow data2D plot
+ self.enable2D = False
+ # model on which the fit would be performed
+ self.model = model
+ self.m_name = None
+ # list of process done to model
+ self.process = []
+ # fit page manager
+ self.manager = None
+ # Event_owner is the owner of model event
+ self.event_owner = None
+ # page name
+ self.page_name = ""
+ # Contains link between model, its parameters, and panel organization
+ self.parameters = []
+ # String parameter list that can not be fitted
+ self.str_parameters = []
+ # Contains list of parameters that cannot be fitted and reference to
+ # panel objects
+ self.fixed_param = []
+ # Contains list of parameters with dispersity and reference to
+ # panel objects
+ self.fittable_param = []
+ # orientation parameters
+ self.orientation_params = []
+ # orientation parameters for gaussian dispersity
+ self.orientation_params_disp = []
+ self.dq_l = None
+ self.dq_r = None
+ self.dx_percent = None
+ self.dx_old = False
+ self.dxl = None
+ self.dxw = None
+ # list of dispersion parameters
+ self.disp_list = []
+ if self.model is not None:
+ self.disp_list = self.model.getDispParamList()
+
+ self.disp_cb_dict = {}
+ self.values = {}
+ self.weights = {}
+
+ # contains link between a model and selected parameters to fit
+ self.param_toFit = []
+ # save the state of the context menu
+ self.saved_states = {}
+ # save selection of combobox
+ self.formfactorcombobox = None
+ self.categorycombobox = None
+ self.structurecombobox = None
+
+ # radio box to select type of model
+ # self.shape_rbutton = False
+ # self.shape_indep_rbutton = False
+ # self.struct_rbutton = False
+ # self.plugin_rbutton = False
+ # the indice of the current selection
+ self.disp_box = 0
+ # Qrange
+ # Q range
+ self.qmin = 0.001
+ self.qmax = 0.1
+ # reset data range
+ self.qmax_x = None
+ self.qmin_x = None
+
+ self.npts = None
+ self.name = ""
+ self.multi_factor = None
+ self.magnetic_on = False
+ # enable smearering state
+ self.enable_smearer = False
+ self.disable_smearer = True
+ self.pinhole_smearer = False
+ self.slit_smearer = False
+ # weighting options
+ self.dI_noweight = False
+ self.dI_didata = True
+ self.dI_sqrdata = False
+ self.dI_idata = False
+ # disperity selection
+ self.enable_disp = False
+ self.disable_disp = True
+
+ # state of selected all check button
+ self.cb1 = False
+ # store value of chisqr
+ self.tcChi = None
+ self.version = (1, 0, 0)
+
+ def clone(self):
+ """
+ Create a new copy of the current object
+ """
+ model = None
+ if self.model is not None:
+ model = self.model.clone()
+ model.name = self.model.name
+ obj = PageState(model=model)
+ obj.file = copy.deepcopy(self.file)
+ obj.data = copy.deepcopy(self.data)
+ if self.data is not None:
+ self.data_name = self.data.name
+ obj.data_name = self.data_name
+ obj.is_data = self.is_data
+
+ obj.categorycombobox = self.categorycombobox
+ obj.formfactorcombobox = self.formfactorcombobox
+ obj.structurecombobox = self.structurecombobox
+
+ # obj.shape_rbutton = self.shape_rbutton
+ # obj.shape_indep_rbutton = self.shape_indep_rbutton
+ # obj.struct_rbutton = self.struct_rbutton
+ # obj.plugin_rbutton = self.plugin_rbutton
+
+ obj.manager = self.manager
+ obj.event_owner = self.event_owner
+ obj.disp_list = copy.deepcopy(self.disp_list)
+
+ obj.enable2D = copy.deepcopy(self.enable2D)
+ obj.parameters = copy.deepcopy(self.parameters)
+ obj.str_parameters = copy.deepcopy(self.str_parameters)
+ obj.fixed_param = copy.deepcopy(self.fixed_param)
+ obj.fittable_param = copy.deepcopy(self.fittable_param)
+ obj.orientation_params = copy.deepcopy(self.orientation_params)
+ obj.orientation_params_disp = \
+ copy.deepcopy(self.orientation_params_disp)
+ obj.enable_disp = copy.deepcopy(self.enable_disp)
+ obj.disable_disp = copy.deepcopy(self.disable_disp)
+ obj.tcChi = self.tcChi
+
+ if len(self.disp_obj_dict) > 0:
+ for k, v in self.disp_obj_dict.items():
+ obj.disp_obj_dict[k] = v
+ if len(self.disp_cb_dict) > 0:
+ for k, v in self.disp_cb_dict.items():
+ obj.disp_cb_dict[k] = v
+ if len(self.values) > 0:
+ for k, v in self.values.items():
+ obj.values[k] = v
+ if len(self.weights) > 0:
+ for k, v in self.weights.items():
+ obj.weights[k] = v
+ obj.enable_smearer = copy.deepcopy(self.enable_smearer)
+ obj.disable_smearer = copy.deepcopy(self.disable_smearer)
+ obj.pinhole_smearer = copy.deepcopy(self.pinhole_smearer)
+ obj.slit_smearer = copy.deepcopy(self.slit_smearer)
+ obj.dI_noweight = copy.deepcopy(self.dI_noweight)
+ obj.dI_didata = copy.deepcopy(self.dI_didata)
+ obj.dI_sqrdata = copy.deepcopy(self.dI_sqrdata)
+ obj.dI_idata = copy.deepcopy(self.dI_idata)
+ obj.dq_l = copy.deepcopy(self.dq_l)
+ obj.dq_r = copy.deepcopy(self.dq_r)
+ obj.dx_percent = copy.deepcopy(self.dx_percent)
+ obj.dx_old = copy.deepcopy(self.dx_old)
+ obj.dxl = copy.deepcopy(self.dxl)
+ obj.dxw = copy.deepcopy(self.dxw)
+ obj.disp_box = copy.deepcopy(self.disp_box)
+ obj.qmin = copy.deepcopy(self.qmin)
+ obj.qmax = copy.deepcopy(self.qmax)
+ obj.multi_factor = self.multi_factor
+ obj.magnetic_on = self.magnetic_on
+ obj.npts = copy.deepcopy(self.npts)
+ obj.cb1 = copy.deepcopy(self.cb1)
+ obj.version = copy.deepcopy(self.version)
+
+ for name, state in self.saved_states.items():
+ copy_name = copy.deepcopy(name)
+ copy_state = state.clone()
+ obj.saved_states[copy_name] = copy_state
+ return obj
+
+ def _old_first_model(self):
+ """
+ Handle save states from 4.0.1 and before where the first item in the
+ selection boxes of category, formfactor and structurefactor were not
+ saved.
+ :return: None
+ """
+ if self.categorycombobox == CUSTOM_MODEL_OLD:
+ self.categorycombobox = CUSTOM_MODEL
+ if self.formfactorcombobox == '':
+ FIRST_FORM = {
+ 'Shapes' : 'BCCrystalModel',
+ 'Uncategorized' : 'LineModel',
+ 'StructureFactor' : 'HardsphereStructure',
+ 'Ellipsoid' : 'core_shell_ellipsoid',
+ 'Lamellae' : 'lamellar',
+ 'Paracrystal' : 'bcc_paracrystal',
+ 'Parallelepiped' : 'core_shell_parallelepiped',
+ 'Shape Independent' : 'be_polyelectrolyte',
+ 'Sphere' : 'adsorbed_layer',
+ 'Structure Factor' : 'hardsphere',
+ CUSTOM_MODEL : ''
+ }
+ if self.categorycombobox == '':
+ if len(self.parameters) == 3:
+ self.categorycombobox = "Shape-Independent"
+ self.formfactorcombobox = 'PowerLawAbsModel'
+ elif len(self.parameters) == 9:
+ self.categorycombobox = 'Cylinder'
+ self.formfactorcombobox = 'barbell'
+ else:
+ msg = "Save state does not have enough information to load"
+ msg += " the all of the data."
+ logger.warning(msg=msg)
+ else:
+ self.formfactorcombobox = FIRST_FORM[self.categorycombobox]
+
+ @staticmethod
+ def param_remap_to_sasmodels_convert(params, is_string=False):
+ """
+ Remaps the parameters for sasmodels conversion
+
+ :param params: list of parameters (likely self.parameters)
+ :return: remapped dictionary of parameters
+ """
+ p = dict()
+ for fittable, name, value, _, uncert, lower, upper, units in params:
+ if not value:
+ value = np.nan
+ if not uncert or uncert[1] == '' or uncert[1] == 'None':
+ uncert[0] = False
+ uncert[1] = np.nan
+ if not upper or upper[1] == '' or upper[1] == 'None':
+ upper[0] = False
+ upper[1] = np.nan
+ if not lower or lower[1] == '' or lower[1] == 'None':
+ lower[0] = False
+ lower[1] = np.nan
+ if is_string:
+ p[name] = str(value)
+ else:
+ p[name] = float(value)
+ p[name + ".fittable"] = bool(fittable)
+ p[name + ".std"] = float(uncert[1])
+ p[name + ".upper"] = float(upper[1])
+ p[name + ".lower"] = float(lower[1])
+ p[name + ".units"] = units
+ return p
+
+ @staticmethod
+ def param_remap_from_sasmodels_convert(params):
+ """
+ Converts {name : value} map back to [] param list
+ :param params: parameter map returned from sasmodels
+ :return: None
+ """
+ p_map = []
+ for name, info in params.items():
+ if ".fittable" in name or ".std" in name or ".upper" in name or \
+ ".lower" in name or ".units" in name:
+ pass
+ else:
+ fittable = params.get(name + ".fittable", True)
+ std = params.get(name + ".std", '0.0')
+ upper = params.get(name + ".upper", 'inf')
+ lower = params.get(name + ".lower", '-inf')
+ units = params.get(name + ".units")
+ if std is not None and std is not np.nan:
+ std = [True, str(std)]
+ else:
+ std = [False, '']
+ if lower is not None and lower is not np.nan:
+ lower = [True, str(lower)]
+ else:
+ lower = [True, '-inf']
+ if upper is not None and upper is not np.nan:
+ upper = [True, str(upper)]
+ else:
+ upper = [True, 'inf']
+ param_list = [bool(fittable), str(name), str(info),
+ "+/-", std, lower, upper, str(units)]
+ p_map.append(param_list)
+ return p_map
+
+ def _convert_to_sasmodels(self):
+ """
+ Convert parameters to a form usable by sasmodels converter
+
+ :return: None
+ """
+ # Create conversion dictionary to send to sasmodels
+ self._old_first_model()
+ p = self.param_remap_to_sasmodels_convert(self.parameters)
+ structurefactor, params = convert.convert_model(self.structurecombobox,
+ p, False, self.version)
+ formfactor, params = convert.convert_model(self.formfactorcombobox,
+ params, False, self.version)
+ if len(self.str_parameters) > 0:
+ str_pars = self.param_remap_to_sasmodels_convert(
+ self.str_parameters, True)
+ formfactor, str_params = convert.convert_model(
+ self.formfactorcombobox, str_pars, False, self.version)
+ for key, value in str_params.items():
+ params[key] = value
+
+ if self.formfactorcombobox == 'SphericalSLDModel':
+ self.multi_factor += 1
+ self.formfactorcombobox = formfactor
+ self.structurecombobox = structurefactor
+ self.parameters = []
+ self.parameters = self.param_remap_from_sasmodels_convert(params)
+
+ def _repr_helper(self, list, rep):
+ """
+ Helper method to print a state
+ """
+ for item in list:
+ rep += "parameter name: %s \n" % str(item[1])
+ rep += "value: %s\n" % str(item[2])
+ rep += "selected: %s\n" % str(item[0])
+ rep += "error displayed : %s \n" % str(item[4][0])
+ rep += "error value:%s \n" % str(item[4][1])
+ rep += "minimum displayed : %s \n" % str(item[5][0])
+ rep += "minimum value : %s \n" % str(item[5][1])
+ rep += "maximum displayed : %s \n" % str(item[6][0])
+ rep += "maximum value : %s \n" % str(item[6][1])
+ rep += "parameter unit: %s\n\n" % str(item[7])
+ return rep
+
+ def __repr__(self):
+ """
+ output string for printing
+ """
+ rep = "\nState name: %s\n" % self.file
+ t = time.localtime(self.timestamp)
+ time_str = time.strftime("%b %d %Y %H:%M:%S ", t)
+
+ rep += "State created: %s\n" % time_str
+ rep += "State form factor combobox selection: %s\n" % \
+ self.formfactorcombobox
+ rep += "State structure factor combobox selection: %s\n" % \
+ self.structurecombobox
+ rep += "is data : %s\n" % self.is_data
+ rep += "data's name : %s\n" % self.data_name
+ rep += "data's id : %s\n" % self.data_id
+ if self.model is not None:
+ m_name = self.model.__class__.__name__
+ if m_name == 'Model':
+ m_name = self.m_name
+ rep += "model name : %s\n" % m_name
+ else:
+ rep += "model name : None\n"
+ rep += "multi_factor : %s\n" % str(self.multi_factor)
+ rep += "magnetic_on : %s\n" % str(self.magnetic_on)
+ rep += "model type (Category) selected: %s\n" % self.categorycombobox
+ rep += "data : %s\n" % str(self.data)
+ rep += "Plotting Range: min: %s, max: %s, steps: %s\n" % \
+ (str(self.qmin), str(self.qmax), str(self.npts))
+ rep += "Dispersion selection : %s\n" % str(self.disp_box)
+ rep += "Smearing enable : %s\n" % str(self.enable_smearer)
+ rep += "Smearing disable : %s\n" % str(self.disable_smearer)
+ rep += "Pinhole smearer enable : %s\n" % str(self.pinhole_smearer)
+ rep += "Slit smearer enable : %s\n" % str(self.slit_smearer)
+ rep += "Dispersity enable : %s\n" % str(self.enable_disp)
+ rep += "Dispersity disable : %s\n" % str(self.disable_disp)
+ rep += "Slit smearer enable: %s\n" % str(self.slit_smearer)
+
+ rep += "dI_noweight : %s\n" % str(self.dI_noweight)
+ rep += "dI_didata : %s\n" % str(self.dI_didata)
+ rep += "dI_sqrdata : %s\n" % str(self.dI_sqrdata)
+ rep += "dI_idata : %s\n" % str(self.dI_idata)
+
+ rep += "2D enable : %s\n" % str(self.enable2D)
+ rep += "All parameters checkbox selected: %s\n" % self.cb1
+ rep += "Value of Chisqr : %s\n" % str(self.tcChi)
+ rep += "dq_l : %s\n" % self.dq_l
+ rep += "dq_r : %s\n" % self.dq_r
+ rep += "dx_percent : %s\n" % str(self.dx_percent)
+ rep += "dxl : %s\n" % str(self.dxl)
+ rep += "dxw : %s\n" % str(self.dxw)
+ rep += "model : %s\n\n" % str(self.model)
+ temp_parameters = []
+ temp_fittable_param = []
+ if self.data.__class__.__name__ == "Data2D":
+ self.is_2D = True
+ else:
+ self.is_2D = False
+ if self.data is not None:
+ if not self.is_2D:
+ for item in self.parameters:
+ if item not in self.orientation_params:
+ temp_parameters.append(item)
+ for item in self.fittable_param:
+ if item not in self.orientation_params_disp:
+ temp_fittable_param.append(item)
+ else:
+ temp_parameters = self.parameters
+ temp_fittable_param = self.fittable_param
+
+ rep += "number parameters(self.parameters): %s\n" % \
+ len(temp_parameters)
+ rep = self._repr_helper(list=temp_parameters, rep=rep)
+ rep += "number str_parameters(self.str_parameters): %s\n" % \
+ len(self.str_parameters)
+ rep = self._repr_helper(list=self.str_parameters, rep=rep)
+ rep += "number fittable_param(self.fittable_param): %s\n" % \
+ len(temp_fittable_param)
+ rep = self._repr_helper(list=temp_fittable_param, rep=rep)
+ return rep
+
+ def _get_report_string(self):
+ """
+ Get the values (strings) from __str__ for report
+ """
+ # Dictionary of the report strings
+ repo_time = ""
+ model_name = ""
+ title = ""
+ title_name = ""
+ file_name = ""
+ param_string = ""
+ paramval_string = ""
+ chi2_string = ""
+ q_range = ""
+ strings = self.__repr__()
+ fixed_parameter = False
+ lines = strings.split('\n')
+ # get all string values from __str__()
+ for line in lines:
+ # Skip lines which are not key: value pairs, which includes
+ # blank lines and freeform notes in SASNotes fields.
+ if not ':' in line:
+ #msg = "Report string expected 'name: value' but got %r" % line
+ #logger.error(msg)
+ continue
+
+ name, value = [s.strip() for s in line.split(":", 1)]
+ if name == "State created":
+ repo_time = value
+ elif name == "parameter name":
+ val_name = value.split(".")
+ if len(val_name) > 1:
+ if val_name[1].count("width"):
+ param_string += value + ','
+ else:
+ continue
+ else:
+ param_string += value + ','
+ elif name == "value":
+ param_string += value + ','
+ elif name == "selected":
+ # remember if it is fixed when reporting error value
+ fixed_parameter = (value == u'False')
+ elif name == "error value":
+ if fixed_parameter:
+ param_string += '(fixed),'
+ else:
+ param_string += value + ','
+ elif name == "parameter unit":
+ param_string += value + ':'
+ elif name == "Value of Chisqr":
+ chi2 = ("Chi2/Npts = " + value)
+ chi2_string = CENTRE % chi2
+ elif name == "Title":
+ if len(value.strip()) == 0:
+ continue
+ title = value + " [" + repo_time + "]"
+ title_name = HEADER % title
+ elif name == "data":
+ try:
+ # parsing "data : File: filename [mmm dd hh:mm]"
+ name = value.split(':', 1)[1].strip()
+ file_value = "File name:" + name
+ file_name = CENTRE % file_value
+ if len(title) == 0:
+ title = name + " [" + repo_time + "]"
+ title_name = HEADER % title
+ except Exception:
+ msg = "While parsing 'data: ...'\n"
+ logger.error(msg + traceback.format_exc())
+ elif name == "model name":
+ try:
+ modelname = "Model name:" + value
+ except Exception:
+ modelname = "Model name:" + " NAN"
+ model_name = CENTRE % modelname
+
+ elif name == "Plotting Range":
+ try:
+ parts = value.split(':')
+ q_range = parts[0] + " = " + parts[1] \
+ + " = " + parts[2].split(",")[0]
+ q_name = ("Q Range: " + q_range)
+ q_range = CENTRE % q_name
+ except Exception:
+ msg = "While parsing 'Plotting Range: ...'\n"
+ logger.error(msg + traceback.format_exc())
+
+ paramval = ""
+ for lines in param_string.split(":"):
+ line = lines.split(",")
+ if len(lines) > 0:
+ param = line[0]
+ param += " = " + line[1]
+ if len(line[2].split()) > 0 and not line[2].count("None"):
+ param += " +- " + line[2]
+ if len(line[3].split()) > 0 and not line[3].count("None"):
+ param += " " + line[3]
+ if not paramval.count(param):
+ paramval += param + "\n"
+ paramval_string += CENTRE % param + "\n"
+
+ text_string = "\n\n\n%s\n\n%s\n%s\n%s\n\n%s" % \
+ (title, file, q_name, chi2, paramval)
+
+ title_name = self._check_html_format(title_name)
+ file_name = self._check_html_format(file_name)
+ title = self._check_html_format(title)
+
+ html_string = title_name + "\n" + file_name + \
+ "\n" + model_name + \
+ "\n" + q_range + \
+ "\n" + chi2_string + \
+ "\n" + ELINE + \
+ "\n" + paramval_string + \
+ "\n" + ELINE + \
+ "\n" + FEET_1 % title
+
+ return html_string, text_string, title
+
+ def _check_html_format(self, name):
+ """
+ Check string '%' for html format
+ """
+ if name.count('%'):
+ name = name.replace('%', '%')
+
+ return name
+
+ def report(self, fig_urls):
+ """
+ Invoke report dialog panel
+
+ : param figs: list of pylab figures [list]
+ """
+ # get the strings for report
+ html_str, text_str, title = self._get_report_string()
+ # Allow 2 figures to append
+ image_links = [FEET_2%fig for fig in fig_urls]
+
+ # final report html strings
+ report_str = html_str + ELINE.join(image_links)
+
+ return report_str, text_str
+
+ def _to_xml_helper(self, thelist, element, newdoc):
+ """
+ Helper method to create xml file for saving state
+ """
+ for item in thelist:
+ sub_element = newdoc.createElement('parameter')
+ sub_element.setAttribute('name', str(item[1]))
+ sub_element.setAttribute('value', str(item[2]))
+ sub_element.setAttribute('selected_to_fit', str(item[0]))
+ sub_element.setAttribute('error_displayed', str(item[4][0]))
+ sub_element.setAttribute('error_value', str(item[4][1]))
+ sub_element.setAttribute('minimum_displayed', str(item[5][0]))
+ sub_element.setAttribute('minimum_value', str(item[5][1]))
+ sub_element.setAttribute('maximum_displayed', str(item[6][0]))
+ sub_element.setAttribute('maximum_value', str(item[6][1]))
+ sub_element.setAttribute('unit', str(item[7]))
+ element.appendChild(sub_element)
+
+ def to_xml(self, file="fitting_state.fitv", doc=None,
+ entry_node=None, batch_fit_state=None):
+ """
+ Writes the state of the fit panel to file, as XML.
+
+ Compatible with standalone writing, or appending to an
+ already existing XML document. In that case, the XML document is
+ required. An optional entry node in the XML document may also be given.
+
+ :param file: file to write to
+ :param doc: XML document object [optional]
+ :param entry_node: XML node within the XML document at which we
+ will append the data [optional]
+ :param batch_fit_state: simultaneous fit state
+ """
+ # Check whether we have to write a standalone XML file
+ if doc is None:
+ impl = getDOMImplementation()
+ doc_type = impl.createDocumentType(FITTING_NODE_NAME, "1.0", "1.0")
+ newdoc = impl.createDocument(None, FITTING_NODE_NAME, doc_type)
+ top_element = newdoc.documentElement
+ else:
+ # We are appending to an existing document
+ newdoc = doc
+ try:
+ top_element = newdoc.createElement(FITTING_NODE_NAME)
+ except Exception:
+ string = etree.tostring(doc, pretty_print=True)
+ newdoc = parseString(string)
+ top_element = newdoc.createElement(FITTING_NODE_NAME)
+ if entry_node is None:
+ newdoc.documentElement.appendChild(top_element)
+ else:
+ try:
+ entry_node.appendChild(top_element)
+ except Exception:
+ node_name = entry_node.tag
+ node_list = newdoc.getElementsByTagName(node_name)
+ entry_node = node_list.item(0)
+ entry_node.appendChild(top_element)
+
+ attr = newdoc.createAttribute("version")
+ attr.nodeValue = SASVIEW_VERSION
+ # attr.nodeValue = '1.0'
+ top_element.setAttributeNode(attr)
+
+ # File name
+ element = newdoc.createElement("filename")
+ if self.file is not None:
+ element.appendChild(newdoc.createTextNode(str(self.file)))
+ else:
+ element.appendChild(newdoc.createTextNode(str(file)))
+ top_element.appendChild(element)
+
+ element = newdoc.createElement("timestamp")
+ element.appendChild(newdoc.createTextNode(time.ctime(self.timestamp)))
+ attr = newdoc.createAttribute("epoch")
+ attr.nodeValue = str(self.timestamp)
+ element.setAttributeNode(attr)
+ top_element.appendChild(element)
+
+ # Inputs
+ inputs = newdoc.createElement("Attributes")
+ top_element.appendChild(inputs)
+
+ if self.data is not None and hasattr(self.data, "group_id"):
+ self.data_group_id = self.data.group_id
+ if self.data is not None and hasattr(self.data, "is_data"):
+ self.is_data = self.data.is_data
+ if self.data is not None:
+ self.data_name = self.data.name
+ if self.data is not None and hasattr(self.data, "id"):
+ self.data_id = self.data.id
+
+ for item in LIST_OF_DATA_ATTRIBUTES:
+ element = newdoc.createElement(item[0])
+ element.setAttribute(item[0], str(getattr(self, item[1])))
+ inputs.appendChild(element)
+
+ for item in LIST_OF_STATE_ATTRIBUTES:
+ element = newdoc.createElement(item[0])
+ element.setAttribute(item[0], str(getattr(self, item[1])))
+ inputs.appendChild(element)
+
+ # For self.values ={ disp_param_name: [vals,...],...}
+ # and for self.weights ={ disp_param_name: [weights,...],...}
+ for item in LIST_OF_MODEL_ATTRIBUTES:
+ element = newdoc.createElement(item[0])
+ value_list = getattr(self, item[1])
+ for key, value in value_list.items():
+ sub_element = newdoc.createElement(key)
+ sub_element.setAttribute('name', str(key))
+ for val in value:
+ sub_element.appendChild(newdoc.createTextNode(str(val)))
+
+ element.appendChild(sub_element)
+ inputs.appendChild(element)
+
+ # Create doc for the dictionary of self.disp_obj_dic
+ for tagname, varname, tagtype in DISPERSION_LIST:
+ element = newdoc.createElement(tagname)
+ value_list = getattr(self, varname)
+ for key, value in value_list.items():
+ sub_element = newdoc.createElement(key)
+ sub_element.setAttribute('name', str(key))
+ sub_element.setAttribute('value', str(value))
+ element.appendChild(sub_element)
+ inputs.appendChild(element)
+
+ for item in LIST_OF_STATE_PARAMETERS:
+ element = newdoc.createElement(item[0])
+ self._to_xml_helper(thelist=getattr(self, item[1]),
+ element=element, newdoc=newdoc)
+ inputs.appendChild(element)
+
+ # Combined and Simultaneous Fit Parameters
+ if batch_fit_state is not None:
+ batch_combo = newdoc.createElement('simultaneous_fit')
+ top_element.appendChild(batch_combo)
+
+ # Simultaneous Fit Number For Linking Later
+ element = newdoc.createElement('sim_fit_number')
+ element.setAttribute('fit_number', str(batch_fit_state.fit_page_no))
+ batch_combo.appendChild(element)
+
+ # Save constraints
+ constraints = newdoc.createElement('constraints')
+ batch_combo.appendChild(constraints)
+ for constraint in batch_fit_state.constraints_list:
+ if constraint.model_cbox.GetValue() != "":
+ # model_cbox, param_cbox, egal_txt, constraint,
+ # btRemove, sizer
+ doc_cons = newdoc.createElement('constraint')
+ doc_cons.setAttribute('model_cbox',
+ str(constraint.model_cbox.GetValue()))
+ doc_cons.setAttribute('param_cbox',
+ str(constraint.param_cbox.GetValue()))
+ doc_cons.setAttribute('egal_txt',
+ str(constraint.egal_txt.GetLabel()))
+ doc_cons.setAttribute('constraint',
+ str(constraint.constraint.GetValue()))
+ constraints.appendChild(doc_cons)
+
+ # Save all models
+ models = newdoc.createElement('model_list')
+ batch_combo.appendChild(models)
+ for model in batch_fit_state.model_list:
+ doc_model = newdoc.createElement('model_list_item')
+ doc_model.setAttribute('checked', str(model[0].GetValue()))
+ keys = model[1].keys()
+ doc_model.setAttribute('name', str(keys[0]))
+ values = model[1].get(keys[0])
+ doc_model.setAttribute('fit_number', str(model[2]))
+ doc_model.setAttribute('fit_page_source', str(model[3]))
+ doc_model.setAttribute('model_name', str(values.model.id))
+ models.appendChild(doc_model)
+
+ # Select All Checkbox
+ element = newdoc.createElement('select_all')
+ if batch_fit_state.select_all:
+ element.setAttribute('checked', 'True')
+ else:
+ element.setAttribute('checked', 'False')
+ batch_combo.appendChild(element)
+
+ # Save the file
+ if doc is None:
+ fd = open(file, 'w')
+ fd.write(newdoc.toprettyxml())
+ fd.close()
+ return None
+ else:
+ return newdoc
+
+ def _from_xml_helper(self, node, list):
+ """
+ Helper function to write state to xml
+ """
+ for item in node:
+ name = item.get('name')
+ value = item.get('value')
+ selected_to_fit = (item.get('selected_to_fit') == "True")
+ error_displayed = (item.get('error_displayed') == "True")
+ error_value = item.get('error_value')
+ minimum_displayed = (item.get('minimum_displayed') == "True")
+ minimum_value = item.get('minimum_value')
+ maximum_displayed = (item.get('maximum_displayed') == "True")
+ maximum_value = item.get('maximum_value')
+ unit = item.get('unit')
+ list.append([selected_to_fit, name, value, "+/-",
+ [error_displayed, error_value],
+ [minimum_displayed, minimum_value],
+ [maximum_displayed, maximum_value], unit])
+
+ def from_xml(self, file=None, node=None):
+ """
+ Load fitting state from a file
+
+ :param file: .fitv file
+ :param node: node of a XML document to read from
+ """
+ if file is not None:
+ msg = "PageState no longer supports non-CanSAS"
+ msg += " format for fitting files"
+ raise RuntimeError(msg)
+
+ if node.get('version'):
+ # Get the version for model conversion purposes
+ self.version = tuple(int(e) for e in
+ str.split(node.get('version'), "."))
+ # The tuple must be at least 3 items long
+ while len(self.version) < 3:
+ ver_list = list(self.version)
+ ver_list.append(0)
+ self.version = tuple(ver_list)
+
+ # Get file name
+ entry = get_content('ns:filename', node)
+ if entry is not None and entry.text:
+ self.file = entry.text.strip()
+ else:
+ self.file = ''
+
+ # Get time stamp
+ entry = get_content('ns:timestamp', node)
+ if entry is not None and entry.get('epoch'):
+ try:
+ self.timestamp = float(entry.get('epoch'))
+ except Exception:
+ msg = "PageState.fromXML: Could not"
+ msg += " read timestamp\n %s" % sys.exc_value
+ logger.error(msg)
+
+ if entry is not None:
+ # Parse fitting attributes
+ entry = get_content('ns:Attributes', node)
+ for item in LIST_OF_DATA_ATTRIBUTES:
+ node = get_content('ns:%s' % item[0], entry)
+ setattr(self, item[0], parse_entry_helper(node, item))
+
+ dx_old_node = get_content('ns:%s' % 'dx_min', entry)
+ for item in LIST_OF_STATE_ATTRIBUTES:
+ if item[0] == "dx_percent" and dx_old_node is not None:
+ dxmin = ["dx_min", "dx_min", "float"]
+ setattr(self, item[0], parse_entry_helper(dx_old_node,
+ dxmin))
+ self.dx_old = True
+ else:
+ node = get_content('ns:%s' % item[0], entry)
+ setattr(self, item[0], parse_entry_helper(node, item))
+
+ for item in LIST_OF_STATE_PARAMETERS:
+ node = get_content("ns:%s" % item[0], entry)
+ self._from_xml_helper(node=node,
+ list=getattr(self, item[1]))
+
+ # Recover disp_obj_dict from xml file
+ self.disp_obj_dict = {}
+ for tagname, varname, tagtype in DISPERSION_LIST:
+ node = get_content("ns:%s" % tagname, entry)
+ for attr in node:
+ parameter = str(attr.get('name'))
+ value = attr.get('value')
+ if value.startswith("<"):
+ try:
+ # <path.to.NamedDistribution object/instance...>
+ cls_name = value[1:].split()[0].split('.')[-1]
+ cls = getattr(sasmodels.weights, cls_name)
+ value = cls.type
+ except Exception:
+ base = "unable to load distribution %r for %s"
+ logger.error(base, value, parameter)
+ continue
+ disp_obj_dict = getattr(self, varname)
+ disp_obj_dict[parameter] = value
+
+ # get self.values and self.weights dic. if exists
+ for tagname, varname in LIST_OF_MODEL_ATTRIBUTES:
+ node = get_content("ns:%s" % tagname, entry)
+ dic = {}
+ value_list = []
+ for par in node:
+ name = par.get('name')
+ values = par.text.split()
+ # Get lines only with numbers
+ for line in values:
+ try:
+ val = float(line)
+ value_list.append(val)
+ except Exception:
+ # pass if line is empty (it happens)
+ msg = ("Error reading %r from %s %s\n"
+ % (line, tagname, name))
+ logger.error(msg + traceback.format_exc())
+ dic[name] = np.array(value_list)
+ setattr(self, varname, dic)
+
+class SimFitPageState(object):
+ """
+ State of the simultaneous fit page for saving purposes
+ """
+
+ def __init__(self):
+ # Sim Fit Page Number
+ self.fit_page_no = None
+ # Select all data
+ self.select_all = False
+ # Data sets sent to fit page
+ self.model_list = []
+ # Data sets to be fit
+ self.model_to_fit = []
+ # Number of constraints
+ self.no_constraint = 0
+ # Dictionary of constraints
+ self.constraint_dict = {}
+ # List of constraints
+ self.constraints_list = []
+
+ def __repr__(self):
+ # TODO: should use __str__, not __repr__ (similarly for PageState)
+ # TODO: could use a nicer representation
+ repr = """\
+fit page number : %(fit_page_no)s
+select all : %(select_all)s
+model_list : %(model_list)s
+model to fit : %(model_to_fit)s
+number of construsts : %(no_constraint)s
+constraint dict : %(constraint_dict)s
+constraints list : %(constraints_list)s
+"""%self.__dict__
+ return repr
+
+class Reader(CansasReader):
+ """
+ Class to load a .fitv fitting file
+ """
+ # File type
+ type_name = "Fitting"
+
+ # Wildcards
+ type = ["Fitting files (*.fitv)|*.fitv"
+ "SASView file (*.svs)|*.svs"]
+ # List of allowed extensions
+ ext = ['.fitv', '.FITV', '.svs', 'SVS']
+
+ def __init__(self, call_back=None, cansas=True):
+ CansasReader.__init__(self)
+ """
+ Initialize the call-back method to be called
+ after we load a file
+
+ :param call_back: call-back method
+ :param cansas: True = files will be written/read in CanSAS format
+ False = write CanSAS format
+
+ """
+ # Call back method to be executed after a file is read
+ self.call_back = call_back
+ # CanSAS format flag
+ self.cansas = cansas
+ self.state = None
+ # batch fitting params for saving
+ self.batchfit_params = []
+
+ def get_state(self):
+ return self.state
+
+ def read(self, path):
+ """
+ Load a new P(r) inversion state from file
+
+ :param path: file path
+
+ """
+ if self.cansas:
+ return self._read_cansas(path)
+
+ def _parse_state(self, entry):
+ """
+ Read a fit result from an XML node
+
+ :param entry: XML node to read from
+ :return: PageState object
+ """
+ # Create an empty state
+ state = None
+ # Locate the P(r) node
+ try:
+ nodes = entry.xpath('ns:%s' % FITTING_NODE_NAME,
+ namespaces=CANSAS_NS)
+ if nodes:
+ # Create an empty state
+ state = PageState()
+ state.from_xml(node=nodes[0])
+
+ except Exception:
+ logger.info("XML document does not contain fitting information.\n"
+ + traceback.format_exc())
+
+ return state
+
+ def _parse_simfit_state(self, entry):
+ """
+ Parses the saved data for a simultaneous fit
+ :param entry: XML object to read from
+ :return: XML object for a simultaneous fit or None
+ """
+ nodes = entry.xpath('ns:%s' % FITTING_NODE_NAME,
+ namespaces=CANSAS_NS)
+ if nodes:
+ simfitstate = nodes[0].xpath('ns:simultaneous_fit',
+ namespaces=CANSAS_NS)
+ if simfitstate:
+ sim_fit_state = SimFitPageState()
+ simfitstate_0 = simfitstate[0]
+ all = simfitstate_0.xpath('ns:select_all',
+ namespaces=CANSAS_NS)
+ atts = all[0].attrib
+ checked = atts.get('checked')
+ sim_fit_state.select_all = bool(checked)
+ model_list = simfitstate_0.xpath('ns:model_list',
+ namespaces=CANSAS_NS)
+ model_list_items = model_list[0].xpath('ns:model_list_item',
+ namespaces=CANSAS_NS)
+ for model in model_list_items:
+ attrs = model.attrib
+ sim_fit_state.model_list.append(attrs)
+
+ constraints = simfitstate_0.xpath('ns:constraints',
+ namespaces=CANSAS_NS)
+ constraint_list = constraints[0].xpath('ns:constraint',
+ namespaces=CANSAS_NS)
+ for constraint in constraint_list:
+ attrs = constraint.attrib
+ sim_fit_state.constraints_list.append(attrs)
+
+ return sim_fit_state
+ else:
+ return None
+
+ def _parse_save_state_entry(self, dom):
+ """
+ Parse a SASentry
+
+ :param node: SASentry node
+
+ :return: Data1D/Data2D object
+
+ """
+ node = dom.xpath('ns:data_class', namespaces=CANSAS_NS)
+ return_value, _ = self._parse_entry(dom)
+ return return_value, _
+
+ def _read_cansas(self, path):
+ """
+ Load data and fitting information from a CanSAS XML file.
+
+ :param path: file path
+ :return: Data1D object if a single SASentry was found,
+ or a list of Data1D objects if multiple entries were found,
+ or None of nothing was found
+ :raise RuntimeError: when the file can't be opened
+ :raise ValueError: when the length of the data vectors are inconsistent
+ """
+ output = []
+ simfitstate = None
+ basename = os.path.basename(path)
+ root, extension = os.path.splitext(basename)
+ ext = extension.lower()
+ try:
+ if os.path.isfile(path):
+ if ext in self.ext or ext == '.xml':
+ tree = etree.parse(path, parser=etree.ETCompatXMLParser())
+ # Check the format version number
+ # Specifying the namespace will take care of the file
+ # format version
+ root = tree.getroot()
+ entry_list = root.xpath('ns:SASentry',
+ namespaces=CANSAS_NS)
+ for entry in entry_list:
+ fitstate = self._parse_state(entry)
+ # state could be None when .svs file is loaded
+ # in this case, skip appending to output
+ if fitstate is not None:
+ try:
+ sas_entry, _ = self._parse_save_state_entry(
+ entry)
+ except:
+ raise
+ sas_entry.meta_data['fitstate'] = fitstate
+ sas_entry.filename = fitstate.file
+ output.append(sas_entry)
+
+ else:
+ self.call_back(format=ext)
+ raise RuntimeError("%s is not a file" % path)
+
+ # Return output consistent with the loader's api
+ if len(output) == 0:
+ self.call_back(state=None, datainfo=None, format=ext)
+ return None
+ else:
+ for data in output:
+ # Call back to post the new state
+ state = data.meta_data['fitstate']
+ t = time.localtime(state.timestamp)
+ time_str = time.strftime("%b %d %H:%M", t)
+ # Check that no time stamp is already appended
+ max_char = state.file.find("[")
+ if max_char < 0:
+ max_char = len(state.file)
+ original_fname = state.file[0:max_char]
+ state.file = original_fname + ' [' + time_str + ']'
+
+ if state is not None and state.is_data is not None:
+ data.is_data = state.is_data
+
+ data.filename = state.file
+ state.data = data
+ state.data.name = data.filename # state.data_name
+ state.data.id = state.data_id
+ if state.is_data is not None:
+ state.data.is_data = state.is_data
+ if data.run_name is not None and len(data.run_name) != 0:
+ if isinstance(data.run_name, dict):
+ # Note: key order in dict is not guaranteed, so sort
+ name = data.run_name.keys()[0]
+ else:
+ name = data.run_name
+ else:
+ name = original_fname
+ state.data.group_id = name
+ state.version = fitstate.version
+ # store state in fitting
+ self.call_back(state=state, datainfo=data, format=ext)
+ self.state = state
+ simfitstate = self._parse_simfit_state(entry)
+ if simfitstate is not None:
+ self.call_back(state=simfitstate)
+
+ return output
+ except:
+ self.call_back(format=ext)
+ raise
+
+ def write(self, filename, datainfo=None, fitstate=None):
+ """
+ Write the content of a Data1D as a CanSAS XML file only for standalone
+
+ :param filename: name of the file to write
+ :param datainfo: Data1D object
+ :param fitstate: PageState object
+
+ """
+ # Sanity check
+ if self.cansas:
+ # Add fitting information to the XML document
+ doc = self.write_toXML(datainfo, fitstate)
+ # Write the XML document
+ else:
+ doc = fitstate.to_xml(file=filename)
+
+ # Save the document no matter the type
+ fd = open(filename, 'w')
+ fd.write(doc.toprettyxml())
+ fd.close()
+
+ def write_toXML(self, datainfo=None, state=None, batchfit=None):
+ """
+ Write toXML, a helper for write(),
+ could be used by guimanager._on_save()
+
+ : return: xml doc
+ """
+
+ self.batchfit_params = batchfit
+ if state.data is None or not state.data.is_data:
+ return None
+ # make sure title and data run are filled.
+ if state.data.title is None or state.data.title == '':
+ state.data.title = state.data.name
+ if state.data.run_name is None or state.data.run_name == {}:
+ state.data.run = [str(state.data.name)]
+ state.data.run_name[0] = state.data.name
+
+ data = state.data
+ doc, sasentry = self._to_xml_doc(data)
+
+ if state is not None:
+ doc = state.to_xml(doc=doc, file=data.filename, entry_node=sasentry,
+ batch_fit_state=self.batchfit_params)
+
+ return doc
+
+# Simple html report template
+HEADER = "<html>\n"
+HEADER += "<head>\n"
+HEADER += "<meta http-equiv=Content-Type content='text/html; "
+HEADER += "charset=windows-1252'> \n"
+HEADER += "<meta name=Generator >\n"
+HEADER += "</head>\n"
+HEADER += "<body lang=EN-US>\n"
+HEADER += "<div class=WordSection1>\n"
+HEADER += "<p class=MsoNormal><b><span ><center><font size='4' >"
+HEADER += "%s</font></center></span></center></b></p>"
+HEADER += "<p class=MsoNormal> </p>"
+PARA = "<p class=MsoNormal><font size='4' > %s \n"
+PARA += "</font></p>"
+CENTRE = "<p class=MsoNormal><center><font size='4' > %s \n"
+CENTRE += "</font></center></p>"
+FEET_1 = \
+"""
+<p class=MsoNormal> </p>
+<br>
+<p class=MsoNormal><b><span ><center> <font size='4' > Graph
+</font></span></center></b></p>
+<p class=MsoNormal> </p>
+<center>
+<br><font size='4' >Model Computation</font>
+<br><font size='4' >Data: "%s"</font><br>
+"""
+FEET_2 = \
+"""<img src="%s" ></img>
+"""
+FEET_3 = \
+"""</center>
+</div>
+</body>
+</html>
+"""
+ELINE = """<p class=MsoNormal> </p>
+"""
diff --git a/src/sas/sascalc/fit/pluginmodel.py b/src/sas/sascalc/fit/pluginmodel.py
index fe29f65..b547d06 100644
--- a/src/sas/sascalc/fit/pluginmodel.py
+++ b/src/sas/sascalc/fit/pluginmodel.py
@@ -34,7 +34,7 @@ class Model1DPlugin(BaseComponent):
y_val = x[0]*math.sin(x[1])
return self.function(x_val)*self.function(y_val)
elif x.__class__.__name__ == 'tuple':
- raise ValueError, "Tuples are not allowed as input to BaseComponent models"
+ raise ValueError("Tuples are not allowed as input to BaseComponent models")
else:
return self.function(x)
@@ -51,7 +51,7 @@ class Model1DPlugin(BaseComponent):
if x.__class__.__name__ == 'list':
return self.function(x[0])*self.function(x[1])
elif x.__class__.__name__ == 'tuple':
- raise ValueError, "Tuples are not allowed as input to BaseComponent models"
+ raise ValueError("Tuples are not allowed as input to BaseComponent models")
else:
return self.function(x)
diff --git a/src/sas/sascalc/data_util/qsmearing.py b/src/sas/sascalc/fit/qsmearing.py
similarity index 89%
rename from src/sas/sascalc/data_util/qsmearing.py
rename to src/sas/sascalc/fit/qsmearing.py
index 938b6c5..fa6cd76 100644
--- a/src/sas/sascalc/data_util/qsmearing.py
+++ b/src/sas/sascalc/fit/qsmearing.py
@@ -4,11 +4,10 @@
#####################################################################
#This software was developed by the University of Tennessee as part of the
#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
-#project funded by the US National Science Foundation.
+#project funded by the US National Science Foundation.
#See the license text in license.txt
#copyright 2008, University of Tennessee
######################################################################
-import numpy
import math
import logging
import sys
@@ -19,7 +18,8 @@ from numpy import pi, exp # type:ignore
from sasmodels.resolution import Slit1D, Pinhole1D
from sasmodels.sesans import SesansTransform
from sasmodels.resolution2d import Pinhole2D
-from .nxsunit import Converter
+
+from sas.sascalc.data_util.nxsunit import Converter
def smear_selection(data, model = None):
"""
@@ -42,9 +42,9 @@ def smear_selection(data, model = None):
# object, just return None
# This checks for 2D data (does not throw exception because fail is common)
if data.__class__.__name__ not in ['Data1D', 'Theory1D']:
- if data == None:
+ if data is None:
return None
- elif data.dqx_data == None or data.dqy_data == None:
+ elif data.dqx_data is None or data.dqy_data is None:
return None
return PySmear2D(data)
# This checks for 1D data with smearing info in the data itself (again, fail is likely; no exceptions)
@@ -59,19 +59,24 @@ def smear_selection(data, model = None):
#if data.dx is not None and data.meta_data['loader']=='SESANS':
if data.dx is not None and data.isSesans:
#if data.dx[0] > 0.0:
- if numpy.size(data.dx[data.dx <= 0]) == 0:
+ if np.size(data.dx[data.dx <= 0]) == 0:
_found_sesans = True
# if data.dx[0] <= 0.0:
- if numpy.size(data.dx[data.dx <= 0]) > 0:
+ if np.size(data.dx[data.dx <= 0]) > 0:
raise ValueError('one or more of your dx values are negative, please check the data file!')
- if _found_sesans == True:
- #Pre-compute the Hankel matrix (H)
- qmax, qunits = data.sample.zacceptance
+ if _found_sesans:
+ # Pre-compute the Hankel matrix (H)
SElength = Converter(data._xunit)(data.x, "A")
- zaccept = Converter(qunits)(qmax, "1/A"),
+
+ theta_max = Converter("radians")(data.sample.zacceptance)[0]
+ q_max = 2 * np.pi / np.max(data.source.wavelength) * np.sin(theta_max)
+ zaccept = Converter("1/A")(q_max, "1/" + data.source.wavelength_unit),
+
Rmax = 10000000
- hankel = SesansTransform(data.x, SElength, zaccept, Rmax)
+ hankel = SesansTransform(data.x, SElength,
+ data.source.wavelength,
+ zaccept, Rmax)
# Then return the actual transform, as if it were a smearing function
return PySmear(hankel, model, offset=0)
@@ -120,7 +125,7 @@ class PySmear(object):
self.model = model
self.resolution = resolution
if offset is None:
- offset = numpy.searchsorted(self.resolution.q_calc, self.resolution.q[0])
+ offset = np.searchsorted(self.resolution.q_calc, self.resolution.q[0])
self.offset = offset
def apply(self, iq_in, first_bin=0, last_bin=None):
@@ -136,7 +141,7 @@ class PySmear(object):
if last_bin is None: last_bin = len(iq_in)
start, end = first_bin + self.offset, last_bin + self.offset
q_calc = self.resolution.q_calc
- iq_calc = numpy.empty_like(q_calc)
+ iq_calc = np.empty_like(q_calc)
if start > 0:
iq_calc[:start] = self.model.evalDistribution(q_calc[:start])
if end+1 < len(q_calc):
@@ -156,8 +161,8 @@ class PySmear(object):
q[first:last+1].
"""
q = self.resolution.q
- first = numpy.searchsorted(q, q_min)
- last = numpy.searchsorted(q, q_max)
+ first = np.searchsorted(q, q_min)
+ last = np.searchsorted(q, q_max)
return first, min(last,len(q)-1)
def slit_smear(data, model=None):
diff --git a/src/sas/sascalc/invariant/invariant.py b/src/sas/sascalc/invariant/invariant.py
index 13d53f7..0a9a992 100644
--- a/src/sas/sascalc/invariant/invariant.py
+++ b/src/sas/sascalc/invariant/invariant.py
@@ -1,962 +1,962 @@
-# pylint: disable=invalid-name
-#####################################################################
-#This software was developed by the University of Tennessee as part of the
-#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
-#project funded by the US National Science Foundation.
-#See the license text in license.txt
-#copyright 2010, University of Tennessee
-######################################################################
-
-"""
-This module implements invariant and its related computations.
-
-:author: Gervaise B. Alina/UTK
-:author: Mathieu Doucet/UTK
-:author: Jae Cho/UTK
-
-"""
-import math
-import numpy
-
-from sas.sascalc.dataloader.data_info import Data1D as LoaderData1D
-
-# The minimum q-value to be used when extrapolating
-Q_MINIMUM = 1e-5
-
-# The maximum q-value to be used when extrapolating
-Q_MAXIMUM = 10
-
-# Number of steps in the extrapolation
-INTEGRATION_NSTEPS = 1000
-
-class Transform(object):
- """
- Define interface that need to compute a function or an inverse
- function given some x, y
- """
-
- def linearize_data(self, data):
- """
- Linearize data so that a linear fit can be performed.
- Filter out the data that can't be transformed.
-
- :param data: LoadData1D instance
-
- """
- # Check that the vector lengths are equal
- assert len(data.x) == len(data.y)
- if data.dy is not None:
- assert len(data.x) == len(data.dy)
- dy = data.dy
- else:
- dy = numpy.ones(len(data.y))
-
- # Transform the data
- data_points = zip(data.x, data.y, dy)
-
- output_points = [(self.linearize_q_value(p[0]),
- math.log(p[1]),
- p[2] / p[1]) for p in data_points if p[0] > 0 and \
- p[1] > 0 and p[2] > 0]
-
- x_out, y_out, dy_out = zip(*output_points)
-
- # Create Data1D object
- x_out = numpy.asarray(x_out)
- y_out = numpy.asarray(y_out)
- dy_out = numpy.asarray(dy_out)
- linear_data = LoaderData1D(x=x_out, y=y_out, dy=dy_out)
-
- return linear_data
-
- def get_allowed_bins(self, data):
- """
- Goes through the data points and returns a list of boolean values
- to indicate whether each points is allowed by the model or not.
-
- :param data: Data1D object
- """
- return [p[0] > 0 and p[1] > 0 and p[2] > 0 for p in zip(data.x, data.y,
- data.dy)]
-
- def linearize_q_value(self, value):
- """
- Transform the input q-value for linearization
- """
- return NotImplemented
-
- def extract_model_parameters(self, constant, slope, dconstant=0, dslope=0):
- """
- set private member
- """
- return NotImplemented
-
- def evaluate_model(self, x):
- """
- Returns an array f(x) values where f is the Transform function.
- """
- return NotImplemented
-
- def evaluate_model_errors(self, x):
- """
- Returns an array of I(q) errors
- """
- return NotImplemented
-
-class Guinier(Transform):
- """
- class of type Transform that performs operations related to guinier
- function
- """
- def __init__(self, scale=1, radius=60):
- Transform.__init__(self)
- self.scale = scale
- self.radius = radius
- ## Uncertainty of scale parameter
- self.dscale = 0
- ## Unvertainty of radius parameter
- self.dradius = 0
-
- def linearize_q_value(self, value):
- """
- Transform the input q-value for linearization
-
- :param value: q-value
-
- :return: q*q
- """
- return value * value
-
- def extract_model_parameters(self, constant, slope, dconstant=0, dslope=0):
- """
- assign new value to the scale and the radius
- """
- self.scale = math.exp(constant)
- if slope > 0:
- slope = 0.0
- self.radius = math.sqrt(-3 * slope)
- # Errors
- self.dscale = math.exp(constant) * dconstant
- if slope == 0.0:
- n_zero = -1.0e-24
- self.dradius = -3.0 / 2.0 / math.sqrt(-3 * n_zero) * dslope
- else:
- self.dradius = -3.0 / 2.0 / math.sqrt(-3 * slope) * dslope
-
- return [self.radius, self.scale], [self.dradius, self.dscale]
-
- def evaluate_model(self, x):
- """
- return F(x)= scale* e-((radius*x)**2/3)
- """
- return self._guinier(x)
-
- def evaluate_model_errors(self, x):
- """
- Returns the error on I(q) for the given array of q-values
-
- :param x: array of q-values
- """
- p1 = numpy.array([self.dscale * math.exp(-((self.radius * q) ** 2 / 3)) \
- for q in x])
- p2 = numpy.array([self.scale * math.exp(-((self.radius * q) ** 2 / 3))\
- * (-(q ** 2 / 3)) * 2 * self.radius * self.dradius for q in x])
- diq2 = p1 * p1 + p2 * p2
- return numpy.array([math.sqrt(err) for err in diq2])
-
- def _guinier(self, x):
- """
- Retrieve the guinier function after apply an inverse guinier function
- to x
- Compute a F(x) = scale* e-((radius*x)**2/3).
-
- :param x: a vector of q values
- :param scale: the scale value
- :param radius: the guinier radius value
-
- :return: F(x)
- """
- # transform the radius of coming from the inverse guinier function to a
- # a radius of a guinier function
- if self.radius <= 0:
- msg = "Rg expected positive value, but got %s" % self.radius
- raise ValueError(msg)
- value = numpy.array([math.exp(-((self.radius * i) ** 2 / 3)) for i in x])
- return self.scale * value
-
-class PowerLaw(Transform):
- """
- class of type transform that perform operation related to power_law
- function
- """
- def __init__(self, scale=1, power=4):
- Transform.__init__(self)
- self.scale = scale
- self.power = power
- self.dscale = 0.0
- self.dpower = 0.0
-
- def linearize_q_value(self, value):
- """
- Transform the input q-value for linearization
-
- :param value: q-value
-
- :return: log(q)
- """
- return math.log(value)
-
- def extract_model_parameters(self, constant, slope, dconstant=0, dslope=0):
- """
- Assign new value to the scale and the power
- """
- self.power = -slope
- self.scale = math.exp(constant)
-
- # Errors
- self.dscale = math.exp(constant) * dconstant
- self.dpower = -dslope
-
- return [self.power, self.scale], [self.dpower, self.dscale]
-
- def evaluate_model(self, x):
- """
- given a scale and a radius transform x, y using a power_law
- function
- """
- return self._power_law(x)
-
- def evaluate_model_errors(self, x):
- """
- Returns the error on I(q) for the given array of q-values
- :param x: array of q-values
- """
- p1 = numpy.array([self.dscale * math.pow(q, -self.power) for q in x])
- p2 = numpy.array([self.scale * self.power * math.pow(q, -self.power - 1)\
- * self.dpower for q in x])
- diq2 = p1 * p1 + p2 * p2
- return numpy.array([math.sqrt(err) for err in diq2])
-
- def _power_law(self, x):
- """
- F(x) = scale* (x)^(-power)
- when power= 4. the model is porod
- else power_law
- The model has three parameters: ::
- 1. x: a vector of q values
- 2. power: power of the function
- 3. scale : scale factor value
-
- :param x: array
- :return: F(x)
- """
- if self.power <= 0:
- msg = "Power_law function expected positive power,"
- msg += " but got %s" % self.power
- raise ValueError(msg)
- if self.scale <= 0:
- msg = "scale expected positive value, but got %s" % self.scale
- raise ValueError(msg)
-
- value = numpy.array([math.pow(i, -self.power) for i in x])
- return self.scale * value
-
-class Extrapolator(object):
- """
- Extrapolate I(q) distribution using a given model
- """
- def __init__(self, data, model=None):
- """
- Determine a and b given a linear equation y = ax + b
-
- If a model is given, it will be used to linearize the data before
- the extrapolation is performed. If None,
- a simple linear fit will be done.
-
- :param data: data containing x and y such as y = ax + b
- :param model: optional Transform object
- """
- self.data = data
- self.model = model
-
- # Set qmin as the lowest non-zero value
- self.qmin = Q_MINIMUM
- for q_value in self.data.x:
- if q_value > 0:
- self.qmin = q_value
- break
- self.qmax = max(self.data.x)
-
- def fit(self, power=None, qmin=None, qmax=None):
- """
- Fit data for y = ax + b return a and b
-
- :param power: a fixed, otherwise None
- :param qmin: Minimum Q-value
- :param qmax: Maximum Q-value
- """
- if qmin is None:
- qmin = self.qmin
- if qmax is None:
- qmax = self.qmax
-
- # Identify the bin range for the fit
- idx = (self.data.x >= qmin) & (self.data.x <= qmax)
-
- fx = numpy.zeros(len(self.data.x))
-
- # Uncertainty
- if type(self.data.dy) == numpy.ndarray and \
- len(self.data.dy) == len(self.data.x) and \
- numpy.all(self.data.dy > 0):
- sigma = self.data.dy
- else:
- sigma = numpy.ones(len(self.data.x))
-
- # Compute theory data f(x)
- fx[idx] = self.data.y[idx]
-
- # Linearize the data
- if self.model is not None:
- linearized_data = self.model.linearize_data(\
- LoaderData1D(self.data.x[idx],
- fx[idx],
- dy=sigma[idx]))
- else:
- linearized_data = LoaderData1D(self.data.x[idx],
- fx[idx],
- dy=sigma[idx])
-
- ##power is given only for function = power_law
- if power != None:
- sigma2 = linearized_data.dy * linearized_data.dy
- a = -(power)
- b = (numpy.sum(linearized_data.y / sigma2) \
- - a * numpy.sum(linearized_data.x / sigma2)) / numpy.sum(1.0 / sigma2)
-
-
- deltas = linearized_data.x * a + \
- numpy.ones(len(linearized_data.x)) * b - linearized_data.y
- residuals = numpy.sum(deltas * deltas / sigma2)
-
- err = math.fabs(residuals) / numpy.sum(1.0 / sigma2)
- return [a, b], [0, math.sqrt(err)]
- else:
- A = numpy.vstack([linearized_data.x / linearized_data.dy, 1.0 / linearized_data.dy]).T
- (p, residuals, _, _) = numpy.linalg.lstsq(A, linearized_data.y / linearized_data.dy)
-
- # Get the covariance matrix, defined as inv_cov = a_transposed * a
- err = numpy.zeros(2)
- try:
- inv_cov = numpy.dot(A.transpose(), A)
- cov = numpy.linalg.pinv(inv_cov)
- err_matrix = math.fabs(residuals) * cov
- err = [math.sqrt(err_matrix[0][0]), math.sqrt(err_matrix[1][1])]
- except:
- err = [-1.0, -1.0]
-
- return p, err
-
-
-class InvariantCalculator(object):
- """
- Compute invariant if data is given.
- Can provide volume fraction and surface area if the user provides
- Porod constant and contrast values.
-
- :precondition: the user must send a data of type DataLoader.Data1D
- the user provide background and scale values.
-
- :note: Some computations depends on each others.
- """
- def __init__(self, data, background=0, scale=1):
- """
- Initialize variables.
-
- :param data: data must be of type DataLoader.Data1D
- :param background: Background value. The data will be corrected
- before processing
- :param scale: Scaling factor for I(q). The data will be corrected
- before processing
- """
- # Background and scale should be private data member if the only way to
- # change them are by instantiating a new object.
- self._background = background
- self._scale = scale
- # slit height for smeared data
- self._smeared = None
- # The data should be private
- self._data = self._get_data(data)
- # get the dxl if the data is smeared: This is done only once on init.
- if self._data.dxl != None and self._data.dxl.all() > 0:
- # assumes constant dxl
- self._smeared = self._data.dxl[0]
-
- # Since there are multiple variants of Q*, you should force the
- # user to use the get method and keep Q* a private data member
- self._qstar = None
-
- # You should keep the error on Q* so you can reuse it without
- # recomputing the whole thing.
- self._qstar_err = 0
-
- # Extrapolation parameters
- self._low_extrapolation_npts = 4
- self._low_extrapolation_function = Guinier()
- self._low_extrapolation_power = None
- self._low_extrapolation_power_fitted = None
-
- self._high_extrapolation_npts = 4
- self._high_extrapolation_function = PowerLaw()
- self._high_extrapolation_power = None
- self._high_extrapolation_power_fitted = None
-
- # Extrapolation range
- self._low_q_limit = Q_MINIMUM
-
- def _get_data(self, data):
- """
- :note: this function must be call before computing any type
- of invariant
-
- :return: new data = self._scale *data - self._background
- """
- if not issubclass(data.__class__, LoaderData1D):
- #Process only data that inherited from DataLoader.Data_info.Data1D
- raise ValueError, "Data must be of type DataLoader.Data1D"
- #from copy import deepcopy
- new_data = (self._scale * data) - self._background
-
- # Check that the vector lengths are equal
- assert len(new_data.x) == len(new_data.y)
-
- # Verify that the errors are set correctly
- if new_data.dy is None or len(new_data.x) != len(new_data.dy) or \
- (min(new_data.dy) == 0 and max(new_data.dy) == 0):
- new_data.dy = numpy.ones(len(new_data.x))
- return new_data
-
- def _fit(self, model, qmin=Q_MINIMUM, qmax=Q_MAXIMUM, power=None):
- """
- fit data with function using
- data = self._get_data()
- fx = Functor(data , function)
- y = data.y
- slope, constant = linalg.lstsq(y,fx)
-
- :param qmin: data first q value to consider during the fit
- :param qmax: data last q value to consider during the fit
- :param power : power value to consider for power-law
- :param function: the function to use during the fit
-
- :return a: the scale of the function
- :return b: the other parameter of the function for guinier will be radius
- for power_law will be the power value
- """
- extrapolator = Extrapolator(data=self._data, model=model)
- p, dp = extrapolator.fit(power=power, qmin=qmin, qmax=qmax)
-
- return model.extract_model_parameters(constant=p[1], slope=p[0],
- dconstant=dp[1], dslope=dp[0])
-
- def _get_qstar(self, data):
- """
- Compute invariant for pinhole data.
- This invariant is given by: ::
-
- q_star = x0**2 *y0 *dx0 +x1**2 *y1 *dx1
- + ..+ xn**2 *yn *dxn for non smeared data
-
- q_star = dxl0 *x0 *y0 *dx0 +dxl1 *x1 *y1 *dx1
- + ..+ dlxn *xn *yn *dxn for smeared data
-
- where n >= len(data.x)-1
- dxl = slit height dQl
- dxi = 1/2*(xi+1 - xi) + (xi - xi-1)
- dx0 = (x1 - x0)/2
- dxn = (xn - xn-1)/2
-
- :param data: the data to use to compute invariant.
-
- :return q_star: invariant value for pinhole data. q_star > 0
- """
- if len(data.x) <= 1 or len(data.y) <= 1 or len(data.x) != len(data.y):
- msg = "Length x and y must be equal"
- msg += " and greater than 1; got x=%s, y=%s" % (len(data.x), len(data.y))
- raise ValueError, msg
- else:
- # Take care of smeared data
- if self._smeared is None:
- gx = data.x * data.x
- # assumes that len(x) == len(dxl).
- else:
- gx = data.dxl * data.x
-
- n = len(data.x) - 1
- #compute the first delta q
- dx0 = (data.x[1] - data.x[0]) / 2
- #compute the last delta q
- dxn = (data.x[n] - data.x[n - 1]) / 2
- total = 0
- total += gx[0] * data.y[0] * dx0
- total += gx[n] * data.y[n] * dxn
-
- if len(data.x) == 2:
- return total
- else:
- #iterate between for element different
- #from the first and the last
- for i in xrange(1, n - 1):
- dxi = (data.x[i + 1] - data.x[i - 1]) / 2
- total += gx[i] * data.y[i] * dxi
- return total
-
- def _get_qstar_uncertainty(self, data):
- """
- Compute invariant uncertainty with with pinhole data.
- This uncertainty is given as follow: ::
-
- dq_star = math.sqrt[(x0**2*(dy0)*dx0)**2 +
- (x1**2 *(dy1)*dx1)**2 + ..+ (xn**2 *(dyn)*dxn)**2 ]
- where n >= len(data.x)-1
- dxi = 1/2*(xi+1 - xi) + (xi - xi-1)
- dx0 = (x1 - x0)/2
- dxn = (xn - xn-1)/2
- dyn: error on dy
-
- :param data:
- :note: if data doesn't contain dy assume dy= math.sqrt(data.y)
- """
- if len(data.x) <= 1 or len(data.y) <= 1 or \
- len(data.x) != len(data.y) or \
- (data.dy is not None and (len(data.dy) != len(data.y))):
- msg = "Length of data.x and data.y must be equal"
- msg += " and greater than 1; got x=%s, y=%s" % (len(data.x), len(data.y))
- raise ValueError, msg
- else:
- #Create error for data without dy error
- if data.dy is None:
- dy = math.sqrt(data.y)
- else:
- dy = data.dy
- # Take care of smeared data
- if self._smeared is None:
- gx = data.x * data.x
- # assumes that len(x) == len(dxl).
- else:
- gx = data.dxl * data.x
-
- n = len(data.x) - 1
- #compute the first delta
- dx0 = (data.x[1] - data.x[0]) / 2
- #compute the last delta
- dxn = (data.x[n] - data.x[n - 1]) / 2
- total = 0
- total += (gx[0] * dy[0] * dx0) ** 2
- total += (gx[n] * dy[n] * dxn) ** 2
- if len(data.x) == 2:
- return math.sqrt(total)
- else:
- #iterate between for element different
- #from the first and the last
- for i in xrange(1, n - 1):
- dxi = (data.x[i + 1] - data.x[i - 1]) / 2
- total += (gx[i] * dy[i] * dxi) ** 2
- return math.sqrt(total)
-
- def _get_extrapolated_data(self, model, npts=INTEGRATION_NSTEPS,
- q_start=Q_MINIMUM, q_end=Q_MAXIMUM):
- """
- :return: extrapolate data create from data
- """
- #create new Data1D to compute the invariant
- q = numpy.linspace(start=q_start,
- stop=q_end,
- num=npts,
- endpoint=True)
- iq = model.evaluate_model(q)
- diq = model.evaluate_model_errors(q)
-
- result_data = LoaderData1D(x=q, y=iq, dy=diq)
- if self._smeared != None:
- result_data.dxl = self._smeared * numpy.ones(len(q))
- return result_data
-
- def get_data(self):
- """
- :return: self._data
- """
- return self._data
-
- def get_extrapolation_power(self, range='high'):
- """
- :return: the fitted power for power law function for a given
- extrapolation range
- """
- if range == 'low':
- return self._low_extrapolation_power_fitted
- return self._high_extrapolation_power_fitted
-
- def get_qstar_low(self):
- """
- Compute the invariant for extrapolated data at low q range.
-
- Implementation:
- data = self._get_extra_data_low()
- return self._get_qstar()
-
- :return q_star: the invariant for data extrapolated at low q.
- """
- # Data boundaries for fitting
- qmin = self._data.x[0]
- qmax = self._data.x[self._low_extrapolation_npts - 1]
-
- # Extrapolate the low-Q data
- p, _ = self._fit(model=self._low_extrapolation_function,
- qmin=qmin,
- qmax=qmax,
- power=self._low_extrapolation_power)
- self._low_extrapolation_power_fitted = p[0]
-
- # Distribution starting point
- self._low_q_limit = Q_MINIMUM
- if Q_MINIMUM >= qmin:
- self._low_q_limit = qmin / 10
-
- data = self._get_extrapolated_data(\
- model=self._low_extrapolation_function,
- npts=INTEGRATION_NSTEPS,
- q_start=self._low_q_limit, q_end=qmin)
-
- # Systematic error
- # If we have smearing, the shape of the I(q) distribution at low Q will
- # may not be a Guinier or simple power law. The following is
- # a conservative estimation for the systematic error.
- err = qmin * qmin * math.fabs((qmin - self._low_q_limit) * \
- (data.y[0] - data.y[INTEGRATION_NSTEPS - 1]))
- return self._get_qstar(data), self._get_qstar_uncertainty(data) + err
-
- def get_qstar_high(self):
- """
- Compute the invariant for extrapolated data at high q range.
-
- Implementation:
- data = self._get_extra_data_high()
- return self._get_qstar()
-
- :return q_star: the invariant for data extrapolated at high q.
- """
- # Data boundaries for fitting
- x_len = len(self._data.x) - 1
- qmin = self._data.x[x_len - (self._high_extrapolation_npts - 1)]
- qmax = self._data.x[x_len]
-
- # fit the data with a model to get the appropriate parameters
- p, _ = self._fit(model=self._high_extrapolation_function,
- qmin=qmin,
- qmax=qmax,
- power=self._high_extrapolation_power)
- self._high_extrapolation_power_fitted = p[0]
-
- #create new Data1D to compute the invariant
- data = self._get_extrapolated_data(\
- model=self._high_extrapolation_function,
- npts=INTEGRATION_NSTEPS,
- q_start=qmax, q_end=Q_MAXIMUM)
-
- return self._get_qstar(data), self._get_qstar_uncertainty(data)
-
- def get_extra_data_low(self, npts_in=None, q_start=None, npts=20):
- """
- Returns the extrapolated data used for the loew-Q invariant calculation.
- By default, the distribution will cover the data points used for the
- extrapolation. The number of overlap points is a parameter (npts_in).
- By default, the maximum q-value of the distribution will be
- the minimum q-value used when extrapolating for the purpose of the
- invariant calculation.
-
- :param npts_in: number of data points for which
- the extrapolated data overlap
- :param q_start: is the minimum value to uses for extrapolated data
- :param npts: the number of points in the extrapolated distribution
-
- """
- # Get extrapolation range
- if q_start is None:
- q_start = self._low_q_limit
-
- if npts_in is None:
- npts_in = self._low_extrapolation_npts
- q_end = self._data.x[max(0, npts_in - 1)]
-
- if q_start >= q_end:
- return numpy.zeros(0), numpy.zeros(0)
-
- return self._get_extrapolated_data(\
- model=self._low_extrapolation_function,
- npts=npts,
- q_start=q_start, q_end=q_end)
-
- def get_extra_data_high(self, npts_in=None, q_end=Q_MAXIMUM, npts=20):
- """
- Returns the extrapolated data used for the high-Q invariant calculation.
- By default, the distribution will cover the data points used for the
- extrapolation. The number of overlap points is a parameter (npts_in).
- By default, the maximum q-value of the distribution will be Q_MAXIMUM,
- the maximum q-value used when extrapolating for the purpose of the
- invariant calculation.
-
- :param npts_in: number of data points for which the
- extrapolated data overlap
- :param q_end: is the maximum value to uses for extrapolated data
- :param npts: the number of points in the extrapolated distribution
- """
- # Get extrapolation range
- if npts_in is None:
- npts_in = self._high_extrapolation_npts
- _npts = len(self._data.x)
- q_start = self._data.x[min(_npts, _npts - npts_in)]
-
- if q_start >= q_end:
- return numpy.zeros(0), numpy.zeros(0)
-
- return self._get_extrapolated_data(\
- model=self._high_extrapolation_function,
- npts=npts,
- q_start=q_start, q_end=q_end)
-
- def set_extrapolation(self, range, npts=4, function=None, power=None):
- """
- Set the extrapolation parameters for the high or low Q-range.
- Note that this does not turn extrapolation on or off.
-
- :param range: a keyword set the type of extrapolation . type string
- :param npts: the numbers of q points of data to consider
- for extrapolation
- :param function: a keyword to select the function to use
- for extrapolation.
- of type string.
- :param power: an power to apply power_low function
-
- """
- range = range.lower()
- if range not in ['high', 'low']:
- raise ValueError, "Extrapolation range should be 'high' or 'low'"
- function = function.lower()
- if function not in ['power_law', 'guinier']:
- msg = "Extrapolation function should be 'guinier' or 'power_law'"
- raise ValueError, msg
-
- if range == 'high':
- if function != 'power_law':
- msg = "Extrapolation only allows a power law at high Q"
- raise ValueError, msg
- self._high_extrapolation_npts = npts
- self._high_extrapolation_power = power
- self._high_extrapolation_power_fitted = power
- else:
- if function == 'power_law':
- self._low_extrapolation_function = PowerLaw()
- else:
- self._low_extrapolation_function = Guinier()
- self._low_extrapolation_npts = npts
- self._low_extrapolation_power = power
- self._low_extrapolation_power_fitted = power
-
- def get_qstar(self, extrapolation=None):
- """
- Compute the invariant of the local copy of data.
-
- :param extrapolation: string to apply optional extrapolation
-
- :return q_star: invariant of the data within data's q range
-
- :warning: When using setting data to Data1D ,
- the user is responsible of
- checking that the scale and the background are
- properly apply to the data
-
- """
- self._qstar = self._get_qstar(self._data)
- self._qstar_err = self._get_qstar_uncertainty(self._data)
-
- if extrapolation is None:
- return self._qstar
-
- # Compute invariant plus invariant of extrapolated data
- extrapolation = extrapolation.lower()
- if extrapolation == "low":
- qs_low, dqs_low = self.get_qstar_low()
- qs_hi, dqs_hi = 0, 0
-
- elif extrapolation == "high":
- qs_low, dqs_low = 0, 0
- qs_hi, dqs_hi = self.get_qstar_high()
-
- elif extrapolation == "both":
- qs_low, dqs_low = self.get_qstar_low()
- qs_hi, dqs_hi = self.get_qstar_high()
-
- self._qstar += qs_low + qs_hi
- self._qstar_err = math.sqrt(self._qstar_err * self._qstar_err \
- + dqs_low * dqs_low + dqs_hi * dqs_hi)
-
- return self._qstar
-
- def get_surface(self, contrast, porod_const, extrapolation=None):
- """
- Compute the specific surface from the data.
-
- Implementation::
-
- V = self.get_volume_fraction(contrast, extrapolation)
-
- Compute the surface given by:
- surface = (2*pi *V(1- V)*porod_const)/ q_star
-
- :param contrast: contrast value to compute the volume
- :param porod_const: Porod constant to compute the surface
- :param extrapolation: string to apply optional extrapolation
-
- :return: specific surface
- """
- # Compute the volume
- volume = self.get_volume_fraction(contrast, extrapolation)
- return 2 * math.pi * volume * (1 - volume) * \
- float(porod_const) / self._qstar
-
- def get_volume_fraction(self, contrast, extrapolation=None):
- """
- Compute volume fraction is deduced as follow: ::
-
- q_star = 2*(pi*contrast)**2* volume( 1- volume)
- for k = 10^(-8)*q_star/(2*(pi*|contrast|)**2)
- we get 2 values of volume:
- with 1 - 4 * k >= 0
- volume1 = (1- sqrt(1- 4*k))/2
- volume2 = (1+ sqrt(1- 4*k))/2
-
- q_star: the invariant value included extrapolation is applied
- unit 1/A^(3)*1/cm
- q_star = self.get_qstar()
-
- the result returned will be 0 <= volume <= 1
-
- :param contrast: contrast value provides by the user of type float.
- contrast unit is 1/A^(2)= 10^(16)cm^(2)
- :param extrapolation: string to apply optional extrapolation
-
- :return: volume fraction
-
- :note: volume fraction must have no unit
- """
- if contrast <= 0:
- raise ValueError, "The contrast parameter must be greater than zero"
-
- # Make sure Q star is up to date
- self.get_qstar(extrapolation)
-
- if self._qstar <= 0:
- msg = "Invalid invariant: Invariant Q* must be greater than zero"
- raise RuntimeError, msg
-
- # Compute intermediate constant
- k = 1.e-8 * self._qstar / (2 * (math.pi * math.fabs(float(contrast))) ** 2)
- # Check discriminant value
- discrim = 1 - 4 * k
-
- # Compute volume fraction
- if discrim < 0:
- msg = "Could not compute the volume fraction: negative discriminant"
- raise RuntimeError, msg
- elif discrim == 0:
- return 1 / 2
- else:
- volume1 = 0.5 * (1 - math.sqrt(discrim))
- volume2 = 0.5 * (1 + math.sqrt(discrim))
-
- if 0 <= volume1 and volume1 <= 1:
- return volume1
- elif 0 <= volume2 and volume2 <= 1:
- return volume2
- msg = "Could not compute the volume fraction: inconsistent results"
- raise RuntimeError, msg
-
- def get_qstar_with_error(self, extrapolation=None):
- """
- Compute the invariant uncertainty.
- This uncertainty computation depends on whether or not the data is
- smeared.
-
- :param extrapolation: string to apply optional extrapolation
-
- :return: invariant, the invariant uncertainty
- """
- self.get_qstar(extrapolation)
- return self._qstar, self._qstar_err
-
- def get_volume_fraction_with_error(self, contrast, extrapolation=None):
- """
- Compute uncertainty on volume value as well as the volume fraction
- This uncertainty is given by the following equation: ::
-
- dV = 0.5 * (4*k* dq_star) /(2* math.sqrt(1-k* q_star))
-
- for k = 10^(-8)*q_star/(2*(pi*|contrast|)**2)
-
- q_star: the invariant value including extrapolated value if existing
- dq_star: the invariant uncertainty
- dV: the volume uncertainty
-
- The uncertainty will be set to -1 if it can't be computed.
-
- :param contrast: contrast value
- :param extrapolation: string to apply optional extrapolation
-
- :return: V, dV = volume fraction, error on volume fraction
- """
- volume = self.get_volume_fraction(contrast, extrapolation)
-
- # Compute error
- k = 1.e-8 * self._qstar / (2 * (math.pi * math.fabs(float(contrast))) ** 2)
- # Check value inside the sqrt function
- value = 1 - k * self._qstar
- if (value) <= 0:
- uncertainty = -1
- # Compute uncertainty
- uncertainty = math.fabs((0.5 * 4 * k * \
- self._qstar_err) / (2 * math.sqrt(1 - k * self._qstar)))
-
- return volume, uncertainty
-
- def get_surface_with_error(self, contrast, porod_const, extrapolation=None):
- """
- Compute uncertainty of the surface value as well as the surface value.
- The uncertainty is given as follow: ::
-
- dS = porod_const *2*pi[( dV -2*V*dV)/q_star
- + dq_star(v-v**2)
-
- q_star: the invariant value
- dq_star: the invariant uncertainty
- V: the volume fraction value
- dV: the volume uncertainty
-
- :param contrast: contrast value
- :param porod_const: porod constant value
- :param extrapolation: string to apply optional extrapolation
-
- :return S, dS: the surface, with its uncertainty
- """
- # We get the volume fraction, with error
- # get_volume_fraction_with_error calls get_volume_fraction
- # get_volume_fraction calls get_qstar
- # which computes Qstar and dQstar
- v, dv = self.get_volume_fraction_with_error(contrast, extrapolation)
-
- s = self.get_surface(contrast=contrast, porod_const=porod_const,
- extrapolation=extrapolation)
- ds = porod_const * 2 * math.pi * ((dv - 2 * v * dv) / self._qstar\
- + self._qstar_err * (v - v ** 2))
-
- return s, ds
+# pylint: disable=invalid-name
+#####################################################################
+#This software was developed by the University of Tennessee as part of the
+#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
+#project funded by the US National Science Foundation.
+#See the license text in license.txt
+#copyright 2010, University of Tennessee
+######################################################################
+
+"""
+This module implements invariant and its related computations.
+
+:author: Gervaise B. Alina/UTK
+:author: Mathieu Doucet/UTK
+:author: Jae Cho/UTK
+
+"""
+import math
+import numpy as np
+
+from sas.sascalc.dataloader.data_info import Data1D as LoaderData1D
+
+# The minimum q-value to be used when extrapolating
+Q_MINIMUM = 1e-5
+
+# The maximum q-value to be used when extrapolating
+Q_MAXIMUM = 10
+
+# Number of steps in the extrapolation
+INTEGRATION_NSTEPS = 1000
+
+class Transform(object):
+ """
+ Define interface that need to compute a function or an inverse
+ function given some x, y
+ """
+
+ def linearize_data(self, data):
+ """
+ Linearize data so that a linear fit can be performed.
+ Filter out the data that can't be transformed.
+
+ :param data: LoadData1D instance
+
+ """
+ # Check that the vector lengths are equal
+ assert len(data.x) == len(data.y)
+ if data.dy is not None:
+ assert len(data.x) == len(data.dy)
+ dy = data.dy
+ else:
+ dy = np.ones(len(data.y))
+
+ # Transform the data
+ data_points = zip(data.x, data.y, dy)
+
+ output_points = [(self.linearize_q_value(p[0]),
+ math.log(p[1]),
+ p[2] / p[1]) for p in data_points if p[0] > 0 and \
+ p[1] > 0 and p[2] > 0]
+
+ x_out, y_out, dy_out = zip(*output_points)
+
+ # Create Data1D object
+ x_out = np.asarray(x_out)
+ y_out = np.asarray(y_out)
+ dy_out = np.asarray(dy_out)
+ linear_data = LoaderData1D(x=x_out, y=y_out, dy=dy_out)
+
+ return linear_data
+
+ def get_allowed_bins(self, data):
+ """
+ Goes through the data points and returns a list of boolean values
+ to indicate whether each points is allowed by the model or not.
+
+ :param data: Data1D object
+ """
+ return [p[0] > 0 and p[1] > 0 and p[2] > 0 for p in zip(data.x, data.y,
+ data.dy)]
+
+ def linearize_q_value(self, value):
+ """
+ Transform the input q-value for linearization
+ """
+ return NotImplemented
+
+ def extract_model_parameters(self, constant, slope, dconstant=0, dslope=0):
+ """
+ set private member
+ """
+ return NotImplemented
+
+ def evaluate_model(self, x):
+ """
+ Returns an array f(x) values where f is the Transform function.
+ """
+ return NotImplemented
+
+ def evaluate_model_errors(self, x):
+ """
+ Returns an array of I(q) errors
+ """
+ return NotImplemented
+
+class Guinier(Transform):
+ """
+ class of type Transform that performs operations related to guinier
+ function
+ """
+ def __init__(self, scale=1, radius=60):
+ Transform.__init__(self)
+ self.scale = scale
+ self.radius = radius
+ ## Uncertainty of scale parameter
+ self.dscale = 0
+ ## Unvertainty of radius parameter
+ self.dradius = 0
+
+ def linearize_q_value(self, value):
+ """
+ Transform the input q-value for linearization
+
+ :param value: q-value
+
+ :return: q*q
+ """
+ return value * value
+
+ def extract_model_parameters(self, constant, slope, dconstant=0, dslope=0):
+ """
+ assign new value to the scale and the radius
+ """
+ self.scale = math.exp(constant)
+ if slope > 0:
+ slope = 0.0
+ self.radius = math.sqrt(-3 * slope)
+ # Errors
+ self.dscale = math.exp(constant) * dconstant
+ if slope == 0.0:
+ n_zero = -1.0e-24
+ self.dradius = -3.0 / 2.0 / math.sqrt(-3 * n_zero) * dslope
+ else:
+ self.dradius = -3.0 / 2.0 / math.sqrt(-3 * slope) * dslope
+
+ return [self.radius, self.scale], [self.dradius, self.dscale]
+
+ def evaluate_model(self, x):
+ """
+ return F(x)= scale* e-((radius*x)**2/3)
+ """
+ return self._guinier(x)
+
+ def evaluate_model_errors(self, x):
+ """
+ Returns the error on I(q) for the given array of q-values
+
+ :param x: array of q-values
+ """
+ p1 = np.array([self.dscale * math.exp(-((self.radius * q) ** 2 / 3)) \
+ for q in x])
+ p2 = np.array([self.scale * math.exp(-((self.radius * q) ** 2 / 3))\
+ * (-(q ** 2 / 3)) * 2 * self.radius * self.dradius for q in x])
+ diq2 = p1 * p1 + p2 * p2
+ return np.array([math.sqrt(err) for err in diq2])
+
+ def _guinier(self, x):
+ """
+ Retrieve the guinier function after apply an inverse guinier function
+ to x
+ Compute a F(x) = scale* e-((radius*x)**2/3).
+
+ :param x: a vector of q values
+ :param scale: the scale value
+ :param radius: the guinier radius value
+
+ :return: F(x)
+ """
+ # transform the radius of coming from the inverse guinier function to a
+ # a radius of a guinier function
+ if self.radius <= 0:
+ msg = "Rg expected positive value, but got %s" % self.radius
+ raise ValueError(msg)
+ value = np.array([math.exp(-((self.radius * i) ** 2 / 3)) for i in x])
+ return self.scale * value
+
+class PowerLaw(Transform):
+ """
+ class of type transform that perform operation related to power_law
+ function
+ """
+ def __init__(self, scale=1, power=4):
+ Transform.__init__(self)
+ self.scale = scale
+ self.power = power
+ self.dscale = 0.0
+ self.dpower = 0.0
+
+ def linearize_q_value(self, value):
+ """
+ Transform the input q-value for linearization
+
+ :param value: q-value
+
+ :return: log(q)
+ """
+ return math.log(value)
+
+ def extract_model_parameters(self, constant, slope, dconstant=0, dslope=0):
+ """
+ Assign new value to the scale and the power
+ """
+ self.power = -slope
+ self.scale = math.exp(constant)
+
+ # Errors
+ self.dscale = math.exp(constant) * dconstant
+ self.dpower = -dslope
+
+ return [self.power, self.scale], [self.dpower, self.dscale]
+
+ def evaluate_model(self, x):
+ """
+ given a scale and a radius transform x, y using a power_law
+ function
+ """
+ return self._power_law(x)
+
+ def evaluate_model_errors(self, x):
+ """
+ Returns the error on I(q) for the given array of q-values
+ :param x: array of q-values
+ """
+ p1 = np.array([self.dscale * math.pow(q, -self.power) for q in x])
+ p2 = np.array([self.scale * self.power * math.pow(q, -self.power - 1)\
+ * self.dpower for q in x])
+ diq2 = p1 * p1 + p2 * p2
+ return np.array([math.sqrt(err) for err in diq2])
+
+ def _power_law(self, x):
+ """
+ F(x) = scale* (x)^(-power)
+ when power= 4. the model is porod
+ else power_law
+ The model has three parameters: ::
+ 1. x: a vector of q values
+ 2. power: power of the function
+ 3. scale : scale factor value
+
+ :param x: array
+ :return: F(x)
+ """
+ if self.power <= 0:
+ msg = "Power_law function expected positive power,"
+ msg += " but got %s" % self.power
+ raise ValueError(msg)
+ if self.scale <= 0:
+ msg = "scale expected positive value, but got %s" % self.scale
+ raise ValueError(msg)
+
+ value = np.array([math.pow(i, -self.power) for i in x])
+ return self.scale * value
+
+class Extrapolator(object):
+ """
+ Extrapolate I(q) distribution using a given model
+ """
+ def __init__(self, data, model=None):
+ """
+ Determine a and b given a linear equation y = ax + b
+
+ If a model is given, it will be used to linearize the data before
+ the extrapolation is performed. If None,
+ a simple linear fit will be done.
+
+ :param data: data containing x and y such as y = ax + b
+ :param model: optional Transform object
+ """
+ self.data = data
+ self.model = model
+
+ # Set qmin as the lowest non-zero value
+ self.qmin = Q_MINIMUM
+ for q_value in self.data.x:
+ if q_value > 0:
+ self.qmin = q_value
+ break
+ self.qmax = max(self.data.x)
+
+ def fit(self, power=None, qmin=None, qmax=None):
+ """
+ Fit data for y = ax + b return a and b
+
+ :param power: a fixed, otherwise None
+ :param qmin: Minimum Q-value
+ :param qmax: Maximum Q-value
+ """
+ if qmin is None:
+ qmin = self.qmin
+ if qmax is None:
+ qmax = self.qmax
+
+ # Identify the bin range for the fit
+ idx = (self.data.x >= qmin) & (self.data.x <= qmax)
+
+ fx = np.zeros(len(self.data.x))
+
+ # Uncertainty
+ if type(self.data.dy) == np.ndarray and \
+ len(self.data.dy) == len(self.data.x) and \
+ np.all(self.data.dy > 0):
+ sigma = self.data.dy
+ else:
+ sigma = np.ones(len(self.data.x))
+
+ # Compute theory data f(x)
+ fx[idx] = self.data.y[idx]
+
+ # Linearize the data
+ if self.model is not None:
+ linearized_data = self.model.linearize_data(\
+ LoaderData1D(self.data.x[idx],
+ fx[idx],
+ dy=sigma[idx]))
+ else:
+ linearized_data = LoaderData1D(self.data.x[idx],
+ fx[idx],
+ dy=sigma[idx])
+
+ ##power is given only for function = power_law
+ if power is not None:
+ sigma2 = linearized_data.dy * linearized_data.dy
+ a = -(power)
+ b = (np.sum(linearized_data.y / sigma2) \
+ - a * np.sum(linearized_data.x / sigma2)) / np.sum(1.0 / sigma2)
+
+
+ deltas = linearized_data.x * a + \
+ np.ones(len(linearized_data.x)) * b - linearized_data.y
+ residuals = np.sum(deltas * deltas / sigma2)
+
+ err = math.fabs(residuals) / np.sum(1.0 / sigma2)
+ return [a, b], [0, math.sqrt(err)]
+ else:
+ A = np.vstack([linearized_data.x / linearized_data.dy, 1.0 / linearized_data.dy]).T
+ (p, residuals, _, _) = np.linalg.lstsq(A, linearized_data.y / linearized_data.dy)
+
+ # Get the covariance matrix, defined as inv_cov = a_transposed * a
+ err = np.zeros(2)
+ try:
+ inv_cov = np.dot(A.transpose(), A)
+ cov = np.linalg.pinv(inv_cov)
+ err_matrix = math.fabs(residuals) * cov
+ err = [math.sqrt(err_matrix[0][0]), math.sqrt(err_matrix[1][1])]
+ except:
+ err = [-1.0, -1.0]
+
+ return p, err
+
+
+class InvariantCalculator(object):
+ """
+ Compute invariant if data is given.
+ Can provide volume fraction and surface area if the user provides
+ Porod constant and contrast values.
+
+ :precondition: the user must send a data of type DataLoader.Data1D
+ the user provide background and scale values.
+
+ :note: Some computations depends on each others.
+ """
+ def __init__(self, data, background=0, scale=1):
+ """
+ Initialize variables.
+
+ :param data: data must be of type DataLoader.Data1D
+ :param background: Background value. The data will be corrected
+ before processing
+ :param scale: Scaling factor for I(q). The data will be corrected
+ before processing
+ """
+ # Background and scale should be private data member if the only way to
+ # change them are by instantiating a new object.
+ self._background = background
+ self._scale = scale
+ # slit height for smeared data
+ self._smeared = None
+ # The data should be private
+ self._data = self._get_data(data)
+ # get the dxl if the data is smeared: This is done only once on init.
+ if self._data.dxl is not None and self._data.dxl.all() > 0:
+ # assumes constant dxl
+ self._smeared = self._data.dxl[0]
+
+ # Since there are multiple variants of Q*, you should force the
+ # user to use the get method and keep Q* a private data member
+ self._qstar = None
+
+ # You should keep the error on Q* so you can reuse it without
+ # recomputing the whole thing.
+ self._qstar_err = 0
+
+ # Extrapolation parameters
+ self._low_extrapolation_npts = 4
+ self._low_extrapolation_function = Guinier()
+ self._low_extrapolation_power = None
+ self._low_extrapolation_power_fitted = None
+
+ self._high_extrapolation_npts = 4
+ self._high_extrapolation_function = PowerLaw()
+ self._high_extrapolation_power = None
+ self._high_extrapolation_power_fitted = None
+
+ # Extrapolation range
+ self._low_q_limit = Q_MINIMUM
+
+ def _get_data(self, data):
+ """
+ :note: this function must be call before computing any type
+ of invariant
+
+ :return: new data = self._scale *data - self._background
+ """
+ if not issubclass(data.__class__, LoaderData1D):
+ #Process only data that inherited from DataLoader.Data_info.Data1D
+ raise ValueError("Data must be of type DataLoader.Data1D")
+ #from copy import deepcopy
+ new_data = (self._scale * data) - self._background
+
+ # Check that the vector lengths are equal
+ assert len(new_data.x) == len(new_data.y)
+
+ # Verify that the errors are set correctly
+ if new_data.dy is None or len(new_data.x) != len(new_data.dy) or \
+ (min(new_data.dy) == 0 and max(new_data.dy) == 0):
+ new_data.dy = np.ones(len(new_data.x))
+ return new_data
+
+ def _fit(self, model, qmin=Q_MINIMUM, qmax=Q_MAXIMUM, power=None):
+ """
+ fit data with function using
+ data = self._get_data()
+ fx = Functor(data , function)
+ y = data.y
+ slope, constant = linalg.lstsq(y,fx)
+
+ :param qmin: data first q value to consider during the fit
+ :param qmax: data last q value to consider during the fit
+ :param power : power value to consider for power-law
+ :param function: the function to use during the fit
+
+ :return a: the scale of the function
+ :return b: the other parameter of the function for guinier will be radius
+ for power_law will be the power value
+ """
+ extrapolator = Extrapolator(data=self._data, model=model)
+ p, dp = extrapolator.fit(power=power, qmin=qmin, qmax=qmax)
+
+ return model.extract_model_parameters(constant=p[1], slope=p[0],
+ dconstant=dp[1], dslope=dp[0])
+
+ def _get_qstar(self, data):
+ """
+ Compute invariant for pinhole data.
+ This invariant is given by: ::
+
+ q_star = x0**2 *y0 *dx0 +x1**2 *y1 *dx1
+ + ..+ xn**2 *yn *dxn for non smeared data
+
+ q_star = dxl0 *x0 *y0 *dx0 +dxl1 *x1 *y1 *dx1
+ + ..+ dlxn *xn *yn *dxn for smeared data
+
+ where n >= len(data.x)-1
+ dxl = slit height dQl
+ dxi = 1/2*(xi+1 - xi) + (xi - xi-1)
+ dx0 = (x1 - x0)/2
+ dxn = (xn - xn-1)/2
+
+ :param data: the data to use to compute invariant.
+
+ :return q_star: invariant value for pinhole data. q_star > 0
+ """
+ if len(data.x) <= 1 or len(data.y) <= 1 or len(data.x) != len(data.y):
+ msg = "Length x and y must be equal"
+ msg += " and greater than 1; got x=%s, y=%s" % (len(data.x), len(data.y))
+ raise ValueError(msg)
+ else:
+ # Take care of smeared data
+ if self._smeared is None:
+ gx = data.x * data.x
+ # assumes that len(x) == len(dxl).
+ else:
+ gx = data.dxl * data.x
+
+ n = len(data.x) - 1
+ #compute the first delta q
+ dx0 = (data.x[1] - data.x[0]) / 2
+ #compute the last delta q
+ dxn = (data.x[n] - data.x[n - 1]) / 2
+ total = 0
+ total += gx[0] * data.y[0] * dx0
+ total += gx[n] * data.y[n] * dxn
+
+ if len(data.x) == 2:
+ return total
+ else:
+ #iterate between for element different
+ #from the first and the last
+ for i in range(1, n - 1):
+ dxi = (data.x[i + 1] - data.x[i - 1]) / 2
+ total += gx[i] * data.y[i] * dxi
+ return total
+
+ def _get_qstar_uncertainty(self, data):
+ """
+ Compute invariant uncertainty with with pinhole data.
+ This uncertainty is given as follow: ::
+
+ dq_star = math.sqrt[(x0**2*(dy0)*dx0)**2 +
+ (x1**2 *(dy1)*dx1)**2 + ..+ (xn**2 *(dyn)*dxn)**2 ]
+ where n >= len(data.x)-1
+ dxi = 1/2*(xi+1 - xi) + (xi - xi-1)
+ dx0 = (x1 - x0)/2
+ dxn = (xn - xn-1)/2
+ dyn: error on dy
+
+ :param data:
+ :note: if data doesn't contain dy assume dy= math.sqrt(data.y)
+ """
+ if len(data.x) <= 1 or len(data.y) <= 1 or \
+ len(data.x) != len(data.y) or \
+ (data.dy is not None and (len(data.dy) != len(data.y))):
+ msg = "Length of data.x and data.y must be equal"
+ msg += " and greater than 1; got x=%s, y=%s" % (len(data.x), len(data.y))
+ raise ValueError(msg)
+ else:
+ #Create error for data without dy error
+ if data.dy is None:
+ dy = math.sqrt(data.y)
+ else:
+ dy = data.dy
+ # Take care of smeared data
+ if self._smeared is None:
+ gx = data.x * data.x
+ # assumes that len(x) == len(dxl).
+ else:
+ gx = data.dxl * data.x
+
+ n = len(data.x) - 1
+ #compute the first delta
+ dx0 = (data.x[1] - data.x[0]) / 2
+ #compute the last delta
+ dxn = (data.x[n] - data.x[n - 1]) / 2
+ total = 0
+ total += (gx[0] * dy[0] * dx0) ** 2
+ total += (gx[n] * dy[n] * dxn) ** 2
+ if len(data.x) == 2:
+ return math.sqrt(total)
+ else:
+ #iterate between for element different
+ #from the first and the last
+ for i in range(1, n - 1):
+ dxi = (data.x[i + 1] - data.x[i - 1]) / 2
+ total += (gx[i] * dy[i] * dxi) ** 2
+ return math.sqrt(total)
+
+ def _get_extrapolated_data(self, model, npts=INTEGRATION_NSTEPS,
+ q_start=Q_MINIMUM, q_end=Q_MAXIMUM):
+ """
+ :return: extrapolate data create from data
+ """
+ #create new Data1D to compute the invariant
+ q = np.linspace(start=q_start,
+ stop=q_end,
+ num=npts,
+ endpoint=True)
+ iq = model.evaluate_model(q)
+ diq = model.evaluate_model_errors(q)
+
+ result_data = LoaderData1D(x=q, y=iq, dy=diq)
+ if self._smeared is not None:
+ result_data.dxl = self._smeared * np.ones(len(q))
+ return result_data
+
+ def get_data(self):
+ """
+ :return: self._data
+ """
+ return self._data
+
+ def get_extrapolation_power(self, range='high'):
+ """
+ :return: the fitted power for power law function for a given
+ extrapolation range
+ """
+ if range == 'low':
+ return self._low_extrapolation_power_fitted
+ return self._high_extrapolation_power_fitted
+
+ def get_qstar_low(self):
+ """
+ Compute the invariant for extrapolated data at low q range.
+
+ Implementation:
+ data = self._get_extra_data_low()
+ return self._get_qstar()
+
+ :return q_star: the invariant for data extrapolated at low q.
+ """
+ # Data boundaries for fitting
+ qmin = self._data.x[0]
+ qmax = self._data.x[int(self._low_extrapolation_npts - 1)]
+
+ # Extrapolate the low-Q data
+ p, _ = self._fit(model=self._low_extrapolation_function,
+ qmin=qmin,
+ qmax=qmax,
+ power=self._low_extrapolation_power)
+ self._low_extrapolation_power_fitted = p[0]
+
+ # Distribution starting point
+ self._low_q_limit = Q_MINIMUM
+ if Q_MINIMUM >= qmin:
+ self._low_q_limit = qmin / 10
+
+ data = self._get_extrapolated_data(\
+ model=self._low_extrapolation_function,
+ npts=INTEGRATION_NSTEPS,
+ q_start=self._low_q_limit, q_end=qmin)
+
+ # Systematic error
+ # If we have smearing, the shape of the I(q) distribution at low Q will
+ # may not be a Guinier or simple power law. The following is
+ # a conservative estimation for the systematic error.
+ err = qmin * qmin * math.fabs((qmin - self._low_q_limit) * \
+ (data.y[0] - data.y[INTEGRATION_NSTEPS - 1]))
+ return self._get_qstar(data), self._get_qstar_uncertainty(data) + err
+
+ def get_qstar_high(self):
+ """
+ Compute the invariant for extrapolated data at high q range.
+
+ Implementation:
+ data = self._get_extra_data_high()
+ return self._get_qstar()
+
+ :return q_star: the invariant for data extrapolated at high q.
+ """
+ # Data boundaries for fitting
+ x_len = len(self._data.x) - 1
+ qmin = self._data.x[int(x_len - (self._high_extrapolation_npts - 1))]
+ qmax = self._data.x[int(x_len)]
+
+ # fit the data with a model to get the appropriate parameters
+ p, _ = self._fit(model=self._high_extrapolation_function,
+ qmin=qmin,
+ qmax=qmax,
+ power=self._high_extrapolation_power)
+ self._high_extrapolation_power_fitted = p[0]
+
+ #create new Data1D to compute the invariant
+ data = self._get_extrapolated_data(\
+ model=self._high_extrapolation_function,
+ npts=INTEGRATION_NSTEPS,
+ q_start=qmax, q_end=Q_MAXIMUM)
+
+ return self._get_qstar(data), self._get_qstar_uncertainty(data)
+
+ def get_extra_data_low(self, npts_in=None, q_start=None, npts=20):
+ """
+ Returns the extrapolated data used for the loew-Q invariant calculation.
+ By default, the distribution will cover the data points used for the
+ extrapolation. The number of overlap points is a parameter (npts_in).
+ By default, the maximum q-value of the distribution will be
+ the minimum q-value used when extrapolating for the purpose of the
+ invariant calculation.
+
+ :param npts_in: number of data points for which
+ the extrapolated data overlap
+ :param q_start: is the minimum value to uses for extrapolated data
+ :param npts: the number of points in the extrapolated distribution
+
+ """
+ # Get extrapolation range
+ if q_start is None:
+ q_start = self._low_q_limit
+
+ if npts_in is None:
+ npts_in = self._low_extrapolation_npts
+ q_end = self._data.x[max(0, int(npts_in - 1))]
+
+ if q_start >= q_end:
+ return np.zeros(0), np.zeros(0)
+
+ return self._get_extrapolated_data(\
+ model=self._low_extrapolation_function,
+ npts=npts,
+ q_start=q_start, q_end=q_end)
+
+ def get_extra_data_high(self, npts_in=None, q_end=Q_MAXIMUM, npts=20):
+ """
+ Returns the extrapolated data used for the high-Q invariant calculation.
+ By default, the distribution will cover the data points used for the
+ extrapolation. The number of overlap points is a parameter (npts_in).
+ By default, the maximum q-value of the distribution will be Q_MAXIMUM,
+ the maximum q-value used when extrapolating for the purpose of the
+ invariant calculation.
+
+ :param npts_in: number of data points for which the
+ extrapolated data overlap
+ :param q_end: is the maximum value to uses for extrapolated data
+ :param npts: the number of points in the extrapolated distribution
+ """
+ # Get extrapolation range
+ if npts_in is None:
+ npts_in = int(self._high_extrapolation_npts)
+ _npts = len(self._data.x)
+ q_start = self._data.x[min(_npts, int(_npts - npts_in))]
+
+ if q_start >= q_end:
+ return np.zeros(0), np.zeros(0)
+
+ return self._get_extrapolated_data(\
+ model=self._high_extrapolation_function,
+ npts=npts,
+ q_start=q_start, q_end=q_end)
+
+ def set_extrapolation(self, range, npts=4, function=None, power=None):
+ """
+ Set the extrapolation parameters for the high or low Q-range.
+ Note that this does not turn extrapolation on or off.
+
+ :param range: a keyword set the type of extrapolation . type string
+ :param npts: the numbers of q points of data to consider
+ for extrapolation
+ :param function: a keyword to select the function to use
+ for extrapolation.
+ of type string.
+ :param power: an power to apply power_low function
+
+ """
+ range = range.lower()
+ if range not in ['high', 'low']:
+ raise ValueError("Extrapolation range should be 'high' or 'low'")
+ function = function.lower()
+ if function not in ['power_law', 'guinier']:
+ msg = "Extrapolation function should be 'guinier' or 'power_law'"
+ raise ValueError(msg)
+
+ if range == 'high':
+ if function != 'power_law':
+ msg = "Extrapolation only allows a power law at high Q"
+ raise ValueError(msg)
+ self._high_extrapolation_npts = npts
+ self._high_extrapolation_power = power
+ self._high_extrapolation_power_fitted = power
+ else:
+ if function == 'power_law':
+ self._low_extrapolation_function = PowerLaw()
+ else:
+ self._low_extrapolation_function = Guinier()
+ self._low_extrapolation_npts = npts
+ self._low_extrapolation_power = power
+ self._low_extrapolation_power_fitted = power
+
+ def get_qstar(self, extrapolation=None):
+ """
+ Compute the invariant of the local copy of data.
+
+ :param extrapolation: string to apply optional extrapolation
+
+ :return q_star: invariant of the data within data's q range
+
+ :warning: When using setting data to Data1D ,
+ the user is responsible of
+ checking that the scale and the background are
+ properly apply to the data
+
+ """
+ self._qstar = self._get_qstar(self._data)
+ self._qstar_err = self._get_qstar_uncertainty(self._data)
+
+ if extrapolation is None:
+ return self._qstar
+
+ # Compute invariant plus invariant of extrapolated data
+ extrapolation = extrapolation.lower()
+ if extrapolation == "low":
+ qs_low, dqs_low = self.get_qstar_low()
+ qs_hi, dqs_hi = 0, 0
+
+ elif extrapolation == "high":
+ qs_low, dqs_low = 0, 0
+ qs_hi, dqs_hi = self.get_qstar_high()
+
+ elif extrapolation == "both":
+ qs_low, dqs_low = self.get_qstar_low()
+ qs_hi, dqs_hi = self.get_qstar_high()
+
+ self._qstar += qs_low + qs_hi
+ self._qstar_err = math.sqrt(self._qstar_err * self._qstar_err \
+ + dqs_low * dqs_low + dqs_hi * dqs_hi)
+
+ return self._qstar
+
+ def get_surface(self, contrast, porod_const, extrapolation=None):
+ """
+ Compute the specific surface from the data.
+
+ Implementation::
+
+ V = self.get_volume_fraction(contrast, extrapolation)
+
+ Compute the surface given by:
+ surface = (2*pi *V(1- V)*porod_const)/ q_star
+
+ :param contrast: contrast value to compute the volume
+ :param porod_const: Porod constant to compute the surface
+ :param extrapolation: string to apply optional extrapolation
+
+ :return: specific surface
+ """
+ # Compute the volume
+ volume = self.get_volume_fraction(contrast, extrapolation)
+ return 2 * math.pi * volume * (1 - volume) * \
+ float(porod_const) / self._qstar
+
+ def get_volume_fraction(self, contrast, extrapolation=None):
+ """
+ Compute volume fraction is deduced as follow: ::
+
+ q_star = 2*(pi*contrast)**2* volume( 1- volume)
+ for k = 10^(-8)*q_star/(2*(pi*|contrast|)**2)
+ we get 2 values of volume:
+ with 1 - 4 * k >= 0
+ volume1 = (1- sqrt(1- 4*k))/2
+ volume2 = (1+ sqrt(1- 4*k))/2
+
+ q_star: the invariant value included extrapolation is applied
+ unit 1/A^(3)*1/cm
+ q_star = self.get_qstar()
+
+ the result returned will be 0 <= volume <= 1
+
+ :param contrast: contrast value provides by the user of type float.
+ contrast unit is 1/A^(2)= 10^(16)cm^(2)
+ :param extrapolation: string to apply optional extrapolation
+
+ :return: volume fraction
+
+ :note: volume fraction must have no unit
+ """
+ if contrast <= 0:
+ raise ValueError("The contrast parameter must be greater than zero")
+
+ # Make sure Q star is up to date
+ self.get_qstar(extrapolation)
+
+ if self._qstar <= 0:
+ msg = "Invalid invariant: Invariant Q* must be greater than zero"
+ raise RuntimeError(msg)
+
+ # Compute intermediate constant
+ k = 1.e-8 * self._qstar / (2 * (math.pi * math.fabs(float(contrast))) ** 2)
+ # Check discriminant value
+ discrim = 1 - 4 * k
+
+ # Compute volume fraction
+ if discrim < 0:
+ msg = "Could not compute the volume fraction: negative discriminant"
+ raise RuntimeError(msg)
+ elif discrim == 0:
+ return 1 / 2
+ else:
+ volume1 = 0.5 * (1 - math.sqrt(discrim))
+ volume2 = 0.5 * (1 + math.sqrt(discrim))
+
+ if 0 <= volume1 and volume1 <= 1:
+ return volume1
+ elif 0 <= volume2 and volume2 <= 1:
+ return volume2
+ msg = "Could not compute the volume fraction: inconsistent results"
+ raise RuntimeError(msg)
+
+ def get_qstar_with_error(self, extrapolation=None):
+ """
+ Compute the invariant uncertainty.
+ This uncertainty computation depends on whether or not the data is
+ smeared.
+
+ :param extrapolation: string to apply optional extrapolation
+
+ :return: invariant, the invariant uncertainty
+ """
+ self.get_qstar(extrapolation)
+ return self._qstar, self._qstar_err
+
+ def get_volume_fraction_with_error(self, contrast, extrapolation=None):
+ """
+ Compute uncertainty on volume value as well as the volume fraction
+ This uncertainty is given by the following equation: ::
+
+ dV = 0.5 * (4*k* dq_star) /(2* math.sqrt(1-k* q_star))
+
+ for k = 10^(-8)*q_star/(2*(pi*|contrast|)**2)
+
+ q_star: the invariant value including extrapolated value if existing
+ dq_star: the invariant uncertainty
+ dV: the volume uncertainty
+
+ The uncertainty will be set to -1 if it can't be computed.
+
+ :param contrast: contrast value
+ :param extrapolation: string to apply optional extrapolation
+
+ :return: V, dV = volume fraction, error on volume fraction
+ """
+ volume = self.get_volume_fraction(contrast, extrapolation)
+
+ # Compute error
+ k = 1.e-8 * self._qstar / (2 * (math.pi * math.fabs(float(contrast))) ** 2)
+ # Check value inside the sqrt function
+ value = 1 - k * self._qstar
+ if (value) <= 0:
+ uncertainty = -1
+ # Compute uncertainty
+ uncertainty = math.fabs((0.5 * 4 * k * \
+ self._qstar_err) / (2 * math.sqrt(1 - k * self._qstar)))
+
+ return volume, uncertainty
+
+ def get_surface_with_error(self, contrast, porod_const, extrapolation=None):
+ """
+ Compute uncertainty of the surface value as well as the surface value.
+ The uncertainty is given as follow: ::
+
+ dS = porod_const *2*pi[( dV -2*V*dV)/q_star
+ + dq_star(v-v**2)
+
+ q_star: the invariant value
+ dq_star: the invariant uncertainty
+ V: the volume fraction value
+ dV: the volume uncertainty
+
+ :param contrast: contrast value
+ :param porod_const: porod constant value
+ :param extrapolation: string to apply optional extrapolation
+
+ :return S, dS: the surface, with its uncertainty
+ """
+ # We get the volume fraction, with error
+ # get_volume_fraction_with_error calls get_volume_fraction
+ # get_volume_fraction calls get_qstar
+ # which computes Qstar and dQstar
+ v, dv = self.get_volume_fraction_with_error(contrast, extrapolation)
+
+ s = self.get_surface(contrast=contrast, porod_const=porod_const,
+ extrapolation=extrapolation)
+ ds = porod_const * 2 * math.pi * ((dv - 2 * v * dv) / self._qstar\
+ + self._qstar_err * (v - v ** 2))
+
+ return s, ds
diff --git a/src/sas/sascalc/invariant/invariant_mapper.py b/src/sas/sascalc/invariant/invariant_mapper.py
index 09d7446..2c7cda8 100644
--- a/src/sas/sascalc/invariant/invariant_mapper.py
+++ b/src/sas/sascalc/invariant/invariant_mapper.py
@@ -1,48 +1,48 @@
-"""
-This module is a wrapper to a map function. It allows to loop through
-different invariant objects to call the same function
-"""
-
-
-def get_qstar(inv, extrapolation=None):
- """
- Get invariant value (Q*)
- """
- return inv.get_qstar(extrapolation)
-
-def get_qstar_with_error(inv, extrapolation=None):
- """
- Get invariant value with uncertainty
- """
- return inv.get_qstar_with_error(extrapolation)
-
-def get_volume_fraction(inv, contrast, extrapolation=None):
- """
- Get volume fraction
- """
- return inv.get_volume_fraction(contrast, extrapolation)
-
-def get_volume_fraction_with_error(inv, contrast, extrapolation=None):
- """
- Get volume fraction with uncertainty
- """
- return inv.get_volume_fraction_with_error(contrast,
- extrapolation)
-
-def get_surface(inv, contrast, porod_const, extrapolation=None):
- """
- Get surface with uncertainty
- """
- return inv.get_surface(contrast=contrast,
- porod_const=porod_const,
- extrapolation=extrapolation)
-
-def get_surface_with_error(inv, contrast,
- porod_const, extrapolation=None):
- """
- Get surface with uncertainty
- """
- return inv.get_surface_with_error(contrast=contrast,
- porod_const=porod_const,
- extrapolation=extrapolation)
-
+"""
+This module is a wrapper to a map function. It allows to loop through
+different invariant objects to call the same function
+"""
+
+
+def get_qstar(inv, extrapolation=None):
+ """
+ Get invariant value (Q*)
+ """
+ return inv.get_qstar(extrapolation)
+
+def get_qstar_with_error(inv, extrapolation=None):
+ """
+ Get invariant value with uncertainty
+ """
+ return inv.get_qstar_with_error(extrapolation)
+
+def get_volume_fraction(inv, contrast, extrapolation=None):
+ """
+ Get volume fraction
+ """
+ return inv.get_volume_fraction(contrast, extrapolation)
+
+def get_volume_fraction_with_error(inv, contrast, extrapolation=None):
+ """
+ Get volume fraction with uncertainty
+ """
+ return inv.get_volume_fraction_with_error(contrast,
+ extrapolation)
+
+def get_surface(inv, contrast, porod_const, extrapolation=None):
+ """
+ Get surface with uncertainty
+ """
+ return inv.get_surface(contrast=contrast,
+ porod_const=porod_const,
+ extrapolation=extrapolation)
+
+def get_surface_with_error(inv, contrast,
+ porod_const, extrapolation=None):
+ """
+ Get surface with uncertainty
+ """
+ return inv.get_surface_with_error(contrast=contrast,
+ porod_const=porod_const,
+ extrapolation=extrapolation)
+
diff --git a/src/sas/sascalc/pr/__init__.py b/src/sas/sascalc/pr/__init__.py
index 5aeedce..c4e5ed5 100644
--- a/src/sas/sascalc/pr/__init__.py
+++ b/src/sas/sascalc/pr/__init__.py
@@ -1,106 +1,106 @@
-"""
- P(r) inversion for SAS
-"""
-## \mainpage P(r) inversion for SAS
-#
-# \section intro_sec Introduction
-# This module provides calculations to transform scattering intensity data
-# I(q) into distance distribution function P(r). A description of the
-# technique can be found elsewhere [1-5]. The module is useable as a
-# standalone application but its functionality is meant to be presented
-# to end-users through the user interface developed as part of the SAS
-# flagship application.
-#
-# Procedure: We will follow the procedure of Moore [1].
-#
-# [1] P.B. Moore, J.Appl. Cryst (1980) 13, 168-175.
-#
-# [2] O. Glatter, J.Appl. Cryst (1977) 10, 415-421.
-#
-# [3] D.I. Svergun, J.Appl. Cryst (1991) 24, 485-492.
-#
-# [4] D.I. Svergun, J.Appl. Cryst (1992) 25, 495-503.
-#
-# [5] S. Hansen and J. Skov Pedersen, J.Appl. Cryst (1991) 24, 541-548.
-#
-## \subsection class Class Diagram:
-# The following shows a partial class diagram with the main attributes
-# and methods of the invertor.
-#
-# \image html architecture.png
-#
-# \section install_sec Installation
-#
-# \subsection obtain Obtaining the Code
-#
-# The code is available here:
-# \verbatim
-#$ svn co svn://danse.us/sas/pr_inversion
-# \endverbatim
-#
-# \subsection depends External Dependencies
-# scipy, numpy
-#
-# \subsection build Building the code
-# The standard python package can be built with distutils.
-# \verbatim
-#$ python setup.py build
-#$ python setup.py install
-# \endverbatim
-#
-#
-# \subsection Tutorial
-# To create an inversion object:
-# \verbatim
-#from sas.sascalc.pr.invertor import Invertor
-# invertor = Invertor()
-# \endverbatim
-#
-# To set the maximum distance between any two points:
-# \verbatim
-# invertor.d_max = 160.0
-# \endverbatim
-#
-# To set the regularization constant:
-# \verbatim
-# invertor.alpha = 0.0007
-# \endverbatim
-#
-# To set the q, I(q) and error on I(q):
-# \verbatim
-# invertor.x = q_vector
-# invertor.y = Iq_vector
-# invertor.err = dIq_vector
-# \endverbatim
-#
-# To perform the inversion. In this example, we choose
-# a P(r) expension wit 10 base functions.
-# \verbatim
-# c_out, c_cov = invertor.invert(10)
-# \endverbatim
-# The c_out and c_cov are the set of coefficients and the covariance
-# matrix for those coefficients, respectively.
-#
-# To get P(r):
-# \verbatim
-# r = 10.0
-# pr = invertor.pr(c_out, r)
-# \endverbatim
-# Alternatively, one can get P(r) with the error on P(r):
-# \verbatim
-# r = 10.0
-# pr, dpr = invertor.pr_err(c_out, c_cov, r)
-# \endverbatim
-#
-# To get the output I(q) from the set of coefficients found:
-# \verbatim
-# q = 0.001
-# iq = invertor.iq(c_out, q)
-# \endverbatim
-#
-# Examples are available as unit tests under sas.pr_inversion.test.
-#
-# \section help_sec Contact Info
-# Code and Documentation produced as part of the DANSE project.
-
-__author__ = 'University of Tennessee'
+"""
+ P(r) inversion for SAS
+"""
+## \mainpage P(r) inversion for SAS
+#
+# \section intro_sec Introduction
+# This module provides calculations to transform scattering intensity data
+# I(q) into distance distribution function P(r). A description of the
+# technique can be found elsewhere [1-5]. The module is useable as a
+# standalone application but its functionality is meant to be presented
+# to end-users through the user interface developed as part of the SAS
+# flagship application.
+#
+# Procedure: We will follow the procedure of Moore [1].
+#
+# [1] P.B. Moore, J.Appl. Cryst (1980) 13, 168-175.
+#
+# [2] O. Glatter, J.Appl. Cryst (1977) 10, 415-421.
+#
+# [3] D.I. Svergun, J.Appl. Cryst (1991) 24, 485-492.
+#
+# [4] D.I. Svergun, J.Appl. Cryst (1992) 25, 495-503.
+#
+# [5] S. Hansen and J. Skov Pedersen, J.Appl. Cryst (1991) 24, 541-548.
+#
+## \subsection class Class Diagram:
+# The following shows a partial class diagram with the main attributes
+# and methods of the invertor.
+#
+# \image html architecture.png
+#
+# \section install_sec Installation
+#
+# \subsection obtain Obtaining the Code
+#
+# The code is available here:
+# \verbatim
+#$ svn co svn://danse.us/sas/pr_inversion
+# \endverbatim
+#
+# \subsection depends External Dependencies
+# scipy, numpy
+#
+# \subsection build Building the code
+# The standard python package can be built with distutils.
+# \verbatim
+#$ python setup.py build
+#$ python setup.py install
+# \endverbatim
+#
+#
+# \subsection Tutorial
+# To create an inversion object:
+# \verbatim
+#from sas.sascalc.pr.invertor import Invertor
+# invertor = Invertor()
+# \endverbatim
+#
+# To set the maximum distance between any two points:
+# \verbatim
+# invertor.d_max = 160.0
+# \endverbatim
+#
+# To set the regularization constant:
+# \verbatim
+# invertor.alpha = 0.0007
+# \endverbatim
+#
+# To set the q, I(q) and error on I(q):
+# \verbatim
+# invertor.x = q_vector
+# invertor.y = Iq_vector
+# invertor.err = dIq_vector
+# \endverbatim
+#
+# To perform the inversion. In this example, we choose
+# a P(r) expension wit 10 base functions.
+# \verbatim
+# c_out, c_cov = invertor.invert(10)
+# \endverbatim
+# The c_out and c_cov are the set of coefficients and the covariance
+# matrix for those coefficients, respectively.
+#
+# To get P(r):
+# \verbatim
+# r = 10.0
+# pr = invertor.pr(c_out, r)
+# \endverbatim
+# Alternatively, one can get P(r) with the error on P(r):
+# \verbatim
+# r = 10.0
+# pr, dpr = invertor.pr_err(c_out, c_cov, r)
+# \endverbatim
+#
+# To get the output I(q) from the set of coefficients found:
+# \verbatim
+# q = 0.001
+# iq = invertor.iq(c_out, q)
+# \endverbatim
+#
+# Examples are available as unit tests under sas.pr_inversion.test.
+#
+# \section help_sec Contact Info
+# Code and Documentation produced as part of the DANSE project.
+
+__author__ = 'University of Tennessee'
diff --git a/src/sas/sascalc/pr/c_extensions/Cinvertor.c b/src/sas/sascalc/pr/c_extensions/Cinvertor.c
index f9fc4af..d0a336b 100644
--- a/src/sas/sascalc/pr/c_extensions/Cinvertor.c
+++ b/src/sas/sascalc/pr/c_extensions/Cinvertor.c
@@ -1,1133 +1,1170 @@
-/**
- * C implementation of the P(r) inversion
- * Cinvertor is the base class for the Invertor class
- * and provides the underlying computations.
- *
- */
-#include <Python.h>
-#include "structmember.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <math.h>
-#include <time.h>
-
-#include "invertor.h"
-
-
-/// Error object for raised exceptions
-PyObject * CinvertorError;
-
-#define INVECTOR(obj,buf,len) \
- do { \
- int err = PyObject_AsReadBuffer(obj, (const void **)(&buf), &len); \
- if (err < 0) return NULL; \
- len /= sizeof(*buf); \
- } while (0)
-
-#define OUTVECTOR(obj,buf,len) \
- do { \
- int err = PyObject_AsWriteBuffer(obj, (void **)(&buf), &len); \
- if (err < 0) return NULL; \
- len /= sizeof(*buf); \
- } while (0)
-
-
-// Class definition
-/**
- * C implementation of the P(r) inversion
- * Cinvertor is the base class for the Invertor class
- * and provides the underlying computations.
- *
- */
-typedef struct {
- PyObject_HEAD
- /// Internal data structure
- Invertor_params params;
-} Cinvertor;
-
-
-static void
-Cinvertor_dealloc(Cinvertor* self)
-{
- invertor_dealloc(&(self->params));
-
- self->ob_type->tp_free((PyObject*)self);
-
-}
-
-static PyObject *
-Cinvertor_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
-{
- Cinvertor *self;
-
- self = (Cinvertor *)type->tp_alloc(type, 0);
-
- return (PyObject *)self;
-}
-
-static int
-Cinvertor_init(Cinvertor *self, PyObject *args, PyObject *kwds)
-{
- if (self != NULL) {
- // Create parameters
- invertor_init(&(self->params));
- }
- return 0;
-}
-
-static PyMemberDef Cinvertor_members[] = {
- //{"params", T_OBJECT, offsetof(Cinvertor, params), 0,
- // "Parameters"},
- {NULL} /* Sentinel */
-};
-
-const char set_x_doc[] =
- "Function to set the x data\n"
- "Takes an array of doubles as input.\n"
- " @return: number of entries found";
-
-/**
- * Function to set the x data
- * Takes an array of doubles as input
- * Returns the number of entries found
- */
-static PyObject * set_x(Cinvertor *self, PyObject *args) {
- PyObject *data_obj;
- Py_ssize_t ndata;
- double *data;
- int i;
-
- if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
- OUTVECTOR(data_obj,data,ndata);
-
- free(self->params.x);
- self->params.x = (double*) malloc(ndata*sizeof(double));
-
- if(self->params.x==NULL) {
- PyErr_SetString(CinvertorError,
- "Cinvertor.set_x: problem allocating memory.");
- return NULL;
- }
-
- for (i=0; i<ndata; i++) {
- self->params.x[i] = data[i];
- }
-
- //self->params.x = data;
- self->params.npoints = (int)ndata;
- return Py_BuildValue("i", self->params.npoints);
-}
-
-const char get_x_doc[] =
- "Function to get the x data\n"
- "Takes an array of doubles as input.\n"
- " @return: number of entries found";
-
-static PyObject * get_x(Cinvertor *self, PyObject *args) {
- PyObject *data_obj;
- Py_ssize_t ndata;
- double *data;
- int i;
-
- if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
- OUTVECTOR(data_obj, data, ndata);
-
- // Check that the input array is large enough
- if (ndata < self->params.npoints) {
- PyErr_SetString(CinvertorError,
- "Cinvertor.get_x: input array too short for data.");
- return NULL;
- }
-
- for(i=0; i<self->params.npoints; i++){
- data[i] = self->params.x[i];
- }
-
- return Py_BuildValue("i", self->params.npoints);
-}
-
-const char set_y_doc[] =
- "Function to set the y data\n"
- "Takes an array of doubles as input.\n"
- " @return: number of entries found";
-
-/**
- * Function to set the y data
- * Takes an array of doubles as input
- * Returns the number of entries found
- */
-static PyObject * set_y(Cinvertor *self, PyObject *args) {
- PyObject *data_obj;
- Py_ssize_t ndata;
- double *data;
- int i;
-
- if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
- OUTVECTOR(data_obj,data,ndata);
-
- free(self->params.y);
- self->params.y = (double*) malloc(ndata*sizeof(double));
-
- if(self->params.y==NULL) {
- PyErr_SetString(CinvertorError,
- "Cinvertor.set_y: problem allocating memory.");
- return NULL;
- }
-
- for (i=0; i<ndata; i++) {
- self->params.y[i] = data[i];
- }
-
- //self->params.y = data;
- self->params.ny = (int)ndata;
- return Py_BuildValue("i", self->params.ny);
-}
-
-const char get_y_doc[] =
- "Function to get the y data\n"
- "Takes an array of doubles as input.\n"
- " @return: number of entries found";
-
-static PyObject * get_y(Cinvertor *self, PyObject *args) {
- PyObject *data_obj;
- Py_ssize_t ndata;
- double *data;
- int i;
-
- if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
- OUTVECTOR(data_obj, data, ndata);
-
- // Check that the input array is large enough
- if (ndata < self->params.ny) {
- PyErr_SetString(CinvertorError,
- "Cinvertor.get_y: input array too short for data.");
- return NULL;
- }
-
- for(i=0; i<self->params.ny; i++){
- data[i] = self->params.y[i];
- }
-
- return Py_BuildValue("i", self->params.npoints);
-}
-
-const char set_err_doc[] =
- "Function to set the err data\n"
- "Takes an array of doubles as input.\n"
- " @return: number of entries found";
-
-/**
- * Function to set the x data
- * Takes an array of doubles as input
- * Returns the number of entries found
- */
-static PyObject * set_err(Cinvertor *self, PyObject *args) {
- PyObject *data_obj;
- Py_ssize_t ndata;
- double *data;
- int i;
-
- if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
- OUTVECTOR(data_obj,data,ndata);
-
- free(self->params.err);
- self->params.err = (double*) malloc(ndata*sizeof(double));
-
- if(self->params.err==NULL) {
- PyErr_SetString(CinvertorError,
- "Cinvertor.set_err: problem allocating memory.");
- return NULL;
- }
-
- for (i=0; i<ndata; i++) {
- self->params.err[i] = data[i];
- }
-
- //self->params.err = data;
- self->params.nerr = (int)ndata;
- return Py_BuildValue("i", self->params.nerr);
-}
-
-const char get_err_doc[] =
- "Function to get the err data\n"
- "Takes an array of doubles as input.\n"
- " @return: number of entries found";
-
-static PyObject * get_err(Cinvertor *self, PyObject *args) {
- PyObject *data_obj;
- Py_ssize_t ndata;
- double *data;
- int i;
-
- if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
- OUTVECTOR(data_obj, data, ndata);
-
- // Check that the input array is large enough
- if (ndata < self->params.nerr) {
- PyErr_SetString(CinvertorError,
- "Cinvertor.get_err: input array too short for data.");
- return NULL;
- }
-
- for(i=0; i<self->params.nerr; i++){
- data[i] = self->params.err[i];
- }
-
- return Py_BuildValue("i", self->params.npoints);
-}
-
-const char is_valid_doc[] =
- "Check the validity of the stored data\n"
- " @return: Returns the number of points if it's all good, -1 otherwise";
-
-/**
- * Check the validity of the stored data
- * Returns the number of points if it's all good, -1 otherwise
- */
-static PyObject * is_valid(Cinvertor *self, PyObject *args) {
- if(self->params.npoints==self->params.ny &&
- self->params.npoints==self->params.nerr) {
- return Py_BuildValue("i", self->params.npoints);
- } else {
- return Py_BuildValue("i", -1);
- }
-}
-
-const char set_has_bck_doc[] =
- "Sets background flag\n";
-
-/**
- * Sets the maximum distance
- */
-static PyObject * set_has_bck(Cinvertor *self, PyObject *args) {
- int has_bck;
-
- if (!PyArg_ParseTuple(args, "i", &has_bck)) return NULL;
- self->params.has_bck = has_bck;
- return Py_BuildValue("i", self->params.has_bck);
-}
-
-const char get_has_bck_doc[] =
- "Gets background flag\n";
-
-/**
- * Gets the maximum distance
- */
-static PyObject * get_has_bck(Cinvertor *self, PyObject *args) {
- return Py_BuildValue("i", self->params.has_bck);
-}
-
-const char set_dmax_doc[] =
- "Sets the maximum distance\n";
-
-/**
- * Sets the maximum distance
- */
-static PyObject * set_dmax(Cinvertor *self, PyObject *args) {
- double d_max;
-
- if (!PyArg_ParseTuple(args, "d", &d_max)) return NULL;
- self->params.d_max = d_max;
- return Py_BuildValue("d", self->params.d_max);
-}
-
-const char get_dmax_doc[] =
- "Gets the maximum distance\n";
-
-/**
- * Gets the maximum distance
- */
-static PyObject * get_dmax(Cinvertor *self, PyObject *args) {
- return Py_BuildValue("d", self->params.d_max);
-}
-
-const char set_slit_height_doc[] =
- "Sets the slit height in units of q [A-1]\n";
-
-/**
- * Sets the slit height
- */
-static PyObject * set_slit_height(Cinvertor *self, PyObject *args) {
- double slit_height;
-
- if (!PyArg_ParseTuple(args, "d", &slit_height)) return NULL;
- self->params.slit_height = slit_height;
- return Py_BuildValue("d", self->params.slit_height);
-}
-
-const char get_slit_height_doc[] =
- "Gets the slit height\n";
-
-/**
- * Gets the slit height
- */
-static PyObject * get_slit_height(Cinvertor *self, PyObject *args) {
- return Py_BuildValue("d", self->params.slit_height);
-}
-
-const char set_slit_width_doc[] =
- "Sets the slit width in units of q [A-1]\n";
-
-/**
- * Sets the slit width
- */
-static PyObject * set_slit_width(Cinvertor *self, PyObject *args) {
- double slit_width;
-
- if (!PyArg_ParseTuple(args, "d", &slit_width)) return NULL;
- self->params.slit_width = slit_width;
- return Py_BuildValue("d", self->params.slit_width);
-}
-
-const char get_slit_width_doc[] =
- "Gets the slit width\n";
-
-/**
- * Gets the slit width
- */
-static PyObject * get_slit_width(Cinvertor *self, PyObject *args) {
- return Py_BuildValue("d", self->params.slit_width);
-}
-
-
-const char set_qmin_doc[] =
- "Sets the minimum q\n";
-
-/**
- * Sets the minimum q
- */
-static PyObject * set_qmin(Cinvertor *self, PyObject *args) {
- double q_min;
-
- if (!PyArg_ParseTuple(args, "d", &q_min)) return NULL;
- self->params.q_min = q_min;
- return Py_BuildValue("d", self->params.q_min);
-}
-
-const char get_qmin_doc[] =
- "Gets the minimum q\n";
-
-/**
- * Gets the minimum q
- */
-static PyObject * get_qmin(Cinvertor *self, PyObject *args) {
- return Py_BuildValue("d", self->params.q_min);
-}
-
-const char set_qmax_doc[] =
- "Sets the maximum q\n";
-
-/**
- * Sets the maximum q
- */
-static PyObject * set_qmax(Cinvertor *self, PyObject *args) {
- double q_max;
-
- if (!PyArg_ParseTuple(args, "d", &q_max)) return NULL;
- self->params.q_max = q_max;
- return Py_BuildValue("d", self->params.q_max);
-}
-
-const char get_qmax_doc[] =
- "Gets the maximum q\n";
-
-/**
- * Gets the maximum q
- */
-static PyObject * get_qmax(Cinvertor *self, PyObject *args) {
- return Py_BuildValue("d", self->params.q_max);
-}
-
-const char set_alpha_doc[] =
- "Sets the alpha parameter\n";
-
-static PyObject * set_alpha(Cinvertor *self, PyObject *args) {
- double alpha;
-
- if (!PyArg_ParseTuple(args, "d", &alpha)) return NULL;
- self->params.alpha = alpha;
- return Py_BuildValue("d", self->params.alpha);
-}
-
-const char get_alpha_doc[] =
- "Gets the alpha parameter\n";
-
-/**
- * Gets the maximum distance
- */
-static PyObject * get_alpha(Cinvertor *self, PyObject *args) {
- return Py_BuildValue("d", self->params.alpha);
-}
-
-const char get_nx_doc[] =
- "Gets the number of x points\n";
-
-/**
- * Gets the number of x points
- */
-static PyObject * get_nx(Cinvertor *self, PyObject *args) {
- return Py_BuildValue("i", self->params.npoints);
-}
-
-const char get_ny_doc[] =
- "Gets the number of y points\n";
-
-/**
- * Gets the number of y points
- */
-static PyObject * get_ny(Cinvertor *self, PyObject *args) {
- return Py_BuildValue("i", self->params.ny);
-}
-
-const char get_nerr_doc[] =
- "Gets the number of err points\n";
-
-/**
- * Gets the number of error points
- */
-static PyObject * get_nerr(Cinvertor *self, PyObject *args) {
- return Py_BuildValue("i", self->params.nerr);
-}
-
-
-const char residuals_doc[] =
- "Function to call to evaluate the residuals\n"
- "for P(r) inversion\n"
- " @param args: input parameters\n"
- " @return: list of residuals";
-
-/**
- * Function to call to evaluate the residuals
- * @param args: input parameters
- * @return: list of residuals
- */
-static PyObject * residuals(Cinvertor *self, PyObject *args) {
- double *pars;
- PyObject* residuals;
- int i;
- double residual, diff;
- // Regularization factor
- double regterm = 0.0;
- // Number of slices in regularization term estimate
- int nslice = 25;
-
- PyObject *data_obj;
- Py_ssize_t npars;
-
- if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
-
- OUTVECTOR(data_obj,pars,npars);
-
- // PyList of residuals
- // Should create this list only once and refill it
- residuals = PyList_New(self->params.npoints);
-
- regterm = reg_term(pars, self->params.d_max, (int)npars, nslice);
-
- for(i=0; i<self->params.npoints; i++) {
- diff = self->params.y[i] - iq(pars, self->params.d_max, (int)npars, self->params.x[i]);
- residual = diff*diff / (self->params.err[i]*self->params.err[i]);
-
- // regularization term
- residual += self->params.alpha * regterm;
-
- if (PyList_SetItem(residuals, i, Py_BuildValue("d",residual) ) < 0){
- PyErr_SetString(CinvertorError,
- "Cinvertor.residuals: error setting residual.");
- return NULL;
- };
- }
- return residuals;
-}
-
-const char pr_residuals_doc[] =
- "Function to call to evaluate the residuals\n"
- "for P(r) minimization (for testing purposes)\n"
- " @param args: input parameters\n"
- " @return: list of residuals";
-
-/**
- * Function to call to evaluate the residuals
- * for P(r) minimization (for testing purposes)
- * @param args: input parameters
- * @return: list of residuals
- */
-static PyObject * pr_residuals(Cinvertor *self, PyObject *args) {
- double *pars;
- PyObject* residuals;
- int i;
- double residual, diff;
- // Regularization factor
- double regterm = 0.0;
- // Number of slices in regularization term estimate
- int nslice = 25;
-
- PyObject *data_obj;
- Py_ssize_t npars;
-
- if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
-
- OUTVECTOR(data_obj,pars,npars);
-
- // Should create this list only once and refill it
- residuals = PyList_New(self->params.npoints);
-
- regterm = reg_term(pars, self->params.d_max, (int)npars, nslice);
-
-
- for(i=0; i<self->params.npoints; i++) {
- diff = self->params.y[i] - pr(pars, self->params.d_max, (int)npars, self->params.x[i]);
- residual = diff*diff / (self->params.err[i]*self->params.err[i]);
-
- // regularization term
- residual += self->params.alpha * regterm;
-
- if (PyList_SetItem(residuals, i, Py_BuildValue("d",residual) ) < 0){
- PyErr_SetString(CinvertorError,
- "Cinvertor.residuals: error setting residual.");
- return NULL;
- };
- }
- return residuals;
-}
-
-const char get_iq_doc[] =
- "Function to call to evaluate the scattering intensity\n"
- " @param args: c-parameters, and q\n"
- " @return: I(q)";
-
-/**
- * Function to call to evaluate the scattering intensity
- * @param args: c-parameters, and q
- * @return: I(q)
- */
-static PyObject * get_iq(Cinvertor *self, PyObject *args) {
- double *pars;
- double q, iq_value;
- PyObject *data_obj;
- Py_ssize_t npars;
-
- if (!PyArg_ParseTuple(args, "Od", &data_obj, &q)) return NULL;
- OUTVECTOR(data_obj,pars,npars);
-
- iq_value = iq(pars, self->params.d_max, (int)npars, q);
- return Py_BuildValue("f", iq_value);
-}
-
-const char get_iq_smeared_doc[] =
- "Function to call to evaluate the scattering intensity.\n"
- "The scattering intensity is slit-smeared."
- " @param args: c-parameters, and q\n"
- " @return: I(q)";
-
-/**
- * Function to call to evaluate the scattering intensity
- * The scattering intensity is slit-smeared.
- * @param args: c-parameters, and q
- * @return: I(q)
- */
-static PyObject * get_iq_smeared(Cinvertor *self, PyObject *args) {
- double *pars;
- double q, iq_value;
- PyObject *data_obj;
- Py_ssize_t npars;
-
- if (!PyArg_ParseTuple(args, "Od", &data_obj, &q)) return NULL;
- OUTVECTOR(data_obj,pars,npars);
-
- iq_value = iq_smeared(pars, self->params.d_max, (int)npars,
- self->params.slit_height, self->params.slit_width,
- q, 21);
- return Py_BuildValue("f", iq_value);
-}
-
-const char get_pr_doc[] =
- "Function to call to evaluate P(r)\n"
- " @param args: c-parameters and r\n"
- " @return: P(r)";
-
-/**
- * Function to call to evaluate P(r)
- * @param args: c-parameters and r
- * @return: P(r)
- */
-static PyObject * get_pr(Cinvertor *self, PyObject *args) {
- double *pars;
- double r, pr_value;
- PyObject *data_obj;
- Py_ssize_t npars;
-
- if (!PyArg_ParseTuple(args, "Od", &data_obj, &r)) return NULL;
- OUTVECTOR(data_obj,pars,npars);
-
- pr_value = pr(pars, self->params.d_max, (int)npars, r);
- return Py_BuildValue("f", pr_value);
-}
-
-const char get_pr_err_doc[] =
- "Function to call to evaluate P(r) with errors\n"
- " @param args: c-parameters and r\n"
- " @return: (P(r),dP(r))";
-
-/**
- * Function to call to evaluate P(r) with errors
- * @param args: c-parameters and r
- * @return: P(r)
- */
-static PyObject * get_pr_err(Cinvertor *self, PyObject *args) {
- double *pars;
- double *pars_err;
- double pr_err_value;
- double r, pr_value;
- PyObject *data_obj;
- Py_ssize_t npars;
- PyObject *err_obj;
- Py_ssize_t npars2;
-
- if (!PyArg_ParseTuple(args, "OOd", &data_obj, &err_obj, &r)) return NULL;
- OUTVECTOR(data_obj,pars,npars);
-
- if (err_obj == Py_None) {
- pr_value = pr(pars, self->params.d_max, (int)npars, r);
- pr_err_value = 0.0;
- } else {
- OUTVECTOR(err_obj,pars_err,npars2);
- pr_err(pars, pars_err, self->params.d_max, (int)npars, r, &pr_value, &pr_err_value);
- }
- return Py_BuildValue("ff", pr_value, pr_err_value);
-}
-
-const char basefunc_ft_doc[] =
- "Returns the value of the nth Fourier transofrmed base function\n"
- " @param args: c-parameters, n and q\n"
- " @return: nth Fourier transformed base function, evaluated at q";
-
-static PyObject * basefunc_ft(Cinvertor *self, PyObject *args) {
- double d_max, q;
- int n;
-
- if (!PyArg_ParseTuple(args, "did", &d_max, &n, &q)) return NULL;
- return Py_BuildValue("f", ortho_transformed(d_max, n, q));
-
-}
-
-const char oscillations_doc[] =
- "Returns the value of the oscillation figure of merit for\n"
- "the given set of coefficients. For a sphere, the oscillation\n"
- "figure of merit is 1.1.\n"
- " @param args: c-parameters\n"
- " @return: oscillation figure of merit";
-
-static PyObject * oscillations(Cinvertor *self, PyObject *args) {
- double *pars;
- PyObject *data_obj;
- Py_ssize_t npars;
- double oscill, norm;
-
- if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
- OUTVECTOR(data_obj,pars,npars);
-
- oscill = reg_term(pars, self->params.d_max, (int)npars, 100);
- norm = int_p2(pars, self->params.d_max, (int)npars, 100);
- return Py_BuildValue("f", sqrt(oscill/norm)/acos(-1.0)*self->params.d_max );
-
-}
-
-const char get_peaks_doc[] =
- "Returns the number of peaks in the output P(r) distrubution\n"
- "for the given set of coefficients.\n"
- " @param args: c-parameters\n"
- " @return: number of P(r) peaks";
-
-static PyObject * get_peaks(Cinvertor *self, PyObject *args) {
- double *pars;
- PyObject *data_obj;
- Py_ssize_t npars;
- int count;
-
- if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
- OUTVECTOR(data_obj,pars,npars);
-
- count = npeaks(pars, self->params.d_max, (int)npars, 100);
-
- return Py_BuildValue("i", count );
-
-}
-
-const char get_positive_doc[] =
- "Returns the fraction of P(r) that is positive over\n"
- "the full range of r for the given set of coefficients.\n"
- " @param args: c-parameters\n"
- " @return: fraction of P(r) that is positive";
-
-static PyObject * get_positive(Cinvertor *self, PyObject *args) {
- double *pars;
- PyObject *data_obj;
- Py_ssize_t npars;
- double fraction;
-
- if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
- OUTVECTOR(data_obj,pars,npars);
-
- fraction = positive_integral(pars, self->params.d_max, (int)npars, 100);
-
- return Py_BuildValue("f", fraction );
-
-}
-
-const char get_pos_err_doc[] =
- "Returns the fraction of P(r) that is 1 standard deviation\n"
- "above zero over the full range of r for the given set of coefficients.\n"
- " @param args: c-parameters\n"
- " @return: fraction of P(r) that is positive";
-
-static PyObject * get_pos_err(Cinvertor *self, PyObject *args) {
- double *pars;
- double *pars_err;
- PyObject *data_obj;
- PyObject *err_obj;
- Py_ssize_t npars;
- Py_ssize_t npars2;
- double fraction;
-
- if (!PyArg_ParseTuple(args, "OO", &data_obj, &err_obj)) return NULL;
- OUTVECTOR(data_obj,pars,npars);
- OUTVECTOR(err_obj,pars_err,npars2);
-
- fraction = positive_errors(pars, pars_err, self->params.d_max, (int)npars, 51);
-
- return Py_BuildValue("f", fraction );
-
-}
-
-const char get_rg_doc[] =
- "Returns the value of the radius of gyration Rg.\n"
- " @param args: c-parameters\n"
- " @return: Rg";
-
-static PyObject * get_rg(Cinvertor *self, PyObject *args) {
- double *pars;
- PyObject *data_obj;
- Py_ssize_t npars;
- double value;
-
- if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
- OUTVECTOR(data_obj,pars,npars);
-
- value = rg(pars, self->params.d_max, (int)npars, 101);
-
- return Py_BuildValue("f", value );
-
-}
-
-const char get_iq0_doc[] =
- "Returns the value of I(q=0).\n"
- " @param args: c-parameters\n"
- " @return: I(q=0)";
-
-static PyObject * get_iq0(Cinvertor *self, PyObject *args) {
- double *pars;
- PyObject *data_obj;
- Py_ssize_t npars;
- double value;
-
- if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
- OUTVECTOR(data_obj,pars,npars);
-
- value = 4.0*acos(-1.0)*int_pr(pars, self->params.d_max, (int)npars, 101);
-
- return Py_BuildValue("f", value );
-
-}
-
-/**
- * Check whether a q-value is within acceptabel limits
- * Return 1 if accepted, 0 if rejected.
- */
-int accept_q(Cinvertor *self, double q) {
- if (self->params.q_min>0 && q<self->params.q_min) return 0;
- if (self->params.q_max>0 && q>self->params.q_max) return 0;
- return 1;
-}
-
-const char get_matrix_doc[] =
- "Returns A matrix and b vector for least square problem.\n"
- " @param nfunc: number of base functions\n"
- " @param nr: number of r-points used when evaluating reg term.\n"
- " @param a: A array to fill\n"
- " @param b: b vector to fill\n"
- " @return: 0";
-
-static PyObject * get_matrix(Cinvertor *self, PyObject *args) {
- double *a;
- double *b;
- PyObject *a_obj;
- PyObject *b_obj;
- Py_ssize_t n_a;
- Py_ssize_t n_b;
- // Number of bins for regularization term evaluation
- int nr, nfunc;
- int i, j, i_r;
- double r, sqrt_alpha, pi;
- double tmp;
- int offset;
-
- if (!PyArg_ParseTuple(args, "iiOO", &nfunc, &nr, &a_obj, &b_obj)) return NULL;
- OUTVECTOR(a_obj,a,n_a);
- OUTVECTOR(b_obj,b,n_b);
-
- assert(n_b>=nfunc);
- assert(n_a>=nfunc*(nr+self->params.npoints));
-
- sqrt_alpha = sqrt(self->params.alpha);
- pi = acos(-1.0);
- offset = (self->params.has_bck==1) ? 0 : 1;
-
- for (j=0; j<nfunc; j++) {
- for (i=0; i<self->params.npoints; i++) {
- if (self->params.err[i]==0.0) {
- PyErr_SetString(CinvertorError,
- "Cinvertor.get_matrix: Some I(Q) points have no error.");
- return NULL;
- }
- if (accept_q(self, self->params.x[i])){
- if (self->params.has_bck==1 && j==0) {
- a[i*nfunc+j] = 1.0/self->params.err[i];
- } else {
- if (self->params.slit_width>0 || self->params.slit_height>0) {
- a[i*nfunc+j] = ortho_transformed_smeared(self->params.d_max,
- j+offset, self->params.slit_height, self->params.slit_width,
- self->params.x[i], 21)/self->params.err[i];
- } else {
- a[i*nfunc+j] = ortho_transformed(self->params.d_max, j+offset, self->params.x[i])/self->params.err[i];
- }
- }
- }
- }
- for (i_r=0; i_r<nr; i_r++){
- if (self->params.has_bck==1 && j==0) {
- a[(i_r+self->params.npoints)*nfunc+j] = 0.0;
- } else {
- r = self->params.d_max/nr*i_r;
- tmp = pi*(j+offset)/self->params.d_max;
- a[(i_r+self->params.npoints)*nfunc+j] = sqrt_alpha * 1.0/nr*self->params.d_max*2.0*
- (2.0*pi*(j+offset)/self->params.d_max*cos(pi*(j+offset)*r/self->params.d_max) +
- tmp*tmp*r * sin(pi*(j+offset)*r/self->params.d_max));
- }
- }
- }
-
- for (i=0; i<self->params.npoints; i++) {
- if (accept_q(self, self->params.x[i])){
- b[i] = self->params.y[i]/self->params.err[i];
- }
- }
-
- return Py_BuildValue("i", 0);
-
-}
-
-const char get_invcov_matrix_doc[] =
- " Compute the inverse covariance matrix, defined as inv_cov = a_transposed x a.\n"
- " @param nfunc: number of base functions\n"
- " @param nr: number of r-points used when evaluating reg term.\n"
- " @param a: A array to fill\n"
- " @param inv_cov: inverse covariance array to be filled\n"
- " @return: 0";
-
-static PyObject * get_invcov_matrix(Cinvertor *self, PyObject *args) {
- double *a;
- PyObject *a_obj;
- Py_ssize_t n_a;
- double *inv_cov;
- PyObject *cov_obj;
- Py_ssize_t n_cov;
- int nr, nfunc;
- int i, j, k;
-
- if (!PyArg_ParseTuple(args, "iiOO", &nfunc, &nr, &a_obj, &cov_obj)) return NULL;
- OUTVECTOR(a_obj,a,n_a);
- OUTVECTOR(cov_obj,inv_cov,n_cov);
-
- assert(n_cov>=nfunc*nfunc);
- assert(n_a>=nfunc*(nr+self->params.npoints));
-
- for (i=0; i<nfunc; i++) {
- for (j=0; j<nfunc; j++) {
- inv_cov[i*nfunc+j] = 0.0;
- for (k=0; k<nr+self->params.npoints; k++) {
- inv_cov[i*nfunc+j] += a[k*nfunc+i]*a[k*nfunc+j];
- }
- }
- }
- return Py_BuildValue("i", 0);
-}
-
-const char get_reg_size_doc[] =
- " Compute the covariance matrix, defined as inv_cov = a_transposed x a.\n"
- " @param nfunc: number of base functions\n"
- " @param nr: number of r-points used when evaluating reg term.\n"
- " @param a: A array to fill\n"
- " @param inv_cov: inverse covariance array to be filled\n"
- " @return: 0";
-
-static PyObject * get_reg_size(Cinvertor *self, PyObject *args) {
- double *a;
- PyObject *a_obj;
- Py_ssize_t n_a;
- int nr, nfunc;
- int i, j;
- double sum_sig, sum_reg;
-
- if (!PyArg_ParseTuple(args, "iiO", &nfunc, &nr, &a_obj)) return NULL;
- OUTVECTOR(a_obj,a,n_a);
-
- assert(n_a>=nfunc*(nr+self->params.npoints));
-
- sum_sig = 0.0;
- sum_reg = 0.0;
- for (j=0; j<nfunc; j++){
- for (i=0; i<self->params.npoints; i++){
- if (accept_q(self, self->params.x[i])==1)
- sum_sig += (a[i*nfunc+j])*(a[i*nfunc+j]);
- }
- for (i=0; i<nr; i++){
- sum_reg += (a[(i+self->params.npoints)*nfunc+j])*(a[(i+self->params.npoints)*nfunc+j]);
- }
- }
- return Py_BuildValue("ff", sum_sig, sum_reg);
-}
-
-const char eeeget_qmin_doc[] = "\
-This is a multiline doc string.\n\
-\n\
-This is the second line.";
-const char eeeset_qmin_doc[] =
- "This is a multiline doc string.\n"
- "\n"
- "This is the second line.";
-
-static PyMethodDef Cinvertor_methods[] = {
- {"residuals", (PyCFunction)residuals, METH_VARARGS, residuals_doc},
- {"pr_residuals", (PyCFunction)pr_residuals, METH_VARARGS, pr_residuals_doc},
- {"set_x", (PyCFunction)set_x, METH_VARARGS, set_x_doc},
- {"get_x", (PyCFunction)get_x, METH_VARARGS, get_x_doc},
- {"set_y", (PyCFunction)set_y, METH_VARARGS, set_y_doc},
- {"get_y", (PyCFunction)get_y, METH_VARARGS, get_y_doc},
- {"set_err", (PyCFunction)set_err, METH_VARARGS, set_err_doc},
- {"get_err", (PyCFunction)get_err, METH_VARARGS, get_err_doc},
- {"set_dmax", (PyCFunction)set_dmax, METH_VARARGS, set_dmax_doc},
- {"get_dmax", (PyCFunction)get_dmax, METH_VARARGS, get_dmax_doc},
- {"set_qmin", (PyCFunction)set_qmin, METH_VARARGS, set_qmin_doc},
- {"get_qmin", (PyCFunction)get_qmin, METH_VARARGS, get_qmin_doc},
- {"set_qmax", (PyCFunction)set_qmax, METH_VARARGS, set_qmax_doc},
- {"get_qmax", (PyCFunction)get_qmax, METH_VARARGS, get_qmax_doc},
- {"set_alpha", (PyCFunction)set_alpha, METH_VARARGS, set_alpha_doc},
- {"get_alpha", (PyCFunction)get_alpha, METH_VARARGS, get_alpha_doc},
- {"set_slit_width", (PyCFunction)set_slit_width, METH_VARARGS, set_slit_width_doc},
- {"get_slit_width", (PyCFunction)get_slit_width, METH_VARARGS, get_slit_width_doc},
- {"set_slit_height", (PyCFunction)set_slit_height, METH_VARARGS, set_slit_height_doc},
- {"get_slit_height", (PyCFunction)get_slit_height, METH_VARARGS, get_slit_height_doc},
- {"set_has_bck", (PyCFunction)set_has_bck, METH_VARARGS, set_has_bck_doc},
- {"get_has_bck", (PyCFunction)get_has_bck, METH_VARARGS, get_has_bck_doc},
- {"get_nx", (PyCFunction)get_nx, METH_VARARGS, get_nx_doc},
- {"get_ny", (PyCFunction)get_ny, METH_VARARGS, get_ny_doc},
- {"get_nerr", (PyCFunction)get_nerr, METH_VARARGS, get_nerr_doc},
- {"iq", (PyCFunction)get_iq, METH_VARARGS, get_iq_doc},
- {"iq_smeared", (PyCFunction)get_iq_smeared, METH_VARARGS, get_iq_smeared_doc},
- {"pr", (PyCFunction)get_pr, METH_VARARGS, get_pr_doc},
- {"get_pr_err", (PyCFunction)get_pr_err, METH_VARARGS, get_pr_err_doc},
- {"is_valid", (PyCFunction)is_valid, METH_VARARGS, is_valid_doc},
- {"basefunc_ft", (PyCFunction)basefunc_ft, METH_VARARGS, basefunc_ft_doc},
- {"oscillations", (PyCFunction)oscillations, METH_VARARGS, oscillations_doc},
- {"get_peaks", (PyCFunction)get_peaks, METH_VARARGS, get_peaks_doc},
- {"get_positive", (PyCFunction)get_positive, METH_VARARGS, get_positive_doc},
- {"get_pos_err", (PyCFunction)get_pos_err, METH_VARARGS, get_pos_err_doc},
- {"rg", (PyCFunction)get_rg, METH_VARARGS, get_rg_doc},
- {"iq0", (PyCFunction)get_iq0, METH_VARARGS, get_iq0_doc},
- {"_get_matrix", (PyCFunction)get_matrix, METH_VARARGS, get_matrix_doc},
- {"_get_invcov_matrix", (PyCFunction)get_invcov_matrix, METH_VARARGS, get_invcov_matrix_doc},
- {"_get_reg_size", (PyCFunction)get_reg_size, METH_VARARGS, get_reg_size_doc},
-
- {NULL}
-};
-
-static PyTypeObject CinvertorType = {
- PyObject_HEAD_INIT(NULL)
- 0, /*ob_size*/
- "Cinvertor", /*tp_name*/
- sizeof(Cinvertor), /*tp_basicsize*/
- 0, /*tp_itemsize*/
- (destructor)Cinvertor_dealloc, /*tp_dealloc*/
- 0, /*tp_print*/
- 0, /*tp_getattr*/
- 0, /*tp_setattr*/
- 0, /*tp_compare*/
- 0, /*tp_repr*/
- 0, /*tp_as_number*/
- 0, /*tp_as_sequence*/
- 0, /*tp_as_mapping*/
- 0, /*tp_hash */
- 0, /*tp_call*/
- 0, /*tp_str*/
- 0, /*tp_getattro*/
- 0, /*tp_setattro*/
- 0, /*tp_as_buffer*/
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
- "Cinvertor objects", /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- Cinvertor_methods, /* tp_methods */
- Cinvertor_members, /* tp_members */
- 0, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- (initproc)Cinvertor_init, /* tp_init */
- 0, /* tp_alloc */
- Cinvertor_new, /* tp_new */
-};
-
-
-static PyMethodDef module_methods[] = {
- {NULL}
-};
-
-/**
- * Function used to add the model class to a module
- * @param module: module to add the class to
- */
-void addCinvertor(PyObject *module) {
- PyObject *d;
-
- if (PyType_Ready(&CinvertorType) < 0)
- return;
-
- Py_INCREF(&CinvertorType);
- PyModule_AddObject(module, "Cinvertor", (PyObject *)&CinvertorType);
-
- d = PyModule_GetDict(module);
- CinvertorError = PyErr_NewException("sas.sascalc.pr.invertor.Cinvertor.InvertorError", PyExc_RuntimeError, NULL);
- PyDict_SetItemString(d, "CinvertorError", CinvertorError);
-}
-
-
-#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */
-#define PyMODINIT_FUNC void
-#endif
-PyMODINIT_FUNC
-initpr_inversion(void)
-{
- PyObject* m;
-
- m = Py_InitModule3("pr_inversion", module_methods,
- "C extension module for inversion to P(r).");
-
- addCinvertor(m);
-}
+/**
+ * C implementation of the P(r) inversion
+ * Cinvertor is the base class for the Invertor class
+ * and provides the underlying computations.
+ *
+ */
+#include <Python.h>
+#include "structmember.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <time.h>
+
+#include "invertor.h"
+
+
+/// Error object for raised exceptions
+PyObject * CinvertorError;
+
+#define INVECTOR(obj,buf,len) \
+ do { \
+ int err = PyObject_AsReadBuffer(obj, (const void **)(&buf), &len); \
+ if (err < 0) return NULL; \
+ len /= sizeof(*buf); \
+ } while (0)
+
+#define OUTVECTOR(obj,buf,len) \
+ do { \
+ int err = PyObject_AsWriteBuffer(obj, (void **)(&buf), &len); \
+ if (err < 0) return NULL; \
+ len /= sizeof(*buf); \
+ } while (0)
+
+
+// Class definition
+/**
+ * C implementation of the P(r) inversion
+ * Cinvertor is the base class for the Invertor class
+ * and provides the underlying computations.
+ *
+ */
+typedef struct {
+ PyObject_HEAD
+ /// Internal data structure
+ Invertor_params params;
+} Cinvertor;
+
+
+static void
+Cinvertor_dealloc(Cinvertor* self)
+{
+ invertor_dealloc(&(self->params));
+
+ Py_TYPE(self)->tp_free((PyObject*)self);
+
+}
+
+static PyObject *
+Cinvertor_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ Cinvertor *self;
+
+ self = (Cinvertor *)type->tp_alloc(type, 0);
+
+ return (PyObject *)self;
+}
+
+static int
+Cinvertor_init(Cinvertor *self, PyObject *args, PyObject *kwds)
+{
+ if (self != NULL) {
+ // Create parameters
+ invertor_init(&(self->params));
+ }
+ return 0;
+}
+
+static PyMemberDef Cinvertor_members[] = {
+ //{"params", T_OBJECT, offsetof(Cinvertor, params), 0,
+ // "Parameters"},
+ {NULL} /* Sentinel */
+};
+
+const char set_x_doc[] =
+ "Function to set the x data\n"
+ "Takes an array of doubles as input.\n"
+ " @return: number of entries found";
+
+/**
+ * Function to set the x data
+ * Takes an array of doubles as input
+ * Returns the number of entries found
+ */
+static PyObject * set_x(Cinvertor *self, PyObject *args) {
+ PyObject *data_obj;
+ Py_ssize_t ndata;
+ double *data;
+ int i;
+
+ if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
+ OUTVECTOR(data_obj,data,ndata);
+
+ free(self->params.x);
+ self->params.x = (double*) malloc(ndata*sizeof(double));
+
+ if(self->params.x==NULL) {
+ PyErr_SetString(CinvertorError,
+ "Cinvertor.set_x: problem allocating memory.");
+ return NULL;
+ }
+
+ for (i=0; i<ndata; i++) {
+ self->params.x[i] = data[i];
+ }
+
+ //self->params.x = data;
+ self->params.npoints = (int)ndata;
+ return Py_BuildValue("i", self->params.npoints);
+}
+
+const char get_x_doc[] =
+ "Function to get the x data\n"
+ "Takes an array of doubles as input.\n"
+ " @return: number of entries found";
+
+static PyObject * get_x(Cinvertor *self, PyObject *args) {
+ PyObject *data_obj;
+ Py_ssize_t ndata;
+ double *data;
+ int i;
+
+ if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
+ OUTVECTOR(data_obj, data, ndata);
+
+ // Check that the input array is large enough
+ if (ndata < self->params.npoints) {
+ PyErr_SetString(CinvertorError,
+ "Cinvertor.get_x: input array too short for data.");
+ return NULL;
+ }
+
+ for(i=0; i<self->params.npoints; i++){
+ data[i] = self->params.x[i];
+ }
+
+ return Py_BuildValue("i", self->params.npoints);
+}
+
+const char set_y_doc[] =
+ "Function to set the y data\n"
+ "Takes an array of doubles as input.\n"
+ " @return: number of entries found";
+
+/**
+ * Function to set the y data
+ * Takes an array of doubles as input
+ * Returns the number of entries found
+ */
+static PyObject * set_y(Cinvertor *self, PyObject *args) {
+ PyObject *data_obj;
+ Py_ssize_t ndata;
+ double *data;
+ int i;
+
+ if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
+ OUTVECTOR(data_obj,data,ndata);
+
+ free(self->params.y);
+ self->params.y = (double*) malloc(ndata*sizeof(double));
+
+ if(self->params.y==NULL) {
+ PyErr_SetString(CinvertorError,
+ "Cinvertor.set_y: problem allocating memory.");
+ return NULL;
+ }
+
+ for (i=0; i<ndata; i++) {
+ self->params.y[i] = data[i];
+ }
+
+ //self->params.y = data;
+ self->params.ny = (int)ndata;
+ return Py_BuildValue("i", self->params.ny);
+}
+
+const char get_y_doc[] =
+ "Function to get the y data\n"
+ "Takes an array of doubles as input.\n"
+ " @return: number of entries found";
+
+static PyObject * get_y(Cinvertor *self, PyObject *args) {
+ PyObject *data_obj;
+ Py_ssize_t ndata;
+ double *data;
+ int i;
+
+ if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
+ OUTVECTOR(data_obj, data, ndata);
+
+ // Check that the input array is large enough
+ if (ndata < self->params.ny) {
+ PyErr_SetString(CinvertorError,
+ "Cinvertor.get_y: input array too short for data.");
+ return NULL;
+ }
+
+ for(i=0; i<self->params.ny; i++){
+ data[i] = self->params.y[i];
+ }
+
+ return Py_BuildValue("i", self->params.npoints);
+}
+
+const char set_err_doc[] =
+ "Function to set the err data\n"
+ "Takes an array of doubles as input.\n"
+ " @return: number of entries found";
+
+/**
+ * Function to set the x data
+ * Takes an array of doubles as input
+ * Returns the number of entries found
+ */
+static PyObject * set_err(Cinvertor *self, PyObject *args) {
+ PyObject *data_obj;
+ Py_ssize_t ndata;
+ double *data;
+ int i;
+
+ if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
+ OUTVECTOR(data_obj,data,ndata);
+
+ free(self->params.err);
+ self->params.err = (double*) malloc(ndata*sizeof(double));
+
+ if(self->params.err==NULL) {
+ PyErr_SetString(CinvertorError,
+ "Cinvertor.set_err: problem allocating memory.");
+ return NULL;
+ }
+
+ for (i=0; i<ndata; i++) {
+ self->params.err[i] = data[i];
+ }
+
+ //self->params.err = data;
+ self->params.nerr = (int)ndata;
+ return Py_BuildValue("i", self->params.nerr);
+}
+
+const char get_err_doc[] =
+ "Function to get the err data\n"
+ "Takes an array of doubles as input.\n"
+ " @return: number of entries found";
+
+static PyObject * get_err(Cinvertor *self, PyObject *args) {
+ PyObject *data_obj;
+ Py_ssize_t ndata;
+ double *data;
+ int i;
+
+ if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
+ OUTVECTOR(data_obj, data, ndata);
+
+ // Check that the input array is large enough
+ if (ndata < self->params.nerr) {
+ PyErr_SetString(CinvertorError,
+ "Cinvertor.get_err: input array too short for data.");
+ return NULL;
+ }
+
+ for(i=0; i<self->params.nerr; i++){
+ data[i] = self->params.err[i];
+ }
+
+ return Py_BuildValue("i", self->params.npoints);
+}
+
+const char is_valid_doc[] =
+ "Check the validity of the stored data\n"
+ " @return: Returns the number of points if it's all good, -1 otherwise";
+
+/**
+ * Check the validity of the stored data
+ * Returns the number of points if it's all good, -1 otherwise
+ */
+static PyObject * is_valid(Cinvertor *self, PyObject *args) {
+ if(self->params.npoints==self->params.ny &&
+ self->params.npoints==self->params.nerr) {
+ return Py_BuildValue("i", self->params.npoints);
+ } else {
+ return Py_BuildValue("i", -1);
+ }
+}
+
+const char set_est_bck_doc[] =
+ "Sets background flag\n";
+
+/**
+ * Sets the maximum distance
+ */
+static PyObject * set_est_bck(Cinvertor *self, PyObject *args) {
+ int est_bck;
+
+ if (!PyArg_ParseTuple(args, "i", &est_bck)) return NULL;
+ self->params.est_bck = est_bck;
+ return Py_BuildValue("i", self->params.est_bck);
+}
+
+const char get_est_bck_doc[] =
+ "Gets background flag\n";
+
+/**
+ * Gets the maximum distance
+ */
+static PyObject * get_est_bck(Cinvertor *self, PyObject *args) {
+ return Py_BuildValue("i", self->params.est_bck);
+}
+
+const char set_dmax_doc[] =
+ "Sets the maximum distance\n";
+
+/**
+ * Sets the maximum distance
+ */
+static PyObject * set_dmax(Cinvertor *self, PyObject *args) {
+ double d_max;
+
+ if (!PyArg_ParseTuple(args, "d", &d_max)) return NULL;
+ self->params.d_max = d_max;
+ return Py_BuildValue("d", self->params.d_max);
+}
+
+const char get_dmax_doc[] =
+ "Gets the maximum distance\n";
+
+/**
+ * Gets the maximum distance
+ */
+static PyObject * get_dmax(Cinvertor *self, PyObject *args) {
+ return Py_BuildValue("d", self->params.d_max);
+}
+
+const char set_slit_height_doc[] =
+ "Sets the slit height in units of q [A-1]\n";
+
+/**
+ * Sets the slit height
+ */
+static PyObject * set_slit_height(Cinvertor *self, PyObject *args) {
+ double slit_height;
+
+ if (!PyArg_ParseTuple(args, "d", &slit_height)) return NULL;
+ self->params.slit_height = slit_height;
+ return Py_BuildValue("d", self->params.slit_height);
+}
+
+const char get_slit_height_doc[] =
+ "Gets the slit height\n";
+
+/**
+ * Gets the slit height
+ */
+static PyObject * get_slit_height(Cinvertor *self, PyObject *args) {
+ return Py_BuildValue("d", self->params.slit_height);
+}
+
+const char set_slit_width_doc[] =
+ "Sets the slit width in units of q [A-1]\n";
+
+/**
+ * Sets the slit width
+ */
+static PyObject * set_slit_width(Cinvertor *self, PyObject *args) {
+ double slit_width;
+
+ if (!PyArg_ParseTuple(args, "d", &slit_width)) return NULL;
+ self->params.slit_width = slit_width;
+ return Py_BuildValue("d", self->params.slit_width);
+}
+
+const char get_slit_width_doc[] =
+ "Gets the slit width\n";
+
+/**
+ * Gets the slit width
+ */
+static PyObject * get_slit_width(Cinvertor *self, PyObject *args) {
+ return Py_BuildValue("d", self->params.slit_width);
+}
+
+
+const char set_qmin_doc[] =
+ "Sets the minimum q\n";
+
+/**
+ * Sets the minimum q
+ */
+static PyObject * set_qmin(Cinvertor *self, PyObject *args) {
+ double q_min;
+
+ if (!PyArg_ParseTuple(args, "d", &q_min)) return NULL;
+ self->params.q_min = q_min;
+ return Py_BuildValue("d", self->params.q_min);
+}
+
+const char get_qmin_doc[] =
+ "Gets the minimum q\n";
+
+/**
+ * Gets the minimum q
+ */
+static PyObject * get_qmin(Cinvertor *self, PyObject *args) {
+ return Py_BuildValue("d", self->params.q_min);
+}
+
+const char set_qmax_doc[] =
+ "Sets the maximum q\n";
+
+/**
+ * Sets the maximum q
+ */
+static PyObject * set_qmax(Cinvertor *self, PyObject *args) {
+ double q_max;
+
+ if (!PyArg_ParseTuple(args, "d", &q_max)) return NULL;
+ self->params.q_max = q_max;
+ return Py_BuildValue("d", self->params.q_max);
+}
+
+const char get_qmax_doc[] =
+ "Gets the maximum q\n";
+
+/**
+ * Gets the maximum q
+ */
+static PyObject * get_qmax(Cinvertor *self, PyObject *args) {
+ return Py_BuildValue("d", self->params.q_max);
+}
+
+const char set_alpha_doc[] =
+ "Sets the alpha parameter\n";
+
+static PyObject * set_alpha(Cinvertor *self, PyObject *args) {
+ double alpha;
+
+ if (!PyArg_ParseTuple(args, "d", &alpha)) return NULL;
+ self->params.alpha = alpha;
+ return Py_BuildValue("d", self->params.alpha);
+}
+
+const char get_alpha_doc[] =
+ "Gets the alpha parameter\n";
+
+/**
+ * Gets the maximum distance
+ */
+static PyObject * get_alpha(Cinvertor *self, PyObject *args) {
+ return Py_BuildValue("d", self->params.alpha);
+}
+
+const char get_nx_doc[] =
+ "Gets the number of x points\n";
+
+/**
+ * Gets the number of x points
+ */
+static PyObject * get_nx(Cinvertor *self, PyObject *args) {
+ return Py_BuildValue("i", self->params.npoints);
+}
+
+const char get_ny_doc[] =
+ "Gets the number of y points\n";
+
+/**
+ * Gets the number of y points
+ */
+static PyObject * get_ny(Cinvertor *self, PyObject *args) {
+ return Py_BuildValue("i", self->params.ny);
+}
+
+const char get_nerr_doc[] =
+ "Gets the number of err points\n";
+
+/**
+ * Gets the number of error points
+ */
+static PyObject * get_nerr(Cinvertor *self, PyObject *args) {
+ return Py_BuildValue("i", self->params.nerr);
+}
+
+
+const char residuals_doc[] =
+ "Function to call to evaluate the residuals\n"
+ "for P(r) inversion\n"
+ " @param args: input parameters\n"
+ " @return: list of residuals";
+
+/**
+ * Function to call to evaluate the residuals
+ * @param args: input parameters
+ * @return: list of residuals
+ */
+static PyObject * residuals(Cinvertor *self, PyObject *args) {
+ double *pars;
+ PyObject* residuals;
+ int i;
+ double residual, diff;
+ // Regularization factor
+ double regterm = 0.0;
+ // Number of slices in regularization term estimate
+ int nslice = 25;
+
+ PyObject *data_obj;
+ Py_ssize_t npars;
+
+ if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
+
+ OUTVECTOR(data_obj,pars,npars);
+
+ // PyList of residuals
+ // Should create this list only once and refill it
+ residuals = PyList_New(self->params.npoints);
+
+ regterm = reg_term(pars, self->params.d_max, (int)npars, nslice);
+
+ for(i=0; i<self->params.npoints; i++) {
+ diff = self->params.y[i] - iq(pars, self->params.d_max, (int)npars, self->params.x[i]);
+ residual = diff*diff / (self->params.err[i]*self->params.err[i]);
+
+ // regularization term
+ residual += self->params.alpha * regterm;
+
+ if (PyList_SetItem(residuals, i, Py_BuildValue("d",residual) ) < 0){
+ PyErr_SetString(CinvertorError,
+ "Cinvertor.residuals: error setting residual.");
+ return NULL;
+ };
+ }
+ return residuals;
+}
+
+const char pr_residuals_doc[] =
+ "Function to call to evaluate the residuals\n"
+ "for P(r) minimization (for testing purposes)\n"
+ " @param args: input parameters\n"
+ " @return: list of residuals";
+
+/**
+ * Function to call to evaluate the residuals
+ * for P(r) minimization (for testing purposes)
+ * @param args: input parameters
+ * @return: list of residuals
+ */
+static PyObject * pr_residuals(Cinvertor *self, PyObject *args) {
+ double *pars;
+ PyObject* residuals;
+ int i;
+ double residual, diff;
+ // Regularization factor
+ double regterm = 0.0;
+ // Number of slices in regularization term estimate
+ int nslice = 25;
+
+ PyObject *data_obj;
+ Py_ssize_t npars;
+
+ if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
+
+ OUTVECTOR(data_obj,pars,npars);
+
+ // Should create this list only once and refill it
+ residuals = PyList_New(self->params.npoints);
+
+ regterm = reg_term(pars, self->params.d_max, (int)npars, nslice);
+
+
+ for(i=0; i<self->params.npoints; i++) {
+ diff = self->params.y[i] - pr(pars, self->params.d_max, (int)npars, self->params.x[i]);
+ residual = diff*diff / (self->params.err[i]*self->params.err[i]);
+
+ // regularization term
+ residual += self->params.alpha * regterm;
+
+ if (PyList_SetItem(residuals, i, Py_BuildValue("d",residual) ) < 0){
+ PyErr_SetString(CinvertorError,
+ "Cinvertor.residuals: error setting residual.");
+ return NULL;
+ };
+ }
+ return residuals;
+}
+
+const char get_iq_doc[] =
+ "Function to call to evaluate the scattering intensity\n"
+ " @param args: c-parameters, and q\n"
+ " @return: I(q)";
+
+/**
+ * Function to call to evaluate the scattering intensity
+ * @param args: c-parameters, and q
+ * @return: I(q)
+ */
+static PyObject * get_iq(Cinvertor *self, PyObject *args) {
+ double *pars;
+ double q, iq_value;
+ PyObject *data_obj;
+ Py_ssize_t npars;
+
+ if (!PyArg_ParseTuple(args, "Od", &data_obj, &q)) return NULL;
+ OUTVECTOR(data_obj,pars,npars);
+
+ iq_value = iq(pars, self->params.d_max, (int)npars, q);
+ return Py_BuildValue("f", iq_value);
+}
+
+const char get_iq_smeared_doc[] =
+ "Function to call to evaluate the scattering intensity.\n"
+ "The scattering intensity is slit-smeared."
+ " @param args: c-parameters, and q\n"
+ " @return: I(q)";
+
+/**
+ * Function to call to evaluate the scattering intensity
+ * The scattering intensity is slit-smeared.
+ * @param args: c-parameters, and q
+ * @return: I(q)
+ */
+static PyObject * get_iq_smeared(Cinvertor *self, PyObject *args) {
+ double *pars;
+ double q, iq_value;
+ PyObject *data_obj;
+ Py_ssize_t npars;
+
+ if (!PyArg_ParseTuple(args, "Od", &data_obj, &q)) return NULL;
+ OUTVECTOR(data_obj,pars,npars);
+
+ iq_value = iq_smeared(pars, self->params.d_max, (int)npars,
+ self->params.slit_height, self->params.slit_width,
+ q, 21);
+ return Py_BuildValue("f", iq_value);
+}
+
+const char get_pr_doc[] =
+ "Function to call to evaluate P(r)\n"
+ " @param args: c-parameters and r\n"
+ " @return: P(r)";
+
+/**
+ * Function to call to evaluate P(r)
+ * @param args: c-parameters and r
+ * @return: P(r)
+ */
+static PyObject * get_pr(Cinvertor *self, PyObject *args) {
+ double *pars;
+ double r, pr_value;
+ PyObject *data_obj;
+ Py_ssize_t npars;
+
+ if (!PyArg_ParseTuple(args, "Od", &data_obj, &r)) return NULL;
+ OUTVECTOR(data_obj,pars,npars);
+
+ pr_value = pr(pars, self->params.d_max, (int)npars, r);
+ return Py_BuildValue("f", pr_value);
+}
+
+const char get_pr_err_doc[] =
+ "Function to call to evaluate P(r) with errors\n"
+ " @param args: c-parameters and r\n"
+ " @return: (P(r),dP(r))";
+
+/**
+ * Function to call to evaluate P(r) with errors
+ * @param args: c-parameters and r
+ * @return: P(r)
+ */
+static PyObject * get_pr_err(Cinvertor *self, PyObject *args) {
+ double *pars;
+ double *pars_err;
+ double pr_err_value;
+ double r, pr_value;
+ PyObject *data_obj;
+ Py_ssize_t npars;
+ PyObject *err_obj;
+ Py_ssize_t npars2;
+
+ if (!PyArg_ParseTuple(args, "OOd", &data_obj, &err_obj, &r)) return NULL;
+ OUTVECTOR(data_obj,pars,npars);
+
+ if (err_obj == Py_None) {
+ pr_value = pr(pars, self->params.d_max, (int)npars, r);
+ pr_err_value = 0.0;
+ } else {
+ OUTVECTOR(err_obj,pars_err,npars2);
+ pr_err(pars, pars_err, self->params.d_max, (int)npars, r, &pr_value, &pr_err_value);
+ }
+ return Py_BuildValue("ff", pr_value, pr_err_value);
+}
+
+const char basefunc_ft_doc[] =
+ "Returns the value of the nth Fourier transofrmed base function\n"
+ " @param args: c-parameters, n and q\n"
+ " @return: nth Fourier transformed base function, evaluated at q";
+
+static PyObject * basefunc_ft(Cinvertor *self, PyObject *args) {
+ double d_max, q;
+ int n;
+
+ if (!PyArg_ParseTuple(args, "did", &d_max, &n, &q)) return NULL;
+ return Py_BuildValue("f", ortho_transformed(d_max, n, q));
+
+}
+
+const char oscillations_doc[] =
+ "Returns the value of the oscillation figure of merit for\n"
+ "the given set of coefficients. For a sphere, the oscillation\n"
+ "figure of merit is 1.1.\n"
+ " @param args: c-parameters\n"
+ " @return: oscillation figure of merit";
+
+static PyObject * oscillations(Cinvertor *self, PyObject *args) {
+ double *pars;
+ PyObject *data_obj;
+ Py_ssize_t npars;
+ double oscill, norm;
+
+ if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
+ OUTVECTOR(data_obj,pars,npars);
+
+ oscill = reg_term(pars, self->params.d_max, (int)npars, 100);
+ norm = int_p2(pars, self->params.d_max, (int)npars, 100);
+ return Py_BuildValue("f", sqrt(oscill/norm)/acos(-1.0)*self->params.d_max );
+
+}
+
+const char get_peaks_doc[] =
+ "Returns the number of peaks in the output P(r) distrubution\n"
+ "for the given set of coefficients.\n"
+ " @param args: c-parameters\n"
+ " @return: number of P(r) peaks";
+
+static PyObject * get_peaks(Cinvertor *self, PyObject *args) {
+ double *pars;
+ PyObject *data_obj;
+ Py_ssize_t npars;
+ int count;
+
+ if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
+ OUTVECTOR(data_obj,pars,npars);
+
+ count = npeaks(pars, self->params.d_max, (int)npars, 100);
+
+ return Py_BuildValue("i", count );
+
+}
+
+const char get_positive_doc[] =
+ "Returns the fraction of P(r) that is positive over\n"
+ "the full range of r for the given set of coefficients.\n"
+ " @param args: c-parameters\n"
+ " @return: fraction of P(r) that is positive";
+
+static PyObject * get_positive(Cinvertor *self, PyObject *args) {
+ double *pars;
+ PyObject *data_obj;
+ Py_ssize_t npars;
+ double fraction;
+
+ if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
+ OUTVECTOR(data_obj,pars,npars);
+
+ fraction = positive_integral(pars, self->params.d_max, (int)npars, 100);
+
+ return Py_BuildValue("f", fraction );
+
+}
+
+const char get_pos_err_doc[] =
+ "Returns the fraction of P(r) that is 1 standard deviation\n"
+ "above zero over the full range of r for the given set of coefficients.\n"
+ " @param args: c-parameters\n"
+ " @return: fraction of P(r) that is positive";
+
+static PyObject * get_pos_err(Cinvertor *self, PyObject *args) {
+ double *pars;
+ double *pars_err;
+ PyObject *data_obj;
+ PyObject *err_obj;
+ Py_ssize_t npars;
+ Py_ssize_t npars2;
+ double fraction;
+
+ if (!PyArg_ParseTuple(args, "OO", &data_obj, &err_obj)) return NULL;
+ OUTVECTOR(data_obj,pars,npars);
+ OUTVECTOR(err_obj,pars_err,npars2);
+
+ fraction = positive_errors(pars, pars_err, self->params.d_max, (int)npars, 51);
+
+ return Py_BuildValue("f", fraction );
+
+}
+
+const char get_rg_doc[] =
+ "Returns the value of the radius of gyration Rg.\n"
+ " @param args: c-parameters\n"
+ " @return: Rg";
+
+static PyObject * get_rg(Cinvertor *self, PyObject *args) {
+ double *pars;
+ PyObject *data_obj;
+ Py_ssize_t npars;
+ double value;
+
+ if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
+ OUTVECTOR(data_obj,pars,npars);
+
+ value = rg(pars, self->params.d_max, (int)npars, 101);
+
+ return Py_BuildValue("f", value );
+
+}
+
+const char get_iq0_doc[] =
+ "Returns the value of I(q=0).\n"
+ " @param args: c-parameters\n"
+ " @return: I(q=0)";
+
+static PyObject * get_iq0(Cinvertor *self, PyObject *args) {
+ double *pars;
+ PyObject *data_obj;
+ Py_ssize_t npars;
+ double value;
+
+ if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
+ OUTVECTOR(data_obj,pars,npars);
+
+ value = 4.0*acos(-1.0)*int_pr(pars, self->params.d_max, (int)npars, 101);
+
+ return Py_BuildValue("f", value );
+
+}
+
+/**
+ * Check whether a q-value is within acceptabel limits
+ * Return 1 if accepted, 0 if rejected.
+ */
+int accept_q(Cinvertor *self, double q) {
+ if (self->params.q_min>0 && q<self->params.q_min) return 0;
+ if (self->params.q_max>0 && q>self->params.q_max) return 0;
+ return 1;
+}
+
+const char get_matrix_doc[] =
+ "Returns A matrix and b vector for least square problem.\n"
+ " @param nfunc: number of base functions\n"
+ " @param nr: number of r-points used when evaluating reg term.\n"
+ " @param a: A array to fill\n"
+ " @param b: b vector to fill\n"
+ " @return: 0";
+
+static PyObject * get_matrix(Cinvertor *self, PyObject *args) {
+ double *a;
+ double *b;
+ PyObject *a_obj;
+ PyObject *b_obj;
+ Py_ssize_t n_a;
+ Py_ssize_t n_b;
+ // Number of bins for regularization term evaluation
+ int nr, nfunc;
+ int i, j, i_r;
+ double r, sqrt_alpha, pi;
+ double tmp;
+ int offset;
+
+ if (!PyArg_ParseTuple(args, "iiOO", &nfunc, &nr, &a_obj, &b_obj)) return NULL;
+ OUTVECTOR(a_obj,a,n_a);
+ OUTVECTOR(b_obj,b,n_b);
+
+ assert(n_b>=nfunc);
+ assert(n_a>=nfunc*(nr+self->params.npoints));
+
+ sqrt_alpha = sqrt(self->params.alpha);
+ pi = acos(-1.0);
+ offset = (self->params.est_bck==1) ? 0 : 1;
+
+ for (j=0; j<nfunc; j++) {
+ for (i=0; i<self->params.npoints; i++) {
+ if (self->params.err[i]==0.0) {
+ PyErr_SetString(CinvertorError,
+ "Cinvertor.get_matrix: Some I(Q) points have no error.");
+ return NULL;
+ }
+ if (accept_q(self, self->params.x[i])){
+ if (self->params.est_bck==1 && j==0) {
+ a[i*nfunc+j] = 1.0/self->params.err[i];
+ } else {
+ if (self->params.slit_width>0 || self->params.slit_height>0) {
+ a[i*nfunc+j] = ortho_transformed_smeared(self->params.d_max,
+ j+offset, self->params.slit_height, self->params.slit_width,
+ self->params.x[i], 21)/self->params.err[i];
+ } else {
+ a[i*nfunc+j] = ortho_transformed(self->params.d_max, j+offset, self->params.x[i])/self->params.err[i];
+ }
+ }
+ }
+ }
+ for (i_r=0; i_r<nr; i_r++){
+ if (self->params.est_bck==1 && j==0) {
+ a[(i_r+self->params.npoints)*nfunc+j] = 0.0;
+ } else {
+ r = self->params.d_max/nr*i_r;
+ tmp = pi*(j+offset)/self->params.d_max;
+ a[(i_r+self->params.npoints)*nfunc+j] = sqrt_alpha * 1.0/nr*self->params.d_max*2.0*
+ (2.0*pi*(j+offset)/self->params.d_max*cos(pi*(j+offset)*r/self->params.d_max) +
+ tmp*tmp*r * sin(pi*(j+offset)*r/self->params.d_max));
+ }
+ }
+ }
+
+ for (i=0; i<self->params.npoints; i++) {
+ if (accept_q(self, self->params.x[i])){
+ b[i] = self->params.y[i]/self->params.err[i];
+ }
+ }
+
+ return Py_BuildValue("i", 0);
+
+}
+
+const char get_invcov_matrix_doc[] =
+ " Compute the inverse covariance matrix, defined as inv_cov = a_transposed x a.\n"
+ " @param nfunc: number of base functions\n"
+ " @param nr: number of r-points used when evaluating reg term.\n"
+ " @param a: A array to fill\n"
+ " @param inv_cov: inverse covariance array to be filled\n"
+ " @return: 0";
+
+static PyObject * get_invcov_matrix(Cinvertor *self, PyObject *args) {
+ double *a;
+ PyObject *a_obj;
+ Py_ssize_t n_a;
+ double *inv_cov;
+ PyObject *cov_obj;
+ Py_ssize_t n_cov;
+ int nr, nfunc;
+ int i, j, k;
+
+ if (!PyArg_ParseTuple(args, "iiOO", &nfunc, &nr, &a_obj, &cov_obj)) return NULL;
+ OUTVECTOR(a_obj,a,n_a);
+ OUTVECTOR(cov_obj,inv_cov,n_cov);
+
+ assert(n_cov>=nfunc*nfunc);
+ assert(n_a>=nfunc*(nr+self->params.npoints));
+
+ for (i=0; i<nfunc; i++) {
+ for (j=0; j<nfunc; j++) {
+ inv_cov[i*nfunc+j] = 0.0;
+ for (k=0; k<nr+self->params.npoints; k++) {
+ inv_cov[i*nfunc+j] += a[k*nfunc+i]*a[k*nfunc+j];
+ }
+ }
+ }
+ return Py_BuildValue("i", 0);
+}
+
+const char get_reg_size_doc[] =
+ " Compute the covariance matrix, defined as inv_cov = a_transposed x a.\n"
+ " @param nfunc: number of base functions\n"
+ " @param nr: number of r-points used when evaluating reg term.\n"
+ " @param a: A array to fill\n"
+ " @param inv_cov: inverse covariance array to be filled\n"
+ " @return: 0";
+
+static PyObject * get_reg_size(Cinvertor *self, PyObject *args) {
+ double *a;
+ PyObject *a_obj;
+ Py_ssize_t n_a;
+ int nr, nfunc;
+ int i, j;
+ double sum_sig, sum_reg;
+
+ if (!PyArg_ParseTuple(args, "iiO", &nfunc, &nr, &a_obj)) return NULL;
+ OUTVECTOR(a_obj,a,n_a);
+
+ assert(n_a>=nfunc*(nr+self->params.npoints));
+
+ sum_sig = 0.0;
+ sum_reg = 0.0;
+ for (j=0; j<nfunc; j++){
+ for (i=0; i<self->params.npoints; i++){
+ if (accept_q(self, self->params.x[i])==1)
+ sum_sig += (a[i*nfunc+j])*(a[i*nfunc+j]);
+ }
+ for (i=0; i<nr; i++){
+ sum_reg += (a[(i+self->params.npoints)*nfunc+j])*(a[(i+self->params.npoints)*nfunc+j]);
+ }
+ }
+ return Py_BuildValue("ff", sum_sig, sum_reg);
+}
+
+const char eeeget_qmin_doc[] = "\
+This is a multiline doc string.\n\
+\n\
+This is the second line.";
+const char eeeset_qmin_doc[] =
+ "This is a multiline doc string.\n"
+ "\n"
+ "This is the second line.";
+
+static PyMethodDef Cinvertor_methods[] = {
+ {"residuals", (PyCFunction)residuals, METH_VARARGS, residuals_doc},
+ {"pr_residuals", (PyCFunction)pr_residuals, METH_VARARGS, pr_residuals_doc},
+ {"set_x", (PyCFunction)set_x, METH_VARARGS, set_x_doc},
+ {"get_x", (PyCFunction)get_x, METH_VARARGS, get_x_doc},
+ {"set_y", (PyCFunction)set_y, METH_VARARGS, set_y_doc},
+ {"get_y", (PyCFunction)get_y, METH_VARARGS, get_y_doc},
+ {"set_err", (PyCFunction)set_err, METH_VARARGS, set_err_doc},
+ {"get_err", (PyCFunction)get_err, METH_VARARGS, get_err_doc},
+ {"set_dmax", (PyCFunction)set_dmax, METH_VARARGS, set_dmax_doc},
+ {"get_dmax", (PyCFunction)get_dmax, METH_VARARGS, get_dmax_doc},
+ {"set_qmin", (PyCFunction)set_qmin, METH_VARARGS, set_qmin_doc},
+ {"get_qmin", (PyCFunction)get_qmin, METH_VARARGS, get_qmin_doc},
+ {"set_qmax", (PyCFunction)set_qmax, METH_VARARGS, set_qmax_doc},
+ {"get_qmax", (PyCFunction)get_qmax, METH_VARARGS, get_qmax_doc},
+ {"set_alpha", (PyCFunction)set_alpha, METH_VARARGS, set_alpha_doc},
+ {"get_alpha", (PyCFunction)get_alpha, METH_VARARGS, get_alpha_doc},
+ {"set_slit_width", (PyCFunction)set_slit_width, METH_VARARGS, set_slit_width_doc},
+ {"get_slit_width", (PyCFunction)get_slit_width, METH_VARARGS, get_slit_width_doc},
+ {"set_slit_height", (PyCFunction)set_slit_height, METH_VARARGS, set_slit_height_doc},
+ {"get_slit_height", (PyCFunction)get_slit_height, METH_VARARGS, get_slit_height_doc},
+ {"set_est_bck", (PyCFunction)set_est_bck, METH_VARARGS, set_est_bck_doc},
+ {"get_est_bck", (PyCFunction)get_est_bck, METH_VARARGS, get_est_bck_doc},
+ {"get_nx", (PyCFunction)get_nx, METH_VARARGS, get_nx_doc},
+ {"get_ny", (PyCFunction)get_ny, METH_VARARGS, get_ny_doc},
+ {"get_nerr", (PyCFunction)get_nerr, METH_VARARGS, get_nerr_doc},
+ {"iq", (PyCFunction)get_iq, METH_VARARGS, get_iq_doc},
+ {"iq_smeared", (PyCFunction)get_iq_smeared, METH_VARARGS, get_iq_smeared_doc},
+ {"pr", (PyCFunction)get_pr, METH_VARARGS, get_pr_doc},
+ {"get_pr_err", (PyCFunction)get_pr_err, METH_VARARGS, get_pr_err_doc},
+ {"is_valid", (PyCFunction)is_valid, METH_VARARGS, is_valid_doc},
+ {"basefunc_ft", (PyCFunction)basefunc_ft, METH_VARARGS, basefunc_ft_doc},
+ {"oscillations", (PyCFunction)oscillations, METH_VARARGS, oscillations_doc},
+ {"get_peaks", (PyCFunction)get_peaks, METH_VARARGS, get_peaks_doc},
+ {"get_positive", (PyCFunction)get_positive, METH_VARARGS, get_positive_doc},
+ {"get_pos_err", (PyCFunction)get_pos_err, METH_VARARGS, get_pos_err_doc},
+ {"rg", (PyCFunction)get_rg, METH_VARARGS, get_rg_doc},
+ {"iq0", (PyCFunction)get_iq0, METH_VARARGS, get_iq0_doc},
+ {"_get_matrix", (PyCFunction)get_matrix, METH_VARARGS, get_matrix_doc},
+ {"_get_invcov_matrix", (PyCFunction)get_invcov_matrix, METH_VARARGS, get_invcov_matrix_doc},
+ {"_get_reg_size", (PyCFunction)get_reg_size, METH_VARARGS, get_reg_size_doc},
+
+ {NULL}
+};
+
+static PyTypeObject CinvertorType = {
+ //PyObject_HEAD_INIT(NULL)
+ //0, /*ob_size*/
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "Cinvertor", /*tp_name*/
+ sizeof(Cinvertor), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)Cinvertor_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ "Cinvertor objects", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ Cinvertor_methods, /* tp_methods */
+ Cinvertor_members, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)Cinvertor_init, /* tp_init */
+ 0, /* tp_alloc */
+ Cinvertor_new, /* tp_new */
+};
+
+
+static PyMethodDef module_methods[] = {
+ {NULL}
+};
+
+/**
+ * Function used to add the model class to a module
+ * @param module: module to add the class to
+ */
+void addCinvertor(PyObject *module) {
+ PyObject *d;
+
+ if (PyType_Ready(&CinvertorType) < 0)
+ return;
+
+ Py_INCREF(&CinvertorType);
+ PyModule_AddObject(module, "Cinvertor", (PyObject *)&CinvertorType);
+
+ d = PyModule_GetDict(module);
+ CinvertorError = PyErr_NewException("sas.sascalc.pr.invertor.Cinvertor.InvertorError", PyExc_RuntimeError, NULL);
+ PyDict_SetItemString(d, "CinvertorError", CinvertorError);
+}
+
+
+#define MODULE_DOC "C extension module for inversion to P(r)."
+#define MODULE_NAME "pr_inversion"
+#define MODULE_INIT2 initpr_inversion
+#define MODULE_INIT3 PyInit_pr_inversion
+#define MODULE_METHODS module_methods
+
+/* ==== boilerplate python 2/3 interface bootstrap ==== */
+
+
+#if defined(WIN32) && !defined(__MINGW32__)
+ #define DLL_EXPORT __declspec(dllexport)
+#else
+ #define DLL_EXPORT
+#endif
+
+#if PY_MAJOR_VERSION >= 3
+
+ DLL_EXPORT PyMODINIT_FUNC MODULE_INIT3(void)
+ {
+ static struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT,
+ MODULE_NAME, /* m_name */
+ MODULE_DOC, /* m_doc */
+ -1, /* m_size */
+ MODULE_METHODS, /* m_methods */
+ NULL, /* m_reload */
+ NULL, /* m_traverse */
+ NULL, /* m_clear */
+ NULL, /* m_free */
+ };
+ PyObject* m = PyModule_Create(&moduledef);
+ addCinvertor(m);
+ return m;
+ }
+
+#else /* !PY_MAJOR_VERSION >= 3 */
+
+ DLL_EXPORT PyMODINIT_FUNC MODULE_INIT2(void)
+ {
+ PyObject* m = Py_InitModule4(MODULE_NAME,
+ MODULE_METHODS,
+ MODULE_DOC,
+ 0,
+ PYTHON_API_VERSION
+ );
+ addCinvertor(m);
+ }
+
+#endif /* !PY_MAJOR_VERSION >= 3 */
\ No newline at end of file
diff --git a/src/sas/sascalc/pr/c_extensions/__init__.py b/src/sas/sascalc/pr/c_extensions/__init__.py
index 7f8dd09..30328b3 100644
--- a/src/sas/sascalc/pr/c_extensions/__init__.py
+++ b/src/sas/sascalc/pr/c_extensions/__init__.py
@@ -1,3 +1,3 @@
-"""
- C extensions to provide the P(r) inversion computations.
-"""
+"""
+ C extensions to provide the P(r) inversion computations.
+"""
diff --git a/src/sas/sascalc/pr/c_extensions/invertor.c b/src/sas/sascalc/pr/c_extensions/invertor.c
index 3b97992..b6c5372 100644
--- a/src/sas/sascalc/pr/c_extensions/invertor.c
+++ b/src/sas/sascalc/pr/c_extensions/invertor.c
@@ -1,315 +1,314 @@
-#include <math.h>
-#include "invertor.h"
-#include <memory.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-double pi = 3.1416;
-
-/**
- * Deallocate memory
- */
-void invertor_dealloc(Invertor_params *pars) {
- free(pars->x);
- free(pars->y);
- free(pars->err);
-}
-
-void invertor_init(Invertor_params *pars) {
- pars->d_max = 180;
- pars->q_min = -1.0;
- pars->q_max = -1.0;
- pars->has_bck = 0;
-}
-
-
-/**
- * P(r) of a sphere, for test purposes
- *
- * @param R: radius of the sphere
- * @param r: distance, in the same units as the radius
- * @return: P(r)
- */
-double pr_sphere(double R, double r) {
- if (r <= 2.0*R) {
- return 12.0* pow(0.5*r/R, 2.0) * pow(1.0-0.5*r/R, 2.0) * ( 2.0 + 0.5*r/R );
- } else {
- return 0.0;
- }
-}
-
-/**
- * Orthogonal functions:
- * B(r) = 2r sin(pi*nr/d)
- *
- */
-double ortho(double d_max, int n, double r) {
- return 2.0*r*sin(pi*n*r/d_max);
-}
-
-/**
- * Fourier transform of the nth orthogonal function
- *
- */
-double ortho_transformed(double d_max, int n, double q) {
- return 8.0*pow(pi, 2.0)/q * d_max * n * pow(-1.0, n+1)
- *sin(q*d_max) / ( pow(pi*n, 2.0) - pow(q*d_max, 2.0) );
-}
-
-/**
- * Slit-smeared Fourier transform of the nth orthogonal function.
- * Smearing follows Lake, Acta Cryst. (1967) 23, 191.
- */
-double ortho_transformed_smeared(double d_max, int n, double height, double width, double q, int npts) {
- double sum, y, z;
- int i, j, n_height, n_width;
- double count_w;
- double fnpts;
- sum = 0.0;
- fnpts = (float)npts-1.0;
-
- // Check for zero slit size
- n_height = (height>0) ? npts : 1;
- n_width = (width>0) ? npts : 1;
-
- count_w = 0.0;
-
- for(j=0; j<n_height; j++) {
- if(height>0){
- z = height/fnpts*(float)j;
- } else {
- z = 0.0;
- }
-
- for(i=0; i<n_width; i++) {
- if(width>0){
- y = -width/2.0+width/fnpts*(float)i;
- } else {
- y = 0.0;
- }
- if (((q-y)*(q-y)+z*z)<=0.0) continue;
- count_w += 1.0;
- sum += ortho_transformed(d_max, n, sqrt((q-y)*(q-y)+z*z));
- }
- }
- return sum/count_w;
-}
-
-/**
- * First derivative in of the orthogonal function dB(r)/dr
- *
- */
-double ortho_derived(double d_max, int n, double r) {
- return 2.0*sin(pi*n*r/d_max) + 2.0*r*cos(pi*n*r/d_max);
-}
-
-/**
- * Scattering intensity calculated from the expansion.
- */
-double iq(double *pars, double d_max, int n_c, double q) {
- double sum = 0.0;
- int i;
- for (i=0; i<n_c; i++) {
- sum += pars[i] * ortho_transformed(d_max, i+1, q);
- }
- return sum;
-}
-
-/**
- * Scattering intensity calculated from the expansion,
- * slit-smeared.
- */
-double iq_smeared(double *pars, double d_max, int n_c, double height, double width, double q, int npts) {
- double sum = 0.0;
- int i;
- for (i=0; i<n_c; i++) {
- sum += pars[i] * ortho_transformed_smeared(d_max, i+1, height, width, q, npts);
- }
- return sum;
-}
-
-/**
- * P(r) calculated from the expansion.
- */
-double pr(double *pars, double d_max, int n_c, double r) {
- double sum = 0.0;
- int i;
- for (i=0; i<n_c; i++) {
- sum += pars[i] * ortho(d_max, i+1, r);
- }
- return sum;
-}
-
-/**
- * P(r) calculated from the expansion, with errors
- */
-void pr_err(double *pars, double *err, double d_max, int n_c,
- double r, double *pr_value, double *pr_value_err) {
- double sum = 0.0;
- double sum_err = 0.0;
- double func_value;
- int i;
- for (i=0; i<n_c; i++) {
- func_value = ortho(d_max, i+1, r);
- sum += pars[i] * func_value;
- //sum_err += err[i]*err[i]*func_value*func_value;
- sum_err += err[i*n_c+i]*func_value*func_value;
- }
- *pr_value = sum;
- if (sum_err>0) {
- *pr_value_err = sqrt(sum_err);
- } else {
- *pr_value_err = sum;
- }
-}
-
-/**
- * dP(r)/dr calculated from the expansion.
- */
-double dprdr(double *pars, double d_max, int n_c, double r) {
- double sum = 0.0;
- int i;
- for (i=0; i<n_c; i++) {
- sum += pars[i] * 2.0*(sin(pi*(i+1)*r/d_max) + pi*(i+1)*r/d_max * cos(pi*(i+1)*r/d_max));
- }
- return sum;
-}
-
-/**
- * regularization term calculated from the expansion.
- */
-double reg_term(double *pars, double d_max, int n_c, int nslice) {
- double sum = 0.0;
- double r;
- double deriv;
- int i;
- for (i=0; i<nslice; i++) {
- r = d_max/(1.0*nslice)*i;
- deriv = dprdr(pars, d_max, n_c, r);
- sum += deriv*deriv;
- }
- return sum/(1.0*nslice)*d_max;
-}
-
-/**
- * regularization term calculated from the expansion.
- */
-double int_p2(double *pars, double d_max, int n_c, int nslice) {
- double sum = 0.0;
- double r;
- double value;
- int i;
- for (i=0; i<nslice; i++) {
- r = d_max/(1.0*nslice)*i;
- value = pr(pars, d_max, n_c, r);
- sum += value*value;
- }
- return sum/(1.0*nslice)*d_max;
-}
-
-/**
- * Integral of P(r)
- */
-double int_pr(double *pars, double d_max, int n_c, int nslice) {
- double sum = 0.0;
- double r;
- double value;
- int i;
- for (i=0; i<nslice; i++) {
- r = d_max/(1.0*nslice)*i;
- value = pr(pars, d_max, n_c, r);
- sum += value;
- }
- return sum/(1.0*nslice)*d_max;
-}
-
-/**
- * Get the number of P(r) peaks.
- */
-int npeaks(double *pars, double d_max, int n_c, int nslice) {
- double r;
- double value;
- int i;
- double previous = 0.0;
- double slope = 0.0;
- int count = 0;
- for (i=0; i<nslice; i++) {
- r = d_max/(1.0*nslice)*i;
- value = pr(pars, d_max, n_c, r);
- if (previous<=value){
- //if (slope<0) count += 1;
- slope = 1;
- } else {
- //printf("slope -1");
- if (slope>0) count += 1;
- slope = -1;
- }
- previous = value;
- }
- return count;
-}
-
-/**
- * Get the fraction of the integral of P(r) over the whole range
- * of r that is above zero.
- * A valid P(r) is define as being positive for all r.
- */
-double positive_integral(double *pars, double d_max, int n_c, int nslice) {
- double r;
- double value;
- int i;
- double sum_pos = 0.0;
- double sum = 0.0;
-
- for (i=0; i<nslice; i++) {
- r = d_max/(1.0*nslice)*i;
- value = pr(pars, d_max, n_c, r);
- if (value>0.0) sum_pos += value;
- sum += fabs(value);
- }
- return sum_pos/sum;
-}
-
-/**
- * Get the fraction of the integral of P(r) over the whole range
- * of r that is at least one sigma above zero.
- */
-double positive_errors(double *pars, double *err, double d_max, int n_c, int nslice) {
- double r;
- int i;
- double sum_pos = 0.0;
- double sum = 0.0;
- double pr_val;
- double pr_val_err;
-
- for (i=0; i<nslice; i++) {
- r = d_max/(1.0*nslice)*i;
- pr_err(pars, err, d_max, n_c, r, &pr_val, &pr_val_err);
- if (pr_val>pr_val_err) sum_pos += pr_val;
- sum += fabs(pr_val);
-
-
- }
- return sum_pos/sum;
-}
-
-/**
- * R_g radius of gyration calculation
- *
- * R_g**2 = integral[r**2 * p(r) dr] / (2.0 * integral[p(r) dr])
- */
-double rg(double *pars, double d_max, int n_c, int nslice) {
- double sum_r2 = 0.0;
- double sum = 0.0;
- double r;
- double value;
- int i;
- for (i=0; i<nslice; i++) {
- r = d_max/(1.0*nslice)*i;
- value = pr(pars, d_max, n_c, r);
- sum += value;
- sum_r2 += r*r*value;
- }
- return sqrt(sum_r2/(2.0*sum));
-}
-
+#include <math.h>
+#include "invertor.h"
+#include <memory.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+double pi = 3.1416;
+
+/**
+ * Deallocate memory
+ */
+void invertor_dealloc(Invertor_params *pars) {
+ free(pars->x);
+ free(pars->y);
+ free(pars->err);
+}
+
+void invertor_init(Invertor_params *pars) {
+ pars->d_max = 180;
+ pars->q_min = -1.0;
+ pars->q_max = -1.0;
+ pars->est_bck = 0;
+}
+
+
+/**
+ * P(r) of a sphere, for test purposes
+ *
+ * @param R: radius of the sphere
+ * @param r: distance, in the same units as the radius
+ * @return: P(r)
+ */
+double pr_sphere(double R, double r) {
+ if (r <= 2.0*R) {
+ return 12.0* pow(0.5*r/R, 2.0) * pow(1.0-0.5*r/R, 2.0) * ( 2.0 + 0.5*r/R );
+ } else {
+ return 0.0;
+ }
+}
+
+/**
+ * Orthogonal functions:
+ * B(r) = 2r sin(pi*nr/d)
+ *
+ */
+double ortho(double d_max, int n, double r) {
+ return 2.0*r*sin(pi*n*r/d_max);
+}
+
+/**
+ * Fourier transform of the nth orthogonal function
+ *
+ */
+double ortho_transformed(double d_max, int n, double q) {
+ return 8.0*pow(pi, 2.0)/q * d_max * n * pow(-1.0, n+1)
+ *sin(q*d_max) / ( pow(pi*n, 2.0) - pow(q*d_max, 2.0) );
+}
+
+/**
+ * Slit-smeared Fourier transform of the nth orthogonal function.
+ * Smearing follows Lake, Acta Cryst. (1967) 23, 191.
+ */
+double ortho_transformed_smeared(double d_max, int n, double height, double width, double q, int npts) {
+ double sum, y, z;
+ int i, j, n_height, n_width;
+ double count_w;
+ double fnpts;
+ sum = 0.0;
+ fnpts = (float)npts-1.0;
+
+ // Check for zero slit size
+ n_height = (height>0) ? npts : 1;
+ n_width = (width>0) ? npts : 1;
+
+ count_w = 0.0;
+
+ for(j=0; j<n_height; j++) {
+ if(height>0){
+ z = height/fnpts*(float)j;
+ } else {
+ z = 0.0;
+ }
+
+ for(i=0; i<n_width; i++) {
+ if(width>0){
+ y = -width/2.0+width/fnpts*(float)i;
+ } else {
+ y = 0.0;
+ }
+ if (((q-y)*(q-y)+z*z)<=0.0) continue;
+ count_w += 1.0;
+ sum += ortho_transformed(d_max, n, sqrt((q-y)*(q-y)+z*z));
+ }
+ }
+ return sum/count_w;
+}
+
+/**
+ * First derivative in of the orthogonal function dB(r)/dr
+ *
+ */
+double ortho_derived(double d_max, int n, double r) {
+ return 2.0*sin(pi*n*r/d_max) + 2.0*r*cos(pi*n*r/d_max);
+}
+
+/**
+ * Scattering intensity calculated from the expansion.
+ */
+double iq(double *pars, double d_max, int n_c, double q) {
+ double sum = 0.0;
+ int i;
+ for (i=0; i<n_c; i++) {
+ sum += pars[i] * ortho_transformed(d_max, i+1, q);
+ }
+ return sum;
+}
+
+/**
+ * Scattering intensity calculated from the expansion,
+ * slit-smeared.
+ */
+double iq_smeared(double *pars, double d_max, int n_c, double height, double width, double q, int npts) {
+ double sum = 0.0;
+ int i;
+ for (i=0; i<n_c; i++) {
+ sum += pars[i] * ortho_transformed_smeared(d_max, i+1, height, width, q, npts);
+ }
+ return sum;
+}
+
+/**
+ * P(r) calculated from the expansion.
+ */
+double pr(double *pars, double d_max, int n_c, double r) {
+ double sum = 0.0;
+ int i;
+ for (i=0; i<n_c; i++) {
+ sum += pars[i] * ortho(d_max, i+1, r);
+ }
+ return sum;
+}
+
+/**
+ * P(r) calculated from the expansion, with errors
+ */
+void pr_err(double *pars, double *err, double d_max, int n_c,
+ double r, double *pr_value, double *pr_value_err) {
+ double sum = 0.0;
+ double sum_err = 0.0;
+ double func_value;
+ int i;
+ for (i=0; i<n_c; i++) {
+ func_value = ortho(d_max, i+1, r);
+ sum += pars[i] * func_value;
+ //sum_err += err[i]*err[i]*func_value*func_value;
+ sum_err += err[i*n_c+i]*func_value*func_value;
+ }
+ *pr_value = sum;
+ if (sum_err>0) {
+ *pr_value_err = sqrt(sum_err);
+ } else {
+ *pr_value_err = sum;
+ }
+}
+
+/**
+ * dP(r)/dr calculated from the expansion.
+ */
+double dprdr(double *pars, double d_max, int n_c, double r) {
+ double sum = 0.0;
+ int i;
+ for (i=0; i<n_c; i++) {
+ sum += pars[i] * 2.0*(sin(pi*(i+1)*r/d_max) + pi*(i+1)*r/d_max * cos(pi*(i+1)*r/d_max));
+ }
+ return sum;
+}
+
+/**
+ * regularization term calculated from the expansion.
+ */
+double reg_term(double *pars, double d_max, int n_c, int nslice) {
+ double sum = 0.0;
+ double r;
+ double deriv;
+ int i;
+ for (i=0; i<nslice; i++) {
+ r = d_max/(1.0*nslice)*i;
+ deriv = dprdr(pars, d_max, n_c, r);
+ sum += deriv*deriv;
+ }
+ return sum/(1.0*nslice)*d_max;
+}
+
+/**
+ * regularization term calculated from the expansion.
+ */
+double int_p2(double *pars, double d_max, int n_c, int nslice) {
+ double sum = 0.0;
+ double r;
+ double value;
+ int i;
+ for (i=0; i<nslice; i++) {
+ r = d_max/(1.0*nslice)*i;
+ value = pr(pars, d_max, n_c, r);
+ sum += value*value;
+ }
+ return sum/(1.0*nslice)*d_max;
+}
+
+/**
+ * Integral of P(r)
+ */
+double int_pr(double *pars, double d_max, int n_c, int nslice) {
+ double sum = 0.0;
+ double r;
+ double value;
+ int i;
+ for (i=0; i<nslice; i++) {
+ r = d_max/(1.0*nslice)*i;
+ value = pr(pars, d_max, n_c, r);
+ sum += value;
+ }
+ return sum/(1.0*nslice)*d_max;
+}
+
+/**
+ * Get the number of P(r) peaks.
+ */
+int npeaks(double *pars, double d_max, int n_c, int nslice) {
+ double r;
+ double value;
+ int i;
+ double previous = 0.0;
+ double slope = 0.0;
+ int count = 0;
+ for (i=0; i<nslice; i++) {
+ r = d_max/(1.0*nslice)*i;
+ value = pr(pars, d_max, n_c, r);
+ if (previous<=value){
+ //if (slope<0) count += 1;
+ slope = 1;
+ } else {
+ //printf("slope -1");
+ if (slope>0) count += 1;
+ slope = -1;
+ }
+ previous = value;
+ }
+ return count;
+}
+
+/**
+ * Get the fraction of the integral of P(r) over the whole range
+ * of r that is above zero.
+ * A valid P(r) is define as being positive for all r.
+ */
+double positive_integral(double *pars, double d_max, int n_c, int nslice) {
+ double r;
+ double value;
+ int i;
+ double sum_pos = 0.0;
+ double sum = 0.0;
+
+ for (i=0; i<nslice; i++) {
+ r = d_max/(1.0*nslice)*i;
+ value = pr(pars, d_max, n_c, r);
+ if (value>0.0) sum_pos += value;
+ sum += fabs(value);
+ }
+ return sum_pos/sum;
+}
+
+/**
+ * Get the fraction of the integral of P(r) over the whole range
+ * of r that is at least one sigma above zero.
+ */
+double positive_errors(double *pars, double *err, double d_max, int n_c, int nslice) {
+ double r;
+ int i;
+ double sum_pos = 0.0;
+ double sum = 0.0;
+ double pr_val;
+ double pr_val_err;
+
+ for (i=0; i<nslice; i++) {
+ r = d_max/(1.0*nslice)*i;
+ pr_err(pars, err, d_max, n_c, r, &pr_val, &pr_val_err);
+ if (pr_val>pr_val_err) sum_pos += pr_val;
+ sum += fabs(pr_val);
+
+
+ }
+ return sum_pos/sum;
+}
+
+/**
+ * R_g radius of gyration calculation
+ *
+ * R_g**2 = integral[r**2 * p(r) dr] / (2.0 * integral[p(r) dr])
+ */
+double rg(double *pars, double d_max, int n_c, int nslice) {
+ double sum_r2 = 0.0;
+ double sum = 0.0;
+ double r;
+ double value;
+ int i;
+ for (i=0; i<nslice; i++) {
+ r = d_max/(1.0*nslice)*i;
+ value = pr(pars, d_max, n_c, r);
+ sum += value;
+ sum_r2 += r*r*value;
+ }
+ return sqrt(sum_r2/(2.0*sum));
+}
diff --git a/src/sas/sascalc/pr/c_extensions/invertor.h b/src/sas/sascalc/pr/c_extensions/invertor.h
index ba93f4f..3cb3951 100644
--- a/src/sas/sascalc/pr/c_extensions/invertor.h
+++ b/src/sas/sascalc/pr/c_extensions/invertor.h
@@ -1,59 +1,59 @@
-#if !defined(invertor_h)
-#define invertor_h
-
-/**
- * Internal data structure for P(r) inversion
- */
-typedef struct {
- /// Maximum distance between any two points in the system
- double d_max;
- /// q data
- double *x;
- /// I(q) data
- double *y;
- /// dI(q) data
- double *err;
- /// Number of q points
- int npoints;
- /// Number of I(q) points
- int ny;
- /// Number of dI(q) points
- int nerr;
- /// Alpha value
- double alpha;
- /// Minimum q to include in inversion
- double q_min;
- /// Maximum q to include in inversion
- double q_max;
- /// Flag for whether or not to evalute a constant background while inverting
- int has_bck;
- /// Slit height in units of q [A-1]
- double slit_height;
- /// Slit width in units of q [A-1]
- double slit_width;
-} Invertor_params;
-
-void invertor_dealloc(Invertor_params *pars);
-
-void invertor_init(Invertor_params *pars);
-
-double pr_sphere(double R, double r);
-double ortho(double d_max, int n, double r);
-double ortho_transformed(double d_max, int n, double q);
-double ortho_derived(double d_max, int n, double r);
-double iq(double *c, double d_max, int n_c, double q);
-double pr(double *c, double d_max, int n_c, double r);
-double dprdr(double *pars, double d_max, int n_c, double r);
-double reg_term(double *pars, double d_max, int n_c, int nslice);
-double int_p2(double *pars, double d_max, int n_c, int nslice);
-void pr_err(double *pars, double *err, double d_max, int n_c,
- double r, double *pr_value, double *pr_value_err);
-int npeaks(double *pars, double d_max, int n_c, int nslice);
-double positive_integral(double *pars, double d_max, int n_c, int nslice);
-double positive_errors(double *pars, double *err, double d_max, int n_c, int nslice);
-double rg(double *pars, double d_max, int n_c, int nslice);
-double int_pr(double *pars, double d_max, int n_c, int nslice);
-double ortho_transformed_smeared(double d_max, int n, double heigth, double width, double q, int npts);
-double iq_smeared(double *pars, double d_max, int n_c, double height, double width, double q, int npts);
-
-#endif
+#if !defined(invertor_h)
+#define invertor_h
+
+/**
+ * Internal data structure for P(r) inversion
+ */
+typedef struct {
+ /// Maximum distance between any two points in the system
+ double d_max;
+ /// q data
+ double *x;
+ /// I(q) data
+ double *y;
+ /// dI(q) data
+ double *err;
+ /// Number of q points
+ int npoints;
+ /// Number of I(q) points
+ int ny;
+ /// Number of dI(q) points
+ int nerr;
+ /// Alpha value
+ double alpha;
+ /// Minimum q to include in inversion
+ double q_min;
+ /// Maximum q to include in inversion
+ double q_max;
+ /// Flag for whether or not to evalute a constant background while inverting
+ int est_bck;
+ /// Slit height in units of q [A-1]
+ double slit_height;
+ /// Slit width in units of q [A-1]
+ double slit_width;
+} Invertor_params;
+
+void invertor_dealloc(Invertor_params *pars);
+
+void invertor_init(Invertor_params *pars);
+
+double pr_sphere(double R, double r);
+double ortho(double d_max, int n, double r);
+double ortho_transformed(double d_max, int n, double q);
+double ortho_derived(double d_max, int n, double r);
+double iq(double *c, double d_max, int n_c, double q);
+double pr(double *c, double d_max, int n_c, double r);
+double dprdr(double *pars, double d_max, int n_c, double r);
+double reg_term(double *pars, double d_max, int n_c, int nslice);
+double int_p2(double *pars, double d_max, int n_c, int nslice);
+void pr_err(double *pars, double *err, double d_max, int n_c,
+ double r, double *pr_value, double *pr_value_err);
+int npeaks(double *pars, double d_max, int n_c, int nslice);
+double positive_integral(double *pars, double d_max, int n_c, int nslice);
+double positive_errors(double *pars, double *err, double d_max, int n_c, int nslice);
+double rg(double *pars, double d_max, int n_c, int nslice);
+double int_pr(double *pars, double d_max, int n_c, int nslice);
+double ortho_transformed_smeared(double d_max, int n, double heigth, double width, double q, int npts);
+double iq_smeared(double *pars, double d_max, int n_c, double height, double width, double q, int npts);
+
+#endif
diff --git a/src/sas/sascalc/pr/distance_explorer.py b/src/sas/sascalc/pr/distance_explorer.py
index c0a1beb..e1cc738 100644
--- a/src/sas/sascalc/pr/distance_explorer.py
+++ b/src/sas/sascalc/pr/distance_explorer.py
@@ -1,107 +1,107 @@
-
-################################################################################
-#This software was developed by the University of Tennessee as part of the
-#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
-#project funded by the US National Science Foundation.
-#
-#See the license text in license.txt
-#
-#copyright 2009, University of Tennessee
-################################################################################
-
-"""
-Module to explore the P(r) inversion results for a range
-of D_max value. User picks a number of points and a range of
-distances, then get a series of outputs as a function of D_max
-over that range.
-"""
-import sys
-
-
-class Results(object):
- """
- Class to hold the inversion output parameters
- as a function of D_max
- """
- def __init__(self):
- """
- Initialization. Create empty arrays
- and dictionary of labels.
- """
- # Array of output for each inversion
- self.chi2 = []
- self.osc = []
- self.pos = []
- self.pos_err = []
- self.rg = []
- self.iq0 = []
- self.bck = []
- self.d_max = []
- ## List of errors found during the last exploration
- self.errors = []
-
-
-class DistExplorer(object):
- """
- The explorer class
- """
-
- def __init__(self, pr_state):
- """
- Initialization.
-
- :param pr_state: sas.sascalc.pr.invertor.Invertor object
-
- """
- self.pr_state = pr_state
- self._default_min = 0.8 * self.pr_state.d_max
- self._default_max = 1.2 * self.pr_state.d_max
-
- def __call__(self, dmin=None, dmax=None, npts=10):
- """
- Compute the outputs as a function of D_max.
-
- :param dmin: minimum value for D_max
- :param dmax: maximum value for D_max
- :param npts: number of points for D_max
-
- """
- # Take care of the defaults if needed
- if dmin is None:
- dmin = self._default_min
-
- if dmax is None:
- dmax = self._default_max
-
- # Results object to store the computation outputs.
- results = Results()
-
- # Loop over d_max values
- for i in range(npts):
- d = dmin + i * (dmax - dmin) / (npts - 1.0)
- self.pr_state.d_max = d
- try:
- out, cov = self.pr_state.invert(self.pr_state.nfunc)
-
- # Store results
- iq0 = self.pr_state.iq0(out)
- rg = self.pr_state.rg(out)
- pos = self.pr_state.get_positive(out)
- pos_err = self.pr_state.get_pos_err(out, cov)
- osc = self.pr_state.oscillations(out)
-
- results.d_max.append(self.pr_state.d_max)
- results.bck.append(self.pr_state.background)
- results.chi2.append(self.pr_state.chi2)
- results.iq0.append(iq0)
- results.rg.append(rg)
- results.pos.append(pos)
- results.pos_err.append(pos_err)
- results.osc.append(osc)
- except:
- # This inversion failed, skip this D_max value
- msg = "ExploreDialog: inversion failed for "
- msg += "D_max=%s\n %s" % (str(d), sys.exc_value)
- results.errors.append(msg)
-
- return results
+
+################################################################################
+#This software was developed by the University of Tennessee as part of the
+#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
+#project funded by the US National Science Foundation.
+#
+#See the license text in license.txt
+#
+#copyright 2009, University of Tennessee
+################################################################################
+
+"""
+Module to explore the P(r) inversion results for a range
+of D_max value. User picks a number of points and a range of
+distances, then get a series of outputs as a function of D_max
+over that range.
+"""
+import sys
+
+
+class Results(object):
+ """
+ Class to hold the inversion output parameters
+ as a function of D_max
+ """
+ def __init__(self):
+ """
+ Initialization. Create empty arrays
+ and dictionary of labels.
+ """
+ # Array of output for each inversion
+ self.chi2 = []
+ self.osc = []
+ self.pos = []
+ self.pos_err = []
+ self.rg = []
+ self.iq0 = []
+ self.bck = []
+ self.d_max = []
+ ## List of errors found during the last exploration
+ self.errors = []
+
+
+class DistExplorer(object):
+ """
+ The explorer class
+ """
+
+ def __init__(self, pr_state):
+ """
+ Initialization.
+
+ :param pr_state: sas.sascalc.pr.invertor.Invertor object
+
+ """
+ self.pr_state = pr_state
+ self._default_min = 0.8 * self.pr_state.d_max
+ self._default_max = 1.2 * self.pr_state.d_max
+
+ def __call__(self, dmin=None, dmax=None, npts=10):
+ """
+ Compute the outputs as a function of D_max.
+
+ :param dmin: minimum value for D_max
+ :param dmax: maximum value for D_max
+ :param npts: number of points for D_max
+
+ """
+ # Take care of the defaults if needed
+ if dmin is None:
+ dmin = self._default_min
+
+ if dmax is None:
+ dmax = self._default_max
+
+ # Results object to store the computation outputs.
+ results = Results()
+
+ # Loop over d_max values
+ for i in range(npts):
+ d = dmin + i * (dmax - dmin) / (npts - 1.0)
+ self.pr_state.d_max = d
+ try:
+ out, cov = self.pr_state.invert(self.pr_state.nfunc)
+
+ # Store results
+ iq0 = self.pr_state.iq0(out)
+ rg = self.pr_state.rg(out)
+ pos = self.pr_state.get_positive(out)
+ pos_err = self.pr_state.get_pos_err(out, cov)
+ osc = self.pr_state.oscillations(out)
+
+ results.d_max.append(self.pr_state.d_max)
+ results.bck.append(self.pr_state.background)
+ results.chi2.append(self.pr_state.chi2)
+ results.iq0.append(iq0)
+ results.rg.append(rg)
+ results.pos.append(pos)
+ results.pos_err.append(pos_err)
+ results.osc.append(osc)
+ except:
+ # This inversion failed, skip this D_max value
+ msg = "ExploreDialog: inversion failed for "
+ msg += "D_max=%s\n %s" % (str(d), sys.exc_value)
+ results.errors.append(msg)
+
+ return results
diff --git a/src/sas/sascalc/pr/fit/AbstractFitEngine.py b/src/sas/sascalc/pr/fit/AbstractFitEngine.py
index 71c8d94..ef3ccc8 100644
--- a/src/sas/sascalc/pr/fit/AbstractFitEngine.py
+++ b/src/sas/sascalc/pr/fit/AbstractFitEngine.py
@@ -1,9 +1,10 @@
+from __future__ import print_function
import copy
#import logging
import sys
import math
-import numpy
+import numpy as np
from sas.sascalc.dataloader.data_info import Data1D
from sas.sascalc.dataloader.data_info import Data2D
@@ -135,21 +136,21 @@ class FitData1D(Data1D):
:param smearer: is an object of class QSmearer or SlitSmearer
that will smear the theory data (slit smearing or resolution
smearing) when set.
-
+
The proper way to set the smearing object would be to
do the following: ::
-
- from sas.sascalc.data_util.qsmearing import smear_selection
+
+ from sas.sascalc.fit.qsmearing import smear_selection
smearer = smear_selection(some_data)
fitdata1d = FitData1D( x= [1,3,..,],
y= [3,4,..,8],
dx=None,
dy=[1,2...], smearer= smearer)
-
+
:Note: that some_data _HAS_ to be of
class DataLoader.data_info.Data1D
Setting it back to None will turn smearing off.
-
+
"""
Data1D.__init__(self, x=x, y=y, dx=dx, dy=dy)
self.num_points = len(x)
@@ -161,20 +162,20 @@ class FitData1D(Data1D):
# TODO: Should provide an option for users to set it like percent,
# constant, or dy data
if dy is None or dy == [] or dy.all() == 0:
- self.dy = numpy.ones(len(y))
+ self.dy = np.ones(len(y))
else:
- self.dy = numpy.asarray(dy).copy()
+ self.dy = np.asarray(dy).copy()
## Min Q-value
#Skip the Q=0 point, especially when y(q=0)=None at x[0].
if min(self.x) == 0.0 and self.x[0] == 0 and\
- not numpy.isfinite(self.y[0]):
+ not np.isfinite(self.y[0]):
self.qmin = min(self.x[self.x != 0])
else:
self.qmin = min(self.x)
## Max Q-value
self.qmax = max(self.x)
-
+
# Range used for input to smearing
self._qmin_unsmeared = self.qmin
self._qmax_unsmeared = self.qmax
@@ -182,31 +183,31 @@ class FitData1D(Data1D):
self.idx = (self.x >= self.qmin) & (self.x <= self.qmax)
self.idx_unsmeared = (self.x >= self._qmin_unsmeared) \
& (self.x <= self._qmax_unsmeared)
-
+
def set_fit_range(self, qmin=None, qmax=None):
""" to set the fit range"""
# Skip Q=0 point, (especially for y(q=0)=None at x[0]).
# ToDo: Find better way to do it.
- if qmin == 0.0 and not numpy.isfinite(self.y[qmin]):
+ if qmin == 0.0 and not np.isfinite(self.y[qmin]):
self.qmin = min(self.x[self.x != 0])
- elif qmin != None:
+ elif qmin is not None:
self.qmin = qmin
- if qmax != None:
+ if qmax is not None:
self.qmax = qmax
# Determine the range needed in unsmeared-Q to cover
# the smeared Q range
self._qmin_unsmeared = self.qmin
self._qmax_unsmeared = self.qmax
-
+
self._first_unsmeared_bin = 0
self._last_unsmeared_bin = len(self.x) - 1
-
- if self.smearer != None:
+
+ if self.smearer is not None:
self._first_unsmeared_bin, self._last_unsmeared_bin = \
self.smearer.get_bin_range(self.qmin, self.qmax)
self._qmin_unsmeared = self.x[self._first_unsmeared_bin]
self._qmax_unsmeared = self.x[self._last_unsmeared_bin]
-
+
# Identify the bin range for the unsmeared and smeared spaces
self.idx = (self.x >= self.qmin) & (self.x <= self.qmax)
## zero error can not participate for fitting
@@ -229,34 +230,34 @@ class FitData1D(Data1D):
def residuals(self, fn):
"""
Compute residuals.
-
+
If self.smearer has been set, use if to smear
the data before computing chi squared.
-
+
:param fn: function that return model value
-
+
:return: residuals
"""
# Compute theory data f(x)
- fx = numpy.zeros(len(self.x))
+ fx = np.zeros(len(self.x))
fx[self.idx_unsmeared] = fn(self.x[self.idx_unsmeared])
-
+
## Smear theory data
if self.smearer is not None:
fx = self.smearer(fx, self._first_unsmeared_bin,
self._last_unsmeared_bin)
## Sanity check
- if numpy.size(self.dy) != numpy.size(fx):
+ if np.size(self.dy) != np.size(fx):
msg = "FitData1D: invalid error array "
- msg += "%d <> %d" % (numpy.shape(self.dy), numpy.size(fx))
- raise RuntimeError, msg
+ msg += "%d <> %d" % (np.shape(self.dy), np.size(fx))
+ raise RuntimeError(msg)
return (self.y[self.idx] - fx[self.idx]) / self.dy[self.idx], fx[self.idx]
-
+
def residuals_deriv(self, model, pars=[]):
"""
:return: residuals derivatives .
-
- :note: in this case just return empty array
+
+ :note: in this case just return empty array
"""
return []
@@ -291,33 +292,33 @@ class FitData2D(Data2D):
x_max = max(math.fabs(sas_data2d.xmin), math.fabs(sas_data2d.xmax))
y_max = max(math.fabs(sas_data2d.ymin), math.fabs(sas_data2d.ymax))
-
+
## fitting range
- if qmin == None:
+ if qmin is None:
self.qmin = 1e-16
- if qmax == None:
+ if qmax is None:
self.qmax = math.sqrt(x_max * x_max + y_max * y_max)
## new error image for fitting purpose
- if self.err_data == None or self.err_data == []:
- self.res_err_data = numpy.ones(len(self.data))
+ if self.err_data is None or self.err_data == []:
+ self.res_err_data = np.ones(len(self.data))
else:
self.res_err_data = copy.deepcopy(self.err_data)
#self.res_err_data[self.res_err_data==0]=1
-
- self.radius = numpy.sqrt(self.qx_data**2 + self.qy_data**2)
-
+
+ self.radius = np.sqrt(self.qx_data**2 + self.qy_data**2)
+
# Note: mask = True: for MASK while mask = False for NOT to mask
self.idx = ((self.qmin <= self.radius) &\
(self.radius <= self.qmax))
self.idx = (self.idx) & (self.mask)
- self.idx = (self.idx) & (numpy.isfinite(self.data))
- self.num_points = numpy.sum(self.idx)
+ self.idx = (self.idx) & (np.isfinite(self.data))
+ self.num_points = np.sum(self.idx)
def set_smearer(self, smearer):
"""
Set smearer
"""
- if smearer == None:
+ if smearer is None:
return
self.smearer = smearer
self.smearer.set_index(self.idx)
@@ -329,15 +330,15 @@ class FitData2D(Data2D):
"""
if qmin == 0.0:
self.qmin = 1e-16
- elif qmin != None:
+ elif qmin is not None:
self.qmin = qmin
- if qmax != None:
+ if qmax is not None:
self.qmax = qmax
- self.radius = numpy.sqrt(self.qx_data**2 + self.qy_data**2)
+ self.radius = np.sqrt(self.qx_data**2 + self.qy_data**2)
self.idx = ((self.qmin <= self.radius) &\
(self.radius <= self.qmax))
self.idx = (self.idx) & (self.mask)
- self.idx = (self.idx) & (numpy.isfinite(self.data))
+ self.idx = (self.idx) & (np.isfinite(self.data))
self.idx = (self.idx) & (self.res_err_data != 0)
def get_fit_range(self):
@@ -350,13 +351,13 @@ class FitData2D(Data2D):
"""
Number of measurement points in data set after masking, etc.
"""
- return numpy.sum(self.idx)
+ return np.sum(self.idx)
def residuals(self, fn):
"""
return the residuals
"""
- if self.smearer != None:
+ if self.smearer is not None:
fn.set_index(self.idx)
# Get necessary data from self.data and set the data for smearing
fn.get_data()
@@ -369,17 +370,17 @@ class FitData2D(Data2D):
res = (self.data[self.idx] - gn) / self.res_err_data[self.idx]
return res, gn
-
+
def residuals_deriv(self, model, pars=[]):
"""
:return: residuals derivatives .
-
+
:note: in this case just return empty array
-
+
"""
return []
-
-
+
+
class FitAbort(Exception):
"""
Exception raise to stop the fit
@@ -397,25 +398,25 @@ class FitEngine:
#Dictionnary of fitArrange element (fit problems)
self.fit_arrange_dict = {}
self.fitter_id = None
-
+
def set_model(self, model, id, pars=[], constraints=[], data=None):
"""
set a model on a given in the fit engine.
-
- :param model: sas.models type
+
+ :param model: sas.models type
:param id: is the key of the fitArrange dictionary where model is saved as a value
- :param pars: the list of parameters to fit
- :param constraints: list of
+ :param pars: the list of parameters to fit
+ :param constraints: list of
tuple (name of parameter, value of parameters)
the value of parameter must be a string to constraint 2 different
parameters.
- Example:
+ Example:
we want to fit 2 model M1 and M2 both have parameters A and B.
constraints can be ``constraints = [(M1.A, M2.B+2), (M1.B= M2.A *5),...,]``
-
-
+
+
:note: pars must contains only name of existing model's parameters
-
+
"""
if not pars:
raise ValueError("no fitting parameters")
@@ -446,7 +447,7 @@ class FitEngine:
Receives plottable, creates a list of data to fit,set data
in a FitArrange object and adds that object in a dictionary
with key id.
-
+
:param data: data added
:param id: unique key corresponding to a fitArrange object with data
"""
@@ -457,7 +458,7 @@ class FitEngine:
fitdata = FitData1D(x=data.x, y=data.y,
dx=data.dx, dy=data.dy, smearer=smearer)
fitdata.sas_data = data
-
+
fitdata.set_fit_range(qmin=qmin, qmax=qmax)
#A fitArrange is already created but contains model only at id
if id in self.fit_arrange_dict:
@@ -467,11 +468,11 @@ class FitEngine:
fitproblem = FitArrange()
fitproblem.add_data(fitdata)
self.fit_arrange_dict[id] = fitproblem
-
+
def get_model(self, id):
"""
:param id: id is key in the dictionary containing the model to return
-
+
:return: a model at this id or None if no FitArrange element was
created with this id
"""
@@ -479,43 +480,43 @@ class FitEngine:
return self.fit_arrange_dict[id].get_model()
else:
return None
-
+
def remove_fit_problem(self, id):
"""remove fitarrange in id"""
if id in self.fit_arrange_dict:
del self.fit_arrange_dict[id]
-
+
def select_problem_for_fit(self, id, value):
"""
select a couple of model and data at the id position in dictionary
and set in self.selected value to value
-
+
:param value: the value to allow fitting.
can only have the value one or zero
"""
if id in self.fit_arrange_dict:
self.fit_arrange_dict[id].set_to_fit(value)
-
+
def get_problem_to_fit(self, id):
"""
return the self.selected value of the fit problem of id
-
+
:param id: the id of the problem
"""
if id in self.fit_arrange_dict:
self.fit_arrange_dict[id].get_to_fit()
-
-
+
+
class FitArrange:
def __init__(self):
"""
Class FitArrange contains a set of data for a given model
to perform the Fit.FitArrange must contain exactly one model
and at least one data for the fit to be performed.
-
+
model: the model selected by the user
Ldata: a list of data what the user wants to fit
-
+
"""
self.model = None
self.data_list = []
@@ -526,49 +527,49 @@ class FitArrange:
def set_model(self, model):
"""
set_model save a copy of the model
-
+
:param model: the model being set
"""
self.model = model
-
+
def add_data(self, data):
"""
add_data fill a self.data_list with data to fit
-
+
:param data: Data to add in the list
"""
if not data in self.data_list:
self.data_list.append(data)
-
+
def get_model(self):
"""
:return: saved model
"""
return self.model
-
+
def get_data(self):
"""
:return: list of data data_list
"""
return self.data_list[0]
-
+
def remove_data(self, data):
"""
Remove one element from the list
-
+
:param data: Data to remove from data_list
"""
if data in self.data_list:
self.data_list.remove(data)
-
+
def set_to_fit(self, value=0):
"""
set self.selected to 0 or 1 for other values raise an exception
-
+
:param value: integer between 0 or 1
"""
self.selected = value
-
+
def get_to_fit(self):
"""
return self.selected value
@@ -600,21 +601,21 @@ class FResult(object):
self.fitter_id = None
if self.model is not None and self.data is not None:
self.inputs = [(self.model, self.data)]
-
+
def set_model(self, model):
"""
"""
self.model = model
-
+
def set_fitness(self, fitness):
"""
"""
self.fitness = fitness
-
+
def __str__(self):
"""
"""
- if self.pvec == None and self.model is None and self.param_list is None:
+ if self.pvec is None and self.model is None and self.param_list is None:
return "No results"
sasmodel = self.model.model
@@ -625,8 +626,8 @@ class FResult(object):
for i,v in pars if v in self.param_list]
msg = [msg1, msg3] + msg2
return "\n".join(msg)
-
+
def print_summary(self):
"""
"""
- print str(self)
+ print(str(self))
diff --git a/src/sas/sascalc/pr/fit/BumpsFitting.py b/src/sas/sascalc/pr/fit/BumpsFitting.py
index 04a13a7..2091ec8 100644
--- a/src/sas/sascalc/pr/fit/BumpsFitting.py
+++ b/src/sas/sascalc/pr/fit/BumpsFitting.py
@@ -4,7 +4,7 @@ BumpsFitting module runs the bumps optimizer.
import os
from datetime import timedelta, datetime
-import numpy
+import numpy as np
from bumps import fitters
try:
@@ -95,7 +95,7 @@ class ConvergenceMonitor(object):
best = history.value[0]
try:
p = history.population_values[0]
- n,p = len(p), numpy.sort(p)
+ n,p = len(p), np.sort(p)
QI,Qmid, = int(0.2*n),int(0.5*n)
self.convergence.append((best, p[0],p[QI],p[Qmid],p[-1-QI],p[-1]))
except:
@@ -192,10 +192,10 @@ class SasFitness(object):
self._dirty = False
def numpoints(self):
- return numpy.sum(self.data.idx) # number of fitted points
+ return np.sum(self.data.idx) # number of fitted points
def nllf(self):
- return 0.5*numpy.sum(self.residuals()**2)
+ return 0.5*np.sum(self.residuals()**2)
def theory(self):
self._recalculate()
@@ -292,15 +292,15 @@ class BumpsFit(FitEngine):
# TODO: should scale stderr by sqrt(chisq/DOF) if dy is unknown
R.success = result['success']
if R.success:
- R.stderr = numpy.hstack((result['stderr'][fitted_index],
- numpy.NaN*numpy.ones(len(fitness.computed_pars))))
- R.pvec = numpy.hstack((result['value'][fitted_index],
+ R.stderr = np.hstack((result['stderr'][fitted_index],
+ np.NaN*np.ones(len(fitness.computed_pars))))
+ R.pvec = np.hstack((result['value'][fitted_index],
[p.value for p in fitness.computed_pars]))
- R.fitness = numpy.sum(R.residuals**2)/(fitness.numpoints() - len(fitted_index))
+ R.fitness = np.sum(R.residuals**2)/(fitness.numpoints() - len(fitted_index))
else:
- R.stderr = numpy.NaN*numpy.ones(len(param_list))
- R.pvec = numpy.asarray( [p.value for p in fitness.fitted_pars+fitness.computed_pars])
- R.fitness = numpy.NaN
+ R.stderr = np.NaN*np.ones(len(param_list))
+ R.pvec = np.asarray( [p.value for p in fitness.fitted_pars+fitness.computed_pars])
+ R.fitness = np.NaN
R.convergence = result['convergence']
if result['uncertainty'] is not None:
R.uncertainty_state = result['uncertainty']
@@ -330,7 +330,7 @@ def run_bumps(problem, handler, curr_thread):
steps = (samples+pop-1)/pop if pop != 0 else samples
max_step = steps + options.get('burn', 0)
pars = [p.name for p in problem._parameters]
- #x0 = numpy.asarray([p.value for p in problem._parameters])
+ #x0 = np.asarray([p.value for p in problem._parameters])
options['monitors'] = [
BumpsMonitor(handler, max_step, pars, problem.dof),
ConvergenceMonitor(),
@@ -351,8 +351,8 @@ def run_bumps(problem, handler, curr_thread):
convergence_list = options['monitors'][-1].convergence
- convergence = (2*numpy.asarray(convergence_list)/problem.dof
- if convergence_list else numpy.empty((0,1),'d'))
+ convergence = (2*np.asarray(convergence_list)/problem.dof
+ if convergence_list else np.empty((0,1),'d'))
success = best is not None
return {
diff --git a/src/sas/sascalc/pr/fit/Loader.py b/src/sas/sascalc/pr/fit/Loader.py
index 18bada0..f2a9987 100644
--- a/src/sas/sascalc/pr/fit/Loader.py
+++ b/src/sas/sascalc/pr/fit/Loader.py
@@ -1,86 +1,87 @@
-# class Loader to load any king of file
-#import wx
-#import string
-import numpy
-
-class Load:
- """
- This class is loading values from given file or value giving by the user
- """
- def __init__(self, x=None, y=None, dx=None, dy=None):
- raise NotImplementedError("a code search shows that this code is not active, and you are not seeing this message")
- # variable to store loaded values
- self.x = x
- self.y = y
- self.dx = dx
- self.dy = dy
- self.filename = None
-
- def set_filename(self, path=None):
- """
- Store path into a variable.If the user doesn't give
- a path as a parameter a pop-up
- window appears to select the file.
-
- :param path: the path given by the user
-
- """
- self.filename = path
-
- def get_filename(self):
- """ return the file's path"""
- return self.filename
-
- def set_values(self):
- """ Store the values loaded from file in local variables"""
- if not self.filename == None:
- input_f = open(self.filename, 'r')
- buff = input_f.read()
- lines = buff.split('\n')
- self.x = []
- self.y = []
- self.dx = []
- self.dy = []
- for line in lines:
- try:
- toks = line.split()
- x = float(toks[0])
- y = float(toks[1])
- dy = float(toks[2])
-
- self.x.append(x)
- self.y.append(y)
- self.dy.append(dy)
- self.dx = numpy.zeros(len(self.x))
- except:
- print "READ ERROR", line
- # Sanity check
- if not len(self.x) == len(self.dx):
- raise ValueError, "x and dx have different length"
- if not len(self.y) == len(self.dy):
- raise ValueError, "y and dy have different length"
-
-
- def get_values(self):
- """ Return x, y, dx, dy"""
- return self.x, self.y, self.dx, self.dy
-
- def load_data(self, data):
- """ Return plottable"""
- #load data
- data.x = self.x
- data.y = self.y
- data.dx = self.dx
- data.dy = self.dy
- #Load its View class
- #plottable.reset_view()
-
-
-if __name__ == "__main__":
- load = Load()
- load.set_filename("testdata_line.txt")
- print load.get_filename()
- load.set_values()
- print load.get_values()
-
-
\ No newline at end of file
+from __future__ import print_function
+
+# class Loader to load any king of file
+#import wx
+#import string
+import numpy as np
+
+class Load:
+ """
+ This class is loading values from given file or value giving by the user
+ """
+ def __init__(self, x=None, y=None, dx=None, dy=None):
+ raise NotImplementedError("a code search shows that this code is not active, and you are not seeing this message")
+ # variable to store loaded values
+ self.x = x
+ self.y = y
+ self.dx = dx
+ self.dy = dy
+ self.filename = None
+
+ def set_filename(self, path=None):
+ """
+ Store path into a variable.If the user doesn't give
+ a path as a parameter a pop-up
+ window appears to select the file.
+
+ :param path: the path given by the user
+
+ """
+ self.filename = path
+
+ def get_filename(self):
+ """ return the file's path"""
+ return self.filename
+
+ def set_values(self):
+ """ Store the values loaded from file in local variables"""
+ if self.filename is not None:
+ input_f = open(self.filename, 'r')
+ buff = input_f.read()
+ lines = buff.split('\n')
+ self.x = []
+ self.y = []
+ self.dx = []
+ self.dy = []
+ for line in lines:
+ try:
+ toks = line.split()
+ x = float(toks[0])
+ y = float(toks[1])
+ dy = float(toks[2])
+
+ self.x.append(x)
+ self.y.append(y)
+ self.dy.append(dy)
+ self.dx = np.zeros(len(self.x))
+ except:
+ print("READ ERROR", line)
+ # Sanity check
+ if not len(self.x) == len(self.dx):
+ raise ValueError("x and dx have different length")
+ if not len(self.y) == len(self.dy):
+ raise ValueError("y and dy have different length")
+
+
+ def get_values(self):
+ """ Return x, y, dx, dy"""
+ return self.x, self.y, self.dx, self.dy
+
+ def load_data(self, data):
+ """ Return plottable"""
+ #load data
+ data.x = self.x
+ data.y = self.y
+ data.dx = self.dx
+ data.dy = self.dy
+ #Load its View class
+ #plottable.reset_view()
+
+
+if __name__ == "__main__":
+ load = Load()
+ load.set_filename("testdata_line.txt")
+ print(load.get_filename())
+ load.set_values()
+ print(load.get_values())
+
diff --git a/src/sas/sascalc/pr/fit/expression.py b/src/sas/sascalc/pr/fit/expression.py
index 21bd9dd..3c36c1b 100644
--- a/src/sas/sascalc/pr/fit/expression.py
+++ b/src/sas/sascalc/pr/fit/expression.py
@@ -1,3 +1,5 @@
+from __future__ import print_function
+
# This program is public domain
"""
Parameter expression evaluator.
@@ -56,7 +58,7 @@ def _symbols(expr,symtab):
used in the expression. Symbols are only returned once even if they
occur multiple times. The return value is a set with the elements in
no particular order.
-
+
This is the first step in computing a dependency graph.
"""
matches = [m.group(0) for m in _symbol_pattern.finditer(expr)]
@@ -78,14 +80,14 @@ def _substitute(expr,mapping):
pieces += [expr[offset:start],text]
offset = end
pieces.append(expr[offset:])
-
+
# Join the pieces and return them
return "".join(pieces)
def _find_dependencies(symtab, exprs):
"""
Returns a list of pair-wise dependencies from the parameter expressions.
-
+
For example, if p3 = p1+p2, then find_dependencies([p1,p2,p3]) will
return [(p3,p1),(p3,p2)]. For base expressions without dependencies,
such as p4 = 2*pi, this should return [(p4, None)]
@@ -107,7 +109,7 @@ def _symbols_or_none(expr,symtab):
def _parameter_mapping(pairs):
"""
Find the parameter substitution we need so that expressions can
- be evaluated without having to traverse a chain of
+ be evaluated without having to traverse a chain of
model.layer.parameter.value
"""
left,right = zip(*pairs)
@@ -119,7 +121,7 @@ def _parameter_mapping(pairs):
if p is not None)
return definition, substitution
-def no_constraints():
+def no_constraints():
"""
This parameter set has no constraints between the parameters.
"""
@@ -160,12 +162,12 @@ def compile_constraints(symtab, exprs, context={}):
evaluations. Unauthenticated users should not be running this code.
Parameter names are assumed to contain only _.a-zA-Z0-9#[]
-
+
Both names are provided for inverse functions, e.g., acos and arccos.
Should try running the function to identify syntax errors before
running it in a fit.
-
+
Use help(fn) to see the code generated for the returned function fn.
dis.dis(fn) will show the corresponding python vm instructions.
"""
@@ -236,7 +238,7 @@ def order_dependencies(pairs):
independent = right - left
if independent == emptyset:
cycleset = ", ".join(str(s) for s in left)
- raise ValueError,"Cyclic dependencies amongst %s"%cycleset
+ raise ValueError("Cyclic dependencies amongst %s"%cycleset)
# The possibly resolvable items are those that depend on the independents
dependent = set([a for a,b in pairs if b in independent])
@@ -264,13 +266,13 @@ def _check(msg,pairs):
if set(n) != items or len(n) != len(items):
n.sort()
items = list(items); items.sort()
- raise Exception,"%s expect %s to contain %s for %s"%(msg,n,items,pairs)
+ raise ValueError("%s expect %s to contain %s for %s"%(msg,n,items,pairs))
for lo,hi in pairs:
if lo in n and hi in n and n.index(lo) >= n.index(hi):
- raise Exception,"%s expect %s before %s in %s for %s"%(msg,lo,hi,n,pairs)
+ raise ValueError("%s expect %s before %s in %s for %s"%(msg,lo,hi,n,pairs))
def test_deps():
- import numpy
+ import numpy as np
# Null case
_check("test empty",[])
@@ -278,37 +280,40 @@ def test_deps():
# Some dependencies
_check("test1",[(2,7),(1,5),(1,4),(2,1),(3,1),(5,6)])
_check("test1 renumbered",[(6,1),(7,3),(7,4),(6,7),(5,7),(3,2)])
- _check("test1 numpy",numpy.array([(2,7),(1,5),(1,4),(2,1),(3,1),(5,6)]))
+ _check("test1 numpy",np.array([(2,7),(1,5),(1,4),(2,1),(3,1),(5,6)]))
# No dependencies
_check("test2",[(4,1),(3,2),(8,4)])
# Cycle test
pairs = [(1,4),(4,3),(4,5),(5,1)]
- try: n = order_dependencies(pairs)
- except ValueError: pass
- else: raise Exception,"test3 expect ValueError exception for %s"%(pairs,)
+ try:
+ n = order_dependencies(pairs)
+ except ValueError:
+ pass
+ else:
+ raise Exception("test3 expect ValueError exception for %s"%(pairs,))
# large test for gross speed check
- A = numpy.random.randint(4000,size=(1000,2))
+ A = np.random.randint(4000,size=(1000,2))
A[:,1] += 4000 # Avoid cycles
_check("test-large",A)
# depth tests
k = 200
- A = numpy.array([range(0,k),range(1,k+1)]).T
+ A = np.array([range(0,k),range(1,k+1)]).T
_check("depth-1",A)
- A = numpy.array([range(1,k+1),range(0,k)]).T
+ A = np.array([range(1,k+1),range(0,k)]).T
_check("depth-2",A)
def test_expr():
import inspect, dis
import math
-
+
symtab = {'a.b.x':1, 'a.c':2, 'a.b':3, 'b.x':4}
expr = 'a.b.x + sin(4*pi*a.c) + a.b.x/a.b'
-
+
# Check symbol lookup
assert _symbols(expr, symtab) == set([1,2,3])
@@ -354,7 +359,7 @@ def test_expr():
fn()
expected = 2*math.pi*math.sin(5/.1875) + 6
assert p2.value == expected,"Value was %s, not %s"%(p2.value,expected)
-
+
# Check empty dependency set doesn't crash
fn = compile_constraints(*world(p1,p3))
fn()
@@ -378,10 +383,10 @@ def test_expr():
fn = compile_constraints(*world(p1,p2,p3,p5),context=dict(tbl=tbl))
fn()
assert p5.value == 2.07,"Value for %s was %s"%(p5.expression,p5.value)
-
+
# Verify that we capture invalid expressions
- for expr in ['G4.cage', 'M0.cage', 'M1.G1 + *2',
+ for expr in ['G4.cage', 'M0.cage', 'M1.G1 + *2',
'piddle',
'5; import sys; print "p0wned"',
'__import__("sys").argv']:
diff --git a/src/sas/sascalc/pr/invertor.py b/src/sas/sascalc/pr/invertor.py
index c436c48..134d428 100644
--- a/src/sas/sascalc/pr/invertor.py
+++ b/src/sas/sascalc/pr/invertor.py
@@ -6,7 +6,7 @@ The module contains the Invertor class.
FIXME: The way the Invertor interacts with its C component should be cleaned up
"""
-import numpy
+import numpy as np
import sys
import math
import time
@@ -18,6 +18,8 @@ from numpy.linalg import lstsq
from scipy import optimize
from sas.sascalc.pr.core.pr_inversion import Cinvertor
+logger = logging.getLogger(__name__)
+
def help():
"""
Provide general online help text
@@ -118,7 +120,7 @@ class Invertor(Cinvertor):
(self.__dict__, self.alpha, self.d_max,
self.q_min, self.q_max,
self.x, self.y,
- self.err, self.has_bck,
+ self.err, self.est_bck,
self.slit_height, self.slit_width) = state
def __reduce_ex__(self, proto):
@@ -130,7 +132,7 @@ class Invertor(Cinvertor):
self.alpha, self.d_max,
self.q_min, self.q_max,
self.x, self.y,
- self.err, self.has_bck,
+ self.err, self.est_bck,
self.slit_height, self.slit_width,
)
return (Invertor, tuple(), state, None, None)
@@ -145,7 +147,7 @@ class Invertor(Cinvertor):
if 0.0 in value:
msg = "Invertor: one of your q-values is zero. "
msg += "Delete that entry before proceeding"
- raise ValueError, msg
+ raise ValueError(msg)
return self.set_x(value)
elif name == 'y':
return self.set_y(value)
@@ -156,14 +158,14 @@ class Invertor(Cinvertor):
if value <= 0.0:
msg = "Invertor: d_max must be greater than zero."
msg += "Correct that entry before proceeding"
- raise ValueError, msg
+ raise ValueError(msg)
return self.set_dmax(value)
elif name == 'q_min':
- if value == None:
+ if value is None:
return self.set_qmin(-1.0)
return self.set_qmin(value)
elif name == 'q_max':
- if value == None:
+ if value is None:
return self.set_qmax(-1.0)
return self.set_qmax(value)
elif name == 'alpha':
@@ -172,13 +174,13 @@ class Invertor(Cinvertor):
return self.set_slit_height(value)
elif name == 'slit_width':
return self.set_slit_width(value)
- elif name == 'has_bck':
+ elif name == 'est_bck':
if value == True:
- return self.set_has_bck(1)
+ return self.set_est_bck(1)
elif value == False:
- return self.set_has_bck(0)
+ return self.set_est_bck(0)
else:
- raise ValueError, "Invertor: has_bck can only be True or False"
+ raise ValueError("Invertor: est_bck can only be True or False")
return Cinvertor.__setattr__(self, name, value)
@@ -188,15 +190,15 @@ class Invertor(Cinvertor):
"""
#import numpy
if name == 'x':
- out = numpy.ones(self.get_nx())
+ out = np.ones(self.get_nx())
self.get_x(out)
return out
elif name == 'y':
- out = numpy.ones(self.get_ny())
+ out = np.ones(self.get_ny())
self.get_y(out)
return out
elif name == 'err':
- out = numpy.ones(self.get_nerr())
+ out = np.ones(self.get_nerr())
self.get_err(out)
return out
elif name == 'd_max':
@@ -217,8 +219,8 @@ class Invertor(Cinvertor):
return self.get_slit_height()
elif name == 'slit_width':
return self.get_slit_width()
- elif name == 'has_bck':
- value = self.get_has_bck()
+ elif name == 'est_bck':
+ value = self.get_est_bck()
if value == 1:
return True
else:
@@ -245,7 +247,8 @@ class Invertor(Cinvertor):
invertor.x = self.x
invertor.y = self.y
invertor.err = self.err
- invertor.has_bck = self.has_bck
+ invertor.est_bck = self.est_bck
+ invertor.background = self.background
invertor.slit_height = self.slit_height
invertor.slit_width = self.slit_width
@@ -287,8 +290,13 @@ class Invertor(Cinvertor):
:return: c_out, c_cov - the coefficients with covariance matrix
"""
# Reset the background value before proceeding
- self.background = 0.0
- return self.lstsq(nfunc, nr=nr)
+ # self.background = 0.0
+ if not self.est_bck:
+ self.y -= self.background
+ out, cov = self.lstsq(nfunc, nr=nr)
+ if not self.est_bck:
+ self.y += self.background
+ return out, cov
def iq(self, out, q):
"""
@@ -322,9 +330,9 @@ class Invertor(Cinvertor):
# First, check that the current data is valid
if self.is_valid() <= 0:
msg = "Invertor.invert: Data array are of different length"
- raise RuntimeError, msg
+ raise RuntimeError(msg)
- p = numpy.ones(nfunc)
+ p = np.ones(nfunc)
t_0 = time.time()
out, cov_x, _, _, _ = optimize.leastsq(self.residuals, p, full_output=1)
@@ -340,7 +348,7 @@ class Invertor(Cinvertor):
self.elapsed = time.time() - t_0
if cov_x is None:
- cov_x = numpy.ones([nfunc, nfunc])
+ cov_x = np.ones([nfunc, nfunc])
cov_x *= math.fabs(chisqr)
return out, cov_x
@@ -355,9 +363,9 @@ class Invertor(Cinvertor):
# First, check that the current data is valid
if self.is_valid() <= 0:
msg = "Invertor.invert: Data arrays are of different length"
- raise RuntimeError, msg
+ raise RuntimeError(msg)
- p = numpy.ones(nfunc)
+ p = np.ones(nfunc)
t_0 = time.time()
out, cov_x, _, _, _ = optimize.leastsq(self.pr_residuals, p, full_output=1)
@@ -392,9 +400,9 @@ class Invertor(Cinvertor):
"""
Check q-value against user-defined range
"""
- if not self.q_min == None and q < self.q_min:
+ if self.q_min is not None and q < self.q_min:
return False
- if not self.q_max == None and q > self.q_max:
+ if self.q_max is not None and q > self.q_max:
return False
return True
@@ -434,12 +442,12 @@ class Invertor(Cinvertor):
"""
# Note: To make sure an array is contiguous:
- # blah = numpy.ascontiguousarray(blah_original)
+ # blah = np.ascontiguousarray(blah_original)
# ... before passing it to C
if self.is_valid() < 0:
msg = "Invertor: invalid data; incompatible data lengths."
- raise RuntimeError, msg
+ raise RuntimeError(msg)
self.nfunc = nfunc
# a -- An M x N matrix.
@@ -451,20 +459,20 @@ class Invertor(Cinvertor):
nq = 0
# If we need to fit the background, add a term
- if self.has_bck == True:
+ if self.est_bck == True:
nfunc_0 = nfunc
nfunc += 1
- a = numpy.zeros([npts + nq, nfunc])
- b = numpy.zeros(npts + nq)
- err = numpy.zeros([nfunc, nfunc])
+ a = np.zeros([npts + nq, nfunc])
+ b = np.zeros(npts + nq)
+ err = np.zeros([nfunc, nfunc])
# Construct the a matrix and b vector that represent the problem
t_0 = time.time()
try:
self._get_matrix(nfunc, nq, a, b)
- except:
- raise RuntimeError, "Invertor: could not invert I(Q)\n %s" % sys.exc_value
+ except Exception as exc:
+ raise RuntimeError("Invertor: could not invert I(Q)\n %s" % str(exc))
# Perform the inversion (least square fit)
c, chi2, _, _ = lstsq(a, b)
@@ -475,7 +483,7 @@ class Invertor(Cinvertor):
chi2 = -1.0
self.chi2 = chi2
- inv_cov = numpy.zeros([nfunc, nfunc])
+ inv_cov = np.zeros([nfunc, nfunc])
# Get the covariance matrix, defined as inv_cov = a_transposed * a
self._get_invcov_matrix(nfunc, nr, a, inv_cov)
@@ -489,23 +497,22 @@ class Invertor(Cinvertor):
self.suggested_alpha = new_alpha
try:
- cov = numpy.linalg.pinv(inv_cov)
+ cov = np.linalg.pinv(inv_cov)
err = math.fabs(chi2 / float(npts - nfunc)) * cov
except:
# We were not able to estimate the errors
# Return an empty error matrix
- logging.error(sys.exc_value)
+ logger.error(sys.exc_value)
# Keep a copy of the last output
- if self.has_bck == False:
- self.background = 0
+ if self.est_bck == False:
self.out = c
self.cov = err
else:
self.background = c[0]
- err_0 = numpy.zeros([nfunc, nfunc])
- c_0 = numpy.zeros(nfunc)
+ err_0 = np.zeros([nfunc, nfunc])
+ c_0 = np.zeros(nfunc)
for i in range(nfunc_0):
c_0[i] = c[i + 1]
@@ -540,7 +547,7 @@ class Invertor(Cinvertor):
# If we fail, estimate alpha and return the default
# number of terms
best_alpha, _, _ = self.estimate_alpha(self.nfunc)
- logging.warning("Invertor.estimate_numterms: %s" % sys.exc_value)
+ logger.warning("Invertor.estimate_numterms: %s" % sys.exc_value)
return self.nfunc, best_alpha, "Could not estimate number of terms"
def estimate_alpha(self, nfunc):
@@ -650,18 +657,18 @@ class Invertor(Cinvertor):
file.write("#slit_height=%g\n" % self.slit_height)
file.write("#slit_width=%g\n" % self.slit_width)
file.write("#background=%g\n" % self.background)
- if self.has_bck == True:
+ if self.est_bck == True:
file.write("#has_bck=1\n")
else:
file.write("#has_bck=0\n")
file.write("#alpha_estimate=%g\n" % self.suggested_alpha)
- if not self.out == None:
+ if self.out is not None:
if len(self.out) == len(self.cov):
for i in range(len(self.out)):
file.write("#C_%i=%s+-%s\n" % (i, str(self.out[i]),
str(self.cov[i][i])))
file.write("<r> <Pr> <dPr>\n")
- r = numpy.arange(0.0, self.d_max, self.d_max / npts)
+ r = np.arange(0.0, self.d_max, self.d_max / npts)
for r_i in r:
(value, err) = self.pr_err(self.out, self.cov, r_i)
@@ -693,8 +700,8 @@ class Invertor(Cinvertor):
elif line.startswith('#nfunc='):
toks = line.split('=')
self.nfunc = int(toks[1])
- self.out = numpy.zeros(self.nfunc)
- self.cov = numpy.zeros([self.nfunc, self.nfunc])
+ self.out = np.zeros(self.nfunc)
+ self.cov = np.zeros([self.nfunc, self.nfunc])
elif line.startswith('#alpha='):
toks = line.split('=')
self.alpha = float(toks[1])
@@ -731,9 +738,9 @@ class Invertor(Cinvertor):
elif line.startswith('#has_bck='):
toks = line.split('=')
if int(toks[1]) == 1:
- self.has_bck = True
+ self.est_bck = True
else:
- self.has_bck = False
+ self.est_bck = False
# Now read in the parameters
elif line.startswith('#C_'):
@@ -748,7 +755,7 @@ class Invertor(Cinvertor):
except:
msg = "Invertor.from_file: corrupted file\n%s" % sys.exc_value
- raise RuntimeError, msg
+ raise RuntimeError(msg)
else:
msg = "Invertor.from_file: '%s' is not a file" % str(path)
- raise RuntimeError, msg
+ raise RuntimeError(msg)
diff --git a/src/sas/sascalc/pr/num_term.py b/src/sas/sascalc/pr/num_term.py
index ea7baad..d427e29 100644
--- a/src/sas/sascalc/pr/num_term.py
+++ b/src/sas/sascalc/pr/num_term.py
@@ -1,197 +1,201 @@
-import math
-import numpy
-import copy
-import sys
-import logging
-from sas.sascalc.pr.invertor import Invertor
-
-class NTermEstimator(object):
- """
- """
- def __init__(self, invertor):
- """
- """
- self.invertor = invertor
- self.nterm_min = 10
- self.nterm_max = len(self.invertor.x)
- if self.nterm_max > 50:
- self.nterm_max = 50
- self.isquit_func = None
-
- self.osc_list = []
- self.err_list = []
- self.alpha_list = []
- self.mess_list = []
- self.dataset = []
-
- def is_odd(self, n):
- """
- """
- return bool(n % 2)
-
- def sort_osc(self):
- """
- """
- #import copy
- osc = copy.deepcopy(self.dataset)
- lis = []
- for i in range(len(osc)):
- osc.sort()
- re = osc.pop(0)
- lis.append(re)
- return lis
-
- def median_osc(self):
- """
- """
- osc = self.sort_osc()
- dv = len(osc)
- med = float(dv) / 2.0
- odd = self.is_odd(dv)
- medi = 0
- for i in range(dv):
- if odd == True:
- medi = osc[int(med)]
- else:
- medi = osc[int(med) - 1]
- return medi
-
- def get0_out(self):
- """
- """
- inver = self.invertor
- self.osc_list = []
- self.err_list = []
- self.alpha_list = []
- for k in range(self.nterm_min, self.nterm_max, 1):
- if self.isquit_func != None:
- self.isquit_func()
- best_alpha, message, _ = inver.estimate_alpha(k)
- inver.alpha = best_alpha
- inver.out, inver.cov = inver.lstsq(k)
- osc = inver.oscillations(inver.out)
- err = inver.get_pos_err(inver.out, inver.cov)
- if osc > 10.0:
- break
- self.osc_list.append(osc)
- self.err_list.append(err)
- self.alpha_list.append(inver.alpha)
- self.mess_list.append(message)
-
- new_osc1 = []
- new_osc2 = []
- new_osc3 = []
- flag9 = False
- flag8 = False
- for i in range(len(self.err_list)):
- if self.err_list[i] <= 1.0 and self.err_list[i] >= 0.9:
- new_osc1.append(self.osc_list[i])
- flag9 = True
- if self.err_list[i] < 0.9 and self.err_list[i] >= 0.8:
- new_osc2.append(self.osc_list[i])
- flag8 = True
- if self.err_list[i] < 0.8 and self.err_list[i] >= 0.7:
- new_osc3.append(self.osc_list[i])
-
- if flag9 == True:
- self.dataset = new_osc1
- elif flag8 == True:
- self.dataset = new_osc2
- else:
- self.dataset = new_osc3
-
- return self.dataset
-
- def ls_osc(self):
- """
- """
- # Generate data
- self.get0_out()
- med = self.median_osc()
-
- #TODO: check 1
- ls_osc = self.dataset
- ls = []
- for i in range(len(ls_osc)):
- if int(med) == int(ls_osc[i]):
- ls.append(ls_osc[i])
- return ls
-
- def compare_err(self):
- """
- """
- ls = self.ls_osc()
- nt_ls = []
- for i in range(len(ls)):
- r = ls[i]
- n = self.osc_list.index(r) + 10
- nt_ls.append(n)
- return nt_ls
-
- def num_terms(self, isquit_func=None):
- """
- """
- try:
- self.isquit_func = isquit_func
- nts = self.compare_err()
- div = len(nts)
- tem = float(div) / 2.0
- odd = self.is_odd(div)
- if odd == True:
- nt = nts[int(tem)]
- else:
- nt = nts[int(tem) - 1]
- return nt, self.alpha_list[nt - 10], self.mess_list[nt - 10]
- except:
- #TODO: check the logic above and make sure it doesn't
- # rely on the try-except.
- return self.nterm_min, self.invertor.alpha, ''
-
-
-#For testing
-def load(path):
- # Read the data from the data file
- data_x = numpy.zeros(0)
- data_y = numpy.zeros(0)
- data_err = numpy.zeros(0)
- scale = None
- min_err = 0.0
- if not path == None:
- input_f = open(path, 'r')
- buff = input_f.read()
- lines = buff.split('\n')
- for line in lines:
- try:
- toks = line.split()
- test_x = float(toks[0])
- test_y = float(toks[1])
- if len(toks) > 2:
- err = float(toks[2])
- else:
- if scale == None:
- scale = 0.05 * math.sqrt(test_y)
- #scale = 0.05/math.sqrt(y)
- min_err = 0.01 * y
- err = scale * math.sqrt(test_y) + min_err
- #err = 0
-
- data_x = numpy.append(data_x, test_x)
- data_y = numpy.append(data_y, test_y)
- data_err = numpy.append(data_err, err)
- except:
- logging.error(sys.exc_value)
-
- return data_x, data_y, data_err
-
-
-if __name__ == "__main__":
- invert = Invertor()
- x, y, erro = load("test/Cyl_A_D102.txt")
- invert.d_max = 102.0
- invert.nfunc = 10
- invert.x = x
- invert.y = y
- invert.err = erro
- # Testing estimator
- est = NTermEstimator(invert)
- print est.num_terms()
+from __future__ import print_function
+
+import math
+import numpy as np
+import copy
+import sys
+import logging
+from sas.sascalc.pr.invertor import Invertor
+
+logger = logging.getLogger(__name__)
+
+class NTermEstimator(object):
+ """
+ """
+ def __init__(self, invertor):
+ """
+ """
+ self.invertor = invertor
+ self.nterm_min = 10
+ self.nterm_max = len(self.invertor.x)
+ if self.nterm_max > 50:
+ self.nterm_max = 50
+ self.isquit_func = None
+
+ self.osc_list = []
+ self.err_list = []
+ self.alpha_list = []
+ self.mess_list = []
+ self.dataset = []
+
+ def is_odd(self, n):
+ """
+ """
+ return bool(n % 2)
+
+ def sort_osc(self):
+ """
+ """
+ #import copy
+ osc = copy.deepcopy(self.dataset)
+ lis = []
+ for i in range(len(osc)):
+ osc.sort()
+ re = osc.pop(0)
+ lis.append(re)
+ return lis
+
+ def median_osc(self):
+ """
+ """
+ osc = self.sort_osc()
+ dv = len(osc)
+ med = float(dv) / 2.0
+ odd = self.is_odd(dv)
+ medi = 0
+ for i in range(dv):
+ if odd == True:
+ medi = osc[int(med)]
+ else:
+ medi = osc[int(med) - 1]
+ return medi
+
+ def get0_out(self):
+ """
+ """
+ inver = self.invertor
+ self.osc_list = []
+ self.err_list = []
+ self.alpha_list = []
+ for k in range(self.nterm_min, self.nterm_max, 1):
+ if self.isquit_func is not None:
+ self.isquit_func()
+ best_alpha, message, _ = inver.estimate_alpha(k)
+ inver.alpha = best_alpha
+ inver.out, inver.cov = inver.lstsq(k)
+ osc = inver.oscillations(inver.out)
+ err = inver.get_pos_err(inver.out, inver.cov)
+ if osc > 10.0:
+ break
+ self.osc_list.append(osc)
+ self.err_list.append(err)
+ self.alpha_list.append(inver.alpha)
+ self.mess_list.append(message)
+
+ new_osc1 = []
+ new_osc2 = []
+ new_osc3 = []
+ flag9 = False
+ flag8 = False
+ for i in range(len(self.err_list)):
+ if self.err_list[i] <= 1.0 and self.err_list[i] >= 0.9:
+ new_osc1.append(self.osc_list[i])
+ flag9 = True
+ if self.err_list[i] < 0.9 and self.err_list[i] >= 0.8:
+ new_osc2.append(self.osc_list[i])
+ flag8 = True
+ if self.err_list[i] < 0.8 and self.err_list[i] >= 0.7:
+ new_osc3.append(self.osc_list[i])
+
+ if flag9 == True:
+ self.dataset = new_osc1
+ elif flag8 == True:
+ self.dataset = new_osc2
+ else:
+ self.dataset = new_osc3
+
+ return self.dataset
+
+ def ls_osc(self):
+ """
+ """
+ # Generate data
+ self.get0_out()
+ med = self.median_osc()
+
+ #TODO: check 1
+ ls_osc = self.dataset
+ ls = []
+ for i in range(len(ls_osc)):
+ if int(med) == int(ls_osc[i]):
+ ls.append(ls_osc[i])
+ return ls
+
+ def compare_err(self):
+ """
+ """
+ ls = self.ls_osc()
+ nt_ls = []
+ for i in range(len(ls)):
+ r = ls[i]
+ n = self.osc_list.index(r) + 10
+ nt_ls.append(n)
+ return nt_ls
+
+ def num_terms(self, isquit_func=None):
+ """
+ """
+ try:
+ self.isquit_func = isquit_func
+ nts = self.compare_err()
+ div = len(nts)
+ tem = float(div) / 2.0
+ odd = self.is_odd(div)
+ if odd == True:
+ nt = nts[int(tem)]
+ else:
+ nt = nts[int(tem) - 1]
+ return nt, self.alpha_list[nt - 10], self.mess_list[nt - 10]
+ except:
+ #TODO: check the logic above and make sure it doesn't
+ # rely on the try-except.
+ return self.nterm_min, self.invertor.alpha, ''
+
+
+#For testing
+def load(path):
+ # Read the data from the data file
+ data_x = np.zeros(0)
+ data_y = np.zeros(0)
+ data_err = np.zeros(0)
+ scale = None
+ min_err = 0.0
+ if path is not None:
+ input_f = open(path, 'r')
+ buff = input_f.read()
+ lines = buff.split('\n')
+ for line in lines:
+ try:
+ toks = line.split()
+ test_x = float(toks[0])
+ test_y = float(toks[1])
+ if len(toks) > 2:
+ err = float(toks[2])
+ else:
+ if scale is None:
+ scale = 0.05 * math.sqrt(test_y)
+ #scale = 0.05/math.sqrt(y)
+ min_err = 0.01 * y
+ err = scale * math.sqrt(test_y) + min_err
+ #err = 0
+
+ data_x = np.append(data_x, test_x)
+ data_y = np.append(data_y, test_y)
+ data_err = np.append(data_err, err)
+ except:
+ logger.error(sys.exc_value)
+
+ return data_x, data_y, data_err
+
+
+if __name__ == "__main__":
+ invert = Invertor()
+ x, y, erro = load("test/Cyl_A_D102.txt")
+ invert.d_max = 102.0
+ invert.nfunc = 10
+ invert.x = x
+ invert.y = y
+ invert.err = erro
+ # Testing estimator
+ est = NTermEstimator(invert)
+ print(est.num_terms())
diff --git a/src/sas/sascalc/realspace/VolumeCanvas.py b/src/sas/sascalc/realspace/VolumeCanvas.py
index 88bf4c7..6155228 100644
--- a/src/sas/sascalc/realspace/VolumeCanvas.py
+++ b/src/sas/sascalc/realspace/VolumeCanvas.py
@@ -1,803 +1,792 @@
-#!/usr/bin/env python
-""" Volume Canvas
-
- Simulation canvas for real-space simulation of SAS scattering intensity.
- The user can create an arrangement of basic shapes and estimate I(q) and
- I(q_x, q_y). Error estimates on the simulation are also available.
-
- Example:
-
- import sas.sascalc.realspace.VolumeCanvas as VolumeCanvas
- canvas = VolumeCanvas.VolumeCanvas()
- canvas.setParam('lores_density', 0.01)
-
- sphere = SphereDescriptor()
- handle = canvas.addObject(sphere)
-
- output, error = canvas.getIqError(q=0.1)
- output, error = canvas.getIq2DError(0.1, 0.1)
-
- or alternatively:
- iq = canvas.run(0.1)
- i2_2D = canvas.run([0.1, 1.57])
-
-"""
-
-from sas.models.BaseComponent import BaseComponent
-from sas.sascalc.simulation.pointsmodelpy import pointsmodelpy
-from sas.sascalc.simulation.geoshapespy import geoshapespy
-
-
-import os.path, math
-
-class ShapeDescriptor:
- """
- Class to hold the information about a shape
- The descriptor holds a dictionary of parameters.
-
- Note: if shape parameters are accessed directly
- from outside VolumeCanvas. The getPr method
- should be called before evaluating I(q).
-
- """
- def __init__(self):
- """
- Initialization
- """
- ## Real space object
- self.shapeObject = None
- ## Parameters of the object
- self.params = {}
- self.params["center"] = [0, 0, 0]
- # Orientation are angular offsets in degrees with respect to X, Y, Z
- self.params["orientation"] = [0, 0, 0]
- # Default to lores shape
- self.params['is_lores'] = True
- self.params['order'] = 0
-
- def create(self):
- """
- Create an instance of the shape
- """
- # Set center
- x0 = self.params["center"][0]
- y0 = self.params["center"][1]
- z0 = self.params["center"][2]
- geoshapespy.set_center(self.shapeObject, x0, y0, z0)
-
- # Set orientation
- x0 = self.params["orientation"][0]
- y0 = self.params["orientation"][1]
- z0 = self.params["orientation"][2]
- geoshapespy.set_orientation(self.shapeObject, x0, y0, z0)
-
-class SphereDescriptor(ShapeDescriptor):
- """
- Descriptor for a sphere
-
- The parameters are:
- - radius [Angstroem] [default = 20 A]
- - Contrast [A-2] [default = 1 A-2]
-
- """
- def __init__(self):
- """
- Initialization
- """
- ShapeDescriptor.__init__(self)
- # Default parameters
- self.params["type"] = "sphere"
- # Radius of the sphere
- self.params["radius"] = 20.0
- # Constrast parameter
- self.params["contrast"] = 1.0
-
- def create(self):
- """
- Create an instance of the shape
- @return: instance of the shape
- """
- self.shapeObject = geoshapespy.new_sphere(\
- self.params["radius"])
-
- ShapeDescriptor.create(self)
- return self.shapeObject
-
-class CylinderDescriptor(ShapeDescriptor):
- """
- Descriptor for a cylinder
- Orientation: Default cylinder is along Y
-
- Parameters:
- - Length [default = 40 A]
- - Radius [default = 10 A]
- - Contrast [default = 1 A-2]
- """
- def __init__(self):
- """
- Initialization
- """
- ShapeDescriptor.__init__(self)
- # Default parameters
- self.params["type"] = "cylinder"
- # Length of the cylinder
- self.params["length"] = 40.0
- # Radius of the cylinder
- self.params["radius"] = 10.0
- # Constrast parameter
- self.params["contrast"] = 1.0
-
- def create(self):
- """
- Create an instance of the shape
- @return: instance of the shape
- """
- self.shapeObject = geoshapespy.new_cylinder(\
- self.params["radius"], self.params["length"])
-
- ShapeDescriptor.create(self)
- return self.shapeObject
-
-
-class EllipsoidDescriptor(ShapeDescriptor):
- """
- Descriptor for an ellipsoid
-
- Parameters:
- - Radius_x along the x-axis [default = 30 A]
- - Radius_y along the y-axis [default = 20 A]
- - Radius_z along the z-axis [default = 10 A]
- - contrast [default = 1 A-2]
- """
- def __init__(self):
- """
- Initialization
- """
- ShapeDescriptor.__init__(self)
- # Default parameters
- self.params["type"] = "ellipsoid"
- self.params["radius_x"] = 30.0
- self.params["radius_y"] = 20.0
- self.params["radius_z"] = 10.0
- self.params["contrast"] = 1.0
-
- def create(self):
- """
- Create an instance of the shape
- @return: instance of the shape
- """
- self.shapeObject = geoshapespy.new_ellipsoid(\
- self.params["radius_x"], self.params["radius_y"],
- self.params["radius_z"])
-
- ShapeDescriptor.create(self)
- return self.shapeObject
-
-class HelixDescriptor(ShapeDescriptor):
- """
- Descriptor for an helix
-
- Parameters:
- -radius_helix: the radius of the helix [default = 10 A]
- -radius_tube: radius of the "tube" that forms the helix [default = 3 A]
- -pitch: distance between two consecutive turns of the helix [default = 34 A]
- -turns: number of turns of the helix [default = 3]
- -contrast: contrast parameter [default = 1 A-2]
- """
- def __init__(self):
- """
- Initialization
- """
- ShapeDescriptor.__init__(self)
- # Default parameters
- self.params["type"] = "singlehelix"
- self.params["radius_helix"] = 10.0
- self.params["radius_tube"] = 3.0
- self.params["pitch"] = 34.0
- self.params["turns"] = 3.0
- self.params["contrast"] = 1.0
-
- def create(self):
- """
- Create an instance of the shape
- @return: instance of the shape
- """
- self.shapeObject = geoshapespy.new_singlehelix(\
- self.params["radius_helix"], self.params["radius_tube"],
- self.params["pitch"], self.params["turns"])
-
- ShapeDescriptor.create(self)
- return self.shapeObject
-
-class PDBDescriptor(ShapeDescriptor):
- """
- Descriptor for a PDB set of points
-
- Parameter:
- - file = name of the PDB file
- """
- def __init__(self, filename):
- """
- Initialization
- @param filename: name of the PDB file to load
- """
- ShapeDescriptor.__init__(self)
- # Default parameters
- self.params["type"] = "pdb"
- self.params["file"] = filename
- self.params['is_lores'] = False
-
- def create(self):
- """
- Create an instance of the shape
- @return: instance of the shape
- """
- self.shapeObject = pointsmodelpy.new_pdbmodel()
- pointsmodelpy.pdbmodel_add(self.shapeObject, self.params['file'])
-
- #ShapeDescriptor.create(self)
- return self.shapeObject
-
-# Define a dictionary for the shape until we find
-# a better way to create them
-shape_dict = {'sphere':SphereDescriptor,
- 'cylinder':CylinderDescriptor,
- 'ellipsoid':EllipsoidDescriptor,
- 'singlehelix':HelixDescriptor}
-
-class VolumeCanvas(BaseComponent):
- """
- Class representing an empty space volume to add
- geometrical object to.
-
- For 1D I(q) simulation, getPr() is called internally for the
- first call to getIq().
-
- """
-
- def __init__(self):
- """
- Initialization
- """
- BaseComponent.__init__(self)
-
- ## Maximum value of q reachable
- self.params['q_max'] = 0.1
- self.params['lores_density'] = 0.1
- self.params['scale'] = 1.0
- self.params['background'] = 0.0
-
- self.lores_model = pointsmodelpy.new_loresmodel(self.params['lores_density'])
- self.complex_model = pointsmodelpy.new_complexmodel()
- self.shapes = {}
- self.shapecount = 0
- self.points = None
- self.npts = 0
- self.hasPr = False
-
- def _model_changed(self):
- """
- Reset internal data members to reflect the fact that the
- real-space model has changed
- """
- self.hasPr = False
- self.points = None
-
- def addObject(self, shapeDesc, id = None):
- """
- Adds a real-space object to the canvas.
-
- @param shapeDesc: object to add to the canvas [ShapeDescriptor]
- @param id: string handle for the object [string] [optional]
- @return: string handle for the object
- """
- # If the handle is not provided, create one
- if id == None:
- id = shapeDesc.params["type"]+str(self.shapecount)
-
- # Self the order number
- shapeDesc.params['order'] = self.shapecount
- # Store the shape in a dictionary entry associated
- # with the handle
- self.shapes[id] = shapeDesc
- self.shapecount += 1
-
- #model changed, need to recalculate P(r)
- self._model_changed()
-
- return id
-
-
- def add(self, shape, id = None):
- """
- The intend of this method is to eventually be able to use it
- as a factory for the canvas and unify the simulation with the
- analytical solutions. For instance, if one adds a cylinder and
- it is the only shape on the canvas, the analytical solution
- could be called. If multiple shapes are involved, then
- simulation has to be performed.
-
- This function is deprecated, use addObject().
-
- @param shape: name of the object to add to the canvas [string]
- @param id: string handle for the object [string] [optional]
- @return: string handle for the object
- """
- # If the handle is not provided, create one
- if id == None:
- id = "shape"+str(self.shapecount)
-
- #shapeDesc = ShapeDescriptor(shape.lower())
- if shape.lower() in shape_dict:
- shapeDesc = shape_dict[shape.lower()]()
- elif os.path.isfile(shape):
- # A valid filename was supplier, create a PDB object
- shapeDesc = PDBDescriptor(shape)
- else:
- raise ValueError, "VolumeCanvas.add: Unknown shape %s" % shape
-
- return self.addObject(shapeDesc, id)
-
- def delete(self, id):
- """
- Delete a shape. The ID for the shape is required.
- @param id: string handle for the object [string] [optional]
- """
-
- if self.shapes.has_key(id):
- del self.shapes[id]
- else:
- raise KeyError, "VolumeCanvas.delete: could not find shape ID"
-
- #model changed, need to recalculate P(r)
- self._model_changed()
-
-
- def setParam(self, name, value):
- """
- Function to set the value of a parameter.
- Both VolumeCanvas parameters and shape parameters
- are accessible.
-
- Note: if shape parameters are accessed directly
- from outside VolumeCanvas. The getPr method
- should be called before evaluating I(q).
-
- TODO: implemented a check method to protect
- against that.
-
- @param name: name of the parameter to change
- @param value: value to give the parameter
- """
-
- # Lowercase for case insensitivity
- name = name.lower()
-
- # Look for shape access
- toks = name.split('.')
-
- # If a shape identifier was given, look the shape up
- # in the dictionary
- if len(toks)>1:
- if toks[0] in self.shapes.keys():
- # The shape was found, now look for the parameter
- if toks[1] in self.shapes[toks[0]].params:
- # The parameter was found, now change it
- self.shapes[toks[0]].params[toks[1]] = value
- self._model_changed()
- else:
- raise ValueError, "Could not find parameter %s" % name
- else:
- raise ValueError, "Could not find shape %s" % toks[0]
-
- else:
- # If we are not accessing the parameters of a
- # shape, see if the parameter is part of this object
- BaseComponent.setParam(self, name, value)
- self._model_changed()
-
- def getParam(self, name):
- """
- @param name: name of the parameter to change
- """
- #TODO: clean this up
-
- # Lowercase for case insensitivity
- name = name.lower()
-
- # Look for sub-model access
- toks = name.split('.')
- if len(toks) == 1:
- try:
- self.params.has_key(toks[0])
- except KeyError:
- raise ValueError, \
- "VolumeCanvas.getParam: Could not find %s" % name
-
- value = self.params[toks[0]]
- if isinstance(value, ShapeDescriptor):
- raise ValueError, \
- "VolumeCanvas.getParam: Cannot get parameter value."
- else:
- return value
-
- elif len(toks) == 2:
- try:
- self.shapes.has_key(toks[0])
- except KeyError:
- raise ValueError, \
- "VolumeCanvas.getParam: Could not find %s" % name
-
- shapeinstance = self.shapes[toks[0]]
-
- try:
- shapeinstance.params.has_key(toks[1])
- except KeyError:
- raise ValueError, \
- "VolumeCanvas.getParam: Could not find %s" % name
-
- return shapeinstance.params[toks[1]]
-
- else:
- raise ValueError, \
- "VolumeCanvas.getParam: Could not find %s" % name
-
- def getParamList(self, shapeid = None):
- """
- return a full list of all available parameters from
- self.params.keys(). If a key in self.params is a instance
- of ShapeDescriptor, extend the return list to:
- [param1,param2,shapeid.param1,shapeid.param2.......]
-
- If shapeid is provided, return the list of parameters that
- belongs to that shape id only : [shapeid.param1, shapeid.param2...]
- """
-
- param_list = []
- if shapeid == None:
- for key1 in self.params.keys():
- #value1 = self.params[key1]
- param_list.append(key1)
- for key2 in self.shapes.keys():
- value2 = self.shapes[key2]
- header = key2 + '.'
- for key3 in value2.params.keys():
- fullname = header + key3
- param_list.append(fullname)
-
- else:
- try:
- self.shapes.has_key(shapeid)
- except KeyError:
- raise ValueError, \
- "VolumeCanvas: getParamList: Could not find %s" % shapeid
- header = shapeid + '.'
- param_list = self.shapes[shapeid].params.keys()
- for i in range(len(param_list)):
- param_list[i] = header + param_list[i]
-
- return param_list
-
- def getShapeList(self):
- """
- Return a list of the shapes
- """
- return self.shapes.keys()
-
- def _addSingleShape(self, shapeDesc):
- """
- create shapeobject based on shapeDesc
- @param shapeDesc: shape description
- """
- #Create the object model
- shapeDesc.create()
-
- if shapeDesc.params['is_lores']:
- # Add the shape to the lores_model
- pointsmodelpy.lores_add(self.lores_model,
- shapeDesc.shapeObject, shapeDesc.params['contrast'])
-
- def _createVolumeFromList(self):
- """
- Create a new lores model with all the shapes in our internal list
- Whenever we change a parameter of a shape, we have to re-create
- the whole thing.
-
- Items with higher 'order' number take precedence for regions
- of space that are shared with other objects. Points in the
- overlapping region belonging to objects with lower 'order'
- will be ignored.
-
- Items are added in decreasing 'order' number.
- The item with the highest 'order' will be added *first*.
- [That conventions is prescribed by the realSpaceModeling module]
- """
-
- # Create empty model
- self.lores_model = \
- pointsmodelpy.new_loresmodel(self.params['lores_density'])
-
- # Create empty complex model
- self.complex_model = pointsmodelpy.new_complexmodel()
-
- # Order the object first
- obj_list = []
-
- for shape in self.shapes:
- order = self.shapes[shape].params['order']
- # find where to place it in the list
- stored = False
-
- for i in range(len(obj_list)):
- if obj_list[i][0] > order:
- obj_list.insert(i, [order, shape])
- stored = True
- break
-
- if not stored:
- obj_list.append([order, shape])
-
- # Add each shape
- len_list = len(obj_list)
- for i in range(len_list-1, -1, -1):
- shapedesc = self.shapes[obj_list[i][1]]
- self._addSingleShape(shapedesc)
-
- return 0
-
- def getPr(self):
- """
- Calculate P(r) from the objects on the canvas.
- This method should always be called after the shapes
- on the VolumeCanvas have changed.
-
- @return: calculation output flag
- """
- # To find a complete example of the correct call order:
- # In LORES2, in actionclass.py, method CalculateAction._get_iq()
-
- # If there are not shapes, do nothing
- if len(self.shapes) == 0:
- self._model_changed()
- return 0
-
- # generate space filling points from shape list
- self._createVolumeFromList()
-
- self.points = pointsmodelpy.new_point3dvec()
-
- pointsmodelpy.complexmodel_add(self.complex_model,
- self.lores_model, "LORES")
- for shape in self.shapes:
- if self.shapes[shape].params['is_lores'] == False:
- pointsmodelpy.complexmodel_add(self.complex_model,
- self.shapes[shape].shapeObject, "PDB")
-
- #pointsmodelpy.get_lorespoints(self.lores_model, self.points)
- self.npts = pointsmodelpy.get_complexpoints(self.complex_model, self.points)
-
- # expecting the rmax is a positive float or 0. The maximum distance.
- #rmax = pointsmodelpy.get_lores_pr(self.lores_model, self.points)
-
- rmax = pointsmodelpy.get_complex_pr(self.complex_model, self.points)
- self.hasPr = True
-
- return rmax
-
- def run(self, q = 0):
- """
- Returns the value of I(q) for a given q-value
- @param q: q-value ([float] or [list]) ([A-1] or [[A-1], [rad]])
- @return: I(q) [float] [cm-1]
- """
- # Check for 1D q length
- if q.__class__.__name__ == 'int' \
- or q.__class__.__name__ == 'float':
- return self.getIq(q)
- # Check for 2D q-value
- elif q.__class__.__name__ == 'list':
- # Compute (Qx, Qy) from (Q, phi)
- # Phi is in radian and Q-values are in A-1
- qx = q[0]*math.cos(q[1])
- qy = q[0]*math.sin(q[1])
- return self.getIq2D(qx, qy)
- # Through an exception if it's not a
- # type we recognize
- else:
- raise ValueError, "run(q): bad type for q"
-
- def runXY(self, q = 0):
- """
- Standard run command for the canvas.
- Redirects to the correct method
- according to the input type.
- @param q: q-value [float] or [list] [A-1]
- @return: I(q) [float] [cm-1]
- """
- # Check for 1D q length
- if q.__class__.__name__ == 'int' \
- or q.__class__.__name__ == 'float':
- return self.getIq(q)
- # Check for 2D q-value
- elif q.__class__.__name__ == 'list':
- return self.getIq2D(q[0], q[1])
- # Through an exception if it's not a
- # type we recognize
- else:
- raise ValueError, "runXY(q): bad type for q"
-
- def _create_modelObject(self):
- """
- Create the simulation model obejct from the list
- of shapes.
-
- This method needs to be called each time a parameter
- changes because of the way the underlying library
- was (badly) written. It is impossible to change a
- parameter, or remove a shape without having to
- refill the space points.
-
- TODO: improve that.
- """
- # To find a complete example of the correct call order:
- # In LORES2, in actionclass.py, method CalculateAction._get_iq()
-
- # If there are not shapes, do nothing
- if len(self.shapes) == 0:
- self._model_changed()
- return 0
-
- # generate space filling points from shape list
- self._createVolumeFromList()
-
- self.points = pointsmodelpy.new_point3dvec()
-
- pointsmodelpy.complexmodel_add(self.complex_model,
- self.lores_model, "LORES")
- for shape in self.shapes:
- if self.shapes[shape].params['is_lores'] == False:
- pointsmodelpy.complexmodel_add(self.complex_model,
- self.shapes[shape].shapeObject, "PDB")
-
- #pointsmodelpy.get_lorespoints(self.lores_model, self.points)
- self.npts = pointsmodelpy.get_complexpoints(self.complex_model, self.points)
-
-
- def getIq2D(self, qx, qy):
- """
- Returns simulate I(q) for given q_x and q_y values.
- @param qx: q_x [A-1]
- @param qy: q_y [A-1]
- @return: I(q) [cm-1]
- """
-
- # If this is the first simulation call, we need to generate the
- # space points
- if self.points == None:
- self._create_modelObject()
-
- # Protect against empty model
- if self.points == None:
- return 0
-
- # Evalute I(q)
- norm = 1.0e8/self.params['lores_density']*self.params['scale']
- return norm*pointsmodelpy.get_complex_iq_2D(self.complex_model, self.points, qx, qy)\
- + self.params['background']
-
- def write_pr(self, filename):
- """
- Write P(r) to an output file
- @param filename: file name for P(r) output
- """
- if self.hasPr == False:
- self.getPr()
-
- pointsmodelpy.outputPR(self.complex_model, filename)
-
- def getPrData(self):
- """
- Write P(r) to an output file
- @param filename: file name for P(r) output
- """
- if self.hasPr == False:
- self.getPr()
-
- return pointsmodelpy.get_pr(self.complex_model)
-
- def getIq(self, q):
- """
- Returns the value of I(q) for a given q-value
-
- This method should remain internal to the class
- and the run() method should be used instead.
-
- @param q: q-value [float]
- @return: I(q) [float]
- """
-
- if self.hasPr == False:
- self.getPr()
-
- # By dividing by the density instead of the actuall V/N,
- # we have an uncertainty of +-1 on N because the number
- # of points chosen for the simulation is int(density*volume).
- # Propagation of error gives:
- # delta(1/density^2) = 2*(1/density^2)/N
- # where N is stored in self.npts
-
- norm = 1.0e8/self.params['lores_density']*self.params['scale']
- #return norm*pointsmodelpy.get_lores_i(self.lores_model, q)
- return norm*pointsmodelpy.get_complex_i(self.complex_model, q)\
- + self.params['background']
-
- def getError(self, q):
- """
- Returns the error of I(q) for a given q-value
- @param q: q-value [float]
- @return: I(q) [float]
- """
-
- if self.hasPr == False:
- self.getPr()
-
- # By dividing by the density instead of the actual V/N,
- # we have an uncertainty of +-1 on N because the number
- # of points chosen for the simulation is int(density*volume).
- # Propagation of error gives:
- # delta(1/density^2) = 2*(1/density^2)/N
- # where N is stored in self.npts
-
- norm = 1.0e8/self.params['lores_density']*self.params['scale']
- #return norm*pointsmodelpy.get_lores_i(self.lores_model, q)
- return norm*pointsmodelpy.get_complex_i_error(self.complex_model, q)\
- + self.params['background']
-
- def getIqError(self, q):
- """
- Return the simulated value along with its estimated
- error for a given q-value
-
- Propagation of errors is used to evaluate the
- uncertainty.
-
- @param q: q-value [float]
- @return: mean, error [float, float]
- """
- val = self.getIq(q)
- # Simulation error (statistical)
- err = self.getError(q)
- # Error on V/N
- simerr = 2*val/self.npts
- return val, err+simerr
-
- def getIq2DError(self, qx, qy):
- """
- Return the simulated value along with its estimated
- error for a given q-value
-
- Propagation of errors is used to evaluate the
- uncertainty.
-
- @param qx: qx-value [float]
- @param qy: qy-value [float]
- @return: mean, error [float, float]
- """
- self._create_modelObject()
-
- norm = 1.0e8/self.params['lores_density']*self.params['scale']
- val = norm*pointsmodelpy.get_complex_iq_2D(self.complex_model, self.points, qx, qy)\
- + self.params['background']
-
- # Simulation error (statistical)
- norm = 1.0e8/self.params['lores_density']*self.params['scale'] \
- * math.pow(self.npts/self.params['lores_density'], 1.0/3.0)/self.npts
- err = norm*pointsmodelpy.get_complex_iq_2D_err(self.complex_model, self.points, qx, qy)
- # Error on V/N
- simerr = 2*val/self.npts
-
- # The error used for the position is over-simplified.
- # The actual error was empirically found to be about
- # an order of magnitude larger.
- return val, 10.0*err+simerr
-
+#!/usr/bin/env python
+""" Volume Canvas
+
+ Simulation canvas for real-space simulation of SAS scattering intensity.
+ The user can create an arrangement of basic shapes and estimate I(q) and
+ I(q_x, q_y). Error estimates on the simulation are also available.
+
+ Example:
+
+ import sas.sascalc.realspace.VolumeCanvas as VolumeCanvas
+ canvas = VolumeCanvas.VolumeCanvas()
+ canvas.setParam('lores_density', 0.01)
+
+ sphere = SphereDescriptor()
+ handle = canvas.addObject(sphere)
+
+ output, error = canvas.getIqError(q=0.1)
+ output, error = canvas.getIq2DError(0.1, 0.1)
+
+ or alternatively:
+ iq = canvas.run(0.1)
+ i2_2D = canvas.run([0.1, 1.57])
+
+"""
+
+from sas.sascalc.calculator.BaseComponent import BaseComponent
+from sas.sascalc.simulation.pointsmodelpy import pointsmodelpy
+from sas.sascalc.simulation.geoshapespy import geoshapespy
+
+
+import os.path, math
+
+class ShapeDescriptor(object):
+ """
+ Class to hold the information about a shape
+ The descriptor holds a dictionary of parameters.
+
+ Note: if shape parameters are accessed directly
+ from outside VolumeCanvas. The getPr method
+ should be called before evaluating I(q).
+
+ """
+ def __init__(self):
+ """
+ Initialization
+ """
+ ## Real space object
+ self.shapeObject = None
+ ## Parameters of the object
+ self.params = {}
+ self.params["center"] = [0, 0, 0]
+ # Orientation are angular offsets in degrees with respect to X, Y, Z
+ self.params["orientation"] = [0, 0, 0]
+ # Default to lores shape
+ self.params['is_lores'] = True
+ self.params['order'] = 0
+
+ def create(self):
+ """
+ Create an instance of the shape
+ """
+ # Set center
+ x0 = self.params["center"][0]
+ y0 = self.params["center"][1]
+ z0 = self.params["center"][2]
+ geoshapespy.set_center(self.shapeObject, x0, y0, z0)
+
+ # Set orientation
+ x0 = self.params["orientation"][0]
+ y0 = self.params["orientation"][1]
+ z0 = self.params["orientation"][2]
+ geoshapespy.set_orientation(self.shapeObject, x0, y0, z0)
+
+class SphereDescriptor(ShapeDescriptor):
+ """
+ Descriptor for a sphere
+
+ The parameters are:
+ - radius [Angstroem] [default = 20 A]
+ - Contrast [A-2] [default = 1 A-2]
+
+ """
+ def __init__(self):
+ """
+ Initialization
+ """
+ ShapeDescriptor.__init__(self)
+ # Default parameters
+ self.params["type"] = "sphere"
+ # Radius of the sphere
+ self.params["radius"] = 20.0
+ # Constrast parameter
+ self.params["contrast"] = 1.0
+
+ def create(self):
+ """
+ Create an instance of the shape
+ @return: instance of the shape
+ """
+ self.shapeObject = geoshapespy.new_sphere(\
+ self.params["radius"])
+
+ ShapeDescriptor.create(self)
+ return self.shapeObject
+
+class CylinderDescriptor(ShapeDescriptor):
+ """
+ Descriptor for a cylinder
+ Orientation: Default cylinder is along Y
+
+ Parameters:
+ - Length [default = 40 A]
+ - Radius [default = 10 A]
+ - Contrast [default = 1 A-2]
+ """
+ def __init__(self):
+ """
+ Initialization
+ """
+ ShapeDescriptor.__init__(self)
+ # Default parameters
+ self.params["type"] = "cylinder"
+ # Length of the cylinder
+ self.params["length"] = 40.0
+ # Radius of the cylinder
+ self.params["radius"] = 10.0
+ # Constrast parameter
+ self.params["contrast"] = 1.0
+
+ def create(self):
+ """
+ Create an instance of the shape
+ @return: instance of the shape
+ """
+ self.shapeObject = geoshapespy.new_cylinder(\
+ self.params["radius"], self.params["length"])
+
+ ShapeDescriptor.create(self)
+ return self.shapeObject
+
+
+class EllipsoidDescriptor(ShapeDescriptor):
+ """
+ Descriptor for an ellipsoid
+
+ Parameters:
+ - Radius_x along the x-axis [default = 30 A]
+ - Radius_y along the y-axis [default = 20 A]
+ - Radius_z along the z-axis [default = 10 A]
+ - contrast [default = 1 A-2]
+ """
+ def __init__(self):
+ """
+ Initialization
+ """
+ ShapeDescriptor.__init__(self)
+ # Default parameters
+ self.params["type"] = "ellipsoid"
+ self.params["radius_x"] = 30.0
+ self.params["radius_y"] = 20.0
+ self.params["radius_z"] = 10.0
+ self.params["contrast"] = 1.0
+
+ def create(self):
+ """
+ Create an instance of the shape
+ @return: instance of the shape
+ """
+ self.shapeObject = geoshapespy.new_ellipsoid(\
+ self.params["radius_x"], self.params["radius_y"],
+ self.params["radius_z"])
+
+ ShapeDescriptor.create(self)
+ return self.shapeObject
+
+class HelixDescriptor(ShapeDescriptor):
+ """
+ Descriptor for an helix
+
+ Parameters:
+ -radius_helix: the radius of the helix [default = 10 A]
+ -radius_tube: radius of the "tube" that forms the helix [default = 3 A]
+ -pitch: distance between two consecutive turns of the helix [default = 34 A]
+ -turns: number of turns of the helix [default = 3]
+ -contrast: contrast parameter [default = 1 A-2]
+ """
+ def __init__(self):
+ """
+ Initialization
+ """
+ ShapeDescriptor.__init__(self)
+ # Default parameters
+ self.params["type"] = "singlehelix"
+ self.params["radius_helix"] = 10.0
+ self.params["radius_tube"] = 3.0
+ self.params["pitch"] = 34.0
+ self.params["turns"] = 3.0
+ self.params["contrast"] = 1.0
+
+ def create(self):
+ """
+ Create an instance of the shape
+ @return: instance of the shape
+ """
+ self.shapeObject = geoshapespy.new_singlehelix(\
+ self.params["radius_helix"], self.params["radius_tube"],
+ self.params["pitch"], self.params["turns"])
+
+ ShapeDescriptor.create(self)
+ return self.shapeObject
+
+class PDBDescriptor(ShapeDescriptor):
+ """
+ Descriptor for a PDB set of points
+
+ Parameter:
+ - file = name of the PDB file
+ """
+ def __init__(self, filename):
+ """
+ Initialization
+ @param filename: name of the PDB file to load
+ """
+ ShapeDescriptor.__init__(self)
+ # Default parameters
+ self.params["type"] = "pdb"
+ self.params["file"] = filename
+ self.params['is_lores'] = False
+
+ def create(self):
+ """
+ Create an instance of the shape
+ @return: instance of the shape
+ """
+ self.shapeObject = pointsmodelpy.new_pdbmodel()
+ pointsmodelpy.pdbmodel_add(self.shapeObject, self.params['file'])
+
+ #ShapeDescriptor.create(self)
+ return self.shapeObject
+
+# Define a dictionary for the shape until we find
+# a better way to create them
+shape_dict = {'sphere':SphereDescriptor,
+ 'cylinder':CylinderDescriptor,
+ 'ellipsoid':EllipsoidDescriptor,
+ 'singlehelix':HelixDescriptor}
+
+class VolumeCanvas(BaseComponent):
+ """
+ Class representing an empty space volume to add
+ geometrical object to.
+
+ For 1D I(q) simulation, getPr() is called internally for the
+ first call to getIq().
+
+ """
+
+ def __init__(self):
+ """
+ Initialization
+ """
+ BaseComponent.__init__(self)
+
+ ## Maximum value of q reachable
+ self.params['q_max'] = 0.1
+ self.params['lores_density'] = 0.1
+ self.params['scale'] = 1.0
+ self.params['background'] = 0.0
+
+ self.lores_model = pointsmodelpy.new_loresmodel(self.params['lores_density'])
+ self.complex_model = pointsmodelpy.new_complexmodel()
+ self.shapes = {}
+ self.shapecount = 0
+ self.points = None
+ self.npts = 0
+ self.hasPr = False
+
+ def _model_changed(self):
+ """
+ Reset internal data members to reflect the fact that the
+ real-space model has changed
+ """
+ self.hasPr = False
+ self.points = None
+
+ def addObject(self, shapeDesc, id=None):
+ """
+ Adds a real-space object to the canvas.
+
+ @param shapeDesc: object to add to the canvas [ShapeDescriptor]
+ @param id: string handle for the object [string] [optional]
+ @return: string handle for the object
+ """
+ # If the handle is not provided, create one
+ if id is None:
+ id = shapeDesc.params["type"]+str(self.shapecount)
+
+ # Self the order number
+ shapeDesc.params['order'] = self.shapecount
+ # Store the shape in a dictionary entry associated
+ # with the handle
+ self.shapes[id] = shapeDesc
+ self.shapecount += 1
+
+ # model changed, need to recalculate P(r)
+ self._model_changed()
+
+ return id
+
+
+ def add(self, shape, id=None):
+ """
+ The intend of this method is to eventually be able to use it
+ as a factory for the canvas and unify the simulation with the
+ analytical solutions. For instance, if one adds a cylinder and
+ it is the only shape on the canvas, the analytical solution
+ could be called. If multiple shapes are involved, then
+ simulation has to be performed.
+
+ This function is deprecated, use addObject().
+
+ @param shape: name of the object to add to the canvas [string]
+ @param id: string handle for the object [string] [optional]
+ @return: string handle for the object
+ """
+ # If the handle is not provided, create one
+ if id is None:
+ id = "shape"+str(self.shapecount)
+
+ # shapeDesc = ShapeDescriptor(shape.lower())
+ if shape.lower() in shape_dict:
+ shapeDesc = shape_dict[shape.lower()]()
+ elif os.path.isfile(shape):
+ # A valid filename was supplier, create a PDB object
+ shapeDesc = PDBDescriptor(shape)
+ else:
+ raise ValueError("VolumeCanvas.add: Unknown shape %s" % shape)
+
+ return self.addObject(shapeDesc, id)
+
+ def delete(self, id):
+ """
+ Delete a shape. The ID for the shape is required.
+ @param id: string handle for the object [string] [optional]
+ """
+
+ if id in self.shapes:
+ del self.shapes[id]
+ else:
+ raise KeyError("VolumeCanvas.delete: could not find shape ID")
+
+ # model changed, need to recalculate P(r)
+ self._model_changed()
+
+
+ def setParam(self, name, value):
+ """
+ Function to set the value of a parameter.
+ Both VolumeCanvas parameters and shape parameters
+ are accessible.
+
+ Note: if shape parameters are accessed directly
+ from outside VolumeCanvas. The getPr method
+ should be called before evaluating I(q).
+
+ TODO: implemented a check method to protect
+ against that.
+
+ @param name: name of the parameter to change
+ @param value: value to give the parameter
+ """
+
+ # Lowercase for case insensitivity
+ name = name.lower()
+
+ # Look for shape access
+ toks = name.split('.')
+
+ # If a shape identifier was given, look the shape up
+ # in the dictionary
+ if len(toks):
+ if toks[0] in self.shapes:
+ # The shape was found, now look for the parameter
+ if toks[1] in self.shapes[toks[0]].params:
+ # The parameter was found, now change it
+ self.shapes[toks[0]].params[toks[1]] = value
+ self._model_changed()
+ else:
+ raise ValueError("Could not find parameter %s" % name)
+ else:
+ raise ValueError("Could not find shape %s" % toks[0])
+
+ else:
+ # If we are not accessing the parameters of a
+ # shape, see if the parameter is part of this object
+ BaseComponent.setParam(self, name, value)
+ self._model_changed()
+
+ def getParam(self, name):
+ """
+ @param name: name of the parameter to change
+ """
+ #TODO: clean this up
+
+ # Lowercase for case insensitivity
+ name = name.lower()
+
+ # Look for sub-model access
+ toks = name.split('.')
+ if len(toks) == 1:
+ try:
+ value = self.params[toks[0]]
+ except KeyError:
+ raise ValueError("VolumeCanvas.getParam: Could not find"
+ " %s" % name)
+ if isinstance(value, ShapeDescriptor):
+ raise ValueError("VolumeCanvas.getParam: Cannot get parameter"
+ " value.")
+ else:
+ return value
+
+ elif len(toks) == 2:
+ try:
+ shapeinstance = self.shapes[toks[0]]
+ except KeyError:
+ raise ValueError("VolumeCanvas.getParam: Could not find "
+ "%s" % name)
+
+ if not toks[1] in shapeinstance.params:
+ raise ValueError("VolumeCanvas.getParam: Could not find "
+ "%s" % name)
+
+ return shapeinstance.params[toks[1]]
+
+ else:
+ raise ValueError("VolumeCanvas.getParam: Could not find %s" % name)
+
+ def getParamList(self, shapeid=None):
+ """
+ return a full list of all available parameters from
+ self.params.keys(). If a key in self.params is a instance
+ of ShapeDescriptor, extend the return list to:
+ [param1,param2,shapeid.param1,shapeid.param2.......]
+
+ If shapeid is provided, return the list of parameters that
+ belongs to that shape id only : [shapeid.param1, shapeid.param2...]
+ """
+
+ param_list = []
+ if shapeid is None:
+ for key1 in self.params:
+ #value1 = self.params[key1]
+ param_list.append(key1)
+ for key2 in self.shapes:
+ value2 = self.shapes[key2]
+ header = key2 + '.'
+ for key3 in value2.params:
+ fullname = header + key3
+ param_list.append(fullname)
+
+ else:
+ if not shapeid in self.shapes:
+ raise ValueError("VolumeCanvas: getParamList: Could not find "
+ "%s" % shapeid)
+
+ header = shapeid + '.'
+ param_list = [header + param for param in self.shapes[shapeid].params]
+ return param_list
+
+ def getShapeList(self):
+ """
+ Return a list of the shapes
+ """
+ return self.shapes.keys()
+
+ def _addSingleShape(self, shapeDesc):
+ """
+ create shapeobject based on shapeDesc
+ @param shapeDesc: shape description
+ """
+ # Create the object model
+ shapeDesc.create()
+
+ if shapeDesc.params['is_lores']:
+ # Add the shape to the lores_model
+ pointsmodelpy.lores_add(self.lores_model,
+ shapeDesc.shapeObject,
+ shapeDesc.params['contrast'])
+
+ def _createVolumeFromList(self):
+ """
+ Create a new lores model with all the shapes in our internal list
+ Whenever we change a parameter of a shape, we have to re-create
+ the whole thing.
+
+ Items with higher 'order' number take precedence for regions
+ of space that are shared with other objects. Points in the
+ overlapping region belonging to objects with lower 'order'
+ will be ignored.
+
+ Items are added in decreasing 'order' number.
+ The item with the highest 'order' will be added *first*.
+ [That conventions is prescribed by the realSpaceModeling module]
+ """
+
+ # Create empty model
+ self.lores_model = \
+ pointsmodelpy.new_loresmodel(self.params['lores_density'])
+
+ # Create empty complex model
+ self.complex_model = pointsmodelpy.new_complexmodel()
+
+ # Order the object first
+ obj_list = []
+
+ for shape in self.shapes:
+ order = self.shapes[shape].params['order']
+ # find where to place it in the list
+ stored = False
+
+ for i in range(len(obj_list)):
+ if obj_list[i][0] > order:
+ obj_list.insert(i, [order, shape])
+ stored = True
+ break
+
+ if not stored:
+ obj_list.append([order, shape])
+
+ # Add each shape
+ len_list = len(obj_list)
+ for i in range(len_list-1, -1, -1):
+ shapedesc = self.shapes[obj_list[i][1]]
+ self._addSingleShape(shapedesc)
+
+ return 0
+
+ def getPr(self):
+ """
+ Calculate P(r) from the objects on the canvas.
+ This method should always be called after the shapes
+ on the VolumeCanvas have changed.
+
+ @return: calculation output flag
+ """
+ # To find a complete example of the correct call order:
+ # In LORES2, in actionclass.py, method CalculateAction._get_iq()
+
+ # If there are not shapes, do nothing
+ if len(self.shapes) == 0:
+ self._model_changed()
+ return 0
+
+ # generate space filling points from shape list
+ self._createVolumeFromList()
+
+ self.points = pointsmodelpy.new_point3dvec()
+
+ pointsmodelpy.complexmodel_add(self.complex_model,
+ self.lores_model, "LORES")
+ for shape in self.shapes:
+ if not self.shapes[shape].params['is_lores']:
+ pointsmodelpy.complexmodel_add(self.complex_model,
+ self.shapes[shape].shapeObject, "PDB")
+
+ #pointsmodelpy.get_lorespoints(self.lores_model, self.points)
+ self.npts = pointsmodelpy.get_complexpoints(self.complex_model, self.points)
+
+ # expecting the rmax is a positive float or 0. The maximum distance.
+ #rmax = pointsmodelpy.get_lores_pr(self.lores_model, self.points)
+
+ rmax = pointsmodelpy.get_complex_pr(self.complex_model, self.points)
+ self.hasPr = True
+
+ return rmax
+
+ def run(self, q=0):
+ """
+ Returns the value of I(q) for a given q-value
+ @param q: q-value ([float] or [list]) ([A-1] or [[A-1], [rad]])
+ @return: I(q) [float] [cm-1]
+ """
+ # Check for 1D q length
+ if q.__class__.__name__ == 'int' \
+ or q.__class__.__name__ == 'float':
+ return self.getIq(q)
+ # Check for 2D q-value
+ elif q.__class__.__name__ == 'list':
+ # Compute (Qx, Qy) from (Q, phi)
+ # Phi is in radian and Q-values are in A-1
+ qx = q[0]*math.cos(q[1])
+ qy = q[0]*math.sin(q[1])
+ return self.getIq2D(qx, qy)
+ # Through an exception if it's not a
+ # type we recognize
+ else:
+ raise ValueError("run(q): bad type for q")
+
+ def runXY(self, q=0):
+ """
+ Standard run command for the canvas.
+ Redirects to the correct method
+ according to the input type.
+ @param q: q-value [float] or [list] [A-1]
+ @return: I(q) [float] [cm-1]
+ """
+ # Check for 1D q length
+ if q.__class__.__name__ == 'int' \
+ or q.__class__.__name__ == 'float':
+ return self.getIq(q)
+ # Check for 2D q-value
+ elif q.__class__.__name__ == 'list':
+ return self.getIq2D(q[0], q[1])
+ # Through an exception if it's not a
+ # type we recognize
+ else:
+ raise ValueError("runXY(q): bad type for q")
+
+ def _create_modelObject(self):
+ """
+ Create the simulation model obejct from the list
+ of shapes.
+
+ This method needs to be called each time a parameter
+ changes because of the way the underlying library
+ was (badly) written. It is impossible to change a
+ parameter, or remove a shape without having to
+ refill the space points.
+
+ TODO: improve that.
+ """
+ # To find a complete example of the correct call order:
+ # In LORES2, in actionclass.py, method CalculateAction._get_iq()
+
+ # If there are not shapes, do nothing
+ if len(self.shapes) == 0:
+ self._model_changed()
+ return 0
+
+ # generate space filling points from shape list
+ self._createVolumeFromList()
+
+ self.points = pointsmodelpy.new_point3dvec()
+
+ pointsmodelpy.complexmodel_add(self.complex_model,
+ self.lores_model, "LORES")
+ for shape in self.shapes:
+ if not self.shapes[shape].params['is_lores']:
+ pointsmodelpy.complexmodel_add(self.complex_model,
+ self.shapes[shape].shapeObject, "PDB")
+
+ #pointsmodelpy.get_lorespoints(self.lores_model, self.points)
+ self.npts = pointsmodelpy.get_complexpoints(self.complex_model, self.points)
+
+
+ def getIq2D(self, qx, qy):
+ """
+ Returns simulate I(q) for given q_x and q_y values.
+ @param qx: q_x [A-1]
+ @param qy: q_y [A-1]
+ @return: I(q) [cm-1]
+ """
+
+ # If this is the first simulation call, we need to generate the
+ # space points
+ if self.points is None:
+ self._create_modelObject()
+
+ # Protect against empty model
+ if self.points is None:
+ return 0
+
+ # Evalute I(q)
+ norm = 1.0e8/self.params['lores_density']*self.params['scale']
+ return norm*pointsmodelpy.get_complex_iq_2D(self.complex_model, self.points, qx, qy)\
+ + self.params['background']
+
+ def write_pr(self, filename):
+ """
+ Write P(r) to an output file
+ @param filename: file name for P(r) output
+ """
+ if not self.hasPr:
+ self.getPr()
+
+ pointsmodelpy.outputPR(self.complex_model, filename)
+
+ def getPrData(self):
+ """
+ Write P(r) to an output file
+ @param filename: file name for P(r) output
+ """
+ if not self.hasPr:
+ self.getPr()
+
+ return pointsmodelpy.get_pr(self.complex_model)
+
+ def getIq(self, q):
+ """
+ Returns the value of I(q) for a given q-value
+
+ This method should remain internal to the class
+ and the run() method should be used instead.
+
+ @param q: q-value [float]
+ @return: I(q) [float]
+ """
+
+ if not self.hasPr:
+ self.getPr()
+
+ # By dividing by the density instead of the actuall V/N,
+ # we have an uncertainty of +-1 on N because the number
+ # of points chosen for the simulation is int(density*volume).
+ # Propagation of error gives:
+ # delta(1/density^2) = 2*(1/density^2)/N
+ # where N is stored in self.npts
+
+ norm = 1.0e8/self.params['lores_density']*self.params['scale']
+ #return norm*pointsmodelpy.get_lores_i(self.lores_model, q)
+ return norm*pointsmodelpy.get_complex_i(self.complex_model, q)\
+ + self.params['background']
+
+ def getError(self, q):
+ """
+ Returns the error of I(q) for a given q-value
+ @param q: q-value [float]
+ @return: I(q) [float]
+ """
+
+ if not self.hasPr:
+ self.getPr()
+
+ # By dividing by the density instead of the actual V/N,
+ # we have an uncertainty of +-1 on N because the number
+ # of points chosen for the simulation is int(density*volume).
+ # Propagation of error gives:
+ # delta(1/density^2) = 2*(1/density^2)/N
+ # where N is stored in self.npts
+
+ norm = 1.0e8/self.params['lores_density']*self.params['scale']
+ #return norm*pointsmodelpy.get_lores_i(self.lores_model, q)
+ return norm*pointsmodelpy.get_complex_i_error(self.complex_model, q)\
+ + self.params['background']
+
+ def getIqError(self, q):
+ """
+ Return the simulated value along with its estimated
+ error for a given q-value
+
+ Propagation of errors is used to evaluate the
+ uncertainty.
+
+ @param q: q-value [float]
+ @return: mean, error [float, float]
+ """
+ val = self.getIq(q)
+ # Simulation error (statistical)
+ err = self.getError(q)
+ # Error on V/N
+ simerr = 2*val/self.npts
+ return val, err+simerr
+
+ def getIq2DError(self, qx, qy):
+ """
+ Return the simulated value along with its estimated
+ error for a given q-value
+
+ Propagation of errors is used to evaluate the
+ uncertainty.
+
+ @param qx: qx-value [float]
+ @param qy: qy-value [float]
+ @return: mean, error [float, float]
+ """
+ self._create_modelObject()
+
+ norm = 1.0e8/self.params['lores_density']*self.params['scale']
+ val = norm*pointsmodelpy.get_complex_iq_2D(self.complex_model, self.points, qx, qy)\
+ + self.params['background']
+
+ # Simulation error (statistical)
+ norm = 1.0e8/self.params['lores_density']*self.params['scale'] \
+ * math.pow(self.npts/self.params['lores_density'], 1.0/3.0)/self.npts
+ err = norm*pointsmodelpy.get_complex_iq_2D_err(self.complex_model, self.points, qx, qy)
+ # Error on V/N
+ simerr = 2*val/self.npts
+
+ # The error used for the position is over-simplified.
+ # The actual error was empirically found to be about
+ # an order of magnitude larger.
+ return val, 10.0*err+simerr
diff --git a/src/sas/sascalc/realspace/__init__.py b/src/sas/sascalc/realspace/__init__.py
index bc73410..4ed4991 100644
--- a/src/sas/sascalc/realspace/__init__.py
+++ b/src/sas/sascalc/realspace/__init__.py
@@ -1,80 +1,79 @@
-"""
- Real-Space Modeling for SAS
-"""
-## \mainpage Real-Space Modeling for SAS
-#
-# \section intro_sec Introduction
-# This module provides SAS scattering intensity simulation
-# based on real-space modeling.
-#
-# Documentation can be found here:
-# http://danse.us/trac/sas/wiki/RealSpaceModeling
-#
-# \section install_sec Installation
-#
-# \subsection obtain Obtaining the Code
-#
-# The code is available here:
-# \verbatim
-#$ svn co svn://danse.us/sas/realSpaceModeling
-#$ svn co svn://danse.us/sas/RealSpaceTopLayer
-# \endverbatim
-#
-# \subsection depends External Dependencies
-# None
-#
-# \subsection build Building the code
-# The standard python package can be built with distutils.
-# From the realSpaceModeling directory:
-# \verbatim
-#$ python setup.py install
-# \endverbatim
-#
-# From the RealSpaceTopLayer/src directory:
-# \verbatim
-#$ python setup.py install
-# \endverbatim
-#
-# \section overview_sec Package Overview
-#
-# \subsection class Class Diagram:
-# \image html real-space-class-diagram.png
-#
-# \subsection behav Behavior Enumeration:
-# \image html enum.gif
-#
-# \subsection Tutorial
-# To create an empty canvas:
-# \verbatim
-#import sas.realspace.VolumeCanvas as VolumeCanvas
-# canvas = VolumeCanvas.VolumeCanvas()
-# \endverbatim
-#
-# To set the simulation point density:
-# \verbatim
-# canvas.setParam('lores_density', 0.01)
-# \endverbatim
-#
-# To add an object:
-# \verbatim
-# sphare = VolumeCanvas.SphereDescriptor()
-# handle = canvas.addObject(sphere)
-# canvas.setParam('%s.radius' % handle, 15.0)
-# \endverbatim
-#
-# To evaluate the scattering intensity at a given q:
-# \verbatim
-# output, error = canvas.getIqError(q=0.1)
-# output, error = canvas.getIq2DError(qx=0.1, qy=0.1)
-# \endverbatim
-#
-# To get the value of a parameter:
-# \verbatim
-# canvas.getParam('scale')
-# \endverbatim
-#
-# Examples are available as unit tests under sas.realspace.test.
-#
-# \section help_sec Contact Info
-# Code and Documentation by Jing Zhou as part of the DANSE project.
-
+"""
+ Real-Space Modeling for SAS
+"""
+## \mainpage Real-Space Modeling for SAS
+#
+# \section intro_sec Introduction
+# This module provides SAS scattering intensity simulation
+# based on real-space modeling.
+#
+# Documentation can be found here:
+# http://danse.us/trac/sas/wiki/RealSpaceModeling
+#
+# \section install_sec Installation
+#
+# \subsection obtain Obtaining the Code
+#
+# The code is available here:
+# \verbatim
+#$ svn co svn://danse.us/sas/realSpaceModeling
+#$ svn co svn://danse.us/sas/RealSpaceTopLayer
+# \endverbatim
+#
+# \subsection depends External Dependencies
+# None
+#
+# \subsection build Building the code
+# The standard python package can be built with distutils.
+# From the realSpaceModeling directory:
+# \verbatim
+#$ python setup.py install
+# \endverbatim
+#
+# From the RealSpaceTopLayer/src directory:
+# \verbatim
+#$ python setup.py install
+# \endverbatim
+#
+# \section overview_sec Package Overview
+#
+# \subsection class Class Diagram:
+# \image html real-space-class-diagram.png
+#
+# \subsection behav Behavior Enumeration:
+# \image html enum.png
+#
+# \subsection Tutorial
+# To create an empty canvas:
+# \verbatim
+#import sas.realspace.VolumeCanvas as VolumeCanvas
+# canvas = VolumeCanvas.VolumeCanvas()
+# \endverbatim
+#
+# To set the simulation point density:
+# \verbatim
+# canvas.setParam('lores_density', 0.01)
+# \endverbatim
+#
+# To add an object:
+# \verbatim
+# sphare = VolumeCanvas.SphereDescriptor()
+# handle = canvas.addObject(sphere)
+# canvas.setParam('%s.radius' % handle, 15.0)
+# \endverbatim
+#
+# To evaluate the scattering intensity at a given q:
+# \verbatim
+# output, error = canvas.getIqError(q=0.1)
+# output, error = canvas.getIq2DError(qx=0.1, qy=0.1)
+# \endverbatim
+#
+# To get the value of a parameter:
+# \verbatim
+# canvas.getParam('scale')
+# \endverbatim
+#
+# Examples are available as unit tests under sas.realspace.test.
+#
+# \section help_sec Contact Info
+# Code and Documentation by Jing Zhou as part of the DANSE project.
diff --git a/src/sas/sascalc/simulation/analmodelpy/tests/signon.py b/src/sas/sascalc/simulation/analmodelpy/tests/signon.py
index 175474c..d16860e 100644
--- a/src/sas/sascalc/simulation/analmodelpy/tests/signon.py
+++ b/src/sas/sascalc/simulation/analmodelpy/tests/signon.py
@@ -16,18 +16,18 @@ if __name__ == "__main__":
import analmodelpy
from analmodelpy import analmodelpy as analmodelpymodule
- print "copyright information:"
- print " ", analmodelpy.copyright()
- print " ", analmodelpymodule.copyright()
+ print("copyright information:")
+ print(" ", analmodelpy.copyright())
+ print(" ", analmodelpymodule.copyright())
- print
- print "module information:"
- print " file:", analmodelpymodule.__file__
- print " doc:", analmodelpymodule.__doc__
- print " contents:", dir(analmodelpymodule)
+ print()
+ print("module information:")
+ print(" file:", analmodelpymodule.__file__)
+ print(" doc:", analmodelpymodule.__doc__)
+ print(" contents:", dir(analmodelpymodule))
- print
- print analmodelpymodule.hello()
+ print()
+ print(analmodelpymodule.hello())
# version
__id__ = "$Id$"
diff --git a/src/sas/sascalc/simulation/analmodelpy/tests/testanal_model.py b/src/sas/sascalc/simulation/analmodelpy/tests/testanal_model.py
index 7382cc0..fe451dd 100644
--- a/src/sas/sascalc/simulation/analmodelpy/tests/testanal_model.py
+++ b/src/sas/sascalc/simulation/analmodelpy/tests/testanal_model.py
@@ -10,6 +10,8 @@
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
+from __future__ import print_function
+
if __name__ == "__main__":
@@ -17,14 +19,14 @@ if __name__ == "__main__":
from SASsimulation import iqPy
from SASsimulation import geoshapespy
- print "copyright information:"
- print " ", analmodelpymodule.copyright()
+ print("copyright information:")
+ print(" ", analmodelpymodule.copyright())
- print
- print "module information:"
- print " file:", analmodelpymodule.__file__
- print " doc:", analmodelpymodule.__doc__
- print " contents:", dir(analmodelpymodule)
+ print()
+ print("module information:")
+ print(" file:", analmodelpymodule.__file__)
+ print(" doc:", analmodelpymodule.__doc__)
+ print(" contents:", dir(analmodelpymodule))
a = geoshapespy.new_sphere(1.0)
iq = iqPy.new_iq(10,0.001, 0.3)
diff --git a/src/sas/sascalc/simulation/geoshapespy/libgeoshapespy/minmax.h b/src/sas/sascalc/simulation/geoshapespy/libgeoshapespy/minmax.h
index 189d885..313e6a7 100644
--- a/src/sas/sascalc/simulation/geoshapespy/libgeoshapespy/minmax.h
+++ b/src/sas/sascalc/simulation/geoshapespy/libgeoshapespy/minmax.h
@@ -1,23 +1,23 @@
-#ifndef GUARD_minmax_H
-#define GUARD_minmax_H
-#ifdef _MSC_VER
-// needed to cope with bug in MS library:
-// it fails to define min/max
-
-template <class T> inline T max(const T& a, const T& b)
-{
-
- return (a > b) ? a : b;
-
-}
-
-template <class T> inline T min(const T& a, const T& b)
-{
-
- return (a < b) ? a : b;
-
-}
-
-#endif
-
+#ifndef GUARD_minmax_H
+#define GUARD_minmax_H
+#ifdef _MSC_VER
+// needed to cope with bug in MS library:
+// it fails to define min/max
+
+template <class T> inline T max(const T& a, const T& b)
+{
+
+ return (a > b) ? a : b;
+
+}
+
+template <class T> inline T min(const T& a, const T& b)
+{
+
+ return (a < b) ? a : b;
+
+}
+
+#endif
+
#endif
\ No newline at end of file
diff --git a/src/sas/sascalc/simulation/geoshapespy/tests/testshapes.py b/src/sas/sascalc/simulation/geoshapespy/tests/testshapes.py
index 08223f3..b255bfd 100644
--- a/src/sas/sascalc/simulation/geoshapespy/tests/testshapes.py
+++ b/src/sas/sascalc/simulation/geoshapespy/tests/testshapes.py
@@ -10,16 +10,18 @@
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
+from __future__ import print_function
+
if __name__ == "__main__":
from SASsimulation import geoshapespy
- print
- print "module information:"
- print " file:", geoshapespy.__file__
- print " doc:", geoshapespy.__doc__
- print " contents:", dir(geoshapespy)
+ print()
+ print("module information:")
+ print(" file:", geoshapespy.__file__)
+ print(" doc:", geoshapespy.__doc__)
+ print(" contents:", dir(geoshapespy))
sp = geoshapespy.new_sphere(10)
# geoshapespy.set_orientation(sp,10,20,10)
diff --git a/src/sas/sascalc/simulation/iqPy/tests/signon.py b/src/sas/sascalc/simulation/iqPy/tests/signon.py
index c18e3c0..1054143 100644
--- a/src/sas/sascalc/simulation/iqPy/tests/signon.py
+++ b/src/sas/sascalc/simulation/iqPy/tests/signon.py
@@ -10,23 +10,25 @@
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
+from __future__ import print_function
+
if __name__ == "__main__":
import iqPy
from iqPy import iqPy as iqPymodule
- print "copyright information:"
- print " ", iqPy.copyright()
- print " ", iqPymodule.copyright()
+ print("copyright information:")
+ print(" ", iqPy.copyright())
+ print(" ", iqPymodule.copyright())
- print
- print "module information:"
- print " file:", iqPymodule.__file__
- print " doc:", iqPymodule.__doc__
- print " contents:", dir(iqPymodule)
+ print()
+ print("module information:")
+ print(" file:", iqPymodule.__file__)
+ print(" doc:", iqPymodule.__doc__)
+ print(" contents:", dir(iqPymodule))
- print
+ print()
# version
__id__ = "$Id$"
diff --git a/src/sas/sascalc/simulation/iqPy/tests/testiq.py b/src/sas/sascalc/simulation/iqPy/tests/testiq.py
index 5b2b2a8..f085abe 100644
--- a/src/sas/sascalc/simulation/iqPy/tests/testiq.py
+++ b/src/sas/sascalc/simulation/iqPy/tests/testiq.py
@@ -16,7 +16,7 @@ if __name__ == "__main__":
from SASsimulation import iqPy
iqPy.new_iq(10,0.01,0.4)
- print "pass."
+ print("pass.")
# version
__id__ = "$Id$"
diff --git a/src/sas/sascalc/simulation/pointsmodelpy/tests/signon.py b/src/sas/sascalc/simulation/pointsmodelpy/tests/signon.py
index acc0702..332eb94 100644
--- a/src/sas/sascalc/simulation/pointsmodelpy/tests/signon.py
+++ b/src/sas/sascalc/simulation/pointsmodelpy/tests/signon.py
@@ -10,24 +10,26 @@
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
+from __future__ import print_function
+
if __name__ == "__main__":
import pointsmodelpy
from pointsmodelpy import pointsmodelpy as pointsmodelpymodule
- print "copyright information:"
- print " ", pointsmodelpy.copyright()
- print " ", pointsmodelpymodule.copyright()
+ print("copyright information:")
+ print(" ", pointsmodelpy.copyright())
+ print(" ", pointsmodelpymodule.copyright())
- print
- print "module information:"
- print " file:", pointsmodelpymodule.__file__
- print " doc:", pointsmodelpymodule.__doc__
- print " contents:", dir(pointsmodelpymodule)
+ print()
+ print("module information:")
+ print(" file:", pointsmodelpymodule.__file__)
+ print(" doc:", pointsmodelpymodule.__doc__)
+ print(" contents:", dir(pointsmodelpymodule))
- print
- print pointsmodelpymodule.hello()
+ print()
+ print(pointsmodelpymodule.hello())
# version
__id__ = "$Id$"
diff --git a/src/sas/sascalc/simulation/pointsmodelpy/tests/test2dui.py b/src/sas/sascalc/simulation/pointsmodelpy/tests/test2dui.py
index 4e80f6c..6d076d7 100644
--- a/src/sas/sascalc/simulation/pointsmodelpy/tests/test2dui.py
+++ b/src/sas/sascalc/simulation/pointsmodelpy/tests/test2dui.py
@@ -1,120 +1,121 @@
-#!/usr/bin/env python
-"""
-Demonstration of drawing a 2D image plot using the "hot" colormap
-"""
-
-#--------------------------------------------------------------------------------
-# Imports:
-#--------------------------------------------------------------------------------
-
-import wx
-
-from enthought.traits import Any, Instance
-from enthought.enable.wx import Window
-from enthought.pyface import ApplicationWindow, GUI
-from enthought.util.numerix import pi, concatenate, array, zeros, ones, \
- arange, resize, ravel
-from enthought.util.numerix import Float as NumericFloat
-from math import sqrt, sin
-
-from enthought.chaco.plot_component import PlotComponent
-from enthought.chaco.plot_axis import PlotAxis
-from enthought.chaco.plot_canvas import PlotCanvas
-from enthought.chaco.plot_group import PlotGroup
-from enthought.chaco.image_plot_value import ImageData, CmapImagePlotValue
-from enthought.chaco.colormap import LinearColormap
-from enthought.chaco.colormap_legend import ColormapLegend
-from enthought.chaco.default_colormaps import hot, gray
-from enthought.chaco.demo.demo_base import PlotApplicationWindow
-
-
-class ImagePlotApplicationWindow( PlotApplicationWindow ):
-
- ###########################################################################
- # PlotApplicationWindow interface.
- ###########################################################################
-
- def _create_plot( self ):
- """ Create the plot to be displayed. """
-
- # Create the image data and the index values
- #value_grid = zeros((100,100), NumericFloat)
- from testlores2d import get2d_2
- value_grid = get2d_2()
- #self._compute_function(value_grid)
- index_vals = (arange(value_grid.shape[0]), arange(value_grid.shape[1]))
-
- data = ImageData(value_grid, index_vals)
- print value_grid, index_vals
-
- # Create the index axes
- xaxis = PlotAxis(tick_visible=False, grid_visible=False)
- # bound_low = index_vals[0][0], bound_high = index_vals[0][-1])
- yaxis = PlotAxis(tick_visible=False, grid_visible=False)
- #bound_low = index_vals[1][0], bound_high = index_vals[1][-1])
- xaxis.visible = False
- yaxis.visible = False
-
- # Create the value axis (i.e. colormap)
- cmap = hot(0,1)
-
- # Create the Image PlotValue
-# image = CmapImagePlotValue(data, cmap, axis_index = xaxis, axis = yaxis, type='image')
- image = CmapImagePlotValue(data, cmap,type='image')
- image.weight = 10
-
- cmap_legend = ColormapLegend(cmap, margin_width=31, margin_height=31)
- cmap_legend.weight = 0.4
-
- group = PlotGroup(cmap_legend, image, orientation='horizontal')
-
- return group
-
- ###########################################################################
- # Private interface.
- ###########################################################################
-
- def _compute_function(self, ary):
- "Fills in ary with the sin(r)/r function"
-
- width, height = ary.shape
- for i in range(width):
- for j in range(height):
- x = i - width / 2.0
- x = x / (width/2.0) * 15
- y = j - height / 2.0
- y = y / (height/2.0) * 15
-
- radius = sqrt(x*x + y*y)
- if radius == 0.0:
- ary[i,j] = 1
- else:
- ary[i,j] = sin(radius) / radius
-
- return
-
-def main():
-
- # Create the GUI (this does NOT start the GUI event loop).
- gui = GUI()
-
- # Screen size:
- screen_width = gui.system_metrics.screen_width or 1024
- screen_height = gui.system_metrics.screen_height or 768
-
- # Create and open the main window.
- window = ImagePlotApplicationWindow( title = "Plot" )
- #window.plot_item = object
- window.size = ( 2 * screen_width / 3, 2 * screen_height / 3 )
- window.open()
-
- # Start the GUI event loop.
- gui.start_event_loop()
-
-
-#===============================================================================
-# Program start-up:
-#===============================================================================
-
-if __name__ == '__main__':
- main()
+#!/usr/bin/env python
+"""
+Demonstration of drawing a 2D image plot using the "hot" colormap
+"""
+
+#--------------------------------------------------------------------------------
+# Imports:
+#--------------------------------------------------------------------------------
+from __future__ import print_function
+
+import wx
+
+from enthought.traits import Any, Instance
+from enthought.enable.wx import Window
+from enthought.pyface import ApplicationWindow, GUI
+from enthought.util.numerix import pi, concatenate, array, zeros, ones, \
+ arange, resize, ravel
+from enthought.util.numerix import Float as NumericFloat
+from math import sqrt, sin
+
+from enthought.chaco.plot_component import PlotComponent
+from enthought.chaco.plot_axis import PlotAxis
+from enthought.chaco.plot_canvas import PlotCanvas
+from enthought.chaco.plot_group import PlotGroup
+from enthought.chaco.image_plot_value import ImageData, CmapImagePlotValue
+from enthought.chaco.colormap import LinearColormap
+from enthought.chaco.colormap_legend import ColormapLegend
+from enthought.chaco.default_colormaps import hot, gray
+from enthought.chaco.demo.demo_base import PlotApplicationWindow
+
+
+class ImagePlotApplicationWindow( PlotApplicationWindow ):
+
+ ###########################################################################
+ # PlotApplicationWindow interface.
+ ###########################################################################
+
+ def _create_plot( self ):
+ """ Create the plot to be displayed. """
+
+ # Create the image data and the index values
+ #value_grid = zeros((100,100), NumericFloat)
+ from testlores2d import get2d_2
+ value_grid = get2d_2()
+ #self._compute_function(value_grid)
+ index_vals = (arange(value_grid.shape[0]), arange(value_grid.shape[1]))
+
+ data = ImageData(value_grid, index_vals)
+ print(value_grid, index_vals)
+
+ # Create the index axes
+ xaxis = PlotAxis(tick_visible=False, grid_visible=False)
+ # bound_low = index_vals[0][0], bound_high = index_vals[0][-1])
+ yaxis = PlotAxis(tick_visible=False, grid_visible=False)
+ #bound_low = index_vals[1][0], bound_high = index_vals[1][-1])
+ xaxis.visible = False
+ yaxis.visible = False
+
+ # Create the value axis (i.e. colormap)
+ cmap = hot(0,1)
+
+ # Create the Image PlotValue
+# image = CmapImagePlotValue(data, cmap, axis_index = xaxis, axis = yaxis, type='image')
+ image = CmapImagePlotValue(data, cmap,type='image')
+ image.weight = 10
+
+ cmap_legend = ColormapLegend(cmap, margin_width=31, margin_height=31)
+ cmap_legend.weight = 0.4
+
+ group = PlotGroup(cmap_legend, image, orientation='horizontal')
+
+ return group
+
+ ###########################################################################
+ # Private interface.
+ ###########################################################################
+
+ def _compute_function(self, ary):
+ "Fills in ary with the sin(r)/r function"
+
+ width, height = ary.shape
+ for i in range(width):
+ for j in range(height):
+ x = i - width / 2.0
+ x = x / (width/2.0) * 15
+ y = j - height / 2.0
+ y = y / (height/2.0) * 15
+
+ radius = sqrt(x*x + y*y)
+ if radius == 0.0:
+ ary[i,j] = 1
+ else:
+ ary[i,j] = sin(radius) / radius
+
+ return
+
+def main():
+
+ # Create the GUI (this does NOT start the GUI event loop).
+ gui = GUI()
+
+ # Screen size:
+ screen_width = gui.system_metrics.screen_width or 1024
+ screen_height = gui.system_metrics.screen_height or 768
+
+ # Create and open the main window.
+ window = ImagePlotApplicationWindow( title = "Plot" )
+ #window.plot_item = object
+ window.size = ( 2 * screen_width / 3, 2 * screen_height / 3 )
+ window.open()
+
+ # Start the GUI event loop.
+ gui.start_event_loop()
+
+
+#===============================================================================
+# Program start-up:
+#===============================================================================
+
+if __name__ == '__main__':
+ main()
diff --git a/src/sas/sascalc/simulation/pointsmodelpy/tests/testcomplexmodel.py b/src/sas/sascalc/simulation/pointsmodelpy/tests/testcomplexmodel.py
index dce6072..93fb80e 100644
--- a/src/sas/sascalc/simulation/pointsmodelpy/tests/testcomplexmodel.py
+++ b/src/sas/sascalc/simulation/pointsmodelpy/tests/testcomplexmodel.py
@@ -1,119 +1,122 @@
-from sasModeling.pointsmodelpy import pointsmodelpy
-from sasModeling.iqPy import iqPy
-from sasModeling.geoshapespy import geoshapespy
-
-#First testing: a normal case, a lores model holds a sphere
-#and a pdbmodel holds one pdb file. and merged into a complex
-#model, then perform calculation
-def test_complex():
- p = pointsmodelpy.new_pdbmodel()
- pointsmodelpy.pdbmodel_add(p,"ff0.pdb")
-
- vp = pointsmodelpy.new_point3dvec()
- pointsmodelpy.get_pdbpoints(p,vp);
-
- pointsmodelpy.get_pdb_pr(p,vp)
- pointsmodelpy.save_pdb_pr(p,"testcomplex.pr")
-
- iq = iqPy.new_iq(100,0.001, 0.3)
- pointsmodelpy.get_pdb_iq(p,iq)
-
- iqPy.OutputIQ(iq,"testcomplex.iq")
-
- a = geoshapespy.new_sphere(10)
- lm = pointsmodelpy.new_loresmodel(0.1)
- pointsmodelpy.lores_add(lm,a,1.0)
-
- vpcomplex = pointsmodelpy.new_point3dvec();
- complex = pointsmodelpy.new_complexmodel()
- pointsmodelpy.complexmodel_add(complex,p,"PDB");
- pointsmodelpy.complexmodel_add(complex,lm,"LORES");
-
- pointsmodelpy.get_complexpoints(complex,vpcomplex);
- pointsmodelpy.get_complex_pr(complex,vpcomplex);
- pointsmodelpy.save_complex_pr(complex,"testcomplex1.pr");
-
- iqcomplex = iqPy.new_iq(100,0.001, 0.3)
- pointsmodelpy.get_complex_iq(complex,iqcomplex);
-
- iqPy.OutputIQ(iq,"testcomplex1.iq")
-
-#testing 2, insert one pdbmodel and one empty loresmodel
-def test_complex2():
- pdb = pointsmodelpy.new_pdbmodel()
- pointsmodelpy.pdbmodel_add(pdb,"ff0.pdb")
-
- lores = pointsmodelpy.new_loresmodel(0.1)
-
- complex = pointsmodelpy.new_complexmodel()
- pointsmodelpy.complexmodel_add(complex,pdb,"PDB");
- pointsmodelpy.complexmodel_add(complex,lores,"LORES")
-
- points = pointsmodelpy.new_point3dvec()
- pointsmodelpy.get_complexpoints(complex,points)
-
- pointsmodelpy.get_complex_pr(complex,points);
- pointsmodelpy.save_complex_pr(complex,"testcomplex2.pr")
-
- iqcomplex = iqPy.new_iq(100,0.001, 0.3)
- pointsmodelpy.get_complex_iq(complex,iqcomplex)
-
- iqPy.OutputIQ(iqcomplex,"testcomplex2.iq")
-
- print "p(r) is saved in testcomplex2.pr"
- print "I(Q) is saved in testcomplex2.iq"
- print "pass"
-
-#testing 3, insert one empty pdbmodel and one loresmodel
-def test_complex3():
- pdb = pointsmodelpy.new_pdbmodel()
-
- lores = pointsmodelpy.new_loresmodel(0.1)
- sph = geoshapespy.new_sphere(10)
- pointsmodelpy.lores_add(lores,sph,1.0)
-
- complex = pointsmodelpy.new_complexmodel()
- pointsmodelpy.complexmodel_add(complex,pdb,"PDB");
- pointsmodelpy.complexmodel_add(complex,lores,"LORES")
-
- points = pointsmodelpy.new_point3dvec()
- pointsmodelpy.get_complexpoints(complex,points)
-
- pointsmodelpy.get_complex_pr(complex,points);
- pointsmodelpy.save_complex_pr(complex,"testcomplex3.pr")
-
- iqcomplex = iqPy.new_iq(100,0.001, 0.3)
- pointsmodelpy.get_complex_iq(complex,iqcomplex)
-
- iqPy.OutputIQ(iqcomplex,"testcomplex3.iq")
-
- print "p(r) is saved in testcomplex3.pr"
- print "I(Q) is saved in testcomplex3.iq"
- print "pass"
-
-# Test 2D complex model
-def test_complex4():
-
-
- a = geoshapespy.new_sphere(10)
- lm = pointsmodelpy.new_loresmodel(0.1)
- pointsmodelpy.lores_add(lm,a,1.0)
-
- vpcomplex = pointsmodelpy.new_point3dvec();
- complex = pointsmodelpy.new_complexmodel()
- pointsmodelpy.complexmodel_add(complex,lm,"LORES");
-
- pointsmodelpy.get_complexpoints(complex,vpcomplex);
-
- print pointsmodelpy.get_complex_iq_2D(complex,vpcomplex,0.1,0.1);
- print pointsmodelpy.get_complex_iq_2D(complex,vpcomplex,0.01,0.1);
-
-
-if __name__ == "__main__":
- #print "test 1, adding one nonempty loresmodel and one nonempty pdbmodel to complex model"
- #test_complex()
- #print "test 2, adding a nonempty pdbmodel, and adding an empty loresmodel"
- #test_complex2()
- #print "test 3, adding an empty pdbmodel, and adding a nonempty loresmodel"
- #test_complex3()
- test_complex4()
+from __future__ import print_function
+
+from sasModeling.pointsmodelpy import pointsmodelpy
+from sasModeling.iqPy import iqPy
+from sasModeling.geoshapespy import geoshapespy
+
+
+#First testing: a normal case, a lores model holds a sphere
+#and a pdbmodel holds one pdb file. and merged into a complex
+#model, then perform calculation
+def test_complex():
+ p = pointsmodelpy.new_pdbmodel()
+ pointsmodelpy.pdbmodel_add(p,"ff0.pdb")
+
+ vp = pointsmodelpy.new_point3dvec()
+ pointsmodelpy.get_pdbpoints(p,vp);
+
+ pointsmodelpy.get_pdb_pr(p,vp)
+ pointsmodelpy.save_pdb_pr(p,"testcomplex.pr")
+
+ iq = iqPy.new_iq(100,0.001, 0.3)
+ pointsmodelpy.get_pdb_iq(p,iq)
+
+ iqPy.OutputIQ(iq,"testcomplex.iq")
+
+ a = geoshapespy.new_sphere(10)
+ lm = pointsmodelpy.new_loresmodel(0.1)
+ pointsmodelpy.lores_add(lm,a,1.0)
+
+ vpcomplex = pointsmodelpy.new_point3dvec();
+ complex = pointsmodelpy.new_complexmodel()
+ pointsmodelpy.complexmodel_add(complex,p,"PDB");
+ pointsmodelpy.complexmodel_add(complex,lm,"LORES");
+
+ pointsmodelpy.get_complexpoints(complex,vpcomplex);
+ pointsmodelpy.get_complex_pr(complex,vpcomplex);
+ pointsmodelpy.save_complex_pr(complex,"testcomplex1.pr");
+
+ iqcomplex = iqPy.new_iq(100,0.001, 0.3)
+ pointsmodelpy.get_complex_iq(complex,iqcomplex);
+
+ iqPy.OutputIQ(iq,"testcomplex1.iq")
+
+#testing 2, insert one pdbmodel and one empty loresmodel
+def test_complex2():
+ pdb = pointsmodelpy.new_pdbmodel()
+ pointsmodelpy.pdbmodel_add(pdb,"ff0.pdb")
+
+ lores = pointsmodelpy.new_loresmodel(0.1)
+
+ complex = pointsmodelpy.new_complexmodel()
+ pointsmodelpy.complexmodel_add(complex,pdb,"PDB");
+ pointsmodelpy.complexmodel_add(complex,lores,"LORES")
+
+ points = pointsmodelpy.new_point3dvec()
+ pointsmodelpy.get_complexpoints(complex,points)
+
+ pointsmodelpy.get_complex_pr(complex,points);
+ pointsmodelpy.save_complex_pr(complex,"testcomplex2.pr")
+
+ iqcomplex = iqPy.new_iq(100,0.001, 0.3)
+ pointsmodelpy.get_complex_iq(complex,iqcomplex)
+
+ iqPy.OutputIQ(iqcomplex,"testcomplex2.iq")
+
+ print("p(r) is saved in testcomplex2.pr")
+ print("I(Q) is saved in testcomplex2.iq")
+ print("pass")
+
+#testing 3, insert one empty pdbmodel and one loresmodel
+def test_complex3():
+ pdb = pointsmodelpy.new_pdbmodel()
+
+ lores = pointsmodelpy.new_loresmodel(0.1)
+ sph = geoshapespy.new_sphere(10)
+ pointsmodelpy.lores_add(lores,sph,1.0)
+
+ complex = pointsmodelpy.new_complexmodel()
+ pointsmodelpy.complexmodel_add(complex,pdb,"PDB");
+ pointsmodelpy.complexmodel_add(complex,lores,"LORES")
+
+ points = pointsmodelpy.new_point3dvec()
+ pointsmodelpy.get_complexpoints(complex,points)
+
+ pointsmodelpy.get_complex_pr(complex,points);
+ pointsmodelpy.save_complex_pr(complex,"testcomplex3.pr")
+
+ iqcomplex = iqPy.new_iq(100,0.001, 0.3)
+ pointsmodelpy.get_complex_iq(complex,iqcomplex)
+
+ iqPy.OutputIQ(iqcomplex,"testcomplex3.iq")
+
+ print("p(r) is saved in testcomplex3.pr")
+ print("I(Q) is saved in testcomplex3.iq")
+ print("pass")
+
+# Test 2D complex model
+def test_complex4():
+
+
+ a = geoshapespy.new_sphere(10)
+ lm = pointsmodelpy.new_loresmodel(0.1)
+ pointsmodelpy.lores_add(lm,a,1.0)
+
+ vpcomplex = pointsmodelpy.new_point3dvec();
+ complex = pointsmodelpy.new_complexmodel()
+ pointsmodelpy.complexmodel_add(complex,lm,"LORES");
+
+ pointsmodelpy.get_complexpoints(complex,vpcomplex);
+
+ print(pointsmodelpy.get_complex_iq_2D(complex,vpcomplex,0.1,0.1));
+ print(pointsmodelpy.get_complex_iq_2D(complex,vpcomplex,0.01,0.1));
+
+
+if __name__ == "__main__":
+ #print "test 1, adding one nonempty loresmodel and one nonempty pdbmodel to complex model"
+ #test_complex()
+ #print "test 2, adding a nonempty pdbmodel, and adding an empty loresmodel"
+ #test_complex2()
+ #print "test 3, adding an empty pdbmodel, and adding a nonempty loresmodel"
+ #test_complex3()
+ test_complex4()
diff --git a/src/sas/sascalc/simulation/pointsmodelpy/tests/testlores.py b/src/sas/sascalc/simulation/pointsmodelpy/tests/testlores.py
index 4ff42a1..84e2277 100644
--- a/src/sas/sascalc/simulation/pointsmodelpy/tests/testlores.py
+++ b/src/sas/sascalc/simulation/pointsmodelpy/tests/testlores.py
@@ -1,63 +1,66 @@
-if __name__ == "__main__":
-
- from sasModeling.iqPy import iqPy
- #from sasModeling.analmodelpy import analmodelpy as analmodelpymodule
- from sasModeling.geoshapespy import geoshapespy
- from sasModeling.pointsmodelpy import pointsmodelpy
-
-# print "copyright information:"
-# print " ", pointsmodelpy.copyright()
-# print " ", pointsmodelpymodule.copyright()
-
- print
- print "module information:"
- print " file:", pointsmodelpy.__file__
- print " doc:", pointsmodelpy.__doc__
- print " contents:", dir(pointsmodelpy)
- print " contents:", dir(geoshapespy)
-
-# a = geoshapespy.new_singlehelix(10,2,30,2)
- #a = geoshapespy.new_sphere(20)
-
- iq = iqPy.new_iq(100,0.001, 0.3)
-
-# geoshapespy.set_orientation(a,20,40,60)
-# geoshapespy.set_center(a,0,0,0)
- lm = pointsmodelpy.new_loresmodel(0.1)
-# pointsmodelpy.lores_add(lm,a,1.0)
-
-# b = geoshapespy.new_sphere(15)
-# geoshapespy.set_center(b,15,15,15)
-# pointsmodelpy.lores_add(lm,b,2.0)
-
-
- c = geoshapespy.new_cylinder(10,40)
- geoshapespy.set_center(c,1,1,1)
- geoshapespy.set_orientation(c,0,0,0)
- pointsmodelpy.lores_add(lm,c,3.0)
-
-# d = geoshapespy.new_ellipsoid(10,8,6)
-# geoshapespy.set_center(d,3,3,3)
-# geoshapespy.set_orientation(c,30,30,30)
-# pointsmodelpy.lores_add(lm,d,1.0)
-
- vp = pointsmodelpy.new_point3dvec()
- pointsmodelpy.get_lorespoints(lm,vp)
- pointsmodelpy.outputPDB(lm,vp,"modelpy.pseudo.pdb")
-
- print "calculating distance distribution"
- rmax = pointsmodelpy.get_lores_pr(lm,vp)
- print "finish calculating get_lores_pr, and rmax is:", rmax
- pointsmodelpy.outputPR(lm,"testlores.pr")
- pointsmodelpy.get_lores_iq(lm,iq)
-
- iqPy.OutputIQ(iq, "testlores.iq")
-
- print "Testing get I from a single q"
- result = pointsmodelpy.get_lores_i(lm,0.1)
- print "The I(0.1) is: %s" % str(result)
-
-# version
-__id__ = "$Id$"
-
-# End of file
+from __future__ import print_function
+
+
+if __name__ == "__main__":
+
+ from sasModeling.iqPy import iqPy
+ #from sasModeling.analmodelpy import analmodelpy as analmodelpymodule
+ from sasModeling.geoshapespy import geoshapespy
+ from sasModeling.pointsmodelpy import pointsmodelpy
+
+# print "copyright information:"
+# print " ", pointsmodelpy.copyright()
+# print " ", pointsmodelpymodule.copyright()
+
+ print()
+ print("module information:")
+ print(" file:", pointsmodelpy.__file__)
+ print(" doc:", pointsmodelpy.__doc__)
+ print(" contents:", dir(pointsmodelpy))
+ print(" contents:", dir(geoshapespy))
+
+# a = geoshapespy.new_singlehelix(10,2,30,2)
+ #a = geoshapespy.new_sphere(20)
+
+ iq = iqPy.new_iq(100,0.001, 0.3)
+
+# geoshapespy.set_orientation(a,20,40,60)
+# geoshapespy.set_center(a,0,0,0)
+ lm = pointsmodelpy.new_loresmodel(0.1)
+# pointsmodelpy.lores_add(lm,a,1.0)
+
+# b = geoshapespy.new_sphere(15)
+# geoshapespy.set_center(b,15,15,15)
+# pointsmodelpy.lores_add(lm,b,2.0)
+
+
+ c = geoshapespy.new_cylinder(10,40)
+ geoshapespy.set_center(c,1,1,1)
+ geoshapespy.set_orientation(c,0,0,0)
+ pointsmodelpy.lores_add(lm,c,3.0)
+
+# d = geoshapespy.new_ellipsoid(10,8,6)
+# geoshapespy.set_center(d,3,3,3)
+# geoshapespy.set_orientation(c,30,30,30)
+# pointsmodelpy.lores_add(lm,d,1.0)
+
+ vp = pointsmodelpy.new_point3dvec()
+ pointsmodelpy.get_lorespoints(lm,vp)
+ pointsmodelpy.outputPDB(lm,vp,"modelpy.pseudo.pdb")
+
+ print("calculating distance distribution")
+ rmax = pointsmodelpy.get_lores_pr(lm,vp)
+ print("finish calculating get_lores_pr, and rmax is:", rmax)
+ pointsmodelpy.outputPR(lm,"testlores.pr")
+ pointsmodelpy.get_lores_iq(lm,iq)
+
+ iqPy.OutputIQ(iq, "testlores.iq")
+
+ print("Testing get I from a single q")
+ result = pointsmodelpy.get_lores_i(lm,0.1)
+ print("The I(0.1) is: %s" % str(result))
+
+# version
+__id__ = "$Id$"
+
+# End of file
diff --git a/src/sas/sascalc/simulation/pointsmodelpy/tests/testlores2d.py b/src/sas/sascalc/simulation/pointsmodelpy/tests/testlores2d.py
index 39bbab0..c11ac01 100644
--- a/src/sas/sascalc/simulation/pointsmodelpy/tests/testlores2d.py
+++ b/src/sas/sascalc/simulation/pointsmodelpy/tests/testlores2d.py
@@ -1,115 +1,118 @@
-def test_lores2d(phi):
- from sasModeling.pointsmodelpy import pointsmodelpy
- from sasModeling.iqPy import iqPy
- from sasModeling.geoshapespy import geoshapespy
-
- #lores model is to hold several geometric objects
- lm = pointsmodelpy.new_loresmodel(0.1)
-
- #generate single geometry shape
- c = geoshapespy.new_cylinder(10,40)
- geoshapespy.set_center(c,1,1,1)
- geoshapespy.set_orientation(c,0,0,0)
-
- #add single geometry shape to lores model
- pointsmodelpy.lores_add(lm,c,3.0)
-
- #retrieve the points from lores model for sas calculation
- vp = pointsmodelpy.new_point3dvec()
- pointsmodelpy.get_lorespoints(lm,vp)
-
- #Calculate I(Q) and P(r) 2D
- pointsmodelpy.distdistribution_xy(lm,vp)
- pointsmodelpy.outputPR_xy(lm,"out_xy.pr")
- iq = iqPy.new_iq(100,0.001, 0.3)
- pointsmodelpy.calculateIQ_2D(lm,iq,phi)
- iqPy.OutputIQ(iq, "out_xy.iq")
-
-def get2d():
- from math import pi
- from Numeric import arange,zeros
- from enthought.util.numerix import Float,zeros
- from sasModeling.file2array import readfile2array
- from sasModeling.pointsmodelpy import pointsmodelpy
- from sasModeling.geoshapespy import geoshapespy
-
- lm = pointsmodelpy.new_loresmodel(0.1)
- sph = geoshapespy.new_sphere(20)
- pointsmodelpy.lores_add(lm,sph,1.0)
-
- vp = pointsmodelpy.new_point3dvec()
- pointsmodelpy.get_lorespoints(lm,vp)
-
- pointsmodelpy.distdistribution_xy(lm,vp)
-
- value_grid = zeros((100,100),Float)
- width, height = value_grid.shape
- print width,height
-
- I = pointsmodelpy.calculateI_Qxy(lm,0.00001,0.000002)
- print I
-
- Imax = 0
- for i in range(width):
- for j in range(height):
- qx = float(i-50)/200.0
- qy = float(j-50)/200.0
- value_grid[i,j] = pointsmodelpy.calculateI_Qxy(lm,qx,qy)
- if value_grid[i][j] > Imax:
- Imax = value_grid[i][j]
-
- for i in range(width):
- for j in range(height):
- value_grid[i][j] = value_grid[i][j]/Imax
-
- value_grid[50,50] = 1
- return value_grid
-
-def get2d_2():
- from math import pi
- from Numeric import arange,zeros
- from enthought.util.numerix import Float,zeros
- from sasModeling.file2array import readfile2array
- from sasModeling.pointsmodelpy import pointsmodelpy
- from sasModeling.geoshapespy import geoshapespy
-
- lm = pointsmodelpy.new_loresmodel(0.1)
- cyn = geoshapespy.new_cylinder(5,20)
- geoshapespy.set_orientation(cyn,0,0,90)
- pointsmodelpy.lores_add(lm,cyn,1.0)
-
- vp = pointsmodelpy.new_point3dvec()
- pointsmodelpy.get_lorespoints(lm,vp)
-
- pointsmodelpy.distdistribution_xy(lm,vp)
-
- value_grid = zeros((100,100),Float)
- width, height = value_grid.shape
- print width,height
-
- I = pointsmodelpy.calculateI_Qxy(lm,0.00001,0.000002)
- print I
-
- Imax = 0
- for i in range(width):
- for j in range(height):
- qx = float(i-50)/200.0
- qy = float(j-50)/200.0
- value_grid[i,j] = pointsmodelpy.calculateI_Qxy(lm,qx,qy)
- if value_grid[i][j] > Imax:
- Imax = value_grid[i][j]
-
- for i in range(width):
- for j in range(height):
- value_grid[i][j] = value_grid[i][j]/Imax
-
- value_grid[50,50] = 1
- return value_grid
-
-if __name__ == "__main__":
-
- print "start to test lores 2D"
-# test_lores2d(10)
- value_grid = get2d_2()
- print value_grid
- print "pass"
+from __future__ import print_function
+
+
+def test_lores2d(phi):
+ from sasModeling.pointsmodelpy import pointsmodelpy
+ from sasModeling.iqPy import iqPy
+ from sasModeling.geoshapespy import geoshapespy
+
+ #lores model is to hold several geometric objects
+ lm = pointsmodelpy.new_loresmodel(0.1)
+
+ #generate single geometry shape
+ c = geoshapespy.new_cylinder(10,40)
+ geoshapespy.set_center(c,1,1,1)
+ geoshapespy.set_orientation(c,0,0,0)
+
+ #add single geometry shape to lores model
+ pointsmodelpy.lores_add(lm,c,3.0)
+
+ #retrieve the points from lores model for sas calculation
+ vp = pointsmodelpy.new_point3dvec()
+ pointsmodelpy.get_lorespoints(lm,vp)
+
+ #Calculate I(Q) and P(r) 2D
+ pointsmodelpy.distdistribution_xy(lm,vp)
+ pointsmodelpy.outputPR_xy(lm,"out_xy.pr")
+ iq = iqPy.new_iq(100,0.001, 0.3)
+ pointsmodelpy.calculateIQ_2D(lm,iq,phi)
+ iqPy.OutputIQ(iq, "out_xy.iq")
+
+def get2d():
+ from math import pi
+ from Numeric import arange,zeros
+ from enthought.util.numerix import Float,zeros
+ from sasModeling.file2array import readfile2array
+ from sasModeling.pointsmodelpy import pointsmodelpy
+ from sasModeling.geoshapespy import geoshapespy
+
+ lm = pointsmodelpy.new_loresmodel(0.1)
+ sph = geoshapespy.new_sphere(20)
+ pointsmodelpy.lores_add(lm,sph,1.0)
+
+ vp = pointsmodelpy.new_point3dvec()
+ pointsmodelpy.get_lorespoints(lm,vp)
+
+ pointsmodelpy.distdistribution_xy(lm,vp)
+
+ value_grid = zeros((100,100),Float)
+ width, height = value_grid.shape
+ print(width,height)
+
+ I = pointsmodelpy.calculateI_Qxy(lm,0.00001,0.000002)
+ print(I)
+
+ Imax = 0
+ for i in range(width):
+ for j in range(height):
+ qx = float(i-50)/200.0
+ qy = float(j-50)/200.0
+ value_grid[i,j] = pointsmodelpy.calculateI_Qxy(lm,qx,qy)
+ if value_grid[i][j] > Imax:
+ Imax = value_grid[i][j]
+
+ for i in range(width):
+ for j in range(height):
+ value_grid[i][j] = value_grid[i][j]/Imax
+
+ value_grid[50,50] = 1
+ return value_grid
+
+def get2d_2():
+ from math import pi
+ from Numeric import arange,zeros
+ from enthought.util.numerix import Float,zeros
+ from sasModeling.file2array import readfile2array
+ from sasModeling.pointsmodelpy import pointsmodelpy
+ from sasModeling.geoshapespy import geoshapespy
+
+ lm = pointsmodelpy.new_loresmodel(0.1)
+ cyn = geoshapespy.new_cylinder(5,20)
+ geoshapespy.set_orientation(cyn,0,0,90)
+ pointsmodelpy.lores_add(lm,cyn,1.0)
+
+ vp = pointsmodelpy.new_point3dvec()
+ pointsmodelpy.get_lorespoints(lm,vp)
+
+ pointsmodelpy.distdistribution_xy(lm,vp)
+
+ value_grid = zeros((100,100),Float)
+ width, height = value_grid.shape
+ print(width,height)
+
+ I = pointsmodelpy.calculateI_Qxy(lm,0.00001,0.000002)
+ print(I)
+
+ Imax = 0
+ for i in range(width):
+ for j in range(height):
+ qx = float(i-50)/200.0
+ qy = float(j-50)/200.0
+ value_grid[i,j] = pointsmodelpy.calculateI_Qxy(lm,qx,qy)
+ if value_grid[i][j] > Imax:
+ Imax = value_grid[i][j]
+
+ for i in range(width):
+ for j in range(height):
+ value_grid[i][j] = value_grid[i][j]/Imax
+
+ value_grid[50,50] = 1
+ return value_grid
+
+if __name__ == "__main__":
+
+ print("start to test lores 2D")
+# test_lores2d(10)
+ value_grid = get2d_2()
+ print(value_grid)
+ print("pass")
diff --git a/src/sas/sascalc/simulation/pointsmodelpy/tests/testnegativepr.py b/src/sas/sascalc/simulation/pointsmodelpy/tests/testnegativepr.py
index 94741a5..3476e98 100644
--- a/src/sas/sascalc/simulation/pointsmodelpy/tests/testnegativepr.py
+++ b/src/sas/sascalc/simulation/pointsmodelpy/tests/testnegativepr.py
@@ -1,16 +1,16 @@
-if __name__ == "__main__":
- from sasModeling.pointsmodelpy import pointsmodelpy
- from sasModeling.iqPy import iqPy
- from sasModeling.geoshapespy import geoshapespy
-
- a = geoshapespy.new_sphere(10)
- lm = pointsmodelpy.new_loresmodel(0.0005)
- pointsmodelpy.lores_add(lm,a,1.0)
- b = geoshapespy.new_sphere(20)
- geoshapespy.set_center(b,20,20,20)
- pointsmodelpy.lores_add(lm,b,-1.0)
-
- vp = pointsmodelpy.new_point3dvec()
- pointsmodelpy.get_lorespoints(lm,vp)
-
- pointsmodelpy.get_lores_pr(lm,vp)
+if __name__ == "__main__":
+ from sasModeling.pointsmodelpy import pointsmodelpy
+ from sasModeling.iqPy import iqPy
+ from sasModeling.geoshapespy import geoshapespy
+
+ a = geoshapespy.new_sphere(10)
+ lm = pointsmodelpy.new_loresmodel(0.0005)
+ pointsmodelpy.lores_add(lm,a,1.0)
+ b = geoshapespy.new_sphere(20)
+ geoshapespy.set_center(b,20,20,20)
+ pointsmodelpy.lores_add(lm,b,-1.0)
+
+ vp = pointsmodelpy.new_point3dvec()
+ pointsmodelpy.get_lorespoints(lm,vp)
+
+ pointsmodelpy.get_lores_pr(lm,vp)
diff --git a/src/sas/sasgui/guiframe/CategoryInstaller.py b/src/sas/sasgui/guiframe/CategoryInstaller.py
index c35cb18..b74af87 100644
--- a/src/sas/sasgui/guiframe/CategoryInstaller.py
+++ b/src/sas/sasgui/guiframe/CategoryInstaller.py
@@ -1,177 +1,173 @@
-"""
-Class for making sure all category stuff is installed
-and works fine.
-
-Copyright (c) Institut Laue-Langevin 2012
-
- at author kieranrcampbell at gmail.com
- at modified by NIST/MD sasview team
-"""
-
-import os
-import sys
-import json
-import logging
-from collections import defaultdict, OrderedDict
-
-USER_FILE = 'categories.json'
-
-class CategoryInstaller:
- """
- Class for making sure all category stuff is installed
-
- Note - class is entirely static!
- """
-
- def __init__(self):
- """ initialization """
-
- @staticmethod
- def _get_installed_model_dir():
- """
- returns the dir where installed_models.txt should be
- """
- import sas.sascalc.dataloader.readers
- return sas.sascalc.dataloader.readers.get_data_path()
-
- @staticmethod
- def _get_models_py_dir():
- """
- returns the dir where models.py should be
- """
- import sas.sasgui.perspectives.fitting.models
- return sas.sasgui.perspectives.fitting.models.get_model_python_path()
-
- @staticmethod
- def _get_default_cat_file_dir():
- """
- returns the dir where default_cat.j should be
- """
- # The default categories file is usually found with the code, except
- # when deploying using py2app (it will be in Contents/Resources), or
- # py2exe (it will be in the exec dir).
- import sas.sasview
- cat_file = "default_categories.json"
-
- possible_cat_file_paths = [
- os.path.join(os.path.split(sas.sasview.__file__)[0], cat_file), # Source
- os.path.join(os.path.dirname(sys.executable), '..', 'Resources', cat_file), # Mac
- os.path.join(os.path.dirname(sys.executable), cat_file) # Windows
- ]
-
- for path in possible_cat_file_paths:
- if os.path.isfile(path):
- return os.path.dirname(path)
-
- raise RuntimeError('CategoryInstaller: Could not find folder containing default categories')
-
- @staticmethod
- def _get_home_dir():
- """
- returns the users sasview config dir
- """
- return os.path.join(os.path.expanduser("~"), ".sasview")
-
- @staticmethod
- def _regenerate_model_dict(master_category_dict):
- """
- regenerates self.by_model_dict which has each model name as the key
- and the list of categories belonging to that model
- along with the enabled mapping
- returns tuplet (by_model_dict, model_enabled_dict)
- """
- by_model_dict = defaultdict(list)
- model_enabled_dict = defaultdict(bool)
-
- for category in master_category_dict:
- for (model, enabled) in master_category_dict[category]:
- by_model_dict[model].append(category)
- model_enabled_dict[model] = enabled
-
- return (by_model_dict, model_enabled_dict)
-
- @staticmethod
- def _regenerate_master_dict(by_model_dict, model_enabled_dict):
- """
- regenerates master_category_dict from by_model_dict
- and model_enabled_dict
- returns the master category dictionary
- """
- master_category_dict = defaultdict(list)
- for model in by_model_dict:
- for category in by_model_dict[model]:
- master_category_dict[category].append(\
- (model, model_enabled_dict[model]))
- return OrderedDict(sorted(master_category_dict.items(), key=lambda t: t[0]))
-
- @staticmethod
- def get_user_file():
- """
- returns the user data file, eg .sasview/categories.json.json
- """
- return os.path.join(CategoryInstaller._get_home_dir(), USER_FILE)
-
- @staticmethod
- def get_default_file():
- logging.warning("CategoryInstaller.get_default_file is deprecated.")
-
- @staticmethod
- def check_install(homedir = None, model_list=None):
- """
- the main method of this class
- makes sure categories.json exists and if not
- compile it and install
- :param homefile: Override the default home directory
- :param model_list: List of model names except those in Plugin Models
- which are user supplied.
- """
- _model_dict = { model.name: model for model in model_list}
- _model_list = _model_dict.keys()
-
- serialized_file = None
- if homedir == None:
- serialized_file = CategoryInstaller.get_user_file()
- else:
- serialized_file = os.path.join(homedir, USER_FILE)
- if os.path.isfile(serialized_file):
- with open(serialized_file, 'rb') as f:
- master_category_dict = json.load(f)
- else:
- master_category_dict = defaultdict(list)
-
- (by_model_dict, model_enabled_dict) = \
- CategoryInstaller._regenerate_model_dict(master_category_dict)
- add_list = _model_list
- del_name = False
- for cat in master_category_dict.keys():
- for ind in range(len(master_category_dict[cat])):
- model_name, enabled = master_category_dict[cat][ind]
- if model_name not in _model_list:
- del_name = True
- try:
- by_model_dict.pop(model_name)
- model_enabled_dict.pop(model_name)
- except:
- logging.error("CategoryInstaller: %s", sys.exc_value)
- else:
- add_list.remove(model_name)
- if del_name or (len(add_list) > 0):
- for model in add_list:
- model_enabled_dict[model]= True
- if _model_dict[model].category is None or len(str(_model_dict[model].category.capitalize())) == 0:
- by_model_dict[model].append('Uncategorized')
- else:
- category = _model_dict[model].category
- toks = category.split(':')
- category = toks[-1]
- toks = category.split('-')
- capitalized_words = [t.capitalize() for t in toks]
- category = ' '.join(capitalized_words)
-
- by_model_dict[model].append(category)
-
- master_category_dict = \
- CategoryInstaller._regenerate_master_dict(by_model_dict,
- model_enabled_dict)
-
- json.dump(master_category_dict, open(serialized_file, 'wb'))
+"""
+Class for making sure all category stuff is installed
+and works fine.
+
+Copyright (c) Institut Laue-Langevin 2012
+
+ at author kieranrcampbell at gmail.com
+ at modified by NIST/MD sasview team
+"""
+
+import os
+import sys
+import json
+import logging
+from collections import defaultdict, OrderedDict
+
+from sas import get_user_dir
+
+USER_FILE = 'categories.json'
+
+logger = logging.getLogger(__name__)
+
+class CategoryInstaller(object):
+ """
+ Class for making sure all category stuff is installed
+
+ Note - class is entirely static!
+ """
+
+ @staticmethod
+ def _get_installed_model_dir():
+ """
+ returns the dir where installed_models.txt should be
+ """
+ from sas.sascalc.dataloader.readers import get_data_path
+ return get_data_path()
+
+ @staticmethod
+ def _get_default_cat_file_dir():
+ """
+ returns the dir where default_cat.j should be
+ """
+ # The default categories file is usually found with the code, except
+ # when deploying using py2app (it will be in Contents/Resources), or
+ # py2exe (it will be in the exec dir).
+ import sas.sasview
+ cat_file = "default_categories.json"
+
+ possible_cat_file_paths = [
+ os.path.join(os.path.split(sas.sasview.__file__)[0], cat_file), # Source
+ os.path.join(os.path.dirname(sys.executable), '..', 'Resources', cat_file), # Mac
+ os.path.join(os.path.dirname(sys.executable), cat_file) # Windows
+ ]
+
+ for path in possible_cat_file_paths:
+ if os.path.isfile(path):
+ return os.path.dirname(path)
+
+ raise RuntimeError('CategoryInstaller: Could not find folder containing default categories')
+
+ @staticmethod
+ def _get_home_dir():
+ """
+ returns the users sasview config dir
+ """
+ return os.path.join(os.path.expanduser("~"), ".sasview")
+
+ @staticmethod
+ def _regenerate_model_dict(master_category_dict):
+ """
+ regenerates self.by_model_dict which has each model name as the key
+ and the list of categories belonging to that model
+ along with the enabled mapping
+ returns tuplet (by_model_dict, model_enabled_dict)
+ """
+ by_model_dict = defaultdict(list)
+ model_enabled_dict = defaultdict(bool)
+
+ for category in master_category_dict:
+ for (model, enabled) in master_category_dict[category]:
+ by_model_dict[model].append(category)
+ model_enabled_dict[model] = enabled
+
+ return (by_model_dict, model_enabled_dict)
+
+ @staticmethod
+ def _regenerate_master_dict(by_model_dict, model_enabled_dict):
+ """
+ regenerates master_category_dict from by_model_dict
+ and model_enabled_dict
+ returns the master category dictionary
+ """
+ master_category_dict = defaultdict(list)
+ for model in by_model_dict:
+ for category in by_model_dict[model]:
+ master_category_dict[category].append(\
+ (model, model_enabled_dict[model]))
+ return OrderedDict(sorted(master_category_dict.items(), key=lambda t: t[0]))
+
+ @staticmethod
+ def get_user_file():
+ """
+ returns the user data file, eg .sasview/categories.json.json
+ """
+ return os.path.join(get_user_dir(), USER_FILE)
+
+ @staticmethod
+ def get_default_file():
+ logger.warning("CategoryInstaller.get_default_file is deprecated.")
+
+ @staticmethod
+ def check_install(homedir = None, model_list=None):
+ """
+ Makes sure categories.json exists and if not compile it and install.
+
+ This is the main method of this class.
+
+ :param homefile: Override the default home directory
+ :param model_list: List of model names except those in
+ Plugin Models which are user supplied.
+ """
+ _model_dict = {model.name: model for model in model_list}
+ _model_list = _model_dict.keys()
+
+ serialized_file = None
+ if homedir is None:
+ serialized_file = CategoryInstaller.get_user_file()
+ else:
+ serialized_file = os.path.join(homedir, USER_FILE)
+ if os.path.isfile(serialized_file):
+ with open(serialized_file, 'rb') as f:
+ master_category_dict = json.load(f)
+ else:
+ master_category_dict = defaultdict(list)
+
+ (by_model_dict, model_enabled_dict) = \
+ CategoryInstaller._regenerate_model_dict(master_category_dict)
+ add_list = _model_list
+ del_name = False
+ for cat in master_category_dict.keys():
+ for ind in range(len(master_category_dict[cat])):
+ model_name, enabled = master_category_dict[cat][ind]
+ if model_name not in _model_list:
+ del_name = True
+ try:
+ by_model_dict.pop(model_name)
+ model_enabled_dict.pop(model_name)
+ except Exception:
+ logger.error("CategoryInstaller: %s", sys.exc_value)
+ else:
+ add_list.remove(model_name)
+ if del_name or (len(add_list) > 0):
+ for model in add_list:
+ model_enabled_dict[model] = True
+ # TODO: should be: not _model_dict[model].category
+ if (_model_dict[model].category is None
+ or len(str(_model_dict[model].category.capitalize())) == 0):
+ by_model_dict[model].append('Uncategorized')
+ else:
+ category = _model_dict[model].category
+ toks = category.split(':')
+ category = toks[-1]
+ toks = category.split('-')
+ capitalized_words = [t.capitalize() for t in toks]
+ category = ' '.join(capitalized_words)
+
+ by_model_dict[model].append(category)
+
+ master_category_dict = \
+ CategoryInstaller._regenerate_master_dict(by_model_dict,
+ model_enabled_dict)
+
+ json.dump(master_category_dict, open(serialized_file, 'wb'))
diff --git a/src/sas/sasgui/guiframe/CategoryManager.py b/src/sas/sasgui/guiframe/CategoryManager.py
index ccf8558..e213899 100644
--- a/src/sas/sasgui/guiframe/CategoryManager.py
+++ b/src/sas/sasgui/guiframe/CategoryManager.py
@@ -20,6 +20,8 @@ from sas.sasgui.guiframe.events import ChangeCategoryEvent
from sas.sasgui.guiframe.CategoryInstaller import CategoryInstaller
IS_MAC = (sys.platform == 'darwin')
+logger = logging.getLogger(__name__)
+
""" Notes
The category manager mechanism works from 3 data structures used:
- self.master_category_dict: keys are the names of categories,
@@ -372,7 +374,7 @@ class CategoryManager(wx.Frame):
with open(cat_file, 'rb') as f:
self.master_category_dict = json.load(f)
except IOError:
- logging.error('Problem reading in category file.')
+ logger.error('Problem reading in category file.')
self._regenerate_model_dict()
diff --git a/src/sas/sasgui/guiframe/__init__.py b/src/sas/sasgui/guiframe/__init__.py
index bb28595..cd99bc2 100644
--- a/src/sas/sasgui/guiframe/__init__.py
+++ b/src/sas/sasgui/guiframe/__init__.py
@@ -1,73 +1,69 @@
-
-
-import os
-from distutils.filelist import findall
-
-def get_data_path(media):
- """
- """
- # Check for data path in the package
- path = os.path.join(os.path.dirname(__file__), media)
- if os.path.isdir(path):
- return path
-
- # Check for data path next to exe/zip file.
- # If we are inside a py2exe zip file, we need to go up
- # to get to the directory containing
- # the media for this module
- path = os.path.dirname(__file__)
- #Look for maximum n_dir up of the current dir to find media
- n_dir = 12
- for i in range(n_dir):
- path, _ = os.path.split(path)
- media_path = os.path.join(path, media)
- if os.path.isdir(media_path):
- module_media_path = os.path.join(media_path, 'icons')
- if os.path.isdir(module_media_path):
- return module_media_path
- return media_path
-
- raise RuntimeError('Could not find guiframe images files')
-
-def get_media_path(media):
- """
- """
- # Check for data path in the package
- path = os.path.join(os.path.dirname(__file__), media)
- if os.path.isdir(path):
- return path
-
- # Check for data path next to exe/zip file.
- # If we are inside a py2exe zip file, we need to go up
- # to get to the directory containing
- # the media for this module
- path = os.path.dirname(__file__)
- #Look for maximum n_dir up of the current dir to find media
- n_dir = 12
- for i in range(n_dir):
- path, _ = os.path.split(path)
- media_path = os.path.join(path, media)
- if os.path.isdir(media_path):
- module_media_path = os.path.join(media_path, 'guiframe_media')
- if os.path.isdir(module_media_path):
- return module_media_path
- return media_path
- raise RuntimeError('Could not find guiframe media files')
-
-def data_files():
- """
- Return the data files associated with guiframe images .
-
- The format is a list of (directory, [files...]) pairs which can be
- used directly in setup(...,data_files=...) for setup.py.
-
- """
- data_files = []
- path = get_data_path(media="images")
- for f in findall(path):
- data_files.append(('images/icons', [f]))
- path = get_media_path(media="media")
- for f in findall(path):
- data_files.append(('media/guiframe_media', [f]))
-
- return data_files
+
+
+import os
+from distutils.filelist import findall
+
+def get_data_path(media):
+ """
+ """
+ # Check for data path in the package
+ path = os.path.join(os.path.dirname(__file__), media)
+ if os.path.isdir(path):
+ return path
+
+ # Check for data path next to exe/zip file.
+ # If we are inside a py2exe zip file, we need to go up
+ # to get to the directory containing
+ # the media for this module
+ path = os.path.dirname(__file__)
+ #Look for maximum n_dir up of the current dir to find media
+ n_dir = 12
+ for i in range(n_dir):
+ path, _ = os.path.split(path)
+ media_path = os.path.join(path, media)
+ if os.path.isdir(media_path):
+ module_media_path = os.path.join(media_path, 'icons')
+ if os.path.isdir(module_media_path):
+ return module_media_path
+ return media_path
+
+ raise RuntimeError('Could not find guiframe images files')
+
+def get_media_path(media):
+ """
+ """
+ # Check for data path in the package
+ path = os.path.join(os.path.dirname(__file__), media)
+ if os.path.isdir(path):
+ return path
+
+ # Check for data path next to exe/zip file.
+ # If we are inside a py2exe zip file, we need to go up
+ # to get to the directory containing
+ # the media for this module
+ path = os.path.dirname(__file__)
+ #Look for maximum n_dir up of the current dir to find media
+ n_dir = 12
+ for i in range(n_dir):
+ path, _ = os.path.split(path)
+ media_path = os.path.join(path, media)
+ if os.path.isdir(media_path):
+ module_media_path = os.path.join(media_path, 'guiframe_media')
+ if os.path.isdir(module_media_path):
+ return module_media_path
+ return media_path
+ raise RuntimeError('Could not find guiframe media files')
+
+def data_files():
+ """
+ Return the data files associated with guiframe images .
+
+ The format is a list of (directory, [files...]) pairs which can be
+ used directly in setup(...,data_files=...) for setup.py.
+
+ """
+ data_files = []
+ data_files.append(('images/icons', findall(get_data_path("images"))))
+ data_files.append(('media/guiframe_media', findall(get_data_path("media"))))
+
+ return data_files
diff --git a/src/sas/sasgui/guiframe/aboutbox.py b/src/sas/sasgui/guiframe/aboutbox.py
index 1738aa1..12b918a 100644
--- a/src/sas/sasgui/guiframe/aboutbox.py
+++ b/src/sas/sasgui/guiframe/aboutbox.py
@@ -1,447 +1,454 @@
-#!/usr/bin/env python
-########################################################################
-#
-# PDFgui by DANSE Diffraction group
-# Simon J. L. Billinge
-# (c) 2006 trustees of the Michigan State University.
-# All rights reserved.
-#
-# File coded by: Dmitriy Bryndin
-#
-# See AUTHORS.txt for a list of people who contributed.
-# See LICENSE.txt for license information.
-#
-# Modified by U. Tennessee for DANSE/SANS
-########################################################################
-
-# version
-__id__ = "$Id: aboutdialog.py 1193 2007-05-03 17:29:59Z dmitriy $"
-__revision__ = "$Revision: 1193 $"
-
-import wx
-import wx.lib.hyperlink
-import random
-import os.path
-import os
-try:
- # Try to find a local config
- import imp
- path = os.getcwd()
- if(os.path.isfile("%s/%s.py" % (path, 'local_config'))) or \
- (os.path.isfile("%s/%s.pyc" % (path, 'local_config'))):
- fObj, path, descr = imp.find_module('local_config', [path])
- config = imp.load_module('local_config', fObj, path, descr)
- else:
- # Try simply importing local_config
- import local_config as config
-except:
- # Didn't find local config, load the default
- import config
-
-def launchBrowser(url):
- """
- Launches browser and opens specified url
-
- In some cases may require BROWSER environment variable to be set up.
-
- :param url: URL to open
-
- """
- import webbrowser
- webbrowser.open(url)
-
-
-class DialogAbout(wx.Dialog):
- """
- "About" Dialog
-
- Shows product name, current version, authors, and link to the product page.
- Current version is taken from version.py
-
- """
-
- def __init__(self, *args, **kwds):
-
- # begin wxGlade: DialogAbout.__init__
- kwds["style"] = wx.DEFAULT_DIALOG_STYLE
- wx.Dialog.__init__(self, *args, **kwds)
-
- file_dir = os.path.dirname(__file__)
-
- # Mac doesn't display images with transparent background so well,
- # keep it for Windows
- image = file_dir + "/images/angles_flat.png"
-
- if os.path.isfile(config._corner_image):
- image = config._corner_image
-
- if os.name == 'nt':
- self.bitmap_logo = wx.StaticBitmap(self, -1, wx.Bitmap(image))
- else:
- self.bitmap_logo = wx.StaticBitmap(self, -1, wx.Bitmap(image))
-
- self.label_title = wx.StaticText(self, -1, config.__appname__)
- self.label_version = wx.StaticText(self, -1, "")
- self.label_build = wx.StaticText(self, -1, "Build:")
- self.label_svnrevision = wx.StaticText(self, -1, "")
- self.label_copyright = wx.StaticText(self, -1, config._copyright)
- self.label_author = wx.StaticText(self, -1, "authors")
- self.hyperlink = wx.lib.hyperlink.HyperLinkCtrl(self, -1,
- config._homepage,
- URL=config._homepage)
- #self.hyperlink_license = wx.lib.hyperlink.HyperLinkCtrl(self, -1,
- #"Comments? Bugs? Requests?", URL=config._paper)
- self.hyperlink_license = wx.StaticText(self, -1,
- "Comments? Bugs? Requests?")
- self.hyperlink_paper = wx.lib.hyperlink.HyperLinkCtrl(self, -1,
- "Send us a ticket",
- URL=config._license)
- self.hyperlink_download = wx.lib.hyperlink.HyperLinkCtrl(self, -1,
- "Get the latest version",
- URL=config._download)
- self.static_line_1 = wx.StaticLine(self, -1)
- self.label_acknowledgement = wx.StaticText(self, -1,
- config._acknowledgement)
- self.static_line_2 = wx.StaticLine(self, -1)
- self.bitmap_button_nist = wx.BitmapButton(self, -1, wx.NullBitmap)
- self.bitmap_button_umd = wx.BitmapButton(self, -1, wx.NullBitmap)
- self.bitmap_button_ornl = wx.BitmapButton(self, -1, wx.NullBitmap)
- #self.bitmap_button_sns = wx.BitmapButton(self, -1, wx.NullBitmap)
- #self.bitmap_button_nsf = wx.BitmapButton(self, -1,
- # wx.NullBitmap)
- #self.bitmap_button_danse = wx.BitmapButton(self, -1, wx.NullBitmap)
- self.bitmap_button_msu = wx.BitmapButton(self, -1, wx.NullBitmap)
-
- self.bitmap_button_isis = wx.BitmapButton(self, -1, wx.NullBitmap)
- self.bitmap_button_ess = wx.BitmapButton(self, -1, wx.NullBitmap)
- self.bitmap_button_ill = wx.BitmapButton(self, -1, wx.NullBitmap)
- self.bitmap_button_ansto = wx.BitmapButton(self, -1, wx.NullBitmap)
- self.bitmap_button_tudelft = wx.BitmapButton(self, -1, wx.NullBitmap)
-
- self.static_line_3 = wx.StaticLine(self, -1)
- self.button_OK = wx.Button(self, wx.ID_OK, "OK")
-
- self.__set_properties()
- self.__do_layout()
-
- self.Bind(wx.EVT_BUTTON, self.onNistLogo, self.bitmap_button_nist)
- self.Bind(wx.EVT_BUTTON, self.onUmdLogo, self.bitmap_button_umd)
- #self.Bind(wx.EVT_BUTTON, self.onSnsLogo, self.bitmap_button_sns)
- self.Bind(wx.EVT_BUTTON, self.onOrnlLogo, self.bitmap_button_ornl)
- #self.Bind(wx.EVT_BUTTON, self.onNsfLogo, self.bitmap_button_nsf)
- #self.Bind(wx.EVT_BUTTON, self.onDanseLogo, self.bitmap_button_danse)
- self.Bind(wx.EVT_BUTTON, self.onUTLogo, self.bitmap_button_msu)
- self.Bind(wx.EVT_BUTTON, self.onIsisLogo, self.bitmap_button_isis)
- self.Bind(wx.EVT_BUTTON, self.onEssLogo, self.bitmap_button_ess)
- self.Bind(wx.EVT_BUTTON, self.onIllLogo, self.bitmap_button_ill)
- self.Bind(wx.EVT_BUTTON, self.onAnstoLogo, self.bitmap_button_ansto)
- self.Bind(wx.EVT_BUTTON, self.onTudelftLogo, self.bitmap_button_tudelft)
- # end wxGlade
- # fill in acknowledgements
- #self.text_ctrl_acknowledgement.SetValue(__acknowledgement__)
- # randomly shuffle authors' names
- random.shuffle(config._authors)
- strLabel = ", ".join(config._authors)
-
- # display version and svn revison numbers
- verwords = config.__version__.split('.')
- version = '.'.join(verwords[:-1])
- revision = verwords[-1]
- try:
- build_num = str(config.__build__)
- except:
- build_num = str(config.__version__)
- self.label_author.SetLabel(strLabel)
- self.label_version.SetLabel(config.__version__)#(version)
- self.label_svnrevision.SetLabel(build_num)
-
- # set bitmaps for logo buttons
- image = file_dir + "/images/nist_logo.png"
- if os.path.isfile(config._nist_logo):
- image = config._nist_logo
- logo = wx.Bitmap(image)
- self.bitmap_button_nist.SetBitmapLabel(logo)
-
- image = file_dir + "/images/umd_logo.png"
- if os.path.isfile(config._umd_logo):
- image = config._umd_logo
- logo = wx.Bitmap(image)
- self.bitmap_button_umd.SetBitmapLabel(logo)
-
- image = file_dir + "/images/ornl_logo.png"
- if os.path.isfile(config._ornl_logo):
- image = config._ornl_logo
- logo = wx.Bitmap(image)
- self.bitmap_button_ornl.SetBitmapLabel(logo)
-
- """
- image = file_dir + "/images/sns_logo.png"
- if os.path.isfile(config._sns_logo):
- image = config._sns_logo
- logo = wx.Bitmap(image)
- self.bitmap_button_sns.SetBitmapLabel(logo)
-
- image = file_dir + "/images/nsf_logo.png"
- if os.path.isfile(config._nsf_logo):
- image = config._nsf_logo
- logo = wx.Bitmap(image)
- self.bitmap_button_nsf.SetBitmapLabel(logo)
-
- image = file_dir + "/images/danse_logo.png"
- if os.path.isfile(config._danse_logo):
- image = config._danse_logo
- logo = wx.Bitmap(image)
- self.bitmap_button_danse.SetBitmapLabel(logo)
- """
- image = file_dir + "/images/utlogo.gif"
- if os.path.isfile(config._inst_logo):
- image = config._inst_logo
- logo = wx.Bitmap(image)
- self.bitmap_button_msu.SetBitmapLabel(logo)
-
- image = file_dir + "/images/isis_logo.png"
- if os.path.isfile(config._isis_logo):
- image = config._isis_logo
- logo = wx.Bitmap(image)
- self.bitmap_button_isis.SetBitmapLabel(logo)
-
- image = file_dir + "/images/ess_logo.png"
- if os.path.isfile(config._ess_logo):
- image = config._ess_logo
- logo = wx.Bitmap(image)
- self.bitmap_button_ess.SetBitmapLabel(logo)
-
- image = file_dir + "/images/ill_logo.png"
- if os.path.isfile(config._ill_logo):
- image = config._ill_logo
- logo = wx.Bitmap(image)
- self.bitmap_button_ill.SetBitmapLabel(logo)
-
- image = file_dir + "/images/ansto_logo.png"
- if os.path.isfile(config._ansto_logo):
- image = config._ansto_logo
- logo = wx.Bitmap(image)
- self.bitmap_button_ansto.SetBitmapLabel(logo)
-
- image = file_dir + "/images/tudelft_logo.png"
- if os.path.isfile(config._tudelft_logo):
- image = config._tudelft_logo
- logo = wx.Bitmap(image)
- self.bitmap_button_tudelft.SetBitmapLabel(logo)
-
- # resize dialog window to fit version number nicely
- if wx.VERSION >= (2, 7, 2, 0):
- size = [self.GetEffectiveMinSize()[0], self.GetSize()[1]]
- else:
- size = [self.GetBestFittingSize()[0], self.GetSize()[1]]
- self.Fit()
-
- def __set_properties(self):
- """
- """
- # begin wxGlade: DialogAbout.__set_properties
- self.SetTitle("About")
- self.SetSize((600, 595))
- self.label_title.SetFont(wx.Font(26, wx.DEFAULT, wx.NORMAL,
- wx.BOLD, 0, ""))
- self.label_version.SetFont(wx.Font(26, wx.DEFAULT, wx.NORMAL,
- wx.NORMAL, 0, ""))
- self.hyperlink_paper.Enable(True)
- self.bitmap_button_nist.SetSize(self.bitmap_button_nist.GetBestSize())
- self.bitmap_button_umd.SetSize(self.bitmap_button_umd.GetBestSize())
- self.bitmap_button_ornl.SetSize(self.bitmap_button_ornl.GetBestSize())
- #self.bitmap_button_sns.SetSize(self.bitmap_button_sns.GetBestSize())
- #self.bitmap_button_nsf.SetSize(self.bitmap_button_nsf.GetBestSize())
- #self.bitmap_button_danse.SetSize(self.bitmap_button_danse.GetBestSize())
- self.bitmap_button_msu.SetSize(self.bitmap_button_msu.GetBestSize())
- self.bitmap_button_isis.SetSize(self.bitmap_button_isis.GetBestSize())
- self.bitmap_button_ess.SetSize(self.bitmap_button_ess.GetBestSize())
- self.bitmap_button_ill.SetSize(self.bitmap_button_ill.GetBestSize())
- self.bitmap_button_ansto.SetSize(self.bitmap_button_ansto.GetBestSize())
- self.bitmap_button_tudelft.SetSize(self.bitmap_button_tudelft.GetBestSize())
- # end wxGlade
-
- def __do_layout(self):
- """
- """
- # begin wxGlade: DialogAbout.__do_layout
- sizer_main = wx.BoxSizer(wx.VERTICAL)
- sizer_button = wx.BoxSizer(wx.HORIZONTAL)
- sizer_logos = wx.BoxSizer(wx.HORIZONTAL)
- sizer_header = wx.BoxSizer(wx.HORIZONTAL)
- sizer_titles = wx.BoxSizer(wx.VERTICAL)
- sizer_build = wx.BoxSizer(wx.HORIZONTAL)
- sizer_title = wx.BoxSizer(wx.HORIZONTAL)
- sizer_header.Add(self.bitmap_logo, 0, wx.EXPAND, 0)
- sizer_title.Add(self.label_title, 0,
- wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 10)
- sizer_title.Add((20, 20), 0, wx.EXPAND|wx.ADJUST_MINSIZE, 0)
- sizer_title.Add(self.label_version, 0,
- wx.RIGHT|wx.ALIGN_BOTTOM|wx.ADJUST_MINSIZE, 10)
- sizer_titles.Add(sizer_title, 0, wx.EXPAND, 0)
- sizer_build.Add(self.label_build, 0,
- wx.LEFT|wx.RIGHT|wx.ADJUST_MINSIZE, 10)
- sizer_build.Add(self.label_svnrevision, 0, wx.ADJUST_MINSIZE, 0)
- sizer_titles.Add(sizer_build, 0, wx.TOP|wx.EXPAND, 5)
- sizer_titles.Add(self.label_copyright, 0,
- wx.LEFT|wx.RIGHT|wx.TOP|wx.ADJUST_MINSIZE, 10)
- sizer_titles.Add(self.label_author, 0,
- wx.LEFT|wx.RIGHT|wx.ADJUST_MINSIZE, 10)
- sizer_titles.Add(self.hyperlink, 0, wx.LEFT|wx.RIGHT, 10)
- sizer_titles.Add((20, 20), 0, wx.ADJUST_MINSIZE, 0)
- sizer_titles.Add(self.hyperlink_license, 0, wx.LEFT|wx.RIGHT, 10)
- sizer_titles.Add(self.hyperlink_paper, 0, wx.LEFT|wx.RIGHT, 10)
- sizer_titles.Add((20, 20), 0, wx.ADJUST_MINSIZE, 0)
- sizer_titles.Add(self.hyperlink_download, 0, wx.LEFT|wx.RIGHT, 10)
- sizer_header.Add(sizer_titles, 0, wx.EXPAND, 0)
- sizer_main.Add(sizer_header, 0, wx.BOTTOM|wx.EXPAND, 3)
- sizer_main.Add(self.static_line_1, 0, wx.EXPAND, 0)
- sizer_main.Add(self.label_acknowledgement, 0,
- wx.LEFT|wx.TOP|wx.BOTTOM|wx.ADJUST_MINSIZE, 7)
- sizer_main.Add(self.static_line_2, 0, wx.EXPAND, 0)
-
- sizer_logos.Add(self.bitmap_button_msu, 0,
- wx.LEFT|wx.ADJUST_MINSIZE, 2)
- #sizer_logos.Add(self.bitmap_button_danse, 0,
- # wx.LEFT|wx.ADJUST_MINSIZE, 2)
- #sizer_logos.Add(self.bitmap_button_nsf, 0,
- # wx.LEFT|wx.ADJUST_MINSIZE, 2)
- sizer_logos.Add(self.bitmap_button_umd, 0,
- wx.LEFT|wx.ADJUST_MINSIZE, 2)
- sizer_logos.Add(self.bitmap_button_nist, 0,
- wx.LEFT|wx.ADJUST_MINSIZE, 2)
- #sizer_logos.Add(self.bitmap_button_sns, 0,
- # wx.LEFT|wx.ADJUST_MINSIZE, 2)
- sizer_logos.Add(self.bitmap_button_ornl, 0,
- wx.LEFT|wx.ADJUST_MINSIZE, 2)
- sizer_logos.Add(self.bitmap_button_isis, 0,
- wx.LEFT|wx.ADJUST_MINSIZE, 2)
- sizer_logos.Add(self.bitmap_button_ess, 0,
- wx.LEFT|wx.ADJUST_MINSIZE, 2)
- sizer_logos.Add(self.bitmap_button_ill, 0,
- wx.LEFT|wx.ADJUST_MINSIZE, 2)
- sizer_logos.Add(self.bitmap_button_ansto, 0,
- wx.LEFT|wx.ADJUST_MINSIZE, 2)
- sizer_logos.Add(self.bitmap_button_tudelft, 0,
- wx.LEFT|wx.ADJUST_MINSIZE, 2)
-
- sizer_logos.Add((10, 50), 0, wx.ADJUST_MINSIZE, 0)
- sizer_main.Add(sizer_logos, 0, wx.EXPAND, 0)
- sizer_main.Add(self.static_line_3, 0, wx.EXPAND, 0)
- sizer_button.Add((20, 40), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0)
- sizer_button.Add(self.button_OK, 0,
- wx.RIGHT|wx.ADJUST_MINSIZE|wx.CENTER, 10)
- sizer_main.Add(sizer_button, 0, wx.EXPAND, 0)
- self.SetAutoLayout(True)
- self.SetSizer(sizer_main)
- self.Layout()
- self.Centre()
- # end wxGlade
-
- def onNistLogo(self, event):
- """
- """
- # wxGlade: DialogAbout.<event_handler>
- launchBrowser(config._nist_url)
- event.Skip()
-
- def onUmdLogo(self, event):
- """
- """
- # wxGlade: DialogAbout.<event_handler>
- launchBrowser(config._umd_url)
- event.Skip()
-
- def onOrnlLogo(self, event):
- """
- """
- # wxGlade: DialogAbout.<event_handler>
- launchBrowser(config._ornl_url)
- event.Skip()
-
- def onSnsLogo(self, event):
- """
- """
- # wxGlade: DialogAbout.<event_handler>
- launchBrowser(config._sns_url)
- event.Skip()
-
- def onNsfLogo(self, event):
- """
- """
- # wxGlade: DialogAbout.<event_handler>
- launchBrowser(config._nsf_url)
- event.Skip()
-
- def onDanseLogo(self, event):
- """
- """
- # wxGlade: DialogAbout.<event_handler>
- launchBrowser(config._danse_url)
- event.Skip()
-
- def onUTLogo(self, event):
- """
- """
- # wxGlade: DialogAbout.<event_handler>
- launchBrowser(config._inst_url)
- event.Skip()
-
- def onIsisLogo(self, event):
- """
- """
- # wxGlade: DialogAbout.<event_handler>
- launchBrowser(config._isis_url)
- event.Skip()
-
- def onEssLogo(self, event):
- """
- """
- # wxGlade: DialogAbout.<event_handler>
- launchBrowser(config._ess_url)
- event.Skip()
-
- def onIllLogo(self, event):
- """
- """
- # wxGlade: DialogAbout.<event_handler>
- launchBrowser(config._ill_url)
- event.Skip()
-
- def onAnstoLogo(self, event):
- """
- """
- # wxGlade: DialogAbout.<event_handler>
- launchBrowser(config._ansto_url)
- event.Skip()
-
- def onTudelftLogo(self, event):
- """
- """
- # wxGlade: DialogAbout.<event_handler>
- launchBrowser(config._tudelft_url)
- event.Skip()
-
-# end of class DialogAbout
-
-##### testing code ############################################################
-class MyApp(wx.App):
- """
- """
- def OnInit(self):
- """
- """
- wx.InitAllImageHandlers()
- dialog = DialogAbout(None, -1, "")
- self.SetTopWindow(dialog)
- dialog.ShowModal()
- dialog.Destroy()
- return 1
-
-# end of class MyApp
-
-if __name__ == "__main__":
- app = MyApp(0)
- app.MainLoop()
-
-##### end of testing code #####################################################
+#!/usr/bin/env python
+########################################################################
+#
+# PDFgui by DANSE Diffraction group
+# Simon J. L. Billinge
+# (c) 2006 trustees of the Michigan State University.
+# All rights reserved.
+#
+# File coded by: Dmitriy Bryndin
+#
+# See AUTHORS.txt for a list of people who contributed.
+# See LICENSE.txt for license information.
+#
+# Modified by U. Tennessee for DANSE/SANS
+########################################################################
+
+# version
+__id__ = "$Id: aboutdialog.py 1193 2007-05-03 17:29:59Z dmitriy $"
+__revision__ = "$Revision: 1193 $"
+
+import wx
+import wx.lib.hyperlink
+import random
+import os.path
+import os
+
+from sas import get_local_config
+config = get_local_config()
+
+def launchBrowser(url):
+ """
+ Launches browser and opens specified url
+
+ In some cases may require BROWSER environment variable to be set up.
+
+ :param url: URL to open
+
+ """
+ import webbrowser
+ webbrowser.open(url)
+
+
+class DialogAbout(wx.Dialog):
+ """
+ "About" Dialog
+
+ Shows product name, current version, authors, and link to the product page.
+ Current version is taken from version.py
+
+ """
+
+ def __init__(self, *args, **kwds):
+
+ # begin wxGlade: DialogAbout.__init__
+ kwds["style"] = wx.DEFAULT_DIALOG_STYLE
+ wx.Dialog.__init__(self, *args, **kwds)
+
+ file_dir = os.path.dirname(__file__)
+
+ # Mac doesn't display images with transparent background so well,
+ # keep it for Windows
+ image = file_dir + "/images/angles_flat.png"
+
+ if os.path.isfile(config._corner_image):
+ image = config._corner_image
+
+ if os.name == 'nt':
+ self.bitmap_logo = wx.StaticBitmap(self, -1, wx.Bitmap(image))
+ else:
+ self.bitmap_logo = wx.StaticBitmap(self, -1, wx.Bitmap(image))
+
+ self.label_title = wx.StaticText(self, -1, config.__appname__)
+ self.label_version = wx.StaticText(self, -1, "")
+ self.label_build = wx.StaticText(self, -1, "Build:")
+ self.label_svnrevision = wx.StaticText(self, -1, "")
+ self.label_copyright = wx.StaticText(self, -1, config._copyright)
+ self.label_author = wx.StaticText(self, -1, "authors")
+ self.hyperlink = wx.lib.hyperlink.HyperLinkCtrl(self, -1,
+ config._homepage,
+ URL=config._homepage)
+ #self.hyperlink_license = wx.lib.hyperlink.HyperLinkCtrl(self, -1,
+ #"Comments? Bugs? Requests?", URL=config._paper)
+ self.hyperlink_license = wx.StaticText(self, -1,
+ "Comments? Bugs? Requests?")
+ self.hyperlink_paper = wx.lib.hyperlink.HyperLinkCtrl(self, -1,
+ "Send us a ticket",
+ URL=config._license)
+ self.hyperlink_download = wx.lib.hyperlink.HyperLinkCtrl(self, -1,
+ "Get the latest version",
+ URL=config._download)
+ self.static_line_1 = wx.StaticLine(self, -1)
+ self.label_acknowledgement = wx.StaticText(self, -1,
+ config._acknowledgement)
+ self.static_line_2 = wx.StaticLine(self, -1)
+ self.bitmap_button_nist = wx.BitmapButton(self, -1, wx.NullBitmap)
+ self.bitmap_button_umd = wx.BitmapButton(self, -1, wx.NullBitmap)
+ self.bitmap_button_ornl = wx.BitmapButton(self, -1, wx.NullBitmap)
+ #self.bitmap_button_sns = wx.BitmapButton(self, -1, wx.NullBitmap)
+ #self.bitmap_button_nsf = wx.BitmapButton(self, -1,
+ # wx.NullBitmap)
+ #self.bitmap_button_danse = wx.BitmapButton(self, -1, wx.NullBitmap)
+ self.bitmap_button_msu = wx.BitmapButton(self, -1, wx.NullBitmap)
+
+ self.bitmap_button_isis = wx.BitmapButton(self, -1, wx.NullBitmap)
+ self.bitmap_button_ess = wx.BitmapButton(self, -1, wx.NullBitmap)
+ self.bitmap_button_ill = wx.BitmapButton(self, -1, wx.NullBitmap)
+ self.bitmap_button_ansto = wx.BitmapButton(self, -1, wx.NullBitmap)
+ self.bitmap_button_tudelft = wx.BitmapButton(self, -1, wx.NullBitmap)
+ self.bitmap_button_dls = wx.BitmapButton(self, -1, wx.NullBitmap)
+
+ self.static_line_3 = wx.StaticLine(self, -1)
+ self.button_OK = wx.Button(self, wx.ID_OK, "OK")
+
+ self.__set_properties()
+ self.__do_layout()
+
+ self.Bind(wx.EVT_BUTTON, self.onNistLogo, self.bitmap_button_nist)
+ self.Bind(wx.EVT_BUTTON, self.onUmdLogo, self.bitmap_button_umd)
+ #self.Bind(wx.EVT_BUTTON, self.onSnsLogo, self.bitmap_button_sns)
+ self.Bind(wx.EVT_BUTTON, self.onOrnlLogo, self.bitmap_button_ornl)
+ #self.Bind(wx.EVT_BUTTON, self.onNsfLogo, self.bitmap_button_nsf)
+ #self.Bind(wx.EVT_BUTTON, self.onDanseLogo, self.bitmap_button_danse)
+ self.Bind(wx.EVT_BUTTON, self.onUTLogo, self.bitmap_button_msu)
+ self.Bind(wx.EVT_BUTTON, self.onIsisLogo, self.bitmap_button_isis)
+ self.Bind(wx.EVT_BUTTON, self.onEssLogo, self.bitmap_button_ess)
+ self.Bind(wx.EVT_BUTTON, self.onIllLogo, self.bitmap_button_ill)
+ self.Bind(wx.EVT_BUTTON, self.onAnstoLogo, self.bitmap_button_ansto)
+ self.Bind(wx.EVT_BUTTON, self.onTudelftLogo, self.bitmap_button_tudelft)
+ self.Bind(wx.EVT_BUTTON, self.onDlsLogo, self.bitmap_button_dls)
+ # end wxGlade
+ # fill in acknowledgements
+ #self.text_ctrl_acknowledgement.SetValue(__acknowledgement__)
+ # randomly shuffle authors' names
+ random.shuffle(config._authors)
+ strLabel = ", ".join(config._authors)
+
+ # display version and svn revison numbers
+ verwords = config.__version__.split('.')
+ version = '.'.join(verwords[:-1])
+ revision = verwords[-1]
+ try:
+ build_num = str(config.__build__)
+ except:
+ build_num = str(config.__version__)
+ self.label_author.SetLabel(strLabel)
+ self.label_version.SetLabel(config.__version__)#(version)
+ self.label_svnrevision.SetLabel(build_num)
+
+ # set bitmaps for logo buttons
+ image = file_dir + "/images/nist_logo.png"
+ if os.path.isfile(config._nist_logo):
+ image = config._nist_logo
+ logo = wx.Bitmap(image)
+ self.bitmap_button_nist.SetBitmapLabel(logo)
+
+ image = file_dir + "/images/umd_logo.png"
+ if os.path.isfile(config._umd_logo):
+ image = config._umd_logo
+ logo = wx.Bitmap(image)
+ self.bitmap_button_umd.SetBitmapLabel(logo)
+
+ image = file_dir + "/images/ornl_logo.png"
+ if os.path.isfile(config._ornl_logo):
+ image = config._ornl_logo
+ logo = wx.Bitmap(image)
+ self.bitmap_button_ornl.SetBitmapLabel(logo)
+
+ """
+ image = file_dir + "/images/sns_logo.png"
+ if os.path.isfile(config._sns_logo):
+ image = config._sns_logo
+ logo = wx.Bitmap(image)
+ self.bitmap_button_sns.SetBitmapLabel(logo)
+
+ image = file_dir + "/images/nsf_logo.png"
+ if os.path.isfile(config._nsf_logo):
+ image = config._nsf_logo
+ logo = wx.Bitmap(image)
+ self.bitmap_button_nsf.SetBitmapLabel(logo)
+
+ image = file_dir + "/images/danse_logo.png"
+ if os.path.isfile(config._danse_logo):
+ image = config._danse_logo
+ logo = wx.Bitmap(image)
+ self.bitmap_button_danse.SetBitmapLabel(logo)
+ """
+ image = file_dir + "/images/utlogo.png"
+ if os.path.isfile(config._inst_logo):
+ image = config._inst_logo
+ logo = wx.Bitmap(image)
+ self.bitmap_button_msu.SetBitmapLabel(logo)
+
+ image = file_dir + "/images/isis_logo.png"
+ if os.path.isfile(config._isis_logo):
+ image = config._isis_logo
+ logo = wx.Bitmap(image)
+ self.bitmap_button_isis.SetBitmapLabel(logo)
+
+ image = file_dir + "/images/ess_logo.png"
+ if os.path.isfile(config._ess_logo):
+ image = config._ess_logo
+ logo = wx.Bitmap(image)
+ self.bitmap_button_ess.SetBitmapLabel(logo)
+
+ image = file_dir + "/images/ill_logo.png"
+ if os.path.isfile(config._ill_logo):
+ image = config._ill_logo
+ logo = wx.Bitmap(image)
+ self.bitmap_button_ill.SetBitmapLabel(logo)
+
+ image = file_dir + "/images/ansto_logo.png"
+ if os.path.isfile(config._ansto_logo):
+ image = config._ansto_logo
+ logo = wx.Bitmap(image)
+ self.bitmap_button_ansto.SetBitmapLabel(logo)
+
+ image = file_dir + "/images/tudelft_logo.png"
+ if os.path.isfile(config._tudelft_logo):
+ image = config._tudelft_logo
+ logo = wx.Bitmap(image)
+ self.bitmap_button_tudelft.SetBitmapLabel(logo)
+
+ image = file_dir + "/images/dls_logo.png"
+ if os.path.isfile(config._dls_logo):
+ image = config._dls_logo
+ logo = wx.Bitmap(image)
+ self.bitmap_button_dls.SetBitmapLabel(logo)
+
+ # resize dialog window to fit version number nicely
+ if wx.VERSION >= (2, 7, 2, 0):
+ size = [self.GetEffectiveMinSize()[0], self.GetSize()[1]]
+ else:
+ size = [self.GetBestFittingSize()[0], self.GetSize()[1]]
+ self.Fit()
+
+ def __set_properties(self):
+ """
+ """
+ # begin wxGlade: DialogAbout.__set_properties
+ self.SetTitle("About")
+ self.SetSize((600, 595))
+ self.label_title.SetFont(wx.Font(26, wx.DEFAULT, wx.NORMAL,
+ wx.BOLD, 0, ""))
+ self.label_version.SetFont(wx.Font(26, wx.DEFAULT, wx.NORMAL,
+ wx.NORMAL, 0, ""))
+ self.hyperlink_paper.Enable(True)
+ self.bitmap_button_nist.SetSize(self.bitmap_button_nist.GetBestSize())
+ self.bitmap_button_umd.SetSize(self.bitmap_button_umd.GetBestSize())
+ self.bitmap_button_ornl.SetSize(self.bitmap_button_ornl.GetBestSize())
+ #self.bitmap_button_sns.SetSize(self.bitmap_button_sns.GetBestSize())
+ #self.bitmap_button_nsf.SetSize(self.bitmap_button_nsf.GetBestSize())
+ #self.bitmap_button_danse.SetSize(self.bitmap_button_danse.GetBestSize())
+ self.bitmap_button_msu.SetSize(self.bitmap_button_msu.GetBestSize())
+ self.bitmap_button_isis.SetSize(self.bitmap_button_isis.GetBestSize())
+ self.bitmap_button_ess.SetSize(self.bitmap_button_ess.GetBestSize())
+ self.bitmap_button_ill.SetSize(self.bitmap_button_ill.GetBestSize())
+ self.bitmap_button_ansto.SetSize(self.bitmap_button_ansto.GetBestSize())
+ self.bitmap_button_tudelft.SetSize(self.bitmap_button_tudelft.GetBestSize())
+ self.bitmap_button_dls.SetSize(self.bitmap_button_dls.GetBestSize())
+ # end wxGlade
+
+ def __do_layout(self):
+ """
+ """
+ # begin wxGlade: DialogAbout.__do_layout
+ sizer_main = wx.BoxSizer(wx.VERTICAL)
+ sizer_button = wx.BoxSizer(wx.HORIZONTAL)
+ sizer_logos = wx.BoxSizer(wx.HORIZONTAL)
+ sizer_header = wx.BoxSizer(wx.HORIZONTAL)
+ sizer_titles = wx.BoxSizer(wx.VERTICAL)
+ sizer_build = wx.BoxSizer(wx.HORIZONTAL)
+ sizer_title = wx.BoxSizer(wx.HORIZONTAL)
+ sizer_header.Add(self.bitmap_logo, 0, wx.EXPAND, 0)
+ sizer_title.Add(self.label_title, 0,
+ wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 10)
+ sizer_title.Add((20, 20), 0, wx.EXPAND|wx.ADJUST_MINSIZE, 0)
+ sizer_title.Add(self.label_version, 0,
+ wx.RIGHT|wx.ALIGN_BOTTOM|wx.ADJUST_MINSIZE, 10)
+ sizer_titles.Add(sizer_title, 0, wx.EXPAND, 0)
+ sizer_build.Add(self.label_build, 0,
+ wx.LEFT|wx.RIGHT|wx.ADJUST_MINSIZE, 10)
+ sizer_build.Add(self.label_svnrevision, 0, wx.ADJUST_MINSIZE, 0)
+ sizer_titles.Add(sizer_build, 0, wx.TOP|wx.EXPAND, 5)
+ sizer_titles.Add(self.label_copyright, 0,
+ wx.LEFT|wx.RIGHT|wx.TOP|wx.ADJUST_MINSIZE, 10)
+ sizer_titles.Add(self.label_author, 0,
+ wx.LEFT|wx.RIGHT|wx.ADJUST_MINSIZE, 10)
+ sizer_titles.Add(self.hyperlink, 0, wx.LEFT|wx.RIGHT, 10)
+ sizer_titles.Add((20, 20), 0, wx.ADJUST_MINSIZE, 0)
+ sizer_titles.Add(self.hyperlink_license, 0, wx.LEFT|wx.RIGHT, 10)
+ sizer_titles.Add(self.hyperlink_paper, 0, wx.LEFT|wx.RIGHT, 10)
+ sizer_titles.Add((20, 20), 0, wx.ADJUST_MINSIZE, 0)
+ sizer_titles.Add(self.hyperlink_download, 0, wx.LEFT|wx.RIGHT, 10)
+ sizer_header.Add(sizer_titles, 0, wx.EXPAND, 0)
+ sizer_main.Add(sizer_header, 0, wx.BOTTOM|wx.EXPAND, 3)
+ sizer_main.Add(self.static_line_1, 0, wx.EXPAND, 0)
+ sizer_main.Add(self.label_acknowledgement, 0,
+ wx.LEFT|wx.TOP|wx.BOTTOM|wx.ADJUST_MINSIZE, 7)
+ sizer_main.Add(self.static_line_2, 0, wx.EXPAND, 0)
+
+ sizer_logos.Add(self.bitmap_button_msu, 0,
+ wx.LEFT|wx.ADJUST_MINSIZE, 2)
+ #sizer_logos.Add(self.bitmap_button_danse, 0,
+ # wx.LEFT|wx.ADJUST_MINSIZE, 2)
+ #sizer_logos.Add(self.bitmap_button_nsf, 0,
+ # wx.LEFT|wx.ADJUST_MINSIZE, 2)
+ sizer_logos.Add(self.bitmap_button_umd, 0,
+ wx.LEFT|wx.ADJUST_MINSIZE, 2)
+ sizer_logos.Add(self.bitmap_button_nist, 0,
+ wx.LEFT|wx.ADJUST_MINSIZE, 2)
+ #sizer_logos.Add(self.bitmap_button_sns, 0,
+ # wx.LEFT|wx.ADJUST_MINSIZE, 2)
+ sizer_logos.Add(self.bitmap_button_ornl, 0,
+ wx.LEFT|wx.ADJUST_MINSIZE, 2)
+ sizer_logos.Add(self.bitmap_button_isis, 0,
+ wx.LEFT|wx.ADJUST_MINSIZE, 2)
+ sizer_logos.Add(self.bitmap_button_ess, 0,
+ wx.LEFT|wx.ADJUST_MINSIZE, 2)
+ sizer_logos.Add(self.bitmap_button_ill, 0,
+ wx.LEFT|wx.ADJUST_MINSIZE, 2)
+ sizer_logos.Add(self.bitmap_button_ansto, 0,
+ wx.LEFT|wx.ADJUST_MINSIZE, 2)
+ sizer_logos.Add(self.bitmap_button_tudelft, 0,
+ wx.LEFT|wx.ADJUST_MINSIZE, 2)
+ sizer_logos.Add(self.bitmap_button_dls, 0,
+ wx.LEFT|wx.ADJUST_MINSIZE, 2)
+
+ sizer_logos.Add((10, 50), 0, wx.ADJUST_MINSIZE, 0)
+ sizer_main.Add(sizer_logos, 0, wx.EXPAND, 0)
+ sizer_main.Add(self.static_line_3, 0, wx.EXPAND, 0)
+ sizer_button.Add((20, 40), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0)
+ sizer_button.Add(self.button_OK, 0,
+ wx.RIGHT|wx.ADJUST_MINSIZE|wx.CENTER, 10)
+ sizer_main.Add(sizer_button, 0, wx.EXPAND, 0)
+ self.SetAutoLayout(True)
+ self.SetSizer(sizer_main)
+ self.Layout()
+ self.Centre()
+ # end wxGlade
+
+ def onNistLogo(self, event):
+ """
+ """
+ # wxGlade: DialogAbout.<event_handler>
+ launchBrowser(config._nist_url)
+ event.Skip()
+
+ def onUmdLogo(self, event):
+ """
+ """
+ # wxGlade: DialogAbout.<event_handler>
+ launchBrowser(config._umd_url)
+ event.Skip()
+
+ def onOrnlLogo(self, event):
+ """
+ """
+ # wxGlade: DialogAbout.<event_handler>
+ launchBrowser(config._ornl_url)
+ event.Skip()
+
+ def onSnsLogo(self, event):
+ """
+ """
+ # wxGlade: DialogAbout.<event_handler>
+ launchBrowser(config._sns_url)
+ event.Skip()
+
+ def onNsfLogo(self, event):
+ """
+ """
+ # wxGlade: DialogAbout.<event_handler>
+ launchBrowser(config._nsf_url)
+ event.Skip()
+
+ def onDanseLogo(self, event):
+ """
+ """
+ # wxGlade: DialogAbout.<event_handler>
+ launchBrowser(config._danse_url)
+ event.Skip()
+
+ def onUTLogo(self, event):
+ """
+ """
+ # wxGlade: DialogAbout.<event_handler>
+ launchBrowser(config._inst_url)
+ event.Skip()
+
+ def onIsisLogo(self, event):
+ """
+ """
+ # wxGlade: DialogAbout.<event_handler>
+ launchBrowser(config._isis_url)
+ event.Skip()
+
+ def onEssLogo(self, event):
+ """
+ """
+ # wxGlade: DialogAbout.<event_handler>
+ launchBrowser(config._ess_url)
+ event.Skip()
+
+ def onIllLogo(self, event):
+ """
+ """
+ # wxGlade: DialogAbout.<event_handler>
+ launchBrowser(config._ill_url)
+ event.Skip()
+
+ def onAnstoLogo(self, event):
+ """
+ """
+ # wxGlade: DialogAbout.<event_handler>
+ launchBrowser(config._ansto_url)
+ event.Skip()
+
+ def onTudelftLogo(self, event):
+ """
+ """
+ # wxGlade: DialogAbout.<event_handler>
+ launchBrowser(config._tudelft_url)
+ event.Skip()
+
+ def onDlsLogo(self, event):
+ """
+ """
+ # wxGlade: DialogAbout.<event_handler>
+ launchBrowser(config._dls_url)
+ event.Skip()
+
+# end of class DialogAbout
+
+##### testing code ############################################################
+class MyApp(wx.App):
+ """
+ """
+ def OnInit(self):
+ """
+ """
+ wx.InitAllImageHandlers()
+ dialog = DialogAbout(None, -1, "")
+ self.SetTopWindow(dialog)
+ dialog.ShowModal()
+ dialog.Destroy()
+ return 1
+
+# end of class MyApp
+
+if __name__ == "__main__":
+ app = MyApp(0)
+ app.MainLoop()
+
+##### end of testing code #####################################################
diff --git a/src/sas/sasgui/guiframe/acknowledgebox.py b/src/sas/sasgui/guiframe/acknowledgebox.py
index aff52d0..2b1435e 100644
--- a/src/sas/sasgui/guiframe/acknowledgebox.py
+++ b/src/sas/sasgui/guiframe/acknowledgebox.py
@@ -11,24 +11,9 @@ import wx
import wx.richtext
import wx.lib.hyperlink
from wx.lib.expando import ExpandoTextCtrl
-import random
-import os.path
-import os
-try:
- # Try to find a local config
- import imp
- path = os.getcwd()
- if(os.path.isfile("%s/%s.py" % (path, 'local_config'))) or \
- (os.path.isfile("%s/%s.pyc" % (path, 'local_config'))):
- fObj, path, descr = imp.find_module('local_config', [path])
- config = imp.load_module('local_config', fObj, path, descr)
- else:
- # Try simply importing local_config
- import local_config as config
-except:
- # Didn't find local config, load the default
- import config
+from sas import get_local_config
+config = get_local_config()
class DialogAcknowledge(wx.Dialog):
"""
diff --git a/src/sas/sasgui/guiframe/config.py b/src/sas/sasgui/guiframe/config.py
index bc10603..75d8e9a 100644
--- a/src/sas/sasgui/guiframe/config.py
+++ b/src/sas/sasgui/guiframe/config.py
@@ -1,11 +1,16 @@
"""
- Application settings
+Application settings
"""
+from __future__ import print_function
+
import time
import os
+import logging
+
from sas.sasgui.guiframe.gui_style import GUIFRAME
import sas.sasview
-import logging
+
+logger = logging.getLogger(__name__)
# Version of the application
__appname__ = "SasView"
@@ -45,7 +50,7 @@ _acknowledgement_citation = \
'''M. Doucet et al. SasView Version 4.1.2, Zenodo, 10.5281/zenodo.825675'''
_acknowledgement = \
-'''This work was originally developed as part of the DANSE project funded by the US NSF under Award DMR-0520547,\n but is currently maintained by a collaboration between UTK, UMD, NIST, ORNL, ISIS, ESS, ILL, ANSTO and TU Delft and the scattering community.\n\n SasView also contains code developed with funding from the EU Horizon 2020 programme under the SINE2020 project (Grant No 654000).\nA list of individual contributors can be found at: https://github.com/orgs/SasView/people
+'''This work was originally developed as part of the DANSE project funded by the US NSF under Award DMR-0520547,\n but is currently maintained by a collaboration between UTK, UMD, NIST, ORNL, ISIS, ESS, ILL, ANSTO, TU Delft, DLS, and the scattering community.\n\n SasView also contains code developed with funding from the EU Horizon 2020 programme under the SINE2020 project (Grant No 654000).\nA list of individual contributors can be found at: http://www.sasview.org/contact.html
'''
_homepage = "http://www.sasview.org"
@@ -56,7 +61,7 @@ _license = "mailto:help at sasview.org"
icon_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "images"))
-logging.info("icon path: %s" % icon_path)
+logger.info("icon path: %s" % icon_path)
media_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "media"))
test_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "test"))
@@ -69,9 +74,10 @@ _ess_logo = os.path.join(icon_path, "ess_logo.png")
_ill_logo = os.path.join(icon_path, "ill_logo.png")
_ansto_logo = os.path.join(icon_path, "ansto_logo.png")
_tudelft_logo = os.path.join(icon_path, "tudelft_logo.png")
+_dls_logo = os.path.join(icon_path, "dls_logo.png")
_nsf_logo = os.path.join(icon_path, "nsf_logo.png")
_danse_logo = os.path.join(icon_path, "danse_logo.png")
-_inst_logo = os.path.join(icon_path, "utlogo.gif")
+_inst_logo = os.path.join(icon_path, "utlogo.png")
_nist_url = "http://www.nist.gov/"
_umd_url = "http://www.umd.edu/"
_sns_url = "http://neutrons.ornl.gov/"
@@ -82,11 +88,12 @@ _ess_url = "http://ess-scandinavia.eu/"
_ill_url = "http://www.ill.eu/"
_ansto_url = "http://www.ansto.gov.au/"
_tudelft_url = "http://www.tnw.tudelft.nl/en/cooperation/facilities/reactor-instituut-delft/"
+_dls_url = "http://www.diamond.ac.uk/"
_danse_url = "http://www.cacr.caltech.edu/projects/danse/release/index.html"
_inst_url = "http://www.utk.edu"
_corner_image = os.path.join(icon_path, "angles_flat.png")
_welcome_image = os.path.join(icon_path, "SVwelcome.png")
-_copyright = "(c) 2009 - 2017, UTK, UMD, NIST, ORNL, ISIS, ESS, ILL, ANSTO and TU Delft"
+_copyright = "(c) 2009 - 2017, UTK, UMD, NIST, ORNL, ISIS, ESS, ILL, ANSTO, TU Delft, and DLS"
marketplace_url = "http://marketplace.sasview.org/"
#edit the list of file state your plugin can read
@@ -137,15 +144,12 @@ DEFAULT_PERSPECTIVE = 'None'
# Time out for updating sasview
UPDATE_TIMEOUT = 2
-#OpenCL option
-SAS_OPENCL = None
-
def printEVT(message):
if __EVT_DEBUG__:
"""
:TODO - Need method doc string
"""
- print "%g: %s" % (time.clock(), message)
+ print("%g: %s" % (time.clock(), message))
if __EVT_DEBUG_2_FILE__:
out = open(__EVT_DEBUG_FILENAME__, 'a')
diff --git a/src/sas/sasgui/guiframe/custom_pstats.py b/src/sas/sasgui/guiframe/custom_pstats.py
index 139d17f..4b05e19 100644
--- a/src/sas/sasgui/guiframe/custom_pstats.py
+++ b/src/sas/sasgui/guiframe/custom_pstats.py
@@ -1,118 +1,118 @@
-
-import cProfile, pstats, os
-def func_std_string(func_name): # match what old profile produced
- if func_name[:2] == ('~', 0):
- # special case for built-in functions
- name = func_name[2]
- if name.startswith('<') and name.endswith('>'):
- return '{%s}' % name[1:-1]
- else:
- return name
- else:
- return "%s:%d(%s)" % func_name
-
-def f8(x):
- return "%8.3f" % x
-
-class CustomPstats(pstats.Stats):
- def __init__(self, *args, **kwds):
- pstats.Stats.__init__(self, *args, **kwds)
-
- def write_stats(self, *amount):
- msg = ''
- for filename in self.files:
- msg += str(filename) + '\n'
- #if self.files: msg += str(self.stream) + '\n'
- indent = ' ' * 8
- for func in self.top_level:
- msg += str(indent)+ str(func_get_function_name(func))+"\n"
-
- msg += str(indent) + str(self.total_calls)+ "function calls" + '\n'
- if self.total_calls != self.prim_calls:
- msg += "(%d primitive calls)" % self.prim_calls + '\n'
- msg += "in %.3f CPU seconds" % self.total_tt + '\n'
- #msg += str(self.stream) + '\n'
-
- width = self.max_name_len
- if self.fcn_list:
- list = self.fcn_list[:]
- temp_msg = " Ordered by: " + self.sort_type + '\n'
- else:
- list = self.stats.keys()
- temp_msg = " Random listing order was used\n"
-
- for selection in amount:
- list, temp_msg = self.eval_print_amount(selection, list, temp_msg)
-
- count = len(list)
-
- if not list:
- width, list = 0, list
- else:
- msg += str(temp_msg) + '\n'
- if count < len(self.stats):
- width = 0
- for func in list:
- if len(func_std_string(func)) > width:
- width = len(func_std_string(func))
-
- width, list = width+2, list
- if list:
- msg += ' ncalls tottime percall cumtime percall'
- msg += ' filename:lineno(function)' + "\n"
- for func in list:
- cc, nc, tt, ct, callers = self.stats[func]
- c = str(nc)
- if nc != cc:
- c = c + '/' + str(cc)
- msg += str( c.rjust(9))
- msg += str(f8(tt))
- if nc == 0:
- msg += str(' '*8)
- else:
- msg += str(f8(tt/nc))
- msg += str(f8(ct))
- if cc == 0:
- msg += str( ' '*80)
- else:
- msg += str(f8(ct/cc))
- msg += " " + str(func_std_string(func)) + '\n'
- msg += str(self.stream) + '\n'
- #msg += str(self.stream) + '\n'
- return self, msg
-
-def profile( fn, name='profile.txt',*args, **kw):
- import cProfile, pstats, os
- global call_result
- def call():
- global call_result
- call_result = fn(*args, **kw)
- cProfile.runctx('call()', dict(call=call), {}, 'profile.txt')
- stats = CustomPstats('profile.txt')
- #sort by cumlative time
- stats.sort_stats('time')
- stats.print_stats(50)
- """
- filename = 'profile_cum_' + name
- _, msg = stats.write_stats(50)
- f = file(filename, 'wb')
- f.write(msg)
- f.close()
- #sort by time
- stats.sort_stats('time')
- _, msg = stats.write_stats(50)
- filename = 'profile_time_' + name
- f = file(filename, 'wb')
- f.write(msg)
- f.close()
- # sort by number of calls
- stats.sort_stats('call')
- _, msg = stats.write_stats(50)
- filename = 'profile_call_' + name
- f = file(filename, 'wb')
- f.write(msg)
- f.close()
- os.unlink('profile.txt')
- """
- return call_result
-
+
+import cProfile, pstats, os
+def func_std_string(func_name): # match what old profile produced
+ if func_name[:2] == ('~', 0):
+ # special case for built-in functions
+ name = func_name[2]
+ if name.startswith('<') and name.endswith('>'):
+ return '{%s}' % name[1:-1]
+ else:
+ return name
+ else:
+ return "%s:%d(%s)" % func_name
+
+def f8(x):
+ return "%8.3f" % x
+
+class CustomPstats(pstats.Stats):
+ def __init__(self, *args, **kwds):
+ pstats.Stats.__init__(self, *args, **kwds)
+
+ def write_stats(self, *amount):
+ msg = ''
+ for filename in self.files:
+ msg += str(filename) + '\n'
+ #if self.files: msg += str(self.stream) + '\n'
+ indent = ' ' * 8
+ for func in self.top_level:
+ msg += str(indent)+ str(func_get_function_name(func))+"\n"
+
+ msg += str(indent) + str(self.total_calls)+ "function calls" + '\n'
+ if self.total_calls != self.prim_calls:
+ msg += "(%d primitive calls)" % self.prim_calls + '\n'
+ msg += "in %.3f CPU seconds" % self.total_tt + '\n'
+ #msg += str(self.stream) + '\n'
+
+ width = self.max_name_len
+ if self.fcn_list:
+ list = self.fcn_list[:]
+ temp_msg = " Ordered by: " + self.sort_type + '\n'
+ else:
+ list = self.stats.keys()
+ temp_msg = " Random listing order was used\n"
+
+ for selection in amount:
+ list, temp_msg = self.eval_print_amount(selection, list, temp_msg)
+
+ count = len(list)
+
+ if not list:
+ width, list = 0, list
+ else:
+ msg += str(temp_msg) + '\n'
+ if count < len(self.stats):
+ width = 0
+ for func in list:
+ if len(func_std_string(func)) > width:
+ width = len(func_std_string(func))
+
+ width, list = width+2, list
+ if list:
+ msg += ' ncalls tottime percall cumtime percall'
+ msg += ' filename:lineno(function)' + "\n"
+ for func in list:
+ cc, nc, tt, ct, callers = self.stats[func]
+ c = str(nc)
+ if nc != cc:
+ c = c + '/' + str(cc)
+ msg += str( c.rjust(9))
+ msg += str(f8(tt))
+ if nc == 0:
+ msg += str(' '*8)
+ else:
+ msg += str(f8(tt/nc))
+ msg += str(f8(ct))
+ if cc == 0:
+ msg += str( ' '*80)
+ else:
+ msg += str(f8(ct/cc))
+ msg += " " + str(func_std_string(func)) + '\n'
+ msg += str(self.stream) + '\n'
+ #msg += str(self.stream) + '\n'
+ return self, msg
+
+def profile( fn, name='profile.txt',*args, **kw):
+ import cProfile, pstats, os
+ global call_result
+ def call():
+ global call_result
+ call_result = fn(*args, **kw)
+ cProfile.runctx('call()', dict(call=call), {}, 'profile.txt')
+ stats = CustomPstats('profile.txt')
+ #sort by cumlative time
+ stats.sort_stats('time')
+ stats.print_stats(50)
+ """
+ filename = 'profile_cum_' + name
+ _, msg = stats.write_stats(50)
+ f = file(filename, 'wb')
+ f.write(msg)
+ f.close()
+ #sort by time
+ stats.sort_stats('time')
+ _, msg = stats.write_stats(50)
+ filename = 'profile_time_' + name
+ f = file(filename, 'wb')
+ f.write(msg)
+ f.close()
+ # sort by number of calls
+ stats.sort_stats('call')
+ _, msg = stats.write_stats(50)
+ filename = 'profile_call_' + name
+ f = file(filename, 'wb')
+ f.write(msg)
+ f.close()
+ os.unlink('profile.txt')
+ """
+ return call_result
+
diff --git a/src/sas/sasgui/guiframe/customdir.py b/src/sas/sasgui/guiframe/customdir.py
deleted file mode 100644
index 4f2d03f..0000000
--- a/src/sas/sasgui/guiframe/customdir.py
+++ /dev/null
@@ -1,68 +0,0 @@
-# Setup and find Custom config dir
-import os.path
-import shutil
-
-CONF_DIR = 'config'
-APPLICATION_NAME = 'sasview'
-
-def _find_usersasview_dir():
- """
- Find and return user/.sasview dir
- """
- return os.path.join(os.path.expanduser("~"), ("." + APPLICATION_NAME))
-
-def _find_customconf_dir():
- """
- Find path of the config directory.
- The plugin directory is located in the user's home directory.
- """
- u_dir = _find_usersasview_dir()
- return os.path.join(u_dir, CONF_DIR)
-
-def _setup_conf_dir(path):
- """
- Setup the custom config dir and cat file
- """
- conf_dir = _find_customconf_dir()
- # If the plugin directory doesn't exist, create it
- if not os.path.isdir(conf_dir):
- os.makedirs(conf_dir)
- config_file = os.path.join(conf_dir, "custom_config.py")
-
- # Place example user models as needed
- try:
- if not os.path.isfile(config_file):
- shutil.copyfile(os.path.join(path, "custom_config.py"), config_file)
-
- #Adding SAS_OPENCL if it doesn't exist in the config file
- # - to support backcompability
- if not "SAS_OPENCL" in open(config_file).read():
- open(config_file,"a+").write("SAS_OPENCL = \"None\"\n")
- except:
- # Check for data path next to exe/zip file.
- #Look for maximum n_dir up of the current dir to find plugins dir
- n_dir = 12
- is_dir = False
- f_dir = path
- for i in range(n_dir):
- if i > 1:
- f_dir, _ = os.path.split(f_dir)
- temp_path = os.path.join(f_dir, "custom_config.py")
- if os.path.isfile(temp_path):
- shutil.copyfile(temp_path, config_file)
- is_dir = True
- break
- if not is_dir:
- raise
- return conf_dir
-
-
-class SetupCustom(object):
- """
- implement custom config dir
- """
- def find_dir(self):
- return _find_customconf_dir()
-
- def setup_dir(self, path):
- return _setup_conf_dir(path)
diff --git a/src/sas/sasgui/guiframe/dataFitting.py b/src/sas/sasgui/guiframe/dataFitting.py
index d10c994..573e855 100644
--- a/src/sas/sasgui/guiframe/dataFitting.py
+++ b/src/sas/sasgui/guiframe/dataFitting.py
@@ -1,511 +1,511 @@
-"""
-Adapters for fitting module
-"""
-import copy
-import numpy
-import math
-from sas.sascalc.data_util.uncertainty import Uncertainty
-from sas.sasgui.plottools.plottables import Data1D as PlotData1D
-from sas.sasgui.plottools.plottables import Data2D as PlotData2D
-from sas.sasgui.plottools.plottables import Theory1D as PlotTheory1D
-
-from sas.sascalc.dataloader.data_info import Data1D as LoadData1D
-from sas.sascalc.dataloader.data_info import Data2D as LoadData2D
-
-
-class Data1D(PlotData1D, LoadData1D):
- """
- """
-
- def __init__(self, x=None, y=None, dx=None, dy=None, lam=None, dlam=None, isSesans=False):
- """
- """
- if x is None:
- x = []
- if y is None:
- y = []
- self.isSesans = isSesans
- PlotData1D.__init__(self, x, y, dx, dy, lam, dlam)
- LoadData1D.__init__(self, x, y, dx, dy, lam, dlam, isSesans)
-
- self.id = None
- self.list_group_id = []
- self.group_id = None
- self.is_data = True
- self.path = None
- self.xtransform = None
- if self.isSesans:
- self.xtransform = "x"
- self.ytransform = None
- if self.isSesans:
- self.ytransform = "y"
- self.title = ""
- self.scale = None
-
- def copy_from_datainfo(self, data1d):
- """
- copy values of Data1D of type DataLaoder.Data_info
- """
- self.x = copy.deepcopy(data1d.x)
- self.y = copy.deepcopy(data1d.y)
- self.dy = copy.deepcopy(data1d.dy)
-
- if hasattr(data1d, "dx"):
- self.dx = copy.deepcopy(data1d.dx)
- if hasattr(data1d, "dxl"):
- self.dxl = copy.deepcopy(data1d.dxl)
- if hasattr(data1d, "dxw"):
- self.dxw = copy.deepcopy(data1d.dxw)
-
- self.xaxis(data1d._xaxis, data1d._xunit)
- self.yaxis(data1d._yaxis, data1d._yunit)
- self.title = data1d.title
-
- def __str__(self):
- """
- print data
- """
- _str = "%s\n" % LoadData1D.__str__(self)
-
- return _str
-
- def _perform_operation(self, other, operation):
- """
- """
- # First, check the data compatibility
- dy, dy_other = self._validity_check(other)
- result = Data1D(x=[], y=[], lam=[], dx=None, dy=None, dlam=None)
- result.clone_without_data(length=len(self.x), clone=self)
- result.copy_from_datainfo(data1d=self)
- if self.dxw == None:
- result.dxw = None
- else:
- result.dxw = numpy.zeros(len(self.x))
- if self.dxl == None:
- result.dxl = None
- else:
- result.dxl = numpy.zeros(len(self.x))
-
- for i in range(len(self.x)):
- result.x[i] = self.x[i]
- if self.dx is not None and len(self.x) == len(self.dx):
- result.dx[i] = self.dx[i]
- if self.dxw is not None and len(self.x) == len(self.dxw):
- result.dxw[i] = self.dxw[i]
- if self.dxl is not None and len(self.x) == len(self.dxl):
- result.dxl[i] = self.dxl[i]
-
- a = Uncertainty(self.y[i], dy[i]**2)
- if isinstance(other, Data1D):
- b = Uncertainty(other.y[i], dy_other[i]**2)
- if other.dx is not None:
- result.dx[i] *= self.dx[i]
- result.dx[i] += (other.dx[i]**2)
- result.dx[i] /= 2
- result.dx[i] = math.sqrt(result.dx[i])
- if result.dxl is not None and other.dxl is not None:
- result.dxl[i] *= self.dxl[i]
- result.dxl[i] += (other.dxl[i]**2)
- result.dxl[i] /= 2
- result.dxl[i] = math.sqrt(result.dxl[i])
- else:
- b = other
-
- output = operation(a, b)
- result.y[i] = output.x
- result.dy[i] = math.sqrt(math.fabs(output.variance))
- return result
-
- def _perform_union(self, other):
- """
- """
- # First, check the data compatibility
- self._validity_check_union(other)
- result = Data1D(x=[], y=[], lam=[], dx=None, dy=None, dlam=None)
- tot_length = len(self.x) + len(other.x)
- result = self.clone_without_data(length=tot_length, clone=result)
- if self.dlam == None or other.dlam is None:
- result.dlam = None
- else:
- result.dlam = numpy.zeros(tot_length)
- if self.dy == None or other.dy is None:
- result.dy = None
- else:
- result.dy = numpy.zeros(tot_length)
- if self.dx == None or other.dx is None:
- result.dx = None
- else:
- result.dx = numpy.zeros(tot_length)
- if self.dxw == None or other.dxw is None:
- result.dxw = None
- else:
- result.dxw = numpy.zeros(tot_length)
- if self.dxl == None or other.dxl is None:
- result.dxl = None
- else:
- result.dxl = numpy.zeros(tot_length)
-
- result.x = numpy.append(self.x, other.x)
- #argsorting
- ind = numpy.argsort(result.x)
- result.x = result.x[ind]
- result.y = numpy.append(self.y, other.y)
- result.y = result.y[ind]
- result.lam = numpy.append(self.lam, other.lam)
- result.lam = result.lam[ind]
- if result.dlam != None:
- result.dlam = numpy.append(self.dlam, other.dlam)
- result.dlam = result.dlam[ind]
- if result.dy != None:
- result.dy = numpy.append(self.dy, other.dy)
- result.dy = result.dy[ind]
- if result.dx is not None:
- result.dx = numpy.append(self.dx, other.dx)
- result.dx = result.dx[ind]
- if result.dxw is not None:
- result.dxw = numpy.append(self.dxw, other.dxw)
- result.dxw = result.dxw[ind]
- if result.dxl is not None:
- result.dxl = numpy.append(self.dxl, other.dxl)
- result.dxl = result.dxl[ind]
- return result
-
-
-
-class Theory1D(PlotTheory1D, LoadData1D):
- """
- """
- def __init__(self, x=None, y=None, dy=None):
- """
- """
- if x is None:
- x = []
- if y is None:
- y = []
- PlotTheory1D.__init__(self, x, y, dy)
- LoadData1D.__init__(self, x, y, dy)
- self.id = None
- self.list_group_id = []
- self.group_id = None
- self.is_data = True
- self.path = None
- self.xtransform = None
- self.ytransform = None
- self.title = ""
- self.scale = None
-
- def copy_from_datainfo(self, data1d):
- """
- copy values of Data1D of type DataLaoder.Data_info
- """
- self.x = copy.deepcopy(data1d.x)
- self.y = copy.deepcopy(data1d.y)
- self.dy = copy.deepcopy(data1d.dy)
- if hasattr(data1d, "dx"):
- self.dx = copy.deepcopy(data1d.dx)
- if hasattr(data1d, "dxl"):
- self.dxl = copy.deepcopy(data1d.dxl)
- if hasattr(data1d, "dxw"):
- self.dxw = copy.deepcopy(data1d.dxw)
- self.xaxis(data1d._xaxis, data1d._xunit)
- self.yaxis(data1d._yaxis, data1d._yunit)
- self.title = data1d.title
-
- def __str__(self):
- """
- print data
- """
- _str = "%s\n" % LoadData1D.__str__(self)
-
- return _str
-
- def _perform_operation(self, other, operation):
- """
- """
- # First, check the data compatibility
- dy, dy_other = self._validity_check(other)
- result = self.clone_without_data(len(self.x))
- result.copy_from_datainfo(data1d=self)
- if self.dxw == None:
- result.dxw = None
- else:
- result.dxw = numpy.zeros(len(self.x))
- if self.dxl == None:
- result.dxl = None
- else:
- result.dxl = numpy.zeros(len(self.x))
-
- for i in range(numpy.size(self.x)):
- result.x[i] = self.x[i]
- if self.dx is not None and len(self.x) == len(self.dx):
- result.dx[i] = self.dx[i]
- if self.dxw is not None and len(self.x) == len(self.dxw):
- result.dxw[i] = self.dxw[i]
- if self.dxl is not None and len(self.x) == len(self.dxl):
- result.dxl[i] = self.dxl[i]
-
- a = Uncertainty(self.y[i], dy[i]**2)
- if isinstance(other, Data1D):
- b = Uncertainty(other.y[i], dy_other[i]**2)
- if other.dx is not None:
- result.dx[i] *= self.dx[i]
- result.dx[i] += (other.dx[i]**2)
- result.dx[i] /= 2
- result.dx[i] = math.sqrt(result.dx[i])
- if result.dxl is not None and other.dxl is not None:
- result.dxl[i] *= self.dxl[i]
- other.dxl[i] += (other.dxl[i]**2)
- result.dxl[i] /= 2
- result.dxl[i] = math.sqrt(result.dxl[i])
- if result.dxw is not None and self.dxw is not None:
- result.dxw[i] *= self.dxw[i]
- other.dxw[i] += (other.dxw[i]**2)
- result.dxw[i] /= 2
- result.dxw[i] = math.sqrt(result.dxw[i])
- else:
- b = other
-
- output = operation(a, b)
- result.y[i] = output.x
- result.dy[i] = math.sqrt(math.fabs(output.variance))
- return result
-
- def _perform_union(self, other):
- """
- """
- # First, check the data compatibility
- self._validity_check_union(other)
- result = Data1D(x=[], y=[], lam=[], dx=None, dy=None, dlam=[])
- tot_length = len(self.x)+len(other.x)
- result.clone_without_data(length=tot_length, clone=self)
- if self.dlam == None or other.dlam is None:
- result.dlam = None
- else:
- result.dlam = numpy.zeros(tot_length)
- if self.dy == None or other.dy is None:
- result.dy = None
- else:
- result.dy = numpy.zeros(tot_length)
- if self.dx == None or other.dx is None:
- result.dx = None
- else:
- result.dx = numpy.zeros(tot_length)
- if self.dxw == None or other.dxw is None:
- result.dxw = None
- else:
- result.dxw = numpy.zeros(tot_length)
- if self.dxl == None or other.dxl is None:
- result.dxl = None
- else:
- result.dxl = numpy.zeros(tot_length)
- result.x = numpy.append(self.x, other.x)
- #argsorting
- ind = numpy.argsort(result.x)
- result.x = result.x[ind]
- result.y = numpy.append(self.y, other.y)
- result.y = result.y[ind]
- result.lam = numpy.append(self.lam, other.lam)
- result.lam = result.lam[ind]
- if result.dy != None:
- result.dy = numpy.append(self.dy, other.dy)
- result.dy = result.dy[ind]
- if result.dx is not None:
- result.dx = numpy.append(self.dx, other.dx)
- result.dx = result.dx[ind]
- if result.dxw is not None:
- result.dxw = numpy.append(self.dxw, other.dxw)
- result.dxw = result.dxw[ind]
- if result.dxl is not None:
- result.dxl = numpy.append(self.dxl, other.dxl)
- result.dxl = result.dxl[ind]
- return result
-
-
-class Data2D(PlotData2D, LoadData2D):
- """
- """
- def __init__(self, image=None, err_image=None,
- qx_data=None, qy_data=None, q_data=None,
- mask=None, dqx_data=None, dqy_data=None,
- xmin=None, xmax=None, ymin=None, ymax=None,
- zmin=None, zmax=None):
- """
- """
- PlotData2D.__init__(self, image=image, err_image=err_image,
- xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax,
- zmin=zmin, zmax=zmax, qx_data=qx_data,
- qy_data=qy_data)
-
- LoadData2D.__init__(self, data=image, err_data=err_image,
- qx_data=qx_data, qy_data=qy_data,
- dqx_data=dqx_data, dqy_data=dqy_data,
- q_data=q_data, mask=mask)
- self.id = None
- self.list_group_id = []
- self.group_id = None
- self.is_data = True
- self.path = None
- self.xtransform = None
- self.ytransform = None
- self.title = ""
- self.scale = None
-
- def copy_from_datainfo(self, data2d):
- """
- copy value of Data2D of type DataLoader.data_info
- """
- self.data = copy.deepcopy(data2d.data)
- self.qx_data = copy.deepcopy(data2d.qx_data)
- self.qy_data = copy.deepcopy(data2d.qy_data)
- self.q_data = copy.deepcopy(data2d.q_data)
- self.mask = copy.deepcopy(data2d.mask)
- self.err_data = copy.deepcopy(data2d.err_data)
- self.x_bins = copy.deepcopy(data2d.x_bins)
- self.y_bins = copy.deepcopy(data2d.y_bins)
- if data2d.dqx_data is not None:
- self.dqx_data = copy.deepcopy(data2d.dqx_data)
- if data2d.dqy_data is not None:
- self.dqy_data = copy.deepcopy(data2d.dqy_data)
- self.xmin = data2d.xmin
- self.xmax = data2d.xmax
- self.ymin = data2d.ymin
- self.ymax = data2d.ymax
- if hasattr(data2d, "zmin"):
- self.zmin = data2d.zmin
- if hasattr(data2d, "zmax"):
- self.zmax = data2d.zmax
- self.xaxis(data2d._xaxis, data2d._xunit)
- self.yaxis(data2d._yaxis, data2d._yunit)
- self.title = data2d.title
-
- def __str__(self):
- """
- print data
- """
- _str = "%s\n" % LoadData2D.__str__(self)
- return _str
-
- def _perform_operation(self, other, operation):
- """
- Perform 2D operations between data sets
-
- :param other: other data set
- :param operation: function defining the operation
-
- """
- # First, check the data compatibility
- dy, dy_other = self._validity_check(other)
- result = Data2D(image=None, qx_data=None, qy_data=None,
- q_data=None, err_image=None, xmin=None, xmax=None,
- ymin=None, ymax=None, zmin=None, zmax=None)
- result.clone_without_data(len(self.data))
- result.copy_from_datainfo(data2d=self)
- result.xmin = self.xmin
- result.xmax = self.xmax
- result.ymin = self.ymin
- result.ymax = self.ymax
- if self.dqx_data == None or self.dqy_data == None:
- result.dqx_data = None
- result.dqy_data = None
- else:
- result.dqx_data = numpy.zeros(len(self.data))
- result.dqy_data = numpy.zeros(len(self.data))
- for i in range(numpy.size(self.data)):
- result.data[i] = self.data[i]
- if self.err_data is not None and \
- numpy.size(self.data) == numpy.size(self.err_data):
- result.err_data[i] = self.err_data[i]
- if self.dqx_data is not None:
- result.dqx_data[i] = self.dqx_data[i]
- if self.dqy_data is not None:
- result.dqy_data[i] = self.dqy_data[i]
- result.qx_data[i] = self.qx_data[i]
- result.qy_data[i] = self.qy_data[i]
- result.q_data[i] = self.q_data[i]
- result.mask[i] = self.mask[i]
-
- a = Uncertainty(self.data[i], dy[i]**2)
- if isinstance(other, Data2D):
- b = Uncertainty(other.data[i], dy_other[i]**2)
- if other.dqx_data is not None and \
- result.dqx_data is not None:
- result.dqx_data[i] *= self.dqx_data[i]
- result.dqx_data[i] += (other.dqx_data[i]**2)
- result.dqx_data[i] /= 2
- result.dqx_data[i] = math.sqrt(result.dqx_data[i])
- if other.dqy_data is not None and \
- result.dqy_data is not None:
- result.dqy_data[i] *= self.dqy_data[i]
- result.dqy_data[i] += (other.dqy_data[i]**2)
- result.dqy_data[i] /= 2
- result.dqy_data[i] = math.sqrt(result.dqy_data[i])
- else:
- b = other
-
- output = operation(a, b)
- result.data[i] = output.x
- result.err_data[i] = math.sqrt(math.fabs(output.variance))
- return result
-
- def _perform_union(self, other):
- """
- Perform 2D operations between data sets
-
- :param other: other data set
- :param operation: function defining the operation
-
- """
- # First, check the data compatibility
- self._validity_check_union(other)
- result = Data2D(image=None, qx_data=None, qy_data=None,
- q_data=None, err_image=None, xmin=None, xmax=None,
- ymin=None, ymax=None, zmin=None, zmax=None)
- length = len(self.data)
- tot_length = length + len(other.data)
- result.clone_without_data(tot_length)
- result.xmin = self.xmin
- result.xmax = self.xmax
- result.ymin = self.ymin
- result.ymax = self.ymax
- if self.dqx_data == None or self.dqy_data == None or \
- other.dqx_data == None or other.dqy_data == None :
- result.dqx_data = None
- result.dqy_data = None
- else:
- result.dqx_data = numpy.zeros(len(self.data) + \
- numpy.size(other.data))
- result.dqy_data = numpy.zeros(len(self.data) + \
- numpy.size(other.data))
-
- result.data = numpy.append(self.data, other.data)
- result.qx_data = numpy.append(self.qx_data, other.qx_data)
- result.qy_data = numpy.append(self.qy_data, other.qy_data)
- result.q_data = numpy.append(self.q_data, other.q_data)
- result.mask = numpy.append(self.mask, other.mask)
- if result.err_data is not None:
- result.err_data = numpy.append(self.err_data, other.err_data)
- if self.dqx_data is not None:
- result.dqx_data = numpy.append(self.dqx_data, other.dqx_data)
- if self.dqy_data is not None:
- result.dqy_data = numpy.append(self.dqy_data, other.dqy_data)
-
- return result
-
-def check_data_validity(data):
- """
- Return True is data is valid enough to compute chisqr, else False
- """
- flag = True
- if data is not None:
- if issubclass(data.__class__, Data2D):
- if (data.data is None) or (len(data.data) == 0)\
- or (len(data.err_data) == 0):
- flag = False
- else:
- if (data.y is None) or (len(data.y) == 0):
- flag = False
- if not data.is_data:
- flag = False
- else:
- flag = False
+"""
+Adapters for fitting module
+"""
+import copy
+import numpy as np
+import math
+from sas.sascalc.data_util.uncertainty import Uncertainty
+from sas.sasgui.plottools.plottables import Data1D as PlotData1D
+from sas.sasgui.plottools.plottables import Data2D as PlotData2D
+from sas.sasgui.plottools.plottables import Theory1D as PlotTheory1D
+
+from sas.sascalc.dataloader.data_info import Data1D as LoadData1D
+from sas.sascalc.dataloader.data_info import Data2D as LoadData2D
+
+
+class Data1D(PlotData1D, LoadData1D):
+ """
+ """
+
+ def __init__(self, x=None, y=None, dx=None, dy=None, lam=None, dlam=None, isSesans=False):
+ """
+ """
+ if x is None:
+ x = []
+ if y is None:
+ y = []
+ self.isSesans = isSesans
+ PlotData1D.__init__(self, x, y, dx, dy, lam, dlam)
+ LoadData1D.__init__(self, x, y, dx, dy, lam, dlam, isSesans)
+
+ self.id = None
+ self.list_group_id = []
+ self.group_id = None
+ self.is_data = True
+ self.path = None
+ self.xtransform = None
+ if self.isSesans:
+ self.xtransform = "x"
+ self.ytransform = None
+ if self.isSesans:
+ self.ytransform = "y"
+ self.title = ""
+ self.scale = None
+
+ def copy_from_datainfo(self, data1d):
+ """
+ copy values of Data1D of type DataLaoder.Data_info
+ """
+ self.x = copy.deepcopy(data1d.x)
+ self.y = copy.deepcopy(data1d.y)
+ self.dy = copy.deepcopy(data1d.dy)
+
+ if hasattr(data1d, "dx"):
+ self.dx = copy.deepcopy(data1d.dx)
+ if hasattr(data1d, "dxl"):
+ self.dxl = copy.deepcopy(data1d.dxl)
+ if hasattr(data1d, "dxw"):
+ self.dxw = copy.deepcopy(data1d.dxw)
+
+ self.xaxis(data1d._xaxis, data1d._xunit)
+ self.yaxis(data1d._yaxis, data1d._yunit)
+ self.title = data1d.title
+
+ def __str__(self):
+ """
+ print data
+ """
+ _str = "%s\n" % LoadData1D.__str__(self)
+
+ return _str
+
+ def _perform_operation(self, other, operation):
+ """
+ """
+ # First, check the data compatibility
+ dy, dy_other = self._validity_check(other)
+ result = Data1D(x=[], y=[], lam=[], dx=None, dy=None, dlam=None)
+ result.clone_without_data(length=len(self.x), clone=self)
+ result.copy_from_datainfo(data1d=self)
+ if self.dxw is None:
+ result.dxw = None
+ else:
+ result.dxw = np.zeros(len(self.x))
+ if self.dxl is None:
+ result.dxl = None
+ else:
+ result.dxl = np.zeros(len(self.x))
+
+ for i in range(len(self.x)):
+ result.x[i] = self.x[i]
+ if self.dx is not None and len(self.x) == len(self.dx):
+ result.dx[i] = self.dx[i]
+ if self.dxw is not None and len(self.x) == len(self.dxw):
+ result.dxw[i] = self.dxw[i]
+ if self.dxl is not None and len(self.x) == len(self.dxl):
+ result.dxl[i] = self.dxl[i]
+
+ a = Uncertainty(self.y[i], dy[i]**2)
+ if isinstance(other, Data1D):
+ b = Uncertainty(other.y[i], dy_other[i]**2)
+ if other.dx is not None:
+ result.dx[i] *= self.dx[i]
+ result.dx[i] += (other.dx[i]**2)
+ result.dx[i] /= 2
+ result.dx[i] = math.sqrt(result.dx[i])
+ if result.dxl is not None and other.dxl is not None:
+ result.dxl[i] *= self.dxl[i]
+ result.dxl[i] += (other.dxl[i]**2)
+ result.dxl[i] /= 2
+ result.dxl[i] = math.sqrt(result.dxl[i])
+ else:
+ b = other
+
+ output = operation(a, b)
+ result.y[i] = output.x
+ result.dy[i] = math.sqrt(math.fabs(output.variance))
+ return result
+
+ def _perform_union(self, other):
+ """
+ """
+ # First, check the data compatibility
+ self._validity_check_union(other)
+ result = Data1D(x=[], y=[], lam=[], dx=None, dy=None, dlam=None)
+ tot_length = len(self.x) + len(other.x)
+ result = self.clone_without_data(length=tot_length, clone=result)
+ if self.dlam is None or other.dlam is None:
+ result.dlam = None
+ else:
+ result.dlam = np.zeros(tot_length)
+ if self.dy is None or other.dy is None:
+ result.dy = None
+ else:
+ result.dy = np.zeros(tot_length)
+ if self.dx is None or other.dx is None:
+ result.dx = None
+ else:
+ result.dx = np.zeros(tot_length)
+ if self.dxw is None or other.dxw is None:
+ result.dxw = None
+ else:
+ result.dxw = np.zeros(tot_length)
+ if self.dxl is None or other.dxl is None:
+ result.dxl = None
+ else:
+ result.dxl = np.zeros(tot_length)
+
+ result.x = np.append(self.x, other.x)
+ #argsorting
+ ind = np.argsort(result.x)
+ result.x = result.x[ind]
+ result.y = np.append(self.y, other.y)
+ result.y = result.y[ind]
+ result.lam = np.append(self.lam, other.lam)
+ result.lam = result.lam[ind]
+ if result.dlam is not None:
+ result.dlam = np.append(self.dlam, other.dlam)
+ result.dlam = result.dlam[ind]
+ if result.dy is not None:
+ result.dy = np.append(self.dy, other.dy)
+ result.dy = result.dy[ind]
+ if result.dx is not None:
+ result.dx = np.append(self.dx, other.dx)
+ result.dx = result.dx[ind]
+ if result.dxw is not None:
+ result.dxw = np.append(self.dxw, other.dxw)
+ result.dxw = result.dxw[ind]
+ if result.dxl is not None:
+ result.dxl = np.append(self.dxl, other.dxl)
+ result.dxl = result.dxl[ind]
+ return result
+
+
+
+class Theory1D(PlotTheory1D, LoadData1D):
+ """
+ """
+ def __init__(self, x=None, y=None, dy=None):
+ """
+ """
+ if x is None:
+ x = []
+ if y is None:
+ y = []
+ PlotTheory1D.__init__(self, x, y, dy)
+ LoadData1D.__init__(self, x, y, dy)
+ self.id = None
+ self.list_group_id = []
+ self.group_id = None
+ self.is_data = True
+ self.path = None
+ self.xtransform = None
+ self.ytransform = None
+ self.title = ""
+ self.scale = None
+
+ def copy_from_datainfo(self, data1d):
+ """
+ copy values of Data1D of type DataLaoder.Data_info
+ """
+ self.x = copy.deepcopy(data1d.x)
+ self.y = copy.deepcopy(data1d.y)
+ self.dy = copy.deepcopy(data1d.dy)
+ if hasattr(data1d, "dx"):
+ self.dx = copy.deepcopy(data1d.dx)
+ if hasattr(data1d, "dxl"):
+ self.dxl = copy.deepcopy(data1d.dxl)
+ if hasattr(data1d, "dxw"):
+ self.dxw = copy.deepcopy(data1d.dxw)
+ self.xaxis(data1d._xaxis, data1d._xunit)
+ self.yaxis(data1d._yaxis, data1d._yunit)
+ self.title = data1d.title
+
+ def __str__(self):
+ """
+ print data
+ """
+ _str = "%s\n" % LoadData1D.__str__(self)
+
+ return _str
+
+ def _perform_operation(self, other, operation):
+ """
+ """
+ # First, check the data compatibility
+ dy, dy_other = self._validity_check(other)
+ result = self.clone_without_data(len(self.x))
+ result.copy_from_datainfo(data1d=self)
+ if self.dxw is None:
+ result.dxw = None
+ else:
+ result.dxw = np.zeros(len(self.x))
+ if self.dxl is None:
+ result.dxl = None
+ else:
+ result.dxl = np.zeros(len(self.x))
+
+ for i in range(np.size(self.x)):
+ result.x[i] = self.x[i]
+ if self.dx is not None and len(self.x) == len(self.dx):
+ result.dx[i] = self.dx[i]
+ if self.dxw is not None and len(self.x) == len(self.dxw):
+ result.dxw[i] = self.dxw[i]
+ if self.dxl is not None and len(self.x) == len(self.dxl):
+ result.dxl[i] = self.dxl[i]
+
+ a = Uncertainty(self.y[i], dy[i]**2)
+ if isinstance(other, Data1D):
+ b = Uncertainty(other.y[i], dy_other[i]**2)
+ if other.dx is not None:
+ result.dx[i] *= self.dx[i]
+ result.dx[i] += (other.dx[i]**2)
+ result.dx[i] /= 2
+ result.dx[i] = math.sqrt(result.dx[i])
+ if result.dxl is not None and other.dxl is not None:
+ result.dxl[i] *= self.dxl[i]
+ other.dxl[i] += (other.dxl[i]**2)
+ result.dxl[i] /= 2
+ result.dxl[i] = math.sqrt(result.dxl[i])
+ if result.dxw is not None and self.dxw is not None:
+ result.dxw[i] *= self.dxw[i]
+ other.dxw[i] += (other.dxw[i]**2)
+ result.dxw[i] /= 2
+ result.dxw[i] = math.sqrt(result.dxw[i])
+ else:
+ b = other
+
+ output = operation(a, b)
+ result.y[i] = output.x
+ result.dy[i] = math.sqrt(math.fabs(output.variance))
+ return result
+
+ def _perform_union(self, other):
+ """
+ """
+ # First, check the data compatibility
+ self._validity_check_union(other)
+ result = Data1D(x=[], y=[], lam=[], dx=None, dy=None, dlam=[])
+ tot_length = len(self.x)+len(other.x)
+ result.clone_without_data(length=tot_length, clone=self)
+ if self.dlam is None or other.dlam is None:
+ result.dlam = None
+ else:
+ result.dlam = np.zeros(tot_length)
+ if self.dy is None or other.dy is None:
+ result.dy = None
+ else:
+ result.dy = np.zeros(tot_length)
+ if self.dx is None or other.dx is None:
+ result.dx = None
+ else:
+ result.dx = np.zeros(tot_length)
+ if self.dxw is None or other.dxw is None:
+ result.dxw = None
+ else:
+ result.dxw = np.zeros(tot_length)
+ if self.dxl is None or other.dxl is None:
+ result.dxl = None
+ else:
+ result.dxl = np.zeros(tot_length)
+ result.x = np.append(self.x, other.x)
+ #argsorting
+ ind = np.argsort(result.x)
+ result.x = result.x[ind]
+ result.y = np.append(self.y, other.y)
+ result.y = result.y[ind]
+ result.lam = np.append(self.lam, other.lam)
+ result.lam = result.lam[ind]
+ if result.dy is not None:
+ result.dy = np.append(self.dy, other.dy)
+ result.dy = result.dy[ind]
+ if result.dx is not None:
+ result.dx = np.append(self.dx, other.dx)
+ result.dx = result.dx[ind]
+ if result.dxw is not None:
+ result.dxw = np.append(self.dxw, other.dxw)
+ result.dxw = result.dxw[ind]
+ if result.dxl is not None:
+ result.dxl = np.append(self.dxl, other.dxl)
+ result.dxl = result.dxl[ind]
+ return result
+
+
+class Data2D(PlotData2D, LoadData2D):
+ """
+ """
+ def __init__(self, image=None, err_image=None,
+ qx_data=None, qy_data=None, q_data=None,
+ mask=None, dqx_data=None, dqy_data=None,
+ xmin=None, xmax=None, ymin=None, ymax=None,
+ zmin=None, zmax=None):
+ """
+ """
+ PlotData2D.__init__(self, image=image, err_image=err_image,
+ xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax,
+ zmin=zmin, zmax=zmax, qx_data=qx_data,
+ qy_data=qy_data)
+
+ LoadData2D.__init__(self, data=image, err_data=err_image,
+ qx_data=qx_data, qy_data=qy_data,
+ dqx_data=dqx_data, dqy_data=dqy_data,
+ q_data=q_data, mask=mask)
+ self.id = None
+ self.list_group_id = []
+ self.group_id = None
+ self.is_data = True
+ self.path = None
+ self.xtransform = None
+ self.ytransform = None
+ self.title = ""
+ self.scale = None
+
+ def copy_from_datainfo(self, data2d):
+ """
+ copy value of Data2D of type DataLoader.data_info
+ """
+ self.data = copy.deepcopy(data2d.data)
+ self.qx_data = copy.deepcopy(data2d.qx_data)
+ self.qy_data = copy.deepcopy(data2d.qy_data)
+ self.q_data = copy.deepcopy(data2d.q_data)
+ self.mask = copy.deepcopy(data2d.mask)
+ self.err_data = copy.deepcopy(data2d.err_data)
+ self.x_bins = copy.deepcopy(data2d.x_bins)
+ self.y_bins = copy.deepcopy(data2d.y_bins)
+ if data2d.dqx_data is not None:
+ self.dqx_data = copy.deepcopy(data2d.dqx_data)
+ if data2d.dqy_data is not None:
+ self.dqy_data = copy.deepcopy(data2d.dqy_data)
+ self.xmin = data2d.xmin
+ self.xmax = data2d.xmax
+ self.ymin = data2d.ymin
+ self.ymax = data2d.ymax
+ if hasattr(data2d, "zmin"):
+ self.zmin = data2d.zmin
+ if hasattr(data2d, "zmax"):
+ self.zmax = data2d.zmax
+ self.xaxis(data2d._xaxis, data2d._xunit)
+ self.yaxis(data2d._yaxis, data2d._yunit)
+ self.title = data2d.title
+
+ def __str__(self):
+ """
+ print data
+ """
+ _str = "%s\n" % LoadData2D.__str__(self)
+ return _str
+
+ def _perform_operation(self, other, operation):
+ """
+ Perform 2D operations between data sets
+
+ :param other: other data set
+ :param operation: function defining the operation
+
+ """
+ # First, check the data compatibility
+ dy, dy_other = self._validity_check(other)
+ result = Data2D(image=None, qx_data=None, qy_data=None,
+ q_data=None, err_image=None, xmin=None, xmax=None,
+ ymin=None, ymax=None, zmin=None, zmax=None)
+ result.clone_without_data(len(self.data))
+ result.copy_from_datainfo(data2d=self)
+ result.xmin = self.xmin
+ result.xmax = self.xmax
+ result.ymin = self.ymin
+ result.ymax = self.ymax
+ if self.dqx_data is None or self.dqy_data is None:
+ result.dqx_data = None
+ result.dqy_data = None
+ else:
+ result.dqx_data = np.zeros(len(self.data))
+ result.dqy_data = np.zeros(len(self.data))
+ for i in range(np.size(self.data)):
+ result.data[i] = self.data[i]
+ if self.err_data is not None and \
+ np.size(self.data) == np.size(self.err_data):
+ result.err_data[i] = self.err_data[i]
+ if self.dqx_data is not None:
+ result.dqx_data[i] = self.dqx_data[i]
+ if self.dqy_data is not None:
+ result.dqy_data[i] = self.dqy_data[i]
+ result.qx_data[i] = self.qx_data[i]
+ result.qy_data[i] = self.qy_data[i]
+ result.q_data[i] = self.q_data[i]
+ result.mask[i] = self.mask[i]
+
+ a = Uncertainty(self.data[i], dy[i]**2)
+ if isinstance(other, Data2D):
+ b = Uncertainty(other.data[i], dy_other[i]**2)
+ if other.dqx_data is not None and \
+ result.dqx_data is not None:
+ result.dqx_data[i] *= self.dqx_data[i]
+ result.dqx_data[i] += (other.dqx_data[i]**2)
+ result.dqx_data[i] /= 2
+ result.dqx_data[i] = math.sqrt(result.dqx_data[i])
+ if other.dqy_data is not None and \
+ result.dqy_data is not None:
+ result.dqy_data[i] *= self.dqy_data[i]
+ result.dqy_data[i] += (other.dqy_data[i]**2)
+ result.dqy_data[i] /= 2
+ result.dqy_data[i] = math.sqrt(result.dqy_data[i])
+ else:
+ b = other
+
+ output = operation(a, b)
+ result.data[i] = output.x
+ result.err_data[i] = math.sqrt(math.fabs(output.variance))
+ return result
+
+ def _perform_union(self, other):
+ """
+ Perform 2D operations between data sets
+
+ :param other: other data set
+ :param operation: function defining the operation
+
+ """
+ # First, check the data compatibility
+ self._validity_check_union(other)
+ result = Data2D(image=None, qx_data=None, qy_data=None,
+ q_data=None, err_image=None, xmin=None, xmax=None,
+ ymin=None, ymax=None, zmin=None, zmax=None)
+ length = len(self.data)
+ tot_length = length + len(other.data)
+ result.clone_without_data(tot_length)
+ result.xmin = self.xmin
+ result.xmax = self.xmax
+ result.ymin = self.ymin
+ result.ymax = self.ymax
+ if self.dqx_data is None or self.dqy_data is None or \
+ other.dqx_data is None or other.dqy_data is None :
+ result.dqx_data = None
+ result.dqy_data = None
+ else:
+ result.dqx_data = np.zeros(len(self.data) + \
+ np.size(other.data))
+ result.dqy_data = np.zeros(len(self.data) + \
+ np.size(other.data))
+
+ result.data = np.append(self.data, other.data)
+ result.qx_data = np.append(self.qx_data, other.qx_data)
+ result.qy_data = np.append(self.qy_data, other.qy_data)
+ result.q_data = np.append(self.q_data, other.q_data)
+ result.mask = np.append(self.mask, other.mask)
+ if result.err_data is not None:
+ result.err_data = np.append(self.err_data, other.err_data)
+ if self.dqx_data is not None:
+ result.dqx_data = np.append(self.dqx_data, other.dqx_data)
+ if self.dqy_data is not None:
+ result.dqy_data = np.append(self.dqy_data, other.dqy_data)
+
+ return result
+
+def check_data_validity(data):
+ """
+ Return True is data is valid enough to compute chisqr, else False
+ """
+ flag = True
+ if data is not None:
+ if issubclass(data.__class__, Data2D):
+ if (data.data is None) or (len(data.data) == 0)\
+ or (len(data.err_data) == 0):
+ flag = False
+ else:
+ if (data.y is None) or (len(data.y) == 0):
+ flag = False
+ if not data.is_data:
+ flag = False
+ else:
+ flag = False
return flag
\ No newline at end of file
diff --git a/src/sas/sasgui/guiframe/data_manager.py b/src/sas/sasgui/guiframe/data_manager.py
index f6fabb6..c2e2f40 100644
--- a/src/sas/sasgui/guiframe/data_manager.py
+++ b/src/sas/sasgui/guiframe/data_manager.py
@@ -1,304 +1,306 @@
-################################################################################
-#This software was developed by the University of Tennessee as part of the
-#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
-#project funded by the US National Science Foundation.
-#
-#See the license text in license.txt
-#
-#copyright 2010, University of Tennessee
-################################################################################
-"""
-This module manages all data loaded into the application. Data_manager makes
-available all data loaded for the current perspective.
-
-All modules "creating Data" posts their data to data_manager .
-Data_manager make these new data available for all other perspectives.
-"""
-import logging
-import os
-import copy
-
-from sas.sasgui.guiframe.data_state import DataState
-from sas.sasgui.guiframe.utils import parse_name
-import sas.sascalc.dataloader.data_info as DataInfo
-from sas.sasgui.guiframe.dataFitting import Data1D
-from sas.sasgui.guiframe.dataFitting import Data2D
-import time
-
-class DataManager(object):
- """
- Manage a list of data
- """
- def __init__(self):
- """
- Store opened path and data object created at the loading time
- :param auto_plot: if True the datamanager sends data to plotting
- plugin.
- :param auto_set_data: if True the datamanager sends to the current
- perspective
- """
- self.stored_data = {}
- self.message = ""
- self.data_name_dict = {}
- self.count = 0
- self.list_of_id = []
- self.time_stamp = time.time()
-
- def __str__(self):
- _str = ""
- _str += "No of states is %s \n" % str(len(self.stored_data))
- n_count = 0
- for value in self.stored_data.values():
- n_count += 1
- _str += "State No %s \n" % str(n_count)
- _str += str(value) + "\n"
- return _str
-
- def create_gui_data(self, data, path=None):
- """
- Receive data from loader and create a data to use for guiframe
- """
-
- if issubclass(Data2D, data.__class__):
- new_plot = Data2D(image=None, err_image=None) # For now, isSesans for 2D data is always false
- else:
- new_plot = Data1D(x=[], y=[], dx=None, dy=None, lam=None, dlam=None, isSesans=data.isSesans)
-
-
- #elif data.meta_data['loader'] == 'SESANS':
- # new_plot = Data1D(x=[], y=[], dx=None, dy=None, lam=None, dlam=None, isSesans=True)
- #else:
- # new_plot = Data1D(x=[], y=[], dx=None, dy=None, lam=None, dlam=None) #SESANS check???
-
- new_plot.copy_from_datainfo(data)
- data.clone_without_data(clone=new_plot)
- #creating a name for data
- title = ""
- file_name = os.path.basename(path) if path is not None else data.filename
- if file_name:
- name = file_name
- elif data.run:
- name = data.run[0]
- else:
- name = "data"
- name = self.rename(name)
- #find title
- if data.title.strip():
- title = data.title
- if title.strip() == "":
- title = file_name
-
- if new_plot.filename.strip() == "":
- new_plot.filename = file_name
-
- new_plot.name = name
- new_plot.title = title
- ## allow to highlight data when plotted
- new_plot.interactive = True
- ## when 2 data have the same id override the 1 st plotted
- self.time_stamp += 1
- new_plot.id = str(name) + str(self.time_stamp)
- ##group_id specify on which panel to plot this data
- new_plot.group_id = str(name) + str(self.time_stamp)
- new_plot.is_data = True
- new_plot.path = path
- new_plot.list_group_id = []
- ##post data to plot
- # plot data
- return new_plot
-
- def rename(self, name):
- """
- rename data
- """
- ## name of the data allow to differentiate data when plotted
- name = parse_name(name=name, expression="_")
-
- max_char = name.find("[")
- if max_char < 0:
- max_char = len(name)
- name = name[0:max_char]
-
- if name not in self.data_name_dict:
- self.data_name_dict[name] = 0
- else:
- self.data_name_dict[name] += 1
- name = name + " [" + str(self.data_name_dict[name]) + "]"
- return name
-
-
- def add_data(self, data_list):
- """
- receive a list of
- """
- for id, data in data_list.iteritems():
- if id in self.stored_data:
- msg = "Data manager already stores %s" % str(data.name)
- msg += ""
- logging.info(msg)
- data_state = self.stored_data[id]
- data_state.data = data
- else:
- data_state = DataState(data)
- data_state.id = id
- data_state.path = data.path
- self.stored_data[id] = data_state
-
- def update_data(self, prev_data, new_data):
- """
- """
- if prev_data.id not in self.stored_data.keys():
- return None, {}
- data_state = self.stored_data[prev_data.id]
- self.stored_data[new_data.id] = data_state.clone()
- self.stored_data[new_data.id].data = new_data
- if prev_data.id in self.stored_data.keys():
- del self.stored_data[prev_data.id]
- return prev_data.id, {new_data.id: self.stored_data[new_data.id]}
-
- def update_theory(self, theory, data_id=None, state=None):
- """
- """
- uid = data_id
- if data_id is None and theory is not None:
- uid = theory.id
- if uid in self.stored_data.keys():
- data_state = self.stored_data[uid]
- else:
- data_state = DataState()
- data_state.uid = uid
- data_state.set_theory(theory_data=theory, theory_state=state)
- self.stored_data[uid] = data_state
- return {uid: self.stored_data[uid]}
-
-
- def get_message(self):
- """
- return message
- """
- return self.message
-
- def get_by_id(self, id_list=None):
- """
- """
- _selected_data = {}
- _selected_theory_list = {}
- if id_list is None:
- return
- for d_id in self.stored_data:
- for search_id in id_list:
- data_state = self.stored_data[d_id]
- data = data_state.data
- theory_list = data_state.get_theory()
- if search_id == d_id:
- _selected_data[search_id] = data
- if search_id in theory_list.keys():
- _selected_theory_list[search_id] = theory_list[search_id]
-
- return _selected_data, _selected_theory_list
-
-
- def freeze(self, theory_id):
- """
- """
- return self.freeze_theory(self.stored_data.keys(), theory_id)
-
- def freeze_theory(self, data_id, theory_id):
- """
- """
- selected_theory = {}
- for d_id in data_id:
- if d_id in self.stored_data:
- data_state = self.stored_data[d_id]
- theory_list = data_state.get_theory()
- for t_id in theory_id:
- if t_id in theory_list.keys():
- theory_data, theory_state = theory_list[t_id]
- new_theory = copy.deepcopy(theory_data)
- new_theory.id = time.time()
- new_theory.is_data = True
- new_theory.name += '_@' + \
- str(new_theory.id)[7:-1].replace('.', '')
- new_theory.title = new_theory.name
- new_theory.label = new_theory.name
- selected_theory[new_theory.id] = DataState(new_theory)
- self.stored_data[new_theory.id] = \
- selected_theory[new_theory.id]
-
- return selected_theory
-
-
- def delete_data(self, data_id, theory_id=None, delete_all=False):
- """
- """
- for d_id in data_id:
- if d_id in self.stored_data.keys():
- data_state = self.stored_data[d_id]
- if data_state.data.name in self.data_name_dict:
- del self.data_name_dict[data_state.data.name]
- del self.stored_data[d_id]
-
- self.delete_theory(data_id, theory_id)
- if delete_all:
- self.stored_data = {}
- self.data_name_dict = {}
-
- def delete_theory(self, data_id, theory_id):
- """
- """
- for d_id in data_id:
- if d_id in self.stored_data:
- data_state = self.stored_data[d_id]
- theory_list = data_state.get_theory()
- if theory_id in theory_list.keys():
- del theory_list[theory_id]
- #del pure theory
- self.delete_by_id(theory_id)
-
- def delete_by_id(self, id_list=None):
- """
- save data and path
- """
- for id in id_list:
- if id in self.stored_data:
- del self.stored_data[id]
-
-
- def get_by_name(self, name_list=None):
- """
- return a list of data given a list of data names
- """
- _selected_data = {}
- for selected_name in name_list:
- for id, data_state in self.stored_data.iteritems():
- if data_state.data.name == selected_name:
- _selected_data[id] = data_state.data
- return _selected_data
-
- def delete_by_name(self, name_list=None):
- """
- save data and path
- """
- for selected_name in name_list:
- for id, data_state in self.stored_data.iteritems():
- if data_state.data.name == selected_name:
- del self.stored_data[id]
-
- def get_data_state(self, data_id):
- """
- Send list of selected data
- """
- _selected_data_state = {}
- for id in data_id:
- if id in self.stored_data.keys():
- _selected_data_state[id] = self.stored_data[id]
- return _selected_data_state
-
- def get_all_data(self):
- """
- return list of all available data
- """
- return self.stored_data
-
-
+################################################################################
+#This software was developed by the University of Tennessee as part of the
+#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
+#project funded by the US National Science Foundation.
+#
+#See the license text in license.txt
+#
+#copyright 2010, University of Tennessee
+################################################################################
+"""
+This module manages all data loaded into the application. Data_manager makes
+available all data loaded for the current perspective.
+
+All modules "creating Data" posts their data to data_manager .
+Data_manager make these new data available for all other perspectives.
+"""
+import logging
+import os
+import copy
+
+from sas.sasgui.guiframe.data_state import DataState
+from sas.sasgui.guiframe.utils import parse_name
+import sas.sascalc.dataloader.data_info as DataInfo
+from sas.sasgui.guiframe.dataFitting import Data1D
+from sas.sasgui.guiframe.dataFitting import Data2D
+import time
+
+logger = logging.getLogger(__name__)
+
+class DataManager(object):
+ """
+ Manage a list of data
+ """
+ def __init__(self):
+ """
+ Store opened path and data object created at the loading time
+ :param auto_plot: if True the datamanager sends data to plotting
+ plugin.
+ :param auto_set_data: if True the datamanager sends to the current
+ perspective
+ """
+ self.stored_data = {}
+ self.message = ""
+ self.data_name_dict = {}
+ self.count = 0
+ self.list_of_id = []
+ self.time_stamp = time.time()
+
+ def __str__(self):
+ _str = ""
+ _str += "No of states is %s \n" % str(len(self.stored_data))
+ n_count = 0
+ for value in self.stored_data.values():
+ n_count += 1
+ _str += "State No %s \n" % str(n_count)
+ _str += str(value) + "\n"
+ return _str
+
+ def create_gui_data(self, data, path=None):
+ """
+ Receive data from loader and create a data to use for guiframe
+ """
+
+ if issubclass(Data2D, data.__class__):
+ new_plot = Data2D(image=None, err_image=None) # For now, isSesans for 2D data is always false
+ else:
+ new_plot = Data1D(x=[], y=[], dx=None, dy=None, lam=None, dlam=None, isSesans=data.isSesans)
+
+
+ #elif data.meta_data['loader'] == 'SESANS':
+ # new_plot = Data1D(x=[], y=[], dx=None, dy=None, lam=None, dlam=None, isSesans=True)
+ #else:
+ # new_plot = Data1D(x=[], y=[], dx=None, dy=None, lam=None, dlam=None) #SESANS check???
+
+ new_plot.copy_from_datainfo(data)
+ data.clone_without_data(clone=new_plot)
+ #creating a name for data
+ title = ""
+ file_name = os.path.basename(path) if path is not None else data.filename
+ if file_name:
+ name = file_name
+ elif data.run:
+ name = data.run[0]
+ else:
+ name = "data"
+ name = self.rename(name)
+ #find title
+ if data.title.strip():
+ title = data.title
+ if title.strip() == "":
+ title = file_name
+
+ if new_plot.filename.strip() == "":
+ new_plot.filename = file_name
+
+ new_plot.name = name
+ new_plot.title = title
+ ## allow to highlight data when plotted
+ new_plot.interactive = True
+ ## when 2 data have the same id override the 1 st plotted
+ self.time_stamp += 1
+ new_plot.id = str(name) + str(self.time_stamp)
+ ##group_id specify on which panel to plot this data
+ new_plot.group_id = str(name) + str(self.time_stamp)
+ new_plot.is_data = True
+ new_plot.path = path
+ new_plot.list_group_id = []
+ ##post data to plot
+ # plot data
+ return new_plot
+
+ def rename(self, name):
+ """
+ rename data
+ """
+ ## name of the data allow to differentiate data when plotted
+ name = parse_name(name=name, expression="_")
+
+ max_char = name.find("[")
+ if max_char < 0:
+ max_char = len(name)
+ name = name[0:max_char]
+
+ if name not in self.data_name_dict:
+ self.data_name_dict[name] = 0
+ else:
+ self.data_name_dict[name] += 1
+ name = name + " [" + str(self.data_name_dict[name]) + "]"
+ return name
+
+
+ def add_data(self, data_list):
+ """
+ receive a list of
+ """
+ for id, data in data_list.iteritems():
+ if id in self.stored_data:
+ msg = "Data manager already stores %s" % str(data.name)
+ msg += ""
+ logger.info(msg)
+ data_state = self.stored_data[id]
+ data_state.data = data
+ else:
+ data_state = DataState(data)
+ data_state.id = id
+ data_state.path = data.path
+ self.stored_data[id] = data_state
+
+ def update_data(self, prev_data, new_data):
+ """
+ """
+ if prev_data.id not in self.stored_data.keys():
+ return None, {}
+ data_state = self.stored_data[prev_data.id]
+ self.stored_data[new_data.id] = data_state.clone()
+ self.stored_data[new_data.id].data = new_data
+ if prev_data.id in self.stored_data.keys():
+ del self.stored_data[prev_data.id]
+ return prev_data.id, {new_data.id: self.stored_data[new_data.id]}
+
+ def update_theory(self, theory, data_id=None, state=None):
+ """
+ """
+ uid = data_id
+ if data_id is None and theory is not None:
+ uid = theory.id
+ if uid in self.stored_data.keys():
+ data_state = self.stored_data[uid]
+ else:
+ data_state = DataState()
+ data_state.uid = uid
+ data_state.set_theory(theory_data=theory, theory_state=state)
+ self.stored_data[uid] = data_state
+ return {uid: self.stored_data[uid]}
+
+
+ def get_message(self):
+ """
+ return message
+ """
+ return self.message
+
+ def get_by_id(self, id_list=None):
+ """
+ """
+ _selected_data = {}
+ _selected_theory_list = {}
+ if id_list is None:
+ return
+ for d_id in self.stored_data:
+ for search_id in id_list:
+ data_state = self.stored_data[d_id]
+ data = data_state.data
+ theory_list = data_state.get_theory()
+ if search_id == d_id:
+ _selected_data[search_id] = data
+ if search_id in theory_list.keys():
+ _selected_theory_list[search_id] = theory_list[search_id]
+
+ return _selected_data, _selected_theory_list
+
+
+ def freeze(self, theory_id):
+ """
+ """
+ return self.freeze_theory(self.stored_data.keys(), theory_id)
+
+ def freeze_theory(self, data_id, theory_id):
+ """
+ """
+ selected_theory = {}
+ for d_id in data_id:
+ if d_id in self.stored_data:
+ data_state = self.stored_data[d_id]
+ theory_list = data_state.get_theory()
+ for t_id in theory_id:
+ if t_id in theory_list.keys():
+ theory_data, theory_state = theory_list[t_id]
+ new_theory = copy.deepcopy(theory_data)
+ new_theory.id = time.time()
+ new_theory.is_data = True
+ new_theory.name += '_@' + \
+ str(new_theory.id)[7:-1].replace('.', '')
+ new_theory.title = new_theory.name
+ new_theory.label = new_theory.name
+ selected_theory[new_theory.id] = DataState(new_theory)
+ self.stored_data[new_theory.id] = \
+ selected_theory[new_theory.id]
+
+ return selected_theory
+
+
+ def delete_data(self, data_id, theory_id=None, delete_all=False):
+ """
+ """
+ for d_id in data_id:
+ if d_id in self.stored_data.keys():
+ data_state = self.stored_data[d_id]
+ if data_state.data.name in self.data_name_dict:
+ del self.data_name_dict[data_state.data.name]
+ del self.stored_data[d_id]
+
+ self.delete_theory(data_id, theory_id)
+ if delete_all:
+ self.stored_data = {}
+ self.data_name_dict = {}
+
+ def delete_theory(self, data_id, theory_id):
+ """
+ """
+ for d_id in data_id:
+ if d_id in self.stored_data:
+ data_state = self.stored_data[d_id]
+ theory_list = data_state.get_theory()
+ if theory_id in theory_list.keys():
+ del theory_list[theory_id]
+ #del pure theory
+ self.delete_by_id(theory_id)
+
+ def delete_by_id(self, id_list=None):
+ """
+ save data and path
+ """
+ for id in id_list:
+ if id in self.stored_data:
+ del self.stored_data[id]
+
+
+ def get_by_name(self, name_list=None):
+ """
+ return a list of data given a list of data names
+ """
+ _selected_data = {}
+ for selected_name in name_list:
+ for id, data_state in self.stored_data.iteritems():
+ if data_state.data.name == selected_name:
+ _selected_data[id] = data_state.data
+ return _selected_data
+
+ def delete_by_name(self, name_list=None):
+ """
+ save data and path
+ """
+ for selected_name in name_list:
+ for id, data_state in self.stored_data.iteritems():
+ if data_state.data.name == selected_name:
+ del self.stored_data[id]
+
+ def get_data_state(self, data_id):
+ """
+ Send list of selected data
+ """
+ _selected_data_state = {}
+ for id in data_id:
+ if id in self.stored_data.keys():
+ _selected_data_state[id] = self.stored_data[id]
+ return _selected_data_state
+
+ def get_all_data(self):
+ """
+ return list of all available data
+ """
+ return self.stored_data
+
+
\ No newline at end of file
diff --git a/src/sas/sasgui/guiframe/data_panel.py b/src/sas/sasgui/guiframe/data_panel.py
index b8fa874..576513f 100644
--- a/src/sas/sasgui/guiframe/data_panel.py
+++ b/src/sas/sasgui/guiframe/data_panel.py
@@ -1,1501 +1,1505 @@
-################################################################################
-# This software was developed by the University of Tennessee as part of the
-# Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
-# project funded by the US National Science Foundation.
-#
-# See the license text in license.txt
-#
-# copyright 2010, University of Tennessee
-################################################################################
-"""
-This module provides Graphic interface for the data_manager module.
-"""
-import wx
-from wx.build import build_options
-
-import sys
-from wx.lib.scrolledpanel import ScrolledPanel
-import wx.lib.agw.customtreectrl as CT
-from sas.sasgui.guiframe.dataFitting import Data1D
-from sas.sasgui.guiframe.dataFitting import Data2D
-from sas.sasgui.guiframe.panel_base import PanelBase
-from sas.sasgui.guiframe.events import StatusEvent
-from sas.sasgui.guiframe.events import EVT_DELETE_PLOTPANEL
-from sas.sasgui.guiframe.events import NewLoadDataEvent
-from sas.sasgui.guiframe.events import NewPlotEvent
-from sas.sasgui.guiframe.gui_style import GUIFRAME
-from sas.sasgui.guiframe.events import NewBatchEvent
-from sas.sascalc.dataloader.loader import Loader
-# from sas.sasgui.guiframe.local_perspectives.plotting.masking \
-# import FloatPanel as QucikPlotDialog
-from sas.sasgui.guiframe.local_perspectives.plotting.SimplePlot \
- import PlotFrame as QucikPlotDialog
-import sas.sasgui.guiframe.config as config
-
-# Check version
-toks = str(wx.__version__).split('.')
-if int(toks[1]) < 9:
- if int(toks[2]) < 12:
- wx_version = 811
- else:
- wx_version = 812
-else:
- wx_version = 900
-
-extension_list = []
-if config.APPLICATION_STATE_EXTENSION is not None:
- extension_list.append(config.APPLICATION_STATE_EXTENSION)
-EXTENSIONS = config.PLUGIN_STATE_EXTENSIONS + extension_list
-PLUGINS_WLIST = config.PLUGINS_WLIST
-APPLICATION_WLIST = config.APPLICATION_WLIST
-
-# Control panel width
-if sys.platform.count("win32") > 0:
- PANEL_WIDTH = 235
- PANEL_HEIGHT = 700
- CBOX_WIDTH = 140
- BUTTON_WIDTH = 80
- FONT_VARIANT = 0
- IS_MAC = False
-else:
- PANEL_WIDTH = 255
- PANEL_HEIGHT = 750
- CBOX_WIDTH = 155
- BUTTON_WIDTH = 100
- FONT_VARIANT = 1
- IS_MAC = True
-
-STYLE_FLAG = (wx.RAISED_BORDER | CT.TR_HAS_BUTTONS |
- wx.WANTS_CHARS | CT.TR_HAS_VARIABLE_ROW_HEIGHT)
-
-
-class DataTreeCtrl(CT.CustomTreeCtrl):
- """
- Check list control to be used for Data Panel
- """
- def __init__(self, parent, root, *args, **kwds):
- # agwstyle is introduced in wx.2.8.11 but is not working for mac
- if IS_MAC and wx_version < 812:
- try:
- kwds['style'] = STYLE_FLAG
- CT.CustomTreeCtrl.__init__(self, parent, *args, **kwds)
- except:
- del kwds['style']
- CT.CustomTreeCtrl.__init__(self, parent, *args, **kwds)
- else:
- # agwstyle is introduced in wx.2.8.11
- # argument working only for windows
- try:
- kwds['agwStyle'] = STYLE_FLAG
- CT.CustomTreeCtrl.__init__(self, parent, *args, **kwds)
- except:
- try:
- del kwds['agwStyle']
- kwds['style'] = STYLE_FLAG
- CT.CustomTreeCtrl.__init__(self, parent, *args, **kwds)
- except:
- del kwds['style']
- CT.CustomTreeCtrl.__init__(self, parent, *args, **kwds)
- self.root = self.AddRoot(root)
-
- def OnCompareItems(self, item1, item2):
- """
- Overrides OnCompareItems in wx.TreeCtrl.
- Used by the SortChildren method.
- """
- # Get the item data
- data_1 = self.GetItemText(item1)
- data_2 = self.GetItemText(item2)
- # Compare the item data
- if data_1 < data_2:
- return -1
- elif data_1 > data_2:
- return 1
- else:
- return 0
-
-
-class DataPanel(ScrolledPanel, PanelBase):
- """
- This panel displays data available in the application and widgets to
- interact with data.
- """
- # Internal name for the AUI manager
- window_name = "Data Panel"
- # Title to appear on top of the window
- window_caption = "Data Explorer"
- # type of window
- window_type = "Data Panel"
- # Flag to tell the GUI manager that this panel is not
- # tied to any perspective
- # ALWAYS_ON = True
-
- def __init__(self, parent,
- list=None,
- size=(PANEL_WIDTH, PANEL_HEIGHT),
- id=-1,
- list_of_perspective=None, manager=None, *args, **kwds):
- # kwds['size'] = size
- # kwds['style'] = STYLE_FLAG
- ScrolledPanel.__init__(self, parent=parent, id=id, *args, **kwds)
- PanelBase.__init__(self, parent)
- self.SetupScrolling()
- # Set window's font size
- self.SetWindowVariant(variant=FONT_VARIANT)
- self.loader = Loader()
- # Default location
- self._default_save_location = None
- self.all_data1d = True
- self.parent = parent.parent
- self._manager = manager
- self.frame = parent
- if list is None:
- list = []
- self.list_of_data = list
- if list_of_perspective is None:
- list_of_perspective = []
- self.list_of_perspective = list_of_perspective
- self.list_rb_perspectives = []
- self.list_cb_data = {}
- self.list_cb_theory = {}
- self.tree_ctrl = None
- self.tree_ctrl_theory = None
- self.perspective_cbox = None
- # Create context menu for page
- self.data_menu = None
- self.popUpMenu = None
- self.plot3d_id = None
- self.editmask_id = None
- # Default attr
- self.vbox = None
- self.sizer1 = None
- self.sizer2 = None
- self.sizer3 = None
- self.sizer4 = None
- self.sizer5 = None
- self.selection_cbox = None
- self.bt_add = None
- self.bt_remove = None
- self.bt_import = None
- self.bt_append_plot = None
- self.bt_plot = None
- self.bt_freeze = None
- self.cb_plotpanel = None
- self.rb_single_mode = None
- self.rb_batch_mode = None
-
- self.owner = None
- self.do_layout()
- self.fill_cbox_analysis(self.list_of_perspective)
- self.Bind(wx.EVT_SHOW, self.on_close_page)
- if self.parent is not None:
- self.parent.Bind(EVT_DELETE_PLOTPANEL, self._on_delete_plot_panel)
-
- def do_layout(self):
- """
- Create the panel layout
- """
- self.define_panel_structure()
- self.layout_selection()
- self.layout_data_list()
- self.layout_batch()
- self.layout_button()
-
- def disable_app_combo(self, enable):
- """
- Disable app combo box
- """
- self.perspective_cbox.Enable(enable)
-
- def define_panel_structure(self):
- """
- Define the skeleton of the panel
- """
- w, h = self.parent.GetSize()
- self.vbox = wx.BoxSizer(wx.VERTICAL)
- self.sizer1 = wx.BoxSizer(wx.VERTICAL)
- self.sizer1.SetMinSize(wx.Size(w/13, h*2/5))
-
- self.sizer2 = wx.BoxSizer(wx.VERTICAL)
- self.sizer3 = wx.FlexGridSizer(9, 2, 4, 1)
- self.sizer4 = wx.BoxSizer(wx.VERTICAL)
- self.sizer5 = wx.BoxSizer(wx.VERTICAL)
-
- self.vbox.Add(self.sizer5, 0, wx.EXPAND | wx.ALL, 1)
- self.vbox.Add(self.sizer1, 1, wx.EXPAND | wx.ALL, 0)
- self.vbox.Add(self.sizer2, 0, wx.EXPAND | wx.ALL, 1)
- self.vbox.Add(self.sizer3, 0, wx.EXPAND | wx.ALL, 10)
- # self.vbox.Add(self.sizer4, 0, wx.EXPAND|wx.ALL,5)
-
- self.SetSizer(self.vbox)
-
- def layout_selection(self):
- """
- Create selection option combo box
- """
- select_txt = wx.StaticText(self, -1, 'Selection Options')
- select_txt.SetForegroundColour('blue')
- self.selection_cbox = wx.ComboBox(self, -1, style=wx.CB_READONLY)
- list_of_options = ['Select all Data',
- 'Unselect all Data',
- 'Select all Data 1D',
- 'Unselect all Data 1D',
- 'Select all Data 2D',
- 'Unselect all Data 2D']
- for option in list_of_options:
- self.selection_cbox.Append(str(option))
- self.selection_cbox.SetValue('Select all Data')
- wx.EVT_COMBOBOX(self.selection_cbox, -1, self._on_selection_type)
- self.sizer5.AddMany([(select_txt, 0, wx.ALL, 5),
- (self.selection_cbox, 0, wx.ALL, 5)])
- self.enable_selection()
-
- def _on_selection_type(self, event):
- """
- Select data according to patterns
- :param event: UI event
- """
- def check_item_and_children(control, check_value=True):
- self.tree_ctrl.CheckItem(data_ctrl, check_value)
- if data_ctrl.HasChildren():
- if check_value and not control.IsExpanded():
- # Only select children if control is expanded
- # Always deselect children, regardless (see ticket #259)
- return
- for child_ctrl in data_ctrl.GetChildren():
- self.tree_ctrl.CheckItem(child_ctrl, check_value)
-
- option = self.selection_cbox.GetValue()
-
- pos = self.selection_cbox.GetSelection()
- if pos == wx.NOT_FOUND:
- return
- option = self.selection_cbox.GetString(pos)
- for item in self.list_cb_data.values():
- data_ctrl, _, _, _, _, _, _, _ = item
- _, data_class, _ = self.tree_ctrl.GetItemPyData(data_ctrl)
- if option == 'Select all Data':
- check_item_and_children(data_ctrl, check_value=True)
- elif option == 'Unselect all Data':
- check_item_and_children(data_ctrl, check_value=False)
- elif option == 'Select all Data 1D':
- if data_class == 'Data1D':
- check_item_and_children(data_ctrl, check_value=True)
- elif option == 'Unselect all Data 1D':
- if data_class == 'Data1D':
- check_item_and_children(data_ctrl, check_value=False)
- elif option == 'Select all Data 2D':
- if data_class == 'Data2D':
- check_item_and_children(data_ctrl, check_value=True)
- elif option == 'Unselect all Data 2D':
- if data_class == 'Data2D':
- check_item_and_children(data_ctrl, check_value=False)
- self.enable_append()
- self.enable_freeze()
- self.enable_plot()
- self.enable_import()
- self.enable_remove()
-
- def layout_button(self):
- """
- Layout widgets related to buttons
- """
- # Load Data Button
- self.bt_add = wx.Button(self, wx.NewId(), "Load Data",
- size=(BUTTON_WIDTH, -1))
- self.bt_add.SetToolTipString("Load data files")
- wx.EVT_BUTTON(self, self.bt_add.GetId(), self._load_data)
-
- # Delete Data Button
- self.bt_remove = wx.Button(self, wx.NewId(), "Delete Data",
- size=(BUTTON_WIDTH, -1))
- self.bt_remove.SetToolTipString("Delete data from the application")
- wx.EVT_BUTTON(self, self.bt_remove.GetId(), self.on_remove)
-
- # Send data to perspective button
- self.bt_import = wx.Button(self, wx.NewId(), "Send To",
- size=(BUTTON_WIDTH, -1))
- self.bt_import.SetToolTipString("Send Data set to active perspective")
- wx.EVT_BUTTON(self, self.bt_import.GetId(), self.on_import)
-
- # Choose perspective to be send data to combo box
- self.perspective_cbox = wx.ComboBox(self, -1,
- style=wx.CB_READONLY)
- if not IS_MAC:
- self.perspective_cbox.SetMinSize((BUTTON_WIDTH*1.6, -1))
- wx.EVT_COMBOBOX(self.perspective_cbox, -1,
- self._on_perspective_selection)
-
- # Append data to current Graph Button
- self.bt_append_plot = wx.Button(self, wx.NewId(), "Append Plot To",
- size=(BUTTON_WIDTH, -1))
- self.bt_append_plot.SetToolTipString(
- "Plot the selected data in the active panel")
- wx.EVT_BUTTON(self, self.bt_append_plot.GetId(), self.on_append_plot)
-
- # Create a new graph and send data to that new graph button
- self.bt_plot = wx.Button(self, wx.NewId(), "New Plot",
- size=(BUTTON_WIDTH, -1))
- self.bt_plot.SetToolTipString("To trigger plotting")
- wx.EVT_BUTTON(self, self.bt_plot.GetId(), self.on_plot)
-
- # Freeze current theory button - becomes a data set and stays on graph
- self.bt_freeze = wx.Button(self, wx.NewId(), "Freeze Theory",
- size=(BUTTON_WIDTH, -1))
- freeze_tip = "To trigger freeze a theory: making a copy\n"
- freeze_tip += "of the theory checked to Data box,\n"
- freeze_tip += " so that it can act like a real data set."
- self.bt_freeze.SetToolTipString(freeze_tip)
- wx.EVT_BUTTON(self, self.bt_freeze.GetId(), self.on_freeze)
-
- # select plot to send to combo box (blank if no data)
- if sys.platform == 'darwin':
- self.cb_plotpanel = wx.ComboBox(self, -1,
- style=wx.CB_READONLY)
- else:
- self.cb_plotpanel = wx.ComboBox(self, -1,
- style=wx.CB_READONLY | wx.CB_SORT)
- wx.EVT_COMBOBOX(self.cb_plotpanel, -1, self._on_plot_selection)
- self.cb_plotpanel.Disable()
-
- # Help button
- self.bt_help = wx.Button(self, wx.NewId(), "HELP",
- size=(BUTTON_WIDTH, -1))
- self.bt_help.SetToolTipString("Help for the Data Explorer.")
- wx.EVT_BUTTON(self, self.bt_help.GetId(), self.on_help)
-
- self.sizer3.AddMany([(self.bt_add),
- ((10, 10)),
- (self.bt_remove),
- ((10, 10)),
- (self.bt_freeze),
- ((10, 10)),
- (self.bt_plot),
- ((10, 10)),
- (self.bt_append_plot),
- (self.cb_plotpanel,
- wx.EXPAND | wx.ADJUST_MINSIZE, 5),
- ((5, 5)),
- ((5, 5)),
- (self.bt_import, 0, wx.EXPAND | wx.RIGHT, 5),
- (self.perspective_cbox,
- wx.EXPAND | wx.ADJUST_MINSIZE, 5),
- ((10, 10)),
- (self.sizer4),
- ((10, 10)),
- (self.bt_help, 0, wx.RIGHT, 5)])
-
- self.sizer3.AddGrowableCol(1, 1)
- self.show_data_button()
- self.enable_remove()
- self.enable_import()
- self.enable_plot()
- self.enable_append()
- self.enable_freeze()
- self.enable_remove_plot()
-
- def layout_batch(self):
- """
- Set up batch mode options
- """
- self.rb_single_mode = wx.RadioButton(self, -1, 'Single Mode',
- style=wx.RB_GROUP)
- self.rb_batch_mode = wx.RadioButton(self, -1, 'Batch Mode')
- self.Bind(wx.EVT_RADIOBUTTON, self.on_single_mode,
- id=self.rb_single_mode.GetId())
- self.Bind(wx.EVT_RADIOBUTTON, self.on_batch_mode,
- id=self.rb_batch_mode.GetId())
-
- self.rb_single_mode.SetValue(not self.parent.batch_on)
- self.rb_batch_mode.SetValue(self.parent.batch_on)
- self.sizer4.AddMany([(self.rb_single_mode, 0, wx.ALL, 4),
- (self.rb_batch_mode, 0, wx.ALL, 4)])
-
- def on_single_mode(self, event):
- """
- Change to single mode
- :param event: UI event
- """
- if self.parent is not None:
- wx.PostEvent(self.parent, NewBatchEvent(enable=False))
-
- def on_batch_mode(self, event):
- """
- Change to batch mode
- :param event: UI event
- """
- if self.parent is not None:
- wx.PostEvent(self.parent,
- NewBatchEvent(enable=True))
-
- def _get_data_selection(self, event):
- """
- Get data selection from the right click
- :param event: UI event
- """
- data = None
- # selection = event.GetSelection()
- id, _, _ = self.FindFocus().GetSelection().GetData()
- data_list, theory_list = \
- self.parent.get_data_manager().get_by_id(id_list=[id])
- if data_list:
- data = data_list.values()[0]
- if data is None:
- data = theory_list.values()[0][0]
- return data
-
- def on_edit_data(self, event):
- """
- Pop Up Data Editor
- """
- data = self._get_data_selection(event)
- from sas.sasgui.guiframe.local_perspectives.plotting.masking \
- import MaskPanel as MaskDialog
-
- panel = MaskDialog(parent=self.parent, base=self,
- data=data, id=wx.NewId())
- panel.ShowModal()
-
- def on_plot_3d(self, event):
- """
- Frozen image of 3D
- """
- data = self._get_data_selection(event)
- from sas.sasgui.guiframe.local_perspectives.plotting.masking \
- import FloatPanel as Float3dDialog
-
- panel = Float3dDialog(base=self, data=data,
- dimension=3, id=wx.NewId())
- panel.ShowModal()
-
- def on_quick_plot(self, event):
- """
- Frozen plot
- """
- data = self._get_data_selection(event)
- if data.__class__.__name__ == "Data2D":
- dimension = 2
- else:
- dimension = 1
- # panel = QucikPlotDialog(base=self, data=data,
- # dimension=dimension, id=wx.NewId())
- frame = QucikPlotDialog(self, -1, "Plot " + data.name, 'log_{10}')
- self.parent.put_icon(frame)
- frame.add_plot(data)
- # frame.SetTitle(title)
- frame.Show(True)
- frame.SetFocus()
- # panel.ShowModal()
-
- def on_data_info(self, event):
- """
- Data Info panel
- """
- data = self._get_data_selection(event)
- if data.__class__.__name__ == "Data2D":
- self.parent.show_data2d(data, data.name)
- else:
- self.parent.show_data1d(data, data.name)
-
- def on_save_as(self, event):
- """
- Save data as a file
- """
- data = self._get_data_selection(event)
- # path = None
- default_name = data.name
- if default_name.count('.') > 0:
- default_name = default_name.split('.')[0]
- default_name += "_out"
- if self.parent is not None:
- if issubclass(data.__class__, Data1D):
- self.parent.save_data1d(data, default_name)
- elif issubclass(data.__class__, Data2D):
- self.parent.save_data2d(data, default_name)
- else:
- print "unable to save this type of data"
-
- def layout_data_list(self):
- """
- Add a listcrtl in the panel
- """
- # Add splitter
- w, h = self.parent.GetSize()
- splitter = wx.SplitterWindow(self)
- splitter.SetMinimumPaneSize(50)
- splitter.SetSashGravity(1.0)
-
- file_sizer = wx.BoxSizer(wx.VERTICAL)
- file_sizer.SetMinSize(wx.Size(w/13, h*2/5))
- theory_sizer = wx.BoxSizer(wx.VERTICAL)
- theory_sizer.SetMinSize(wx.Size(w/13, h*2/5))
-
- self.tree_ctrl = DataTreeCtrl(parent=splitter,
- style=wx.SUNKEN_BORDER,
- root="Available Data")
-
- self.tree_ctrl.Bind(CT.EVT_TREE_ITEM_CHECKING, self.on_check_item)
- self.tree_ctrl.Bind(CT.EVT_TREE_ITEM_MENU, self.on_right_click_data)
- # Create context menu for page
- self.data_menu = wx.Menu()
- id = wx.NewId()
- name = "Data Info"
- msg = "Show Data Info"
- self.data_menu.Append(id, name, msg)
- wx.EVT_MENU(self, id, self.on_data_info)
-
- id = wx.NewId()
- name = "Save As"
- msg = "Save Theory/Data as a file"
- self.data_menu.Append(id, name, msg)
- wx.EVT_MENU(self, id, self.on_save_as)
-
- quickplot_id = wx.NewId()
- name = "Quick Plot"
- msg = "Plot the current Data"
- self.data_menu.Append(quickplot_id, name, msg)
- wx.EVT_MENU(self, quickplot_id, self.on_quick_plot)
-
- self.plot3d_id = wx.NewId()
- name = "Quick 3DPlot (Slow)"
- msg = "Plot3D the current 2D Data"
- self.data_menu.Append(self.plot3d_id, name, msg)
- wx.EVT_MENU(self, self.plot3d_id, self.on_plot_3d)
-
- self.editmask_id = wx.NewId()
- name = "Edit Mask"
- msg = "Edit Mask for the current 2D Data"
- self.data_menu.Append(self.editmask_id, name, msg)
- wx.EVT_MENU(self, self.editmask_id, self.on_edit_data)
-
- self.tree_ctrl_theory = DataTreeCtrl(parent=splitter,
- style=wx.SUNKEN_BORDER,
- root="Available Theory")
- self.tree_ctrl_theory.Bind(CT.EVT_TREE_ITEM_CHECKING,
- self.on_check_item)
- self.tree_ctrl_theory.Bind(CT.EVT_TREE_ITEM_MENU,
- self.on_right_click_theory)
- splitter.SplitHorizontally(self.tree_ctrl, self.tree_ctrl_theory)
- self.sizer1.Add(splitter, 1, wx.EXPAND | wx.ALL, 10)
-
- def on_right_click_theory(self, event):
- """
- On click theory data
- """
- try:
- id, data_class_name, _ = \
- self.tree_ctrl_theory.GetSelection().GetData()
- _, _ = self.parent.get_data_manager().get_by_id(id_list=[id])
- except:
- return
- if self.data_menu is not None:
- menu_enable = (data_class_name == "Data2D")
- self.data_menu.Enable(self.editmask_id, False)
- self.data_menu.Enable(self.plot3d_id, menu_enable)
- self.PopupMenu(self.data_menu)
-
- def on_right_click_data(self, event):
- """
- Allow Editing Data
- """
- # selection = event.GetSelection()
- is_data = True
- try:
- id, data_class_name, _ = self.tree_ctrl.GetSelection().GetData()
- data_list, _ = \
- self.parent.get_data_manager().get_by_id(id_list=[id])
- if not data_list:
- is_data = False
- except:
- return
- if self.data_menu is not None:
- menu_enable = (data_class_name == "Data2D")
- maskmenu_enable = (menu_enable and is_data)
- self.data_menu.Enable(self.editmask_id, maskmenu_enable)
- self.data_menu.Enable(self.plot3d_id, menu_enable)
- self.PopupMenu(self.data_menu)
-
- def onContextMenu(self, event):
- """
- Retrieve the state selected state
- """
- # Skipping the save state functionality for release 0.9.0
- # return
- pos = event.GetPosition()
- pos = self.ScreenToClient(pos)
- self.PopupMenu(self.popUpMenu, pos)
-
- def on_check_item(self, event):
- """
- On check item
- """
- item = event.GetItem()
- item.Check(not item.IsChecked())
- self.enable_append()
- self.enable_freeze()
- self.enable_plot()
- self.enable_import()
- self.enable_remove()
- event.Skip()
-
- def fill_cbox_analysis(self, plugin):
- """
- fill the combobox with analysis name
- """
- self.list_of_perspective = plugin
- if self.parent is None or \
- not hasattr(self.parent, "get_current_perspective") or \
- len(self.list_of_perspective) == 0:
- return
- if self.parent is not None and self.perspective_cbox is not None:
- for plug in self.list_of_perspective:
- if plug.get_perspective():
- self.perspective_cbox.Append(plug.sub_menu, plug)
-
- curr_pers = self.parent.get_current_perspective()
- if curr_pers:
- self.perspective_cbox.SetStringSelection(curr_pers.sub_menu)
- self.enable_import()
-
- def load_data_list(self, list):
- """
- add need data with its theory under the tree
- """
- if list:
- for state_id, dstate in list.iteritems():
- data = dstate.get_data()
- theory_list = dstate.get_theory()
- if data is not None:
- data_name = str(data.name)
- data_title = str(data.title)
- data_run = str(data.run)
- data_class = data.__class__.__name__
- path = dstate.get_path()
- process_list = data.process
- data_id = data.id
- s_path = str(path)
- if state_id not in self.list_cb_data:
- # new state
- data_c = self.tree_ctrl.InsertItem(self.tree_ctrl.root,
- 0, data_name,
- ct_type=1,
- data=(data_id, data_class, state_id))
- data_c.Check(True)
- d_i_c = self.tree_ctrl.AppendItem(data_c, 'Info')
- d_t_c = self.tree_ctrl.AppendItem(d_i_c,
- 'Title: %s' %
- data_title)
- r_n_c = self.tree_ctrl.AppendItem(d_i_c,
- 'Run: %s' % data_run)
- i_c_c = self.tree_ctrl.AppendItem(d_i_c,
- 'Type: %s' %
- data_class)
- p_c_c = self.tree_ctrl.AppendItem(d_i_c,
- "Path: '%s'" % s_path)
- d_p_c = self.tree_ctrl.AppendItem(d_i_c, 'Process')
-
- for process in process_list:
- process_str = str(process).replace('\n', ' ')
- if len(process_str) > 20:
- process_str = process_str[:20] + ' [...]'
- self.tree_ctrl.AppendItem(d_p_c, process_str)
- theory_child = self.tree_ctrl.AppendItem(data_c,
- "THEORIES")
- self.list_cb_data[state_id] = [data_c,
- d_i_c,
- d_t_c,
- r_n_c,
- i_c_c,
- p_c_c,
- d_p_c,
- theory_child]
- else:
- data_ctrl_list = self.list_cb_data[state_id]
- # This state is already display replace it contains
- data_c, d_i_c, d_t_c, r_n_c, i_c_c, p_c_c, d_p_c, _ \
- = data_ctrl_list
- self.tree_ctrl.SetItemText(data_c, data_name)
- temp = (data_id, data_class, state_id)
- self.tree_ctrl.SetItemPyData(data_c, temp)
- self.tree_ctrl.SetItemText(i_c_c,
- 'Type: %s' % data_class)
- self.tree_ctrl.SetItemText(p_c_c,
- 'Path: %s' % s_path)
- self.tree_ctrl.DeleteChildren(d_p_c)
- for process in process_list:
- if not process.is_empty():
- _ = self.tree_ctrl.AppendItem(d_p_c,
- process.single_line_desc())
- wx.CallAfter(self.append_theory, state_id, theory_list)
- # Sort by data name
- if self.tree_ctrl.root:
- self.tree_ctrl.SortChildren(self.tree_ctrl.root)
- # Expand root if # of data sets > 0
- if self.tree_ctrl.GetCount() > 0:
- self.tree_ctrl.root.Expand()
- self.enable_remove()
- self.enable_import()
- self.enable_plot()
- self.enable_freeze()
- self.enable_selection()
-
- def _uncheck_all(self):
- """
- Uncheck all check boxes
- """
- for item in self.list_cb_data.values():
- data_ctrl, _, _, _, _, _, _, _ = item
- self.tree_ctrl.CheckItem(data_ctrl, False)
- self.enable_append()
- self.enable_freeze()
- self.enable_plot()
- self.enable_import()
- self.enable_remove()
-
- def append_theory(self, state_id, theory_list):
- """
- append theory object under data from a state of id = state_id
- replace that theory if already displayed
- """
- if not theory_list:
- return
- if state_id not in self.list_cb_data.keys():
- root = self.tree_ctrl_theory.root
- tree = self.tree_ctrl_theory
- else:
- item = self.list_cb_data[state_id]
- data_c, _, _, _, _, _, _, _ = item
- root = data_c
- tree = self.tree_ctrl
- if root is not None:
- wx.CallAfter(self.append_theory_helper, tree=tree, root=root,
- state_id=state_id,
- theory_list=theory_list)
- if self.tree_ctrl_theory.GetCount() > 0:
- self.tree_ctrl_theory.root.Expand()
-
- def append_theory_helper(self, tree, root, state_id, theory_list):
- """
- Append theory helper
- """
- if state_id in self.list_cb_theory.keys():
- # update current list of theory for this data
- theory_list_ctrl = self.list_cb_theory[state_id]
-
- for theory_id, item in theory_list.iteritems():
- theory_data, _ = item
- if theory_data is None:
- name = "Unknown"
- theory_class = "Unknown"
- theory_id = "Unknown"
- temp = (None, None, None)
- else:
- name = theory_data.name
- theory_class = theory_data.__class__.__name__
- theory_id = theory_data.id
- # if theory_state is not None:
- # name = theory_state.model.name
- temp = (theory_id, theory_class, state_id)
- if theory_id not in theory_list_ctrl:
- # add new theory
- t_child = tree.AppendItem(root,
- name, ct_type=1, data=temp)
- t_i_c = tree.AppendItem(t_child, 'Info')
- i_c_c = tree.AppendItem(t_i_c,
- 'Type: %s' % theory_class)
- t_p_c = tree.AppendItem(t_i_c, 'Process')
-
- for process in theory_data.process:
- tree.AppendItem(t_p_c, process.__str__())
- theory_list_ctrl[theory_id] = [t_child,
- i_c_c,
- t_p_c]
- else:
- # replace theory
- t_child, i_c_c, t_p_c = theory_list_ctrl[theory_id]
- tree.SetItemText(t_child, name)
- tree.SetItemPyData(t_child, temp)
- tree.SetItemText(i_c_c, 'Type: %s' % theory_class)
- tree.DeleteChildren(t_p_c)
- for process in theory_data.process:
- tree.AppendItem(t_p_c, process.__str__())
-
- else:
- # data didn't have a theory associated it before
- theory_list_ctrl = {}
- for theory_id, item in theory_list.iteritems():
- theory_data, _ = item
- if theory_data is not None:
- name = theory_data.name
- theory_class = theory_data.__class__.__name__
- theory_id = theory_data.id
- # if theory_state is not None:
- # name = theory_state.model.name
- temp = (theory_id, theory_class, state_id)
- t_child = tree.AppendItem(root,
- name, ct_type=1,
- data=(theory_data.id, theory_class, state_id))
- t_i_c = tree.AppendItem(t_child, 'Info')
- i_c_c = tree.AppendItem(t_i_c,
- 'Type: %s' % theory_class)
- t_p_c = tree.AppendItem(t_i_c, 'Process')
-
- for process in theory_data.process:
- tree.AppendItem(t_p_c, process.__str__())
-
- theory_list_ctrl[theory_id] = [t_child, i_c_c, t_p_c]
- # self.list_cb_theory[data_id] = theory_list_ctrl
- self.list_cb_theory[state_id] = theory_list_ctrl
-
- def set_data_helper(self):
- """
- Set data helper
- """
- data_to_plot = []
- state_to_plot = []
- theory_to_plot = []
- for value in self.list_cb_data.values():
- item, _, _, _, _, _, _, _ = value
- if item.IsChecked():
- data_id, _, state_id = self.tree_ctrl.GetItemPyData(item)
- data_to_plot.append(data_id)
- if state_id not in state_to_plot:
- state_to_plot.append(state_id)
-
- for theory_dict in self.list_cb_theory.values():
- for _, value in theory_dict.iteritems():
- item, _, _ = value
- if item.IsChecked():
- theory_id, _, state_id = self.tree_ctrl.GetItemPyData(item)
- theory_to_plot.append(theory_id)
- if state_id not in state_to_plot:
- state_to_plot.append(state_id)
- return data_to_plot, theory_to_plot, state_to_plot
-
- def remove_by_id(self, id):
- """
- Remove_dat by id
- """
- for item in self.list_cb_data.values():
- data_c, _, _, _, _, _, _, _ = item
- data_id, _, state_id = self.tree_ctrl.GetItemPyData(data_c)
- if id == data_id:
- self.tree_ctrl.Delete(data_c)
- del self.list_cb_data[state_id]
- del self.list_cb_theory[data_id]
-
- def load_error(self, error=None):
- """
- Pop up an error message.
-
- :param error: details error message to be displayed
- """
- if error is not None or str(error).strip() != "":
- dial = wx.MessageDialog(self.parent, str(error),
- 'Error Loading File',
- wx.OK | wx.ICON_EXCLAMATION)
- dial.ShowModal()
-
- def _load_data(self, event):
- """
- send an event to the parent to trigger load from plugin module
- """
- if self.parent is not None:
- wx.PostEvent(self.parent, NewLoadDataEvent())
-
- def on_remove(self, event, prompt=True):
- """
- Get a list of item checked and remove them from the treectrl
- Ask the parent to remove reference to this item
- """
- if prompt:
- msg = "This operation will delete the data sets checked "
- msg += "and all the dependents."
- msg_box = wx.MessageDialog(None, msg, 'Warning', wx.OK|wx.CANCEL)
- if msg_box.ShowModal() != wx.ID_OK:
- return
-
- data_to_remove, theory_to_remove, _ = self.set_data_helper()
- data_key = []
- theory_key = []
- # remove data from treectrl
- for d_key, item in self.list_cb_data.iteritems():
- data_c, _, _, _, _, _, _, _ = item
- if data_c.IsChecked():
- self.tree_ctrl.Delete(data_c)
- data_key.append(d_key)
- if d_key in self.list_cb_theory.keys():
- theory_list_ctrl = self.list_cb_theory[d_key]
- theory_to_remove += theory_list_ctrl.keys()
- # Remove theory from treectrl
- for _, theory_dict in self.list_cb_theory.iteritems():
- for key, value in theory_dict.iteritems():
- item, _, _ = value
- if item.IsChecked():
- try:
- self.tree_ctrl.Delete(item)
- except:
- pass
- theory_key.append(key)
-
- # Remove data and related theory references
- for key in data_key:
- del self.list_cb_data[key]
- if key in theory_key:
- del self.list_cb_theory[key]
- # remove theory references independently of data
- for key in theory_key:
- for _, theory_dict in self.list_cb_theory.iteritems():
- if key in theory_dict:
- for key, value in theory_dict.iteritems():
- item, _, _ = value
- if item.IsChecked():
- try:
- self.tree_ctrl_theory.Delete(item)
- except:
- pass
- del theory_dict[key]
-
- self.parent.remove_data(data_id=data_to_remove,
- theory_id=theory_to_remove)
- self.enable_remove()
- self.enable_freeze()
- self.enable_remove_plot()
-
- def on_import(self, event=None):
- """
- Get all select data and set them to the current active perspetive
- """
- if event is not None:
- event.Skip()
- data_id, theory_id, state_id = self.set_data_helper()
- temp = data_id + state_id
- self.parent.set_data(data_id=temp, theory_id=theory_id)
-
- def on_append_plot(self, event=None):
- """
- append plot to plot panel on focus
- """
- self._on_plot_selection()
- data_id, theory_id, state_id = self.set_data_helper()
- self.parent.plot_data(data_id=data_id,
- state_id=state_id,
- theory_id=theory_id,
- append=True)
-
- def on_plot(self, event=None):
- """
- Send a list of data names to plot
- """
- data_id, theory_id, state_id = self.set_data_helper()
- self.parent.plot_data(data_id=data_id,
- state_id=state_id,
- theory_id=theory_id,
- append=False)
- self.enable_remove_plot()
-
- def on_close_page(self, event=None):
- """
- On close
- """
- if event is not None:
- event.Skip()
- # send parent to update menu with no show nor hide action
- self.parent.show_data_panel(action=False)
-
- def on_freeze(self, event):
- """
- On freeze to make a theory to a data set
- """
- _, theory_id, state_id = self.set_data_helper()
- if len(theory_id) > 0:
- self.parent.freeze(data_id=state_id, theory_id=theory_id)
- msg = "Freeze Theory:"
- msg += " The theory(s) copied to the Data box as a data set."
- else:
- msg = "Freeze Theory: Requires at least one theory checked."
- wx.PostEvent(self.parent, StatusEvent(status=msg))
-
- def set_active_perspective(self, name):
- """
- set the active perspective
- """
- self.perspective_cbox.SetStringSelection(name)
- self.enable_import()
-
- def _on_delete_plot_panel(self, event):
- """
- get an event with attribute name and caption to delete existing name
- from the combobox of the current panel
- """
- # name = event.name
- caption = event.caption
- if self.cb_plotpanel is not None:
- pos = self.cb_plotpanel.FindString(str(caption))
- if pos != wx.NOT_FOUND:
- self.cb_plotpanel.Delete(pos)
- self.enable_append()
-
- def set_panel_on_focus(self, name=None):
- """
- set the plot panel on focus
- """
- if self.cb_plotpanel and self.cb_plotpanel.IsBeingDeleted():
- return
- for _, value in self.parent.plot_panels.iteritems():
- name_plot_panel = str(value.window_caption)
- if name_plot_panel not in self.cb_plotpanel.GetItems():
- self.cb_plotpanel.Append(name_plot_panel, value)
- if name is not None and name == name_plot_panel:
- self.cb_plotpanel.SetStringSelection(name_plot_panel)
- break
- self.enable_append()
- self.enable_remove_plot()
-
- def set_plot_unfocus(self):
- """
- Unfocus plot
- """
- return
-
- def _on_perspective_selection(self, event=None):
- """
- select the current perspective for guiframe
- """
- selection = self.perspective_cbox.GetSelection()
- if self.perspective_cbox.GetValue() != 'None':
- perspective = self.perspective_cbox.GetClientData(selection)
- perspective.on_perspective(event=None)
- self.parent.check_multimode(perspective=perspective)
-
- def _on_plot_selection(self, event=None):
- """
- On source combobox selection
- """
- if event is not None:
- combo = event.GetEventObject()
- event.Skip()
- else:
- combo = self.cb_plotpanel
- selection = combo.GetSelection()
-
- if combo.GetValue() != 'None':
- panel = combo.GetClientData(selection)
- self.parent.on_set_plot_focus(panel)
-
- def on_close_plot(self, event):
- """
- clseo the panel on focus
- """
- self.enable_append()
- selection = self.cb_plotpanel.GetSelection()
- if self.cb_plotpanel.GetValue() != 'None':
- panel = self.cb_plotpanel.GetClientData(selection)
- if self.parent is not None and panel is not None:
- wx.PostEvent(self.parent,
- NewPlotEvent(group_id=panel.group_id,
- action="delete"))
- self.enable_remove_plot()
-
- def set_frame(self, frame):
- """
- """
- self.frame = frame
-
- def get_frame(self):
- """
- """
- return self.frame
-
- def on_help(self, event):
- """
- Bring up the data manager Documentation whenever
- the HELP button is clicked.
-
- Calls DocumentationWindow with the path of the location within the
- documentation tree (after /doc/ ....". Note that when using old
- versions of Wx (before 2.9) and thus not the release version of
- installers, the help comes up at the top level of the file as
- webbrowser does not pass anything past the # to the browser when it is
- running "file:///...."
-
- :param event: Triggers on clicking the help button
- """
-
- #import documentation window here to avoid circular imports
- #if put at top of file with rest of imports.
- from documentation_window import DocumentationWindow
-
- _TreeLocation = "user/sasgui/guiframe/data_explorer_help.html"
- _doc_viewer = DocumentationWindow(self, -1, _TreeLocation, "",
- "Data Explorer Help")
-
- def on_close(self, event):
- """
- On close event
- """
- self.parent.show_data_panel(event)
-
- def set_schedule_full_draw(self, panel=None, func='del'):
- """
- Send full draw to guimanager
- """
- self.parent.set_schedule_full_draw(panel, func)
-
- def enable_remove_plot(self):
- """
- enable remove plot button if there is a plot panel on focus
- """
- pass
- #if self.cb_plotpanel.GetCount() == 0:
- # self.bt_close_plot.Disable()
- #else:
- # self.bt_close_plot.Enable()
-
- def enable_remove(self):
- """
- enable or disable remove button
- """
- n_t = self.tree_ctrl.GetCount()
- n_t_t = self.tree_ctrl_theory.GetCount()
- if n_t + n_t_t <= 0:
- self.bt_remove.Disable()
- else:
- self.bt_remove.Enable()
-
- def enable_import(self):
- """
- enable or disable send button
- """
- n_t = 0
- if self.tree_ctrl is not None:
- n_t = self.tree_ctrl.GetCount()
- if n_t > 0 and len(self.list_of_perspective) > 0:
- self.bt_import.Enable()
- else:
- self.bt_import.Disable()
- if len(self.list_of_perspective) <= 0 or \
- self.perspective_cbox.GetValue() in ["None",
- "No Active Application"]:
- self.perspective_cbox.Disable()
- else:
- self.perspective_cbox.Enable()
-
- def enable_plot(self):
- """
- enable or disable plot button
- """
- n_t = 0
- n_t_t = 0
- if self.tree_ctrl is not None:
- n_t = self.tree_ctrl.GetCount()
- if self.tree_ctrl_theory is not None:
- n_t_t = self.tree_ctrl_theory.GetCount()
- if n_t + n_t_t <= 0:
- self.bt_plot.Disable()
- else:
- self.bt_plot.Enable()
- self.enable_append()
-
- def enable_append(self):
- """
- enable or disable append button
- """
- n_t = 0
- n_t_t = 0
- if self.tree_ctrl is not None:
- n_t = self.tree_ctrl.GetCount()
- if self.tree_ctrl_theory is not None:
- n_t_t = self.tree_ctrl_theory.GetCount()
- if n_t + n_t_t <= 0:
- self.bt_append_plot.Disable()
- self.cb_plotpanel.Disable()
- elif self.cb_plotpanel.GetCount() <= 0:
- self.cb_plotpanel.Disable()
- self.bt_append_plot.Disable()
- else:
- self.bt_append_plot.Enable()
- self.cb_plotpanel.Enable()
-
- def check_theory_to_freeze(self):
- """
- Check_theory_to_freeze
- """
- def enable_freeze(self):
- """
- enable or disable the freeze button
- """
- n_t_t = 0
- n_l = 0
- if self.tree_ctrl_theory is not None:
- n_t_t = self.tree_ctrl_theory.GetCount()
- n_l = len(self.list_cb_theory)
- if (n_t_t + n_l > 0):
- self.bt_freeze.Enable()
- else:
- self.bt_freeze.Disable()
-
- def enable_selection(self):
- """
- enable or disable combobo box selection
- """
- n_t = 0
- n_t_t = 0
- if self.tree_ctrl is not None:
- n_t = self.tree_ctrl.GetCount()
- if self.tree_ctrl_theory is not None:
- n_t_t = self.tree_ctrl_theory.GetCount()
- if n_t + n_t_t > 0 and self.selection_cbox is not None:
- self.selection_cbox.Enable()
- else:
- self.selection_cbox.Disable()
-
- def show_data_button(self):
- """
- show load data and remove data button if
- dataloader on else hide them
- """
- try:
- gui_style = self.parent.get_style()
- style = gui_style & GUIFRAME.DATALOADER_ON
- if style == GUIFRAME.DATALOADER_ON:
- #self.bt_remove.Show(True)
- self.bt_add.Show(True)
- else:
- #self.bt_remove.Hide()
- self.bt_add.Hide()
- except:
- #self.bt_remove.Hide()
- self.bt_add.Hide()
-
-
-WIDTH = 400
-HEIGHT = 300
-
-
-class DataDialog(wx.Dialog):
- """
- Allow file selection at loading time
- """
- def __init__(self, data_list, parent=None, text='', *args, **kwds):
- wx.Dialog.__init__(self, parent, *args, **kwds)
- self.SetTitle("Data Selection")
- self.SetSize((WIDTH, HEIGHT))
- self.list_of_ctrl = []
- if not data_list:
- return
- self._sizer_main = wx.BoxSizer(wx.VERTICAL)
- self._sizer_txt = wx.BoxSizer(wx.VERTICAL)
- self._sizer_button = wx.BoxSizer(wx.HORIZONTAL)
- self.sizer = wx.GridBagSizer(5, 5)
- self._panel = ScrolledPanel(self, style=wx.RAISED_BORDER,
- size=(WIDTH-20, HEIGHT-50))
- self._panel.SetupScrolling()
- self.__do_layout(data_list, text=text)
-
- def __do_layout(self, data_list, text=''):
- """
- layout the dialog
- """
- if not data_list or len(data_list) <= 1:
- return
- # add text
-
- text = "Deleting these file reset some panels.\n"
- text += "Do you want to proceed?\n"
- text_ctrl = wx.StaticText(self, -1, str(text))
- self._sizer_txt.Add(text_ctrl)
- iy = 0
- ix = 0
- # data_count = 0
- for (data_name, in_use, sub_menu) in range(len(data_list)):
- if in_use:
- ctrl_name = wx.StaticBox(self, -1, str(data_name))
- ctrl_in_use = wx.StaticBox(self, -1, " is used by ")
- plug_name = str(sub_menu) + "\n"
- # ctrl_sub_menu = wx.StaticBox(self, -1, plug_name)
- self.sizer.Add(ctrl_name, (iy, ix),
- (1, 1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
- ix += 1
- self._sizer_button.Add(ctrl_in_use, 1,
- wx.EXPAND|wx.ADJUST_MINSIZE, 0)
- ix += 1
- self._sizer_button.Add(plug_name, 1,
- wx.EXPAND|wx.ADJUST_MINSIZE, 0)
- iy += 1
- self._panel.SetSizer(self.sizer)
- # add sizer
- self._sizer_button.Add((20, 20), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0)
- button_cancel = wx.Button(self, wx.ID_CANCEL, "Cancel")
- self._sizer_button.Add(button_cancel, 0,
- wx.LEFT|wx.RIGHT|wx.ADJUST_MINSIZE, 10)
- button_OK = wx.Button(self, wx.ID_OK, "Ok")
- button_OK.SetFocus()
- self._sizer_button.Add(button_OK, 0,
- wx.LEFT|wx.RIGHT|wx.ADJUST_MINSIZE, 10)
- static_line = wx.StaticLine(self, -1)
-
- self._sizer_txt.Add(self._panel, 1, wx.EXPAND|wx.LEFT|wx.RIGHT, 5)
- self._sizer_main.Add(self._sizer_txt, 1, wx.EXPAND|wx.ALL, 10)
- #self._sizer_main.Add(self._data_text_ctrl, 0,
- # wx.EXPAND|wx.LEFT|wx.RIGHT, 10)
- self._sizer_main.Add(static_line, 0, wx.EXPAND, 0)
- self._sizer_main.Add(self._sizer_button, 0, wx.EXPAND|wx.ALL, 10)
- self.SetSizer(self._sizer_main)
- self.Layout()
-
- def get_data(self):
- """
- return the selected data
- """
- temp = []
- for item in self.list_of_ctrl:
- cb, data = item
- if cb.GetValue():
- temp.append(data)
- return temp
-
-class DataFrame(wx.Frame):
- """
- Data Frame
- """
- ## Internal name for the AUI manager
- window_name = "Data Panel"
- ## Title to appear on top of the window
- window_caption = "Data Panel"
- ## Flag to tell the GUI manager that this panel is not
- # tied to any perspective
- ALWAYS_ON = True
-
- def __init__(self, parent=None, owner=None, manager=None, size=(300, 800),
- list_of_perspective=[], list=[], *args, **kwds):
- kwds['size'] = size
- kwds['id'] = -1
- kwds['title'] = "Loaded Data"
- wx.Frame.__init__(self, parent=parent, *args, **kwds)
- self.parent = parent
- self.owner = owner
- self._manager = manager
- self.panel = DataPanel(parent=self,
- manager=manager,
- list_of_perspective=list_of_perspective)
-
- def load_data_list(self, list=[]):
- """
- Fill the list inside its panel
- """
- self.panel.load_data_list(list=list)
-
-
-from sas.sasgui.guiframe.dataFitting import Theory1D
-from sas.sasgui.guiframe.data_state import DataState
-
-
-class State():
- """
- DataPanel State
- """
- def __init__(self):
- self.msg = ""
- def __str__(self):
- self.msg = "model mane : model1\n"
- self.msg += "params : \n"
- self.msg += "name value\n"
- return self.msg
-
-
-def set_data_state(data=None, path=None, theory=None, state=None):
- """
- Set data state
- """
- dstate = DataState(data=data)
- dstate.set_path(path=path)
- dstate.set_theory(theory, state)
-
- return dstate
-
-if __name__ == "__main__":
-
- app = wx.App()
- try:
- # list_of_perspective = [('perspective2', False), ('perspective1', True)]
- data_list1 = {}
- # state 1
- data1 = Data2D()
- data1.name = "data2"
- data1.id = 1
- data1.append_empty_process()
- process1 = data1.process[len(data1.process)-1]
- process1.data = "07/01/2010"
- theory1 = Data2D()
- theory1.id = 34
- theory1.name = "theory1"
- path1 = "path1"
- state1 = State()
- data_list1['1'] = set_data_state(data1, path1, theory1, state1)
- # state 2
- data1 = Data2D()
- data1.name = "data2"
- data1.id = 76
- theory1 = Data2D()
- theory1.id = 78
- theory1.name = "CoreShell 07/24/25"
- path1 = "path2"
- # state3
- state1 = State()
- data_list1['2'] = set_data_state(data1, path1, theory1, state1)
- data1 = Data1D()
- data1.id = 3
- data1.name = "data2"
- theory1 = Theory1D()
- theory1.name = "CoreShell"
- theory1.id = 4
- theory1.append_empty_process()
- process1 = theory1.process[len(theory1.process)-1]
- process1.description = "this is my description"
- path1 = "path3"
- data1.append_empty_process()
- process1 = data1.process[len(data1.process)-1]
- process1.data = "07/22/2010"
- data_list1['4'] = set_data_state(data1, path1, theory1, state1)
- # state 4
- temp_data_list = {}
- data1.name = "data5 erasing data2"
- temp_data_list['4'] = set_data_state(data1, path1, theory1, state1)
- # state 5
- data1 = Data2D()
- data1.name = "data3"
- data1.id = 5
- data1.append_empty_process()
- process1 = data1.process[len(data1.process)-1]
- process1.data = "07/01/2010"
- theory1 = Theory1D()
- theory1.name = "Cylinder"
- path1 = "path2"
- state1 = State()
- dstate1 = set_data_state(data1, path1, theory1, state1)
- theory1 = Theory1D()
- theory1.id = 6
- theory1.name = "CoreShell"
- dstate1.set_theory(theory1)
- theory1 = Theory1D()
- theory1.id = 6
- theory1.name = "CoreShell replacing coreshell in data3"
- dstate1.set_theory(theory1)
- data_list1['3'] = dstate1
- #state 6
- data_list1['6'] = set_data_state(None, path1, theory1, state1)
- data_list1['6'] = set_data_state(theory=theory1, state=None)
- theory1 = Theory1D()
- theory1.id = 7
- data_list1['6'] = set_data_state(theory=theory1, state=None)
- data_list1['7'] = set_data_state(theory=theory1, state=None)
- window = DataFrame(list=data_list1)
- window.load_data_list(list=data_list1)
- window.Show(True)
- window.load_data_list(list=temp_data_list)
- except:
- # raise
- print "error", sys.exc_value
-
- app.MainLoop()
+################################################################################
+# This software was developed by the University of Tennessee as part of the
+# Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
+# project funded by the US National Science Foundation.
+#
+# See the license text in license.txt
+#
+# copyright 2010, University of Tennessee
+################################################################################
+"""
+This module provides Graphic interface for the data_manager module.
+"""
+from __future__ import print_function
+
+import wx
+from wx.build import build_options
+
+import sys
+from wx.lib.scrolledpanel import ScrolledPanel
+import wx.lib.agw.customtreectrl as CT
+from sas.sasgui.guiframe.dataFitting import Data1D
+from sas.sasgui.guiframe.dataFitting import Data2D
+from sas.sasgui.guiframe.panel_base import PanelBase
+from sas.sasgui.guiframe.events import StatusEvent
+from sas.sasgui.guiframe.events import EVT_DELETE_PLOTPANEL
+from sas.sasgui.guiframe.events import NewLoadDataEvent
+from sas.sasgui.guiframe.events import NewPlotEvent
+from sas.sasgui.guiframe.gui_style import GUIFRAME
+from sas.sasgui.guiframe.events import NewBatchEvent
+from sas.sascalc.dataloader.loader import Loader
+# from sas.sasgui.guiframe.local_perspectives.plotting.masking \
+# import FloatPanel as QucikPlotDialog
+from sas.sasgui.guiframe.local_perspectives.plotting.SimplePlot \
+ import PlotFrame as QucikPlotDialog
+from sas import get_local_config
+
+config = get_local_config()
+
+# Check version
+toks = str(wx.__version__).split('.')
+if int(toks[1]) < 9:
+ if int(toks[2]) < 12:
+ wx_version = 811
+ else:
+ wx_version = 812
+else:
+ wx_version = 900
+
+extension_list = []
+if config.APPLICATION_STATE_EXTENSION is not None:
+ extension_list.append(config.APPLICATION_STATE_EXTENSION)
+EXTENSIONS = config.PLUGIN_STATE_EXTENSIONS + extension_list
+PLUGINS_WLIST = config.PLUGINS_WLIST
+APPLICATION_WLIST = config.APPLICATION_WLIST
+
+# Control panel width
+if sys.platform.count("win32") > 0:
+ PANEL_WIDTH = 235
+ PANEL_HEIGHT = 700
+ CBOX_WIDTH = 140
+ BUTTON_WIDTH = 80
+ FONT_VARIANT = 0
+ IS_MAC = False
+else:
+ PANEL_WIDTH = 255
+ PANEL_HEIGHT = 750
+ CBOX_WIDTH = 155
+ BUTTON_WIDTH = 100
+ FONT_VARIANT = 1
+ IS_MAC = True
+
+STYLE_FLAG = (wx.RAISED_BORDER | CT.TR_HAS_BUTTONS |
+ wx.WANTS_CHARS | CT.TR_HAS_VARIABLE_ROW_HEIGHT)
+
+
+class DataTreeCtrl(CT.CustomTreeCtrl):
+ """
+ Check list control to be used for Data Panel
+ """
+ def __init__(self, parent, root, *args, **kwds):
+ # agwstyle is introduced in wx.2.8.11 but is not working for mac
+ if IS_MAC and wx_version < 812:
+ try:
+ kwds['style'] = STYLE_FLAG
+ CT.CustomTreeCtrl.__init__(self, parent, *args, **kwds)
+ except:
+ del kwds['style']
+ CT.CustomTreeCtrl.__init__(self, parent, *args, **kwds)
+ else:
+ # agwstyle is introduced in wx.2.8.11
+ # argument working only for windows
+ try:
+ kwds['agwStyle'] = STYLE_FLAG
+ CT.CustomTreeCtrl.__init__(self, parent, *args, **kwds)
+ except:
+ try:
+ del kwds['agwStyle']
+ kwds['style'] = STYLE_FLAG
+ CT.CustomTreeCtrl.__init__(self, parent, *args, **kwds)
+ except:
+ del kwds['style']
+ CT.CustomTreeCtrl.__init__(self, parent, *args, **kwds)
+ self.root = self.AddRoot(root)
+
+ def OnCompareItems(self, item1, item2):
+ """
+ Overrides OnCompareItems in wx.TreeCtrl.
+ Used by the SortChildren method.
+ """
+ # Get the item data
+ data_1 = self.GetItemText(item1)
+ data_2 = self.GetItemText(item2)
+ # Compare the item data
+ if data_1 < data_2:
+ return -1
+ elif data_1 > data_2:
+ return 1
+ else:
+ return 0
+
+
+class DataPanel(ScrolledPanel, PanelBase):
+ """
+ This panel displays data available in the application and widgets to
+ interact with data.
+ """
+ # Internal name for the AUI manager
+ window_name = "Data Panel"
+ # Title to appear on top of the window
+ window_caption = "Data Explorer"
+ # type of window
+ window_type = "Data Panel"
+ # Flag to tell the GUI manager that this panel is not
+ # tied to any perspective
+ # ALWAYS_ON = True
+
+ def __init__(self, parent,
+ list=None,
+ size=(PANEL_WIDTH, PANEL_HEIGHT),
+ id=-1,
+ list_of_perspective=None, manager=None, *args, **kwds):
+ # kwds['size'] = size
+ # kwds['style'] = STYLE_FLAG
+ ScrolledPanel.__init__(self, parent=parent, id=id, *args, **kwds)
+ PanelBase.__init__(self, parent)
+ self.SetupScrolling()
+ # Set window's font size
+ self.SetWindowVariant(variant=FONT_VARIANT)
+ self.loader = Loader()
+ # Default location
+ self._default_save_location = None
+ self.all_data1d = True
+ self.parent = parent.parent
+ self._manager = manager
+ self.frame = parent
+ if list is None:
+ list = []
+ self.list_of_data = list
+ if list_of_perspective is None:
+ list_of_perspective = []
+ self.list_of_perspective = list_of_perspective
+ self.list_rb_perspectives = []
+ self.list_cb_data = {}
+ self.list_cb_theory = {}
+ self.tree_ctrl = None
+ self.tree_ctrl_theory = None
+ self.perspective_cbox = None
+ # Create context menu for page
+ self.data_menu = None
+ self.popUpMenu = None
+ self.plot3d_id = None
+ self.editmask_id = None
+ # Default attr
+ self.vbox = None
+ self.sizer1 = None
+ self.sizer2 = None
+ self.sizer3 = None
+ self.sizer4 = None
+ self.sizer5 = None
+ self.selection_cbox = None
+ self.bt_add = None
+ self.bt_remove = None
+ self.bt_import = None
+ self.bt_append_plot = None
+ self.bt_plot = None
+ self.bt_freeze = None
+ self.cb_plotpanel = None
+ self.rb_single_mode = None
+ self.rb_batch_mode = None
+
+ self.owner = None
+ self.do_layout()
+ self.fill_cbox_analysis(self.list_of_perspective)
+ self.Bind(wx.EVT_SHOW, self.on_close_page)
+ if self.parent is not None:
+ self.parent.Bind(EVT_DELETE_PLOTPANEL, self._on_delete_plot_panel)
+
+ def do_layout(self):
+ """
+ Create the panel layout
+ """
+ self.define_panel_structure()
+ self.layout_selection()
+ self.layout_data_list()
+ self.layout_batch()
+ self.layout_button()
+
+ def disable_app_combo(self, enable):
+ """
+ Disable app combo box
+ """
+ self.perspective_cbox.Enable(enable)
+
+ def define_panel_structure(self):
+ """
+ Define the skeleton of the panel
+ """
+ w, h = self.parent.GetSize()
+ self.vbox = wx.BoxSizer(wx.VERTICAL)
+ self.sizer1 = wx.BoxSizer(wx.VERTICAL)
+ self.sizer1.SetMinSize(wx.Size(w/13, h*2/5))
+
+ self.sizer2 = wx.BoxSizer(wx.VERTICAL)
+ self.sizer3 = wx.FlexGridSizer(9, 2, 4, 1)
+ self.sizer4 = wx.BoxSizer(wx.VERTICAL)
+ self.sizer5 = wx.BoxSizer(wx.VERTICAL)
+
+ self.vbox.Add(self.sizer5, 0, wx.EXPAND | wx.ALL, 1)
+ self.vbox.Add(self.sizer1, 1, wx.EXPAND | wx.ALL, 0)
+ self.vbox.Add(self.sizer2, 0, wx.EXPAND | wx.ALL, 1)
+ self.vbox.Add(self.sizer3, 0, wx.EXPAND | wx.ALL, 10)
+ # self.vbox.Add(self.sizer4, 0, wx.EXPAND|wx.ALL,5)
+
+ self.SetSizer(self.vbox)
+
+ def layout_selection(self):
+ """
+ Create selection option combo box
+ """
+ select_txt = wx.StaticText(self, -1, 'Selection Options')
+ select_txt.SetForegroundColour('blue')
+ self.selection_cbox = wx.ComboBox(self, -1, style=wx.CB_READONLY)
+ list_of_options = ['Select all Data',
+ 'Unselect all Data',
+ 'Select all Data 1D',
+ 'Unselect all Data 1D',
+ 'Select all Data 2D',
+ 'Unselect all Data 2D']
+ for option in list_of_options:
+ self.selection_cbox.Append(str(option))
+ self.selection_cbox.SetValue('Select all Data')
+ wx.EVT_COMBOBOX(self.selection_cbox, -1, self._on_selection_type)
+ self.sizer5.AddMany([(select_txt, 0, wx.ALL, 5),
+ (self.selection_cbox, 0, wx.ALL, 5)])
+ self.enable_selection()
+
+ def _on_selection_type(self, event):
+ """
+ Select data according to patterns
+ :param event: UI event
+ """
+ def check_item_and_children(control, check_value=True):
+ self.tree_ctrl.CheckItem(data_ctrl, check_value)
+ if data_ctrl.HasChildren():
+ if check_value and not control.IsExpanded():
+ # Only select children if control is expanded
+ # Always deselect children, regardless (see ticket #259)
+ return
+ for child_ctrl in data_ctrl.GetChildren():
+ self.tree_ctrl.CheckItem(child_ctrl, check_value)
+
+ option = self.selection_cbox.GetValue()
+
+ pos = self.selection_cbox.GetSelection()
+ if pos == wx.NOT_FOUND:
+ return
+ option = self.selection_cbox.GetString(pos)
+ for item in self.list_cb_data.values():
+ data_ctrl, _, _, _, _, _, _, _ = item
+ _, data_class, _ = self.tree_ctrl.GetItemPyData(data_ctrl)
+ if option == 'Select all Data':
+ check_item_and_children(data_ctrl, check_value=True)
+ elif option == 'Unselect all Data':
+ check_item_and_children(data_ctrl, check_value=False)
+ elif option == 'Select all Data 1D':
+ if data_class == 'Data1D':
+ check_item_and_children(data_ctrl, check_value=True)
+ elif option == 'Unselect all Data 1D':
+ if data_class == 'Data1D':
+ check_item_and_children(data_ctrl, check_value=False)
+ elif option == 'Select all Data 2D':
+ if data_class == 'Data2D':
+ check_item_and_children(data_ctrl, check_value=True)
+ elif option == 'Unselect all Data 2D':
+ if data_class == 'Data2D':
+ check_item_and_children(data_ctrl, check_value=False)
+ self.enable_append()
+ self.enable_freeze()
+ self.enable_plot()
+ self.enable_import()
+ self.enable_remove()
+
+ def layout_button(self):
+ """
+ Layout widgets related to buttons
+ """
+ # Load Data Button
+ self.bt_add = wx.Button(self, wx.NewId(), "Load Data",
+ size=(BUTTON_WIDTH, -1))
+ self.bt_add.SetToolTipString("Load data files")
+ wx.EVT_BUTTON(self, self.bt_add.GetId(), self._load_data)
+
+ # Delete Data Button
+ self.bt_remove = wx.Button(self, wx.NewId(), "Delete Data",
+ size=(BUTTON_WIDTH, -1))
+ self.bt_remove.SetToolTipString("Delete data from the application")
+ wx.EVT_BUTTON(self, self.bt_remove.GetId(), self.on_remove)
+
+ # Send data to perspective button
+ self.bt_import = wx.Button(self, wx.NewId(), "Send To",
+ size=(BUTTON_WIDTH, -1))
+ self.bt_import.SetToolTipString("Send Data set to active perspective")
+ wx.EVT_BUTTON(self, self.bt_import.GetId(), self.on_import)
+
+ # Choose perspective to be send data to combo box
+ self.perspective_cbox = wx.ComboBox(self, -1,
+ style=wx.CB_READONLY)
+ if not IS_MAC:
+ self.perspective_cbox.SetMinSize((BUTTON_WIDTH*1.6, -1))
+ wx.EVT_COMBOBOX(self.perspective_cbox, -1,
+ self._on_perspective_selection)
+
+ # Append data to current Graph Button
+ self.bt_append_plot = wx.Button(self, wx.NewId(), "Append Plot To",
+ size=(BUTTON_WIDTH, -1))
+ self.bt_append_plot.SetToolTipString(
+ "Plot the selected data in the active panel")
+ wx.EVT_BUTTON(self, self.bt_append_plot.GetId(), self.on_append_plot)
+
+ # Create a new graph and send data to that new graph button
+ self.bt_plot = wx.Button(self, wx.NewId(), "New Plot",
+ size=(BUTTON_WIDTH, -1))
+ self.bt_plot.SetToolTipString("To trigger plotting")
+ wx.EVT_BUTTON(self, self.bt_plot.GetId(), self.on_plot)
+
+ # Freeze current theory button - becomes a data set and stays on graph
+ self.bt_freeze = wx.Button(self, wx.NewId(), "Freeze Theory",
+ size=(BUTTON_WIDTH, -1))
+ freeze_tip = "To trigger freeze a theory: making a copy\n"
+ freeze_tip += "of the theory checked to Data box,\n"
+ freeze_tip += " so that it can act like a real data set."
+ self.bt_freeze.SetToolTipString(freeze_tip)
+ wx.EVT_BUTTON(self, self.bt_freeze.GetId(), self.on_freeze)
+
+ # select plot to send to combo box (blank if no data)
+ if sys.platform == 'darwin':
+ self.cb_plotpanel = wx.ComboBox(self, -1,
+ style=wx.CB_READONLY)
+ else:
+ self.cb_plotpanel = wx.ComboBox(self, -1,
+ style=wx.CB_READONLY | wx.CB_SORT)
+ wx.EVT_COMBOBOX(self.cb_plotpanel, -1, self._on_plot_selection)
+ self.cb_plotpanel.Disable()
+
+ # Help button
+ self.bt_help = wx.Button(self, wx.NewId(), "HELP",
+ size=(BUTTON_WIDTH, -1))
+ self.bt_help.SetToolTipString("Help for the Data Explorer.")
+ wx.EVT_BUTTON(self, self.bt_help.GetId(), self.on_help)
+
+ self.sizer3.AddMany([(self.bt_add),
+ ((10, 10)),
+ (self.bt_remove),
+ ((10, 10)),
+ (self.bt_freeze),
+ ((10, 10)),
+ (self.bt_plot),
+ ((10, 10)),
+ (self.bt_append_plot),
+ (self.cb_plotpanel,
+ wx.EXPAND | wx.ADJUST_MINSIZE, 5),
+ ((5, 5)),
+ ((5, 5)),
+ (self.bt_import, 0, wx.EXPAND | wx.RIGHT, 5),
+ (self.perspective_cbox,
+ wx.EXPAND | wx.ADJUST_MINSIZE, 5),
+ ((10, 10)),
+ (self.sizer4),
+ ((10, 10)),
+ (self.bt_help, 0, wx.RIGHT, 5)])
+
+ self.sizer3.AddGrowableCol(1, 1)
+ self.show_data_button()
+ self.enable_remove()
+ self.enable_import()
+ self.enable_plot()
+ self.enable_append()
+ self.enable_freeze()
+ self.enable_remove_plot()
+
+ def layout_batch(self):
+ """
+ Set up batch mode options
+ """
+ self.rb_single_mode = wx.RadioButton(self, -1, 'Single Mode',
+ style=wx.RB_GROUP)
+ self.rb_batch_mode = wx.RadioButton(self, -1, 'Batch Mode')
+ self.Bind(wx.EVT_RADIOBUTTON, self.on_single_mode,
+ id=self.rb_single_mode.GetId())
+ self.Bind(wx.EVT_RADIOBUTTON, self.on_batch_mode,
+ id=self.rb_batch_mode.GetId())
+
+ self.rb_single_mode.SetValue(not self.parent.batch_on)
+ self.rb_batch_mode.SetValue(self.parent.batch_on)
+ self.sizer4.AddMany([(self.rb_single_mode, 0, wx.ALL, 4),
+ (self.rb_batch_mode, 0, wx.ALL, 4)])
+
+ def on_single_mode(self, event):
+ """
+ Change to single mode
+ :param event: UI event
+ """
+ if self.parent is not None:
+ wx.PostEvent(self.parent, NewBatchEvent(enable=False))
+
+ def on_batch_mode(self, event):
+ """
+ Change to batch mode
+ :param event: UI event
+ """
+ if self.parent is not None:
+ wx.PostEvent(self.parent,
+ NewBatchEvent(enable=True))
+
+ def _get_data_selection(self, event):
+ """
+ Get data selection from the right click
+ :param event: UI event
+ """
+ data = None
+ # selection = event.GetSelection()
+ id, _, _ = self.FindFocus().GetSelection().GetData()
+ data_list, theory_list = \
+ self.parent.get_data_manager().get_by_id(id_list=[id])
+ if data_list:
+ data = data_list.values()[0]
+ if data is None:
+ data = theory_list.values()[0][0]
+ return data
+
+ def on_edit_data(self, event):
+ """
+ Pop Up Data Editor
+ """
+ data = self._get_data_selection(event)
+ from sas.sasgui.guiframe.local_perspectives.plotting.masking \
+ import MaskPanel as MaskDialog
+
+ panel = MaskDialog(parent=self.parent, base=self,
+ data=data, id=wx.NewId())
+ panel.ShowModal()
+
+ def on_plot_3d(self, event):
+ """
+ Frozen image of 3D
+ """
+ data = self._get_data_selection(event)
+ from sas.sasgui.guiframe.local_perspectives.plotting.masking \
+ import FloatPanel as Float3dDialog
+
+ panel = Float3dDialog(base=self, data=data,
+ dimension=3, id=wx.NewId())
+ panel.ShowModal()
+
+ def on_quick_plot(self, event):
+ """
+ Frozen plot
+ """
+ data = self._get_data_selection(event)
+ if data.__class__.__name__ == "Data2D":
+ dimension = 2
+ else:
+ dimension = 1
+ # panel = QucikPlotDialog(base=self, data=data,
+ # dimension=dimension, id=wx.NewId())
+ frame = QucikPlotDialog(self, -1, "Plot " + data.name, 'log_{10}')
+ self.parent.put_icon(frame)
+ frame.add_plot(data)
+ # frame.SetTitle(title)
+ frame.Show(True)
+ frame.SetFocus()
+ # panel.ShowModal()
+
+ def on_data_info(self, event):
+ """
+ Data Info panel
+ """
+ data = self._get_data_selection(event)
+ if data.__class__.__name__ == "Data2D":
+ self.parent.show_data2d(data, data.name)
+ else:
+ self.parent.show_data1d(data, data.name)
+
+ def on_save_as(self, event):
+ """
+ Save data as a file
+ """
+ data = self._get_data_selection(event)
+ # path = None
+ default_name = data.name
+ if default_name.count('.') > 0:
+ default_name = default_name.split('.')[0]
+ default_name += "_out"
+ if self.parent is not None:
+ if issubclass(data.__class__, Data1D):
+ self.parent.save_data1d(data, default_name)
+ elif issubclass(data.__class__, Data2D):
+ self.parent.save_data2d(data, default_name)
+ else:
+ print("unable to save this type of data")
+
+ def layout_data_list(self):
+ """
+ Add a listcrtl in the panel
+ """
+ # Add splitter
+ w, h = self.parent.GetSize()
+ splitter = wx.SplitterWindow(self)
+ splitter.SetMinimumPaneSize(50)
+ splitter.SetSashGravity(1.0)
+
+ file_sizer = wx.BoxSizer(wx.VERTICAL)
+ file_sizer.SetMinSize(wx.Size(w/13, h*2/5))
+ theory_sizer = wx.BoxSizer(wx.VERTICAL)
+ theory_sizer.SetMinSize(wx.Size(w/13, h*2/5))
+
+ self.tree_ctrl = DataTreeCtrl(parent=splitter,
+ style=wx.SUNKEN_BORDER,
+ root="Available Data")
+
+ self.tree_ctrl.Bind(CT.EVT_TREE_ITEM_CHECKING, self.on_check_item)
+ self.tree_ctrl.Bind(CT.EVT_TREE_ITEM_MENU, self.on_right_click_data)
+ # Create context menu for page
+ self.data_menu = wx.Menu()
+ id = wx.NewId()
+ name = "Data Info"
+ msg = "Show Data Info"
+ self.data_menu.Append(id, name, msg)
+ wx.EVT_MENU(self, id, self.on_data_info)
+
+ id = wx.NewId()
+ name = "Save As"
+ msg = "Save Theory/Data as a file"
+ self.data_menu.Append(id, name, msg)
+ wx.EVT_MENU(self, id, self.on_save_as)
+
+ quickplot_id = wx.NewId()
+ name = "Quick Plot"
+ msg = "Plot the current Data"
+ self.data_menu.Append(quickplot_id, name, msg)
+ wx.EVT_MENU(self, quickplot_id, self.on_quick_plot)
+
+ self.plot3d_id = wx.NewId()
+ name = "Quick 3DPlot (Slow)"
+ msg = "Plot3D the current 2D Data"
+ self.data_menu.Append(self.plot3d_id, name, msg)
+ wx.EVT_MENU(self, self.plot3d_id, self.on_plot_3d)
+
+ self.editmask_id = wx.NewId()
+ name = "Edit Mask"
+ msg = "Edit Mask for the current 2D Data"
+ self.data_menu.Append(self.editmask_id, name, msg)
+ wx.EVT_MENU(self, self.editmask_id, self.on_edit_data)
+
+ self.tree_ctrl_theory = DataTreeCtrl(parent=splitter,
+ style=wx.SUNKEN_BORDER,
+ root="Available Theory")
+ self.tree_ctrl_theory.Bind(CT.EVT_TREE_ITEM_CHECKING,
+ self.on_check_item)
+ self.tree_ctrl_theory.Bind(CT.EVT_TREE_ITEM_MENU,
+ self.on_right_click_theory)
+ splitter.SplitHorizontally(self.tree_ctrl, self.tree_ctrl_theory)
+ self.sizer1.Add(splitter, 1, wx.EXPAND | wx.ALL, 10)
+
+ def on_right_click_theory(self, event):
+ """
+ On click theory data
+ """
+ try:
+ id, data_class_name, _ = \
+ self.tree_ctrl_theory.GetSelection().GetData()
+ _, _ = self.parent.get_data_manager().get_by_id(id_list=[id])
+ except:
+ return
+ if self.data_menu is not None:
+ menu_enable = (data_class_name == "Data2D")
+ self.data_menu.Enable(self.editmask_id, False)
+ self.data_menu.Enable(self.plot3d_id, menu_enable)
+ self.PopupMenu(self.data_menu)
+
+ def on_right_click_data(self, event):
+ """
+ Allow Editing Data
+ """
+ # selection = event.GetSelection()
+ is_data = True
+ try:
+ id, data_class_name, _ = self.tree_ctrl.GetSelection().GetData()
+ data_list, _ = \
+ self.parent.get_data_manager().get_by_id(id_list=[id])
+ if not data_list:
+ is_data = False
+ except:
+ return
+ if self.data_menu is not None:
+ menu_enable = (data_class_name == "Data2D")
+ maskmenu_enable = (menu_enable and is_data)
+ self.data_menu.Enable(self.editmask_id, maskmenu_enable)
+ self.data_menu.Enable(self.plot3d_id, menu_enable)
+ self.PopupMenu(self.data_menu)
+
+ def onContextMenu(self, event):
+ """
+ Retrieve the state selected state
+ """
+ # Skipping the save state functionality for release 0.9.0
+ # return
+ pos = event.GetPosition()
+ pos = self.ScreenToClient(pos)
+ self.PopupMenu(self.popUpMenu, pos)
+
+ def on_check_item(self, event):
+ """
+ On check item
+ """
+ item = event.GetItem()
+ item.Check(not item.IsChecked())
+ self.enable_append()
+ self.enable_freeze()
+ self.enable_plot()
+ self.enable_import()
+ self.enable_remove()
+ event.Skip()
+
+ def fill_cbox_analysis(self, plugin):
+ """
+ fill the combobox with analysis name
+ """
+ self.list_of_perspective = plugin
+ if self.parent is None or \
+ not hasattr(self.parent, "get_current_perspective") or \
+ len(self.list_of_perspective) == 0:
+ return
+ if self.parent is not None and self.perspective_cbox is not None:
+ for plug in self.list_of_perspective:
+ if plug.get_perspective():
+ self.perspective_cbox.Append(plug.sub_menu, plug)
+
+ curr_pers = self.parent.get_current_perspective()
+ if curr_pers:
+ self.perspective_cbox.SetStringSelection(curr_pers.sub_menu)
+ self.enable_import()
+
+ def load_data_list(self, list):
+ """
+ add need data with its theory under the tree
+ """
+ if list:
+ for state_id, dstate in list.iteritems():
+ data = dstate.get_data()
+ theory_list = dstate.get_theory()
+ if data is not None:
+ data_name = str(data.name)
+ data_title = str(data.title)
+ data_run = str(data.run)
+ data_class = data.__class__.__name__
+ path = dstate.get_path()
+ process_list = data.process
+ data_id = data.id
+ s_path = str(path)
+ if state_id not in self.list_cb_data:
+ # new state
+ data_c = self.tree_ctrl.InsertItem(self.tree_ctrl.root,
+ 0, data_name,
+ ct_type=1,
+ data=(data_id, data_class, state_id))
+ data_c.Check(True)
+ d_i_c = self.tree_ctrl.AppendItem(data_c, 'Info')
+ d_t_c = self.tree_ctrl.AppendItem(d_i_c,
+ 'Title: %s' %
+ data_title)
+ r_n_c = self.tree_ctrl.AppendItem(d_i_c,
+ 'Run: %s' % data_run)
+ i_c_c = self.tree_ctrl.AppendItem(d_i_c,
+ 'Type: %s' %
+ data_class)
+ p_c_c = self.tree_ctrl.AppendItem(d_i_c,
+ "Path: '%s'" % s_path)
+ d_p_c = self.tree_ctrl.AppendItem(d_i_c, 'Process')
+
+ for process in process_list:
+ process_str = str(process).replace('\n', ' ')
+ if len(process_str) > 20:
+ process_str = process_str[:20] + ' [...]'
+ self.tree_ctrl.AppendItem(d_p_c, process_str)
+ theory_child = self.tree_ctrl.AppendItem(data_c,
+ "THEORIES")
+ self.list_cb_data[state_id] = [data_c,
+ d_i_c,
+ d_t_c,
+ r_n_c,
+ i_c_c,
+ p_c_c,
+ d_p_c,
+ theory_child]
+ else:
+ data_ctrl_list = self.list_cb_data[state_id]
+ # This state is already display replace it contains
+ data_c, d_i_c, d_t_c, r_n_c, i_c_c, p_c_c, d_p_c, _ \
+ = data_ctrl_list
+ self.tree_ctrl.SetItemText(data_c, data_name)
+ temp = (data_id, data_class, state_id)
+ self.tree_ctrl.SetItemPyData(data_c, temp)
+ self.tree_ctrl.SetItemText(i_c_c,
+ 'Type: %s' % data_class)
+ self.tree_ctrl.SetItemText(p_c_c,
+ 'Path: %s' % s_path)
+ self.tree_ctrl.DeleteChildren(d_p_c)
+ for process in process_list:
+ if not process.is_empty():
+ _ = self.tree_ctrl.AppendItem(d_p_c,
+ process.single_line_desc())
+ wx.CallAfter(self.append_theory, state_id, theory_list)
+ # Sort by data name
+ if self.tree_ctrl.root:
+ self.tree_ctrl.SortChildren(self.tree_ctrl.root)
+ # Expand root if # of data sets > 0
+ if self.tree_ctrl.GetCount() > 0:
+ self.tree_ctrl.root.Expand()
+ self.enable_remove()
+ self.enable_import()
+ self.enable_plot()
+ self.enable_freeze()
+ self.enable_selection()
+
+ def _uncheck_all(self):
+ """
+ Uncheck all check boxes
+ """
+ for item in self.list_cb_data.values():
+ data_ctrl, _, _, _, _, _, _, _ = item
+ self.tree_ctrl.CheckItem(data_ctrl, False)
+ self.enable_append()
+ self.enable_freeze()
+ self.enable_plot()
+ self.enable_import()
+ self.enable_remove()
+
+ def append_theory(self, state_id, theory_list):
+ """
+ append theory object under data from a state of id = state_id
+ replace that theory if already displayed
+ """
+ if not theory_list:
+ return
+ if state_id not in self.list_cb_data.keys():
+ root = self.tree_ctrl_theory.root
+ tree = self.tree_ctrl_theory
+ else:
+ item = self.list_cb_data[state_id]
+ data_c, _, _, _, _, _, _, _ = item
+ root = data_c
+ tree = self.tree_ctrl
+ if root is not None:
+ wx.CallAfter(self.append_theory_helper, tree=tree, root=root,
+ state_id=state_id,
+ theory_list=theory_list)
+ if self.tree_ctrl_theory.GetCount() > 0:
+ self.tree_ctrl_theory.root.Expand()
+
+ def append_theory_helper(self, tree, root, state_id, theory_list):
+ """
+ Append theory helper
+ """
+ if state_id in self.list_cb_theory.keys():
+ # update current list of theory for this data
+ theory_list_ctrl = self.list_cb_theory[state_id]
+
+ for theory_id, item in theory_list.iteritems():
+ theory_data, _ = item
+ if theory_data is None:
+ name = "Unknown"
+ theory_class = "Unknown"
+ theory_id = "Unknown"
+ temp = (None, None, None)
+ else:
+ name = theory_data.name
+ theory_class = theory_data.__class__.__name__
+ theory_id = theory_data.id
+ # if theory_state is not None:
+ # name = theory_state.model.name
+ temp = (theory_id, theory_class, state_id)
+ if theory_id not in theory_list_ctrl:
+ # add new theory
+ t_child = tree.AppendItem(root,
+ name, ct_type=1, data=temp)
+ t_i_c = tree.AppendItem(t_child, 'Info')
+ i_c_c = tree.AppendItem(t_i_c,
+ 'Type: %s' % theory_class)
+ t_p_c = tree.AppendItem(t_i_c, 'Process')
+
+ for process in theory_data.process:
+ tree.AppendItem(t_p_c, process.__str__())
+ theory_list_ctrl[theory_id] = [t_child,
+ i_c_c,
+ t_p_c]
+ else:
+ # replace theory
+ t_child, i_c_c, t_p_c = theory_list_ctrl[theory_id]
+ tree.SetItemText(t_child, name)
+ tree.SetItemPyData(t_child, temp)
+ tree.SetItemText(i_c_c, 'Type: %s' % theory_class)
+ tree.DeleteChildren(t_p_c)
+ for process in theory_data.process:
+ tree.AppendItem(t_p_c, process.__str__())
+
+ else:
+ # data didn't have a theory associated it before
+ theory_list_ctrl = {}
+ for theory_id, item in theory_list.iteritems():
+ theory_data, _ = item
+ if theory_data is not None:
+ name = theory_data.name
+ theory_class = theory_data.__class__.__name__
+ theory_id = theory_data.id
+ # if theory_state is not None:
+ # name = theory_state.model.name
+ temp = (theory_id, theory_class, state_id)
+ t_child = tree.AppendItem(root,
+ name, ct_type=1,
+ data=(theory_data.id, theory_class, state_id))
+ t_i_c = tree.AppendItem(t_child, 'Info')
+ i_c_c = tree.AppendItem(t_i_c,
+ 'Type: %s' % theory_class)
+ t_p_c = tree.AppendItem(t_i_c, 'Process')
+
+ for process in theory_data.process:
+ tree.AppendItem(t_p_c, process.__str__())
+
+ theory_list_ctrl[theory_id] = [t_child, i_c_c, t_p_c]
+ # self.list_cb_theory[data_id] = theory_list_ctrl
+ self.list_cb_theory[state_id] = theory_list_ctrl
+
+ def set_data_helper(self):
+ """
+ Set data helper
+ """
+ data_to_plot = []
+ state_to_plot = []
+ theory_to_plot = []
+ for value in self.list_cb_data.values():
+ item, _, _, _, _, _, _, _ = value
+ if item.IsChecked():
+ data_id, _, state_id = self.tree_ctrl.GetItemPyData(item)
+ data_to_plot.append(data_id)
+ if state_id not in state_to_plot:
+ state_to_plot.append(state_id)
+
+ for theory_dict in self.list_cb_theory.values():
+ for _, value in theory_dict.iteritems():
+ item, _, _ = value
+ if item.IsChecked():
+ theory_id, _, state_id = self.tree_ctrl.GetItemPyData(item)
+ theory_to_plot.append(theory_id)
+ if state_id not in state_to_plot:
+ state_to_plot.append(state_id)
+ return data_to_plot, theory_to_plot, state_to_plot
+
+ def remove_by_id(self, id):
+ """
+ Remove_dat by id
+ """
+ for item in self.list_cb_data.values():
+ data_c, _, _, _, _, _, _, _ = item
+ data_id, _, state_id = self.tree_ctrl.GetItemPyData(data_c)
+ if id == data_id:
+ self.tree_ctrl.Delete(data_c)
+ del self.list_cb_data[state_id]
+ del self.list_cb_theory[data_id]
+
+ def load_error(self, error=None):
+ """
+ Pop up an error message.
+
+ :param error: details error message to be displayed
+ """
+ if error is not None or str(error).strip() != "":
+ dial = wx.MessageDialog(self.parent, str(error),
+ 'Error Loading File',
+ wx.OK | wx.ICON_EXCLAMATION)
+ dial.ShowModal()
+
+ def _load_data(self, event):
+ """
+ send an event to the parent to trigger load from plugin module
+ """
+ if self.parent is not None:
+ wx.PostEvent(self.parent, NewLoadDataEvent())
+
+ def on_remove(self, event, prompt=True):
+ """
+ Get a list of item checked and remove them from the treectrl
+ Ask the parent to remove reference to this item
+ """
+ if prompt:
+ msg = "This operation will delete the data sets checked "
+ msg += "and all the dependents."
+ msg_box = wx.MessageDialog(None, msg, 'Warning', wx.OK|wx.CANCEL)
+ if msg_box.ShowModal() != wx.ID_OK:
+ return
+
+ data_to_remove, theory_to_remove, _ = self.set_data_helper()
+ data_key = []
+ theory_key = []
+ # remove data from treectrl
+ for d_key, item in self.list_cb_data.iteritems():
+ data_c, _, _, _, _, _, _, _ = item
+ if data_c.IsChecked():
+ self.tree_ctrl.Delete(data_c)
+ data_key.append(d_key)
+ if d_key in self.list_cb_theory.keys():
+ theory_list_ctrl = self.list_cb_theory[d_key]
+ theory_to_remove += theory_list_ctrl.keys()
+ # Remove theory from treectrl
+ for _, theory_dict in self.list_cb_theory.iteritems():
+ for key, value in theory_dict.iteritems():
+ item, _, _ = value
+ if item.IsChecked():
+ try:
+ self.tree_ctrl.Delete(item)
+ except:
+ pass
+ theory_key.append(key)
+
+ # Remove data and related theory references
+ for key in data_key:
+ del self.list_cb_data[key]
+ if key in theory_key:
+ del self.list_cb_theory[key]
+ # remove theory references independently of data
+ for key in theory_key:
+ for _, theory_dict in self.list_cb_theory.iteritems():
+ if key in theory_dict:
+ for key, value in theory_dict.iteritems():
+ item, _, _ = value
+ if item.IsChecked():
+ try:
+ self.tree_ctrl_theory.Delete(item)
+ except:
+ pass
+ del theory_dict[key]
+
+ self.parent.remove_data(data_id=data_to_remove,
+ theory_id=theory_to_remove)
+ self.enable_remove()
+ self.enable_freeze()
+ self.enable_remove_plot()
+
+ def on_import(self, event=None):
+ """
+ Get all select data and set them to the current active perspetive
+ """
+ if event is not None:
+ event.Skip()
+ data_id, theory_id, state_id = self.set_data_helper()
+ temp = data_id + state_id
+ self.parent.set_data(data_id=temp, theory_id=theory_id)
+
+ def on_append_plot(self, event=None):
+ """
+ append plot to plot panel on focus
+ """
+ self._on_plot_selection()
+ data_id, theory_id, state_id = self.set_data_helper()
+ self.parent.plot_data(data_id=data_id,
+ state_id=state_id,
+ theory_id=theory_id,
+ append=True)
+
+ def on_plot(self, event=None):
+ """
+ Send a list of data names to plot
+ """
+ data_id, theory_id, state_id = self.set_data_helper()
+ self.parent.plot_data(data_id=data_id,
+ state_id=state_id,
+ theory_id=theory_id,
+ append=False)
+ self.enable_remove_plot()
+
+ def on_close_page(self, event=None):
+ """
+ On close
+ """
+ if event is not None:
+ event.Skip()
+ # send parent to update menu with no show nor hide action
+ self.parent.show_data_panel(action=False)
+
+ def on_freeze(self, event):
+ """
+ On freeze to make a theory to a data set
+ """
+ _, theory_id, state_id = self.set_data_helper()
+ if len(theory_id) > 0:
+ self.parent.freeze(data_id=state_id, theory_id=theory_id)
+ msg = "Freeze Theory:"
+ msg += " The theory(s) copied to the Data box as a data set."
+ else:
+ msg = "Freeze Theory: Requires at least one theory checked."
+ wx.PostEvent(self.parent, StatusEvent(status=msg))
+
+ def set_active_perspective(self, name):
+ """
+ set the active perspective
+ """
+ self.perspective_cbox.SetStringSelection(name)
+ self.enable_import()
+
+ def _on_delete_plot_panel(self, event):
+ """
+ get an event with attribute name and caption to delete existing name
+ from the combobox of the current panel
+ """
+ # name = event.name
+ caption = event.caption
+ if self.cb_plotpanel is not None:
+ pos = self.cb_plotpanel.FindString(str(caption))
+ if pos != wx.NOT_FOUND:
+ self.cb_plotpanel.Delete(pos)
+ self.enable_append()
+
+ def set_panel_on_focus(self, name=None):
+ """
+ set the plot panel on focus
+ """
+ if self.cb_plotpanel and self.cb_plotpanel.IsBeingDeleted():
+ return
+ for _, value in self.parent.plot_panels.iteritems():
+ name_plot_panel = str(value.window_caption)
+ if name_plot_panel not in self.cb_plotpanel.GetItems():
+ self.cb_plotpanel.Append(name_plot_panel, value)
+ if name is not None and name == name_plot_panel:
+ self.cb_plotpanel.SetStringSelection(name_plot_panel)
+ break
+ self.enable_append()
+ self.enable_remove_plot()
+
+ def set_plot_unfocus(self):
+ """
+ Unfocus plot
+ """
+ return
+
+ def _on_perspective_selection(self, event=None):
+ """
+ select the current perspective for guiframe
+ """
+ selection = self.perspective_cbox.GetSelection()
+ if self.perspective_cbox.GetValue() != 'None':
+ perspective = self.perspective_cbox.GetClientData(selection)
+ perspective.on_perspective(event=None)
+ self.parent.check_multimode(perspective=perspective)
+
+ def _on_plot_selection(self, event=None):
+ """
+ On source combobox selection
+ """
+ if event is not None:
+ combo = event.GetEventObject()
+ event.Skip()
+ else:
+ combo = self.cb_plotpanel
+ selection = combo.GetSelection()
+
+ if combo.GetValue() != 'None':
+ panel = combo.GetClientData(selection)
+ self.parent.on_set_plot_focus(panel)
+
+ def on_close_plot(self, event):
+ """
+ clseo the panel on focus
+ """
+ self.enable_append()
+ selection = self.cb_plotpanel.GetSelection()
+ if self.cb_plotpanel.GetValue() != 'None':
+ panel = self.cb_plotpanel.GetClientData(selection)
+ if self.parent is not None and panel is not None:
+ wx.PostEvent(self.parent,
+ NewPlotEvent(group_id=panel.group_id,
+ action="delete"))
+ self.enable_remove_plot()
+
+ def set_frame(self, frame):
+ """
+ """
+ self.frame = frame
+
+ def get_frame(self):
+ """
+ """
+ return self.frame
+
+ def on_help(self, event):
+ """
+ Bring up the data manager Documentation whenever
+ the HELP button is clicked.
+
+ Calls DocumentationWindow with the path of the location within the
+ documentation tree (after /doc/ ....". Note that when using old
+ versions of Wx (before 2.9) and thus not the release version of
+ installers, the help comes up at the top level of the file as
+ webbrowser does not pass anything past the # to the browser when it is
+ running "file:///...."
+
+ :param event: Triggers on clicking the help button
+ """
+
+ #import documentation window here to avoid circular imports
+ #if put at top of file with rest of imports.
+ from documentation_window import DocumentationWindow
+
+ _TreeLocation = "user/sasgui/guiframe/data_explorer_help.html"
+ _doc_viewer = DocumentationWindow(self, -1, _TreeLocation, "",
+ "Data Explorer Help")
+
+ def on_close(self, event):
+ """
+ On close event
+ """
+ self.parent.show_data_panel(event)
+
+ def set_schedule_full_draw(self, panel=None, func='del'):
+ """
+ Send full draw to guimanager
+ """
+ self.parent.set_schedule_full_draw(panel, func)
+
+ def enable_remove_plot(self):
+ """
+ enable remove plot button if there is a plot panel on focus
+ """
+ pass
+ #if self.cb_plotpanel.GetCount() == 0:
+ # self.bt_close_plot.Disable()
+ #else:
+ # self.bt_close_plot.Enable()
+
+ def enable_remove(self):
+ """
+ enable or disable remove button
+ """
+ n_t = self.tree_ctrl.GetCount()
+ n_t_t = self.tree_ctrl_theory.GetCount()
+ if n_t + n_t_t <= 0:
+ self.bt_remove.Disable()
+ else:
+ self.bt_remove.Enable()
+
+ def enable_import(self):
+ """
+ enable or disable send button
+ """
+ n_t = 0
+ if self.tree_ctrl is not None:
+ n_t = self.tree_ctrl.GetCount()
+ if n_t > 0 and len(self.list_of_perspective) > 0:
+ self.bt_import.Enable()
+ else:
+ self.bt_import.Disable()
+ if len(self.list_of_perspective) <= 0 or \
+ self.perspective_cbox.GetValue() in ["None",
+ "No Active Application"]:
+ self.perspective_cbox.Disable()
+ else:
+ self.perspective_cbox.Enable()
+
+ def enable_plot(self):
+ """
+ enable or disable plot button
+ """
+ n_t = 0
+ n_t_t = 0
+ if self.tree_ctrl is not None:
+ n_t = self.tree_ctrl.GetCount()
+ if self.tree_ctrl_theory is not None:
+ n_t_t = self.tree_ctrl_theory.GetCount()
+ if n_t + n_t_t <= 0:
+ self.bt_plot.Disable()
+ else:
+ self.bt_plot.Enable()
+ self.enable_append()
+
+ def enable_append(self):
+ """
+ enable or disable append button
+ """
+ n_t = 0
+ n_t_t = 0
+ if self.tree_ctrl is not None:
+ n_t = self.tree_ctrl.GetCount()
+ if self.tree_ctrl_theory is not None:
+ n_t_t = self.tree_ctrl_theory.GetCount()
+ if n_t + n_t_t <= 0:
+ self.bt_append_plot.Disable()
+ self.cb_plotpanel.Disable()
+ elif self.cb_plotpanel.GetCount() <= 0:
+ self.cb_plotpanel.Disable()
+ self.bt_append_plot.Disable()
+ else:
+ self.bt_append_plot.Enable()
+ self.cb_plotpanel.Enable()
+
+ def check_theory_to_freeze(self):
+ """
+ Check_theory_to_freeze
+ """
+ def enable_freeze(self):
+ """
+ enable or disable the freeze button
+ """
+ n_t_t = 0
+ n_l = 0
+ if self.tree_ctrl_theory is not None:
+ n_t_t = self.tree_ctrl_theory.GetCount()
+ n_l = len(self.list_cb_theory)
+ if (n_t_t + n_l > 0):
+ self.bt_freeze.Enable()
+ else:
+ self.bt_freeze.Disable()
+
+ def enable_selection(self):
+ """
+ enable or disable combobo box selection
+ """
+ n_t = 0
+ n_t_t = 0
+ if self.tree_ctrl is not None:
+ n_t = self.tree_ctrl.GetCount()
+ if self.tree_ctrl_theory is not None:
+ n_t_t = self.tree_ctrl_theory.GetCount()
+ if n_t + n_t_t > 0 and self.selection_cbox is not None:
+ self.selection_cbox.Enable()
+ else:
+ self.selection_cbox.Disable()
+
+ def show_data_button(self):
+ """
+ show load data and remove data button if
+ dataloader on else hide them
+ """
+ try:
+ gui_style = self.parent.get_style()
+ style = gui_style & GUIFRAME.DATALOADER_ON
+ if style == GUIFRAME.DATALOADER_ON:
+ #self.bt_remove.Show(True)
+ self.bt_add.Show(True)
+ else:
+ #self.bt_remove.Hide()
+ self.bt_add.Hide()
+ except:
+ #self.bt_remove.Hide()
+ self.bt_add.Hide()
+
+
+WIDTH = 400
+HEIGHT = 300
+
+
+class DataDialog(wx.Dialog):
+ """
+ Allow file selection at loading time
+ """
+ def __init__(self, data_list, parent=None, text='', *args, **kwds):
+ wx.Dialog.__init__(self, parent, *args, **kwds)
+ self.SetTitle("Data Selection")
+ self.SetSize((WIDTH, HEIGHT))
+ self.list_of_ctrl = []
+ if not data_list:
+ return
+ self._sizer_main = wx.BoxSizer(wx.VERTICAL)
+ self._sizer_txt = wx.BoxSizer(wx.VERTICAL)
+ self._sizer_button = wx.BoxSizer(wx.HORIZONTAL)
+ self.sizer = wx.GridBagSizer(5, 5)
+ self._panel = ScrolledPanel(self, style=wx.RAISED_BORDER,
+ size=(WIDTH-20, HEIGHT-50))
+ self._panel.SetupScrolling()
+ self.__do_layout(data_list, text=text)
+
+ def __do_layout(self, data_list, text=''):
+ """
+ layout the dialog
+ """
+ if not data_list or len(data_list) <= 1:
+ return
+ # add text
+
+ text = "Deleting these file reset some panels.\n"
+ text += "Do you want to proceed?\n"
+ text_ctrl = wx.StaticText(self, -1, str(text))
+ self._sizer_txt.Add(text_ctrl)
+ iy = 0
+ ix = 0
+ # data_count = 0
+ for (data_name, in_use, sub_menu) in range(len(data_list)):
+ if in_use:
+ ctrl_name = wx.StaticBox(self, -1, str(data_name))
+ ctrl_in_use = wx.StaticBox(self, -1, " is used by ")
+ plug_name = str(sub_menu) + "\n"
+ # ctrl_sub_menu = wx.StaticBox(self, -1, plug_name)
+ self.sizer.Add(ctrl_name, (iy, ix),
+ (1, 1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
+ ix += 1
+ self._sizer_button.Add(ctrl_in_use, 1,
+ wx.EXPAND|wx.ADJUST_MINSIZE, 0)
+ ix += 1
+ self._sizer_button.Add(plug_name, 1,
+ wx.EXPAND|wx.ADJUST_MINSIZE, 0)
+ iy += 1
+ self._panel.SetSizer(self.sizer)
+ # add sizer
+ self._sizer_button.Add((20, 20), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0)
+ button_cancel = wx.Button(self, wx.ID_CANCEL, "Cancel")
+ self._sizer_button.Add(button_cancel, 0,
+ wx.LEFT|wx.RIGHT|wx.ADJUST_MINSIZE, 10)
+ button_OK = wx.Button(self, wx.ID_OK, "Ok")
+ button_OK.SetFocus()
+ self._sizer_button.Add(button_OK, 0,
+ wx.LEFT|wx.RIGHT|wx.ADJUST_MINSIZE, 10)
+ static_line = wx.StaticLine(self, -1)
+
+ self._sizer_txt.Add(self._panel, 1, wx.EXPAND|wx.LEFT|wx.RIGHT, 5)
+ self._sizer_main.Add(self._sizer_txt, 1, wx.EXPAND|wx.ALL, 10)
+ #self._sizer_main.Add(self._data_text_ctrl, 0,
+ # wx.EXPAND|wx.LEFT|wx.RIGHT, 10)
+ self._sizer_main.Add(static_line, 0, wx.EXPAND, 0)
+ self._sizer_main.Add(self._sizer_button, 0, wx.EXPAND|wx.ALL, 10)
+ self.SetSizer(self._sizer_main)
+ self.Layout()
+
+ def get_data(self):
+ """
+ return the selected data
+ """
+ temp = []
+ for item in self.list_of_ctrl:
+ cb, data = item
+ if cb.GetValue():
+ temp.append(data)
+ return temp
+
+class DataFrame(wx.Frame):
+ """
+ Data Frame
+ """
+ ## Internal name for the AUI manager
+ window_name = "Data Panel"
+ ## Title to appear on top of the window
+ window_caption = "Data Panel"
+ ## Flag to tell the GUI manager that this panel is not
+ # tied to any perspective
+ ALWAYS_ON = True
+
+ def __init__(self, parent=None, owner=None, manager=None, size=(300, 800),
+ list_of_perspective=[], list=[], *args, **kwds):
+ kwds['size'] = size
+ kwds['id'] = -1
+ kwds['title'] = "Loaded Data"
+ wx.Frame.__init__(self, parent=parent, *args, **kwds)
+ self.parent = parent
+ self.owner = owner
+ self._manager = manager
+ self.panel = DataPanel(parent=self,
+ manager=manager,
+ list_of_perspective=list_of_perspective)
+
+ def load_data_list(self, list=[]):
+ """
+ Fill the list inside its panel
+ """
+ self.panel.load_data_list(list=list)
+
+
+from sas.sasgui.guiframe.dataFitting import Theory1D
+from sas.sasgui.guiframe.data_state import DataState
+
+
+class State():
+ """
+ DataPanel State
+ """
+ def __init__(self):
+ self.msg = ""
+ def __str__(self):
+ self.msg = "model mane : model1\n"
+ self.msg += "params : \n"
+ self.msg += "name value\n"
+ return self.msg
+
+
+def set_data_state(data=None, path=None, theory=None, state=None):
+ """
+ Set data state
+ """
+ dstate = DataState(data=data)
+ dstate.set_path(path=path)
+ dstate.set_theory(theory, state)
+
+ return dstate
+
+if __name__ == "__main__":
+
+ app = wx.App()
+ try:
+ # list_of_perspective = [('perspective2', False), ('perspective1', True)]
+ data_list1 = {}
+ # state 1
+ data1 = Data2D()
+ data1.name = "data2"
+ data1.id = 1
+ data1.append_empty_process()
+ process1 = data1.process[len(data1.process)-1]
+ process1.data = "07/01/2010"
+ theory1 = Data2D()
+ theory1.id = 34
+ theory1.name = "theory1"
+ path1 = "path1"
+ state1 = State()
+ data_list1['1'] = set_data_state(data1, path1, theory1, state1)
+ # state 2
+ data1 = Data2D()
+ data1.name = "data2"
+ data1.id = 76
+ theory1 = Data2D()
+ theory1.id = 78
+ theory1.name = "CoreShell 07/24/25"
+ path1 = "path2"
+ # state3
+ state1 = State()
+ data_list1['2'] = set_data_state(data1, path1, theory1, state1)
+ data1 = Data1D()
+ data1.id = 3
+ data1.name = "data2"
+ theory1 = Theory1D()
+ theory1.name = "CoreShell"
+ theory1.id = 4
+ theory1.append_empty_process()
+ process1 = theory1.process[len(theory1.process)-1]
+ process1.description = "this is my description"
+ path1 = "path3"
+ data1.append_empty_process()
+ process1 = data1.process[len(data1.process)-1]
+ process1.data = "07/22/2010"
+ data_list1['4'] = set_data_state(data1, path1, theory1, state1)
+ # state 4
+ temp_data_list = {}
+ data1.name = "data5 erasing data2"
+ temp_data_list['4'] = set_data_state(data1, path1, theory1, state1)
+ # state 5
+ data1 = Data2D()
+ data1.name = "data3"
+ data1.id = 5
+ data1.append_empty_process()
+ process1 = data1.process[len(data1.process)-1]
+ process1.data = "07/01/2010"
+ theory1 = Theory1D()
+ theory1.name = "Cylinder"
+ path1 = "path2"
+ state1 = State()
+ dstate1 = set_data_state(data1, path1, theory1, state1)
+ theory1 = Theory1D()
+ theory1.id = 6
+ theory1.name = "CoreShell"
+ dstate1.set_theory(theory1)
+ theory1 = Theory1D()
+ theory1.id = 6
+ theory1.name = "CoreShell replacing coreshell in data3"
+ dstate1.set_theory(theory1)
+ data_list1['3'] = dstate1
+ #state 6
+ data_list1['6'] = set_data_state(None, path1, theory1, state1)
+ data_list1['6'] = set_data_state(theory=theory1, state=None)
+ theory1 = Theory1D()
+ theory1.id = 7
+ data_list1['6'] = set_data_state(theory=theory1, state=None)
+ data_list1['7'] = set_data_state(theory=theory1, state=None)
+ window = DataFrame(list=data_list1)
+ window.load_data_list(list=data_list1)
+ window.Show(True)
+ window.load_data_list(list=temp_data_list)
+ except:
+ # raise
+ print("error", sys.exc_value)
+
+ app.MainLoop()
diff --git a/src/sas/sasgui/guiframe/data_processor.py b/src/sas/sasgui/guiframe/data_processor.py
index a6f540a..d038487 100644
--- a/src/sas/sasgui/guiframe/data_processor.py
+++ b/src/sas/sasgui/guiframe/data_processor.py
@@ -17,17 +17,21 @@ The organization of the classes goes as:
:align: center
"""
-import wx
-import numpy
-import math
-import re
+from __future__ import print_function
+
import os
import sys
import copy
-from wx.lib.scrolledpanel import ScrolledPanel
+import math
+import re
+import wx
+import numpy as np
+
import wx.aui
from wx.aui import AuiNotebook as nb
import wx.lib.sheet as sheet
+from wx.lib.scrolledpanel import ScrolledPanel
+
from sas.sasgui.guiframe.panel_base import PanelBase
from sas.sasgui.guiframe.events import NewPlotEvent
from sas.sasgui.guiframe.events import StatusEvent
@@ -312,7 +316,7 @@ class GridPage(sheet.CSheet):
row, _ = event.GetRow(), event.GetCol()
if row > self.max_row_touse:
self.max_row_touse = row
- if self.data == None:
+ if self.data is None:
self.data = {}
event.Skip()
@@ -811,9 +815,9 @@ class GridPage(sheet.CSheet):
paste options
"""
- if self.data == None:
+ if self.data is None:
self.data = {}
- if self.file_name == None:
+ if self.file_name is None:
self.file_name = 'copied_data'
self.Paste()
@@ -1014,7 +1018,7 @@ class Notebook(nb, PanelBase):
temp_list.insert(index, (None, None))
if index - 1 >= 0:
new_row, _ = temp_list[index - 1]
- if not new_row == None and new_row != ' ':
+ if new_row is not None and new_row != ' ':
label += create_label(col_name, None,
int(new_row) + 1)
else:
@@ -1022,10 +1026,10 @@ class Notebook(nb, PanelBase):
label += ","
if index + 1 < len(temp_list):
new_row, _ = temp_list[index + 1]
- if not new_row == None:
+ if new_row is not None:
label += create_label(col_name,
int(new_row) + 1, None)
- if row_min != None and row_max != None:
+ if row_min is not None and row_max is not None:
if index == 0:
label += create_label(col_name,
int(row_min) + 1, None)
@@ -1082,7 +1086,7 @@ class Notebook(nb, PanelBase):
"""
# Let's re-order the data from the keys in 'Data' name.
- if outputs == None:
+ if outputs is None:
return
try:
# For outputs from batch
@@ -1090,7 +1094,7 @@ class Notebook(nb, PanelBase):
except:
# When inputs are from an external file
return inputs, outputs
- inds = numpy.lexsort((to_be_sort, to_be_sort))
+ inds = np.lexsort((to_be_sort, to_be_sort))
for key in outputs.keys():
key_list = outputs[key]
temp_key = [item for item in key_list]
@@ -1371,14 +1375,14 @@ class GridPanel(SPanel):
msg += "Got X length = %s, Y length = %s" % (str(len(x)), str(len(y)))
wx.PostEvent(self.parent.parent, StatusEvent(status=msg, info="error"))
return
- if dy != None and (len(y) != len(dy)):
+ if dy is not None and (len(y) != len(dy)):
msg = "Need same length for Y and dY axis and both greater than 0"
msg += " to plot.\n"
msg += "Got Y length = %s, dY length = %s" % (str(len(y)), str(len(dy)))
wx.PostEvent(self.parent.parent, StatusEvent(status=msg, info="error"))
return
- if dy == None:
- dy = numpy.zeros(len(y))
+ if dy is None:
+ dy = np.zeros(len(y))
#plotting
new_plot = Data1D(x=x, y=y, dy=dy)
new_plot.id = wx.NewId()
@@ -1438,7 +1442,7 @@ class GridPanel(SPanel):
for tok, (col_name, list) in dict.iteritems():
col = column_names[col_name]
axis = self.get_plot_axis(col, list)
- if axis == None:
+ if axis is None:
return None
sentence = sentence.replace(tok, "numpy.array(%s)" % str(axis))
for key, value in FUNC_DICT.iteritems():
@@ -1569,9 +1573,9 @@ class GridPanel(SPanel):
get controls to modify
"""
- if label != None:
+ if label is not None:
tcrtl_label.SetValue(str(label))
- if title != None:
+ if title is not None:
tcrtl_title.SetValue(str(title))
def add_column(self):
@@ -1682,7 +1686,7 @@ class GridFrame(wx.Frame):
"""
# I Believe this is no longer used now that we have removed the
# edit menu from the menubar - PDB July 12, 2015
- if event != None:
+ if event is not None:
event.Skip()
pos = self.panel.notebook.GetSelection()
grid = self.panel.notebook.GetPage(pos)
@@ -1694,7 +1698,7 @@ class GridFrame(wx.Frame):
"""
# I Believe this is no longer used now that we have removed the
# edit menu from the menubar - PDB July 12, 2015
- if event != None:
+ if event is not None:
event.Skip()
pos = self.panel.notebook.GetSelection()
grid = self.panel.notebook.GetPage(pos)
@@ -1736,7 +1740,7 @@ class GridFrame(wx.Frame):
if self.file == event.GetMenu():
pos = self.panel.notebook.GetSelection()
grid = self.panel.notebook.GetPage(pos)
- has_data = (grid.data != None and grid.data != {})
+ has_data = (grid.data is not None and grid.data != {})
self.open_excel_menu.Enable(has_data)
self.save_menu.Enable(has_data)
@@ -1819,7 +1823,7 @@ class GridFrame(wx.Frame):
if dlg.ShowModal() == wx.ID_OK:
path = dlg.GetPath()
dlg.Destroy()
- if path != None:
+ if path is not None:
if self.parent is not None:
data = grid.get_grid_view()
self.parent.write_batch_tofile(data=data,
@@ -2004,7 +2008,7 @@ class BatchOutputFrame(wx.Frame):
if dlg.ShowModal() == wx.ID_OK:
path = dlg.GetPath()
dlg.Destroy()
- if path != None:
+ if path is not None:
if self.parent is not None and self.data is not None:
self.parent.write_batch_tofile(data=self.data,
file_name=path,
@@ -2032,6 +2036,6 @@ if __name__ == "__main__":
frame = GridFrame(data_outputs=data, data_inputs=data_input)
frame.Show(True)
except:
- print sys.exc_value
+ print(sys.exc_value)
app.MainLoop()
diff --git a/src/sas/sasgui/guiframe/data_state.py b/src/sas/sasgui/guiframe/data_state.py
index 6c3d985..7e75d46 100644
--- a/src/sas/sasgui/guiframe/data_state.py
+++ b/src/sas/sasgui/guiframe/data_state.py
@@ -1,108 +1,108 @@
-################################################################################
-#This software was developed by the University of Tennessee as part of the
-#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
-#project funded by the US National Science Foundation.
-#
-#See the license text in license.txt
-#
-#copyright 2010, University of Tennessee
-################################################################################
-"""
-"""
-import copy
-
-
-class DataState(object):
- """
- Store information about data
- """
- def __init__(self, data=None, parent=None):
- """
-
- """
- self.parent = parent
- self.data = data
- self.name = ""
- self.path = None
- self.theory_list = {}
- self.message = ""
- self.id = None
-
- def __str__(self):
- _str = ""
- _str += "State with ID : %s \n" % str(self.id)
- if self.data is not None:
- _str += "Data name : %s \n" % str(self.data.name)
- _str += "Data ID : %s \n" % str(self.data.id)
- _str += "Theories available: %s \n" % len(self.theory_list)
- if self.theory_list:
- for id, item in self.theory_list.iteritems():
- theory_data, theory_state = item
- _str += "Theory name : %s \n" % str(theory_data.name)
- _str += "Theory ID : %s \n" % str(id)
- _str += "Theory info: \n"
- _str += str(theory_data)
-
- return _str
-
- def clone(self):
- obj = DataState(copy.deepcopy(self.data))
- obj.parent = self.parent
- obj.name = self.name
- obj.path = self.path
- obj.message = self.message
- obj.id = self.id
- for id, item in self.theory_list.iteritems():
- theory_data, theory_state = item
- state = None
- if theory_state is not None:
- state = theory_state.clone()
- obj.theory_list[id] = [copy.deepcopy(theory_data),
- state]
- return obj
-
- def set_name(self, name):
- self.name = name
-
- def get_name(self):
- return self.name
-
- def set_data(self, data):
- """
- """
- self.data = data
-
-
- def get_data(self):
- """
- """
- return self.data
-
- def set_path(self, path):
- """
- Set the path of the loaded data
- """
- self.path = path
-
- def get_path(self):
- """
- return the path of the loaded data
- """
- return self.path
-
- def set_theory(self, theory_data, theory_state=None):
- """
- """
- self.theory_list[theory_data.id] = [theory_data, theory_state]
- data, state = self.theory_list.values()[0]
-
- def get_theory(self):
- return self.theory_list
-
- def get_message(self):
- """
- return message
- """
- return self.message
-
+################################################################################
+#This software was developed by the University of Tennessee as part of the
+#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
+#project funded by the US National Science Foundation.
+#
+#See the license text in license.txt
+#
+#copyright 2010, University of Tennessee
+################################################################################
+"""
+"""
+import copy
+
+
+class DataState(object):
+ """
+ Store information about data
+ """
+ def __init__(self, data=None, parent=None):
+ """
+
+ """
+ self.parent = parent
+ self.data = data
+ self.name = ""
+ self.path = None
+ self.theory_list = {}
+ self.message = ""
+ self.id = None
+
+ def __str__(self):
+ _str = ""
+ _str += "State with ID : %s \n" % str(self.id)
+ if self.data is not None:
+ _str += "Data name : %s \n" % str(self.data.name)
+ _str += "Data ID : %s \n" % str(self.data.id)
+ _str += "Theories available: %s \n" % len(self.theory_list)
+ if self.theory_list:
+ for id, item in self.theory_list.iteritems():
+ theory_data, theory_state = item
+ _str += "Theory name : %s \n" % str(theory_data.name)
+ _str += "Theory ID : %s \n" % str(id)
+ _str += "Theory info: \n"
+ _str += str(theory_data)
+
+ return _str
+
+ def clone(self):
+ obj = DataState(copy.deepcopy(self.data))
+ obj.parent = self.parent
+ obj.name = self.name
+ obj.path = self.path
+ obj.message = self.message
+ obj.id = self.id
+ for id, item in self.theory_list.iteritems():
+ theory_data, theory_state = item
+ state = None
+ if theory_state is not None:
+ state = theory_state.clone()
+ obj.theory_list[id] = [copy.deepcopy(theory_data),
+ state]
+ return obj
+
+ def set_name(self, name):
+ self.name = name
+
+ def get_name(self):
+ return self.name
+
+ def set_data(self, data):
+ """
+ """
+ self.data = data
+
+
+ def get_data(self):
+ """
+ """
+ return self.data
+
+ def set_path(self, path):
+ """
+ Set the path of the loaded data
+ """
+ self.path = path
+
+ def get_path(self):
+ """
+ return the path of the loaded data
+ """
+ return self.path
+
+ def set_theory(self, theory_data, theory_state=None):
+ """
+ """
+ self.theory_list[theory_data.id] = [theory_data, theory_state]
+ data, state = self.theory_list.values()[0]
+
+ def get_theory(self):
+ return self.theory_list
+
+ def get_message(self):
+ """
+ return message
+ """
+ return self.message
+
\ No newline at end of file
diff --git a/src/sas/sasgui/guiframe/documentation_window.py b/src/sas/sasgui/guiframe/documentation_window.py
index 88298f8..1b1b636 100644
--- a/src/sas/sasgui/guiframe/documentation_window.py
+++ b/src/sas/sasgui/guiframe/documentation_window.py
@@ -1,101 +1,137 @@
-"""
-documentation module provides a simple means to add help throughout the
-application. It checks for the existence of html2 package needed to support
-fully html panel which supports css. The class defined here takes a title for
-the particular help panel, a pointer to the html documentation file of interest
-within the documentation tree along with a 'command' string such as a page
-anchor or a query string etc. The path to the doc directory is retrieved
-automatically by the class itself. Thus with these three pieces of information
-the class generates a panel with the appropriate title bar and help file
-formatted according the style sheets called in the html file. Finally, if an
-old version of Python is running and the html2 package is not available the
-class brings up the default browser and passes the file:/// string to it. In
-this case however the instruction portion is usually not passed for security
-reasons.
-"""
-import os
-import logging
-import wx
-import webbrowser
-import urllib
-import sys
-
-SPHINX_DOC_ENV = "SASVIEW_DOC_PATH"
-WX_SUPPORTS_HTML2 = True
-try:
- import wx.html2 as html
-except:
- WX_SUPPORTS_HTML2 = False
-
-
-from gui_manager import get_app_dir
-
-
-class DocumentationWindow(wx.Frame):
- """
- DocumentationWindow inherits from wx.Frame and provides a centralized
- coherent framework for all help documentation. Help files must be html
- files stored in an properly organized tree below the top 'doc' folder. In
- order to display the appropriate help file from anywhere in the gui, the
- code simply needs to know the location below the top level where the
- help file resides along with the name of the help file.
- called
- (self, parent, dummy_id, path, url_instruction, title, size=(850, 540))
-
- :param path: path to html file beginning AFTER /doc/ and ending in the\
- file.html.
- :param url_instructions: anchor string or other query e.g. '#MyAnchor'
- :param title: text to place in the title bar of the help panel
- """
- def __init__(self, parent, dummy_id, path, url_instruction, title, size=(850, 540)):
- wx.Frame.__init__(self, parent, dummy_id, title, size=size)
-
- if SPHINX_DOC_ENV in os.environ:
- docs_path = os.path.join(os.environ[SPHINX_DOC_ENV])
- else:
- # For the installer, docs are in a top-level directory. We're not
- # bothering to worry about docs when running using the old
- # (non - run.py) way.
- docs_path = os.path.join(get_app_dir(), "doc")
-
- #note that filepath for mac OS, at least in bundle starts with a
- #forward slash as /Application, while the PC string begins C:\
- #It seems that mac OS is happy with four slashes as in file:////App...
- #Two slashes is not sufficient to indicate path from root. Thus for now
- #we use "file:///" +... If the mac behavior changes may need to make the
- #file:/// be another constant at the beginning that yields // for Mac
- #and /// for PC.
- #Note added June 21, 2015 PDB
- file_path = os.path.join(docs_path, path)
- url = "file:///" + urllib.quote(file_path, r'/\:')+ url_instruction
-
- if not os.path.exists(file_path):
- logging.error("Could not find Sphinx documentation at %s \
- -- has it been built?", file_path)
- #Commenting following 5 lines, so default browser is forced
- #This is due to CDN mathjax discontinuation of service, intenal help
- #browser should be back with qt version
- #Note added by Wojtek Potrzebowski, July 4th 2017
- # elif WX_SUPPORTS_HTML2:
- # # Complete HTML/CSS support!
- # self.view = html.WebView.New(self)
- # self.view.LoadURL(url)
- # self.Show()
- else:
- logging.error("No html2 support, popping up a web browser")
- #For cases that do not build against current version dependency
- # Wx 3.0 we provide a webbrowser call - this is particularly for
- #Red hat used at SNS for which Wx 3.0 is not available. This
- #does not deal with issue of math in docs of course.
- webbrowser.open_new_tab(url)
-
-def main():
- """
- main loop function if running alone for testing.
- """
- app = wx.App()
- DocumentationWindow(None, -1, "index.html", "", "Documentation",)
- app.MainLoop()
-
-if __name__ == '__main__':
- main()
+"""
+documentation module provides a simple means to add help throughout the
+application. It checks for the existence of html2 package needed to support
+fully html panel which supports css. The class defined here takes a title for
+the particular help panel, a pointer to the html documentation file of interest
+within the documentation tree along with a 'command' string such as a page
+anchor or a query string etc. The path to the doc directory is retrieved
+automatically by the class itself. Thus with these three pieces of information
+the class generates a panel with the appropriate title bar and help file
+formatted according the style sheets called in the html file. Finally, if an
+old version of Python is running and the html2 package is not available the
+class brings up the default browser and passes the file:/// string to it. In
+this case however the instruction portion is usually not passed for security
+reasons.
+"""
+import os
+import logging
+import webbrowser
+import urllib
+import sys
+
+import wx
+try:
+ import wx.html2 as html
+ WX_SUPPORTS_HTML2 = True
+except ImportError:
+ WX_SUPPORTS_HTML2 = False
+
+from sas import get_app_dir
+
+# Don't use wx html renderer on windows.
+if os.name == 'nt':
+ WX_SUPPORTS_HTML2 = False
+
+logger = logging.getLogger(__name__)
+
+SPHINX_DOC_ENV = "SASVIEW_DOC_PATH"
+
+THREAD_STARTED = False
+def start_documentation_server(doc_root, port):
+ import thread
+ global THREAD_STARTED
+ if not THREAD_STARTED:
+ thread.start_new_thread(_documentation_server, (doc_root, port))
+ THREAD_STARTED = True
+
+def _documentation_server(doc_root, port):
+ from SimpleHTTPServer import SimpleHTTPRequestHandler
+ from SocketServer import TCPServer
+
+ os.chdir(doc_root)
+ httpd = TCPServer(("127.0.0.1", port), SimpleHTTPRequestHandler, bind_and_activate=False)
+ httpd.allow_reuse_address = True
+ try:
+ httpd.server_bind()
+ httpd.server_activate()
+ httpd.serve_forever()
+ finally:
+ httpd.server_close()
+
+class DocumentationWindow(wx.Frame):
+ """
+ DocumentationWindow inherits from wx.Frame and provides a centralized
+ coherent framework for all help documentation. Help files must be html
+ files stored in an properly organized tree below the top 'doc' folder. In
+ order to display the appropriate help file from anywhere in the gui, the
+ code simply needs to know the location below the top level where the
+ help file resides along with the name of the help file.
+ called
+ (self, parent, dummy_id, path, url_instruction, title, size=(850, 540))
+
+ :param path: path to html file beginning AFTER /doc/ and ending in the\
+ file.html.
+ :param url_instructions: anchor string or other query e.g. '#MyAnchor'
+ :param title: text to place in the title bar of the help panel
+ """
+ def __init__(self, parent, dummy_id, path, url_instruction, title, size=(850, 540)):
+ wx.Frame.__init__(self, parent, dummy_id, title, size=size)
+
+ if SPHINX_DOC_ENV in os.environ:
+ docs_path = os.path.join(os.environ[SPHINX_DOC_ENV])
+ else:
+ # For the installer, docs are in a top-level directory. We're not
+ # bothering to worry about docs when running using the old
+ # (non - run.py) way.
+ docs_path = os.path.join(get_app_dir(), "doc")
+
+ #note that filepath for mac OS, at least in bundle starts with a
+ #forward slash as /Application, while the PC string begins C:\
+ #It seems that mac OS is happy with four slashes as in file:////App...
+ #Two slashes is not sufficient to indicate path from root. Thus for now
+ #we use "file:///" +... If the mac behavior changes may need to make the
+ #file:/// be another constant at the beginning that yields // for Mac
+ #and /// for PC.
+ #Note added June 21, 2015 PDB
+ file_path = os.path.join(docs_path, path)
+ if path.startswith('http'):
+ url = path
+ elif not os.path.exists(file_path):
+ url = "index.html"
+ logger.error("Could not find Sphinx documentation at %s -- has it been built?",
+ file_path)
+ elif False:
+ start_documentation_server(docs_path, port=7999)
+ url = "http://127.0.0.1:7999/" + path.replace('\\', '/') + url_instruction
+ else:
+ url = "file:///" + urllib.quote(file_path, r'/\:')+ url_instruction
+
+ #logger.info("showing url " + url)
+ if WX_SUPPORTS_HTML2:
+ # Complete HTML/CSS support!
+ self.view = html.WebView.New(self)
+ self.view.LoadURL(url)
+ self.Bind(html.EVT_WEBVIEW_ERROR, self.OnError, self.view)
+ self.Show()
+ else:
+ logger.error("No html2 support, popping up a web browser")
+ #For cases that do not build against current version dependency
+ # Wx 3.0 we provide a webbrowser call - this is particularly for
+ #Red hat used at SNS for which Wx 3.0 is not available. This
+ #does not deal with issue of math in docs of course.
+ webbrowser.open_new_tab(url)
+
+ def OnError(self, evt):
+ logger.error("%d: %s", evt.GetInt(), evt.GetString())
+
+def main():
+ """
+ main loop function if running alone for testing.
+ """
+ url = "index.html" if len(sys.argv) <= 1 else sys.argv[1]
+ app = wx.App()
+ DocumentationWindow(None, -1, url, "", "Documentation",)
+ app.MainLoop()
+
+if __name__ == '__main__':
+ main()
diff --git a/src/sas/sasgui/guiframe/dummyapp.py b/src/sas/sasgui/guiframe/dummyapp.py
index 10547c0..7515177 100644
--- a/src/sas/sasgui/guiframe/dummyapp.py
+++ b/src/sas/sasgui/guiframe/dummyapp.py
@@ -1,126 +1,128 @@
-"""
-Dummy application.
-Allows the user to set an external data manager
-"""
-import sas.sasgui.guiframe.gui_manager as gui_manager
-
-from sas.sasgui.guiframe.plugin_base import PluginBase
-
-class DummyView(gui_manager.SasViewApp):
- """
- """
-
-class TestPlugin(PluginBase):
-
- def populate_menu(self, parent):
- """
- Create and return the list of application menu
- items for the plug-in.
- :param parent: parent window
-
- :return: plug-in menu
-
- """
- import wx
- # Create a menu
- plug_menu = wx.Menu()
-
- # Always get event IDs from wx
- id = wx.NewId()
-
- # Fill your menu
- plug_menu.Append(id, '&Do something')
- def _on_do_something(event):
- print "Do something"
- wx.EVT_MENU(self.parent, id, _on_do_something)
-
- # Returns the menu and a name for it.
- return [(plug_menu, "DummyApp")]
-
- def get_panels(self, parent):
- """
- Create and return the list of wx.Panels for your plug-in.
- Define the plug-in perspective.
-
- Panels should inherit from DefaultPanel defined below,
- or should present the same interface. They must define
- "window_caption" and "window_name".
-
- :param parent: parent window
-
- :return: list of panels
-
- """
- ## Save a reference to the parent
- self.parent = parent
-
- # Define a panel
- defaultpanel = gui_manager.DefaultPanel(self.parent, -1)
- defaultpanel.window_name = "Test"
-
- # If needed, add its name to the perspective list
- self.perspective = [defaultpanel.window_name]
-
- # Return the list of panels
- return [defaultpanel]
-
- def get_tools(self):
- """
- Returns a set of menu entries for tools
- """
- def _test_dialog(event):
- import wx
- frame = wx.Dialog(None, -1, 'Test Tool')
- frame.Show(True)
- return [["Tool 1", "This is an example tool", _test_dialog],
- ["Tool 2", "This is another example tool", _test_dialog]]
-
- def get_context_menu(self, graph=None):
- """
- This method is optional.
-
- When the context menu of a plot is rendered, the
- get_context_menu method will be called to give you a
- chance to add a menu item to the context menu.
-
- A ref to a Graph object is passed so that you can
- investigate the plot content and decide whether you
- need to add items to the context menu.
-
- This method returns a list of menu items.
- Each item is itself a list defining the text to
- appear in the menu, a tool-tip help text, and a
- call-back method.
-
- :param graph: the Graph object to which we attach the context menu
-
- :return: a list of menu items with call-back function
- """
- return [["Menu text",
- "Tool-tip help text",
- "self._on_context_do_something"]]
-
-class SasView():
-
- def __init__(self):
- """
- Initialization
- """
- self.gui = DummyView(0)
-
- fitting_plug = TestPlugin()
- self.gui.add_perspective(fitting_plug)
-
- # Build the GUI
- self.gui.build_gui()
-
- # Set the application manager for the GUI
- self.gui.set_manager(self)
-
- # Start the main loop
- self.gui.MainLoop()
-
-if __name__ == "__main__":
- from multiprocessing import freeze_support
- freeze_support()
- sasview = SasView()
+"""
+Dummy application.
+Allows the user to set an external data manager
+"""
+from __future__ import print_function
+
+import sas.sasgui.guiframe.gui_manager as gui_manager
+
+from sas.sasgui.guiframe.plugin_base import PluginBase
+
+class DummyView(gui_manager.SasViewApp):
+ """
+ """
+
+class TestPlugin(PluginBase):
+
+ def populate_menu(self, parent):
+ """
+ Create and return the list of application menu
+ items for the plug-in.
+ :param parent: parent window
+
+ :return: plug-in menu
+
+ """
+ import wx
+ # Create a menu
+ plug_menu = wx.Menu()
+
+ # Always get event IDs from wx
+ id = wx.NewId()
+
+ # Fill your menu
+ plug_menu.Append(id, '&Do something')
+ def _on_do_something(event):
+ print("Do something")
+ wx.EVT_MENU(self.parent, id, _on_do_something)
+
+ # Returns the menu and a name for it.
+ return [(plug_menu, "DummyApp")]
+
+ def get_panels(self, parent):
+ """
+ Create and return the list of wx.Panels for your plug-in.
+ Define the plug-in perspective.
+
+ Panels should inherit from DefaultPanel defined below,
+ or should present the same interface. They must define
+ "window_caption" and "window_name".
+
+ :param parent: parent window
+
+ :return: list of panels
+
+ """
+ ## Save a reference to the parent
+ self.parent = parent
+
+ # Define a panel
+ defaultpanel = gui_manager.DefaultPanel(self.parent, -1)
+ defaultpanel.window_name = "Test"
+
+ # If needed, add its name to the perspective list
+ self.perspective = [defaultpanel.window_name]
+
+ # Return the list of panels
+ return [defaultpanel]
+
+ def get_tools(self):
+ """
+ Returns a set of menu entries for tools
+ """
+ def _test_dialog(event):
+ import wx
+ frame = wx.Dialog(None, -1, 'Test Tool')
+ frame.Show(True)
+ return [["Tool 1", "This is an example tool", _test_dialog],
+ ["Tool 2", "This is another example tool", _test_dialog]]
+
+ def get_context_menu(self, graph=None):
+ """
+ This method is optional.
+
+ When the context menu of a plot is rendered, the
+ get_context_menu method will be called to give you a
+ chance to add a menu item to the context menu.
+
+ A ref to a Graph object is passed so that you can
+ investigate the plot content and decide whether you
+ need to add items to the context menu.
+
+ This method returns a list of menu items.
+ Each item is itself a list defining the text to
+ appear in the menu, a tool-tip help text, and a
+ call-back method.
+
+ :param graph: the Graph object to which we attach the context menu
+
+ :return: a list of menu items with call-back function
+ """
+ return [["Menu text",
+ "Tool-tip help text",
+ "self._on_context_do_something"]]
+
+class SasView():
+
+ def __init__(self):
+ """
+ Initialization
+ """
+ self.gui = DummyView(0)
+
+ fitting_plug = TestPlugin()
+ self.gui.add_perspective(fitting_plug)
+
+ # Build the GUI
+ self.gui.build_gui()
+
+ # Set the application manager for the GUI
+ self.gui.set_manager(self)
+
+ # Start the main loop
+ self.gui.MainLoop()
+
+if __name__ == "__main__":
+ from multiprocessing import freeze_support
+ freeze_support()
+ sasview = SasView()
diff --git a/src/sas/sasgui/guiframe/events.py b/src/sas/sasgui/guiframe/events.py
index a595221..ff6d57f 100644
--- a/src/sas/sasgui/guiframe/events.py
+++ b/src/sas/sasgui/guiframe/events.py
@@ -1,37 +1,37 @@
-import wx.lib.newevent
-#send data to data manager
-(NewStoreDataEvent, EVT_NEW_STORE_DATA) = wx.lib.newevent.NewEvent()
-# send data to other perspectives
-(NewLoadedDataEvent, EVT_NEW_LOADED_DATA) = wx.lib.newevent.NewEvent()
-# plot data
-(NewPlotEvent, EVT_NEW_PLOT) = wx.lib.newevent.NewEvent()
-# plot Qrange
-(PlotQrangeEvent, EVT_PLOT_QRANGE) = wx.lib.newevent.NewEvent()
-# set plot limits
-(PlotLimitEvent, EVT_PLOT_LIM) = wx.lib.newevent.NewEvent()
-# print the messages on statusbar
-(StatusEvent, EVT_STATUS) = wx.lib.newevent.NewEvent()
-#create a panel slicer
-(SlicerPanelEvent, EVT_SLICER_PANEL) = wx.lib.newevent.NewEvent()
-#print update paramaters for panel slicer
-(SlicerParamUpdateEvent, EVT_SLICER_PARS_UPDATE) = wx.lib.newevent.NewEvent()
-#update the slicer from the panel
-(SlicerParameterEvent, EVT_SLICER_PARS) = wx.lib.newevent.NewEvent()
-#slicer event
-(SlicerEvent, EVT_SLICER) = wx.lib.newevent.NewEvent()
-## event that that destroy panel name in the datapanel combobox
-(DeletePlotPanelEvent, EVT_DELETE_PLOTPANEL) = wx.lib.newevent.NewEvent()
-##event that allow to add more that to the same plot
-(AddManyDataEvent, EVT_ADD_MANY_DATA) = wx.lib.newevent.NewEvent()
-##event for the panel on focus
-(PanelOnFocusEvent, EVT_PANEL_ON_FOCUS) = wx.lib.newevent.NewEvent()
-#book mark event
-(AppendBookmarkEvent, EVT_APPEND_BOOKMARK) = wx.lib.newevent.NewEvent()
-#event to ask dataloader plugin to load data if dataloader plugin exist
-(NewLoadDataEvent, EVT_NEW_LOAD_DATA) = wx.lib.newevent.NewEvent()
-#event to toggle from single model to batch
-(NewBatchEvent, EVT_NEW_BATCH) = wx.lib.newevent.NewEvent()
-##color event
-(NewColorEvent, EVT_NEW_COLOR) = wx.lib.newevent.NewEvent()
-##change category event
-(ChangeCategoryEvent, EVT_CATEGORY) = wx.lib.newevent.NewEvent()
+import wx.lib.newevent
+#send data to data manager
+(NewStoreDataEvent, EVT_NEW_STORE_DATA) = wx.lib.newevent.NewEvent()
+# send data to other perspectives
+(NewLoadedDataEvent, EVT_NEW_LOADED_DATA) = wx.lib.newevent.NewEvent()
+# plot data
+(NewPlotEvent, EVT_NEW_PLOT) = wx.lib.newevent.NewEvent()
+# plot Qrange
+(PlotQrangeEvent, EVT_PLOT_QRANGE) = wx.lib.newevent.NewEvent()
+# set plot limits
+(PlotLimitEvent, EVT_PLOT_LIM) = wx.lib.newevent.NewEvent()
+# print the messages on statusbar
+(StatusEvent, EVT_STATUS) = wx.lib.newevent.NewEvent()
+#create a panel slicer
+(SlicerPanelEvent, EVT_SLICER_PANEL) = wx.lib.newevent.NewEvent()
+#print update paramaters for panel slicer
+(SlicerParamUpdateEvent, EVT_SLICER_PARS_UPDATE) = wx.lib.newevent.NewEvent()
+#update the slicer from the panel
+(SlicerParameterEvent, EVT_SLICER_PARS) = wx.lib.newevent.NewEvent()
+#slicer event
+(SlicerEvent, EVT_SLICER) = wx.lib.newevent.NewEvent()
+## event that that destroy panel name in the datapanel combobox
+(DeletePlotPanelEvent, EVT_DELETE_PLOTPANEL) = wx.lib.newevent.NewEvent()
+##event that allow to add more that to the same plot
+(AddManyDataEvent, EVT_ADD_MANY_DATA) = wx.lib.newevent.NewEvent()
+##event for the panel on focus
+(PanelOnFocusEvent, EVT_PANEL_ON_FOCUS) = wx.lib.newevent.NewEvent()
+#book mark event
+(AppendBookmarkEvent, EVT_APPEND_BOOKMARK) = wx.lib.newevent.NewEvent()
+#event to ask dataloader plugin to load data if dataloader plugin exist
+(NewLoadDataEvent, EVT_NEW_LOAD_DATA) = wx.lib.newevent.NewEvent()
+#event to toggle from single model to batch
+(NewBatchEvent, EVT_NEW_BATCH) = wx.lib.newevent.NewEvent()
+##color event
+(NewColorEvent, EVT_NEW_COLOR) = wx.lib.newevent.NewEvent()
+##change category event
+(ChangeCategoryEvent, EVT_CATEGORY) = wx.lib.newevent.NewEvent()
diff --git a/src/sas/sasgui/guiframe/gui_manager.py b/src/sas/sasgui/guiframe/gui_manager.py
index b7edae1..6f6fbef 100644
--- a/src/sas/sasgui/guiframe/gui_manager.py
+++ b/src/sas/sasgui/guiframe/gui_manager.py
@@ -21,12 +21,13 @@ import imp
import warnings
import re
import logging
-import httplib
import traceback
import urllib
-import urllib2
import json
+from matplotlib import _pylab_helpers
+
+from sas import get_local_config, get_custom_config, get_app_dir, get_user_dir
from sas.sasgui.guiframe.events import EVT_CATEGORY
from sas.sasgui.guiframe.events import EVT_STATUS
from sas.sasgui.guiframe.events import EVT_APPEND_BOOKMARK
@@ -45,103 +46,12 @@ from sas.sasgui.guiframe.events import EVT_NEW_BATCH
from sas.sasgui.guiframe.CategoryManager import CategoryManager
from sas.sascalc.dataloader.loader import Loader
from sas.sasgui.guiframe.proxy import Connection
-from matplotlib import _pylab_helpers
+logger = logging.getLogger(__name__)
warnings.simplefilter("ignore")
-
-def get_app_dir():
- """
- The application directory is the one where the default custom_config.py
- file resides.
-
- :returns: app_path - the path to the applicatin directory
- """
- # First, try the directory of the executable we are running
- app_path = sys.path[0]
- if os.path.isfile(app_path):
- app_path = os.path.dirname(app_path)
- if os.path.isfile(os.path.join(app_path, "custom_config.py")):
- app_path = os.path.abspath(app_path)
- logging.info("Using application path: %s", app_path)
- return app_path
-
- # Next, try the current working directory
- if os.path.isfile(os.path.join(os.getcwd(), "custom_config.py")):
- logging.info("Using application path: %s", os.getcwd())
- return os.path.abspath(os.getcwd())
-
- # Finally, try the directory of the sasview module
- # TODO: gui_manager will have to know about sasview until we
- # clean all these module variables and put them into a config class
- # that can be passed by sasview.py.
- logging.info(sys.executable)
- logging.info(str(sys.argv))
- from sas import sasview as sasview
- app_path = os.path.dirname(sasview.__file__)
- logging.info("Using application path: %s", app_path)
- return app_path
-
-
-def get_user_directory():
- """
- Returns the user's home directory
- """
- userdir = os.path.join(os.path.expanduser("~"), ".sasview")
- if not os.path.isdir(userdir):
- os.makedirs(userdir)
- return userdir
-
-
-def _find_local_config(file, path):
- """
- Find configuration file for the current application
- """
- config_module = None
- fObj = None
- try:
- fObj, path_config, descr = imp.find_module(file, [path])
- config_module = imp.load_module(file, fObj, path_config, descr)
- except:
- logging.error("Error loading %s/%s: %s" % (path, file, sys.exc_value))
- finally:
- if fObj is not None:
- fObj.close()
- logging.info("GuiManager loaded %s/%s" % (path, file))
- return config_module
-
-# Get APP folder
-PATH_APP = get_app_dir()
-DATAPATH = PATH_APP
-
-# GUI always starts from the App folder
-# os.chdir(PATH_APP)
-# Read in the local config, which can either be with the main
-# application or in the installation directory
-config = _find_local_config('local_config', PATH_APP)
-if config is None:
- config = _find_local_config('local_config', os.getcwd())
- if config is None:
- # Didn't find local config, load the default
- import sas.sasgui.guiframe.config as config
- logging.info("using default local_config")
- else:
- logging.info("found local_config in %s" % os.getcwd())
-else:
- logging.info("found local_config in %s" % PATH_APP)
-
-from sas.sasgui.guiframe.customdir import SetupCustom
-c_conf_dir = SetupCustom().setup_dir(PATH_APP)
-custom_config = _find_local_config('custom_config', c_conf_dir)
-if custom_config is None:
- custom_config = _find_local_config('custom_config', os.getcwd())
- if custom_config is None:
- msgConfig = "Custom_config file was not imported"
- logging.info(msgConfig)
- else:
- logging.info("using custom_config in %s" % os.getcwd())
-else:
- logging.info("using custom_config from %s" % c_conf_dir)
+config = get_local_config()
+custom_config = get_custom_config()
# read some constants from config
APPLICATION_STATE_EXTENSION = config.APPLICATION_STATE_EXTENSION
@@ -151,7 +61,6 @@ WELCOME_PANEL_ON = config.WELCOME_PANEL_ON
SPLASH_SCREEN_WIDTH = config.SPLASH_SCREEN_WIDTH
SPLASH_SCREEN_HEIGHT = config.SPLASH_SCREEN_HEIGHT
SS_MAX_DISPLAY_TIME = config.SS_MAX_DISPLAY_TIME
-SAS_OPENCL = config.SAS_OPENCL
if not WELCOME_PANEL_ON:
WELCOME_PANEL_SHOW = False
else:
@@ -175,7 +84,7 @@ try:
if open_folder is not None and os.path.isdir(open_folder):
DEFAULT_OPEN_FOLDER = os.path.abspath(open_folder)
else:
- DEFAULT_OPEN_FOLDER = PATH_APP
+ DEFAULT_OPEN_FOLDER = get_app_dir()
SAS_OPENCL = custom_config.SAS_OPENCL
except:
DATALOADER_SHOW = True
@@ -190,6 +99,7 @@ except:
CONTROL_HEIGHT = -1
DEFAULT_PERSPECTIVE = None
CLEANUP_PLOT = False
+ DEFAULT_OPEN_FOLDER = get_app_dir()
DEFAULT_OPEN_FOLDER = PATH_APP
SAS_OPENCL = None
DEFAULT_STYLE = config.DEFAULT_STYLE
@@ -226,10 +136,6 @@ if sys.platform.count("win32") < 1:
PARENT_FRAME = wx.Frame
CHILD_FRAME = wx.Frame
-#Initiliaze enviromental variable with custom setting but only if variable not set
-if SAS_OPENCL and not "SAS_OPENCL" in os.environ:
- os.environ["SAS_OPENCL"] = SAS_OPENCL
-
class ViewerFrame(PARENT_FRAME):
"""
Main application frame
@@ -263,7 +169,7 @@ class ViewerFrame(PARENT_FRAME):
'images', 'ball.ico')
if os.path.isfile(ico_file):
self.SetIcon(wx.Icon(ico_file, wx.BITMAP_TYPE_ICO))
- self.path = PATH_APP
+ self.path = get_app_dir()
self.application_name = APPLICATION_NAME
# Application manager
self._input_file = None
@@ -373,7 +279,7 @@ class ViewerFrame(PARENT_FRAME):
icon = self.GetIcon()
frame.SetIcon(icon)
except:
- logging.error("ViewerFrame.put_icon: could not set icon")
+ logger.error("ViewerFrame.put_icon: could not set icon")
def get_client_size(self):
"""
@@ -538,9 +444,9 @@ class ViewerFrame(PARENT_FRAME):
_, ext = os.path.splitext(name)
try:
fd = open(file_name, 'w')
- except:
+ except Exception:
# On Permission denied: IOError
- temp_dir = get_user_directory()
+ temp_dir = get_user_dir()
temp_file_name = os.path.join(temp_dir, name)
fd = open(temp_file_name, 'w')
separator = "\t"
@@ -802,7 +708,7 @@ class ViewerFrame(PARENT_FRAME):
msg = "%s Cannot load file %s\n" % (str(APPLICATION_NAME),
str(self._input_file))
msg += str(sys.exc_value) + '\n'
- logging.error(msg)
+ logger.error(msg)
if self._data_panel is not None and len(self.plugins) > 0:
self._data_panel.fill_cbox_analysis(self.plugins)
self.post_init()
@@ -868,12 +774,12 @@ class ViewerFrame(PARENT_FRAME):
item.set_batch_selection(self.batch_on)
if plugin.__class__ == item.__class__:
msg = "Plugin %s already loaded" % plugin.sub_menu
- logging.info(msg)
+ logger.info(msg)
is_loaded = True
if not is_loaded:
self.plugins.append(plugin)
msg = "Plugin %s appended" % plugin.sub_menu
- logging.info(msg)
+ logger.info(msg)
def _get_local_plugins(self):
"""
@@ -893,7 +799,7 @@ class ViewerFrame(PARENT_FRAME):
except:
msg = "ViewerFrame._get_local_plugins:"
msg += "cannot import dataloader plugin.\n %s" % sys.exc_value
- logging.error(msg)
+ logger.error(msg)
if style2 == GUIFRAME.PLOTTING_ON:
try:
from sas.sasgui.guiframe.local_perspectives.plotting \
@@ -903,7 +809,7 @@ class ViewerFrame(PARENT_FRAME):
except:
msg = "ViewerFrame._get_local_plugins:"
msg += "cannot import plotting plugin.\n %s" % sys.exc_value
- logging.error(msg)
+ logger.error(msg)
return plugins
@@ -948,21 +854,21 @@ class ViewerFrame(PARENT_FRAME):
try:
plugins.append(module.Plugin())
msg = "Found plug-in: %s" % module.PLUGIN_ID
- logging.info(msg)
+ logger.info(msg)
except:
msg = "Error accessing PluginPanel"
msg += " in %s\n %s" % (name, sys.exc_value)
config.printEVT(msg)
except:
msg = "ViewerFrame._find_plugins: %s" % sys.exc_value
- logging.error(msg)
+ logger.error(msg)
finally:
if file is not None:
file.close()
except:
# Should raise and catch at a higher level and
# display error on status bar
- logging.error(sys.exc_value)
+ logger.error(sys.exc_value)
return plugins
@@ -1384,7 +1290,7 @@ class ViewerFrame(PARENT_FRAME):
wx.EVT_MENU(self, wx_id, self._onAcknowledge)
if config._do_aboutbox:
- logging.info("Doing help menu")
+ logger.info("Doing help menu")
wx_id = wx.NewId()
self._help_menu.Append(wx_id, '&About', 'Software information')
wx.EVT_MENU(self, wx_id, self._onAbout)
@@ -1530,7 +1436,7 @@ class ViewerFrame(PARENT_FRAME):
# another menu item will need to check if this is still where we
# want Analysis. This is NOT an issue on the Mac which does not
# have the extra Window menu item.
- # March 2016 Code Camp -- PDB
+ # March 2016 Code Camp -- PDB
Tools_pos = self._menubar.FindMenu("Tools")
self._menubar.Insert(Tools_pos+1, self._applications_menu,
'&Analysis')
@@ -1745,7 +1651,7 @@ class ViewerFrame(PARENT_FRAME):
if ID in self.panels.keys():
del self.panels[ID]
else:
- logging.error("delete_panel: No such plot id as %s" % ID)
+ logger.error("delete_panel: No such plot id as %s" % ID)
def create_gui_data(self, data, path=None):
"""
@@ -1762,7 +1668,7 @@ class ViewerFrame(PARENT_FRAME):
log_msg = "File Loader cannot "
log_msg += "load: %s\n" % str(basename)
log_msg += "Try Data opening...."
- logging.error(log_msg)
+ logger.error(log_msg)
return
# reading a state file
@@ -1842,13 +1748,13 @@ class ViewerFrame(PARENT_FRAME):
log_msg = "Data Loader cannot "
log_msg += "load: %s\n" % str(path)
log_msg += "Try File opening ...."
- logging.error(log_msg)
+ logger.error(log_msg)
return
log_msg = ''
output = {}
error_message = ""
try:
- logging.info("Loading Data...:\n" + str(path) + "\n")
+ logger.info("Loading Data...:\n" + str(path) + "\n")
temp = self.loader.load(path)
if temp.__class__.__name__ == "list":
for item in temp:
@@ -1863,7 +1769,7 @@ class ViewerFrame(PARENT_FRAME):
error_message = "Error while loading"
error_message += " Data from cmd:\n %s\n" % str(path)
error_message += str(sys.exc_value) + "\n"
- logging.error(error_message)
+ logger.error(error_message)
def load_folder(self, path):
"""
@@ -1884,7 +1790,7 @@ class ViewerFrame(PARENT_FRAME):
error_message = "Error while loading"
error_message += " Data folder from cmd:\n %s\n" % str(path)
error_message += str(sys.exc_value) + "\n"
- logging.error(error_message)
+ logger.error(error_message)
def _on_open_state_application(self, event):
"""
@@ -2043,7 +1949,7 @@ class ViewerFrame(PARENT_FRAME):
msg += "should have a data set "
msg += "and model selected. "
msg += "No project was saved to %s" % (str(path))
- logging.warning(msg)
+ logger.warning(msg)
wx.PostEvent(self, StatusEvent(status=msg, info="error"))
except Exception:
msg = "Error occurred while saving: "
@@ -2110,7 +2016,7 @@ class ViewerFrame(PARENT_FRAME):
"""
#IF SAS_OPENCL is set, settings are stored in the custom config file
self._write_opencl_config_file()
- logging.info(" --- SasView session was closed --- \n")
+ logger.info(" --- SasView session was closed --- \n")
wx.Exit()
sys.exit()
@@ -2120,16 +2026,17 @@ class ViewerFrame(PARENT_FRAME):
from session to session
"""
if custom_config is not None:
- sas_opencl = os.environ.get("SAS_OPENCL",None)
+ sas_opencl = os.environ.get("SAS_OPENCL")
new_config_lines = []
config_file = open(custom_config.__file__)
config_lines = config_file.readlines()
for line in config_lines:
if "SAS_OPENCL" in line:
if sas_opencl:
- new_config_lines.append("SAS_OPENCL = \""+sas_opencl+"\"")
+ new_config_lines.append("SAS_OPENCL = \"" + sas_opencl
+ + "\"\n")
else:
- new_config_lines.append("SAS_OPENCL = None")
+ new_config_lines.append("SAS_OPENCL = \"None\"\n")
else:
new_config_lines.append(line)
config_file.close()
@@ -2139,7 +2046,7 @@ class ViewerFrame(PARENT_FRAME):
new_config_file.writelines(new_config_lines)
new_config_file.close()
else:
- logging.info("Failed to save OPENCL settings in custom config file")
+ logger.info("Failed to save OPENCL settings in custom config file")
def _check_update(self, event=None):
@@ -2154,15 +2061,14 @@ class ViewerFrame(PARENT_FRAME):
response = c.connect()
if response is not None:
try:
- #
content = response.read().strip()
- logging.info("Connected to www.sasview.org. Latest version: %s"
- % (content))
+ logger.info("Connected to www.sasview.org. Latest version: %s", content)
version_info = json.loads(content)
except:
- logging.info("Failed to connect to www.sasview.org")
+ logger.info("Failed to connect to www.sasview.org")
self._process_version(version_info, standalone=event is None)
+
def _process_version(self, version_info, standalone=True):
"""
Call-back method for the process of checking for updates.
@@ -2200,7 +2106,7 @@ class ViewerFrame(PARENT_FRAME):
except:
msg = "guiframe: could not get latest application"
msg += " version number\n %s" % sys.exc_value
- logging.error(msg)
+ logger.error(msg)
if not standalone:
msg = "Could not connect to the application server."
msg += " Please try again later."
@@ -2247,15 +2153,15 @@ class ViewerFrame(PARENT_FRAME):
self.put_icon(dialog)
dialog.Show(True)
except:
- logging.error("Error in _onTutorial: %s" % sys.exc_value)
+ logger.error("Error in _onTutorial: %s" % sys.exc_value)
try:
# Try an alternate method
- logging.error(
+ logger.error(
"Could not open the tutorial pdf, trying xhtml2pdf")
from xhtml2pdf import pisa
pisa.startViewer(path)
except:
- logging.error(
+ logger.error(
"Could not open the tutorial pdf with xhtml2pdf")
msg = "This feature requires 'PDF Viewer'\n"
wx.MessageBox(msg, 'Error')
@@ -2266,12 +2172,12 @@ class ViewerFrame(PARENT_FRAME):
except:
try:
# Try an alternate method
- logging.error(
+ logger.error(
"Could not open the tutorial pdf, trying xhtml2pdf")
from xhtml2pdf import pisa
pisa.startViewer(path)
except:
- logging.error(
+ logger.error(
"Could not open the tutorial pdf with xhtml2pdf")
msg = "This feature requires the Preview application\n"
wx.MessageBox(msg, 'Error')
@@ -2410,7 +2316,7 @@ class ViewerFrame(PARENT_FRAME):
else:
msg = "Guiframe does not have a current perspective"
- logging.info(msg)
+ logger.info(msg)
def set_theory(self, state_id, theory_id=None):
"""
@@ -2421,11 +2327,11 @@ class ViewerFrame(PARENT_FRAME):
self._current_perspective.set_theory(list_theory.values())
except:
msg = "Guiframe set_theory: \n" + str(sys.exc_value)
- logging.info(msg)
+ logger.info(msg)
wx.PostEvent(self, StatusEvent(status=msg, info="error"))
else:
msg = "Guiframe does not have a current perspective"
- logging.info(msg)
+ logger.info(msg)
def plot_data(self, state_id, data_id=None,
theory_id=None, append=False):
@@ -2507,7 +2413,7 @@ class ViewerFrame(PARENT_FRAME):
group_id=("res" + str(id)),
action='remove'))
except:
- logging.error(sys.exc_value)
+ logger.error(sys.exc_value)
def save_data1d(self, data, fname):
"""
@@ -3305,7 +3211,7 @@ class SasViewApp(wx.App):
except:
msg = "%s Could not load " % str(APPLICATION_NAME)
msg += "input file from command line.\n"
- logging.error(msg)
+ logger.error(msg)
# Display a splash screen on top of the frame.
try:
if os.path.isfile(SPLASH_SCREEN_PATH):
@@ -3319,7 +3225,7 @@ class SasViewApp(wx.App):
self.s_screen.Close()
msg = "Cannot display splash screen\n"
msg += str(sys.exc_value)
- logging.error(msg)
+ logger.error(msg)
self.frame.Show()
self.SetTopWindow(self.frame)
@@ -3350,7 +3256,7 @@ class SasViewApp(wx.App):
app_app = app_base + '.app'
if basename.lower() in [app_py, app_exe, app_app, app_base]:
data_base = sys.argv[1]
- input_file = os.path.normpath(os.path.join(DATAPATH,
+ input_file = os.path.normpath(os.path.join(get_app_dir(),
data_base))
if input_file is None:
return
@@ -3365,7 +3271,7 @@ class SasViewApp(wx.App):
"""
# do it only the first time app loaded
# delete unused model folder
- model_folder = os.path.join(PATH_APP, path)
+ model_folder = os.path.join(get_app_dir(), path)
if os.path.exists(model_folder) and os.path.isdir(model_folder):
if len(os.listdir(model_folder)) > 0:
try:
@@ -3374,7 +3280,7 @@ class SasViewApp(wx.App):
if os.path.isfile(file_path):
os.remove(file_path)
except:
- logging.error("gui_manager.clean_plugin_models:\n %s"
+ logger.error("gui_manager.clean_plugin_models:\n %s"
% sys.exc_value)
def set_manager(self, manager):
diff --git a/src/sas/sasgui/guiframe/gui_statusbar.py b/src/sas/sasgui/guiframe/gui_statusbar.py
index ea53546..741c0d1 100644
--- a/src/sas/sasgui/guiframe/gui_statusbar.py
+++ b/src/sas/sasgui/guiframe/gui_statusbar.py
@@ -11,6 +11,8 @@ from wx.lib import newevent
import wx.richtext
from sas.sasgui.guiframe.gui_style import GUIFRAME_ICON
+logger = logging.getLogger(__name__)
+
# Number of fields on the status bar
NB_FIELDS = 4
#position of the status bar's fields
@@ -70,12 +72,12 @@ class ConsolePanel(wx.Panel):
if hasattr(event, "info"):
icon_type = event.info.lower()
if icon_type == "warning":
- logging.warning(status)
+ logger.warning(status)
color = (0, 0, 255) # blue
icon_bmp = wx.ArtProvider.GetBitmap(wx.ART_WARNING,
wx.ART_TOOLBAR)
if icon_type == "error":
- logging.error(status)
+ logger.error(status)
color = (255, 0, 0) # red
icon_bmp = wx.ArtProvider.GetBitmap(wx.ART_ERROR,
wx.ART_TOOLBAR)
diff --git a/src/sas/sasgui/guiframe/gui_style.py b/src/sas/sasgui/guiframe/gui_style.py
index 6eeae3f..71bfc97 100644
--- a/src/sas/sasgui/guiframe/gui_style.py
+++ b/src/sas/sasgui/guiframe/gui_style.py
@@ -1,90 +1,92 @@
-
-"""
-Provide the style for guiframe
-"""
-import wx
-import os
-from sas.sasgui.guiframe import get_data_path
-
-
-class GUIFRAME:
- MANAGER_ON = 1
- FLOATING_PANEL = 2
- FIXED_PANEL = 4
- PLOTTING_ON = 8
- DATALOADER_ON = 16
- TOOLBAR_ON = 32
- CALCULATOR_ON = 256
- SINGLE_APPLICATION = 64
- WELCOME_PANEL_ON = 128
- DEFAULT_STYLE = SINGLE_APPLICATION|DATALOADER_ON|PLOTTING_ON|FIXED_PANEL
- MULTIPLE_APPLICATIONS = DEFAULT_STYLE
-
-class GUIFRAME_ID:
- UNDO_ID = wx.NewId()
- REDO_ID = wx.NewId()
- COPY_ID = wx.NewId()
- PASTE_ID = wx.NewId()
- BOOKMARK_ID = wx.NewId()
- SAVE_ID = wx.NewId()
- ZOOM_IN_ID = wx.NewId()
- ZOOM_OUT_ID = wx.NewId()
- ZOOM_ID = wx.NewId()
- DRAG_ID = wx.NewId()
- RESET_ID = wx.NewId()
- PREVIEW_ID = wx.NewId()
- PRINT_ID = wx.NewId()
- CURRENT_APPLICATION = wx.NewId()
- CURVE_SYMBOL_NUM = 13
- COPYEX_ID = wx.NewId()
- COPYLAT_ID = wx.NewId()
- COPYAS_ID = wx.NewId()
-
-
-class GUIFRAME_ICON:
- PATH = get_data_path(media='images')
- FRAME_ICON_PATH = os.path.join(PATH, 'ball.ico')
- SAVE_ICON_PATH = os.path.join(PATH, 'save.png')
- UNDO_ICON_PATH = os.path.join(PATH, 'undo.png')
- REDO_ICON_PATH = os.path.join(PATH, 'redo.png')
- COPY_ICON_PATH = os.path.join(PATH, 'copy.png')
- PASTE_ICON_PATH = os.path.join(PATH, 'paste.png')
- BOOKMARK_ICON_PATH = os.path.join(PATH, 'bookmark.png')
- ZOOM_IN_ID_PATH = os.path.join(PATH, 'zoom_in.png')
- ZOOM_OUT_ID_PATH = os.path.join(PATH, 'zoom_out.png')
- ZOOM_ID_PATH = os.path.join(PATH, 'search_pan.png')
- DRAG_ID_PATH = os.path.join(PATH, 'drag_hand.png')
- RESET_ID_PATH = os.path.join(PATH, 'reset.png')
- PREVIEW_ID_PATH = os.path.join(PATH, 'report.png')
- PRINT_ID_PATH = os.path.join(PATH, 'printer.png')
- HIDE_ID_PATH = os.path.join(PATH, 'hide.png')
-
-
- SAVE_ICON = wx.Image(os.path.join(PATH, 'save.png'))
- UNDO_ICON = wx.Image(os.path.join(PATH, 'undo.png'))
- REDO_ICON = wx.Image(os.path.join(PATH, 'redo.png'))
- COPY_ICON = wx.Image(os.path.join(PATH, 'copy.png'))
- PASTE_ICON = wx.Image(os.path.join(PATH, 'paste.png'))
- BOOKMARK_ICON = wx.Image(os.path.join(PATH, 'bookmark.png'))
- ZOOM_IN_ICON = wx.Image(os.path.join(PATH, 'zoom_in.png'))
- ZOOM_OUT_ICON = wx.Image(os.path.join(PATH, 'zoom_out.png'))
- ZOOM_ICON = wx.Image(os.path.join(PATH, 'search_pan.png'))
- DRAG_ICON = wx.Image(os.path.join(PATH, 'drag_hand.png'))
- RESET_ICON = wx.Image(os.path.join(PATH, 'reset.png'))
- REPORT_ICON = wx.Image(os.path.join(PATH, 'report.png'))
- PREVIEW_ICON = wx.Image(os.path.join(PATH, 'preview.png'))
- PRINT_ICON = wx.Image(os.path.join(PATH, 'printer.png'))
- HIDE_ICON = wx.Image(os.path.join(PATH, 'hide.png'))
-
-if __name__ == "__main__":
-
- print GUIFRAME.DEFAULT_STYLE
- print GUIFRAME.FLOATING_PANEL
- print GUIFRAME.SINGLE_APPLICATION
- style = GUIFRAME.MULTIPLE_APPLICATIONS
- style &= GUIFRAME.PLOTTING_ON
- print style == GUIFRAME.PLOTTING_ON
- style1 = GUIFRAME.MULTIPLE_APPLICATIONS
- style1 &= (~GUIFRAME.MANAGER_ON)
- print style1 == GUIFRAME.DEFAULT_STYLE
- print style1
\ No newline at end of file
+
+"""
+Provide the style for guiframe
+"""
+from __future__ import print_function
+
+import wx
+import os
+from sas.sasgui.guiframe import get_data_path
+
+
+class GUIFRAME:
+ MANAGER_ON = 1
+ FLOATING_PANEL = 2
+ FIXED_PANEL = 4
+ PLOTTING_ON = 8
+ DATALOADER_ON = 16
+ TOOLBAR_ON = 32
+ CALCULATOR_ON = 256
+ SINGLE_APPLICATION = 64
+ WELCOME_PANEL_ON = 128
+ DEFAULT_STYLE = SINGLE_APPLICATION|DATALOADER_ON|PLOTTING_ON|FIXED_PANEL
+ MULTIPLE_APPLICATIONS = DEFAULT_STYLE
+
+class GUIFRAME_ID:
+ UNDO_ID = wx.NewId()
+ REDO_ID = wx.NewId()
+ COPY_ID = wx.NewId()
+ PASTE_ID = wx.NewId()
+ BOOKMARK_ID = wx.NewId()
+ SAVE_ID = wx.NewId()
+ ZOOM_IN_ID = wx.NewId()
+ ZOOM_OUT_ID = wx.NewId()
+ ZOOM_ID = wx.NewId()
+ DRAG_ID = wx.NewId()
+ RESET_ID = wx.NewId()
+ PREVIEW_ID = wx.NewId()
+ PRINT_ID = wx.NewId()
+ CURRENT_APPLICATION = wx.NewId()
+ CURVE_SYMBOL_NUM = 13
+ COPYEX_ID = wx.NewId()
+ COPYLAT_ID = wx.NewId()
+ COPYAS_ID = wx.NewId()
+
+
+class GUIFRAME_ICON:
+ PATH = get_data_path(media='images')
+ FRAME_ICON_PATH = os.path.join(PATH, 'ball.ico')
+ SAVE_ICON_PATH = os.path.join(PATH, 'save.png')
+ UNDO_ICON_PATH = os.path.join(PATH, 'undo.png')
+ REDO_ICON_PATH = os.path.join(PATH, 'redo.png')
+ COPY_ICON_PATH = os.path.join(PATH, 'copy.png')
+ PASTE_ICON_PATH = os.path.join(PATH, 'paste.png')
+ BOOKMARK_ICON_PATH = os.path.join(PATH, 'bookmark.png')
+ ZOOM_IN_ID_PATH = os.path.join(PATH, 'zoom_in.png')
+ ZOOM_OUT_ID_PATH = os.path.join(PATH, 'zoom_out.png')
+ ZOOM_ID_PATH = os.path.join(PATH, 'search_pan.png')
+ DRAG_ID_PATH = os.path.join(PATH, 'drag_hand.png')
+ RESET_ID_PATH = os.path.join(PATH, 'reset.png')
+ PREVIEW_ID_PATH = os.path.join(PATH, 'report.png')
+ PRINT_ID_PATH = os.path.join(PATH, 'printer.png')
+ HIDE_ID_PATH = os.path.join(PATH, 'hide.png')
+
+
+ SAVE_ICON = wx.Image(os.path.join(PATH, 'save.png'))
+ UNDO_ICON = wx.Image(os.path.join(PATH, 'undo.png'))
+ REDO_ICON = wx.Image(os.path.join(PATH, 'redo.png'))
+ COPY_ICON = wx.Image(os.path.join(PATH, 'copy.png'))
+ PASTE_ICON = wx.Image(os.path.join(PATH, 'paste.png'))
+ BOOKMARK_ICON = wx.Image(os.path.join(PATH, 'bookmark.png'))
+ ZOOM_IN_ICON = wx.Image(os.path.join(PATH, 'zoom_in.png'))
+ ZOOM_OUT_ICON = wx.Image(os.path.join(PATH, 'zoom_out.png'))
+ ZOOM_ICON = wx.Image(os.path.join(PATH, 'search_pan.png'))
+ DRAG_ICON = wx.Image(os.path.join(PATH, 'drag_hand.png'))
+ RESET_ICON = wx.Image(os.path.join(PATH, 'reset.png'))
+ REPORT_ICON = wx.Image(os.path.join(PATH, 'report.png'))
+ PREVIEW_ICON = wx.Image(os.path.join(PATH, 'preview.png'))
+ PRINT_ICON = wx.Image(os.path.join(PATH, 'printer.png'))
+ HIDE_ICON = wx.Image(os.path.join(PATH, 'hide.png'))
+
+if __name__ == "__main__":
+
+ print(GUIFRAME.DEFAULT_STYLE)
+ print(GUIFRAME.FLOATING_PANEL)
+ print(GUIFRAME.SINGLE_APPLICATION)
+ style = GUIFRAME.MULTIPLE_APPLICATIONS
+ style &= GUIFRAME.PLOTTING_ON
+ print(style == GUIFRAME.PLOTTING_ON)
+ style1 = GUIFRAME.MULTIPLE_APPLICATIONS
+ style1 &= (~GUIFRAME.MANAGER_ON)
+ print(style1 == GUIFRAME.DEFAULT_STYLE)
+ print(style1)
\ No newline at end of file
diff --git a/src/sas/sasgui/guiframe/gui_toolbar.py b/src/sas/sasgui/guiframe/gui_toolbar.py
index 9685254..5dfb3c2 100644
--- a/src/sas/sasgui/guiframe/gui_toolbar.py
+++ b/src/sas/sasgui/guiframe/gui_toolbar.py
@@ -1,279 +1,279 @@
-
-import wx
-import os
-from wx import ToolBar as Tbar
-from wx.lib.platebtn import PlateButton
-from sas.sasgui.guiframe.gui_style import GUIFRAME_ID
-from sas.sasgui.guiframe.gui_style import GUIFRAME_ICON
-from wx.lib.platebtn import PB_STYLE_DEFAULT, PB_STYLE_DROPARROW,PB_STYLE_NOBG
-#Control panel width
-import sys
-if sys.platform.count("darwin")==0:
- FONT_VARIANT = 0
- NAME_BOX = wx.DefaultSize
- TB_H = 21
- IS_MAC = False
-else:
- FONT_VARIANT = 1
- NAME_BOX = (200, 25)
- TB_H = 25
- IS_MAC = True
-
-def clear_image(image):
- w, h = image.GetSize()
- factor = 155
- compress = lambda x: int(x * factor/255.) + factor
- for y in range(h):
- for x in range(w):
- grey = compress(image.GetGreen(x, y))
- image.SetRGB(x, y, grey, grey, grey)
- if image.HasAlpha():
- image.ConvertAlphaToMask()
- return image
-
-class GUIToolBar(Tbar):
- """
- Implement toolbar for guiframe
- """
- ID_BOOKMARK = wx.NewId()
- def __init__(self, parent, *args, **kwds):
- Tbar.__init__(self, parent, *args, **kwds)
- #Set window's font size
- self.SetWindowVariant(variant=FONT_VARIANT)
- self.parent = parent
- self._bookmark_menu = None
- self._bookmark_bt = None
- self.do_layout()
- self.on_bind_button()
-
- def do_layout(self):
- """
- """
- t_size = TB_H
- tbar_size = (t_size, t_size)
- button_type = wx.ITEM_NORMAL
-
- reset_im = GUIFRAME_ICON.RESET_ICON
- reset_im.Rescale(tbar_size[0], tbar_size[1], wx.IMAGE_QUALITY_HIGH)
- reset_bmp = reset_im.ConvertToBitmap()
- #disable_reset_bmp = clear_image(reset_im).ConvertToBitmap()
- disable_reset_bmp = wx.NullBitmap
- self.AddLabelTool(GUIFRAME_ID.RESET_ID, 'Reset', reset_bmp,
- disable_reset_bmp, button_type,'Reset')
- self.AddSeparator()
- save_im = GUIFRAME_ICON.SAVE_ICON
- save_im.Rescale(tbar_size[0], tbar_size[1], wx.IMAGE_QUALITY_HIGH)
- save_bmp = save_im.ConvertToBitmap()
- disable_save_bmp = wx.NullBitmap
- self.AddLabelTool(GUIFRAME_ID.SAVE_ID, 'Save', save_bmp,
- disable_save_bmp, button_type,'Save')
- self.AddSeparator()
- report_im = GUIFRAME_ICON.REPORT_ICON
- report_im.Rescale(tbar_size[0], tbar_size[1], wx.IMAGE_QUALITY_HIGH)
- report_bmp = report_im.ConvertToBitmap()
- #disable_report_bmp = clear_image(report_im).ConvertToBitmap()
- disable_report_bmp = wx.NullBitmap
- self.AddLabelTool(GUIFRAME_ID.PREVIEW_ID, 'Report', report_bmp,
- disable_report_bmp, button_type,'Report')
- self.AddSeparator()
- undo_im = GUIFRAME_ICON.UNDO_ICON
- undo_im.Rescale(tbar_size[0], tbar_size[1], wx.IMAGE_QUALITY_HIGH)
- undo_bmp = undo_im.ConvertToBitmap()
- disable_undo_bmp = wx.NullBitmap
- self.AddLabelTool(GUIFRAME_ID.UNDO_ID, 'Undo', undo_bmp,
- disable_undo_bmp, button_type,'Undo')
- self.AddSeparator()
- redo_im = GUIFRAME_ICON.REDO_ICON
- redo_im.Rescale(tbar_size[0], tbar_size[1], wx.IMAGE_QUALITY_HIGH)
- redo_bmp = redo_im.ConvertToBitmap()
- disable_redo_bmp = wx.NullBitmap
- self.AddLabelTool(GUIFRAME_ID.REDO_ID, 'Redo', redo_bmp,
- disable_redo_bmp, button_type,'Redo')
- self.AddSeparator()
- copy_im = GUIFRAME_ICON.COPY_ICON
- copy_im.Rescale(tbar_size[0], tbar_size[1], wx.IMAGE_QUALITY_HIGH)
- copy_bmp = copy_im.ConvertToBitmap()
- disable_copy_bmp = wx.NullBitmap
- self.AddLabelTool(GUIFRAME_ID.COPY_ID, 'Copy', copy_bmp,
- disable_copy_bmp, button_type,'Copy parameter values')
- self.AddSeparator()
- paste_im = GUIFRAME_ICON.PASTE_ICON
- paste_im.Rescale(tbar_size[0], tbar_size[1], wx.IMAGE_QUALITY_HIGH)
- paste_bmp = paste_im.ConvertToBitmap()
- disable_paste_bmp = wx.NullBitmap
- self.AddLabelTool(GUIFRAME_ID.PASTE_ID, 'Paste', paste_bmp,
- disable_paste_bmp, button_type,'Paste parameter values')
- self.AddSeparator()
- self._bookmark_bt = PlateButton(self, -1, 'Bookmarks',
- GUIFRAME_ICON.BOOKMARK_ICON.ConvertToBitmap(),
- style=PB_STYLE_DEFAULT|PB_STYLE_DROPARROW|PB_STYLE_NOBG)
- self._bookmark_bt.SetWindowVariant(FONT_VARIANT)
- self._bookmark_bt.Disable()
- self._bookmark_menu = wx.Menu()
- self.add_bookmark_default()
- self._bookmark_bt.SetMenu(self._bookmark_menu)
- self.AddControl(self._bookmark_bt)
- self.SetToolBitmapSize(tbar_size)
- self.AddSeparator()
- #add button for the panel on focus
- self.button_panel = wx.StaticText(self, -1, 'No Panel',
- pos=wx.DefaultPosition,
- size=NAME_BOX,
- style=wx.SUNKEN_BORDER|wx.ALIGN_LEFT)
- button_panel_font = self.button_panel.GetFont()
- button_panel_font.SetWeight(wx.BOLD)
- self.button_panel.SetFont(button_panel_font)
- hint = 'Control Panel on Focus'
- self.button_panel.SetToolTipString(hint)
- self.AddControl(self.button_panel)
- self.AddSeparator()
- self.Realize()
-
- def add_bookmark_default(self):
- """
- Add default items in bookmark menu
- """
- self._bookmark_menu.Append(self.ID_BOOKMARK, 'Bookmark This Page State')
- self._bookmark_menu.AppendSeparator()
- wx.EVT_MENU(self, self.ID_BOOKMARK, self.on_bookmark)
-
- def on_bind_button(self):
- """
- Bind the buttons
- """
- if self.parent is not None:
-
- self.parent.Bind(wx.EVT_TOOL, self.parent.on_redo_panel,
- id=GUIFRAME_ID.REDO_ID)
- self.parent.Bind(wx.EVT_TOOL, self.parent.on_undo_panel,
- id=GUIFRAME_ID.UNDO_ID)
- self.parent.Bind(wx.EVT_TOOL, self.parent.on_copy_panel,
- id=GUIFRAME_ID.COPY_ID)
- self.parent.Bind(wx.EVT_TOOL, self.parent.on_paste_panel,
- id=GUIFRAME_ID.PASTE_ID)
- self.parent.Bind(wx.EVT_TOOL, self.parent.on_reset_panel,
- id=GUIFRAME_ID.RESET_ID)
- self.parent.Bind(wx.EVT_TOOL, self.parent.on_save_panel,
- id=GUIFRAME_ID.SAVE_ID)
- self.parent.Bind(wx.EVT_TOOL, self.parent.on_preview_panel,
- id=GUIFRAME_ID.PREVIEW_ID)
- #self.parent.Bind(wx.EVT_TOOL, self.parent.on_print_panel,
- # id=GUIFRAME_ID.PRINT_ID)
-
- def update_button(self, application_name='', panel_name=''):
- """
- """
- #self.button_application.SetLabel(str(application_name))
- self.button_panel.SetLabel(str(panel_name))
- self.button_panel.SetToolTipString(str(panel_name))
-
- def update_toolbar(self, panel=None):
- """
- """
- if panel is None:
- #self.EnableTool(GUIFRAME_ID.PRINT_ID, False)
- self.EnableTool(GUIFRAME_ID.UNDO_ID,False)
- self.EnableTool(GUIFRAME_ID.REDO_ID, False)
- self.EnableTool(GUIFRAME_ID.COPY_ID,False)
- self.EnableTool(GUIFRAME_ID.PASTE_ID, False)
- self.EnableTool(GUIFRAME_ID.PREVIEW_ID, False)
- self.EnableTool(GUIFRAME_ID.RESET_ID, False)
- self.EnableTool(GUIFRAME_ID.SAVE_ID, False)
- self._bookmark_bt.Disable()
-
- else:
- #self.EnableTool(GUIFRAME_ID.PRINT_ID, panel.get_print_flag())
- self.EnableTool(GUIFRAME_ID.UNDO_ID, panel.get_undo_flag())
- self.EnableTool(GUIFRAME_ID.REDO_ID, panel.get_redo_flag())
- self.EnableTool(GUIFRAME_ID.COPY_ID, panel.get_copy_flag())
- self.EnableTool(GUIFRAME_ID.PASTE_ID, panel.get_paste_flag())
- self.EnableTool(GUIFRAME_ID.PREVIEW_ID, panel.get_preview_flag())
- self.EnableTool(GUIFRAME_ID.RESET_ID, panel.get_reset_flag())
- self.EnableTool(GUIFRAME_ID.SAVE_ID, panel.get_save_flag())
- self._bookmark_bt.Enable(panel.get_bookmark_flag())
- self.Realize()
-
- def enable_undo(self, panel):
- self.EnableTool(GUIFRAME_ID.UNDO_ID, panel.get_undo_flag())
- self.Realize()
-
- def enable_redo(self, panel):
- self.EnableTool(GUIFRAME_ID.REDO_ID, panel.get_redo_flag())
- self.Realize()
-
- def enable_copy(self, panel):
- self.EnableTool(GUIFRAME_ID.COPY_ID, panel.get_copy_flag())
- self.Realize()
-
- def enable_paste(self, panel):
- self.EnableTool(GUIFRAME_ID.PASTE_ID, panel.get_paste_flag())
- self.Realize()
-
- def enable_print(self, panel):
- self.EnableTool(GUIFRAME_ID.PRINT_ID, panel.get_print_flag())
- self.Realize()
-
- def enable_zoom(self, panel):
- self.EnableTool(GUIFRAME_ID.ZOOM_ID, panel.get_zoom_flag())
- self.Realize()
-
- def enable_zoom_in(self, panel):
- self.EnableTool(GUIFRAME_ID.ZOOM_IN_ID, panel.get_zoom_in_flag())
- self.Realize()
-
- def enable_zoom_out(self, panel):
- self.EnableTool(GUIFRAME_ID.ZOOM_OUT_ID, panel.get_zoom_out_flag())
- self.Realize()
-
- def enable_bookmark(self, panel):
- flag = panel.get_bookmark_flag()
- self._bookmark_bt.Enable(flag)
- self.Realize()
-
- def enable_save(self, panel):
- self.EnableTool(GUIFRAME_ID.SAVE_ID, panel.get_save_flag())
- self.Realize()
-
- def enable_reset(self, panel):
- self.EnableTool(GUIFRAME_ID.RESET_ID, panel.get_reset_flag())
- self.Realize()
-
- def enable_preview(self, panel):
- self.EnableTool(GUIFRAME_ID.PREVIEW_ID, panel.get_preview_flag())
- self.Realize()
-
- def on_bookmark(self, event):
- """
- add book mark
- """
- if self.parent is not None:
- self.parent.on_bookmark_panel(event)
-
- def append_bookmark(self, event):
- """
- receive item to append on the toolbar button bookmark
- """
- title = event.title
- hint = event.hint
- handler = event.handler
- id = wx.NewId()
- self._bookmark_menu.Append(id, str(title), str(hint))
- wx.EVT_MENU(self, id, handler)
-
- def remove_bookmark_item(self, item):
- """
- Remove a bookmark item
- """
- self._bookmark_menu.DestroyItem(item)
-
- def get_bookmark_items(self):
- """
- Get bookmark menu items
- """
- return self._bookmark_menu.GetMenuItems()
-
- def append_bookmark_item(self, id, label):
- """
- Append a item in bookmark
- """
- self._bookmark_menu.Append(id, label)
+
+import wx
+import os
+from wx import ToolBar as Tbar
+from wx.lib.platebtn import PlateButton
+from sas.sasgui.guiframe.gui_style import GUIFRAME_ID
+from sas.sasgui.guiframe.gui_style import GUIFRAME_ICON
+from wx.lib.platebtn import PB_STYLE_DEFAULT, PB_STYLE_DROPARROW,PB_STYLE_NOBG
+#Control panel width
+import sys
+if sys.platform.count("darwin")==0:
+ FONT_VARIANT = 0
+ NAME_BOX = wx.DefaultSize
+ TB_H = 21
+ IS_MAC = False
+else:
+ FONT_VARIANT = 1
+ NAME_BOX = (200, 25)
+ TB_H = 25
+ IS_MAC = True
+
+def clear_image(image):
+ w, h = image.GetSize()
+ factor = 155
+ compress = lambda x: int(x * factor/255.) + factor
+ for y in range(h):
+ for x in range(w):
+ grey = compress(image.GetGreen(x, y))
+ image.SetRGB(x, y, grey, grey, grey)
+ if image.HasAlpha():
+ image.ConvertAlphaToMask()
+ return image
+
+class GUIToolBar(Tbar):
+ """
+ Implement toolbar for guiframe
+ """
+ ID_BOOKMARK = wx.NewId()
+ def __init__(self, parent, *args, **kwds):
+ Tbar.__init__(self, parent, *args, **kwds)
+ #Set window's font size
+ self.SetWindowVariant(variant=FONT_VARIANT)
+ self.parent = parent
+ self._bookmark_menu = None
+ self._bookmark_bt = None
+ self.do_layout()
+ self.on_bind_button()
+
+ def do_layout(self):
+ """
+ """
+ t_size = TB_H
+ tbar_size = (t_size, t_size)
+ button_type = wx.ITEM_NORMAL
+
+ reset_im = GUIFRAME_ICON.RESET_ICON
+ reset_im.Rescale(tbar_size[0], tbar_size[1], wx.IMAGE_QUALITY_HIGH)
+ reset_bmp = reset_im.ConvertToBitmap()
+ #disable_reset_bmp = clear_image(reset_im).ConvertToBitmap()
+ disable_reset_bmp = wx.NullBitmap
+ self.AddLabelTool(GUIFRAME_ID.RESET_ID, 'Reset', reset_bmp,
+ disable_reset_bmp, button_type,'Reset')
+ self.AddSeparator()
+ save_im = GUIFRAME_ICON.SAVE_ICON
+ save_im.Rescale(tbar_size[0], tbar_size[1], wx.IMAGE_QUALITY_HIGH)
+ save_bmp = save_im.ConvertToBitmap()
+ disable_save_bmp = wx.NullBitmap
+ self.AddLabelTool(GUIFRAME_ID.SAVE_ID, 'Save', save_bmp,
+ disable_save_bmp, button_type,'Save')
+ self.AddSeparator()
+ report_im = GUIFRAME_ICON.REPORT_ICON
+ report_im.Rescale(tbar_size[0], tbar_size[1], wx.IMAGE_QUALITY_HIGH)
+ report_bmp = report_im.ConvertToBitmap()
+ #disable_report_bmp = clear_image(report_im).ConvertToBitmap()
+ disable_report_bmp = wx.NullBitmap
+ self.AddLabelTool(GUIFRAME_ID.PREVIEW_ID, 'Report', report_bmp,
+ disable_report_bmp, button_type,'Report')
+ self.AddSeparator()
+ undo_im = GUIFRAME_ICON.UNDO_ICON
+ undo_im.Rescale(tbar_size[0], tbar_size[1], wx.IMAGE_QUALITY_HIGH)
+ undo_bmp = undo_im.ConvertToBitmap()
+ disable_undo_bmp = wx.NullBitmap
+ self.AddLabelTool(GUIFRAME_ID.UNDO_ID, 'Undo', undo_bmp,
+ disable_undo_bmp, button_type,'Undo')
+ self.AddSeparator()
+ redo_im = GUIFRAME_ICON.REDO_ICON
+ redo_im.Rescale(tbar_size[0], tbar_size[1], wx.IMAGE_QUALITY_HIGH)
+ redo_bmp = redo_im.ConvertToBitmap()
+ disable_redo_bmp = wx.NullBitmap
+ self.AddLabelTool(GUIFRAME_ID.REDO_ID, 'Redo', redo_bmp,
+ disable_redo_bmp, button_type,'Redo')
+ self.AddSeparator()
+ copy_im = GUIFRAME_ICON.COPY_ICON
+ copy_im.Rescale(tbar_size[0], tbar_size[1], wx.IMAGE_QUALITY_HIGH)
+ copy_bmp = copy_im.ConvertToBitmap()
+ disable_copy_bmp = wx.NullBitmap
+ self.AddLabelTool(GUIFRAME_ID.COPY_ID, 'Copy', copy_bmp,
+ disable_copy_bmp, button_type,'Copy parameter values')
+ self.AddSeparator()
+ paste_im = GUIFRAME_ICON.PASTE_ICON
+ paste_im.Rescale(tbar_size[0], tbar_size[1], wx.IMAGE_QUALITY_HIGH)
+ paste_bmp = paste_im.ConvertToBitmap()
+ disable_paste_bmp = wx.NullBitmap
+ self.AddLabelTool(GUIFRAME_ID.PASTE_ID, 'Paste', paste_bmp,
+ disable_paste_bmp, button_type,'Paste parameter values')
+ self.AddSeparator()
+ self._bookmark_bt = PlateButton(self, -1, 'Bookmarks',
+ GUIFRAME_ICON.BOOKMARK_ICON.ConvertToBitmap(),
+ style=PB_STYLE_DEFAULT|PB_STYLE_DROPARROW|PB_STYLE_NOBG)
+ self._bookmark_bt.SetWindowVariant(FONT_VARIANT)
+ self._bookmark_bt.Disable()
+ self._bookmark_menu = wx.Menu()
+ self.add_bookmark_default()
+ self._bookmark_bt.SetMenu(self._bookmark_menu)
+ self.AddControl(self._bookmark_bt)
+ self.SetToolBitmapSize(tbar_size)
+ self.AddSeparator()
+ #add button for the panel on focus
+ self.button_panel = wx.StaticText(self, -1, 'No Panel',
+ pos=wx.DefaultPosition,
+ size=NAME_BOX,
+ style=wx.SUNKEN_BORDER|wx.ALIGN_LEFT)
+ button_panel_font = self.button_panel.GetFont()
+ button_panel_font.SetWeight(wx.BOLD)
+ self.button_panel.SetFont(button_panel_font)
+ hint = 'Control Panel on Focus'
+ self.button_panel.SetToolTipString(hint)
+ self.AddControl(self.button_panel)
+ self.AddSeparator()
+ self.Realize()
+
+ def add_bookmark_default(self):
+ """
+ Add default items in bookmark menu
+ """
+ self._bookmark_menu.Append(self.ID_BOOKMARK, 'Bookmark This Page State')
+ self._bookmark_menu.AppendSeparator()
+ wx.EVT_MENU(self, self.ID_BOOKMARK, self.on_bookmark)
+
+ def on_bind_button(self):
+ """
+ Bind the buttons
+ """
+ if self.parent is not None:
+
+ self.parent.Bind(wx.EVT_TOOL, self.parent.on_redo_panel,
+ id=GUIFRAME_ID.REDO_ID)
+ self.parent.Bind(wx.EVT_TOOL, self.parent.on_undo_panel,
+ id=GUIFRAME_ID.UNDO_ID)
+ self.parent.Bind(wx.EVT_TOOL, self.parent.on_copy_panel,
+ id=GUIFRAME_ID.COPY_ID)
+ self.parent.Bind(wx.EVT_TOOL, self.parent.on_paste_panel,
+ id=GUIFRAME_ID.PASTE_ID)
+ self.parent.Bind(wx.EVT_TOOL, self.parent.on_reset_panel,
+ id=GUIFRAME_ID.RESET_ID)
+ self.parent.Bind(wx.EVT_TOOL, self.parent.on_save_panel,
+ id=GUIFRAME_ID.SAVE_ID)
+ self.parent.Bind(wx.EVT_TOOL, self.parent.on_preview_panel,
+ id=GUIFRAME_ID.PREVIEW_ID)
+ #self.parent.Bind(wx.EVT_TOOL, self.parent.on_print_panel,
+ # id=GUIFRAME_ID.PRINT_ID)
+
+ def update_button(self, application_name='', panel_name=''):
+ """
+ """
+ #self.button_application.SetLabel(str(application_name))
+ self.button_panel.SetLabel(str(panel_name))
+ self.button_panel.SetToolTipString(str(panel_name))
+
+ def update_toolbar(self, panel=None):
+ """
+ """
+ if panel is None:
+ #self.EnableTool(GUIFRAME_ID.PRINT_ID, False)
+ self.EnableTool(GUIFRAME_ID.UNDO_ID,False)
+ self.EnableTool(GUIFRAME_ID.REDO_ID, False)
+ self.EnableTool(GUIFRAME_ID.COPY_ID,False)
+ self.EnableTool(GUIFRAME_ID.PASTE_ID, False)
+ self.EnableTool(GUIFRAME_ID.PREVIEW_ID, False)
+ self.EnableTool(GUIFRAME_ID.RESET_ID, False)
+ self.EnableTool(GUIFRAME_ID.SAVE_ID, False)
+ self._bookmark_bt.Disable()
+
+ else:
+ #self.EnableTool(GUIFRAME_ID.PRINT_ID, panel.get_print_flag())
+ self.EnableTool(GUIFRAME_ID.UNDO_ID, panel.get_undo_flag())
+ self.EnableTool(GUIFRAME_ID.REDO_ID, panel.get_redo_flag())
+ self.EnableTool(GUIFRAME_ID.COPY_ID, panel.get_copy_flag())
+ self.EnableTool(GUIFRAME_ID.PASTE_ID, panel.get_paste_flag())
+ self.EnableTool(GUIFRAME_ID.PREVIEW_ID, panel.get_preview_flag())
+ self.EnableTool(GUIFRAME_ID.RESET_ID, panel.get_reset_flag())
+ self.EnableTool(GUIFRAME_ID.SAVE_ID, panel.get_save_flag())
+ self._bookmark_bt.Enable(panel.get_bookmark_flag())
+ self.Realize()
+
+ def enable_undo(self, panel):
+ self.EnableTool(GUIFRAME_ID.UNDO_ID, panel.get_undo_flag())
+ self.Realize()
+
+ def enable_redo(self, panel):
+ self.EnableTool(GUIFRAME_ID.REDO_ID, panel.get_redo_flag())
+ self.Realize()
+
+ def enable_copy(self, panel):
+ self.EnableTool(GUIFRAME_ID.COPY_ID, panel.get_copy_flag())
+ self.Realize()
+
+ def enable_paste(self, panel):
+ self.EnableTool(GUIFRAME_ID.PASTE_ID, panel.get_paste_flag())
+ self.Realize()
+
+ def enable_print(self, panel):
+ self.EnableTool(GUIFRAME_ID.PRINT_ID, panel.get_print_flag())
+ self.Realize()
+
+ def enable_zoom(self, panel):
+ self.EnableTool(GUIFRAME_ID.ZOOM_ID, panel.get_zoom_flag())
+ self.Realize()
+
+ def enable_zoom_in(self, panel):
+ self.EnableTool(GUIFRAME_ID.ZOOM_IN_ID, panel.get_zoom_in_flag())
+ self.Realize()
+
+ def enable_zoom_out(self, panel):
+ self.EnableTool(GUIFRAME_ID.ZOOM_OUT_ID, panel.get_zoom_out_flag())
+ self.Realize()
+
+ def enable_bookmark(self, panel):
+ flag = panel.get_bookmark_flag()
+ self._bookmark_bt.Enable(flag)
+ self.Realize()
+
+ def enable_save(self, panel):
+ self.EnableTool(GUIFRAME_ID.SAVE_ID, panel.get_save_flag())
+ self.Realize()
+
+ def enable_reset(self, panel):
+ self.EnableTool(GUIFRAME_ID.RESET_ID, panel.get_reset_flag())
+ self.Realize()
+
+ def enable_preview(self, panel):
+ self.EnableTool(GUIFRAME_ID.PREVIEW_ID, panel.get_preview_flag())
+ self.Realize()
+
+ def on_bookmark(self, event):
+ """
+ add book mark
+ """
+ if self.parent is not None:
+ self.parent.on_bookmark_panel(event)
+
+ def append_bookmark(self, event):
+ """
+ receive item to append on the toolbar button bookmark
+ """
+ title = event.title
+ hint = event.hint
+ handler = event.handler
+ id = wx.NewId()
+ self._bookmark_menu.Append(id, str(title), str(hint))
+ wx.EVT_MENU(self, id, handler)
+
+ def remove_bookmark_item(self, item):
+ """
+ Remove a bookmark item
+ """
+ self._bookmark_menu.DestroyItem(item)
+
+ def get_bookmark_items(self):
+ """
+ Get bookmark menu items
+ """
+ return self._bookmark_menu.GetMenuItems()
+
+ def append_bookmark_item(self, id, label):
+ """
+ Append a item in bookmark
+ """
+ self._bookmark_menu.Append(id, label)
diff --git a/src/sas/sasgui/guiframe/images/angles.png b/src/sas/sasgui/guiframe/images/angles.png
deleted file mode 100644
index 085ac6f..0000000
Binary files a/src/sas/sasgui/guiframe/images/angles.png and /dev/null differ
diff --git a/src/sas/sasgui/guiframe/images/angles_flat.png b/src/sas/sasgui/guiframe/images/angles_flat.png
deleted file mode 100644
index 914e903..0000000
Binary files a/src/sas/sasgui/guiframe/images/angles_flat.png and /dev/null differ
diff --git a/src/sas/sasgui/guiframe/images/ansto_logo.png b/src/sas/sasgui/guiframe/images/ansto_logo.png
deleted file mode 100644
index 972382b..0000000
Binary files a/src/sas/sasgui/guiframe/images/ansto_logo.png and /dev/null differ
diff --git a/src/sas/sasgui/guiframe/images/danse_logo.png b/src/sas/sasgui/guiframe/images/danse_logo.png
deleted file mode 100644
index ae962d2..0000000
Binary files a/src/sas/sasgui/guiframe/images/danse_logo.png and /dev/null differ
diff --git a/src/sas/sasgui/guiframe/images/ess_logo.png b/src/sas/sasgui/guiframe/images/ess_logo.png
deleted file mode 100644
index 85c8ee8..0000000
Binary files a/src/sas/sasgui/guiframe/images/ess_logo.png and /dev/null differ
diff --git a/src/sas/sasgui/guiframe/images/ill_logo.png b/src/sas/sasgui/guiframe/images/ill_logo.png
deleted file mode 100644
index 765b430..0000000
Binary files a/src/sas/sasgui/guiframe/images/ill_logo.png and /dev/null differ
diff --git a/src/sas/sasgui/guiframe/images/isis_logo.png b/src/sas/sasgui/guiframe/images/isis_logo.png
deleted file mode 100644
index 1208d62..0000000
Binary files a/src/sas/sasgui/guiframe/images/isis_logo.png and /dev/null differ
diff --git a/src/sas/sasgui/guiframe/images/nist_logo.png b/src/sas/sasgui/guiframe/images/nist_logo.png
deleted file mode 100644
index 33b82b9..0000000
Binary files a/src/sas/sasgui/guiframe/images/nist_logo.png and /dev/null differ
diff --git a/src/sas/sasgui/guiframe/images/nsf_logo.png b/src/sas/sasgui/guiframe/images/nsf_logo.png
deleted file mode 100644
index f708d9c..0000000
Binary files a/src/sas/sasgui/guiframe/images/nsf_logo.png and /dev/null differ
diff --git a/src/sas/sasgui/guiframe/images/ornl_logo.png b/src/sas/sasgui/guiframe/images/ornl_logo.png
deleted file mode 100644
index 9522889..0000000
Binary files a/src/sas/sasgui/guiframe/images/ornl_logo.png and /dev/null differ
diff --git a/src/sas/sasgui/guiframe/images/sns_logo.png b/src/sas/sasgui/guiframe/images/sns_logo.png
deleted file mode 100644
index cfadef8..0000000
Binary files a/src/sas/sasgui/guiframe/images/sns_logo.png and /dev/null differ
diff --git a/src/sas/sasgui/guiframe/images/tudelft_logo.png b/src/sas/sasgui/guiframe/images/tudelft_logo.png
deleted file mode 100644
index 581c77c..0000000
Binary files a/src/sas/sasgui/guiframe/images/tudelft_logo.png and /dev/null differ
diff --git a/src/sas/sasgui/guiframe/images/umd_logo.png b/src/sas/sasgui/guiframe/images/umd_logo.png
deleted file mode 100644
index 6c6e0cc..0000000
Binary files a/src/sas/sasgui/guiframe/images/umd_logo.png and /dev/null differ
diff --git a/src/sas/sasgui/guiframe/images/utlogo.gif b/src/sas/sasgui/guiframe/images/utlogo.gif
deleted file mode 100644
index 073a93a..0000000
Binary files a/src/sas/sasgui/guiframe/images/utlogo.gif and /dev/null differ
diff --git a/src/sas/sasgui/guiframe/images/utlogo.png b/src/sas/sasgui/guiframe/images/utlogo.png
new file mode 100644
index 0000000..9514483
Binary files /dev/null and b/src/sas/sasgui/guiframe/images/utlogo.png differ
diff --git a/src/sas/sasgui/guiframe/local_perspectives/data_loader/__init__.py b/src/sas/sasgui/guiframe/local_perspectives/data_loader/__init__.py
index 8a765fd..70d2fd2 100644
--- a/src/sas/sasgui/guiframe/local_perspectives/data_loader/__init__.py
+++ b/src/sas/sasgui/guiframe/local_perspectives/data_loader/__init__.py
@@ -1,2 +1,2 @@
-PLUGIN_ID = "DataLoader plug-in 1.0"
-from sas.sasgui.guiframe.local_perspectives.data_loader import *
+PLUGIN_ID = "DataLoader plug-in 1.0"
+from sas.sasgui.guiframe.local_perspectives.data_loader import *
diff --git a/src/sas/sasgui/guiframe/local_perspectives/data_loader/data_loader.py b/src/sas/sasgui/guiframe/local_perspectives/data_loader/data_loader.py
index 6247b0d..c95699a 100644
--- a/src/sas/sasgui/guiframe/local_perspectives/data_loader/data_loader.py
+++ b/src/sas/sasgui/guiframe/local_perspectives/data_loader/data_loader.py
@@ -7,30 +7,19 @@ import sys
import wx
import logging
+logger = logging.getLogger(__name__)
+
+from sas import get_local_config
+
from sas.sascalc.dataloader.loader import Loader
+from sas.sascalc.dataloader.loader_exceptions import NoKnownLoaderException
+
from sas.sasgui.guiframe.plugin_base import PluginBase
from sas.sasgui.guiframe.events import StatusEvent
from sas.sasgui.guiframe.gui_style import GUIFRAME
from sas.sasgui.guiframe.gui_manager import DEFAULT_OPEN_FOLDER
-try:
- # Try to find a local config
- import imp
- path = os.getcwd()
- if(os.path.isfile("%s/%s.py" % (path, 'local_config'))) or \
- (os.path.isfile("%s/%s.pyc" % (path, 'local_config'))):
- fObj, path, descr = imp.find_module('local_config', [path])
- config = imp.load_module('local_config', fObj, path, descr)
- else:
- # Try simply importing local_config
- import local_config as config
-except:
- # Didn't find local config, load the default
- import sas.sasgui.guiframe.config as config
-
-if config is None:
- import sas.sasgui.guiframe.config as config
-
+config = get_local_config()
extension_list = []
if config.APPLICATION_STATE_EXTENSION is not None:
extension_list.append(config.APPLICATION_STATE_EXTENSION)
@@ -38,6 +27,7 @@ EXTENSIONS = config.PLUGIN_STATE_EXTENSIONS + extension_list
PLUGINS_WLIST = config.PLUGINS_WLIST
APPLICATION_WLIST = config.APPLICATION_WLIST
+
class Plugin(PluginBase):
def __init__(self):
@@ -53,12 +43,10 @@ class Plugin(PluginBase):
add load file menu item and load folder item
"""
# menu for data files
- menu_list = []
data_file_hint = "load one or more data in the application"
menu_list = [('&Load Data File(s)', data_file_hint, self.load_data)]
gui_style = self.parent.get_style()
style = gui_style & GUIFRAME.MULTIPLE_APPLICATIONS
- style1 = gui_style & GUIFRAME.DATALOADER_ON
if style == GUIFRAME.MULTIPLE_APPLICATIONS:
# menu for data from folder
data_folder_hint = "load multiple data in the application"
@@ -72,7 +60,7 @@ class Plugin(PluginBase):
"""
path = None
self._default_save_location = self.parent._default_save_location
- if self._default_save_location == None:
+ if self._default_save_location is None:
self._default_save_location = os.getcwd()
cards = self.loader.get_wildcards()
@@ -89,7 +77,7 @@ class Plugin(PluginBase):
style=style)
if dlg.ShowModal() == wx.ID_OK:
file_list = dlg.GetPaths()
- if len(file_list) >= 0 and not file_list[0] is None:
+ if len(file_list) >= 0 and file_list[0] is not None:
self._default_save_location = os.path.dirname(file_list[0])
path = self._default_save_location
dlg.Destroy()
@@ -99,21 +87,19 @@ class Plugin(PluginBase):
self.parent._default_save_location = self._default_save_location
self.get_data(file_list)
-
def can_load_data(self):
"""
if return True, then call handler to laod data
"""
return True
-
def _load_folder(self, event):
"""
Load entire folder
"""
path = None
self._default_save_location = self.parent._default_save_location
- if self._default_save_location == None:
+ if self._default_save_location is None:
self._default_save_location = os.getcwd()
dlg = wx.DirDialog(self.parent, "Choose a directory",
self._default_save_location,
@@ -137,7 +123,8 @@ class Plugin(PluginBase):
:param error: details error message to be displayed
"""
if error is not None or str(error).strip() != "":
- dial = wx.MessageDialog(self.parent, str(error), 'Error Loading File',
+ dial = wx.MessageDialog(self.parent, str(error),
+ 'Error Loading File',
wx.OK | wx.ICON_EXCLAMATION)
dial.ShowModal()
@@ -146,7 +133,8 @@ class Plugin(PluginBase):
Receive a list containing folder then return a list of file
"""
if os.path.isdir(path):
- return [os.path.join(os.path.abspath(path), filename) for filename in os.listdir(path)]
+ return [os.path.join(os.path.abspath(path), filename) for filename
+ in os.listdir(path)]
def _process_data_and_errors(self, item, p_file, output, message):
"""
@@ -159,7 +147,7 @@ class Plugin(PluginBase):
data_error = True
message += "\tError: {0}\n".format(error_data)
else:
- logging.error("Loader returned an invalid object:\n %s" % str(item))
+ logger.error("Loader returned an invalid object:\n %s" % str(item))
data_error = True
data = self.parent.create_gui_data(item, p_file)
@@ -175,13 +163,22 @@ class Plugin(PluginBase):
for p_file in path:
basename = os.path.basename(p_file)
+ # Skip files that start with a period
+ if basename.startswith("."):
+ msg = "The folder included a potential hidden file - %s." \
+ % basename
+ msg += " Do you wish to load this file as data?"
+ msg_box = wx.MessageDialog(None, msg, 'Warning',
+ wx.OK | wx.CANCEL)
+ if msg_box.ShowModal() == wx.ID_CANCEL:
+ continue
_, extension = os.path.splitext(basename)
if extension.lower() in EXTENSIONS:
log_msg = "Data Loader cannot "
log_msg += "load: {}\n".format(str(p_file))
log_msg += "Please try to open that file from \"open project\""
log_msg += "or \"open analysis\" menu."
- logging.info(log_msg)
+ logger.info(log_msg)
file_errors[basename] = [log_msg]
continue
@@ -210,17 +207,24 @@ class Plugin(PluginBase):
message="Loaded {}\n".format(p_file),
info="info")
- except:
- logging.error(sys.exc_value)
+ except NoKnownLoaderException as e:
+ exception_occurred = True
+ logger.error(e.message)
+
+ error_message = "Loading data failed!\n" + e.message
+ self.load_update(output=None, message=e.message, info="warning")
+
+ except Exception as e:
+ exception_occurred = True
+ logger.error(e.message)
- error_message = "The Data file you selected could not be loaded.\n"
- error_message += "Make sure the content of your file"
- error_message += " is properly formatted.\n"
- error_message += "When contacting the SasView team, mention the"
- error_message += " following:\n"
- error_message += "Error: " + str(sys.exc_info()[1])
- file_errors[basename] = [error_message]
- self.load_update(output=output, message=error_message, info="warning")
+ file_err = "The Data file you selected could not be "
+ file_err += "loaded.\nMake sure the content of your file"
+ file_err += " is properly formatted.\n"
+ file_err += "When contacting the SasView team, mention the"
+ file_err += " following:\n"
+ file_err += e.message
+ file_errors[basename] = [file_err]
if len(file_errors) > 0:
error_message = ""
@@ -230,10 +234,15 @@ class Plugin(PluginBase):
for message in error_array:
error_message += message + "\n"
error_message += "\n"
- self.load_update(output=output, message=error_message, info="error")
+ if not exception_occurred: # Some data loaded but with errors
+ self.load_update(output=output, message=error_message, info="error")
+
+ if not exception_occurred: # Everything loaded as expected
+ self.load_complete(output=output, message="Loading data complete!",
+ info="info")
+ else:
+ self.load_complete(output=None, message=error_message, info="error")
- self.load_complete(output=output, message="Loading data complete!",
- info="info")
def load_update(self, output=None, message="", info="warning"):
"""
@@ -242,14 +251,12 @@ class Plugin(PluginBase):
if message != "":
wx.PostEvent(self.parent, StatusEvent(status=message, info=info,
type="progress"))
- def load_complete(self, output, message="", error_message="", path=None,
- info="warning"):
+
+ def load_complete(self, output, message="", info="warning"):
"""
- post message to status bar and return list of data
+ post message to status bar and return list of data
"""
- wx.PostEvent(self.parent, StatusEvent(status=message,
- info=info,
+ wx.PostEvent(self.parent, StatusEvent(status=message, info=info,
type="stop"))
- # if error_message != "":
- # self.load_error(error_message)
- self.parent.add_data(data_list=output)
+ if output is not None:
+ self.parent.add_data(data_list=output)
diff --git a/src/sas/sasgui/guiframe/local_perspectives/data_loader/load_thread.py b/src/sas/sasgui/guiframe/local_perspectives/data_loader/load_thread.py
index 4c03ac1..5994915 100644
--- a/src/sas/sasgui/guiframe/local_perspectives/data_loader/load_thread.py
+++ b/src/sas/sasgui/guiframe/local_perspectives/data_loader/load_thread.py
@@ -1,81 +1,81 @@
-"""
- Loading thread
-"""
-import time
-import sys
-import os
-
-from sas.sascalc.data_util.calcthread import CalcThread
-
-
-EXTENSIONS = ['.svs', '.prv', '.inv', '.fitv']
-
-class DataReader(CalcThread):
- """
- Load a data given a filename
- """
- def __init__(self, path, loader,
- flag=True,
- transform_data=None,
- completefn=None,
- updatefn=None,
- yieldtime=0.01,
- worktime=0.01):
- CalcThread.__init__(self, completefn,
- updatefn,
- yieldtime,
- worktime)
- self.load_state_flag = flag
- self.transform_data = transform_data
- self.list_path = path
- # Instantiate a loader
- self.loader = loader
- self.message = ""
- self.starttime = 0
- self.updatefn = updatefn
-
- def isquit(self):
- """
- :raise KeyboardInterrupt: when the thread is interrupted
- """
- try:
- CalcThread.isquit(self)
- except KeyboardInterrupt:
- raise KeyboardInterrupt
-
- def compute(self):
- """
- read some data
- """
- self.starttime = time.time()
- output = []
- error_message = ""
- for path in self.list_path:
- basename = os.path.basename(path)
- _, extension = os.path.splitext(basename)
- if self.load_state_flag:
- if extension.lower() in EXTENSIONS:
- pass
- else:
- if extension.lower() not in EXTENSIONS:
- pass
- try:
- temp = self.loader.load(path)
- if temp.__class__.__name__ == "list":
- for item in temp:
- data = self.transform_data(item, path)
- output.append(data)
- else:
- data = self.transform_data(temp, path)
- output.append(data)
- message = "Loading ..." + str(path) + "\n"
- if self.updatefn is not None:
- self.updatefn(output=output, message=message)
- except:
- error_message = "Error while loading: %s\n" % str(path)
- error_message += str(sys.exc_value) + "\n"
- self.updatefn(output=output, message=error_message)
-
- message = "Loading Complete!"
- self.complete(output=output, error_message=error_message,
- message=message, path=self.list_path)
+"""
+ Loading thread
+"""
+import time
+import sys
+import os
+
+from sas.sascalc.data_util.calcthread import CalcThread
+
+
+EXTENSIONS = ['.svs', '.prv', '.inv', '.fitv']
+
+class DataReader(CalcThread):
+ """
+ Load a data given a filename
+ """
+ def __init__(self, path, loader,
+ flag=True,
+ transform_data=None,
+ completefn=None,
+ updatefn=None,
+ yieldtime=0.01,
+ worktime=0.01):
+ CalcThread.__init__(self, completefn,
+ updatefn,
+ yieldtime,
+ worktime)
+ self.load_state_flag = flag
+ self.transform_data = transform_data
+ self.list_path = path
+ # Instantiate a loader
+ self.loader = loader
+ self.message = ""
+ self.starttime = 0
+ self.updatefn = updatefn
+
+ def isquit(self):
+ """
+ :raise KeyboardInterrupt: when the thread is interrupted
+ """
+ try:
+ CalcThread.isquit(self)
+ except KeyboardInterrupt:
+ raise KeyboardInterrupt
+
+ def compute(self):
+ """
+ read some data
+ """
+ self.starttime = time.time()
+ output = []
+ error_message = ""
+ for path in self.list_path:
+ basename = os.path.basename(path)
+ _, extension = os.path.splitext(basename)
+ if self.load_state_flag:
+ if extension.lower() in EXTENSIONS:
+ pass
+ else:
+ if extension.lower() not in EXTENSIONS:
+ pass
+ try:
+ temp = self.loader.load(path)
+ if temp.__class__.__name__ == "list":
+ for item in temp:
+ data = self.transform_data(item, path)
+ output.append(data)
+ else:
+ data = self.transform_data(temp, path)
+ output.append(data)
+ message = "Loading ..." + str(path) + "\n"
+ if self.updatefn is not None:
+ self.updatefn(output=output, message=message)
+ except:
+ error_message = "Error while loading: %s\n" % str(path)
+ error_message += str(sys.exc_value) + "\n"
+ self.updatefn(output=output, message=error_message)
+
+ message = "Loading Complete!"
+ self.complete(output=output, error_message=error_message,
+ message=message, path=self.list_path)
diff --git a/src/sas/sasgui/guiframe/local_perspectives/plotting/AnnulusSlicer.py b/src/sas/sasgui/guiframe/local_perspectives/plotting/AnnulusSlicer.py
index e705cf6..22d5b8a 100644
--- a/src/sas/sasgui/guiframe/local_perspectives/plotting/AnnulusSlicer.py
+++ b/src/sas/sasgui/guiframe/local_perspectives/plotting/AnnulusSlicer.py
@@ -121,7 +121,7 @@ class AnnulusInteractor(_BaseInteractor):
# Data to average
data = self.base.data2D
# If we have no data, just return
- if data == None:
+ if data is None:
return
from sas.sascalc.dataloader.manipulations import Ring
@@ -131,7 +131,7 @@ class AnnulusInteractor(_BaseInteractor):
math.fabs(self.outer_circle.get_radius()))
# if the user does not specify the numbers of points to plot
# the default number will be nbins= 36
- if nbins == None:
+ if nbins is None:
self.nbins = 36
else:
self.nbins = nbins
@@ -497,7 +497,7 @@ class CircularMask(_BaseInteractor):
"""
# Update locations
self.outer_circle.update()
- # if self.is_inside != None:
+ # if self.is_inside is not None:
out = self._post_data()
return out
@@ -520,7 +520,7 @@ class CircularMask(_BaseInteractor):
data = self.base.data
# If we have no data, just return
- if data == None:
+ if data is None:
return
mask = data.mask
from sas.sascalc.dataloader.manipulations import Ringcut
diff --git a/src/sas/sasgui/guiframe/local_perspectives/plotting/Arc.py b/src/sas/sasgui/guiframe/local_perspectives/plotting/Arc.py
index 017da31..4697075 100644
--- a/src/sas/sasgui/guiframe/local_perspectives/plotting/Arc.py
+++ b/src/sas/sasgui/guiframe/local_perspectives/plotting/Arc.py
@@ -1,161 +1,161 @@
-"""
- Arc slicer for 2D data
-"""
-import math
-
-from BaseInteractor import _BaseInteractor
-from sas.sasgui.guiframe.events import SlicerParameterEvent
-
-class ArcInteractor(_BaseInteractor):
- """
- Select an annulus through a 2D plot
- """
- def __init__(self, base, axes, color='black', zorder=5, r=1.0,
- theta1=math.pi / 8, theta2=math.pi / 4):
- _BaseInteractor.__init__(self, base, axes, color=color)
- self.markers = []
- self.axes = axes
- self._mouse_x = r
- self._mouse_y = 0
- self._save_x = r
- self._save_y = 0
- self.scale = 10.0
- self.theta1 = theta1
- self.theta2 = theta2
- self.radius = r
- [self.arc] = self.axes.plot([], [], linestyle='-', marker='', color=self.color)
- self.npts = 20
- self.has_move = False
- self.connect_markers([self.arc])
- self.update()
-
- def set_layer(self, n):
- """
- Allow adding plot to the same panel
- :param n: the number of layer
- """
- self.layernum = n
- self.update()
-
- def clear(self):
- """
- Clear this slicer and its markers
- """
- self.clear_markers()
- try:
- for item in self.markers:
- item.remove()
- self.arc.remove()
- except:
- # Old version of matplotlib
- for item in range(len(self.axes.lines)):
- del self.axes.lines[0]
-
- def get_radius(self):
- """
- Return arc radius
- """
- radius = math.sqrt(math.pow(self._mouse_x, 2) + \
- math.pow(self._mouse_y, 2))
- return radius
-
- def update(self, theta1=None, theta2=None, nbins=None, r=None):
- """
- Update the plotted arc
- :param theta1: starting angle of the arc
- :param theta2: ending angle of the arc
- :param nbins: number of points along the arc
- :param r: radius of the arc
- """
- # Plot inner circle
- x = []
- y = []
- if theta1 != None:
- self.theta1 = theta1
- if theta2 != None:
- self.theta2 = theta2
- while self.theta2 < self.theta1:
- self.theta2 += (2 * math.pi)
- while self.theta2 >= (self.theta1 + 2 * math.pi):
- self.theta2 -= (2 * math.pi)
- npts = int((self.theta2 - self.theta1) / (math.pi / 120))
-
- if r == None:
- self.radius = math.sqrt(math.pow(self._mouse_x, 2) + \
- math.pow(self._mouse_y, 2))
- else:
- self.radius = r
- for i in range(self.npts):
- phi = (self.theta2 - self.theta1) / (self.npts - 1) * i + self.theta1
- xval = 1.0 * self.radius * math.cos(phi)
- yval = 1.0 * self.radius * math.sin(phi)
-
- x.append(xval)
- y.append(yval)
- # self.marker.set(xdata=[self._mouse_x],ydata=[0])
- self.arc.set_data(x, y)
-
- def save(self, ev):
- """
- Remember the roughness for this layer and the next so that we
- can restore on Esc.
- """
- self._save_x = self._mouse_x
- self._save_y = self._mouse_y
- # self._save_x = ev.xdata
- # self._save_y = ev.ydata
- self.base.freeze_axes()
-
- def moveend(self, ev):
- """
- After a dragging motion reset the flag self.has_move to False
- :param ev: event
- """
- self.has_move = False
-
- event = SlicerParameterEvent()
- event.type = self.__class__.__name__
- event.params = self.get_params()
- self.base.moveend(ev)
-
- def restore(self):
- """
- Restore the roughness for this layer.
- """
- self._mouse_x = self._save_x
- self._mouse_y = self._save_y
-
- def move(self, x, y, ev):
- """
- Process move to a new position, making sure that the move is allowed.
- """
- # print "ring move x, y", x,y
- self._mouse_x = x
- self._mouse_y = y
- self.has_move = True
- self.base.base.update()
-
- def set_cursor(self, radius, phi_min, phi_max, nbins):
- """
- """
- self.theta1 = phi_min
- self.theta2 = phi_max
- self.update(nbins=nbins, r=radius)
-
- def get_params(self):
- """
- """
- params = {}
- params["radius"] = self.radius
- params["theta1"] = self.theta1
- params["theta2"] = self.theta2
- return params
-
- def set_params(self, params):
- """
- """
- x = params["radius"]
- phi_max = self.theta2
- nbins = self.npts
- self.set_cursor(x, self._mouse_y, phi_max, nbins)
-
+"""
+ Arc slicer for 2D data
+"""
+import math
+
+from BaseInteractor import _BaseInteractor
+from sas.sasgui.guiframe.events import SlicerParameterEvent
+
+class ArcInteractor(_BaseInteractor):
+ """
+ Select an annulus through a 2D plot
+ """
+ def __init__(self, base, axes, color='black', zorder=5, r=1.0,
+ theta1=math.pi / 8, theta2=math.pi / 4):
+ _BaseInteractor.__init__(self, base, axes, color=color)
+ self.markers = []
+ self.axes = axes
+ self._mouse_x = r
+ self._mouse_y = 0
+ self._save_x = r
+ self._save_y = 0
+ self.scale = 10.0
+ self.theta1 = theta1
+ self.theta2 = theta2
+ self.radius = r
+ [self.arc] = self.axes.plot([], [], linestyle='-', marker='', color=self.color)
+ self.npts = 20
+ self.has_move = False
+ self.connect_markers([self.arc])
+ self.update()
+
+ def set_layer(self, n):
+ """
+ Allow adding plot to the same panel
+ :param n: the number of layer
+ """
+ self.layernum = n
+ self.update()
+
+ def clear(self):
+ """
+ Clear this slicer and its markers
+ """
+ self.clear_markers()
+ try:
+ for item in self.markers:
+ item.remove()
+ self.arc.remove()
+ except:
+ # Old version of matplotlib
+ for item in range(len(self.axes.lines)):
+ del self.axes.lines[0]
+
+ def get_radius(self):
+ """
+ Return arc radius
+ """
+ radius = math.sqrt(math.pow(self._mouse_x, 2) + \
+ math.pow(self._mouse_y, 2))
+ return radius
+
+ def update(self, theta1=None, theta2=None, nbins=None, r=None):
+ """
+ Update the plotted arc
+ :param theta1: starting angle of the arc
+ :param theta2: ending angle of the arc
+ :param nbins: number of points along the arc
+ :param r: radius of the arc
+ """
+ # Plot inner circle
+ x = []
+ y = []
+ if theta1 is not None:
+ self.theta1 = theta1
+ if theta2 is not None:
+ self.theta2 = theta2
+ while self.theta2 < self.theta1:
+ self.theta2 += (2 * math.pi)
+ while self.theta2 >= (self.theta1 + 2 * math.pi):
+ self.theta2 -= (2 * math.pi)
+ npts = int((self.theta2 - self.theta1) / (math.pi / 120))
+
+ if r is None:
+ self.radius = math.sqrt(math.pow(self._mouse_x, 2) + \
+ math.pow(self._mouse_y, 2))
+ else:
+ self.radius = r
+ for i in range(self.npts):
+ phi = (self.theta2 - self.theta1) / (self.npts - 1) * i + self.theta1
+ xval = 1.0 * self.radius * math.cos(phi)
+ yval = 1.0 * self.radius * math.sin(phi)
+
+ x.append(xval)
+ y.append(yval)
+ # self.marker.set(xdata=[self._mouse_x],ydata=[0])
+ self.arc.set_data(x, y)
+
+ def save(self, ev):
+ """
+ Remember the roughness for this layer and the next so that we
+ can restore on Esc.
+ """
+ self._save_x = self._mouse_x
+ self._save_y = self._mouse_y
+ # self._save_x = ev.xdata
+ # self._save_y = ev.ydata
+ self.base.freeze_axes()
+
+ def moveend(self, ev):
+ """
+ After a dragging motion reset the flag self.has_move to False
+ :param ev: event
+ """
+ self.has_move = False
+
+ event = SlicerParameterEvent()
+ event.type = self.__class__.__name__
+ event.params = self.get_params()
+ self.base.moveend(ev)
+
+ def restore(self):
+ """
+ Restore the roughness for this layer.
+ """
+ self._mouse_x = self._save_x
+ self._mouse_y = self._save_y
+
+ def move(self, x, y, ev):
+ """
+ Process move to a new position, making sure that the move is allowed.
+ """
+ # print "ring move x, y", x,y
+ self._mouse_x = x
+ self._mouse_y = y
+ self.has_move = True
+ self.base.base.update()
+
+ def set_cursor(self, radius, phi_min, phi_max, nbins):
+ """
+ """
+ self.theta1 = phi_min
+ self.theta2 = phi_max
+ self.update(nbins=nbins, r=radius)
+
+ def get_params(self):
+ """
+ """
+ params = {}
+ params["radius"] = self.radius
+ params["theta1"] = self.theta1
+ params["theta2"] = self.theta2
+ return params
+
+ def set_params(self, params):
+ """
+ """
+ x = params["radius"]
+ phi_max = self.theta2
+ nbins = self.npts
+ self.set_cursor(x, self._mouse_y, phi_max, nbins)
+
diff --git a/src/sas/sasgui/guiframe/local_perspectives/plotting/BaseInteractor.py b/src/sas/sasgui/guiframe/local_perspectives/plotting/BaseInteractor.py
index 3b0abfc..315988f 100644
--- a/src/sas/sasgui/guiframe/local_perspectives/plotting/BaseInteractor.py
+++ b/src/sas/sasgui/guiframe/local_perspectives/plotting/BaseInteractor.py
@@ -1,180 +1,180 @@
-interface_color = 'black'
-disable_color = 'gray'
-active_color = 'red'
-rho_color = 'black'
-mu_color = 'green'
-P_color = 'blue'
-theta_color = 'orange'
-profile_colors = [rho_color, mu_color, P_color, theta_color]
-
-class _BaseInteractor(object):
- """
- Share some functions between the interface interactor and various layer
- interactors.
-
- Individual interactors need the following functions:
-
- save(ev) - save the current state for later restore
- restore() - restore the old state
- move(x,y,ev) - move the interactor to position x,y
- moveend(ev) - end the drag event
- update() - draw the interactors
-
- The following are provided by the base class:
-
- connect_markers(markers) - register callbacks for all markers
- clear_markers() - remove all items in self.markers
- onHilite(ev) - enter/leave event processing
- onLeave(ev) - enter/leave event processing
- onClick(ev) - mouse click: calls save()
- onRelease(ev) - mouse click ends: calls moveend()
- onDrag(ev) - mouse move: calls move() or restore()
- onKey(ev) - keyboard move: calls move() or restore()
-
- Interactor attributes:
-
- base - model we are operating on
- axes - axes holding the interactor
- color - color of the interactor in non-active state
- markers - list of handles for the interactor
-
- """
- def __init__(self, base, axes, color='black'):
- """
- """
- self.base = base
- self.axes = axes
- self.color = color
- self.clickx = None
- self.clicky = None
- self.markers = []
-
- def clear_markers(self):
- """
- Clear old markers and interfaces.
- """
- for h in self.markers: h.remove()
- if self.markers:
- self.base.connect.clear(*self.markers)
- self.markers = []
-
- def save(self, ev):
- """
- """
- pass
-
- def restore(self, ev):
- """
- """
- pass
-
- def move(self, x, y, ev):
- """
- """
- pass
-
- def moveend(self, ev):
- """
- """
- pass
-
- def connect_markers(self, markers):
- """
- Connect markers to callbacks
- """
-
- for h in markers:
- connect = self.base.connect
- connect('enter', h, self.onHilite)
- connect('leave', h, self.onLeave)
- connect('click', h, self.onClick)
- connect('release', h, self.onRelease)
- connect('drag', h, self.onDrag)
- connect('key', h, self.onKey)
-
- def onHilite(self, ev):
- """
- Hilite the artist reporting the event, indicating that it is
- ready to receive a click.
- """
- ev.artist.set_color(active_color)
- self.base.draw()
- return True
-
- def onLeave(self, ev):
- """
- Restore the artist to the original colour when the cursor leaves.
- """
- ev.artist.set_color(self.color)
- self.base.draw()
- return True
-
- def onClick(self, ev):
- """
- Prepare to move the artist. Calls save() to preserve the state for
- later restore().
- """
- self.clickx, self.clicky = ev.xdata, ev.ydata
- self.save(ev)
- return True
-
- def onRelease(self, ev):
- """
- """
- self.moveend(ev)
- return True
-
- def onDrag(self, ev):
- """
- Move the artist. Calls move() to update the state, or restore() if
- the mouse leaves the window.
- """
- inside, _ = self.axes.contains(ev)
- if inside:
- self.clickx, self.clicky = ev.xdata, ev.ydata
- self.move(ev.xdata, ev.ydata, ev)
- else:
- self.restore()
- self.base.update()
- return True
-
- def onKey(self, ev):
- """
- Respond to keyboard events. Arrow keys move the widget. Escape
- restores it to the position before the last click.
-
- Calls move() to update the state. Calls restore() on escape.
- """
- if ev.key == 'escape':
- self.restore()
- elif ev.key in ['up', 'down', 'right', 'left']:
- dx, dy = self.dpixel(self.clickx, self.clicky, nudge=ev.control)
- if ev.key == 'up':
- self.clicky += dy
- elif ev.key == 'down':
- self.clicky -= dy
- elif ev.key == 'right':
- self.clickx += dx
- else: self.clickx -= dx
- self.move(self.clickx, self.clicky, ev)
- else:
- return False
- self.base.update()
- return True
-
- def dpixel(self, x, y, nudge=False):
- """
- Return the step size in data coordinates for a small
- step in screen coordinates. If nudge is False (default)
- the step size is one pixel. If nudge is True, the step
- size is 0.2 pixels.
- """
- ax = self.axes
- px, py = ax.transData.inverse_xy_tup((x, y))
- if nudge:
- nx, ny = ax.transData.xy_tup((px + 0.2, py + 0.2))
- else:
- nx, ny = ax.transData.xy_tup((px + 1.0, py + 1.0))
- dx, dy = nx - x, ny - y
- return dx, dy
-
+interface_color = 'black'
+disable_color = 'gray'
+active_color = 'red'
+rho_color = 'black'
+mu_color = 'green'
+P_color = 'blue'
+theta_color = 'orange'
+profile_colors = [rho_color, mu_color, P_color, theta_color]
+
+class _BaseInteractor(object):
+ """
+ Share some functions between the interface interactor and various layer
+ interactors.
+
+ Individual interactors need the following functions:
+
+ save(ev) - save the current state for later restore
+ restore() - restore the old state
+ move(x,y,ev) - move the interactor to position x,y
+ moveend(ev) - end the drag event
+ update() - draw the interactors
+
+ The following are provided by the base class:
+
+ connect_markers(markers) - register callbacks for all markers
+ clear_markers() - remove all items in self.markers
+ onHilite(ev) - enter/leave event processing
+ onLeave(ev) - enter/leave event processing
+ onClick(ev) - mouse click: calls save()
+ onRelease(ev) - mouse click ends: calls moveend()
+ onDrag(ev) - mouse move: calls move() or restore()
+ onKey(ev) - keyboard move: calls move() or restore()
+
+ Interactor attributes:
+
+ base - model we are operating on
+ axes - axes holding the interactor
+ color - color of the interactor in non-active state
+ markers - list of handles for the interactor
+
+ """
+ def __init__(self, base, axes, color='black'):
+ """
+ """
+ self.base = base
+ self.axes = axes
+ self.color = color
+ self.clickx = None
+ self.clicky = None
+ self.markers = []
+
+ def clear_markers(self):
+ """
+ Clear old markers and interfaces.
+ """
+ for h in self.markers: h.remove()
+ if self.markers:
+ self.base.connect.clear(*self.markers)
+ self.markers = []
+
+ def save(self, ev):
+ """
+ """
+ pass
+
+ def restore(self, ev):
+ """
+ """
+ pass
+
+ def move(self, x, y, ev):
+ """
+ """
+ pass
+
+ def moveend(self, ev):
+ """
+ """
+ pass
+
+ def connect_markers(self, markers):
+ """
+ Connect markers to callbacks
+ """
+
+ for h in markers:
+ connect = self.base.connect
+ connect('enter', h, self.onHilite)
+ connect('leave', h, self.onLeave)
+ connect('click', h, self.onClick)
+ connect('release', h, self.onRelease)
+ connect('drag', h, self.onDrag)
+ connect('key', h, self.onKey)
+
+ def onHilite(self, ev):
+ """
+ Hilite the artist reporting the event, indicating that it is
+ ready to receive a click.
+ """
+ ev.artist.set_color(active_color)
+ self.base.draw()
+ return True
+
+ def onLeave(self, ev):
+ """
+ Restore the artist to the original colour when the cursor leaves.
+ """
+ ev.artist.set_color(self.color)
+ self.base.draw()
+ return True
+
+ def onClick(self, ev):
+ """
+ Prepare to move the artist. Calls save() to preserve the state for
+ later restore().
+ """
+ self.clickx, self.clicky = ev.xdata, ev.ydata
+ self.save(ev)
+ return True
+
+ def onRelease(self, ev):
+ """
+ """
+ self.moveend(ev)
+ return True
+
+ def onDrag(self, ev):
+ """
+ Move the artist. Calls move() to update the state, or restore() if
+ the mouse leaves the window.
+ """
+ inside, _ = self.axes.contains(ev)
+ if inside:
+ self.clickx, self.clicky = ev.xdata, ev.ydata
+ self.move(ev.xdata, ev.ydata, ev)
+ else:
+ self.restore()
+ self.base.update()
+ return True
+
+ def onKey(self, ev):
+ """
+ Respond to keyboard events. Arrow keys move the widget. Escape
+ restores it to the position before the last click.
+
+ Calls move() to update the state. Calls restore() on escape.
+ """
+ if ev.key == 'escape':
+ self.restore()
+ elif ev.key in ['up', 'down', 'right', 'left']:
+ dx, dy = self.dpixel(self.clickx, self.clicky, nudge=ev.control)
+ if ev.key == 'up':
+ self.clicky += dy
+ elif ev.key == 'down':
+ self.clicky -= dy
+ elif ev.key == 'right':
+ self.clickx += dx
+ else: self.clickx -= dx
+ self.move(self.clickx, self.clicky, ev)
+ else:
+ return False
+ self.base.update()
+ return True
+
+ def dpixel(self, x, y, nudge=False):
+ """
+ Return the step size in data coordinates for a small
+ step in screen coordinates. If nudge is False (default)
+ the step size is one pixel. If nudge is True, the step
+ size is 0.2 pixels.
+ """
+ ax = self.axes
+ px, py = ax.transData.inverse_xy_tup((x, y))
+ if nudge:
+ nx, ny = ax.transData.xy_tup((px + 0.2, py + 0.2))
+ else:
+ nx, ny = ax.transData.xy_tup((px + 1.0, py + 1.0))
+ dx, dy = nx - x, ny - y
+ return dx, dy
+
diff --git a/src/sas/sasgui/guiframe/local_perspectives/plotting/Edge.py b/src/sas/sasgui/guiframe/local_perspectives/plotting/Edge.py
index 1f2b8c2..c72d191 100644
--- a/src/sas/sasgui/guiframe/local_perspectives/plotting/Edge.py
+++ b/src/sas/sasgui/guiframe/local_perspectives/plotting/Edge.py
@@ -1,128 +1,128 @@
-import math
-from BaseInteractor import _BaseInteractor
-
-
-class RadiusInteractor(_BaseInteractor):
- """
- Select an annulus through a 2D plot
- """
- def __init__(self, base, axes, color='black', zorder=5, arc1=None,
- arc2=None, theta=math.pi / 8):
- """
- """
- _BaseInteractor.__init__(self, base, axes, color=color)
- self.markers = []
- self.axes = axes
- self.r1 = arc1.get_radius()
- self.r2 = arc2.get_radius()
- self.theta = theta
- self.save_theta = theta
- self.move_stop = False
- self.theta_left = None
- self.theta_right = None
- self.arc1 = arc1
- self.arc2 = arc2
- x1 = self.r1 * math.cos(self.theta)
- y1 = self.r1 * math.sin(self.theta)
- x2 = self.r2 * math.cos(self.theta)
- y2 = self.r2 * math.sin(self.theta)
- self.line = self.axes.plot([x1, x2], [y1, y2],
- linestyle='-', marker='',
- color=self.color,
- visible=True)[0]
- self.phi = theta
- self.npts = 20
- self.has_move = False
- self.connect_markers([self.line])
- self.update()
-
- def set_layer(self, n):
- """
- """
- self.layernum = n
- self.update()
-
- def clear(self):
- """
- """
- self.clear_markers()
- try:
- self.line.remove()
- except:
- # Old version of matplotlib
- for item in range(len(self.axes.lines)):
- del self.axes.lines[0]
-
- def get_angle(self):
- """
- """
- return self.theta
-
- def update(self, r1=None, r2=None, theta=None):
- """
- Draw the new roughness on the graph.
- """
- if r1 != None:
- self.r1 = r1
- if r2 != None:
- self.r2 = r2
- if theta != None:
- self.theta = theta
- x1 = self.r1 * math.cos(self.theta)
- y1 = self.r1 * math.sin(self.theta)
- x2 = self.r2 * math.cos(self.theta)
- y2 = self.r2 * math.sin(self.theta)
- self.line.set(xdata=[x1, x2], ydata=[y1, y2])
-
- def save(self, ev):
- """
- Remember the roughness for this layer and the next so that we
- can restore on Esc.
- """
- self.save_theta = math.atan2(ev.y, ev.x)
- self.base.freeze_axes()
-
- def moveend(self, ev):
- """
- """
- self.has_move = False
- self.base.moveend(ev)
-
- def restore(self, ev):
- """
- Restore the roughness for this layer.
- """
- self.theta = self.save_theta
-
- def move(self, x, y, ev):
- """
- Process move to a new position, making sure that the move is allowed.
- """
- self.theta = math.atan2(y, x)
- self.has_move = True
- self.base.base.update()
-
- def set_cursor(self, r_min, r_max, theta):
- """
- """
- self.theta = theta
- self.r1 = r_min
- self.r2 = r_max
- self.update()
-
- def get_params(self):
- """
- """
- params = {}
- params["radius1"] = self.r1
- params["radius2"] = self.r2
- params["theta"] = self.theta
- return params
-
- def set_params(self, params):
- """
- """
- x1 = params["radius1"]
- x2 = params["radius2"]
- theta = params["theta"]
- self.set_cursor(x1, x2, theta)
+import math
+from BaseInteractor import _BaseInteractor
+
+
+class RadiusInteractor(_BaseInteractor):
+ """
+ Select an annulus through a 2D plot
+ """
+ def __init__(self, base, axes, color='black', zorder=5, arc1=None,
+ arc2=None, theta=math.pi / 8):
+ """
+ """
+ _BaseInteractor.__init__(self, base, axes, color=color)
+ self.markers = []
+ self.axes = axes
+ self.r1 = arc1.get_radius()
+ self.r2 = arc2.get_radius()
+ self.theta = theta
+ self.save_theta = theta
+ self.move_stop = False
+ self.theta_left = None
+ self.theta_right = None
+ self.arc1 = arc1
+ self.arc2 = arc2
+ x1 = self.r1 * math.cos(self.theta)
+ y1 = self.r1 * math.sin(self.theta)
+ x2 = self.r2 * math.cos(self.theta)
+ y2 = self.r2 * math.sin(self.theta)
+ self.line = self.axes.plot([x1, x2], [y1, y2],
+ linestyle='-', marker='',
+ color=self.color,
+ visible=True)[0]
+ self.phi = theta
+ self.npts = 20
+ self.has_move = False
+ self.connect_markers([self.line])
+ self.update()
+
+ def set_layer(self, n):
+ """
+ """
+ self.layernum = n
+ self.update()
+
+ def clear(self):
+ """
+ """
+ self.clear_markers()
+ try:
+ self.line.remove()
+ except:
+ # Old version of matplotlib
+ for item in range(len(self.axes.lines)):
+ del self.axes.lines[0]
+
+ def get_angle(self):
+ """
+ """
+ return self.theta
+
+ def update(self, r1=None, r2=None, theta=None):
+ """
+ Draw the new roughness on the graph.
+ """
+ if r1 is not None:
+ self.r1 = r1
+ if r2 is not None:
+ self.r2 = r2
+ if theta is not None:
+ self.theta = theta
+ x1 = self.r1 * math.cos(self.theta)
+ y1 = self.r1 * math.sin(self.theta)
+ x2 = self.r2 * math.cos(self.theta)
+ y2 = self.r2 * math.sin(self.theta)
+ self.line.set(xdata=[x1, x2], ydata=[y1, y2])
+
+ def save(self, ev):
+ """
+ Remember the roughness for this layer and the next so that we
+ can restore on Esc.
+ """
+ self.save_theta = math.atan2(ev.y, ev.x)
+ self.base.freeze_axes()
+
+ def moveend(self, ev):
+ """
+ """
+ self.has_move = False
+ self.base.moveend(ev)
+
+ def restore(self, ev):
+ """
+ Restore the roughness for this layer.
+ """
+ self.theta = self.save_theta
+
+ def move(self, x, y, ev):
+ """
+ Process move to a new position, making sure that the move is allowed.
+ """
+ self.theta = math.atan2(y, x)
+ self.has_move = True
+ self.base.base.update()
+
+ def set_cursor(self, r_min, r_max, theta):
+ """
+ """
+ self.theta = theta
+ self.r1 = r_min
+ self.r2 = r_max
+ self.update()
+
+ def get_params(self):
+ """
+ """
+ params = {}
+ params["radius1"] = self.r1
+ params["radius2"] = self.r2
+ params["theta"] = self.theta
+ return params
+
+ def set_params(self, params):
+ """
+ """
+ x1 = params["radius1"]
+ x2 = params["radius2"]
+ theta = params["theta"]
+ self.set_cursor(x1, x2, theta)
diff --git a/src/sas/sasgui/guiframe/local_perspectives/plotting/Plotter1D.py b/src/sas/sasgui/guiframe/local_perspectives/plotting/Plotter1D.py
index 1da60b1..aa9eedf 100644
--- a/src/sas/sasgui/guiframe/local_perspectives/plotting/Plotter1D.py
+++ b/src/sas/sasgui/guiframe/local_perspectives/plotting/Plotter1D.py
@@ -1,890 +1,891 @@
-
-################################################################################
-# This software was developed by the University of Tennessee as part of the
-# Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
-# project funded by the US National Science Foundation.
-#
-# See the license text in license.txt
-#
-# copyright 2008, University of Tennessee
-################################################################################
-
-
-import wx
-import sys
-import math
-import numpy
-import logging
-from sas.sasgui.plottools.PlotPanel import PlotPanel
-from sas.sasgui.guiframe.events import StatusEvent
-from sas.sasgui.guiframe.events import PanelOnFocusEvent
-from sas.sasgui.guiframe.utils import PanelMenu, IdList
-from sas.sasgui.guiframe.panel_base import PanelBase
-from sas.sasgui.guiframe.gui_style import GUIFRAME_ICON
-from appearanceDialog import appearanceDialog
-from graphAppearance import graphAppearance
-
-DEFAULT_QMAX = 0.05
-DEFAULT_QSTEP = 0.001
-DEFAULT_BEAM = 0.005
-BIN_WIDTH = 1
-IS_MAC = (sys.platform == 'darwin')
-
-
-def find_key(dic, val):
- """return the key of dictionary dic given the value"""
- return [k for k, v in dic.iteritems() if v == val][0]
-
-class ModelPanel1D(PlotPanel, PanelBase):
- """
- Plot panel for use with the GUI manager
- """
-
- ## Internal name for the AUI manager
- window_name = "plotpanel"
- ## Title to appear on top of the window
- window_caption = "Graph"
- ## Flag to tell the GUI manager that this panel is not
- # tied to any perspective
- ALWAYS_ON = True
- ## Group ID
- group_id = None
- _menu_ids = IdList()
-
- def __init__(self, parent, id=-1, color=None,
- dpi=None, style=wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs):
- PlotPanel.__init__(self, parent, id=id, style=style, **kwargs)
- PanelBase.__init__(self, parent)
- ## Reference to the parent window
- self.parent = parent
- if hasattr(parent, "parent"):
- self.parent = self.parent.parent
- ## Plottables
- self.plots = {}
- self.frame = None
- # context menu
- self._slicerpop = None
- self._available_data = []
- self._symbol_labels = self.get_symbol_label()
- self._color_labels = self.get_color_label()
- self.currColorIndex = ""
- self._is_changed_legend_label = False
- self.is_xtick = False
- self.is_ytick = False
-
- self.hide_menu = None
- ## Unique ID (from gui_manager)
- self.uid = None
- self.x_size = None
- ## Default locations
- # self._default_save_location = os.getcwd()
- self.size = None
- self.vl_ind = 0
- ## Graph
- # self.graph = Graph()
- self.graph.xaxis("\\rm{Q}", 'A^{-1}')
- self.graph.yaxis("\\rm{Intensity} ", "cm^{-1}")
- self.graph.render(self)
- self.cursor_id = None
-
- # In resizing event
- self.resizing = False
- self.canvas.set_resizing(self.resizing)
- self.Bind(wx.EVT_SIZE, self._OnReSize)
- self.parent.SetFocus()
-
- # If true, there are 3 qrange bars
- self.is_corfunc = False
-
-
- def get_symbol_label(self):
- """
- Associates label to symbol
- """
- _labels = {}
- i = 0
- _labels['Circle'] = i
- i += 1
- _labels['Cross X '] = i
- i += 1
- _labels['Triangle Down'] = i
- i += 1
- _labels['Triangle Up'] = i
- i += 1
- _labels['Triangle Left'] = i
- i += 1
- _labels['Triangle Right'] = i
- i += 1
- _labels['Cross +'] = i
- i += 1
- _labels['Square'] = i
- i += 1
- _labels['diamond'] = i
- i += 1
- _labels['Diamond'] = i
- i += 1
- _labels['Hexagon1'] = i
- i += 1
- _labels['Hexagon2'] = i
- i += 1
- _labels['Pentagon'] = i
- i += 1
- _labels['Line'] = i
- i += 1
- _labels['Dash'] = i
- i += 1
- _labels['Vline'] = i
- i += 1
- _labels['Step'] = i
- return _labels
-
- def get_color_label(self):
- """
- Associates label to a specific color
- """
- _labels = {}
- i = 0
- _labels['Blue'] = i
- i += 1
- _labels['Green'] = i
- i += 1
- _labels['Red'] = i
- i += 1
- _labels['Cyan'] = i
- i += 1
- _labels['Magenta'] = i
- i += 1
- _labels['Yellow'] = i
- i += 1
- _labels['Black'] = i
- return _labels
-
-
- def set_data(self, list=None):
- """
- """
- pass
-
- def _reset(self):
- """
- Resets internal data and graph
- """
- self.graph.reset()
- self.plots = {}
- self.is_zoomed = False
-
- def _OnReSize(self, event):
- """
- On response of the resize of a panel, set axes_visiable False
- """
- # It was found that wx >= 2.9.3 sends an event even if no size changed.
- # So manually recode the size (=x_size) and compare here.
- # Massy code to work around:<
- if self.parent._mgr != None:
- max_panel = self.parent._mgr.GetPane(self)
- if max_panel.IsMaximized():
- self.parent._mgr.RestorePane(max_panel)
- max_panel.Maximize()
- if self.x_size != None:
- if self.x_size == self.GetSize():
- self.resizing = False
- self.canvas.set_resizing(self.resizing)
- return
- self.x_size = self.GetSize()
-
- # Ready for another event
- # Do not remove this Skip. Otherwise it will get runtime error on wx>=2.9.
- event.Skip()
- # set the resizing flag
- self.resizing = True
- self.canvas.set_resizing(self.resizing)
- self.parent.set_schedule(True)
- pos_x, pos_y = self.GetPositionTuple()
- if pos_x != 0 and pos_y != 0:
- self.size, _ = self.GetClientSizeTuple()
- self.SetSizer(self.sizer)
- wx.CallAfter(self.parent.disable_app_menu, self)
-
- def on_plot_qrange(self, event=None):
- """
- On Qmin Qmax vertical line event
- """
- if event == None:
- return
- event.Skip()
- active_ctrl = event.active
- if active_ctrl == None:
- return
- if hasattr(event, 'is_corfunc'):
- self.is_corfunc = event.is_corfunc
- if event.id in self.plots.keys():
- ctrl = event.ctrl
- self.cursor_id = event.id
- # Set line position and color
- colors = ['red', 'purple']
- x_data = self.plots[self.cursor_id].x
- values = [max(x_data.min(), float(ctrl[0].GetValue())),
- min(x_data.max(), float(ctrl[1].GetValue()))]
- if len(ctrl) == 3:
- colors.append('purple')
- values.append(min(x_data.max(), float(ctrl[2].GetValue())))
- if self.ly == None:
- self.ly = []
- for c, v in zip(colors, values):
- h = self.subplot.axvline(x=v, color=c, lw=2.5, alpha=0.7)
- h.set_rasterized(True)
- self.ly.append(h)
- try:
- # Display x,y in the status bar if possible
- xval = float(active_ctrl.GetValue())
- position = self.get_data_xy_vals(xval)
- if position != None and not self.is_corfunc:
- wx.PostEvent(self.parent, StatusEvent(status=position))
- except:
- logging.error(sys.exc_value)
- if not event.leftdown:
- # text event
- try:
- is_moved = False
- for h, v in zip(self.ly, values):
- # check if vline moved
- if h.get_xdata() != v:
- h.set_xdata(v)
- is_moved = True
- if is_moved:
- self.canvas.draw()
- except:
- logging.error(sys.exc_value)
- event.Skip()
- return
- self.q_ctrl = ctrl
- for h, c, v in zip(self.ly, colors, values):
- h.set_color(c)
- h.set_xdata(v)
- self.canvas.draw()
- else:
- self.q_ctrl = None
-
- def get_data_xy_vals(self, xval):
- """
- Get x, y data values near x = x_val
- """
- try:
- x_data = self.plots[self.cursor_id].x
- y_data = self.plots[self.cursor_id].y
- indx = self._find_nearest(x_data, xval)
- pos_x = x_data[indx]
- pos_y = y_data[indx]
- position = str(pos_x), str(pos_y)
- return position
- except:
- return None
-
- def _find_nearest(self, array, value):
- """
- Find and return the nearest value in array to the value.
- Used in cusor_line()
- :Param array: numpy array
- :Param value: float
- """
- idx = (numpy.abs(array - value)).argmin()
- return int(idx) # array.flat[idx]
-
- def _check_line_positions(self, pos_x=None, nop=None):
- """
- Check vertical line positions
- :Param pos_x: position of the current line [float]
- :Param nop: number of plots [int]
- """
- ly = self.ly
- ly0x = ly[0].get_xdata()
- ly1x = ly[1].get_xdata()
- ly2x = None
- if self.is_corfunc: ly2x = ly[2].get_xdata()
- self.q_ctrl[0].SetBackgroundColour('white')
- self.q_ctrl[1].SetBackgroundColour('white')
- if ly0x >= ly1x:
- if self.vl_ind == 0:
- ly[1].set_xdata(pos_x)
- ly[1].set_zorder(nop)
- self.q_ctrl[1].SetValue(str(pos_x))
- self.q_ctrl[0].SetBackgroundColour('pink')
- elif self.vl_ind == 1:
- ly[0].set_xdata(pos_x)
- ly[0].set_zorder(nop)
- self.q_ctrl[0].SetValue(str(pos_x))
- self.q_ctrl[1].SetBackgroundColour('pink')
- elif ly2x is not None and ly1x >= ly2x:
- if self.vl_ind == 1:
- ly[2].set_xdata(posx)
- ly[2].set_zorder(nop)
- self.q_ctrl[2].SetValue(str(pos_x))
- elif self.vl_ind == 2:
- ly[1].set_xdata(posx)
- ly[1].set_zorder(nop)
- self.q_ctrl[1].SetValue(str(pos_x))
-
-
- def _get_cusor_lines(self, event):
- """
- Revmove or switch cursor line if drawn
- :Param event: LeftClick mouse event
- """
- ax = event.inaxes
- if hasattr(event, "action"):
- dclick = event.action == 'dclick'
- if ax == None or dclick:
- # remove the vline
- self._check_zoom_plot()
- self.canvas.draw()
- self.q_ctrl = None
- return
- if self.ly != None and event.xdata != None:
- # Selecting a new line if cursor lines are displayed already
- dqmin = math.fabs(event.xdata - self.ly[0].get_xdata())
- dqmax = math.fabs(event.xdata - self.ly[1].get_xdata())
- if not self.is_corfunc:
- is_qmax = dqmin > dqmax
- if is_qmax:
- self.vl_ind = 1
- else:
- self.vl_ind = 0
- else:
- dqmax2 = math.fabs(event.xdata - self.ly[2].get_xdata())
- closest = min(dqmin, dqmax, dqmax2)
- self.vl_ind = { dqmin: 0, dqmax: 1, dqmax2: 2 }.get(closest)
-
- def cusor_line(self, event):
- """
- Move the cursor line to write Q range
- """
- if self.q_ctrl == None:
- return
- # release a q range vline
- if self.ly != None and not self.leftdown:
- for ly in self.ly:
- ly.set_alpha(0.7)
- self.canvas.draw()
- return
- ax = event.inaxes
- if ax == None or not hasattr(event, 'action'):
- return
- end_drag = event.action != 'drag' and event.xdata != None
- nop = len(self.plots)
- pos_x, _ = float(event.xdata), float(event.ydata)
- try:
- ly = self.ly
- ly0x = ly[0].get_xdata()
- ly1x = ly[1].get_xdata()
- if ly0x == ly1x:
- if ly[0].get_zorder() > ly[1].get_zorder():
- self.vl_ind = 0
- else:
- self.vl_ind = 1
- vl_ind = self.vl_ind
- x_data = self.plots[self.cursor_id].x
- xmin = x_data.min()
- xmax = x_data.max()
- indx = self._find_nearest(x_data, pos_x)
- # Need to hold LeftButton to drag
- if end_drag:
- if event.button:
- self._check_line_positions(pos_x, nop)
- return
- if indx >= len(x_data):
- indx = len(x_data) - 1
- pos_x = x_data[indx]
- if xmin == ly1x:
- vl_ind = 1
- elif xmax == ly0x:
- vl_ind = 0
- else:
- ly[vl_ind].set_xdata(pos_x)
- ly[vl_ind].set_zorder(nop + 1)
- self._check_line_positions(pos_x, nop)
- ly[vl_ind].set_xdata(pos_x)
- ly[vl_ind].set_alpha(1.0)
- ly[vl_ind].set_zorder(nop + 1)
- self.canvas.draw()
- self.q_ctrl[vl_ind].SetValue(str(pos_x))
- except:
- logging.error(sys.exc_value)
-
- def set_resizing(self, resizing=False):
- """
- Set the resizing (True/False)
- """
- self.resizing = resizing
- # self.canvas.set_resizing(resizing)
-
- def schedule_full_draw(self, func='append'):
- """
- Put self in schedule to full redraw list
- """
- # append/del this panel in the schedule list
- self.parent.set_schedule_full_draw(self, func)
-
- def remove_data_by_id(self, id):
- """
- Remove data from plot
- """
- if id in self.plots.keys():
- data = self.plots[id]
- self.graph.delete(data)
- data_manager = self._manager.parent.get_data_manager()
- data_list, theory_list = data_manager.get_by_id(id_list=[id])
-
- if id in data_list.keys():
- data = data_list[id]
- if id in theory_list.keys():
- data = theory_list[id]
-
- del self.plots[id]
- self.graph.render(self)
- self.subplot.figure.canvas.draw_idle()
- if len(self.graph.plottables) == 0:
- # onRemove: graph is empty must be the panel must be destroyed
- self.parent.delete_panel(self.uid)
-
- def plot_data(self, data):
- """
- Data is ready to be displayed
-
- :param event: data event
- """
- if data.__class__.__name__ == 'Data2D':
- return
- plot_keys = self.plots.keys()
- if data.id in plot_keys:
- # Recover panel prop.s
- xlo, xhi = self.subplot.get_xlim()
- ylo, yhi = self.subplot.get_ylim()
- old_data = self.plots[data.id]
- if self._is_changed_legend_label:
- data.label = old_data.label
- if old_data.__class__.__name__ == 'Data1D':
- data.custom_color = old_data.custom_color
- data.symbol = old_data.symbol
- data.markersize = old_data.markersize
- data.zorder = len(plot_keys)
- # Replace data
- self.graph.replace(data)
- self.plots[data.id] = data
- ## Set the view scale for all plots
- try:
- self._onEVT_FUNC_PROPERTY()
- except Exception, exc:
- wx.PostEvent(self.parent,
- StatusEvent(status="Plotting Error: %s" % str(exc), info="error"))
- if self.is_zoomed:
- # Recover the x,y limits
- self.subplot.set_xlim((xlo, xhi))
- self.subplot.set_ylim((ylo, yhi))
- else:
- self.plots[data.id] = data
- self.graph.add(self.plots[data.id])
- data.zorder = len(plot_keys)
- ## Set the view scale for all plots
- try:
- self._onEVT_FUNC_PROPERTY()
- if IS_MAC:
- # MAC: forcing to plot 2D avg
- self.canvas._onDrawIdle()
- except Exception, exc:
- wx.PostEvent(self.parent, StatusEvent(status=\
- "Plotting Error: %s" % str(exc), info="error"))
- self.toolbar.update()
- self.is_zoomed = False
-
- def draw_plot(self):
- """
- Draw plot
- """
- self.draw()
-
- def onLeftDown(self, event):
- """
- left button down and ready to drag
- Display the position of the mouse on the statusbar
- """
- # self.parent.set_plot_unfocus()
- self._get_cusor_lines(event)
- ax = event.inaxes
- PlotPanel.onLeftDown(self, event)
- if ax != None:
- try:
- pos_x = float(event.xdata) # / size_x
- pos_y = float(event.ydata) # / size_y
- pos_x = "%8.3g" % pos_x
- pos_y = "%8.3g" % pos_y
- self.position = str(pos_x), str(pos_y)
- wx.PostEvent(self.parent, StatusEvent(status=self.position))
- except:
- self.position = None
- # unfocus all
- self.parent.set_plot_unfocus()
- # post nd event to notify guiframe that this panel is on focus
- wx.PostEvent(self.parent, PanelOnFocusEvent(panel=self))
-
-
- def _ontoggle_hide_error(self, event):
- """
- Toggle error display to hide or show
- """
- menu = event.GetEventObject()
- event_id = event.GetId()
- self.set_selected_from_menu(menu, event_id)
- # Check zoom
- xlo, xhi = self.subplot.get_xlim()
- ylo, yhi = self.subplot.get_ylim()
-
- selected_plot = self.plots[self.graph.selected_plottable]
- if self.hide_menu.GetText() == "Hide Error Bar":
- selected_plot.hide_error = True
- else:
- selected_plot.hide_error = False
- ## increment graph color
- self.graph.render(self)
- self.subplot.figure.canvas.draw_idle()
- if self.is_zoomed:
- # Recover the x,y limits
- self.subplot.set_xlim((xlo, xhi))
- self.subplot.set_ylim((ylo, yhi))
- self.graph.selected_plottable = None
-
-
- def _onRemove(self, event):
- """
- Remove a plottable from the graph and render the graph
-
- :param event: Menu event
-
- """
- menu = event.GetEventObject()
- event_id = event.GetId()
- self.set_selected_from_menu(menu, event_id)
- ## Check if there is a selected graph to remove
- if self.graph.selected_plottable in self.plots.keys():
- graph_id = self.graph.selected_plottable
- self.remove_data_by_id(graph_id)
-
- def onContextMenu(self, event):
- """
- 1D plot context menu
-
- :param event: wx context event
-
- """
- self._slicerpop = PanelMenu()
- self._slicerpop.set_plots(self.plots)
- self._slicerpop.set_graph(self.graph)
- ids = iter(self._menu_ids)
-
- # Various plot options
- wx_id = ids.next()
- self._slicerpop.Append(wx_id, '&Save Image', 'Save image as PNG')
- wx.EVT_MENU(self, wx_id, self.onSaveImage)
- wx_id = ids.next()
- self._slicerpop.Append(wx_id, '&Print Image', 'Print image ')
- wx.EVT_MENU(self, wx_id, self.onPrint)
-
- wx_id = ids.next()
- self._slicerpop.Append(wx_id, '&Copy to Clipboard',
- 'Copy to the clipboard')
- wx.EVT_MENU(self, wx_id, self.OnCopyFigureMenu)
-
- self._slicerpop.AppendSeparator()
-
- for plot in self.plots.values():
- # title = plot.title
- name = plot.name
- plot_menu = wx.Menu()
- if self.graph.selected_plottable:
- if not self.graph.selected_plottable in self.plots.keys():
- continue
- if plot != self.plots[self.graph.selected_plottable]:
- continue
-
- wx_id = ids.next()
- plot_menu.Append(wx_id, "&DataInfo", name)
- wx.EVT_MENU(self, wx_id, self. _onDataShow)
- wx_id = ids.next()
- plot_menu.Append(wx_id, "&Save Points as a File", name)
- wx.EVT_MENU(self, wx_id, self._onSave)
- plot_menu.AppendSeparator()
-
- # add menu of other plugins
- item_list = self.parent.get_current_context_menu(self)
- if (not item_list == None) and (not len(item_list) == 0):
- for item, wx_id in zip(item_list, [ids.next() for i in range(len(item_list))]):
-
- try:
- plot_menu.Append(wx_id, item[0], name)
- wx.EVT_MENU(self, wx_id, item[2])
- except:
- msg = "ModelPanel1D.onContextMenu: "
- msg += "bad menu item %s" % sys.exc_value
- wx.PostEvent(self.parent, StatusEvent(status=msg))
- plot_menu.AppendSeparator()
-
- if self.parent.ClassName.count('wxDialog') == 0:
- if plot.id != 'fit':
- wx_id = ids.next()
- plot_menu.Append(wx_id, '&Linear Fit', name)
- wx.EVT_MENU(self, wx_id, self.onFitting)
- plot_menu.AppendSeparator()
-
- wx_id = ids.next()
- plot_menu.Append(wx_id, "Remove", name)
- wx.EVT_MENU(self, wx_id, self._onRemove)
- if not plot.is_data:
- wx_id = ids.next()
- plot_menu.Append(wx_id, '&Freeze', name)
- wx.EVT_MENU(self, wx_id, self.onFreeze)
- plot_menu.AppendSeparator()
-
- if plot.is_data:
- wx_id = ids.next()
- self.hide_menu = plot_menu.Append(wx_id, "Hide Error Bar", name)
-
- if plot.dy is not None and plot.dy != []:
- if plot.hide_error:
- self.hide_menu.SetText('Show Error Bar')
- else:
- self.hide_menu.SetText('Hide Error Bar')
- else:
- self.hide_menu.Enable(False)
- wx.EVT_MENU(self, wx_id, self._ontoggle_hide_error)
-
- plot_menu.AppendSeparator()
-
- wx_id = ids.next()
- plot_menu.Append(wx_id, '&Modify Plot Property', name)
- wx.EVT_MENU(self, wx_id, self.createAppDialog)
- wx_id = ids.next()
- # plot_menu.SetTitle(name)
- self._slicerpop.AppendMenu(wx_id, '&%s' % name, plot_menu)
- # Option to hide
- # TODO: implement functionality to hide a plottable (legend click)
-
- self._slicerpop.AppendSeparator()
- loc_menu = wx.Menu()
- for label in self._loc_labels:
- wx_id = ids.next()
- loc_menu.Append(wx_id, str(label), str(label))
- wx.EVT_MENU(self, wx_id, self.onChangeLegendLoc)
-
- wx_id = ids.next()
- self._slicerpop.Append(wx_id, '&Modify Graph Appearance',
- 'Modify graph appearance')
- wx.EVT_MENU(self, wx_id, self.modifyGraphAppearance)
- self._slicerpop.AppendSeparator()
-
-
- if self.position != None:
- wx_id = ids.next()
- self._slicerpop.Append(wx_id, '&Add Text')
- wx.EVT_MENU(self, wx_id, self._on_addtext)
- wx_id = ids.next()
- self._slicerpop.Append(wx_id, '&Remove Text')
- wx.EVT_MENU(self, wx_id, self._on_removetext)
- self._slicerpop.AppendSeparator()
- wx_id = ids.next()
- self._slicerpop.Append(wx_id, '&Change Scale')
- wx.EVT_MENU(self, wx_id, self._onProperties)
- self._slicerpop.AppendSeparator()
- wx_id = ids.next()
- self._slicerpop.Append(wx_id, '&Set Graph Range')
- wx.EVT_MENU(self, wx_id, self.onSetRange)
- wx_id = ids.next()
- self._slicerpop.Append(wx_id, '&Reset Graph Range')
- wx.EVT_MENU(self, wx_id, self.onResetGraph)
-
- if self.parent.ClassName.count('wxDialog') == 0:
- self._slicerpop.AppendSeparator()
- wx_id = ids.next()
- self._slicerpop.Append(wx_id, '&Window Title')
- wx.EVT_MENU(self, wx_id, self.onChangeCaption)
- try:
- pos_evt = event.GetPosition()
- pos = self.ScreenToClient(pos_evt)
- except:
- pos_x, pos_y = self.toolbar.GetPositionTuple()
- pos = (pos_x, pos_y + 5)
- self.PopupMenu(self._slicerpop, pos)
-
- def onSetRange(self, event):
- # Display dialog
- # self.subplot.set_xlim((low, high))
- # self.subplot.set_ylim((low, high))
- from sas.sasgui.plottools.RangeDialog import RangeDialog
- d = RangeDialog(self, -1)
- xlim = self.subplot.get_xlim()
- ylim = self.subplot.get_ylim()
- d.SetXRange(xlim)
- d.SetYRange(ylim)
- if d.ShowModal() == wx.ID_OK:
- x_range = d.GetXRange()
- y_range = d.GetYRange()
- if x_range is not None and y_range is not None:
- self.subplot.set_xlim(x_range)
- self.subplot.set_ylim(y_range)
- self.subplot.figure.canvas.draw_idle()
- self.is_zoomed = True
- d.Destroy()
-
- def onFreeze(self, event):
- """
- on Freeze data
- """
- menu = event.GetEventObject()
- wx_id = event.GetId()
- self.set_selected_from_menu(menu, wx_id)
- plot = self.plots[self.graph.selected_plottable]
- self.parent.onfreeze([plot.id])
-
- def _onSave(self, evt):
- """
- Save a data set to a text file
-
- :param evt: Menu event
-
- """
- menu = evt.GetEventObject()
- event_id = evt.GetId()
- self.set_selected_from_menu(menu, event_id)
- data = self.plots[self.graph.selected_plottable]
- default_name = data.label
- if default_name.count('.') > 0:
- default_name = default_name.split('.')[0]
- default_name += "_out"
- if self.parent != None:
- self.parent.save_data1d(data, default_name)
-
- def _onDataShow(self, evt):
- """
- Show the data set in text
-
- :param evt: Menu event
-
- """
- menu = evt.GetEventObject()
- event_id = evt.GetId()
- self.set_selected_from_menu(menu, event_id)
- data = self.plots[self.graph.selected_plottable]
- default_name = data.label
- if default_name.count('.') > 0:
- default_name = default_name.split('.')[0]
- # default_name += "_out"
- if self.parent != None:
- self.parent.show_data1d(data, default_name)
-
- def _on_hide(self, event):
- """
- Hides the plot when button is pressed
- """
- if self.parent is not None:
- self.parent.hide_panel(self.uid)
-
- def on_close(self, event):
- """
- On Close Event
- """
- ID = self.uid
- self.parent.delete_panel(ID)
-
- def createAppDialog(self, event):
- """
- Create the custom dialog for fit appearance modification
- """
- menu = event.GetEventObject()
- event_id = event.GetId()
- self.set_selected_from_menu(menu, event_id)
- self.appearance_selected_plot = \
- self.plots[self.graph.selected_plottable]
- # find current properties
- curr_color = self.appearance_selected_plot.custom_color
- curr_symbol = self.appearance_selected_plot.symbol
- curr_size = self.appearance_selected_plot.markersize
- curr_label = self.appearance_selected_plot.label
-
- if curr_color == None:
- curr_color = self._color_labels['Blue']
- curr_symbol = 13
-
- self.appD = appearanceDialog(self, 'Modify Plot Property')
- icon = self.parent.GetIcon()
- self.appD.SetIcon(icon)
- self.appD.set_defaults(float(curr_size), int(curr_color),
- str(appearanceDialog.find_key(self.get_symbol_label(),
- int(curr_symbol))), curr_label)
- self.appD.Bind(wx.EVT_CLOSE, self.on_AppDialog_close)
- self.graph.selected_plottable = None
-
- def on_AppDialog_close(self, event):
- """
- on_Modify Plot Property_close
- """
- if self.appD.okay_clicked == True:
- info = self.appD.get_current_values()
- self.appearance_selected_plot.custom_color = \
- self._color_labels[info[1].encode('ascii', 'ignore')]
-
- self.appearance_selected_plot.markersize = float(info[0])
- self.appearance_selected_plot.symbol = \
- self.get_symbol_label()[info[2]]
- self.appearance_selected_plot.label = str(info[3])
- self.appD.Destroy()
- self._check_zoom_plot()
-
- def modifyGraphAppearance(self, event):
- """
- On Modify Graph Appearance
- """
- self.graphApp = graphAppearance(self, 'Modify Graph Appearance')
- icon = self.parent.GetIcon()
- self.graphApp.SetIcon(icon)
- self.graphApp.setDefaults(self.grid_on, self.legend_on,
- self.xaxis_label, self.yaxis_label,
- self.xaxis_unit, self.yaxis_unit,
- self.xaxis_font, self.yaxis_font,
- find_key(self.get_loc_label(), self.legendLoc),
- self.xcolor, self.ycolor,
- self.is_xtick, self.is_ytick)
- self.graphApp.Bind(wx.EVT_CLOSE, self.on_graphApp_close)
-
- def on_graphApp_close(self, event):
- """
- Gets values from graph appearance dialog and sends them off
- to modify the plot
- """
- graph_app = self.graphApp
- toggle_grid = graph_app.get_togglegrid()
- legend_loc = graph_app.get_legend_loc()
- toggle_legend = graph_app.get_togglelegend()
-
- self.onGridOnOff(toggle_grid)
- self.ChangeLegendLoc(legend_loc)
- self.onLegend(toggle_legend)
-
- self.xaxis_label = graph_app.get_xlab()
- self.yaxis_label = graph_app.get_ylab()
- self.xaxis_unit = graph_app.get_xunit()
- self.yaxis_unit = graph_app.get_yunit()
- self.xaxis_font = graph_app.get_xfont()
- self.yaxis_font = graph_app.get_yfont()
- self.is_xtick = graph_app.get_xtick_check()
- self.is_ytick = graph_app.get_ytick_check()
- if self.is_xtick:
- self.xaxis_tick = self.xaxis_font
- if self.is_ytick:
- self.yaxis_tick = self.yaxis_font
-
- self.xaxis(self.xaxis_label, self.xaxis_unit,
- graph_app.get_xfont(), graph_app.get_xcolor(),
- self.xaxis_tick)
- self.yaxis(self.yaxis_label, self.yaxis_unit,
- graph_app.get_yfont(), graph_app.get_ycolor(),
- self.yaxis_tick)
-
- graph_app.Destroy()
+
+################################################################################
+# This software was developed by the University of Tennessee as part of the
+# Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
+# project funded by the US National Science Foundation.
+#
+# See the license text in license.txt
+#
+# copyright 2008, University of Tennessee
+################################################################################
+
+
+import wx
+import sys
+import math
+import numpy as np
+import logging
+from sas.sasgui.plottools.PlotPanel import PlotPanel
+from sas.sasgui.guiframe.events import StatusEvent
+from sas.sasgui.guiframe.events import PanelOnFocusEvent
+from sas.sasgui.guiframe.utils import PanelMenu, IdList
+from sas.sasgui.guiframe.panel_base import PanelBase
+from sas.sasgui.guiframe.gui_style import GUIFRAME_ICON
+from appearanceDialog import appearanceDialog
+from graphAppearance import graphAppearance
+
+logger = logging.getLogger(__name__)
+
+DEFAULT_QMAX = 0.05
+DEFAULT_QSTEP = 0.001
+DEFAULT_BEAM = 0.005
+BIN_WIDTH = 1
+IS_MAC = (sys.platform == 'darwin')
+
+
+def find_key(dic, val):
+ """return the key of dictionary dic given the value"""
+ return [k for k, v in dic.iteritems() if v == val][0]
+
+class ModelPanel1D(PlotPanel, PanelBase):
+ """
+ Plot panel for use with the GUI manager
+ """
+
+ ## Internal name for the AUI manager
+ window_name = "plotpanel"
+ ## Title to appear on top of the window
+ window_caption = "Graph"
+ ## Flag to tell the GUI manager that this panel is not
+ # tied to any perspective
+ ALWAYS_ON = True
+ ## Group ID
+ group_id = None
+ _menu_ids = IdList()
+
+ def __init__(self, parent, id=-1, color=None,
+ dpi=None, style=wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs):
+ PlotPanel.__init__(self, parent, id=id, style=style, **kwargs)
+ PanelBase.__init__(self, parent)
+ ## Reference to the parent window
+ self.parent = parent
+ if hasattr(parent, "parent"):
+ self.parent = self.parent.parent
+ ## Plottables
+ self.plots = {}
+ self.frame = None
+ # context menu
+ self._slicerpop = None
+ self._available_data = []
+ self._symbol_labels = self.get_symbol_label()
+ self._color_labels = self.get_color_label()
+ self.currColorIndex = ""
+ self._is_changed_legend_label = False
+ self.is_xtick = False
+ self.is_ytick = False
+
+ self.hide_menu = None
+ ## Unique ID (from gui_manager)
+ self.uid = None
+ self.x_size = None
+ ## Default locations
+ # self._default_save_location = os.getcwd()
+ self.size = None
+ self.vl_ind = 0
+ ## Graph
+ # self.graph = Graph()
+ self.graph.xaxis("\\rm{Q}", 'A^{-1}')
+ self.graph.yaxis("\\rm{Intensity} ", "cm^{-1}")
+ self.graph.render(self)
+ self.cursor_id = None
+
+ # In resizing event
+ self.resizing = False
+ self.canvas.set_resizing(self.resizing)
+ self.Bind(wx.EVT_SIZE, self._OnReSize)
+ self.parent.SetFocus()
+
+ # If true, there are 3 qrange bars
+ self.is_corfunc = False
+
+
+ def get_symbol_label(self):
+ """
+ Associates label to symbol
+ """
+ _labels = {}
+ i = 0
+ _labels['Circle'] = i
+ i += 1
+ _labels['Cross X '] = i
+ i += 1
+ _labels['Triangle Down'] = i
+ i += 1
+ _labels['Triangle Up'] = i
+ i += 1
+ _labels['Triangle Left'] = i
+ i += 1
+ _labels['Triangle Right'] = i
+ i += 1
+ _labels['Cross +'] = i
+ i += 1
+ _labels['Square'] = i
+ i += 1
+ _labels['diamond'] = i
+ i += 1
+ _labels['Diamond'] = i
+ i += 1
+ _labels['Hexagon1'] = i
+ i += 1
+ _labels['Hexagon2'] = i
+ i += 1
+ _labels['Pentagon'] = i
+ i += 1
+ _labels['Line'] = i
+ i += 1
+ _labels['Dash'] = i
+ i += 1
+ _labels['Vline'] = i
+ i += 1
+ _labels['Step'] = i
+ return _labels
+
+ def get_color_label(self):
+ """
+ Associates label to a specific color
+ """
+ _labels = {}
+ i = 0
+ _labels['Blue'] = i
+ i += 1
+ _labels['Green'] = i
+ i += 1
+ _labels['Red'] = i
+ i += 1
+ _labels['Cyan'] = i
+ i += 1
+ _labels['Magenta'] = i
+ i += 1
+ _labels['Yellow'] = i
+ i += 1
+ _labels['Black'] = i
+ return _labels
+
+
+ def set_data(self, list=None):
+ """
+ """
+ pass
+
+ def _reset(self):
+ """
+ Resets internal data and graph
+ """
+ self.graph.reset()
+ self.plots = {}
+ self.is_zoomed = False
+
+ def _OnReSize(self, event):
+ """
+ On response of the resize of a panel, set axes_visiable False
+ """
+ # It was found that wx >= 2.9.3 sends an event even if no size changed.
+ # So manually recode the size (=x_size) and compare here.
+ # Massy code to work around:<
+ if self.parent._mgr is not None:
+ max_panel = self.parent._mgr.GetPane(self)
+ if max_panel.IsMaximized():
+ self.parent._mgr.RestorePane(max_panel)
+ max_panel.Maximize()
+ if self.x_size is not None:
+ if self.x_size == self.GetSize():
+ self.resizing = False
+ self.canvas.set_resizing(self.resizing)
+ return
+ self.x_size = self.GetSize()
+
+ # Ready for another event
+ # Do not remove this Skip. Otherwise it will get runtime error on wx>=2.9.
+ event.Skip()
+ # set the resizing flag
+ self.resizing = True
+ self.canvas.set_resizing(self.resizing)
+ self.parent.set_schedule(True)
+ pos_x, pos_y = self.GetPositionTuple()
+ if pos_x != 0 and pos_y != 0:
+ self.size, _ = self.GetClientSizeTuple()
+ self.SetSizer(self.sizer)
+ wx.CallAfter(self.parent.disable_app_menu, self)
+
+ def on_plot_qrange(self, event=None):
+ """
+ On Qmin Qmax vertical line event
+ """
+ if event is None:
+ return
+ event.Skip()
+ active_ctrl = event.active
+ if active_ctrl is None:
+ return
+ if hasattr(event, 'is_corfunc'):
+ self.is_corfunc = event.is_corfunc
+ if event.id in self.plots.keys():
+ ctrl = event.ctrl
+ self.cursor_id = event.id
+ # Set line position and color
+ colors = ['red', 'purple']
+ x_data = self.plots[self.cursor_id].x
+ values = [max(x_data.min(), float(ctrl[0].GetValue())),
+ min(x_data.max(), float(ctrl[1].GetValue()))]
+ if len(ctrl) == 3:
+ colors.append('purple')
+ values.append(min(x_data.max(), float(ctrl[2].GetValue())))
+ if self.ly is None:
+ self.ly = []
+ for c, v in zip(colors, values):
+ h = self.subplot.axvline(x=v, color=c, lw=2.5, alpha=0.7)
+ h.set_rasterized(True)
+ self.ly.append(h)
+ try:
+ # Display x,y in the status bar if possible
+ xval = float(active_ctrl.GetValue())
+ position = self.get_data_xy_vals(xval)
+ if position is not None and not self.is_corfunc:
+ wx.PostEvent(self.parent, StatusEvent(status=position))
+ except:
+ logger.error(sys.exc_value)
+ if not event.leftdown:
+ # text event
+ try:
+ is_moved = False
+ for h, v in zip(self.ly, values):
+ # check if vline moved
+ if h.get_xdata() != v:
+ h.set_xdata(v)
+ is_moved = True
+ if is_moved:
+ self.canvas.draw()
+ except:
+ logger.error(sys.exc_value)
+ event.Skip()
+ return
+ self.q_ctrl = ctrl
+ for h, c, v in zip(self.ly, colors, values):
+ h.set_color(c)
+ h.set_xdata(v)
+ self.canvas.draw()
+ else:
+ self.q_ctrl = None
+
+ def get_data_xy_vals(self, xval):
+ """
+ Get x, y data values near x = x_val
+ """
+ try:
+ x_data = self.plots[self.cursor_id].x
+ y_data = self.plots[self.cursor_id].y
+ indx = self._find_nearest(x_data, xval)
+ pos_x = x_data[indx]
+ pos_y = y_data[indx]
+ position = str(pos_x), str(pos_y)
+ return position
+ except:
+ return None
+
+ def _find_nearest(self, array, value):
+ """
+ Find and return the nearest value in array to the value.
+ Used in cusor_line()
+ :Param array: numpy array
+ :Param value: float
+ """
+ idx = (np.abs(array - value)).argmin()
+ return int(idx) # array.flat[idx]
+
+ def _check_line_positions(self, pos_x=None, nop=None):
+ """
+ Check vertical line positions
+ :Param pos_x: position of the current line [float]
+ :Param nop: number of plots [int]
+ """
+ ly = self.ly
+ ly0x = ly[0].get_xdata()
+ ly1x = ly[1].get_xdata()
+ ly2x = None
+ if self.is_corfunc: ly2x = ly[2].get_xdata()
+ self.q_ctrl[0].SetBackgroundColour('white')
+ self.q_ctrl[1].SetBackgroundColour('white')
+ if ly0x >= ly1x:
+ if self.vl_ind == 0:
+ ly[1].set_xdata(pos_x)
+ ly[1].set_zorder(nop)
+ self.q_ctrl[1].SetValue(str(pos_x))
+ self.q_ctrl[0].SetBackgroundColour('pink')
+ elif self.vl_ind == 1:
+ ly[0].set_xdata(pos_x)
+ ly[0].set_zorder(nop)
+ self.q_ctrl[0].SetValue(str(pos_x))
+ self.q_ctrl[1].SetBackgroundColour('pink')
+ elif ly2x is not None and ly1x >= ly2x:
+ if self.vl_ind == 1:
+ ly[2].set_xdata(posx)
+ ly[2].set_zorder(nop)
+ self.q_ctrl[2].SetValue(str(pos_x))
+ elif self.vl_ind == 2:
+ ly[1].set_xdata(posx)
+ ly[1].set_zorder(nop)
+ self.q_ctrl[1].SetValue(str(pos_x))
+
+
+ def _get_cusor_lines(self, event):
+ """
+ Revmove or switch cursor line if drawn
+ :Param event: LeftClick mouse event
+ """
+ ax = event.inaxes
+ if hasattr(event, "action"):
+ dclick = event.action == 'dclick'
+ if ax is None or dclick:
+ # remove the vline
+ self._check_zoom_plot()
+ self.canvas.draw()
+ self.q_ctrl = None
+ return
+ if self.ly is not None and event.xdata is not None:
+ # Selecting a new line if cursor lines are displayed already
+ dqmin = math.fabs(event.xdata - self.ly[0].get_xdata())
+ dqmax = math.fabs(event.xdata - self.ly[1].get_xdata())
+ if not self.is_corfunc:
+ is_qmax = dqmin > dqmax
+ if is_qmax:
+ self.vl_ind = 1
+ else:
+ self.vl_ind = 0
+ else:
+ dqmax2 = math.fabs(event.xdata - self.ly[2].get_xdata())
+ closest = min(dqmin, dqmax, dqmax2)
+ self.vl_ind = { dqmin: 0, dqmax: 1, dqmax2: 2 }.get(closest)
+
+ def cusor_line(self, event):
+ """
+ Move the cursor line to write Q range
+ """
+ if self.q_ctrl is None:
+ return
+ # release a q range vline
+ if self.ly is not None and not self.leftdown:
+ for ly in self.ly:
+ ly.set_alpha(0.7)
+ self.canvas.draw()
+ return
+ ax = event.inaxes
+ if ax is None or not hasattr(event, 'action'):
+ return
+ end_drag = event.action != 'drag' and event.xdata is not None
+ nop = len(self.plots)
+ pos_x, _ = float(event.xdata), float(event.ydata)
+ try:
+ ly = self.ly
+ ly0x = ly[0].get_xdata()
+ ly1x = ly[1].get_xdata()
+ if ly0x == ly1x:
+ if ly[0].get_zorder() > ly[1].get_zorder():
+ self.vl_ind = 0
+ else:
+ self.vl_ind = 1
+ vl_ind = self.vl_ind
+ x_data = self.plots[self.cursor_id].x
+ xmin = x_data.min()
+ xmax = x_data.max()
+ indx = self._find_nearest(x_data, pos_x)
+ # Need to hold LeftButton to drag
+ if end_drag:
+ if event.button:
+ self._check_line_positions(pos_x, nop)
+ return
+ if indx >= len(x_data):
+ indx = len(x_data) - 1
+ pos_x = x_data[indx]
+ if xmin == ly1x:
+ vl_ind = 1
+ elif xmax == ly0x:
+ vl_ind = 0
+ else:
+ ly[vl_ind].set_xdata(pos_x)
+ ly[vl_ind].set_zorder(nop + 1)
+ self._check_line_positions(pos_x, nop)
+ ly[vl_ind].set_xdata(pos_x)
+ ly[vl_ind].set_alpha(1.0)
+ ly[vl_ind].set_zorder(nop + 1)
+ self.canvas.draw()
+ self.q_ctrl[vl_ind].SetValue(str(pos_x))
+ except:
+ logger.error(sys.exc_value)
+
+ def set_resizing(self, resizing=False):
+ """
+ Set the resizing (True/False)
+ """
+ self.resizing = resizing
+ # self.canvas.set_resizing(resizing)
+
+ def schedule_full_draw(self, func='append'):
+ """
+ Put self in schedule to full redraw list
+ """
+ # append/del this panel in the schedule list
+ self.parent.set_schedule_full_draw(self, func)
+
+ def remove_data_by_id(self, id):
+ """
+ Remove data from plot
+ """
+ if id in self.plots.keys():
+ data = self.plots[id]
+ self.graph.delete(data)
+ data_manager = self._manager.parent.get_data_manager()
+ data_list, theory_list = data_manager.get_by_id(id_list=[id])
+
+ if id in data_list.keys():
+ data = data_list[id]
+ if id in theory_list.keys():
+ data = theory_list[id]
+
+ del self.plots[id]
+ self.graph.render(self)
+ self.subplot.figure.canvas.draw_idle()
+ if len(self.graph.plottables) == 0:
+ # onRemove: graph is empty must be the panel must be destroyed
+ self.parent.delete_panel(self.uid)
+
+ def plot_data(self, data):
+ """
+ Data is ready to be displayed
+
+ :param event: data event
+ """
+ if data.__class__.__name__ == 'Data2D':
+ return
+ plot_keys = self.plots.keys()
+ if data.id in plot_keys:
+ # Recover panel prop.s
+ xlo, xhi = self.subplot.get_xlim()
+ ylo, yhi = self.subplot.get_ylim()
+ old_data = self.plots[data.id]
+ if self._is_changed_legend_label:
+ data.label = old_data.label
+ if old_data.__class__.__name__ == 'Data1D':
+ data.custom_color = old_data.custom_color
+ data.symbol = old_data.symbol
+ data.markersize = old_data.markersize
+ data.zorder = len(plot_keys)
+ # Replace data
+ self.graph.replace(data)
+ self.plots[data.id] = data
+ ## Set the view scale for all plots
+ try:
+ self._onEVT_FUNC_PROPERTY()
+ except Exception, exc:
+ wx.PostEvent(self.parent,
+ StatusEvent(status="Plotting Error: %s" % str(exc), info="error"))
+ if self.is_zoomed:
+ # Recover the x,y limits
+ self.subplot.set_xlim((xlo, xhi))
+ self.subplot.set_ylim((ylo, yhi))
+ else:
+ self.plots[data.id] = data
+ self.graph.add(self.plots[data.id])
+ data.zorder = len(plot_keys)
+ ## Set the view scale for all plots
+ try:
+ self._onEVT_FUNC_PROPERTY()
+ if IS_MAC:
+ # MAC: forcing to plot 2D avg
+ self.canvas._onDrawIdle()
+ except Exception, exc:
+ wx.PostEvent(self.parent, StatusEvent(status=\
+ "Plotting Error: %s" % str(exc), info="error"))
+ self.toolbar.update()
+ self.is_zoomed = False
+
+ def draw_plot(self):
+ """
+ Draw plot
+ """
+ self.draw()
+
+ def onLeftDown(self, event):
+ """
+ left button down and ready to drag
+ Display the position of the mouse on the statusbar
+ """
+ # self.parent.set_plot_unfocus()
+ self._get_cusor_lines(event)
+ ax = event.inaxes
+ PlotPanel.onLeftDown(self, event)
+ if ax is not None:
+ try:
+ pos_x = float(event.xdata) # / size_x
+ pos_y = float(event.ydata) # / size_y
+ pos_x = "%8.3g" % pos_x
+ pos_y = "%8.3g" % pos_y
+ self.position = str(pos_x), str(pos_y)
+ wx.PostEvent(self.parent, StatusEvent(status=self.position))
+ except:
+ self.position = None
+ # unfocus all
+ self.parent.set_plot_unfocus()
+ # post nd event to notify guiframe that this panel is on focus
+ wx.PostEvent(self.parent, PanelOnFocusEvent(panel=self))
+
+
+ def _ontoggle_hide_error(self, event):
+ """
+ Toggle error display to hide or show
+ """
+ menu = event.GetEventObject()
+ event_id = event.GetId()
+ self.set_selected_from_menu(menu, event_id)
+ # Check zoom
+ xlo, xhi = self.subplot.get_xlim()
+ ylo, yhi = self.subplot.get_ylim()
+
+ selected_plot = self.plots[self.graph.selected_plottable]
+ if self.hide_menu.GetText() == "Hide Error Bar":
+ selected_plot.hide_error = True
+ else:
+ selected_plot.hide_error = False
+ ## increment graph color
+ self.graph.render(self)
+ self.subplot.figure.canvas.draw_idle()
+ if self.is_zoomed:
+ # Recover the x,y limits
+ self.subplot.set_xlim((xlo, xhi))
+ self.subplot.set_ylim((ylo, yhi))
+ self.graph.selected_plottable = None
+
+
+ def _onRemove(self, event):
+ """
+ Remove a plottable from the graph and render the graph
+
+ :param event: Menu event
+
+ """
+ menu = event.GetEventObject()
+ event_id = event.GetId()
+ self.set_selected_from_menu(menu, event_id)
+ ## Check if there is a selected graph to remove
+ if self.graph.selected_plottable in self.plots.keys():
+ graph_id = self.graph.selected_plottable
+ self.remove_data_by_id(graph_id)
+
+ def onContextMenu(self, event):
+ """
+ 1D plot context menu
+
+ :param event: wx context event
+
+ """
+ self._slicerpop = PanelMenu()
+ self._slicerpop.set_plots(self.plots)
+ self._slicerpop.set_graph(self.graph)
+ ids = iter(self._menu_ids)
+
+ # Various plot options
+ wx_id = ids.next()
+ self._slicerpop.Append(wx_id, '&Save Image', 'Save image as PNG')
+ wx.EVT_MENU(self, wx_id, self.onSaveImage)
+ wx_id = ids.next()
+ self._slicerpop.Append(wx_id, '&Print Image', 'Print image ')
+ wx.EVT_MENU(self, wx_id, self.onPrint)
+
+ wx_id = ids.next()
+ self._slicerpop.Append(wx_id, '&Copy to Clipboard',
+ 'Copy to the clipboard')
+ wx.EVT_MENU(self, wx_id, self.OnCopyFigureMenu)
+
+ self._slicerpop.AppendSeparator()
+
+ for plot in self.plots.values():
+ # title = plot.title
+ name = plot.name
+ plot_menu = wx.Menu()
+ if self.graph.selected_plottable:
+ if not self.graph.selected_plottable in self.plots.keys():
+ continue
+ if plot != self.plots[self.graph.selected_plottable]:
+ continue
+
+ wx_id = ids.next()
+ plot_menu.Append(wx_id, "&DataInfo", name)
+ wx.EVT_MENU(self, wx_id, self. _onDataShow)
+ wx_id = ids.next()
+ plot_menu.Append(wx_id, "&Save Points as a File", name)
+ wx.EVT_MENU(self, wx_id, self._onSave)
+ plot_menu.AppendSeparator()
+
+ # add menu of other plugins
+ item_list = self.parent.get_current_context_menu(self)
+ if (item_list is not None) and (len(item_list)):
+ for item, wx_id in zip(item_list, [ids.next() for i in range(len(item_list))]):
+ try:
+ plot_menu.Append(wx_id, item[0], name)
+ wx.EVT_MENU(self, wx_id, item[2])
+ except:
+ msg = "ModelPanel1D.onContextMenu: "
+ msg += "bad menu item %s" % sys.exc_value
+ wx.PostEvent(self.parent, StatusEvent(status=msg))
+ plot_menu.AppendSeparator()
+
+ if self.parent.ClassName.count('wxDialog') == 0:
+ if plot.id != 'fit':
+ wx_id = ids.next()
+ plot_menu.Append(wx_id, '&Linear Fit', name)
+ wx.EVT_MENU(self, wx_id, self.onFitting)
+ plot_menu.AppendSeparator()
+
+ wx_id = ids.next()
+ plot_menu.Append(wx_id, "Remove", name)
+ wx.EVT_MENU(self, wx_id, self._onRemove)
+ if not plot.is_data:
+ wx_id = ids.next()
+ plot_menu.Append(wx_id, '&Freeze', name)
+ wx.EVT_MENU(self, wx_id, self.onFreeze)
+ plot_menu.AppendSeparator()
+
+ if plot.is_data:
+ wx_id = ids.next()
+ self.hide_menu = plot_menu.Append(wx_id, "Hide Error Bar", name)
+
+ if plot.dy is not None and plot.dy != []:
+ if plot.hide_error:
+ self.hide_menu.SetText('Show Error Bar')
+ else:
+ self.hide_menu.SetText('Hide Error Bar')
+ else:
+ self.hide_menu.Enable(False)
+ wx.EVT_MENU(self, wx_id, self._ontoggle_hide_error)
+
+ plot_menu.AppendSeparator()
+
+ wx_id = ids.next()
+ plot_menu.Append(wx_id, '&Modify Plot Property', name)
+ wx.EVT_MENU(self, wx_id, self.createAppDialog)
+ wx_id = ids.next()
+ # plot_menu.SetTitle(name)
+ self._slicerpop.AppendMenu(wx_id, '&%s' % name, plot_menu)
+ # Option to hide
+ # TODO: implement functionality to hide a plottable (legend click)
+
+ self._slicerpop.AppendSeparator()
+ loc_menu = wx.Menu()
+ for label in self._loc_labels:
+ wx_id = ids.next()
+ loc_menu.Append(wx_id, str(label), str(label))
+ wx.EVT_MENU(self, wx_id, self.onChangeLegendLoc)
+
+ wx_id = ids.next()
+ self._slicerpop.Append(wx_id, '&Modify Graph Appearance',
+ 'Modify graph appearance')
+ wx.EVT_MENU(self, wx_id, self.modifyGraphAppearance)
+ self._slicerpop.AppendSeparator()
+
+
+ if self.position is not None:
+ wx_id = ids.next()
+ self._slicerpop.Append(wx_id, '&Add Text')
+ wx.EVT_MENU(self, wx_id, self._on_addtext)
+ wx_id = ids.next()
+ self._slicerpop.Append(wx_id, '&Remove Text')
+ wx.EVT_MENU(self, wx_id, self._on_removetext)
+ self._slicerpop.AppendSeparator()
+ wx_id = ids.next()
+ self._slicerpop.Append(wx_id, '&Change Scale')
+ wx.EVT_MENU(self, wx_id, self._onProperties)
+ self._slicerpop.AppendSeparator()
+ wx_id = ids.next()
+ self._slicerpop.Append(wx_id, '&Set Graph Range')
+ wx.EVT_MENU(self, wx_id, self.onSetRange)
+ wx_id = ids.next()
+ self._slicerpop.Append(wx_id, '&Reset Graph Range')
+ wx.EVT_MENU(self, wx_id, self.onResetGraph)
+
+ if self.parent.ClassName.count('wxDialog') == 0:
+ self._slicerpop.AppendSeparator()
+ wx_id = ids.next()
+ self._slicerpop.Append(wx_id, '&Window Title')
+ wx.EVT_MENU(self, wx_id, self.onChangeCaption)
+ try:
+ pos_evt = event.GetPosition()
+ pos = self.ScreenToClient(pos_evt)
+ except:
+ pos_x, pos_y = self.toolbar.GetPositionTuple()
+ pos = (pos_x, pos_y + 5)
+ self.PopupMenu(self._slicerpop, pos)
+
+ def onSetRange(self, event):
+ # Display dialog
+ # self.subplot.set_xlim((low, high))
+ # self.subplot.set_ylim((low, high))
+ from sas.sasgui.plottools.RangeDialog import RangeDialog
+ d = RangeDialog(self, -1)
+ xlim = self.subplot.get_xlim()
+ ylim = self.subplot.get_ylim()
+ d.SetXRange(xlim)
+ d.SetYRange(ylim)
+ if d.ShowModal() == wx.ID_OK:
+ x_range = d.GetXRange()
+ y_range = d.GetYRange()
+ if x_range is not None and y_range is not None:
+ self.subplot.set_xlim(x_range)
+ self.subplot.set_ylim(y_range)
+ self.subplot.figure.canvas.draw_idle()
+ self.is_zoomed = True
+ d.Destroy()
+
+ def onFreeze(self, event):
+ """
+ on Freeze data
+ """
+ menu = event.GetEventObject()
+ wx_id = event.GetId()
+ self.set_selected_from_menu(menu, wx_id)
+ plot = self.plots[self.graph.selected_plottable]
+ self.parent.onfreeze([plot.id])
+
+ def _onSave(self, evt):
+ """
+ Save a data set to a text file
+
+ :param evt: Menu event
+
+ """
+ menu = evt.GetEventObject()
+ event_id = evt.GetId()
+ self.set_selected_from_menu(menu, event_id)
+ data = self.plots[self.graph.selected_plottable]
+ default_name = data.label
+ if default_name.count('.') > 0:
+ default_name = default_name.split('.')[0]
+ default_name += "_out"
+ if self.parent is not None:
+ self.parent.save_data1d(data, default_name)
+
+ def _onDataShow(self, evt):
+ """
+ Show the data set in text
+
+ :param evt: Menu event
+
+ """
+ menu = evt.GetEventObject()
+ event_id = evt.GetId()
+ self.set_selected_from_menu(menu, event_id)
+ data = self.plots[self.graph.selected_plottable]
+ default_name = data.label
+ if default_name.count('.') > 0:
+ default_name = default_name.split('.')[0]
+ # default_name += "_out"
+ if self.parent is not None:
+ self.parent.show_data1d(data, default_name)
+
+ def _on_hide(self, event):
+ """
+ Hides the plot when button is pressed
+ """
+ if self.parent is not None:
+ self.parent.hide_panel(self.uid)
+
+ def on_close(self, event):
+ """
+ On Close Event
+ """
+ ID = self.uid
+ self.parent.delete_panel(ID)
+
+ def createAppDialog(self, event):
+ """
+ Create the custom dialog for fit appearance modification
+ """
+ menu = event.GetEventObject()
+ event_id = event.GetId()
+ self.set_selected_from_menu(menu, event_id)
+ self.appearance_selected_plot = \
+ self.plots[self.graph.selected_plottable]
+ # find current properties
+ curr_color = self.appearance_selected_plot.custom_color
+ curr_symbol = self.appearance_selected_plot.symbol
+ curr_size = self.appearance_selected_plot.markersize
+ curr_label = self.appearance_selected_plot.label
+
+ if curr_color is None:
+ curr_color = self._color_labels['Blue']
+ curr_symbol = 13
+
+ self.appD = appearanceDialog(self, 'Modify Plot Property')
+ icon = self.parent.GetIcon()
+ self.appD.SetIcon(icon)
+ self.appD.set_defaults(float(curr_size), int(curr_color),
+ str(appearanceDialog.find_key(self.get_symbol_label(),
+ int(curr_symbol))), curr_label)
+ self.appD.Bind(wx.EVT_CLOSE, self.on_AppDialog_close)
+ self.graph.selected_plottable = None
+
+ def on_AppDialog_close(self, event):
+ """
+ on_Modify Plot Property_close
+ """
+ if self.appD.okay_clicked == True:
+ info = self.appD.get_current_values()
+ self.appearance_selected_plot.custom_color = \
+ self._color_labels[info[1].encode('ascii', 'ignore')]
+
+ self.appearance_selected_plot.markersize = float(info[0])
+ self.appearance_selected_plot.symbol = \
+ self.get_symbol_label()[info[2]]
+ self.appearance_selected_plot.label = str(info[3])
+ self.appD.Destroy()
+ self._check_zoom_plot()
+
+ def modifyGraphAppearance(self, event):
+ """
+ On Modify Graph Appearance
+ """
+ self.graphApp = graphAppearance(self, 'Modify Graph Appearance')
+ icon = self.parent.GetIcon()
+ self.graphApp.SetIcon(icon)
+ self.graphApp.setDefaults(self.grid_on, self.legend_on,
+ self.xaxis_label, self.yaxis_label,
+ self.xaxis_unit, self.yaxis_unit,
+ self.xaxis_font, self.yaxis_font,
+ find_key(self.get_loc_label(), self.legendLoc),
+ self.xcolor, self.ycolor,
+ self.is_xtick, self.is_ytick)
+ self.graphApp.Bind(wx.EVT_CLOSE, self.on_graphApp_close)
+
+ def on_graphApp_close(self, event):
+ """
+ Gets values from graph appearance dialog and sends them off
+ to modify the plot
+ """
+ graph_app = self.graphApp
+ toggle_grid = graph_app.get_togglegrid()
+ legend_loc = graph_app.get_legend_loc()
+ toggle_legend = graph_app.get_togglelegend()
+
+ self.onGridOnOff(toggle_grid)
+ self.ChangeLegendLoc(legend_loc)
+ self.onLegend(toggle_legend)
+
+ self.xaxis_label = graph_app.get_xlab()
+ self.yaxis_label = graph_app.get_ylab()
+ self.xaxis_unit = graph_app.get_xunit()
+ self.yaxis_unit = graph_app.get_yunit()
+ self.xaxis_font = graph_app.get_xfont()
+ self.yaxis_font = graph_app.get_yfont()
+ self.is_xtick = graph_app.get_xtick_check()
+ self.is_ytick = graph_app.get_ytick_check()
+ if self.is_xtick:
+ self.xaxis_tick = self.xaxis_font
+ if self.is_ytick:
+ self.yaxis_tick = self.yaxis_font
+
+ self.xaxis(self.xaxis_label, self.xaxis_unit,
+ graph_app.get_xfont(), graph_app.get_xcolor(),
+ self.xaxis_tick)
+ self.yaxis(self.yaxis_label, self.yaxis_unit,
+ graph_app.get_yfont(), graph_app.get_ycolor(),
+ self.yaxis_tick)
+
+ graph_app.Destroy()
diff --git a/src/sas/sasgui/guiframe/local_perspectives/plotting/Plotter2D.py b/src/sas/sasgui/guiframe/local_perspectives/plotting/Plotter2D.py
index 5672338..8070ab2 100644
--- a/src/sas/sasgui/guiframe/local_perspectives/plotting/Plotter2D.py
+++ b/src/sas/sasgui/guiframe/local_perspectives/plotting/Plotter2D.py
@@ -1,799 +1,801 @@
-
-################################################################################
-#This software was developed by the University of Tennessee as part of the
-#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
-#project funded by the US National Science Foundation.
-#
-#See the license text in license.txt
-#
-#copyright 2008, University of Tennessee
-################################################################################
-
-
-import wx
-import sys
-import math
-import numpy
-import logging
-from sas.sasgui.plottools.PlotPanel import PlotPanel
-from sas.sasgui.plottools.plottables import Graph
-from sas.sasgui.plottools.TextDialog import TextDialog
-from sas.sasgui.guiframe.events import StatusEvent
-from sas.sasgui.guiframe.events import NewPlotEvent
-from sas.sasgui.guiframe.events import PanelOnFocusEvent
-from sas.sasgui.guiframe.events import SlicerEvent
-from sas.sasgui.guiframe.utils import PanelMenu
-from sas.sasgui.guiframe.local_perspectives.plotting.binder import BindArtist
-from Plotter1D import ModelPanel1D
-from sas.sasgui.plottools.toolbar import NavigationToolBar
-from matplotlib.font_manager import FontProperties
-from graphAppearance import graphAppearance
-(InternalEvent, EVT_INTERNAL) = wx.lib.newevent.NewEvent()
-
-DEFAULT_QMAX = 0.05
-DEFAULT_QSTEP = 0.001
-DEFAULT_BEAM = 0.005
-BIN_WIDTH = 1.0
-
-
-def find_key(dic, val):
- """return the key of dictionary dic given the value"""
- return [k for k, v in dic.iteritems() if v == val][0]
-
-
-class NavigationToolBar2D(NavigationToolBar):
- """
- """
- def __init__(self, canvas, parent=None):
- NavigationToolBar.__init__(self, canvas=canvas, parent=parent)
-
- def delete_option(self):
- """
- remove default toolbar item
- """
- #delete reset button
- self.DeleteToolByPos(0)
- #delete dragging
- self.DeleteToolByPos(2)
- #delete unwanted button that configures subplot parameters
- self.DeleteToolByPos(4)
-
- def add_option(self):
- """
- add item to the toolbar
- """
- #add button
- id_context = wx.NewId()
- context_tip = 'Graph Menu'
- context = wx.ArtProvider.GetBitmap(wx.ART_LIST_VIEW, wx.ART_TOOLBAR)
- self.InsertSimpleTool(0, id_context, context, context_tip, context_tip)
- wx.EVT_TOOL(self, id_context, self.parent.onToolContextMenu)
- self.InsertSeparator(1)
- #add print button
- id_print = wx.NewId()
- print_bmp = wx.ArtProvider.GetBitmap(wx.ART_PRINT, wx.ART_TOOLBAR)
- self.AddSimpleTool(id_print, print_bmp, 'Print', 'Activate printing')
- wx.EVT_TOOL(self, id_print, self.on_print)
-
-
-class ModelPanel2D(ModelPanel1D):
- """
- Plot panel for use with the GUI manager
- """
-
- ## Internal name for the AUI manager
- window_name = "plotpanel"
- ## Title to appear on top of the window
- window_caption = "Plot Panel"
- ## Flag to tell the GUI manager that this panel is not
- # tied to any perspective
- ALWAYS_ON = True
- ## Group ID
- group_id = None
-
-
- def __init__(self, parent, id=-1, data2d=None, color=None,
- dpi=None, style=wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs):
- """
- Initialize the panel
- """
- ModelPanel1D.__init__(self, parent, id=id, style=style, **kwargs)
- self.parent = parent
- ## Reference to the parent window
- if hasattr(parent, "parent"):
- self.parent = self.parent.parent
- ## Dictionary containing Plottables
- self.plots = {}
- ## Save reference of the current plotted
- self.data2D = data2d
- ## Unique ID (from gui_manager)
- self.uid = None
- ## Action IDs for internal call-backs
- self.action_ids = {}
- ## Create Artist and bind it
- self.connect = BindArtist(self.subplot.figure)
- ## Beam stop
- self.beamstop_radius = DEFAULT_BEAM
- ## to set the order of lines drawn first.
- self.slicer_z = 5
- ## Reference to the current slicer
- self.slicer = None
- ## event to send slicer info
- self.Bind(EVT_INTERNAL, self._onEVT_INTERNAL)
-
- self.axes_frozen = False
- ## panel that contains result from slicer motion (ex: Boxsum info)
- self.panel_slicer = None
- self.title_label = None
- self.title_font = None
- self.title_color = 'black'
- ## Graph
- self.graph = Graph()
- self.graph.xaxis("\\rm{Q}", 'A^{-1}')
- self.graph.yaxis("\\rm{Intensity} ", "cm^{-1}")
- self.graph.render(self)
- ## store default value of zmin and zmax
- self.default_zmin_ctl = self.zmin_2D
- self.default_zmax_ctl = self.zmax_2D
-
- def on_plot_qrange(self, event=None):
- """
- On Qmin Qmax vertical line event
- """
- # Not implemented
- if event == None:
- return
- event.Skip()
-
- def onLeftDown(self, event):
- """
- left button down and ready to drag
-
- """
- # Check that the LEFT button was pressed
- PlotPanel.onLeftDown(self, event)
- ax = event.inaxes
- if ax != None:
- # data coordinate position
- pos_x = "%8.3g" % event.xdata
- pos_y = "%8.3g" % event.ydata
- position = "x: %s y: %s" % (pos_x, pos_y)
- wx.PostEvent(self.parent, StatusEvent(status=position))
- self.plottable_selected(self.data2D.id)
- self._manager.set_panel_on_focus(self)
- wx.PostEvent(self.parent, PanelOnFocusEvent(panel=self))
-
- def add_toolbar(self):
- """
- add toolbar
- """
- self.enable_toolbar = True
- self.toolbar = NavigationToolBar2D(parent=self, canvas=self.canvas)
- self.toolbar.Realize()
- # On Windows platform, default window size is incorrect, so set
- # toolbar width to figure width.
- _, th = self.toolbar.GetSizeTuple()
- fw, _ = self.canvas.GetSizeTuple()
- self.toolbar.SetSize(wx.Size(fw, th))
- self.sizer.Add(self.toolbar, 0, wx.LEFT | wx.EXPAND)
- # update the axes menu on the toolbar
- self.toolbar.update()
-
- def plot_data(self, data):
- """
- Data is ready to be displayed
-
- :TODO: this name should be changed to something more appropriate
- Don't forget that changing this name will mean changing code
- in plotting.py
-
- :param event: data event
- """
- xlo = None
- xhi = None
- ylo = None
- yhi = None
- if data.__class__.__name__ == 'Data1D':
- return
- ## Update self.data2d with the current plot
- self.data2D = data
- if data.id in self.plots.keys():
- #replace
- xlo, xhi = self.subplot.get_xlim()
- ylo, yhi = self.subplot.get_ylim()
- self.graph.replace(data)
- self.plots[data.id] = data
- else:
- self.plots[data.id] = data
- self.graph.add(self.plots[data.id])
- # update qmax with the new xmax of data plotted
- self.qmax = data.xmax
- self.slicer = None
- # Check axis labels
- #TODO: Should re-factor this
- ## render the graph with its new content
- #data2D: put 'Pixel (Number)' for axis title and unit in case of having no detector info and none in _units
- if len(data.detector) < 1:
- if len(data._xunit) < 1 and len(data._yunit) < 1:
- data._xaxis = '\\rm{x}'
- data._yaxis = '\\rm{y}'
- data._xunit = 'pixel'
- data._yunit = 'pixel'
- # graph properties
- self.graph.xaxis(data._xaxis, data._xunit)
- self.graph.yaxis(data._yaxis, data._yunit)
- if self._is_changed_legend_label:
- data.label = self.title_label
- if data.label == None:
- data.label = data.name
- if not self.title_font:
- self.graph.title(data.label)
- self.graph.render(self)
- # Set the axis labels on subplot
- self._set_axis_labels()
- self.draw_plot()
- else:
- self.graph.render(self)
- self.draw_plot()
- self.subplot.set_title(label=data.label,
- fontproperties=self.title_font,
- color=self.title_color)
- self.subplot.figure.canvas.draw_idle()
- ## store default value of zmin and zmax
- self.default_zmin_ctl = self.zmin_2D
- self.default_zmax_ctl = self.zmax_2D
- if not self.is_zoomed:
- return
- # Recover the x,y limits
- if xlo and xhi and ylo and yhi:
- if xlo > data.xmin and xhi < data.xmax and \
- ylo > data.ymin and yhi < data.ymax:
- self.subplot.set_xlim((xlo, xhi))
- self.subplot.set_ylim((ylo, yhi))
- else:
- self.toolbar.update()
- self.is_zoomed = False
-
- def _set_axis_labels(self):
- """
- Set axis labels
- """
- data = self.data2D
- # control axis labels from the panel itself
- yname, yunits = data.get_yaxis()
- if self.yaxis_label != None:
- yname = self.yaxis_label
- yunits = self.yaxis_unit
- else:
- self.yaxis_label = yname
- self.yaxis_unit = yunits
- xname, xunits = data.get_xaxis()
- if self.xaxis_label != None:
- xname = self.xaxis_label
- xunits = self.xaxis_unit
- else:
- self.xaxis_label = xname
- self.xaxis_unit = xunits
- self.xaxis(xname, xunits, self.xaxis_font,
- self.xaxis_color, self.xaxis_tick)
- self.yaxis(yname, yunits, self.yaxis_font,
- self.yaxis_color, self.yaxis_tick)
-
- def onContextMenu(self, event):
- """
- 2D plot context menu
-
- :param event: wx context event
-
- """
- ids = iter(self._menu_ids)
- slicerpop = PanelMenu()
- slicerpop.set_plots(self.plots)
- slicerpop.set_graph(self.graph)
-
- wx_id = ids.next()
- slicerpop.Append(wx_id, '&Save Image', 'Save image as png')
- wx.EVT_MENU(self, wx_id, self.onSaveImage)
-
- wx_id = ids.next()
- slicerpop.Append(wx_id, '&Print Image', 'Print image')
- wx.EVT_MENU(self, wx_id, self.onPrint)
-
- wx_id = ids.next()
- slicerpop.Append(wx_id, '&Copy to Clipboard', 'Copy to the clipboard')
- wx.EVT_MENU(self, wx_id, self.OnCopyFigureMenu)
- slicerpop.AppendSeparator()
- # saving data
- plot = self.data2D
- wx_id = ids.next()
- slicerpop.Append(wx_id, "&Data Info")
- wx.EVT_MENU(self, wx_id, self._onDataShow)
-
- wx_id = ids.next()
- slicerpop.Append(wx_id, "&Save as a File (DAT)")
- self.action_ids[str(wx_id)] = plot
- wx.EVT_MENU(self, wx_id, self._onSave)
-
- slicerpop.AppendSeparator()
- if len(self.data2D.detector) <= 1:
- item_list = self.parent.get_current_context_menu(self)
- if (not item_list == None) and (not len(item_list) == 0) and\
- self.data2D.name.split(" ")[0] != 'Residuals':
- for item, wx_id in zip(item_list, [ids.next() for i in range(len(item_list))]):
- try:
- slicerpop.Append(wx_id, item[0], item[1])
- wx.EVT_MENU(self, wx_id, item[2])
- except:
- msg = "ModelPanel1D.onContextMenu: "
- msg += "bad menu item %s" % sys.exc_value
- wx.PostEvent(self.parent, StatusEvent(status=msg))
- slicerpop.AppendSeparator()
-
- wx_id = ids.next()
- slicerpop.Append(wx_id, '&Perform Circular Average')
- wx.EVT_MENU(self, wx_id, self.onCircular) \
- # For Masked Data
- if not plot.mask.all():
- wx_id = ids.next()
- slicerpop.Append(wx_id, '&Masked Circular Average')
- wx.EVT_MENU(self, wx_id, self.onMaskedCircular)
- wx_id = ids.next()
- slicerpop.Append(wx_id, '&Sector [Q View]')
- wx.EVT_MENU(self, wx_id, self.onSectorQ)
- wx_id = ids.next()
- slicerpop.Append(wx_id, '&Annulus [Phi View ]')
- wx.EVT_MENU(self, wx_id, self.onSectorPhi)
- wx_id = ids.next()
- slicerpop.Append(wx_id, '&Box Sum')
- wx.EVT_MENU(self, wx_id, self.onBoxSum)
- wx_id = ids.next()
- slicerpop.Append(wx_id, '&Box Averaging in Qx')
- wx.EVT_MENU(self, wx_id, self.onBoxavgX)
- wx_id = ids.next()
- slicerpop.Append(wx_id, '&Box Averaging in Qy')
- wx.EVT_MENU(self, wx_id, self.onBoxavgY)
- if self.slicer != None:
- wx_id = ids.next()
- slicerpop.Append(wx_id, '&Clear Slicer')
- wx.EVT_MENU(self, wx_id, self.onClearSlicer)
- if self.slicer.__class__.__name__ != "BoxSum":
- wx_id = ids.next()
- slicerpop.Append(wx_id, '&Edit Slicer Parameters')
- wx.EVT_MENU(self, wx_id, self._onEditSlicer)
- slicerpop.AppendSeparator()
-
- wx_id = ids.next()
- slicerpop.Append(wx_id, '&Edit Graph Label', 'Edit Graph Label')
- wx.EVT_MENU(self, wx_id, self.onEditLabels)
- slicerpop.AppendSeparator()
-
- # ILL mod here
-
- wx_id = ids.next()
- slicerpop.Append(wx_id, '&Modify graph appearance', 'Modify graph appearance')
- wx.EVT_MENU(self, wx_id, self.modifyGraphAppearance)
- slicerpop.AppendSeparator()
-
- wx_id = ids.next()
- slicerpop.Append(wx_id, '&2D Color Map')
- wx.EVT_MENU(self, wx_id, self._onEditDetector)
- slicerpop.AppendSeparator()
-
- wx_id = ids.next()
- slicerpop.Append(wx_id, '&Toggle Linear/Log Scale')
- wx.EVT_MENU(self, wx_id, self._onToggleScale)
-
- slicerpop.AppendSeparator()
- wx_id = ids.next()
- slicerpop.Append(wx_id, '&Window Title')
- wx.EVT_MENU(self, wx_id, self.onChangeCaption)
-
- try:
- pos_evt = event.GetPosition()
- pos = self.ScreenToClient(pos_evt)
- except:
- pos_x, pos_y = self.toolbar.GetPositionTuple()
- pos = (pos_x, pos_y + 5)
- self.PopupMenu(slicerpop, pos)
-
- def onEditLabels(self, event):
- """
- Edit legend label
- """
- try:
- selected_plot = self.plots[self.graph.selected_plottable]
- except:
- selected_plot = self.plots[self.data2D.id]
- label = selected_plot.label
- dial = TextDialog(None, -1, 'Change Label', label)
- if dial.ShowModal() == wx.ID_OK:
- try:
- FONT = FontProperties()
- newlabel = dial.getText()
- font = FONT.copy()
- font.set_size(dial.getSize())
- font.set_family(dial.getFamily())
- font.set_style(dial.getStyle())
- font.set_weight(dial.getWeight())
- colour = dial.getColor()
- if len(newlabel) > 0:
- # update Label
- selected_plot.label = newlabel
- self.graph.title(newlabel)
- self.title_label = selected_plot.label
- self.title_font = font
- self.title_color = colour
- ## render the graph
- self.subplot.set_title(label=self.title_label,
- fontproperties=self.title_font,
- color=self.title_color)
- self._is_changed_legend_label = True
- self.subplot.figure.canvas.draw_idle()
- except:
- msg = "Add Text: Error. Check your property values..."
- logging.error(msg)
- if self.parent != None:
- wx.PostEvent(self.parent, StatusEvent(status=msg))
- dial.Destroy()
-
- def _onEditDetector(self, event):
- """
- Allow to view and edits detector parameters
-
- :param event: wx.menu event
-
- """
- import detector_dialog
- dialog = detector_dialog.DetectorDialog(self, -1, base=self.parent,
- reset_zmin_ctl=self.default_zmin_ctl,
- reset_zmax_ctl=self.default_zmax_ctl, cmap=self.cmap)
- ## info of current detector and data2D
- xnpts = len(self.data2D.x_bins)
- ynpts = len(self.data2D.y_bins)
- xmax = max(self.data2D.xmin, self.data2D.xmax)
- ymax = max(self.data2D.ymin, self.data2D.ymax)
- qmax = math.sqrt(math.pow(xmax, 2) + math.pow(ymax, 2))
- ## set dialog window content
- dialog.setContent(xnpts=xnpts, ynpts=ynpts, qmax=qmax,
- beam=self.data2D.xmin,
- zmin=self.zmin_2D,
- zmax=self.zmax_2D)
- if dialog.ShowModal() == wx.ID_OK:
- evt = dialog.getContent()
- self.zmin_2D = evt.zmin
- self.zmax_2D = evt.zmax
- self.cmap = evt.cmap
- dialog.Destroy()
- ## Redraw the current image
- self.image(data=self.data2D.data,
- qx_data=self.data2D.qx_data,
- qy_data=self.data2D.qy_data,
- xmin=self.data2D.xmin,
- xmax=self.data2D.xmax,
- ymin=self.data2D.ymin,
- ymax=self.data2D.ymax,
- zmin=self.zmin_2D,
- zmax=self.zmax_2D,
- cmap=self.cmap,
- color=0, symbol=0, label=self.data2D.name)
- self.subplot.figure.canvas.draw_idle()
-
- def freeze_axes(self):
- """
- """
- self.axes_frozen = True
-
- def thaw_axes(self):
- """
- """
- self.axes_frozen = False
-
- def onMouseMotion(self, event):
- """
- """
- pass
-
- def onWheel(self, event):
- """
- """
- pass
-
- def update(self, draw=True):
- """
- Respond to changes in the model by recalculating the
- profiles and resetting the widgets.
- """
- self.draw_plot()
-
- def _getEmptySlicerEvent(self):
- """
- create an empty slicervent
- """
- return SlicerEvent(type=None, params=None, obj_class=None)
-
- def _onEVT_INTERNAL(self, event):
- """
- Draw the slicer
-
- :param event: wx.lib.newevent (SlicerEvent) containing slicer
- parameter
-
- """
- self._setSlicer(event.slicer)
-
- def _setSlicer(self, slicer):
- """
- Clear the previous slicer and create a new one.Post an internal
- event.
-
- :param slicer: slicer class to create
-
- """
- ## Clear current slicer
- if not self.slicer == None:
- self.slicer.clear()
- ## Create a new slicer
- self.slicer_z += 1
- self.slicer = slicer(self, self.subplot, zorder=self.slicer_z)
- self.subplot.set_ylim(self.data2D.ymin, self.data2D.ymax)
- self.subplot.set_xlim(self.data2D.xmin, self.data2D.xmax)
- ## Draw slicer
- self.update()
- self.slicer.update()
- msg = "Plotter2D._setSlicer %s" % self.slicer.__class__.__name__
- wx.PostEvent(self.parent, StatusEvent(status=msg))
- # Post slicer event
- event = self._getEmptySlicerEvent()
- event.type = self.slicer.__class__.__name__
- event.obj_class = self.slicer.__class__
- event.params = self.slicer.get_params()
- wx.PostEvent(self, event)
-
- def onMaskedCircular(self, event):
- """
- perform circular averaging on Data2D with mask if it exists
-
- :param event: wx.menu event
-
- """
- self.onCircular(event, True)
-
- def onCircular(self, event, ismask=False):
- """
- perform circular averaging on Data2D
-
- :param event: wx.menu event
-
- """
- # Find the best number of bins
- npt = math.sqrt(len(self.data2D.data[numpy.isfinite(self.data2D.data)]))
- npt = math.floor(npt)
- from sas.sascalc.dataloader.manipulations import CircularAverage
- ## compute the maximum radius of data2D
- self.qmax = max(math.fabs(self.data2D.xmax),
- math.fabs(self.data2D.xmin))
- self.ymax = max(math.fabs(self.data2D.ymax),
- math.fabs(self.data2D.ymin))
- self.radius = math.sqrt(math.pow(self.qmax, 2) + math.pow(self.ymax, 2))
- ##Compute beam width
- bin_width = (self.qmax + self.qmax) / npt
- ## Create data1D circular average of data2D
- Circle = CircularAverage(r_min=0, r_max=self.radius,
- bin_width=bin_width)
- circ = Circle(self.data2D, ismask=ismask)
- from sas.sasgui.guiframe.dataFitting import Data1D
- if hasattr(circ, "dxl"):
- dxl = circ.dxl
- else:
- dxl = None
- if hasattr(circ, "dxw"):
- dxw = circ.dxw
- else:
- dxw = None
-
- new_plot = Data1D(x=circ.x, y=circ.y, dy=circ.dy, dx=circ.dx)
- new_plot.dxl = dxl
- new_plot.dxw = dxw
- new_plot.name = "Circ avg " + self.data2D.name
- new_plot.source = self.data2D.source
- #new_plot.info = self.data2D.info
- new_plot.interactive = True
- new_plot.detector = self.data2D.detector
-
- ## If the data file does not tell us what the axes are, just assume...
- new_plot.xaxis("\\rm{Q}", "A^{-1}")
- if hasattr(self.data2D, "scale") and \
- self.data2D.scale == 'linear':
- new_plot.ytransform = 'y'
- new_plot.yaxis("\\rm{Residuals} ", "normalized")
- else:
- new_plot.yaxis("\\rm{Intensity} ", "cm^{-1}")
-
- new_plot.group_id = "2daverage" + self.data2D.name
- new_plot.id = "Circ avg " + self.data2D.name
- new_plot.is_data = True
- self.parent.update_theory(data_id=self.data2D.id, \
- theory=new_plot)
- wx.PostEvent(self.parent,
- NewPlotEvent(plot=new_plot, title=new_plot.name))
-
- def _onEditSlicer(self, event):
- """
- Is available only when a slicer is drawn.Create a dialog
- window where the user can enter value to reset slicer
- parameters.
-
- :param event: wx.menu event
-
- """
- if self.slicer != None:
- from SlicerParameters import SlicerParameterPanel
- dialog = SlicerParameterPanel(self, -1, "Slicer Parameters")
- dialog.set_slicer(self.slicer.__class__.__name__,
- self.slicer.get_params())
- if dialog.ShowModal() == wx.ID_OK:
- dialog.Destroy()
-
- def onSectorQ(self, event):
- """
- Perform sector averaging on Q and draw sector slicer
- """
- from SectorSlicer import SectorInteractor
- self.onClearSlicer(event)
- wx.PostEvent(self, InternalEvent(slicer=SectorInteractor))
-
- def onSectorPhi(self, event):
- """
- Perform sector averaging on Phi and draw annulus slicer
- """
- from AnnulusSlicer import AnnulusInteractor
- self.onClearSlicer(event)
- wx.PostEvent(self, InternalEvent(slicer=AnnulusInteractor))
-
- def onBoxSum(self, event):
- """
- """
- from sas.sasgui.guiframe.gui_manager import MDIFrame
- from boxSum import BoxSum
- self.onClearSlicer(event)
- self.slicer_z += 1
- self.slicer = BoxSum(self, self.subplot, zorder=self.slicer_z)
- self.subplot.set_ylim(self.data2D.ymin, self.data2D.ymax)
- self.subplot.set_xlim(self.data2D.xmin, self.data2D.xmax)
- self.update()
- self.slicer.update()
- ## Value used to initially set the slicer panel
- params = self.slicer.get_params()
- ## Create a new panel to display results of summation of Data2D
- from slicerpanel import SlicerPanel
- win = MDIFrame(self.parent, None, 'None', (100, 200))
- new_panel = SlicerPanel(parent=win, id=-1,
- base=self, type=self.slicer.__class__.__name__,
- params=params, style=wx.RAISED_BORDER)
-
- new_panel.window_caption = self.slicer.__class__.__name__ + " " + \
- str(self.data2D.name)
- new_panel.window_name = self.slicer.__class__.__name__ + " " + \
- str(self.data2D.name)
- ## Store a reference of the new created panel
-
- ## save the window_caption of the new panel in the current slicer
- self.slicer.set_panel_name(name=new_panel.window_caption)
- ## post slicer panel to guiframe to display it
- from sas.sasgui.guiframe.events import SlicerPanelEvent
-
- win.set_panel(new_panel)
- new_panel.frame = win
- wx.PostEvent(self.parent, SlicerPanelEvent(panel=new_panel,
- main_panel=self))
- wx.CallAfter(new_panel.frame.Show)
- self.panel_slicer = new_panel
-
- def onBoxavgX(self, event):
- """
- Perform 2D data averaging on Qx
- Create a new slicer .
-
- :param event: wx.menu event
- """
- from boxSlicer import BoxInteractorX
- self.onClearSlicer(event)
- wx.PostEvent(self, InternalEvent(slicer=BoxInteractorX))
-
- def onBoxavgY(self, event):
- """
- Perform 2D data averaging on Qy
- Create a new slicer .
-
- :param event: wx.menu event
-
- """
- from boxSlicer import BoxInteractorY
- self.onClearSlicer(event)
- wx.PostEvent(self, InternalEvent(slicer=BoxInteractorY))
-
- def onClearSlicer(self, event):
- """
- Clear the slicer on the plot
- """
- if not self.slicer == None:
- self.slicer.clear()
- self.subplot.figure.canvas.draw()
- self.slicer = None
- # Post slicer None event
- event = self._getEmptySlicerEvent()
- wx.PostEvent(self, event)
-
- def _onSave(self, evt):
- """
- Save a data set to a dat(text) file
-
- :param evt: Menu event
-
- """
- event_id = str(evt.GetId())
- if self.parent != None:
- self._default_save_location = self.parent._default_save_location
- default_name = self.plots[self.graph.selected_plottable].label
- if default_name.count('.') > 0:
- default_name = default_name.split('.')[0]
- default_name += "_out"
- if event_id in self.action_ids:
- self.parent.save_data2d(self.data2D, default_name)
-
- def _onDataShow(self, evt):
- """
- Show the data set in text
-
- :param evt: Menu event
-
- """
- menu = evt.GetEventObject()
- event_id = evt.GetId()
- self.set_selected_from_menu(menu, event_id)
- data = self.plots[self.graph.selected_plottable]
- default_name = data.label
- if default_name.count('.') > 0:
- default_name = default_name.split('.')[0]
- #default_name += "_out"
- if self.parent != None:
- self.parent.show_data2d(data, default_name)
-
- def modifyGraphAppearance(self, e):
- self.graphApp = graphAppearance(self, 'Modify graph appearance', legend=False)
- self.graphApp.setDefaults(self.grid_on, self.legend_on,
- self.xaxis_label, self.yaxis_label,
- self.xaxis_unit, self.yaxis_unit,
- self.xaxis_font, self.yaxis_font,
- find_key(self.get_loc_label(), self.legendLoc),
- self.xcolor, self.ycolor,
- self.is_xtick, self.is_ytick)
- self.graphApp.Bind(wx.EVT_CLOSE, self.on_graphApp_close)
-
- def on_graphApp_close(self, e):
- """
- Gets values from graph appearance dialog and sends them off
- to modify the plot
- """
- self.onGridOnOff(self.graphApp.get_togglegrid())
- self.xaxis_label = self.graphApp.get_xlab()
- self.yaxis_label = self.graphApp.get_ylab()
- self.xaxis_unit = self.graphApp.get_xunit()
- self.yaxis_unit = self.graphApp.get_yunit()
- self.xaxis_font = self.graphApp.get_xfont()
- self.yaxis_font = self.graphApp.get_yfont()
- self.is_xtick = self.graphApp.get_xtick_check()
- self.is_ytick = self.graphApp.get_ytick_check()
- if self.is_xtick:
- self.xaxis_tick = self.xaxis_font
- if self.is_ytick:
- self.yaxis_tick = self.yaxis_font
-
- self.xaxis(self.xaxis_label, self.xaxis_unit,
- self.graphApp.get_xfont(), self.graphApp.get_xcolor(),
- self.xaxis_tick)
- self.yaxis(self.yaxis_label, self.yaxis_unit,
- self.graphApp.get_yfont(), self.graphApp.get_ycolor(),
- self.yaxis_tick)
-
- self.graphApp.Destroy()
+
+################################################################################
+#This software was developed by the University of Tennessee as part of the
+#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
+#project funded by the US National Science Foundation.
+#
+#See the license text in license.txt
+#
+#copyright 2008, University of Tennessee
+################################################################################
+
+
+import wx
+import sys
+import math
+import numpy as np
+import logging
+from sas.sasgui.plottools.PlotPanel import PlotPanel
+from sas.sasgui.plottools.plottables import Graph
+from sas.sasgui.plottools.TextDialog import TextDialog
+from sas.sasgui.guiframe.events import StatusEvent
+from sas.sasgui.guiframe.events import NewPlotEvent
+from sas.sasgui.guiframe.events import PanelOnFocusEvent
+from sas.sasgui.guiframe.events import SlicerEvent
+from sas.sasgui.guiframe.utils import PanelMenu
+from sas.sasgui.guiframe.local_perspectives.plotting.binder import BindArtist
+from Plotter1D import ModelPanel1D
+from sas.sasgui.plottools.toolbar import NavigationToolBar
+from matplotlib.font_manager import FontProperties
+from graphAppearance import graphAppearance
+(InternalEvent, EVT_INTERNAL) = wx.lib.newevent.NewEvent()
+
+logger = logging.getLogger(__name__)
+
+DEFAULT_QMAX = 0.05
+DEFAULT_QSTEP = 0.001
+DEFAULT_BEAM = 0.005
+BIN_WIDTH = 1.0
+
+
+def find_key(dic, val):
+ """return the key of dictionary dic given the value"""
+ return [k for k, v in dic.iteritems() if v == val][0]
+
+
+class NavigationToolBar2D(NavigationToolBar):
+ """
+ """
+ def __init__(self, canvas, parent=None):
+ NavigationToolBar.__init__(self, canvas=canvas, parent=parent)
+
+ def delete_option(self):
+ """
+ remove default toolbar item
+ """
+ #delete reset button
+ self.DeleteToolByPos(0)
+ #delete dragging
+ self.DeleteToolByPos(2)
+ #delete unwanted button that configures subplot parameters
+ self.DeleteToolByPos(4)
+
+ def add_option(self):
+ """
+ add item to the toolbar
+ """
+ #add button
+ id_context = wx.NewId()
+ context_tip = 'Graph Menu'
+ context = wx.ArtProvider.GetBitmap(wx.ART_LIST_VIEW, wx.ART_TOOLBAR)
+ self.InsertSimpleTool(0, id_context, context, context_tip, context_tip)
+ wx.EVT_TOOL(self, id_context, self.parent.onToolContextMenu)
+ self.InsertSeparator(1)
+ #add print button
+ id_print = wx.NewId()
+ print_bmp = wx.ArtProvider.GetBitmap(wx.ART_PRINT, wx.ART_TOOLBAR)
+ self.AddSimpleTool(id_print, print_bmp, 'Print', 'Activate printing')
+ wx.EVT_TOOL(self, id_print, self.on_print)
+
+
+class ModelPanel2D(ModelPanel1D):
+ """
+ Plot panel for use with the GUI manager
+ """
+
+ ## Internal name for the AUI manager
+ window_name = "plotpanel"
+ ## Title to appear on top of the window
+ window_caption = "Plot Panel"
+ ## Flag to tell the GUI manager that this panel is not
+ # tied to any perspective
+ ALWAYS_ON = True
+ ## Group ID
+ group_id = None
+
+
+ def __init__(self, parent, id=-1, data2d=None, color=None,
+ dpi=None, style=wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs):
+ """
+ Initialize the panel
+ """
+ ModelPanel1D.__init__(self, parent, id=id, style=style, **kwargs)
+ self.parent = parent
+ ## Reference to the parent window
+ if hasattr(parent, "parent"):
+ self.parent = self.parent.parent
+ ## Dictionary containing Plottables
+ self.plots = {}
+ ## Save reference of the current plotted
+ self.data2D = data2d
+ ## Unique ID (from gui_manager)
+ self.uid = None
+ ## Action IDs for internal call-backs
+ self.action_ids = {}
+ ## Create Artist and bind it
+ self.connect = BindArtist(self.subplot.figure)
+ ## Beam stop
+ self.beamstop_radius = DEFAULT_BEAM
+ ## to set the order of lines drawn first.
+ self.slicer_z = 5
+ ## Reference to the current slicer
+ self.slicer = None
+ ## event to send slicer info
+ self.Bind(EVT_INTERNAL, self._onEVT_INTERNAL)
+
+ self.axes_frozen = False
+ ## panel that contains result from slicer motion (ex: Boxsum info)
+ self.panel_slicer = None
+ self.title_label = None
+ self.title_font = None
+ self.title_color = 'black'
+ ## Graph
+ self.graph = Graph()
+ self.graph.xaxis("\\rm{Q}", 'A^{-1}')
+ self.graph.yaxis("\\rm{Intensity} ", "cm^{-1}")
+ self.graph.render(self)
+ ## store default value of zmin and zmax
+ self.default_zmin_ctl = self.zmin_2D
+ self.default_zmax_ctl = self.zmax_2D
+
+ def on_plot_qrange(self, event=None):
+ """
+ On Qmin Qmax vertical line event
+ """
+ # Not implemented
+ if event is None:
+ return
+ event.Skip()
+
+ def onLeftDown(self, event):
+ """
+ left button down and ready to drag
+
+ """
+ # Check that the LEFT button was pressed
+ PlotPanel.onLeftDown(self, event)
+ ax = event.inaxes
+ if ax is not None:
+ # data coordinate position
+ pos_x = "%8.3g" % event.xdata
+ pos_y = "%8.3g" % event.ydata
+ position = "x: %s y: %s" % (pos_x, pos_y)
+ wx.PostEvent(self.parent, StatusEvent(status=position))
+ self.plottable_selected(self.data2D.id)
+ self._manager.set_panel_on_focus(self)
+ wx.PostEvent(self.parent, PanelOnFocusEvent(panel=self))
+
+ def add_toolbar(self):
+ """
+ add toolbar
+ """
+ self.enable_toolbar = True
+ self.toolbar = NavigationToolBar2D(parent=self, canvas=self.canvas)
+ self.toolbar.Realize()
+ # On Windows platform, default window size is incorrect, so set
+ # toolbar width to figure width.
+ _, th = self.toolbar.GetSizeTuple()
+ fw, _ = self.canvas.GetSizeTuple()
+ self.toolbar.SetSize(wx.Size(fw, th))
+ self.sizer.Add(self.toolbar, 0, wx.LEFT | wx.EXPAND)
+ # update the axes menu on the toolbar
+ self.toolbar.update()
+
+ def plot_data(self, data):
+ """
+ Data is ready to be displayed
+
+ :TODO: this name should be changed to something more appropriate
+ Don't forget that changing this name will mean changing code
+ in plotting.py
+
+ :param event: data event
+ """
+ xlo = None
+ xhi = None
+ ylo = None
+ yhi = None
+ if data.__class__.__name__ == 'Data1D':
+ return
+ ## Update self.data2d with the current plot
+ self.data2D = data
+ if data.id in self.plots.keys():
+ #replace
+ xlo, xhi = self.subplot.get_xlim()
+ ylo, yhi = self.subplot.get_ylim()
+ self.graph.replace(data)
+ self.plots[data.id] = data
+ else:
+ self.plots[data.id] = data
+ self.graph.add(self.plots[data.id])
+ # update qmax with the new xmax of data plotted
+ self.qmax = data.xmax
+ self.slicer = None
+ # Check axis labels
+ #TODO: Should re-factor this
+ ## render the graph with its new content
+ #data2D: put 'Pixel (Number)' for axis title and unit in case of having no detector info and none in _units
+ if len(data.detector) < 1:
+ if len(data._xunit) < 1 and len(data._yunit) < 1:
+ data._xaxis = '\\rm{x}'
+ data._yaxis = '\\rm{y}'
+ data._xunit = 'pixel'
+ data._yunit = 'pixel'
+ # graph properties
+ self.graph.xaxis(data._xaxis, data._xunit)
+ self.graph.yaxis(data._yaxis, data._yunit)
+ if self._is_changed_legend_label:
+ data.label = self.title_label
+ if data.label is None:
+ data.label = data.name
+ if not self.title_font:
+ self.graph.title(data.label)
+ self.graph.render(self)
+ # Set the axis labels on subplot
+ self._set_axis_labels()
+ self.draw_plot()
+ else:
+ self.graph.render(self)
+ self.draw_plot()
+ self.subplot.set_title(label=data.label,
+ fontproperties=self.title_font,
+ color=self.title_color)
+ self.subplot.figure.canvas.draw_idle()
+ ## store default value of zmin and zmax
+ self.default_zmin_ctl = self.zmin_2D
+ self.default_zmax_ctl = self.zmax_2D
+ if not self.is_zoomed:
+ return
+ # Recover the x,y limits
+ if xlo and xhi and ylo and yhi:
+ if xlo > data.xmin and xhi < data.xmax and \
+ ylo > data.ymin and yhi < data.ymax:
+ self.subplot.set_xlim((xlo, xhi))
+ self.subplot.set_ylim((ylo, yhi))
+ else:
+ self.toolbar.update()
+ self.is_zoomed = False
+
+ def _set_axis_labels(self):
+ """
+ Set axis labels
+ """
+ data = self.data2D
+ # control axis labels from the panel itself
+ yname, yunits = data.get_yaxis()
+ if self.yaxis_label is not None:
+ yname = self.yaxis_label
+ yunits = self.yaxis_unit
+ else:
+ self.yaxis_label = yname
+ self.yaxis_unit = yunits
+ xname, xunits = data.get_xaxis()
+ if self.xaxis_label is not None:
+ xname = self.xaxis_label
+ xunits = self.xaxis_unit
+ else:
+ self.xaxis_label = xname
+ self.xaxis_unit = xunits
+ self.xaxis(xname, xunits, self.xaxis_font,
+ self.xaxis_color, self.xaxis_tick)
+ self.yaxis(yname, yunits, self.yaxis_font,
+ self.yaxis_color, self.yaxis_tick)
+
+ def onContextMenu(self, event):
+ """
+ 2D plot context menu
+
+ :param event: wx context event
+
+ """
+ ids = iter(self._menu_ids)
+ slicerpop = PanelMenu()
+ slicerpop.set_plots(self.plots)
+ slicerpop.set_graph(self.graph)
+
+ wx_id = ids.next()
+ slicerpop.Append(wx_id, '&Save Image', 'Save image as png')
+ wx.EVT_MENU(self, wx_id, self.onSaveImage)
+
+ wx_id = ids.next()
+ slicerpop.Append(wx_id, '&Print Image', 'Print image')
+ wx.EVT_MENU(self, wx_id, self.onPrint)
+
+ wx_id = ids.next()
+ slicerpop.Append(wx_id, '&Copy to Clipboard', 'Copy to the clipboard')
+ wx.EVT_MENU(self, wx_id, self.OnCopyFigureMenu)
+ slicerpop.AppendSeparator()
+ # saving data
+ plot = self.data2D
+ wx_id = ids.next()
+ slicerpop.Append(wx_id, "&Data Info")
+ wx.EVT_MENU(self, wx_id, self._onDataShow)
+
+ wx_id = ids.next()
+ slicerpop.Append(wx_id, "&Save as a File (DAT)")
+ self.action_ids[str(wx_id)] = plot
+ wx.EVT_MENU(self, wx_id, self._onSave)
+
+ slicerpop.AppendSeparator()
+ if len(self.data2D.detector) <= 1:
+ item_list = self.parent.get_current_context_menu(self)
+ if ((item_list is not None) and len(item_list) and
+ self.data2D.name.split(" ")[0] != 'Residuals'):
+ for item, wx_id in zip(item_list, [ids.next() for i in range(len(item_list))]):
+ try:
+ slicerpop.Append(wx_id, item[0], item[1])
+ wx.EVT_MENU(self, wx_id, item[2])
+ except:
+ msg = "ModelPanel1D.onContextMenu: "
+ msg += "bad menu item %s" % sys.exc_value
+ wx.PostEvent(self.parent, StatusEvent(status=msg))
+ slicerpop.AppendSeparator()
+
+ wx_id = ids.next()
+ slicerpop.Append(wx_id, '&Perform Circular Average')
+ wx.EVT_MENU(self, wx_id, self.onCircular) \
+ # For Masked Data
+ if not plot.mask.all():
+ wx_id = ids.next()
+ slicerpop.Append(wx_id, '&Masked Circular Average')
+ wx.EVT_MENU(self, wx_id, self.onMaskedCircular)
+ wx_id = ids.next()
+ slicerpop.Append(wx_id, '&Sector [Q View]')
+ wx.EVT_MENU(self, wx_id, self.onSectorQ)
+ wx_id = ids.next()
+ slicerpop.Append(wx_id, '&Annulus [Phi View ]')
+ wx.EVT_MENU(self, wx_id, self.onSectorPhi)
+ wx_id = ids.next()
+ slicerpop.Append(wx_id, '&Box Sum')
+ wx.EVT_MENU(self, wx_id, self.onBoxSum)
+ wx_id = ids.next()
+ slicerpop.Append(wx_id, '&Box Averaging in Qx')
+ wx.EVT_MENU(self, wx_id, self.onBoxavgX)
+ wx_id = ids.next()
+ slicerpop.Append(wx_id, '&Box Averaging in Qy')
+ wx.EVT_MENU(self, wx_id, self.onBoxavgY)
+ if self.slicer is not None:
+ wx_id = ids.next()
+ slicerpop.Append(wx_id, '&Clear Slicer')
+ wx.EVT_MENU(self, wx_id, self.onClearSlicer)
+ if self.slicer.__class__.__name__ != "BoxSum":
+ wx_id = ids.next()
+ name = '&Edit Slicer Parameters and Batch Slicing'
+ slicerpop.Append(wx_id, name)
+ wx.EVT_MENU(self, wx_id, self._onEditSlicer)
+ slicerpop.AppendSeparator()
+
+ wx_id = ids.next()
+ slicerpop.Append(wx_id, '&Edit Graph Label', 'Edit Graph Label')
+ wx.EVT_MENU(self, wx_id, self.onEditLabels)
+ slicerpop.AppendSeparator()
+
+ # ILL mod here
+
+ wx_id = ids.next()
+ slicerpop.Append(wx_id, '&Modify graph appearance', 'Modify graph appearance')
+ wx.EVT_MENU(self, wx_id, self.modifyGraphAppearance)
+ slicerpop.AppendSeparator()
+
+ wx_id = ids.next()
+ slicerpop.Append(wx_id, '&2D Color Map')
+ wx.EVT_MENU(self, wx_id, self._onEditDetector)
+ slicerpop.AppendSeparator()
+
+ wx_id = ids.next()
+ slicerpop.Append(wx_id, '&Toggle Linear/Log Scale')
+ wx.EVT_MENU(self, wx_id, self._onToggleScale)
+
+ slicerpop.AppendSeparator()
+ wx_id = ids.next()
+ slicerpop.Append(wx_id, '&Window Title')
+ wx.EVT_MENU(self, wx_id, self.onChangeCaption)
+
+ try:
+ pos_evt = event.GetPosition()
+ pos = self.ScreenToClient(pos_evt)
+ except:
+ pos_x, pos_y = self.toolbar.GetPositionTuple()
+ pos = (pos_x, pos_y + 5)
+ self.PopupMenu(slicerpop, pos)
+
+ def onEditLabels(self, event):
+ """
+ Edit legend label
+ """
+ try:
+ selected_plot = self.plots[self.graph.selected_plottable]
+ except:
+ selected_plot = self.plots[self.data2D.id]
+ label = selected_plot.label
+ dial = TextDialog(None, -1, 'Change Label', label)
+ if dial.ShowModal() == wx.ID_OK:
+ try:
+ FONT = FontProperties()
+ newlabel = dial.getText()
+ font = FONT.copy()
+ font.set_size(dial.getSize())
+ font.set_family(dial.getFamily())
+ font.set_style(dial.getStyle())
+ font.set_weight(dial.getWeight())
+ colour = dial.getColor()
+ if len(newlabel) > 0:
+ # update Label
+ selected_plot.label = newlabel
+ self.graph.title(newlabel)
+ self.title_label = selected_plot.label
+ self.title_font = font
+ self.title_color = colour
+ ## render the graph
+ self.subplot.set_title(label=self.title_label,
+ fontproperties=self.title_font,
+ color=self.title_color)
+ self._is_changed_legend_label = True
+ self.subplot.figure.canvas.draw_idle()
+ except:
+ msg = "Add Text: Error. Check your property values..."
+ logger.error(msg)
+ if self.parent is not None:
+ wx.PostEvent(self.parent, StatusEvent(status=msg))
+ dial.Destroy()
+
+ def _onEditDetector(self, event):
+ """
+ Allow to view and edits detector parameters
+
+ :param event: wx.menu event
+
+ """
+ import detector_dialog
+ dialog = detector_dialog.DetectorDialog(self, -1, base=self.parent,
+ reset_zmin_ctl=self.default_zmin_ctl,
+ reset_zmax_ctl=self.default_zmax_ctl, cmap=self.cmap)
+ ## info of current detector and data2D
+ xnpts = len(self.data2D.x_bins)
+ ynpts = len(self.data2D.y_bins)
+ xmax = max(self.data2D.xmin, self.data2D.xmax)
+ ymax = max(self.data2D.ymin, self.data2D.ymax)
+ qmax = math.sqrt(math.pow(xmax, 2) + math.pow(ymax, 2))
+ ## set dialog window content
+ dialog.setContent(xnpts=xnpts, ynpts=ynpts, qmax=qmax,
+ beam=self.data2D.xmin,
+ zmin=self.zmin_2D,
+ zmax=self.zmax_2D)
+ if dialog.ShowModal() == wx.ID_OK:
+ evt = dialog.getContent()
+ self.zmin_2D = evt.zmin
+ self.zmax_2D = evt.zmax
+ self.cmap = evt.cmap
+ dialog.Destroy()
+ ## Redraw the current image
+ self.image(data=self.data2D.data,
+ qx_data=self.data2D.qx_data,
+ qy_data=self.data2D.qy_data,
+ xmin=self.data2D.xmin,
+ xmax=self.data2D.xmax,
+ ymin=self.data2D.ymin,
+ ymax=self.data2D.ymax,
+ zmin=self.zmin_2D,
+ zmax=self.zmax_2D,
+ cmap=self.cmap,
+ color=0, symbol=0, label=self.data2D.name)
+ self.subplot.figure.canvas.draw_idle()
+
+ def freeze_axes(self):
+ """
+ """
+ self.axes_frozen = True
+
+ def thaw_axes(self):
+ """
+ """
+ self.axes_frozen = False
+
+ def onMouseMotion(self, event):
+ """
+ """
+ pass
+
+ def onWheel(self, event):
+ """
+ """
+ pass
+
+ def update(self, draw=True):
+ """
+ Respond to changes in the model by recalculating the
+ profiles and resetting the widgets.
+ """
+ self.draw_plot()
+
+ def _getEmptySlicerEvent(self):
+ """
+ create an empty slicervent
+ """
+ return SlicerEvent(type=None, params=None, obj_class=None)
+
+ def _onEVT_INTERNAL(self, event):
+ """
+ Draw the slicer
+
+ :param event: wx.lib.newevent (SlicerEvent) containing slicer
+ parameter
+
+ """
+ self._setSlicer(event.slicer)
+
+ def _setSlicer(self, slicer):
+ """
+ Clear the previous slicer and create a new one.Post an internal
+ event.
+
+ :param slicer: slicer class to create
+
+ """
+ # Clear current slicer
+ if self.slicer is not None:
+ self.slicer.clear()
+ # Create a new slicer
+ self.slicer_z += 1
+ self.slicer = slicer(self, self.subplot, zorder=self.slicer_z)
+ self.subplot.set_ylim(self.data2D.ymin, self.data2D.ymax)
+ self.subplot.set_xlim(self.data2D.xmin, self.data2D.xmax)
+ # Draw slicer
+ self.update()
+ self.slicer.update()
+ msg = "Plotter2D._setSlicer %s" % self.slicer.__class__.__name__
+ wx.PostEvent(self.parent, StatusEvent(status=msg))
+ # Post slicer event
+ event = self._getEmptySlicerEvent()
+ event.type = self.slicer.__class__.__name__
+ event.obj_class = self.slicer.__class__
+ event.params = self.slicer.get_params()
+ wx.PostEvent(self, event)
+
+ def onMaskedCircular(self, event):
+ """
+ perform circular averaging on Data2D with mask if it exists
+
+ :param event: wx.menu event
+
+ """
+ self.onCircular(event, True)
+
+ def onCircular(self, event, ismask=False):
+ """
+ perform circular averaging on Data2D
+
+ :param event: wx.menu event
+
+ """
+ # Find the best number of bins
+ npt = math.sqrt(len(self.data2D.data[np.isfinite(self.data2D.data)]))
+ npt = math.floor(npt)
+ from sas.sascalc.dataloader.manipulations import CircularAverage
+ # compute the maximum radius of data2D
+ self.qmax = max(math.fabs(self.data2D.xmax),
+ math.fabs(self.data2D.xmin))
+ self.ymax = max(math.fabs(self.data2D.ymax),
+ math.fabs(self.data2D.ymin))
+ self.radius = math.sqrt(math.pow(self.qmax, 2) + math.pow(self.ymax, 2))
+ # Compute beam width
+ bin_width = (self.qmax + self.qmax) / npt
+ # Create data1D circular average of data2D
+ Circle = CircularAverage(r_min=0, r_max=self.radius,
+ bin_width=bin_width)
+ circ = Circle(self.data2D, ismask=ismask)
+ from sas.sasgui.guiframe.dataFitting import Data1D
+ if hasattr(circ, "dxl"):
+ dxl = circ.dxl
+ else:
+ dxl = None
+ if hasattr(circ, "dxw"):
+ dxw = circ.dxw
+ else:
+ dxw = None
+
+ new_plot = Data1D(x=circ.x, y=circ.y, dy=circ.dy, dx=circ.dx)
+ new_plot.dxl = dxl
+ new_plot.dxw = dxw
+ new_plot.name = "Circ avg " + self.data2D.name
+ new_plot.source = self.data2D.source
+ # new_plot.info = self.data2D.info
+ new_plot.interactive = True
+ new_plot.detector = self.data2D.detector
+
+ # If the data file does not tell us what the axes are, just assume...
+ new_plot.xaxis("\\rm{Q}", "A^{-1}")
+ if hasattr(self.data2D, "scale") and \
+ self.data2D.scale == 'linear':
+ new_plot.ytransform = 'y'
+ new_plot.yaxis("\\rm{Residuals} ", "normalized")
+ else:
+ new_plot.yaxis("\\rm{Intensity} ", "cm^{-1}")
+
+ new_plot.group_id = "2daverage" + self.data2D.name
+ new_plot.id = "Circ avg " + self.data2D.name
+ new_plot.is_data = True
+ self.parent.update_theory(data_id=self.data2D.id, theory=new_plot)
+ wx.PostEvent(self.parent,
+ NewPlotEvent(plot=new_plot, title=new_plot.name))
+
+ def _onEditSlicer(self, event):
+ """
+ Is available only when a slicer is drawn.Create a dialog
+ window where the user can enter value to reset slicer
+ parameters.
+
+ :param event: wx.menu event
+
+ """
+ if self.slicer is not None:
+ from parameters_panel_slicer import SlicerParameterPanel
+ dialog = SlicerParameterPanel(self, -1, "Slicer Parameters")
+ dialog.set_slicer(self.slicer.__class__.__name__,
+ self.slicer.get_params())
+ if dialog.ShowModal() == wx.ID_OK:
+ dialog.Destroy()
+
+ def onSectorQ(self, event):
+ """
+ Perform sector averaging on Q and draw sector slicer
+ """
+ from SectorSlicer import SectorInteractor
+ self.onClearSlicer(event)
+ wx.PostEvent(self, InternalEvent(slicer=SectorInteractor))
+
+ def onSectorPhi(self, event):
+ """
+ Perform sector averaging on Phi and draw annulus slicer
+ """
+ from AnnulusSlicer import AnnulusInteractor
+ self.onClearSlicer(event)
+ wx.PostEvent(self, InternalEvent(slicer=AnnulusInteractor))
+
+ def onBoxSum(self, event):
+ """
+ """
+ from sas.sasgui.guiframe.gui_manager import MDIFrame
+ from boxSum import BoxSum
+ self.onClearSlicer(event)
+ self.slicer_z += 1
+ self.slicer = BoxSum(self, self.subplot, zorder=self.slicer_z)
+ self.subplot.set_ylim(self.data2D.ymin, self.data2D.ymax)
+ self.subplot.set_xlim(self.data2D.xmin, self.data2D.xmax)
+ self.update()
+ self.slicer.update()
+ ## Value used to initially set the slicer panel
+ params = self.slicer.get_params()
+ ## Create a new panel to display results of summation of Data2D
+ from parameters_panel_boxsum import SlicerPanel
+ win = MDIFrame(self.parent, None, 'None', (100, 200))
+ new_panel = SlicerPanel(parent=win, id=-1,
+ base=self, type=self.slicer.__class__.__name__,
+ params=params, style=wx.RAISED_BORDER)
+
+ new_panel.window_caption = self.slicer.__class__.__name__ + " " + \
+ str(self.data2D.name)
+ new_panel.window_name = self.slicer.__class__.__name__ + " " + \
+ str(self.data2D.name)
+ ## Store a reference of the new created panel
+
+ ## save the window_caption of the new panel in the current slicer
+ self.slicer.set_panel_name(name=new_panel.window_caption)
+ ## post slicer panel to guiframe to display it
+ from sas.sasgui.guiframe.events import SlicerPanelEvent
+
+ win.set_panel(new_panel)
+ new_panel.frame = win
+ wx.PostEvent(self.parent, SlicerPanelEvent(panel=new_panel,
+ main_panel=self))
+ wx.CallAfter(new_panel.frame.Show)
+ self.panel_slicer = new_panel
+
+ def onBoxavgX(self, event):
+ """
+ Perform 2D data averaging on Qx
+ Create a new slicer .
+
+ :param event: wx.menu event
+ """
+ from boxSlicer import BoxInteractorX
+ self.onClearSlicer(event)
+ wx.PostEvent(self, InternalEvent(slicer=BoxInteractorX))
+
+ def onBoxavgY(self, event):
+ """
+ Perform 2D data averaging on Qy
+ Create a new slicer .
+
+ :param event: wx.menu event
+
+ """
+ from boxSlicer import BoxInteractorY
+ self.onClearSlicer(event)
+ wx.PostEvent(self, InternalEvent(slicer=BoxInteractorY))
+
+ def onClearSlicer(self, event):
+ """
+ Clear the slicer on the plot
+ """
+ if self.slicer is not None:
+ self.slicer.clear()
+ self.subplot.figure.canvas.draw()
+ self.slicer = None
+ # Post slicer None event
+ event = self._getEmptySlicerEvent()
+ wx.PostEvent(self, event)
+
+ def _onSave(self, evt):
+ """
+ Save a data set to a dat(text) file
+
+ :param evt: Menu event
+
+ """
+ event_id = str(evt.GetId())
+ if self.parent is not None:
+ self._default_save_location = self.parent._default_save_location
+ default_name = self.plots[self.graph.selected_plottable].label
+ if default_name.count('.') > 0:
+ default_name = default_name.split('.')[0]
+ default_name += "_out"
+ if event_id in self.action_ids:
+ self.parent.save_data2d(self.data2D, default_name)
+
+ def _onDataShow(self, evt):
+ """
+ Show the data set in text
+
+ :param evt: Menu event
+
+ """
+ menu = evt.GetEventObject()
+ event_id = evt.GetId()
+ self.set_selected_from_menu(menu, event_id)
+ data = self.plots[self.graph.selected_plottable]
+ default_name = data.label
+ if default_name.count('.') > 0:
+ default_name = default_name.split('.')[0]
+ if self.parent is not None:
+ self.parent.show_data2d(data, default_name)
+
+ def modifyGraphAppearance(self, e):
+ self.graphApp = graphAppearance(self, 'Modify graph appearance',
+ legend=False)
+ self.graphApp.setDefaults(self.grid_on, self.legend_on,
+ self.xaxis_label, self.yaxis_label,
+ self.xaxis_unit, self.yaxis_unit,
+ self.xaxis_font, self.yaxis_font,
+ find_key(self.get_loc_label(), self.legendLoc),
+ self.xcolor, self.ycolor,
+ self.is_xtick, self.is_ytick)
+ self.graphApp.Bind(wx.EVT_CLOSE, self.on_graphApp_close)
+
+ def on_graphApp_close(self, e):
+ """
+ Gets values from graph appearance dialog and sends them off
+ to modify the plot
+ """
+ self.onGridOnOff(self.graphApp.get_togglegrid())
+ self.xaxis_label = self.graphApp.get_xlab()
+ self.yaxis_label = self.graphApp.get_ylab()
+ self.xaxis_unit = self.graphApp.get_xunit()
+ self.yaxis_unit = self.graphApp.get_yunit()
+ self.xaxis_font = self.graphApp.get_xfont()
+ self.yaxis_font = self.graphApp.get_yfont()
+ self.is_xtick = self.graphApp.get_xtick_check()
+ self.is_ytick = self.graphApp.get_ytick_check()
+ if self.is_xtick:
+ self.xaxis_tick = self.xaxis_font
+ if self.is_ytick:
+ self.yaxis_tick = self.yaxis_font
+
+ self.xaxis(self.xaxis_label, self.xaxis_unit,
+ self.graphApp.get_xfont(), self.graphApp.get_xcolor(),
+ self.xaxis_tick)
+ self.yaxis(self.yaxis_label, self.yaxis_unit,
+ self.graphApp.get_yfont(), self.graphApp.get_ycolor(),
+ self.yaxis_tick)
+
+ self.graphApp.Destroy()
diff --git a/src/sas/sasgui/guiframe/local_perspectives/plotting/SectorSlicer.py b/src/sas/sasgui/guiframe/local_perspectives/plotting/SectorSlicer.py
index 2327b91..03ce2a3 100644
--- a/src/sas/sasgui/guiframe/local_perspectives/plotting/SectorSlicer.py
+++ b/src/sas/sasgui/guiframe/local_perspectives/plotting/SectorSlicer.py
@@ -1,596 +1,601 @@
-"""
- Sector interactor
-"""
-import math
-import wx
-from BaseInteractor import _BaseInteractor
-from sas.sasgui.guiframe.events import NewPlotEvent
-from sas.sasgui.guiframe.events import StatusEvent
-from sas.sasgui.guiframe.events import SlicerParameterEvent
-from sas.sasgui.guiframe.events import EVT_SLICER_PARS
-from sas.sasgui.guiframe.dataFitting import Data1D
-
-
-class SectorInteractor(_BaseInteractor):
- """
- Draw a sector slicer.Allow to performQ averaging on data 2D
- """
- def __init__(self, base, axes, color='black', zorder=3):
-
- _BaseInteractor.__init__(self, base, axes, color=color)
- ## Class initialization
- self.markers = []
- self.axes = axes
- ## connect the plot to event
- self.connect = self.base.connect
-
- ## compute qmax limit to reset the graph
- x = math.pow(max(self.base.data2D.xmax,
- math.fabs(self.base.data2D.xmin)), 2)
- y = math.pow(max(self.base.data2D.ymax,
- math.fabs(self.base.data2D.ymin)), 2)
- self.qmax = math.sqrt(x + y)
- ## Number of points on the plot
- self.nbins = 20
- ## Angle of the middle line
- self.theta2 = math.pi / 3
- ## Absolute value of the Angle between the middle line and any side line
- self.phi = math.pi / 12
- ## Middle line
- self.main_line = LineInteractor(self, self.base.subplot, color='blue',
- zorder=zorder, r=self.qmax,
- theta=self.theta2)
- self.main_line.qmax = self.qmax
- ## Right Side line
- self.right_line = SideInteractor(self, self.base.subplot, color='black',
- zorder=zorder, r=self.qmax,
- phi=-1 * self.phi, theta2=self.theta2)
- self.right_line.qmax = self.qmax
- ## Left Side line
- self.left_line = SideInteractor(self, self.base.subplot, color='black',
- zorder=zorder, r=self.qmax,
- phi=self.phi, theta2=self.theta2)
- self.left_line.qmax = self.qmax
- ## draw the sector
- self.update()
- self._post_data()
- ## Bind to slice parameter events
- self.base.Bind(EVT_SLICER_PARS, self._onEVT_SLICER_PARS)
-
- def _onEVT_SLICER_PARS(self, event):
- """
- receive an event containing parameters values to reset the slicer
-
- :param event: event of type SlicerParameterEvent with params as
- attribute
-
- """
- wx.PostEvent(self.base.parent,
- StatusEvent(status="SectorSlicer._onEVT_SLICER_PARS"))
- event.Skip()
- if event.type == self.__class__.__name__:
- self.set_params(event.params)
- self.base.update()
-
- def set_layer(self, n):
- """
- Allow adding plot to the same panel
-
- :param n: the number of layer
-
- """
- self.layernum = n
- self.update()
-
- def clear(self):
- """
- Clear the slicer and all connected events related to this slicer
- """
- self.clear_markers()
- self.main_line.clear()
- self.left_line.clear()
- self.right_line.clear()
- self.base.connect.clearall()
- self.base.Unbind(EVT_SLICER_PARS)
-
- def update(self):
- """
- Respond to changes in the model by recalculating the profiles and
- resetting the widgets.
- """
- # Update locations
- ## Check if the middle line was dragged and
- #update the picture accordingly
- if self.main_line.has_move:
- self.main_line.update()
- self.right_line.update(delta=-self.left_line.phi / 2,
- mline=self.main_line.theta)
- self.left_line.update(delta=self.left_line.phi / 2,
- mline=self.main_line.theta)
- ## Check if the left side has moved and update the slicer accordingly
- if self.left_line.has_move:
- self.main_line.update()
- self.left_line.update(phi=None, delta=None, mline=self.main_line,
- side=True, left=True)
- self.right_line.update(phi=self.left_line.phi, delta=None,
- mline=self.main_line, side=True,
- left=False, right=True)
- ## Check if the right side line has moved and
- #update the slicer accordingly
- if self.right_line.has_move:
- self.main_line.update()
- self.right_line.update(phi=None, delta=None, mline=self.main_line,
- side=True, left=False, right=True)
- self.left_line.update(phi=self.right_line.phi, delta=None,
- mline=self.main_line, side=True, left=False)
-
- def save(self, ev):
- """
- Remember the roughness for this layer and the next so that we
- can restore on Esc.
- """
- self.base.freeze_axes()
- self.main_line.save(ev)
- self.right_line.save(ev)
- self.left_line.save(ev)
-
- def _post_data(self, nbins=None):
- """
- compute sector averaging of data2D into data1D
-
- :param nbins: the number of point to plot for the average 1D data
- """
- ## get the data2D to average
- data = self.base.data2D
- # If we have no data, just return
- if data == None:
- return
- ## Averaging
- from sas.sascalc.dataloader.manipulations import SectorQ
- radius = self.qmax
- phimin = -self.left_line.phi + self.main_line.theta
- phimax = self.left_line.phi + self.main_line.theta
- if nbins == None:
- nbins = 20
- sect = SectorQ(r_min=0.0, r_max=radius,
- phi_min=phimin + math.pi,
- phi_max=phimax + math.pi, nbins=nbins)
-
- sector = sect(self.base.data2D)
- ##Create 1D data resulting from average
-
- if hasattr(sector, "dxl"):
- dxl = sector.dxl
- else:
- dxl = None
- if hasattr(sector, "dxw"):
- dxw = sector.dxw
- else:
- dxw = None
- new_plot = Data1D(x=sector.x, y=sector.y, dy=sector.dy, dx=sector.dx)
- new_plot.dxl = dxl
- new_plot.dxw = dxw
- new_plot.name = "SectorQ" + "(" + self.base.data2D.name + ")"
- new_plot.source = self.base.data2D.source
- #new_plot.info=self.base.data2D.info
- new_plot.interactive = True
- new_plot.detector = self.base.data2D.detector
- ## If the data file does not tell us what the axes are, just assume...
- new_plot.xaxis("\\rm{Q}", "A^{-1}")
- new_plot.yaxis("\\rm{Intensity}", "cm^{-1}")
- if hasattr(data, "scale") and data.scale == 'linear' and \
- self.base.data2D.name.count("Residuals") > 0:
- new_plot.ytransform = 'y'
- new_plot.yaxis("\\rm{Residuals} ", "/")
-
- new_plot.group_id = "2daverage" + self.base.data2D.name
- new_plot.id = "SectorQ" + self.base.data2D.name
- new_plot.is_data = True
- self.base.parent.update_theory(data_id=data.id, theory=new_plot)
- wx.PostEvent(self.base.parent,
- NewPlotEvent(plot=new_plot, title="SectorQ" + self.base.data2D.name))
-
- def moveend(self, ev):
- """
- Called a dragging motion ends.Get slicer event
- """
- self.base.thaw_axes()
- ## Post parameters
- event = SlicerParameterEvent()
- event.type = self.__class__.__name__
- event.params = self.get_params()
- ## Send slicer paramers to plotter2D
- wx.PostEvent(self.base, event)
-
- def restore(self):
- """
- Restore the roughness for this layer.
- """
- self.main_line.restore()
- self.left_line.restore()
- self.right_line.restore()
-
- def move(self, x, y, ev):
- """
- Process move to a new position, making sure that the move is allowed.
- """
- pass
-
- def set_cursor(self, x, y):
- """
- """
- pass
-
- def get_params(self):
- """
- Store a copy of values of parameters of the slicer into a dictionary.
-
- :return params: the dictionary created
-
- """
- params = {}
- ## Always make sure that the left and the right line are at phi
- ## angle of the middle line
- if math.fabs(self.left_line.phi) != math.fabs(self.right_line.phi):
- msg = "Phi left and phi right are different"
- msg += " %f, %f" % (self.left_line.phi, self.right_line.phi)
- raise ValueError, msg
- params["Phi [deg]"] = self.main_line.theta * 180 / math.pi
- params["Delta_Phi [deg]"] = math.fabs(self.left_line.phi * 180 / math.pi)
- params["nbins"] = self.nbins
- return params
-
- def set_params(self, params):
- """
- Receive a dictionary and reset the slicer with values contained
- in the values of the dictionary.
-
- :param params: a dictionary containing name of slicer parameters and
- values the user assigned to the slicer.
- """
- main = params["Phi [deg]"] * math.pi / 180
- phi = math.fabs(params["Delta_Phi [deg]"] * math.pi / 180)
- self.nbins = int(params["nbins"])
- self.main_line.theta = main
- ## Reset the slicer parameters
- self.main_line.update()
- self.right_line.update(phi=phi, delta=None, mline=self.main_line,
- side=True, right=True)
- self.left_line.update(phi=phi, delta=None,
- mline=self.main_line, side=True)
- ## post the new corresponding data
- self._post_data(nbins=self.nbins)
-
- def freeze_axes(self):
- """
- """
- self.base.freeze_axes()
-
- def thaw_axes(self):
- """
- """
- self.base.thaw_axes()
-
- def draw(self):
- """
- """
- self.base.draw()
-
-
-class SideInteractor(_BaseInteractor):
- """
- Draw an oblique line
-
- :param phi: the phase between the middle line and one side line
- :param theta2: the angle between the middle line and x- axis
-
- """
- def __init__(self, base, axes, color='black', zorder=5, r=1.0,
- phi=math.pi / 4, theta2=math.pi / 3):
- """
- """
- _BaseInteractor.__init__(self, base, axes, color=color)
- ## Initialize the class
- self.markers = []
- self.axes = axes
- ## compute the value of the angle between the current line and
- ## the x-axis
- self.save_theta = theta2 + phi
- self.theta = theta2 + phi
- ## the value of the middle line angle with respect to the x-axis
- self.theta2 = theta2
- ## Radius to find polar coordinates this line's endpoints
- self.radius = r
- ## phi is the phase between the current line and the middle line
- self.phi = phi
- ## End points polar coordinates
- x1 = self.radius * math.cos(self.theta)
- y1 = self.radius * math.sin(self.theta)
- x2 = -1 * self.radius * math.cos(self.theta)
- y2 = -1 * self.radius * math.sin(self.theta)
- ## defining a new marker
- self.inner_marker = self.axes.plot([x1 / 2.5], [y1 / 2.5], linestyle='',
- marker='s', markersize=10,
- color=self.color, alpha=0.6,
- pickradius=5, label="pick",
- zorder=zorder, visible=True)[0]
-
- ## Defining the current line
- self.line = self.axes.plot([x1, x2], [y1, y2],
- linestyle='-', marker='',
- color=self.color, visible=True)[0]
- ## Flag to differentiate the left line from the right line motion
- self.left_moving = False
- ## Flag to define a motion
- self.has_move = False
- ## connecting markers and draw the picture
- self.connect_markers([self.inner_marker, self.line])
-
- def set_layer(self, n):
- """
- Allow adding plot to the same panel
-
- :param n: the number of layer
-
- """
- self.layernum = n
- self.update()
-
- def clear(self):
- """
- Clear the slicer and all connected events related to this slicer
- """
- self.clear_markers()
- try:
- self.line.remove()
- self.inner_marker.remove()
- except:
- # Old version of matplotlib
- for item in range(len(self.axes.lines)):
- del self.axes.lines[0]
-
- def update(self, phi=None, delta=None, mline=None,
- side=False, left=False, right=False):
- """
- Draw oblique line
-
- :param phi: the phase between the middle line and the current line
- :param delta: phi/2 applied only when the mline was moved
-
- """
- #print "update left or right ", self.has_move
- self.left_moving = left
- theta3 = 0
- if phi != None:
- self.phi = phi
- if delta == None:
- delta = 0
- if right:
- self.phi = -1 * math.fabs(self.phi)
- #delta=-delta
- else:
- self.phi = math.fabs(self.phi)
- if side:
- self.theta = mline.theta + self.phi
-
- if mline != None:
- if delta != 0:
- self.theta2 = mline + delta
- else:
- self.theta2 = mline.theta
- if delta == 0:
- theta3 = self.theta + delta
- else:
- theta3 = self.theta2 + delta
- x1 = self.radius * math.cos(theta3)
- y1 = self.radius * math.sin(theta3)
- x2 = -1 * self.radius * math.cos(theta3)
- y2 = -1 * self.radius * math.sin(theta3)
- self.inner_marker.set(xdata=[x1 / 2.5], ydata=[y1 / 2.5])
- self.line.set(xdata=[x1, x2], ydata=[y1, y2])
-
- def save(self, ev):
- """
- Remember the roughness for this layer and the next so that we
- can restore on Esc.
- """
- self.save_theta = self.theta
- self.base.freeze_axes()
-
- def moveend(self, ev):
- """
- """
- self.has_move = False
- self.base.moveend(ev)
-
- def restore(self):
- """
- Restore the roughness for this layer.
- """
- self.theta = self.save_theta
-
- def move(self, x, y, ev):
- """
- Process move to a new position, making sure that the move is allowed.
- """
- self.theta = math.atan2(y, x)
- self.has_move = True
- #ToDo: Simplify below
- if not self.left_moving:
- if self.theta2 - self.theta <= 0 and self.theta2 > 0:
- self.restore()
- return
- elif self.theta2 < 0 and self.theta < 0 and \
- self.theta - self.theta2 >= 0:
- self.restore()
- return
- elif self.theta2 < 0 and self.theta > 0 and \
- (self.theta2 + 2 * math.pi - self.theta) >= math.pi / 2:
- self.restore()
- return
- elif self.theta2 < 0 and self.theta < 0 and \
- (self.theta2 - self.theta) >= math.pi / 2:
- self.restore()
- return
- elif self.theta2 > 0 and (self.theta2 - self.theta >= math.pi / 2 or \
- (self.theta2 - self.theta >= math.pi / 2)):
- self.restore()
- return
- else:
- if self.theta < 0 and (self.theta + math.pi * 2 - self.theta2) <= 0:
- self.restore()
- return
- elif self.theta2 < 0 and (self.theta - self.theta2) <= 0:
- self.restore()
- return
- elif self.theta > 0 and self.theta - self.theta2 <= 0:
- self.restore()
- return
- elif self.theta - self.theta2 >= math.pi / 2 or \
- ((self.theta + math.pi * 2 - self.theta2) >= math.pi / 2 and \
- self.theta < 0 and self.theta2 > 0):
- self.restore()
- return
-
- self.phi = math.fabs(self.theta2 - self.theta)
- if self.phi > math.pi:
- self.phi = 2 * math.pi - math.fabs(self.theta2 - self.theta)
- self.base.base.update()
-
- def set_cursor(self, x, y):
- """
- """
- self.move(x, y, None)
- self.update()
-
- def get_params(self):
- """
- """
- params = {}
- params["radius"] = self.radius
- params["theta"] = self.theta
- return params
-
- def set_params(self, params):
- """
- """
- x = params["radius"]
- self.set_cursor(x, None)
-
-
-class LineInteractor(_BaseInteractor):
- """
- Select an annulus through a 2D plot
- """
- def __init__(self, base, axes, color='black',
- zorder=5, r=1.0, theta=math.pi / 4):
- """
- """
- _BaseInteractor.__init__(self, base, axes, color=color)
-
- self.markers = []
- self.axes = axes
- self.save_theta = theta
- self.theta = theta
- self.radius = r
- self.scale = 10.0
- # Inner circle
- x1 = self.radius * math.cos(self.theta)
- y1 = self.radius * math.sin(self.theta)
- x2 = -1 * self.radius * math.cos(self.theta)
- y2 = -1 * self.radius * math.sin(self.theta)
- # Inner circle marker
- self.inner_marker = self.axes.plot([x1 / 2.5], [y1 / 2.5], linestyle='',
- marker='s', markersize=10,
- color=self.color, alpha=0.6,
- pickradius=5, label="pick",
- zorder=zorder,
- visible=True)[0]
- self.line = self.axes.plot([x1, x2], [y1, y2],
- linestyle='-', marker='',
- color=self.color, visible=True)[0]
- self.npts = 20
- self.has_move = False
- self.connect_markers([self.inner_marker, self.line])
- self.update()
-
- def set_layer(self, n):
- """
- """
- self.layernum = n
- self.update()
-
- def clear(self):
- """
- """
- self.clear_markers()
- try:
- self.inner_marker.remove()
- self.line.remove()
- except:
- # Old version of matplotlib
- for item in range(len(self.axes.lines)):
- del self.axes.lines[0]
-
- def update(self, theta=None):
- """
- Draw the new roughness on the graph.
- """
-
- if theta != None:
- self.theta = theta
- x1 = self.radius * math.cos(self.theta)
- y1 = self.radius * math.sin(self.theta)
- x2 = -1 * self.radius * math.cos(self.theta)
- y2 = -1 * self.radius * math.sin(self.theta)
-
- self.inner_marker.set(xdata=[x1 / 2.5], ydata=[y1 / 2.5])
- self.line.set(xdata=[x1, x2], ydata=[y1, y2])
-
- def save(self, ev):
- """
- Remember the roughness for this layer and the next so that we
- can restore on Esc.
- """
- self.save_theta = self.theta
- self.base.freeze_axes()
-
- def moveend(self, ev):
- """
- """
- self.has_move = False
- self.base.moveend(ev)
-
- def restore(self):
- """
- Restore the roughness for this layer.
- """
- self.theta = self.save_theta
-
- def move(self, x, y, ev):
- """
- Process move to a new position, making sure that the move is allowed.
- """
- self.theta = math.atan2(y, x)
- self.has_move = True
- self.base.base.update()
-
- def set_cursor(self, x, y):
- """
- """
- self.move(x, y, None)
- self.update()
-
- def get_params(self):
- """
- """
- params = {}
- params["radius"] = self.radius
- params["theta"] = self.theta
- return params
-
- def set_params(self, params):
- """
- """
- x = params["radius"]
- self.set_cursor(x, None)
+"""
+ Sector interactor
+"""
+import math
+import wx
+from BaseInteractor import _BaseInteractor
+from sas.sasgui.guiframe.events import NewPlotEvent
+from sas.sasgui.guiframe.events import StatusEvent
+from sas.sasgui.guiframe.events import SlicerParameterEvent
+from sas.sasgui.guiframe.events import EVT_SLICER_PARS
+from sas.sasgui.guiframe.dataFitting import Data1D
+
+
+class SectorInteractor(_BaseInteractor):
+ """
+ Draw a sector slicer.Allow to performQ averaging on data 2D
+ """
+ def __init__(self, base, axes, color='black', zorder=3):
+
+ _BaseInteractor.__init__(self, base, axes, color=color)
+ ## Class initialization
+ self.markers = []
+ self.axes = axes
+ ## connect the plot to event
+ self.connect = self.base.connect
+
+ ## compute qmax limit to reset the graph
+ x = math.pow(max(self.base.data2D.xmax,
+ math.fabs(self.base.data2D.xmin)), 2)
+ y = math.pow(max(self.base.data2D.ymax,
+ math.fabs(self.base.data2D.ymin)), 2)
+ self.qmax = math.sqrt(x + y)
+ ## Number of points on the plot
+ self.nbins = 20
+ ## Angle of the middle line
+ self.theta2 = math.pi / 3
+ ## Absolute value of the Angle between the middle line and any side line
+ self.phi = math.pi / 12
+ # Binning base for log/lin binning
+ self.bin_base = 0
+ ## Middle line
+ self.main_line = LineInteractor(self, self.base.subplot, color='blue',
+ zorder=zorder, r=self.qmax,
+ theta=self.theta2)
+ self.main_line.qmax = self.qmax
+ ## Right Side line
+ self.right_line = SideInteractor(self, self.base.subplot, color='black',
+ zorder=zorder, r=self.qmax,
+ phi=-1 * self.phi, theta2=self.theta2)
+ self.right_line.qmax = self.qmax
+ ## Left Side line
+ self.left_line = SideInteractor(self, self.base.subplot, color='black',
+ zorder=zorder, r=self.qmax,
+ phi=self.phi, theta2=self.theta2)
+ self.left_line.qmax = self.qmax
+ ## draw the sector
+ self.update()
+ self._post_data()
+ ## Bind to slice parameter events
+ self.base.Bind(EVT_SLICER_PARS, self._onEVT_SLICER_PARS)
+
+ def _onEVT_SLICER_PARS(self, event):
+ """
+ receive an event containing parameters values to reset the slicer
+
+ :param event: event of type SlicerParameterEvent with params as
+ attribute
+
+ """
+ wx.PostEvent(self.base.parent,
+ StatusEvent(status="SectorSlicer._onEVT_SLICER_PARS"))
+ event.Skip()
+ if event.type == self.__class__.__name__:
+ self.set_params(event.params)
+ self.base.update()
+
+ def set_layer(self, n):
+ """
+ Allow adding plot to the same panel
+
+ :param n: the number of layer
+
+ """
+ self.layernum = n
+ self.update()
+
+ def clear(self):
+ """
+ Clear the slicer and all connected events related to this slicer
+ """
+ self.clear_markers()
+ self.main_line.clear()
+ self.left_line.clear()
+ self.right_line.clear()
+ self.base.connect.clearall()
+ self.base.Unbind(EVT_SLICER_PARS)
+
+ def update(self):
+ """
+ Respond to changes in the model by recalculating the profiles and
+ resetting the widgets.
+ """
+ # Update locations
+ ## Check if the middle line was dragged and
+ #update the picture accordingly
+ if self.main_line.has_move:
+ self.main_line.update()
+ self.right_line.update(delta=-self.left_line.phi / 2,
+ mline=self.main_line.theta)
+ self.left_line.update(delta=self.left_line.phi / 2,
+ mline=self.main_line.theta)
+ ## Check if the left side has moved and update the slicer accordingly
+ if self.left_line.has_move:
+ self.main_line.update()
+ self.left_line.update(phi=None, delta=None, mline=self.main_line,
+ side=True, left=True)
+ self.right_line.update(phi=self.left_line.phi, delta=None,
+ mline=self.main_line, side=True,
+ left=False, right=True)
+ ## Check if the right side line has moved and
+ #update the slicer accordingly
+ if self.right_line.has_move:
+ self.main_line.update()
+ self.right_line.update(phi=None, delta=None, mline=self.main_line,
+ side=True, left=False, right=True)
+ self.left_line.update(phi=self.right_line.phi, delta=None,
+ mline=self.main_line, side=True, left=False)
+
+ def save(self, ev):
+ """
+ Remember the roughness for this layer and the next so that we
+ can restore on Esc.
+ """
+ self.base.freeze_axes()
+ self.main_line.save(ev)
+ self.right_line.save(ev)
+ self.left_line.save(ev)
+
+ def _post_data(self, nbins=None):
+ """
+ compute sector averaging of data2D into data1D
+
+ :param nbins: the number of point to plot for the average 1D data
+ """
+ ## get the data2D to average
+ data = self.base.data2D
+ # If we have no data, just return
+ if data is None:
+ return
+ ## Averaging
+ from sas.sascalc.dataloader.manipulations import SectorQ
+ radius = self.qmax
+ phimin = -self.left_line.phi + self.main_line.theta
+ phimax = self.left_line.phi + self.main_line.theta
+ bin_base = self.bin_base
+ if nbins is None:
+ nbins = 20
+ sect = SectorQ(r_min=0.0, r_max=radius,
+ phi_min=phimin + math.pi,
+ phi_max=phimax + math.pi, nbins=nbins, base=bin_base)
+
+ sector = sect(self.base.data2D)
+ ##Create 1D data resulting from average
+
+ if hasattr(sector, "dxl"):
+ dxl = sector.dxl
+ else:
+ dxl = None
+ if hasattr(sector, "dxw"):
+ dxw = sector.dxw
+ else:
+ dxw = None
+ new_plot = Data1D(x=sector.x, y=sector.y, dy=sector.dy, dx=sector.dx)
+ new_plot.dxl = dxl
+ new_plot.dxw = dxw
+ new_plot.name = "SectorQ" + "(" + self.base.data2D.name + ")"
+ new_plot.source = self.base.data2D.source
+ #new_plot.info=self.base.data2D.info
+ new_plot.interactive = True
+ new_plot.detector = self.base.data2D.detector
+ ## If the data file does not tell us what the axes are, just assume...
+ new_plot.xaxis("\\rm{Q}", "A^{-1}")
+ new_plot.yaxis("\\rm{Intensity}", "cm^{-1}")
+ if hasattr(data, "scale") and data.scale == 'linear' and \
+ self.base.data2D.name.count("Residuals") > 0:
+ new_plot.ytransform = 'y'
+ new_plot.yaxis("\\rm{Residuals} ", "/")
+
+ new_plot.group_id = "2daverage" + self.base.data2D.name
+ new_plot.id = "SectorQ" + self.base.data2D.name
+ new_plot.is_data = True
+ self.base.parent.update_theory(data_id=data.id, theory=new_plot)
+ wx.PostEvent(self.base.parent,
+ NewPlotEvent(plot=new_plot, title="SectorQ" + self.base.data2D.name))
+
+ def moveend(self, ev):
+ """
+ Called a dragging motion ends.Get slicer event
+ """
+ self.base.thaw_axes()
+ ## Post parameters
+ event = SlicerParameterEvent()
+ event.type = self.__class__.__name__
+ event.params = self.get_params()
+ ## Send slicer paramers to plotter2D
+ wx.PostEvent(self.base, event)
+
+ def restore(self):
+ """
+ Restore the roughness for this layer.
+ """
+ self.main_line.restore()
+ self.left_line.restore()
+ self.right_line.restore()
+
+ def move(self, x, y, ev):
+ """
+ Process move to a new position, making sure that the move is allowed.
+ """
+ pass
+
+ def set_cursor(self, x, y):
+ """
+ """
+ pass
+
+ def get_params(self):
+ """
+ Store a copy of values of parameters of the slicer into a dictionary.
+
+ :return params: the dictionary created
+
+ """
+ params = {}
+ ## Always make sure that the left and the right line are at phi
+ ## angle of the middle line
+ if math.fabs(self.left_line.phi) != math.fabs(self.right_line.phi):
+ msg = "Phi left and phi right are different"
+ msg += " %f, %f" % (self.left_line.phi, self.right_line.phi)
+ raise ValueError, msg
+ params["Phi [deg]"] = self.main_line.theta * 180 / math.pi
+ params["Delta_Phi [deg]"] = math.fabs(self.left_line.phi * 180 / math.pi)
+ params["nbins"] = self.nbins
+ params["binning base"] = self.bin_base
+ return params
+
+ def set_params(self, params):
+ """
+ Receive a dictionary and reset the slicer with values contained
+ in the values of the dictionary.
+
+ :param params: a dictionary containing name of slicer parameters and
+ values the user assigned to the slicer.
+ """
+ main = params["Phi [deg]"] * math.pi / 180
+ phi = math.fabs(params["Delta_Phi [deg]"] * math.pi / 180)
+ self.nbins = int(params["nbins"])
+ self.bin_base = params["binning base"]
+ self.main_line.theta = main
+ ## Reset the slicer parameters
+ self.main_line.update()
+ self.right_line.update(phi=phi, delta=None, mline=self.main_line,
+ side=True, right=True)
+ self.left_line.update(phi=phi, delta=None,
+ mline=self.main_line, side=True)
+ ## post the new corresponding data
+ self._post_data(nbins=self.nbins)
+
+ def freeze_axes(self):
+ """
+ """
+ self.base.freeze_axes()
+
+ def thaw_axes(self):
+ """
+ """
+ self.base.thaw_axes()
+
+ def draw(self):
+ """
+ """
+ self.base.draw()
+
+
+class SideInteractor(_BaseInteractor):
+ """
+ Draw an oblique line
+
+ :param phi: the phase between the middle line and one side line
+ :param theta2: the angle between the middle line and x- axis
+
+ """
+ def __init__(self, base, axes, color='black', zorder=5, r=1.0,
+ phi=math.pi / 4, theta2=math.pi / 3):
+ """
+ """
+ _BaseInteractor.__init__(self, base, axes, color=color)
+ ## Initialize the class
+ self.markers = []
+ self.axes = axes
+ ## compute the value of the angle between the current line and
+ ## the x-axis
+ self.save_theta = theta2 + phi
+ self.theta = theta2 + phi
+ ## the value of the middle line angle with respect to the x-axis
+ self.theta2 = theta2
+ ## Radius to find polar coordinates this line's endpoints
+ self.radius = r
+ ## phi is the phase between the current line and the middle line
+ self.phi = phi
+ ## End points polar coordinates
+ x1 = self.radius * math.cos(self.theta)
+ y1 = self.radius * math.sin(self.theta)
+ x2 = -1 * self.radius * math.cos(self.theta)
+ y2 = -1 * self.radius * math.sin(self.theta)
+ ## defining a new marker
+ self.inner_marker = self.axes.plot([x1 / 2.5], [y1 / 2.5], linestyle='',
+ marker='s', markersize=10,
+ color=self.color, alpha=0.6,
+ pickradius=5, label="pick",
+ zorder=zorder, visible=True)[0]
+
+ ## Defining the current line
+ self.line = self.axes.plot([x1, x2], [y1, y2],
+ linestyle='-', marker='',
+ color=self.color, visible=True)[0]
+ ## Flag to differentiate the left line from the right line motion
+ self.left_moving = False
+ ## Flag to define a motion
+ self.has_move = False
+ ## connecting markers and draw the picture
+ self.connect_markers([self.inner_marker, self.line])
+
+ def set_layer(self, n):
+ """
+ Allow adding plot to the same panel
+
+ :param n: the number of layer
+
+ """
+ self.layernum = n
+ self.update()
+
+ def clear(self):
+ """
+ Clear the slicer and all connected events related to this slicer
+ """
+ self.clear_markers()
+ try:
+ self.line.remove()
+ self.inner_marker.remove()
+ except:
+ # Old version of matplotlib
+ for item in range(len(self.axes.lines)):
+ del self.axes.lines[0]
+
+ def update(self, phi=None, delta=None, mline=None,
+ side=False, left=False, right=False):
+ """
+ Draw oblique line
+
+ :param phi: the phase between the middle line and the current line
+ :param delta: phi/2 applied only when the mline was moved
+
+ """
+ #print "update left or right ", self.has_move
+ self.left_moving = left
+ theta3 = 0
+ if phi is not None:
+ self.phi = phi
+ if delta is None:
+ delta = 0
+ if right:
+ self.phi = -1 * math.fabs(self.phi)
+ #delta=-delta
+ else:
+ self.phi = math.fabs(self.phi)
+ if side:
+ self.theta = mline.theta + self.phi
+
+ if mline is not None:
+ if delta != 0:
+ self.theta2 = mline + delta
+ else:
+ self.theta2 = mline.theta
+ if delta == 0:
+ theta3 = self.theta + delta
+ else:
+ theta3 = self.theta2 + delta
+ x1 = self.radius * math.cos(theta3)
+ y1 = self.radius * math.sin(theta3)
+ x2 = -1 * self.radius * math.cos(theta3)
+ y2 = -1 * self.radius * math.sin(theta3)
+ self.inner_marker.set(xdata=[x1 / 2.5], ydata=[y1 / 2.5])
+ self.line.set(xdata=[x1, x2], ydata=[y1, y2])
+
+ def save(self, ev):
+ """
+ Remember the roughness for this layer and the next so that we
+ can restore on Esc.
+ """
+ self.save_theta = self.theta
+ self.base.freeze_axes()
+
+ def moveend(self, ev):
+ """
+ """
+ self.has_move = False
+ self.base.moveend(ev)
+
+ def restore(self):
+ """
+ Restore the roughness for this layer.
+ """
+ self.theta = self.save_theta
+
+ def move(self, x, y, ev):
+ """
+ Process move to a new position, making sure that the move is allowed.
+ """
+ self.theta = math.atan2(y, x)
+ self.has_move = True
+ #ToDo: Simplify below
+ if not self.left_moving:
+ if self.theta2 - self.theta <= 0 and self.theta2 > 0:
+ self.restore()
+ return
+ elif self.theta2 < 0 and self.theta < 0 and \
+ self.theta - self.theta2 >= 0:
+ self.restore()
+ return
+ elif self.theta2 < 0 and self.theta > 0 and \
+ (self.theta2 + 2 * math.pi - self.theta) >= math.pi / 2:
+ self.restore()
+ return
+ elif self.theta2 < 0 and self.theta < 0 and \
+ (self.theta2 - self.theta) >= math.pi / 2:
+ self.restore()
+ return
+ elif self.theta2 > 0 and (self.theta2 - self.theta >= math.pi / 2 or \
+ (self.theta2 - self.theta >= math.pi / 2)):
+ self.restore()
+ return
+ else:
+ if self.theta < 0 and (self.theta + math.pi * 2 - self.theta2) <= 0:
+ self.restore()
+ return
+ elif self.theta2 < 0 and (self.theta - self.theta2) <= 0:
+ self.restore()
+ return
+ elif self.theta > 0 and self.theta - self.theta2 <= 0:
+ self.restore()
+ return
+ elif self.theta - self.theta2 >= math.pi / 2 or \
+ ((self.theta + math.pi * 2 - self.theta2) >= math.pi / 2 and \
+ self.theta < 0 and self.theta2 > 0):
+ self.restore()
+ return
+
+ self.phi = math.fabs(self.theta2 - self.theta)
+ if self.phi > math.pi:
+ self.phi = 2 * math.pi - math.fabs(self.theta2 - self.theta)
+ self.base.base.update()
+
+ def set_cursor(self, x, y):
+ """
+ """
+ self.move(x, y, None)
+ self.update()
+
+ def get_params(self):
+ """
+ """
+ params = {}
+ params["radius"] = self.radius
+ params["theta"] = self.theta
+ return params
+
+ def set_params(self, params):
+ """
+ """
+ x = params["radius"]
+ self.set_cursor(x, None)
+
+
+class LineInteractor(_BaseInteractor):
+ """
+ Select an annulus through a 2D plot
+ """
+ def __init__(self, base, axes, color='black',
+ zorder=5, r=1.0, theta=math.pi / 4):
+ """
+ """
+ _BaseInteractor.__init__(self, base, axes, color=color)
+
+ self.markers = []
+ self.axes = axes
+ self.save_theta = theta
+ self.theta = theta
+ self.radius = r
+ self.scale = 10.0
+ # Inner circle
+ x1 = self.radius * math.cos(self.theta)
+ y1 = self.radius * math.sin(self.theta)
+ x2 = -1 * self.radius * math.cos(self.theta)
+ y2 = -1 * self.radius * math.sin(self.theta)
+ # Inner circle marker
+ self.inner_marker = self.axes.plot([x1 / 2.5], [y1 / 2.5], linestyle='',
+ marker='s', markersize=10,
+ color=self.color, alpha=0.6,
+ pickradius=5, label="pick",
+ zorder=zorder,
+ visible=True)[0]
+ self.line = self.axes.plot([x1, x2], [y1, y2],
+ linestyle='-', marker='',
+ color=self.color, visible=True)[0]
+ self.npts = 20
+ self.has_move = False
+ self.connect_markers([self.inner_marker, self.line])
+ self.update()
+
+ def set_layer(self, n):
+ """
+ """
+ self.layernum = n
+ self.update()
+
+ def clear(self):
+ """
+ """
+ self.clear_markers()
+ try:
+ self.inner_marker.remove()
+ self.line.remove()
+ except:
+ # Old version of matplotlib
+ for item in range(len(self.axes.lines)):
+ del self.axes.lines[0]
+
+ def update(self, theta=None):
+ """
+ Draw the new roughness on the graph.
+ """
+
+ if theta is not None:
+ self.theta = theta
+ x1 = self.radius * math.cos(self.theta)
+ y1 = self.radius * math.sin(self.theta)
+ x2 = -1 * self.radius * math.cos(self.theta)
+ y2 = -1 * self.radius * math.sin(self.theta)
+
+ self.inner_marker.set(xdata=[x1 / 2.5], ydata=[y1 / 2.5])
+ self.line.set(xdata=[x1, x2], ydata=[y1, y2])
+
+ def save(self, ev):
+ """
+ Remember the roughness for this layer and the next so that we
+ can restore on Esc.
+ """
+ self.save_theta = self.theta
+ self.base.freeze_axes()
+
+ def moveend(self, ev):
+ """
+ """
+ self.has_move = False
+ self.base.moveend(ev)
+
+ def restore(self):
+ """
+ Restore the roughness for this layer.
+ """
+ self.theta = self.save_theta
+
+ def move(self, x, y, ev):
+ """
+ Process move to a new position, making sure that the move is allowed.
+ """
+ self.theta = math.atan2(y, x)
+ self.has_move = True
+ self.base.base.update()
+
+ def set_cursor(self, x, y):
+ """
+ """
+ self.move(x, y, None)
+ self.update()
+
+ def get_params(self):
+ """
+ """
+ params = {}
+ params["radius"] = self.radius
+ params["theta"] = self.theta
+ return params
+
+ def set_params(self, params):
+ """
+ """
+ x = params["radius"]
+ self.set_cursor(x, None)
diff --git a/src/sas/sasgui/guiframe/local_perspectives/plotting/SimplePlot.py b/src/sas/sasgui/guiframe/local_perspectives/plotting/SimplePlot.py
index e57dcd8..33abfa4 100644
--- a/src/sas/sasgui/guiframe/local_perspectives/plotting/SimplePlot.py
+++ b/src/sas/sasgui/guiframe/local_perspectives/plotting/SimplePlot.py
@@ -1,327 +1,327 @@
-"""
-Simple Plot Frame : supporting only copy, print, scale
-"""
-import wx
-from sas.sasgui.guiframe.local_perspectives.plotting.Plotter2D import ModelPanel2D as PlotPanel
-from sas.sasgui.plottools.toolbar import NavigationToolBar
-from sas.sasgui.plottools.plottables import Graph
-from sas.sasgui.guiframe.utils import PanelMenu
-from sas.sasgui.guiframe.events import StatusEvent
-
-class SimplePlotPanel(PlotPanel):
- """
- PlotPanel for 1d and 2d
- """
- _window_caption = 'Simple Plot'
- def __init__(self, parent, id=-1, color=None,
- dpi=None, style=wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs):
- """
- Init
- """
- PlotPanel.__init__(self, parent, id=id, style=style, **kwargs)
-
- self.SetColor(wx.WHITE)
-
- self.toolbar = NavigationToolBar(parent=self, canvas=self.canvas)
- self.toolbar.Show(False)
- self.scale = parent.scale
- self.window_caption = self._window_caption
-
- def draw(self):
- """
- """
- self.resizing = False
- self.canvas.set_resizing(self.resizing)
- self.canvas.draw()
-
- def add_toolbar(self):
- """
- """
- pass
-
- def onContextMenu(self, event):
- """
- 2D plot context menu
-
- :param event: wx context event
-
- """
- slicerpop = PanelMenu()
- slicerpop.set_plots(self.plots)
- slicerpop.set_graph(self.graph)
-
- wx_id = wx.NewId()
- slicerpop.Append(wx_id, '&Save Image')
- wx.EVT_MENU(self, wx_id, self.onSaveImage)
-
- wx_id = wx.NewId()
- slicerpop.Append(wx_id, '&Print Image', 'Print image')
- wx.EVT_MENU(self, wx_id, self.onPrint)
-
- wx_id = wx.NewId()
- slicerpop.Append(wx_id, '&Copy to Clipboard', 'Copy to the clipboard')
- wx.EVT_MENU(self, wx_id, self.OnCopyFigureMenu)
-
- if self.dimension != 3:
- slicerpop.AppendSeparator()
- wx_id = wx.NewId()
- slicerpop.Append(wx_id, '&Toggle Grid On/Off', 'Toggle Grid On/Off')
- wx.EVT_MENU(self, wx_id, self.on_grid_onoff)
-
- if self.data.__class__.__name__ == 'Data1D':
- slicerpop.AppendSeparator()
- wx_id = wx.NewId()
- slicerpop.Append(wx_id, '&Change Scale')
- wx.EVT_MENU(self, wx_id, self._onProperties)
- elif self.data2D.__class__.__name__ == 'Data2D':
- slicerpop.AppendSeparator()
- wx_id = wx.NewId()
- slicerpop.Append(wx_id, '&Toggle Linear/Log Scale')
- wx.EVT_MENU(self, wx_id, self._onToggleScale)
-
- try:
- pos_evt = event.GetPosition()
- pos = self.ScreenToClient(pos_evt)
- except:
- pos_x, pos_y = self.toolbar.GetPositionTuple()
- pos = (pos_x, pos_y + 5)
- self.PopupMenu(slicerpop, pos)
- if self.scale != None:
- self.parent.scale2d = self.scale
-
- def on_grid_onoff(self, event):
- """
- On grid on/off
- """
- switch = (not self.grid_on)
- self.onGridOnOff(switch)
-
- def onLeftDown(self, event):
- """
- left button down and ready to drag
-
- """
- # Check that the LEFT button was pressed
- if event.button == 1:
- self.leftdown = True
- ax = event.inaxes
- if ax != None:
- self.xInit, self.yInit = event.xdata, event.ydata
- try:
- pos_x = float(event.xdata) # / size_x
- pos_y = float(event.ydata) # / size_y
- pos_x = "%8.3g" % pos_x
- pos_y = "%8.3g" % pos_y
- self.position = str(pos_x), str(pos_y)
- wx.PostEvent(self.parent, StatusEvent(status=self.position))
- except:
- self.position = None
-
- def _OnReSize(self, event):
- """
- On response of the resize of a panel, set axes_visiable False
- """
- self.resizing = False
- if self.x_size != None:
- if self.x_size == self.GetSize():
- self.canvas.set_resizing(self.resizing)
- return
- self.x_size = self.GetSize()
-
- # Ready for another event
- # Do not remove this Skip.
- # Otherwise it will get runtime error on wx>=2.9.
- event.Skip()
- # set the resizing flag
- self.canvas.set_resizing(self.resizing)
- pos_x, pos_y = self.GetPositionTuple()
- if pos_x != 0 and pos_y != 0:
- self.size, _ = self.GetClientSizeTuple()
- self.SetSizer(self.sizer)
-
- def on_set_focus(self, event):
- """
- By pass default boundary blue color drawing
- """
- pass
-
- def on_kill_focus(self, event):
- """
- Reset the panel color
- """
- pass
-
- def show_plot(self, plot):
- """
- Show the plot
- """
- _yaxis, _yunit = plot.get_yaxis()
- _xaxis, _xunit = plot.get_xaxis()
- self.data = plot
- self.plots[plot.name] = plot
- # Axis scales
- if plot.xtransform != None:
- self.xLabel = plot.xtransform
- if plot.ytransform != None:
- self.yLabel = plot.ytransform
- # Init graph
- self.graph = Graph()
- # Add plot: Handles both 1D and 2D
- self.graph.add(self.data)
- self.canvas.set_resizing(False)
- if self.data.__class__.__name__ == 'Data2D':
- self.data2D = plot
- elif self.data.__class__.__name__ == 'Data1D':
- self._onEVT_FUNC_PROPERTY(show=False)
- # Axes
- self.graph.xaxis(_xaxis, _xunit)
- self.graph.yaxis(_yaxis, _yunit)
- self.xaxis(_xaxis, _xunit)
- self.yaxis(_yaxis, _yunit)
- self.set_xscale(self.xscale)
- self.set_yscale(self.yscale)
- self.graph.render(self)
-
-class PlotFrame(wx.Frame):
- """
- Frame for simple plot
- """
- def __init__(self, parent, id, title, scale='log_{10}',
- size=wx.Size(550, 470), show_menu_icons=True):
- """
- comment
- :param parent: parent panel/container
- """
- # Initialize the Frame object
- wx.Frame.__init__(self, parent, id, title, wx.DefaultPosition, size)
-
- # Panel for 1D plot
- self.parent = parent
- self._mgr = None
- self.menu_bar = None
- self._default_save_location = None
- self.scale = scale
- self._show_menu_icons = show_menu_icons
- self.plotpanel = SimplePlotPanel(self, -1)
- self._build_menubar()
-
- def _build_menubar(self):
- """
- Build menubar
- """
- tsize = (13, 13)
- save_bmp = wx.ArtProvider.GetBitmap(wx.ART_FILE_SAVE_AS, wx.ART_TOOLBAR, tsize)
- quit_bmp = wx.ArtProvider.GetBitmap(wx.ART_QUIT, wx.ART_TOOLBAR, tsize)
- print_bmp = wx.ArtProvider.GetBitmap(wx.ART_PRINT, wx.ART_TOOLBAR, tsize)
- copy_bmp = wx.ArtProvider.GetBitmap(wx.ART_COPY, wx.ART_TOOLBAR, tsize)
- menu_bar = wx.MenuBar()
-
- menu = wx.Menu()
- id = wx.NewId()
- save_item = wx.MenuItem(menu, id, "&Save Image")
- menu.AppendItem(save_item)
- wx.EVT_MENU(self, id, self.on_save_file)
-
- id = wx.NewId()
- print_item = wx.MenuItem(menu, id, "&Print Image")
- menu.AppendItem(print_item)
- wx.EVT_MENU(self, id, self.on_print_image)
-
- menu.AppendSeparator()
- id = wx.NewId()
- quit_item = wx.MenuItem(menu, id, "&Quit")
- menu.AppendItem(quit_item)
-
- menu_bar.Append(menu, "&File")
- wx.EVT_MENU(self, id, self.on_close)
-
- menu_edit = wx.Menu()
- id = wx.NewId()
- copy_item = wx.MenuItem(menu_edit, id, "&Copy")
- menu_edit.AppendItem(copy_item)
- wx.EVT_MENU(self, id, self.on_copy_image)
-
- if self._show_menu_icons:
- save_item.SetBitmap(save_bmp)
- print_item.SetBitmap(print_bmp)
- quit_item.SetBitmap(quit_bmp)
- copy_item.SetBitmap(copy_bmp)
-
- menu_bar.Append(menu_edit, "&Edit")
- self.menu_bar = menu_bar
- self.SetMenuBar(self.menu_bar)
-
- def set_plot_unfocus(self):
- """
- un focusing
- """
- pass
-
- def add_plot(self, plot):
- """
- Add Image
- """
- plotpanel = self.plotpanel
- plotpanel.scale = self.scale
- plotpanel.show_plot(plot)
-
- def set_schedule_full_draw(self, panel, func):
- """
- """
- self.plotpanel.resizing = False
-
- def im_show(self, img):
- """
- Show background image
- :Param img: [imread(path) from matplotlib.pyplot]
- """
- self.plotpanel.subplot.imshow(img)
-
- def set_schedule(self, schedule=False):
- """
- """
- #Not implemented
-
- def disable_app_menu(self, panel):
- """
- """
- #Not implemented
-
- def get_current_context_menu(self, plotpanel):
- """
- """
- #Not implemented
-
- def on_save_file(self, event):
- """
- Save image
- """
- self.plotpanel.onSaveImage(event)
-
- def on_print_image(self, event):
- """
- Save image
- """
- self.plotpanel.onPrint(event)
-
- def on_print_preview(self, event):
- """
- Save image
- """
- self.plotpanel.onPrinterPreview(event)
-
- def on_copy_image(self, event):
- """
- Save image
- """
- self.plotpanel.OnCopyFigureMenu(event)
-
- def on_close(self, event):
- """
- On Close
- """
- try:
- self.parent.set_scale2d(self.scale)
- self.parent.on_panel_close(event)
- except:
- self.Destroy()
+"""
+Simple Plot Frame : supporting only copy, print, scale
+"""
+import wx
+from sas.sasgui.guiframe.local_perspectives.plotting.Plotter2D import ModelPanel2D as PlotPanel
+from sas.sasgui.plottools.toolbar import NavigationToolBar
+from sas.sasgui.plottools.plottables import Graph
+from sas.sasgui.guiframe.utils import PanelMenu
+from sas.sasgui.guiframe.events import StatusEvent
+
+class SimplePlotPanel(PlotPanel):
+ """
+ PlotPanel for 1d and 2d
+ """
+ _window_caption = 'Simple Plot'
+ def __init__(self, parent, id=-1, color=None,
+ dpi=None, style=wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs):
+ """
+ Init
+ """
+ PlotPanel.__init__(self, parent, id=id, style=style, **kwargs)
+
+ self.SetColor(wx.WHITE)
+
+ self.toolbar = NavigationToolBar(parent=self, canvas=self.canvas)
+ self.toolbar.Show(False)
+ self.scale = parent.scale
+ self.window_caption = self._window_caption
+
+ def draw(self):
+ """
+ """
+ self.resizing = False
+ self.canvas.set_resizing(self.resizing)
+ self.canvas.draw()
+
+ def add_toolbar(self):
+ """
+ """
+ pass
+
+ def onContextMenu(self, event):
+ """
+ 2D plot context menu
+
+ :param event: wx context event
+
+ """
+ slicerpop = PanelMenu()
+ slicerpop.set_plots(self.plots)
+ slicerpop.set_graph(self.graph)
+
+ wx_id = wx.NewId()
+ slicerpop.Append(wx_id, '&Save Image')
+ wx.EVT_MENU(self, wx_id, self.onSaveImage)
+
+ wx_id = wx.NewId()
+ slicerpop.Append(wx_id, '&Print Image', 'Print image')
+ wx.EVT_MENU(self, wx_id, self.onPrint)
+
+ wx_id = wx.NewId()
+ slicerpop.Append(wx_id, '&Copy to Clipboard', 'Copy to the clipboard')
+ wx.EVT_MENU(self, wx_id, self.OnCopyFigureMenu)
+
+ if self.dimension != 3:
+ slicerpop.AppendSeparator()
+ wx_id = wx.NewId()
+ slicerpop.Append(wx_id, '&Toggle Grid On/Off', 'Toggle Grid On/Off')
+ wx.EVT_MENU(self, wx_id, self.on_grid_onoff)
+
+ if self.data.__class__.__name__ == 'Data1D':
+ slicerpop.AppendSeparator()
+ wx_id = wx.NewId()
+ slicerpop.Append(wx_id, '&Change Scale')
+ wx.EVT_MENU(self, wx_id, self._onProperties)
+ elif self.data2D.__class__.__name__ == 'Data2D':
+ slicerpop.AppendSeparator()
+ wx_id = wx.NewId()
+ slicerpop.Append(wx_id, '&Toggle Linear/Log Scale')
+ wx.EVT_MENU(self, wx_id, self._onToggleScale)
+
+ try:
+ pos_evt = event.GetPosition()
+ pos = self.ScreenToClient(pos_evt)
+ except:
+ pos_x, pos_y = self.toolbar.GetPositionTuple()
+ pos = (pos_x, pos_y + 5)
+ self.PopupMenu(slicerpop, pos)
+ if self.scale is not None:
+ self.parent.scale2d = self.scale
+
+ def on_grid_onoff(self, event):
+ """
+ On grid on/off
+ """
+ switch = (not self.grid_on)
+ self.onGridOnOff(switch)
+
+ def onLeftDown(self, event):
+ """
+ left button down and ready to drag
+
+ """
+ # Check that the LEFT button was pressed
+ if event.button == 1:
+ self.leftdown = True
+ ax = event.inaxes
+ if ax is not None:
+ self.xInit, self.yInit = event.xdata, event.ydata
+ try:
+ pos_x = float(event.xdata) # / size_x
+ pos_y = float(event.ydata) # / size_y
+ pos_x = "%8.3g" % pos_x
+ pos_y = "%8.3g" % pos_y
+ self.position = str(pos_x), str(pos_y)
+ wx.PostEvent(self.parent, StatusEvent(status=self.position))
+ except:
+ self.position = None
+
+ def _OnReSize(self, event):
+ """
+ On response of the resize of a panel, set axes_visiable False
+ """
+ self.resizing = False
+ if self.x_size is not None:
+ if self.x_size == self.GetSize():
+ self.canvas.set_resizing(self.resizing)
+ return
+ self.x_size = self.GetSize()
+
+ # Ready for another event
+ # Do not remove this Skip.
+ # Otherwise it will get runtime error on wx>=2.9.
+ event.Skip()
+ # set the resizing flag
+ self.canvas.set_resizing(self.resizing)
+ pos_x, pos_y = self.GetPositionTuple()
+ if pos_x != 0 and pos_y != 0:
+ self.size, _ = self.GetClientSizeTuple()
+ self.SetSizer(self.sizer)
+
+ def on_set_focus(self, event):
+ """
+ By pass default boundary blue color drawing
+ """
+ pass
+
+ def on_kill_focus(self, event):
+ """
+ Reset the panel color
+ """
+ pass
+
+ def show_plot(self, plot):
+ """
+ Show the plot
+ """
+ _yaxis, _yunit = plot.get_yaxis()
+ _xaxis, _xunit = plot.get_xaxis()
+ self.data = plot
+ self.plots[plot.name] = plot
+ # Axis scales
+ if plot.xtransform is not None:
+ self.xLabel = plot.xtransform
+ if plot.ytransform is not None:
+ self.yLabel = plot.ytransform
+ # Init graph
+ self.graph = Graph()
+ # Add plot: Handles both 1D and 2D
+ self.graph.add(self.data)
+ self.canvas.set_resizing(False)
+ if self.data.__class__.__name__ == 'Data2D':
+ self.data2D = plot
+ elif self.data.__class__.__name__ == 'Data1D':
+ self._onEVT_FUNC_PROPERTY(show=False)
+ # Axes
+ self.graph.xaxis(_xaxis, _xunit)
+ self.graph.yaxis(_yaxis, _yunit)
+ self.xaxis(_xaxis, _xunit)
+ self.yaxis(_yaxis, _yunit)
+ self.set_xscale(self.xscale)
+ self.set_yscale(self.yscale)
+ self.graph.render(self)
+
+class PlotFrame(wx.Frame):
+ """
+ Frame for simple plot
+ """
+ def __init__(self, parent, id, title, scale='log_{10}',
+ size=wx.Size(550, 470), show_menu_icons=True):
+ """
+ comment
+ :param parent: parent panel/container
+ """
+ # Initialize the Frame object
+ wx.Frame.__init__(self, parent, id, title, wx.DefaultPosition, size)
+
+ # Panel for 1D plot
+ self.parent = parent
+ self._mgr = None
+ self.menu_bar = None
+ self._default_save_location = None
+ self.scale = scale
+ self._show_menu_icons = show_menu_icons
+ self.plotpanel = SimplePlotPanel(self, -1)
+ self._build_menubar()
+
+ def _build_menubar(self):
+ """
+ Build menubar
+ """
+ tsize = (13, 13)
+ save_bmp = wx.ArtProvider.GetBitmap(wx.ART_FILE_SAVE_AS, wx.ART_TOOLBAR, tsize)
+ quit_bmp = wx.ArtProvider.GetBitmap(wx.ART_QUIT, wx.ART_TOOLBAR, tsize)
+ print_bmp = wx.ArtProvider.GetBitmap(wx.ART_PRINT, wx.ART_TOOLBAR, tsize)
+ copy_bmp = wx.ArtProvider.GetBitmap(wx.ART_COPY, wx.ART_TOOLBAR, tsize)
+ menu_bar = wx.MenuBar()
+
+ menu = wx.Menu()
+ id = wx.NewId()
+ save_item = wx.MenuItem(menu, id, "&Save Image")
+ menu.AppendItem(save_item)
+ wx.EVT_MENU(self, id, self.on_save_file)
+
+ id = wx.NewId()
+ print_item = wx.MenuItem(menu, id, "&Print Image")
+ menu.AppendItem(print_item)
+ wx.EVT_MENU(self, id, self.on_print_image)
+
+ menu.AppendSeparator()
+ id = wx.NewId()
+ quit_item = wx.MenuItem(menu, id, "&Quit")
+ menu.AppendItem(quit_item)
+
+ menu_bar.Append(menu, "&File")
+ wx.EVT_MENU(self, id, self.on_close)
+
+ menu_edit = wx.Menu()
+ id = wx.NewId()
+ copy_item = wx.MenuItem(menu_edit, id, "&Copy")
+ menu_edit.AppendItem(copy_item)
+ wx.EVT_MENU(self, id, self.on_copy_image)
+
+ if self._show_menu_icons:
+ save_item.SetBitmap(save_bmp)
+ print_item.SetBitmap(print_bmp)
+ quit_item.SetBitmap(quit_bmp)
+ copy_item.SetBitmap(copy_bmp)
+
+ menu_bar.Append(menu_edit, "&Edit")
+ self.menu_bar = menu_bar
+ self.SetMenuBar(self.menu_bar)
+
+ def set_plot_unfocus(self):
+ """
+ un focusing
+ """
+ pass
+
+ def add_plot(self, plot):
+ """
+ Add Image
+ """
+ plotpanel = self.plotpanel
+ plotpanel.scale = self.scale
+ plotpanel.show_plot(plot)
+
+ def set_schedule_full_draw(self, panel, func):
+ """
+ """
+ self.plotpanel.resizing = False
+
+ def im_show(self, img):
+ """
+ Show background image
+ :Param img: [imread(path) from matplotlib.pyplot]
+ """
+ self.plotpanel.subplot.imshow(img)
+
+ def set_schedule(self, schedule=False):
+ """
+ """
+ #Not implemented
+
+ def disable_app_menu(self, panel):
+ """
+ """
+ #Not implemented
+
+ def get_current_context_menu(self, plotpanel):
+ """
+ """
+ #Not implemented
+
+ def on_save_file(self, event):
+ """
+ Save image
+ """
+ self.plotpanel.onSaveImage(event)
+
+ def on_print_image(self, event):
+ """
+ Save image
+ """
+ self.plotpanel.onPrint(event)
+
+ def on_print_preview(self, event):
+ """
+ Save image
+ """
+ self.plotpanel.onPrinterPreview(event)
+
+ def on_copy_image(self, event):
+ """
+ Save image
+ """
+ self.plotpanel.OnCopyFigureMenu(event)
+
+ def on_close(self, event):
+ """
+ On Close
+ """
+ try:
+ self.parent.set_scale2d(self.scale)
+ self.parent.on_panel_close(event)
+ except:
+ self.Destroy()
diff --git a/src/sas/sasgui/guiframe/local_perspectives/plotting/SlicerParameters.py b/src/sas/sasgui/guiframe/local_perspectives/plotting/SlicerParameters.py
deleted file mode 100644
index 2ba740d..0000000
--- a/src/sas/sasgui/guiframe/local_perspectives/plotting/SlicerParameters.py
+++ /dev/null
@@ -1,146 +0,0 @@
-
-
-import wx
-import wx.lib.newevent
-#from copy import deepcopy
-from sas.sasgui.guiframe.events import EVT_SLICER_PARS
-from sas.sasgui.guiframe.utils import format_number
-from sas.sasgui.guiframe.events import EVT_SLICER
-from sas.sasgui.guiframe.events import SlicerParameterEvent
-
-
-class SlicerParameterPanel(wx.Dialog):
- """
- Panel class to show the slicer parameters
- """
- #TODO: show units
- #TODO: order parameters properly
-
- def __init__(self, parent, *args, **kwargs):
- """
- Dialog window that allow to edit parameters slicer
- by entering new values
- """
- wx.Dialog.__init__(self, parent, *args, **kwargs)
- self.params = {}
- self.parent = parent
- self.type = None
- self.listeners = []
- self.parameters = []
- self.bck = wx.GridBagSizer(5, 5)
- self.SetSizer(self.bck)
- label = "Right-click on 2D plot for slicer options"
- title = wx.StaticText(self, -1, label, style=wx.ALIGN_LEFT)
- self.bck.Add(title, (0, 0), (1, 2),
- flag=wx.LEFT | wx.ALIGN_CENTER_VERTICAL, border=15)
- # Bindings
- self.parent.Bind(EVT_SLICER, self.onEVT_SLICER)
- self.parent.Bind(EVT_SLICER_PARS, self.onParamChange)
-
- def onEVT_SLICER(self, event):
- """
- Process EVT_SLICER events
- When the slicer changes, update the panel
-
- :param event: EVT_SLICER event
- """
- event.Skip()
- if event.obj_class == None:
- self.set_slicer(None, None)
- else:
- self.set_slicer(event.type, event.params)
-
- def set_slicer(self, type, params):
- """
- Rebuild the panel
- """
- self.bck.Clear(True)
- self.type = type
- if type == None:
- label = "Right-click on 2D plot for slicer options"
- title = wx.StaticText(self, -1, label, style=wx.ALIGN_LEFT)
- self.bck.Add(title, (0, 0), (1, 2),
- flag=wx.LEFT | wx.ALIGN_CENTER_VERTICAL, border=15)
- else:
- title = wx.StaticText(self, -1,
- "Slicer Parameters", style=wx.ALIGN_LEFT)
- self.bck.Add(title, (0, 0), (1, 2),
- flag=wx.LEFT | wx.ALIGN_CENTER_VERTICAL, border=15)
- ix = 0
- iy = 0
- self.parameters = []
- keys = params.keys()
- keys.sort()
- for item in keys:
- iy += 1
- ix = 0
- if not item in ["count", "errors"]:
- text = wx.StaticText(self, -1, item, style=wx.ALIGN_LEFT)
- self.bck.Add(text, (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- ctl = wx.TextCtrl(self, -1, size=(80, 20),
- style=wx.TE_PROCESS_ENTER)
- hint_msg = "Modify the value of %s to change" % item
- hint_msg += " the 2D slicer"
- ctl.SetToolTipString(hint_msg)
- ix = 1
- ctl.SetValue(format_number(str(params[item])))
- self.Bind(wx.EVT_TEXT_ENTER, self.onTextEnter)
- self.parameters.append([item, ctl])
- self.bck.Add(ctl, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix = 3
- self.bck.Add((20, 20), (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- else:
- text = wx.StaticText(self, -1, item + " : ",
- style=wx.ALIGN_LEFT)
- self.bck.Add(text, (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- ctl = wx.StaticText(self, -1,
- format_number(str(params[item])),
- style=wx.ALIGN_LEFT)
- ix = 1
- self.bck.Add(ctl, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- iy += 1
- ix = 1
- self.bck.Add((20, 20), (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- self.bck.Layout()
- self.bck.Fit(self)
- self.parent.GetSizer().Layout()
-
- def onParamChange(self, evt):
- """
- receive an event end reset value text fields
- inside self.parameters
- """
- evt.Skip()
- if evt.type == "UPDATE":
- for item in self.parameters:
- if item[0] in evt.params:
- item[1].SetValue("%-5.3g" % evt.params[item[0]])
- item[1].Refresh()
-
- def onTextEnter(self, evt):
- """
- Parameters have changed
- """
- params = {}
- has_error = False
- for item in self.parameters:
- try:
- params[item[0]] = float(item[1].GetValue())
- item[1].SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
- item[1].Refresh()
- except:
- has_error = True
- item[1].SetBackgroundColour("pink")
- item[1].Refresh()
-
- if has_error == False:
- # Post parameter event
- ##parent hier is plotter2D
- event = SlicerParameterEvent(type=self.type, params=params)
- wx.PostEvent(self.parent, event)
diff --git a/src/sas/sasgui/guiframe/local_perspectives/plotting/__init__.py b/src/sas/sasgui/guiframe/local_perspectives/plotting/__init__.py
index 8403c02..b88d224 100644
--- a/src/sas/sasgui/guiframe/local_perspectives/plotting/__init__.py
+++ b/src/sas/sasgui/guiframe/local_perspectives/plotting/__init__.py
@@ -1,2 +1,2 @@
-PLUGIN_ID = "Plotting plug-in 1.0"
-from sas.sasgui.guiframe.local_perspectives.plotting import *
+PLUGIN_ID = "Plotting plug-in 1.0"
+from sas.sasgui.guiframe.local_perspectives.plotting import *
diff --git a/src/sas/sasgui/guiframe/local_perspectives/plotting/binder.py b/src/sas/sasgui/guiframe/local_perspectives/plotting/binder.py
index 6fd2a72..12a90f7 100644
--- a/src/sas/sasgui/guiframe/local_perspectives/plotting/binder.py
+++ b/src/sas/sasgui/guiframe/local_perspectives/plotting/binder.py
@@ -4,6 +4,8 @@ Extension to MPL to support the binding of artists to key/mouse events.
import logging
import sys
+logger = logging.getLogger(__name__)
+
class Selection(object):
"""
Store and compare selections.
@@ -69,7 +71,7 @@ class BindArtist(object):
canvas.mpl_disconnect(canvas.button_pick_id)
canvas.mpl_disconnect(canvas.scroll_pick_id)
except:
- logging.error(sys.exc_value)
+ logger.error(sys.exc_value)
self.canvas = canvas
self.figure = figure
self.clearall()
diff --git a/src/sas/sasgui/guiframe/local_perspectives/plotting/boxMask.py b/src/sas/sasgui/guiframe/local_perspectives/plotting/boxMask.py
index 7b396b0..71cb4da 100644
--- a/src/sas/sasgui/guiframe/local_perspectives/plotting/boxMask.py
+++ b/src/sas/sasgui/guiframe/local_perspectives/plotting/boxMask.py
@@ -1,241 +1,241 @@
-import math
-from BaseInteractor import _BaseInteractor
-from boxSum import PointInteractor
-from boxSum import VerticalDoubleLine
-from boxSum import HorizontalDoubleLine
-
-
-class BoxMask(_BaseInteractor):
- """
- BoxMask Class: determine 2 rectangular area to find the pixel of
- a Data inside of box.
-
- Uses PointerInteractor , VerticalDoubleLine,HorizontalDoubleLine.
-
- :param zorder: Artists with lower zorder values are drawn first.
- :param x_min: the minimum value of the x coordinate
- :param x_max: the maximum value of the x coordinate
- :param y_min: the minimum value of the y coordinate
- :param y_max: the maximum value of the y coordinate
-
- """
- def __init__(self, base, axes, color='black', zorder=3, side=None,
- x_min=0.008, x_max=0.008, y_min=0.0025, y_max=0.0025):
- """
- """
- _BaseInteractor.__init__(self, base, axes, color=color)
- # # class initialization
- # # list of Boxmask markers
- self.markers = []
- self.axes = axes
- self.mask = None
- self.is_inside = side
- # # connect the artist for the motion
- self.connect = self.base.connect
- # # when qmax is reached the selected line is reset
- # the its previous value
- self.qmax = min(self.base.data.xmax, self.base.data.xmin)
- # # Define the box limits
- self.xmin = -1 * 0.5 * min(math.fabs(self.base.data.xmax),
- math.fabs(self.base.data.xmin))
- self.ymin = -1 * 0.5 * min(math.fabs(self.base.data.xmax),
- math.fabs(self.base.data.xmin))
- self.xmax = 0.5 * min(math.fabs(self.base.data.xmax),
- math.fabs(self.base.data.xmin))
- self.ymax = 0.5 * min(math.fabs(self.base.data.xmax),
- math.fabs(self.base.data.xmin))
- # # center of the box
- self.center_x = 0.0002
- self.center_y = 0.0003
- # # Number of points on the plot
- self.nbins = 20
- # # Define initial result the summation
- self.count = 0
- self.error = 0
- self.data = self.base.data
- # # Flag to determine if the current figure has moved
- # # set to False == no motion , set to True== motion
- self.has_move = False
- # # Create Box edges
- self.horizontal_lines = HorizontalDoubleLine(self,
- self.base.subplot,
- color='blue',
- zorder=zorder,
- y=self.ymax,
- x=self.xmax,
- center_x=self.center_x,
- center_y=self.center_y)
- self.horizontal_lines.qmax = self.qmax
-
- self.vertical_lines = VerticalDoubleLine(self,
- self.base.subplot,
- color='grey',
- zorder=zorder,
- y=self.ymax,
- x=self.xmax,
- center_x=self.center_x,
- center_y=self.center_y)
- self.vertical_lines.qmax = self.qmax
-
- self.center = PointInteractor(self,
- self.base.subplot, color='grey',
- zorder=zorder,
- center_x=self.center_x,
- center_y=self.center_y)
- # # Save the name of the slicer panel associate with this slicer
- self.panel_name = ""
- # # Update and post slicer parameters
- self.update()
- self._post_data()
-
- def clear(self):
- """
- Clear the slicer and all connected events related to this slicer
- """
- self.clear_markers()
- self.horizontal_lines.clear()
- self.vertical_lines.clear()
- self.center.clear()
- self.base.connect.clearall()
-
- def update(self):
- """
- Respond to changes in the model by recalculating the profiles and
- resetting the widgets.
- """
- # check if the center point has moved and update the figure accordingly
- if self.center.has_move:
- self.center.update()
- self.horizontal_lines.update(center=self.center)
- self.vertical_lines.update(center=self.center)
- # # check if the horizontal lines have moved and update
- # the figure accordingly
- if self.horizontal_lines.has_move:
- self.horizontal_lines.update()
- self.vertical_lines.update(y1=self.horizontal_lines.y1,
- y2=self.horizontal_lines.y2,
- height=self.horizontal_lines.half_height)
- # # check if the vertical lines have moved and update
- # the figure accordingly
- if self.vertical_lines.has_move:
- self.vertical_lines.update()
- self.horizontal_lines.update(x1=self.vertical_lines.x1,
- x2=self.vertical_lines.x2,
- width=self.vertical_lines.half_width)
- # if self.is_inside != None:
- out = self._post_data()
- return out
-
- def save(self, ev):
- """
- Remember the roughness for this layer and the next so that we
- can restore on Esc.
- """
- self.base.freeze_axes()
- self.horizontal_lines.save(ev)
- self.vertical_lines.save(ev)
- self.center.save(ev)
-
- def _post_data(self):
- """
- Get the limits of the boxsum and compute the sum of the pixel
- contained in that region and the error on that sum
- """
- from sas.sascalc.dataloader.manipulations import Boxcut
- # # Data 2D for which the pixel will be summed
- data = self.base.data
- mask = data.mask
- # # the region of the summation
- x_min = self.horizontal_lines.x2
- x_max = self.horizontal_lines.x1
- y_min = self.vertical_lines.y2
- y_max = self.vertical_lines.y1
- mask = Boxcut(x_min=x_min, x_max=x_max, y_min=y_min, y_max=y_max)
-
- if self.is_inside:
- out = (mask(data) == False)
- else:
- out = (mask(data))
- # self.base.data.mask=out
- self.mask = mask
- return out
-
- def moveend(self, ev):
- """
- After a dragging motion this function is called to compute
- the error and the sum of pixel of a given data 2D
- """
- self.base.thaw_axes()
- # # post
- self._post_data()
-
- def restore(self):
- """
- Restore the roughness for this layer.
- """
- self.horizontal_lines.restore()
- self.vertical_lines.restore()
- self.center.restore()
-
- def move(self, x, y, ev):
- """
- Process move to a new position, making sure that the move is allowed.
- """
- pass
-
- def set_cursor(self, x, y):
- pass
-
- def get_params(self):
- """
- Store a copy of values of parameters of the slicer into a dictionary.
-
- :return params: the dictionary created
-
- """
- params = {}
- params["Width"] = math.fabs(self.vertical_lines.half_width) * 2
- params["Height"] = math.fabs(self.horizontal_lines.half_height) * 2
- params["center_x"] = self.center.x
- params["center_y"] = self.center.y
- return params
-
- def get_mask(self):
- """
- return mask as a result of boxcut
- """
- mask = self.mask
- return mask
-
- def set_params(self, params):
- """
- Receive a dictionary and reset the slicer with values contained
- in the values of the dictionary.
-
- :param params: a dictionary containing name of slicer parameters and
- values the user assigned to the slicer.
- """
- x_max = math.fabs(params["Width"]) / 2
- y_max = math.fabs(params["Height"]) / 2
-
- self.center_x = params["center_x"]
- self.center_y = params["center_y"]
- # update the slicer given values of params
- self.center.update(center_x=self.center_x, center_y=self.center_y)
- self.horizontal_lines.update(center=self.center, width=x_max, height=y_max)
- self.vertical_lines.update(center=self.center, width=x_max, height=y_max)
- # compute the new error and sum given values of params
- self._post_data()
-
- def freeze_axes(self):
- self.base.freeze_axes()
-
- def thaw_axes(self):
- self.base.thaw_axes()
-
- def draw(self):
- self.base.update()
-
-class inner_BoxMask(BoxMask):
- def __call__(self):
- self.base.data.mask = (self._post_data() == False)
+import math
+from BaseInteractor import _BaseInteractor
+from boxSum import PointInteractor
+from boxSum import VerticalDoubleLine
+from boxSum import HorizontalDoubleLine
+
+
+class BoxMask(_BaseInteractor):
+ """
+ BoxMask Class: determine 2 rectangular area to find the pixel of
+ a Data inside of box.
+
+ Uses PointerInteractor , VerticalDoubleLine,HorizontalDoubleLine.
+
+ :param zorder: Artists with lower zorder values are drawn first.
+ :param x_min: the minimum value of the x coordinate
+ :param x_max: the maximum value of the x coordinate
+ :param y_min: the minimum value of the y coordinate
+ :param y_max: the maximum value of the y coordinate
+
+ """
+ def __init__(self, base, axes, color='black', zorder=3, side=None,
+ x_min=0.008, x_max=0.008, y_min=0.0025, y_max=0.0025):
+ """
+ """
+ _BaseInteractor.__init__(self, base, axes, color=color)
+ # # class initialization
+ # # list of Boxmask markers
+ self.markers = []
+ self.axes = axes
+ self.mask = None
+ self.is_inside = side
+ # # connect the artist for the motion
+ self.connect = self.base.connect
+ # # when qmax is reached the selected line is reset
+ # the its previous value
+ self.qmax = min(self.base.data.xmax, self.base.data.xmin)
+ # # Define the box limits
+ self.xmin = -1 * 0.5 * min(math.fabs(self.base.data.xmax),
+ math.fabs(self.base.data.xmin))
+ self.ymin = -1 * 0.5 * min(math.fabs(self.base.data.xmax),
+ math.fabs(self.base.data.xmin))
+ self.xmax = 0.5 * min(math.fabs(self.base.data.xmax),
+ math.fabs(self.base.data.xmin))
+ self.ymax = 0.5 * min(math.fabs(self.base.data.xmax),
+ math.fabs(self.base.data.xmin))
+ # # center of the box
+ self.center_x = 0.0002
+ self.center_y = 0.0003
+ # # Number of points on the plot
+ self.nbins = 20
+ # # Define initial result the summation
+ self.count = 0
+ self.error = 0
+ self.data = self.base.data
+ # # Flag to determine if the current figure has moved
+ # # set to False == no motion , set to True== motion
+ self.has_move = False
+ # # Create Box edges
+ self.horizontal_lines = HorizontalDoubleLine(self,
+ self.base.subplot,
+ color='blue',
+ zorder=zorder,
+ y=self.ymax,
+ x=self.xmax,
+ center_x=self.center_x,
+ center_y=self.center_y)
+ self.horizontal_lines.qmax = self.qmax
+
+ self.vertical_lines = VerticalDoubleLine(self,
+ self.base.subplot,
+ color='grey',
+ zorder=zorder,
+ y=self.ymax,
+ x=self.xmax,
+ center_x=self.center_x,
+ center_y=self.center_y)
+ self.vertical_lines.qmax = self.qmax
+
+ self.center = PointInteractor(self,
+ self.base.subplot, color='grey',
+ zorder=zorder,
+ center_x=self.center_x,
+ center_y=self.center_y)
+ # # Save the name of the slicer panel associate with this slicer
+ self.panel_name = ""
+ # # Update and post slicer parameters
+ self.update()
+ self._post_data()
+
+ def clear(self):
+ """
+ Clear the slicer and all connected events related to this slicer
+ """
+ self.clear_markers()
+ self.horizontal_lines.clear()
+ self.vertical_lines.clear()
+ self.center.clear()
+ self.base.connect.clearall()
+
+ def update(self):
+ """
+ Respond to changes in the model by recalculating the profiles and
+ resetting the widgets.
+ """
+ # check if the center point has moved and update the figure accordingly
+ if self.center.has_move:
+ self.center.update()
+ self.horizontal_lines.update(center=self.center)
+ self.vertical_lines.update(center=self.center)
+ # # check if the horizontal lines have moved and update
+ # the figure accordingly
+ if self.horizontal_lines.has_move:
+ self.horizontal_lines.update()
+ self.vertical_lines.update(y1=self.horizontal_lines.y1,
+ y2=self.horizontal_lines.y2,
+ height=self.horizontal_lines.half_height)
+ # # check if the vertical lines have moved and update
+ # the figure accordingly
+ if self.vertical_lines.has_move:
+ self.vertical_lines.update()
+ self.horizontal_lines.update(x1=self.vertical_lines.x1,
+ x2=self.vertical_lines.x2,
+ width=self.vertical_lines.half_width)
+ # if self.is_inside is not None:
+ out = self._post_data()
+ return out
+
+ def save(self, ev):
+ """
+ Remember the roughness for this layer and the next so that we
+ can restore on Esc.
+ """
+ self.base.freeze_axes()
+ self.horizontal_lines.save(ev)
+ self.vertical_lines.save(ev)
+ self.center.save(ev)
+
+ def _post_data(self):
+ """
+ Get the limits of the boxsum and compute the sum of the pixel
+ contained in that region and the error on that sum
+ """
+ from sas.sascalc.dataloader.manipulations import Boxcut
+ # # Data 2D for which the pixel will be summed
+ data = self.base.data
+ mask = data.mask
+ # # the region of the summation
+ x_min = self.horizontal_lines.x2
+ x_max = self.horizontal_lines.x1
+ y_min = self.vertical_lines.y2
+ y_max = self.vertical_lines.y1
+ mask = Boxcut(x_min=x_min, x_max=x_max, y_min=y_min, y_max=y_max)
+
+ if self.is_inside:
+ out = (mask(data) == False)
+ else:
+ out = (mask(data))
+ # self.base.data.mask=out
+ self.mask = mask
+ return out
+
+ def moveend(self, ev):
+ """
+ After a dragging motion this function is called to compute
+ the error and the sum of pixel of a given data 2D
+ """
+ self.base.thaw_axes()
+ # # post
+ self._post_data()
+
+ def restore(self):
+ """
+ Restore the roughness for this layer.
+ """
+ self.horizontal_lines.restore()
+ self.vertical_lines.restore()
+ self.center.restore()
+
+ def move(self, x, y, ev):
+ """
+ Process move to a new position, making sure that the move is allowed.
+ """
+ pass
+
+ def set_cursor(self, x, y):
+ pass
+
+ def get_params(self):
+ """
+ Store a copy of values of parameters of the slicer into a dictionary.
+
+ :return params: the dictionary created
+
+ """
+ params = {}
+ params["Width"] = math.fabs(self.vertical_lines.half_width) * 2
+ params["Height"] = math.fabs(self.horizontal_lines.half_height) * 2
+ params["center_x"] = self.center.x
+ params["center_y"] = self.center.y
+ return params
+
+ def get_mask(self):
+ """
+ return mask as a result of boxcut
+ """
+ mask = self.mask
+ return mask
+
+ def set_params(self, params):
+ """
+ Receive a dictionary and reset the slicer with values contained
+ in the values of the dictionary.
+
+ :param params: a dictionary containing name of slicer parameters and
+ values the user assigned to the slicer.
+ """
+ x_max = math.fabs(params["Width"]) / 2
+ y_max = math.fabs(params["Height"]) / 2
+
+ self.center_x = params["center_x"]
+ self.center_y = params["center_y"]
+ # update the slicer given values of params
+ self.center.update(center_x=self.center_x, center_y=self.center_y)
+ self.horizontal_lines.update(center=self.center, width=x_max, height=y_max)
+ self.vertical_lines.update(center=self.center, width=x_max, height=y_max)
+ # compute the new error and sum given values of params
+ self._post_data()
+
+ def freeze_axes(self):
+ self.base.freeze_axes()
+
+ def thaw_axes(self):
+ self.base.thaw_axes()
+
+ def draw(self):
+ self.base.update()
+
+class inner_BoxMask(BoxMask):
+ def __call__(self):
+ self.base.data.mask = (self._post_data() == False)
diff --git a/src/sas/sasgui/guiframe/local_perspectives/plotting/boxSlicer.py b/src/sas/sasgui/guiframe/local_perspectives/plotting/boxSlicer.py
index fe19cbf..47bb345 100644
--- a/src/sas/sasgui/guiframe/local_perspectives/plotting/boxSlicer.py
+++ b/src/sas/sasgui/guiframe/local_perspectives/plotting/boxSlicer.py
@@ -1,540 +1,540 @@
-import wx
-import math
-import numpy
-from sas.sasgui.guiframe.events import NewPlotEvent
-from sas.sasgui.guiframe.events import StatusEvent
-from sas.sasgui.guiframe.events import SlicerParameterEvent
-from sas.sasgui.guiframe.events import EVT_SLICER_PARS
-from BaseInteractor import _BaseInteractor
-from sas.sasgui.guiframe.dataFitting import Data1D
-
-
-class BoxInteractor(_BaseInteractor):
- """
- BoxInteractor define a rectangle that return data1D average of Data2D
- in a rectangle area defined by -x, x ,y, -y
- """
- def __init__(self, base, axes, color='black', zorder=3):
- _BaseInteractor.__init__(self, base, axes, color=color)
- # # Class initialization
- self.markers = []
- self.axes = axes
- # #connecting artist
- self.connect = self.base.connect
- # # which direction is the preferred interaction direction
- self.direction = None
- # # determine x y values
- self.x = 0.5 * min(math.fabs(self.base.data2D.xmax),
- math.fabs(self.base.data2D.xmin))
- self.y = 0.5 * min(math.fabs(self.base.data2D.xmax),
- math.fabs(self.base.data2D.xmin))
- # # when reach qmax reset the graph
- self.qmax = max(self.base.data2D.xmax, self.base.data2D.xmin,
- self.base.data2D.ymax, self.base.data2D.ymin)
- # # Number of points on the plot
- self.nbins = 30
- # # If True, I(|Q|) will be return, otherwise,
- # negative q-values are allowed
- self.fold = True
- # # reference of the current Slab averaging
- self.averager = None
- # # Create vertical and horizaontal lines for the rectangle
- self.vertical_lines = VerticalLines(self,
- self.base.subplot,
- color='blue',
- zorder=zorder,
- y=self.y,
- x=self.x)
- self.vertical_lines.qmax = self.qmax
-
- self.horizontal_lines = HorizontalLines(self,
- self.base.subplot,
- color='green',
- zorder=zorder,
- x=self.x,
- y=self.y)
- self.horizontal_lines.qmax = self.qmax
- # # draw the rectangle and plost the data 1D resulting
- # # of averaging data2D
- self.update()
- self._post_data()
- # # Bind to slice parameter events
- self.base.Bind(EVT_SLICER_PARS, self._onEVT_SLICER_PARS)
-
- def _onEVT_SLICER_PARS(self, event):
- """
- receive an event containing parameters values to reset the slicer
-
- :param event: event of type SlicerParameterEvent with params as
- attribute
- """
- wx.PostEvent(self.base.parent,
- StatusEvent(status="BoxSlicer._onEVT_SLICER_PARS"))
- event.Skip()
- if event.type == self.__class__.__name__:
- self.set_params(event.params)
- self.base.update()
-
- def update_and_post(self):
- """
- Update the slicer and plot the resulting data
- """
- self.update()
- self._post_data()
-
- def set_layer(self, n):
- """
- Allow adding plot to the same panel
-
- :param n: the number of layer
-
- """
- self.layernum = n
- self.update()
-
- def clear(self):
- """
- Clear the slicer and all connected events related to this slicer
- """
- self.averager = None
- self.clear_markers()
- self.horizontal_lines.clear()
- self.vertical_lines.clear()
- self.base.connect.clearall()
- self.base.Unbind(EVT_SLICER_PARS)
-
- def update(self):
- """
- Respond to changes in the model by recalculating the profiles and
- resetting the widgets.
- """
- # #Update the slicer if an horizontal line is dragged
- if self.horizontal_lines.has_move:
- self.horizontal_lines.update()
- self.vertical_lines.update(y=self.horizontal_lines.y)
- # #Update the slicer if a vertical line is dragged
- if self.vertical_lines.has_move:
- self.vertical_lines.update()
- self.horizontal_lines.update(x=self.vertical_lines.x)
-
- def save(self, ev):
- """
- Remember the roughness for this layer and the next so that we
- can restore on Esc.
- """
- self.base.freeze_axes()
- self.vertical_lines.save(ev)
- self.horizontal_lines.save(ev)
-
- def _post_data(self):
- pass
-
- def post_data(self, new_slab=None, nbins=None, direction=None):
- """
- post data averaging in Qx or Qy given new_slab type
-
- :param new_slab: slicer that determine with direction to average
- :param nbins: the number of points plotted when averaging
- :param direction: the direction of averaging
-
- """
- if self.direction == None:
- self.direction = direction
-
- x_min = -1 * math.fabs(self.vertical_lines.x)
- x_max = math.fabs(self.vertical_lines.x)
- y_min = -1 * math.fabs(self.horizontal_lines.y)
- y_max = math.fabs(self.horizontal_lines.y)
-
- if nbins != None:
- self.nbins = nbins
- if self.averager == None:
- if new_slab == None:
- msg = "post data:cannot average , averager is empty"
- raise ValueError, msg
- self.averager = new_slab
- if self.direction == "X":
- if self.fold:
- x_low = 0
- else:
- x_low = math.fabs(x_min)
- bin_width = (x_max + x_low) / self.nbins
- elif self.direction == "Y":
- if self.fold:
- y_low = 0
- else:
- y_low = math.fabs(y_min)
- bin_width = (y_max + y_low) / self.nbins
- else:
- msg = "post data:no Box Average direction was supplied"
- raise ValueError, msg
- # # Average data2D given Qx or Qy
- box = self.averager(x_min=x_min, x_max=x_max, y_min=y_min, y_max=y_max,
- bin_width=bin_width)
- box.fold = self.fold
- boxavg = box(self.base.data2D)
- # 3 Create Data1D to plot
- if hasattr(boxavg, "dxl"):
- dxl = boxavg.dxl
- else:
- dxl = None
- if hasattr(boxavg, "dxw"):
- dxw = boxavg.dxw
- else:
- dxw = None
- new_plot = Data1D(x=boxavg.x, y=boxavg.y, dy=boxavg.dy)
- new_plot.dxl = dxl
- new_plot.dxw = dxw
- new_plot.name = str(self.averager.__name__) + \
- "(" + self.base.data2D.name + ")"
- new_plot.source = self.base.data2D.source
- new_plot.interactive = True
- new_plot.detector = self.base.data2D.detector
- # # If the data file does not tell us what the axes are, just assume...
- new_plot.xaxis("\\rm{Q}", "A^{-1}")
- new_plot.yaxis("\\rm{Intensity} ", "cm^{-1}")
-
- data = self.base.data2D
- if hasattr(data, "scale") and data.scale == 'linear' and \
- self.base.data2D.name.count("Residuals") > 0:
- new_plot.ytransform = 'y'
- new_plot.yaxis("\\rm{Residuals} ", "/")
-
- new_plot.group_id = "2daverage" + self.base.data2D.name
- new_plot.id = (self.averager.__name__) + self.base.data2D.name
- new_plot.is_data = True
- self.base.parent.update_theory(data_id=self.base.data2D.id, \
- theory=new_plot)
- wx.PostEvent(self.base.parent,
- NewPlotEvent(plot=new_plot, title=str(self.averager.__name__)))
-
- def moveend(self, ev):
- """
- Called after a dragging event.
- Post the slicer new parameters and creates a new Data1D
- corresponding to the new average
- """
- self.base.thaw_axes()
- # Post paramters
- event = SlicerParameterEvent()
- event.type = self.__class__.__name__
- event.params = self.get_params()
- wx.PostEvent(self.base.parent, event)
- # create the new data1D
- self._post_data()
-
- def restore(self):
- """
- Restore the roughness for this layer.
- """
- self.horizontal_lines.restore()
- self.vertical_lines.restore()
-
- def move(self, x, y, ev):
- """
- Process move to a new position, making sure that the move is allowed.
- """
- pass
-
- def set_cursor(self, x, y):
- pass
-
- def get_params(self):
- """
- Store a copy of values of parameters of the slicer into a dictionary.
-
- :return params: the dictionary created
-
- """
- params = {}
- params["x_max"] = math.fabs(self.vertical_lines.x)
- params["y_max"] = math.fabs(self.horizontal_lines.y)
- params["nbins"] = self.nbins
- return params
-
- def set_params(self, params):
- """
- Receive a dictionary and reset the slicer with values contained
- in the values of the dictionary.
-
- :param params: a dictionary containing name of slicer parameters and
- values the user assigned to the slicer.
- """
- self.x = float(math.fabs(params["x_max"]))
- self.y = float(math.fabs(params["y_max"]))
- self.nbins = params["nbins"]
-
- self.horizontal_lines.update(x=self.x, y=self.y)
- self.vertical_lines.update(x=self.x, y=self.y)
- self.post_data(nbins=None)
-
- def freeze_axes(self):
- """
- """
- self.base.freeze_axes()
-
- def thaw_axes(self):
- """
- """
- self.base.thaw_axes()
-
- def draw(self):
- """
- """
- self.base.draw()
-
-
-class HorizontalLines(_BaseInteractor):
- """
- Draw 2 Horizontal lines centered on (0,0) that can move
- on the x- direction and in opposite direction
- """
- def __init__(self, base, axes, color='black', zorder=5, x=0.5, y=0.5):
- """
- """
- _BaseInteractor.__init__(self, base, axes, color=color)
- # #Class initialization
- self.markers = []
- self.axes = axes
- # # Saving the end points of two lines
- self.x = x
- self.save_x = x
-
- self.y = y
- self.save_y = y
- # # Creating a marker
- # Inner circle marker
- self.inner_marker = self.axes.plot([0], [self.y], linestyle='',
- marker='s', markersize=10,
- color=self.color, alpha=0.6,
- pickradius=5, label="pick",
- zorder=zorder,
- visible=True)[0]
- # # Define 2 horizontal lines
- self.top_line = self.axes.plot([self.x, -self.x], [self.y, self.y],
- linestyle='-', marker='',
- color=self.color, visible=True)[0]
- self.bottom_line = self.axes.plot([self.x, -self.x], [-self.y, -self.y],
- linestyle='-', marker='',
- color=self.color, visible=True)[0]
- # # Flag to check the motion of the lines
- self.has_move = False
- # # Connecting markers to mouse events and draw
- self.connect_markers([self.top_line, self.inner_marker])
- self.update()
-
- def set_layer(self, n):
- """
- Allow adding plot to the same panel
-
- :param n: the number of layer
-
- """
- self.layernum = n
- self.update()
-
- def clear(self):
- """
- Clear this slicer and its markers
- """
- self.clear_markers()
- try:
- self.inner_marker.remove()
- self.top_line.remove()
- self.bottom_line.remove()
- except:
- # Old version of matplotlib
- for item in range(len(self.axes.lines)):
- del self.axes.lines[0]
-
- def update(self, x=None, y=None):
- """
- Draw the new roughness on the graph.
-
- :param x: x-coordinates to reset current class x
- :param y: y-coordinates to reset current class y
-
- """
- # # Reset x, y- coordinates if send as parameters
- if x != None:
- self.x = numpy.sign(self.x) * math.fabs(x)
- if y != None:
- self.y = numpy.sign(self.y) * math.fabs(y)
- # # Draw lines and markers
- self.inner_marker.set(xdata=[0], ydata=[self.y])
- self.top_line.set(xdata=[self.x, -self.x], ydata=[self.y, self.y])
- self.bottom_line.set(xdata=[self.x, -self.x], ydata=[-self.y, -self.y])
-
- def save(self, ev):
- """
- Remember the roughness for this layer and the next so that we
- can restore on Esc.
- """
- self.save_x = self.x
- self.save_y = self.y
- self.base.freeze_axes()
-
- def moveend(self, ev):
- """
- Called after a dragging this edge and set self.has_move to False
- to specify the end of dragging motion
- """
- self.has_move = False
- self.base.moveend(ev)
-
- def restore(self):
- """
- Restore the roughness for this layer.
- """
- self.x = self.save_x
- self.y = self.save_y
-
- def move(self, x, y, ev):
- """
- Process move to a new position, making sure that the move is allowed.
- """
- self.y = y
- self.has_move = True
- self.base.base.update()
-
-
-class VerticalLines(_BaseInteractor):
- """
- Select an annulus through a 2D plot
- """
- def __init__(self, base, axes, color='black', zorder=5, x=0.5, y=0.5):
- """
- """
- _BaseInteractor.__init__(self, base, axes, color=color)
- self.markers = []
- self.axes = axes
- self.x = math.fabs(x)
- self.save_x = self.x
- self.y = math.fabs(y)
- self.save_y = y
- # Inner circle marker
- self.inner_marker = self.axes.plot([self.x], [0], linestyle='',
- marker='s', markersize=10,
- color=self.color, alpha=0.6,
- pickradius=5, label="pick",
- zorder=zorder, visible=True)[0]
- self.right_line = self.axes.plot([self.x, self.x],
- [self.y, -self.y],
- linestyle='-', marker='',
- color=self.color, visible=True)[0]
- self.left_line = self.axes.plot([-self.x, -self.x],
- [self.y, -self.y],
- linestyle='-', marker='',
- color=self.color, visible=True)[0]
- self.has_move = False
- self.connect_markers([self.right_line, self.inner_marker])
- self.update()
-
- def set_layer(self, n):
- """
- Allow adding plot to the same panel
-
- :param n: the number of layer
-
- """
- self.layernum = n
- self.update()
-
- def clear(self):
- """
- Clear this slicer and its markers
- """
- self.clear_markers()
- try:
- self.inner_marker.remove()
- self.left_line.remove()
- self.right_line.remove()
- except:
- # Old version of matplotlib
- for item in range(len(self.axes.lines)):
- del self.axes.lines[0]
-
- def update(self, x=None, y=None):
- """
- Draw the new roughness on the graph.
-
- :param x: x-coordinates to reset current class x
- :param y: y-coordinates to reset current class y
-
- """
- # # reset x, y -coordinates if given as parameters
- if x != None:
- self.x = numpy.sign(self.x) * math.fabs(x)
- if y != None:
- self.y = numpy.sign(self.y) * math.fabs(y)
- # # draw lines and markers
- self.inner_marker.set(xdata=[self.x], ydata=[0])
- self.left_line.set(xdata=[-self.x, -self.x], ydata=[self.y, -self.y])
- self.right_line.set(xdata=[self.x, self.x], ydata=[self.y, -self.y])
-
- def save(self, ev):
- """
- Remember the roughness for this layer and the next so that we
- can restore on Esc.
- """
- self.save_x = self.x
- self.save_y = self.y
- self.base.freeze_axes()
-
- def moveend(self, ev):
- """
- Called after a dragging this edge and set self.has_move to False
- to specify the end of dragging motion
- """
- self.has_move = False
- self.base.moveend(ev)
-
- def restore(self):
- """
- Restore the roughness for this layer.
- """
- self.x = self.save_x
- self.y = self.save_y
-
- def move(self, x, y, ev):
- """
- Process move to a new position, making sure that the move is allowed.
- """
- self.has_move = True
- self.x = x
- self.base.base.update()
-
-
-class BoxInteractorX(BoxInteractor):
- """
- Average in Qx direction
- """
- def __init__(self, base, axes, color='black', zorder=3):
- BoxInteractor.__init__(self, base, axes, color=color)
- self.base = base
- self._post_data()
-
- def _post_data(self):
- """
- Post data creating by averaging in Qx direction
- """
- from sas.sascalc.dataloader.manipulations import SlabX
- self.post_data(SlabX, direction="X")
-
-
-class BoxInteractorY(BoxInteractor):
- """
- Average in Qy direction
- """
- def __init__(self, base, axes, color='black', zorder=3):
- BoxInteractor.__init__(self, base, axes, color=color)
- self.base = base
- self._post_data()
-
- def _post_data(self):
- """
- Post data creating by averaging in Qy direction
- """
- from sas.sascalc.dataloader.manipulations import SlabY
- self.post_data(SlabY, direction="Y")
-
+import wx
+import math
+import numpy as np
+from sas.sasgui.guiframe.events import NewPlotEvent
+from sas.sasgui.guiframe.events import StatusEvent
+from sas.sasgui.guiframe.events import SlicerParameterEvent
+from sas.sasgui.guiframe.events import EVT_SLICER_PARS
+from BaseInteractor import _BaseInteractor
+from sas.sasgui.guiframe.dataFitting import Data1D
+
+
+class BoxInteractor(_BaseInteractor):
+ """
+ BoxInteractor define a rectangle that return data1D average of Data2D
+ in a rectangle area defined by -x, x ,y, -y
+ """
+ def __init__(self, base, axes, color='black', zorder=3):
+ _BaseInteractor.__init__(self, base, axes, color=color)
+ # # Class initialization
+ self.markers = []
+ self.axes = axes
+ # #connecting artist
+ self.connect = self.base.connect
+ # # which direction is the preferred interaction direction
+ self.direction = None
+ # # determine x y values
+ self.x = 0.5 * min(math.fabs(self.base.data2D.xmax),
+ math.fabs(self.base.data2D.xmin))
+ self.y = 0.5 * min(math.fabs(self.base.data2D.xmax),
+ math.fabs(self.base.data2D.xmin))
+ # # when reach qmax reset the graph
+ self.qmax = max(self.base.data2D.xmax, self.base.data2D.xmin,
+ self.base.data2D.ymax, self.base.data2D.ymin)
+ # # Number of points on the plot
+ self.nbins = 30
+ # # If True, I(|Q|) will be return, otherwise,
+ # negative q-values are allowed
+ self.fold = True
+ # # reference of the current Slab averaging
+ self.averager = None
+ # # Create vertical and horizaontal lines for the rectangle
+ self.vertical_lines = VerticalLines(self,
+ self.base.subplot,
+ color='blue',
+ zorder=zorder,
+ y=self.y,
+ x=self.x)
+ self.vertical_lines.qmax = self.qmax
+
+ self.horizontal_lines = HorizontalLines(self,
+ self.base.subplot,
+ color='green',
+ zorder=zorder,
+ x=self.x,
+ y=self.y)
+ self.horizontal_lines.qmax = self.qmax
+ # # draw the rectangle and plost the data 1D resulting
+ # # of averaging data2D
+ self.update()
+ self._post_data()
+ # # Bind to slice parameter events
+ self.base.Bind(EVT_SLICER_PARS, self._onEVT_SLICER_PARS)
+
+ def _onEVT_SLICER_PARS(self, event):
+ """
+ receive an event containing parameters values to reset the slicer
+
+ :param event: event of type SlicerParameterEvent with params as
+ attribute
+ """
+ wx.PostEvent(self.base.parent,
+ StatusEvent(status="BoxSlicer._onEVT_SLICER_PARS"))
+ event.Skip()
+ if event.type == self.__class__.__name__:
+ self.set_params(event.params)
+ self.base.update()
+
+ def update_and_post(self):
+ """
+ Update the slicer and plot the resulting data
+ """
+ self.update()
+ self._post_data()
+
+ def set_layer(self, n):
+ """
+ Allow adding plot to the same panel
+
+ :param n: the number of layer
+
+ """
+ self.layernum = n
+ self.update()
+
+ def clear(self):
+ """
+ Clear the slicer and all connected events related to this slicer
+ """
+ self.averager = None
+ self.clear_markers()
+ self.horizontal_lines.clear()
+ self.vertical_lines.clear()
+ self.base.connect.clearall()
+ self.base.Unbind(EVT_SLICER_PARS)
+
+ def update(self):
+ """
+ Respond to changes in the model by recalculating the profiles and
+ resetting the widgets.
+ """
+ # #Update the slicer if an horizontal line is dragged
+ if self.horizontal_lines.has_move:
+ self.horizontal_lines.update()
+ self.vertical_lines.update(y=self.horizontal_lines.y)
+ # #Update the slicer if a vertical line is dragged
+ if self.vertical_lines.has_move:
+ self.vertical_lines.update()
+ self.horizontal_lines.update(x=self.vertical_lines.x)
+
+ def save(self, ev):
+ """
+ Remember the roughness for this layer and the next so that we
+ can restore on Esc.
+ """
+ self.base.freeze_axes()
+ self.vertical_lines.save(ev)
+ self.horizontal_lines.save(ev)
+
+ def _post_data(self):
+ pass
+
+ def post_data(self, new_slab=None, nbins=None, direction=None):
+ """
+ post data averaging in Qx or Qy given new_slab type
+
+ :param new_slab: slicer that determine with direction to average
+ :param nbins: the number of points plotted when averaging
+ :param direction: the direction of averaging
+
+ """
+ if self.direction is None:
+ self.direction = direction
+
+ x_min = -1 * math.fabs(self.vertical_lines.x)
+ x_max = math.fabs(self.vertical_lines.x)
+ y_min = -1 * math.fabs(self.horizontal_lines.y)
+ y_max = math.fabs(self.horizontal_lines.y)
+
+ if nbins is not None:
+ self.nbins = nbins
+ if self.averager is None:
+ if new_slab is None:
+ msg = "post data:cannot average , averager is empty"
+ raise ValueError, msg
+ self.averager = new_slab
+ if self.direction == "X":
+ if self.fold:
+ x_low = 0
+ else:
+ x_low = math.fabs(x_min)
+ bin_width = (x_max + x_low) / self.nbins
+ elif self.direction == "Y":
+ if self.fold:
+ y_low = 0
+ else:
+ y_low = math.fabs(y_min)
+ bin_width = (y_max + y_low) / self.nbins
+ else:
+ msg = "post data:no Box Average direction was supplied"
+ raise ValueError, msg
+ # # Average data2D given Qx or Qy
+ box = self.averager(x_min=x_min, x_max=x_max, y_min=y_min, y_max=y_max,
+ bin_width=bin_width)
+ box.fold = self.fold
+ boxavg = box(self.base.data2D)
+ # 3 Create Data1D to plot
+ if hasattr(boxavg, "dxl"):
+ dxl = boxavg.dxl
+ else:
+ dxl = None
+ if hasattr(boxavg, "dxw"):
+ dxw = boxavg.dxw
+ else:
+ dxw = None
+ new_plot = Data1D(x=boxavg.x, y=boxavg.y, dy=boxavg.dy)
+ new_plot.dxl = dxl
+ new_plot.dxw = dxw
+ new_plot.name = str(self.averager.__name__) + \
+ "(" + self.base.data2D.name + ")"
+ new_plot.source = self.base.data2D.source
+ new_plot.interactive = True
+ new_plot.detector = self.base.data2D.detector
+ # # If the data file does not tell us what the axes are, just assume...
+ new_plot.xaxis("\\rm{Q}", "A^{-1}")
+ new_plot.yaxis("\\rm{Intensity} ", "cm^{-1}")
+
+ data = self.base.data2D
+ if hasattr(data, "scale") and data.scale == 'linear' and \
+ self.base.data2D.name.count("Residuals") > 0:
+ new_plot.ytransform = 'y'
+ new_plot.yaxis("\\rm{Residuals} ", "/")
+
+ new_plot.group_id = "2daverage" + self.base.data2D.name
+ new_plot.id = (self.averager.__name__) + self.base.data2D.name
+ new_plot.is_data = True
+ self.base.parent.update_theory(data_id=self.base.data2D.id, \
+ theory=new_plot)
+ wx.PostEvent(self.base.parent,
+ NewPlotEvent(plot=new_plot, title=str(self.averager.__name__)))
+
+ def moveend(self, ev):
+ """
+ Called after a dragging event.
+ Post the slicer new parameters and creates a new Data1D
+ corresponding to the new average
+ """
+ self.base.thaw_axes()
+ # Post paramters
+ event = SlicerParameterEvent()
+ event.type = self.__class__.__name__
+ event.params = self.get_params()
+ wx.PostEvent(self.base.parent, event)
+ # create the new data1D
+ self._post_data()
+
+ def restore(self):
+ """
+ Restore the roughness for this layer.
+ """
+ self.horizontal_lines.restore()
+ self.vertical_lines.restore()
+
+ def move(self, x, y, ev):
+ """
+ Process move to a new position, making sure that the move is allowed.
+ """
+ pass
+
+ def set_cursor(self, x, y):
+ pass
+
+ def get_params(self):
+ """
+ Store a copy of values of parameters of the slicer into a dictionary.
+
+ :return params: the dictionary created
+
+ """
+ params = {}
+ params["x_max"] = math.fabs(self.vertical_lines.x)
+ params["y_max"] = math.fabs(self.horizontal_lines.y)
+ params["nbins"] = self.nbins
+ return params
+
+ def set_params(self, params):
+ """
+ Receive a dictionary and reset the slicer with values contained
+ in the values of the dictionary.
+
+ :param params: a dictionary containing name of slicer parameters and
+ values the user assigned to the slicer.
+ """
+ self.x = float(math.fabs(params["x_max"]))
+ self.y = float(math.fabs(params["y_max"]))
+ self.nbins = params["nbins"]
+
+ self.horizontal_lines.update(x=self.x, y=self.y)
+ self.vertical_lines.update(x=self.x, y=self.y)
+ self.post_data(nbins=None)
+
+ def freeze_axes(self):
+ """
+ """
+ self.base.freeze_axes()
+
+ def thaw_axes(self):
+ """
+ """
+ self.base.thaw_axes()
+
+ def draw(self):
+ """
+ """
+ self.base.draw()
+
+
+class HorizontalLines(_BaseInteractor):
+ """
+ Draw 2 Horizontal lines centered on (0,0) that can move
+ on the x- direction and in opposite direction
+ """
+ def __init__(self, base, axes, color='black', zorder=5, x=0.5, y=0.5):
+ """
+ """
+ _BaseInteractor.__init__(self, base, axes, color=color)
+ # #Class initialization
+ self.markers = []
+ self.axes = axes
+ # # Saving the end points of two lines
+ self.x = x
+ self.save_x = x
+
+ self.y = y
+ self.save_y = y
+ # # Creating a marker
+ # Inner circle marker
+ self.inner_marker = self.axes.plot([0], [self.y], linestyle='',
+ marker='s', markersize=10,
+ color=self.color, alpha=0.6,
+ pickradius=5, label="pick",
+ zorder=zorder,
+ visible=True)[0]
+ # # Define 2 horizontal lines
+ self.top_line = self.axes.plot([self.x, -self.x], [self.y, self.y],
+ linestyle='-', marker='',
+ color=self.color, visible=True)[0]
+ self.bottom_line = self.axes.plot([self.x, -self.x], [-self.y, -self.y],
+ linestyle='-', marker='',
+ color=self.color, visible=True)[0]
+ # # Flag to check the motion of the lines
+ self.has_move = False
+ # # Connecting markers to mouse events and draw
+ self.connect_markers([self.top_line, self.inner_marker])
+ self.update()
+
+ def set_layer(self, n):
+ """
+ Allow adding plot to the same panel
+
+ :param n: the number of layer
+
+ """
+ self.layernum = n
+ self.update()
+
+ def clear(self):
+ """
+ Clear this slicer and its markers
+ """
+ self.clear_markers()
+ try:
+ self.inner_marker.remove()
+ self.top_line.remove()
+ self.bottom_line.remove()
+ except:
+ # Old version of matplotlib
+ for item in range(len(self.axes.lines)):
+ del self.axes.lines[0]
+
+ def update(self, x=None, y=None):
+ """
+ Draw the new roughness on the graph.
+
+ :param x: x-coordinates to reset current class x
+ :param y: y-coordinates to reset current class y
+
+ """
+ # # Reset x, y- coordinates if send as parameters
+ if x is not None:
+ self.x = np.sign(self.x) * math.fabs(x)
+ if y is not None:
+ self.y = np.sign(self.y) * math.fabs(y)
+ # # Draw lines and markers
+ self.inner_marker.set(xdata=[0], ydata=[self.y])
+ self.top_line.set(xdata=[self.x, -self.x], ydata=[self.y, self.y])
+ self.bottom_line.set(xdata=[self.x, -self.x], ydata=[-self.y, -self.y])
+
+ def save(self, ev):
+ """
+ Remember the roughness for this layer and the next so that we
+ can restore on Esc.
+ """
+ self.save_x = self.x
+ self.save_y = self.y
+ self.base.freeze_axes()
+
+ def moveend(self, ev):
+ """
+ Called after a dragging this edge and set self.has_move to False
+ to specify the end of dragging motion
+ """
+ self.has_move = False
+ self.base.moveend(ev)
+
+ def restore(self):
+ """
+ Restore the roughness for this layer.
+ """
+ self.x = self.save_x
+ self.y = self.save_y
+
+ def move(self, x, y, ev):
+ """
+ Process move to a new position, making sure that the move is allowed.
+ """
+ self.y = y
+ self.has_move = True
+ self.base.base.update()
+
+
+class VerticalLines(_BaseInteractor):
+ """
+ Select an annulus through a 2D plot
+ """
+ def __init__(self, base, axes, color='black', zorder=5, x=0.5, y=0.5):
+ """
+ """
+ _BaseInteractor.__init__(self, base, axes, color=color)
+ self.markers = []
+ self.axes = axes
+ self.x = math.fabs(x)
+ self.save_x = self.x
+ self.y = math.fabs(y)
+ self.save_y = y
+ # Inner circle marker
+ self.inner_marker = self.axes.plot([self.x], [0], linestyle='',
+ marker='s', markersize=10,
+ color=self.color, alpha=0.6,
+ pickradius=5, label="pick",
+ zorder=zorder, visible=True)[0]
+ self.right_line = self.axes.plot([self.x, self.x],
+ [self.y, -self.y],
+ linestyle='-', marker='',
+ color=self.color, visible=True)[0]
+ self.left_line = self.axes.plot([-self.x, -self.x],
+ [self.y, -self.y],
+ linestyle='-', marker='',
+ color=self.color, visible=True)[0]
+ self.has_move = False
+ self.connect_markers([self.right_line, self.inner_marker])
+ self.update()
+
+ def set_layer(self, n):
+ """
+ Allow adding plot to the same panel
+
+ :param n: the number of layer
+
+ """
+ self.layernum = n
+ self.update()
+
+ def clear(self):
+ """
+ Clear this slicer and its markers
+ """
+ self.clear_markers()
+ try:
+ self.inner_marker.remove()
+ self.left_line.remove()
+ self.right_line.remove()
+ except:
+ # Old version of matplotlib
+ for item in range(len(self.axes.lines)):
+ del self.axes.lines[0]
+
+ def update(self, x=None, y=None):
+ """
+ Draw the new roughness on the graph.
+
+ :param x: x-coordinates to reset current class x
+ :param y: y-coordinates to reset current class y
+
+ """
+ # # reset x, y -coordinates if given as parameters
+ if x is not None:
+ self.x = np.sign(self.x) * math.fabs(x)
+ if y is not None:
+ self.y = np.sign(self.y) * math.fabs(y)
+ # # draw lines and markers
+ self.inner_marker.set(xdata=[self.x], ydata=[0])
+ self.left_line.set(xdata=[-self.x, -self.x], ydata=[self.y, -self.y])
+ self.right_line.set(xdata=[self.x, self.x], ydata=[self.y, -self.y])
+
+ def save(self, ev):
+ """
+ Remember the roughness for this layer and the next so that we
+ can restore on Esc.
+ """
+ self.save_x = self.x
+ self.save_y = self.y
+ self.base.freeze_axes()
+
+ def moveend(self, ev):
+ """
+ Called after a dragging this edge and set self.has_move to False
+ to specify the end of dragging motion
+ """
+ self.has_move = False
+ self.base.moveend(ev)
+
+ def restore(self):
+ """
+ Restore the roughness for this layer.
+ """
+ self.x = self.save_x
+ self.y = self.save_y
+
+ def move(self, x, y, ev):
+ """
+ Process move to a new position, making sure that the move is allowed.
+ """
+ self.has_move = True
+ self.x = x
+ self.base.base.update()
+
+
+class BoxInteractorX(BoxInteractor):
+ """
+ Average in Qx direction
+ """
+ def __init__(self, base, axes, color='black', zorder=3):
+ BoxInteractor.__init__(self, base, axes, color=color)
+ self.base = base
+ self._post_data()
+
+ def _post_data(self):
+ """
+ Post data creating by averaging in Qx direction
+ """
+ from sas.sascalc.dataloader.manipulations import SlabX
+ self.post_data(SlabX, direction="X")
+
+
+class BoxInteractorY(BoxInteractor):
+ """
+ Average in Qy direction
+ """
+ def __init__(self, base, axes, color='black', zorder=3):
+ BoxInteractor.__init__(self, base, axes, color=color)
+ self.base = base
+ self._post_data()
+
+ def _post_data(self):
+ """
+ Post data creating by averaging in Qy direction
+ """
+ from sas.sascalc.dataloader.manipulations import SlabY
+ self.post_data(SlabY, direction="Y")
+
diff --git a/src/sas/sasgui/guiframe/local_perspectives/plotting/boxSum.py b/src/sas/sasgui/guiframe/local_perspectives/plotting/boxSum.py
index 471354f..e2f42b8 100644
--- a/src/sas/sasgui/guiframe/local_perspectives/plotting/boxSum.py
+++ b/src/sas/sasgui/guiframe/local_perspectives/plotting/boxSum.py
@@ -352,9 +352,9 @@ class PointInteractor(_BaseInteractor):
"""
Draw the new roughness on the graph.
"""
- if center_x != None:
+ if center_x is not None:
self.x = center_x
- if center_y != None:
+ if center_y is not None:
self.y = center_y
self.center_marker.set(xdata=[self.x], ydata=[self.y])
self.center.set(xdata=[self.x], ydata=[self.y])
@@ -489,13 +489,13 @@ class VerticalDoubleLine(_BaseInteractor):
:param center: provided x, y coordinates of the center point
"""
# # save the new height, witdh of the rectangle if given as a param
- if width != None:
+ if width is not None:
self.half_width = width
- if height != None:
+ if height is not None:
self.half_height = height
# # If new center coordinates are given draw the rectangle
# #given these value
- if center != None:
+ if center is not None:
self.center_x = center.x
self.center_y = center.y
self.x1 = self.half_width + self.center_x
@@ -510,13 +510,13 @@ class VerticalDoubleLine(_BaseInteractor):
ydata=[self.y1, self.y2])
return
# # if x1, y1, y2, y3 are given draw the rectangle with this value
- if x1 != None:
+ if x1 is not None:
self.x1 = x1
- if x2 != None:
+ if x2 is not None:
self.x2 = x2
- if y1 != None:
+ if y1 is not None:
self.y1 = y1
- if y2 != None:
+ if y2 is not None:
self.y2 = y2
# # Draw 2 vertical lines and a marker
self.right_marker.set(xdata=[self.x1], ydata=[self.center_y])
@@ -656,13 +656,13 @@ class HorizontalDoubleLine(_BaseInteractor):
:param center: provided x, y coordinates of the center point
"""
# # save the new height, witdh of the rectangle if given as a param
- if width != None:
+ if width is not None:
self.half_width = width
- if height != None:
+ if height is not None:
self.half_height = height
# # If new center coordinates are given draw the rectangle
# #given these value
- if center != None:
+ if center is not None:
self.center_x = center.x
self.center_y = center.y
self.x1 = self.half_width + self.center_x
@@ -678,13 +678,13 @@ class HorizontalDoubleLine(_BaseInteractor):
ydata=[self.y2, self.y2])
return
# # if x1, y1, y2, y3 are given draw the rectangle with this value
- if x1 != None:
+ if x1 is not None:
self.x1 = x1
- if x2 != None:
+ if x2 is not None:
self.x2 = x2
- if y1 != None:
+ if y1 is not None:
self.y1 = y1
- if y2 != None:
+ if y2 is not None:
self.y2 = y2
# # Draw 2 vertical lines and a marker
self.top_marker.set(xdata=[self.center_x], ydata=[self.y1])
diff --git a/src/sas/sasgui/guiframe/local_perspectives/plotting/detector_dialog.py b/src/sas/sasgui/guiframe/local_perspectives/plotting/detector_dialog.py
index d16b229..fc5f90b 100644
--- a/src/sas/sasgui/guiframe/local_perspectives/plotting/detector_dialog.py
+++ b/src/sas/sasgui/guiframe/local_perspectives/plotting/detector_dialog.py
@@ -1,282 +1,282 @@
-"""
- Widget to display a 2D map of the detector
-"""
-import wx
-import sys
-from sas.sasgui.guiframe.utils import format_number
-from sas.sasgui.guiframe.events import StatusEvent
-from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as Canvas
-import matplotlib as mpl
-from matplotlib import pylab
-# FONT size
-if sys.platform.count("win32") > 0:
- FONT_VARIANT = 0
-else:
- FONT_VARIANT = 1
-
-DEFAULT_CMAP = pylab.cm.get_cmap('jet')
-
-class DetectorDialog(wx.Dialog):
- """
- Dialog box to let the user edit detector settings
- """
-
- def __init__(self, parent, id=1, base=None, dpi=None,
- cmap=DEFAULT_CMAP, reset_zmin_ctl=None,
- reset_zmax_ctl=None, *args, **kwds):
- """
- """
- kwds["style"] = wx.DEFAULT_DIALOG_STYLE
- wx.Dialog.__init__(self, parent, id=1, *args, **kwds)
- self.SetWindowVariant(variant=FONT_VARIANT)
- self.parent = base
- self.dpi = dpi
- self.cmap = cmap
- self.reset_zmin_ctl = reset_zmin_ctl
- self.reset_zmax_ctl = reset_zmax_ctl
- self.label_xnpts = wx.StaticText(self, -1, "Detector width in pixels")
- self.label_ynpts = wx.StaticText(self, -1, "Detector Height in pixels")
- self.label_qmax = wx.StaticText(self, -1, "Q max")
- self.label_zmin = wx.StaticText(self, -1,
- "Min amplitude for color map (optional)")
- self.label_zmax = wx.StaticText(self, -1,
- "Max amplitude for color map (optional)")
- self.label_beam = wx.StaticText(self, -1,
- "Beam stop radius in units of q")
- self.xnpts_ctl = wx.StaticText(self, -1, "")
- self.ynpts_ctl = wx.StaticText(self, -1, "")
- self.qmax_ctl = wx.StaticText(self, -1, "")
- self.beam_ctl = wx.StaticText(self, -1, "")
- self.zmin_ctl = wx.TextCtrl(self, -1, size=(60, 20))
- self.zmin_ctl.Bind(wx.EVT_SET_FOCUS, self.onSetFocus)
- self.zmax_ctl = wx.TextCtrl(self, -1, size=(60, 20))
- self.zmax_ctl.Bind(wx.EVT_SET_FOCUS, self.onSetFocus)
- self.static_line_3 = wx.StaticLine(self, -1)
- self.button_cancel = wx.Button(self, wx.ID_CANCEL, "Cancel")
- self.button_reset = wx.Button(self, wx.NewId(), "Reset")
- self.Bind(wx.EVT_BUTTON, self.resetValues, self.button_reset)
- self.button_ok = wx.Button(self, wx.ID_OK, "OK")
- self.Bind(wx.EVT_BUTTON, self.checkValues, self.button_ok)
- self.__set_properties()
- self.__do_layout()
- self.Fit()
-
- class Event(object):
- """
- """
- xnpts = 0
- ynpts = 0
- qpax = 0
- beam = 0
- zmin = 0
- zmax = 0
- cmap = None
- sym4 = False
-
- def onSetFocus(self, event):
- """
- Highlight the txtcrtl
- """
- # Get a handle to the TextCtrl
- widget = event.GetEventObject()
- # Select the whole control, after this event resolves
- wx.CallAfter(widget.SetSelection, -1, -1)
-
- def resetValues(self, event):
- """
- reset detector info
- """
- try:
- zmin = self.reset_zmin_ctl
- zmax = self.reset_zmax_ctl
- if zmin == None:
- zmin = ""
- if zmax == None:
- zmax = ""
- self.zmin_ctl.SetValue(str(zmin))
- self.zmax_ctl.SetValue(str(zmax))
- self.cmap = DEFAULT_CMAP
- self.cmap_selector.SetStringSelection("jet")
- self._on_select_cmap(event=None)
- except:
- msg = "error occurs while resetting Detector: %s" % sys.exc_value
- wx.PostEvent(self.parent, StatusEvent(status=msg))
-
- def checkValues(self, event):
- """
- Check the valitidity of zmin and zmax value
- zmax should be a float and zmin less than zmax
- """
- flag = True
- try:
- value = self.zmin_ctl.GetValue()
- self.zmin_ctl.SetBackgroundColour(wx.WHITE)
- self.zmin_ctl.Refresh()
- except:
- flag = False
- wx.PostEvent(self.parent, StatusEvent(status="Enter float value"))
- self.zmin_ctl.SetBackgroundColour("pink")
- self.zmin_ctl.Refresh()
- try:
- value = self.zmax_ctl.GetValue()
- if value and float(value) == 0.0:
- flag = False
- wx.PostEvent(self.parent,
- StatusEvent(status="Enter number greater than zero"))
- self.zmax_ctl.SetBackgroundColour("pink")
- self.zmax_ctl.Refresh()
- else:
- self.zmax_ctl.SetBackgroundColour(wx.WHITE)
- self.zmax_ctl.Refresh()
- except:
- flag = False
- wx.PostEvent(self.parent, StatusEvent(status="Enter Integer value"))
- self.zmax_ctl.SetBackgroundColour("pink")
- self.zmax_ctl.Refresh()
- if flag:
- event.Skip(True)
-
- def setContent(self, xnpts, ynpts, qmax, beam,
- zmin=None, zmax=None, sym=False):
- """
- received value and displayed them
-
- :param xnpts: the number of point of the x_bins of data
- :param ynpts: the number of point of the y_bins of data
- :param qmax: the maxmimum value of data pixel
- :param beam: the radius of the beam
- :param zmin: the value to get the minimum color
- :param zmax: the value to get the maximum color
- :param sym:
-
- """
- self.xnpts_ctl.SetLabel(str(format_number(xnpts)))
- self.ynpts_ctl.SetLabel(str(format_number(ynpts)))
- self.qmax_ctl.SetLabel(str(format_number(qmax)))
- self.beam_ctl.SetLabel(str(format_number(beam)))
- if zmin != None:
- self.zmin_ctl.SetValue(str(format_number(zmin)))
- if zmax != None:
- self.zmax_ctl.SetValue(str(format_number(zmax)))
-
- def getContent(self):
- """
- return event containing value to reset the detector of a given data
- """
- event = self.Event()
- t_min = self.zmin_ctl.GetValue()
- t_max = self.zmax_ctl.GetValue()
- v_min = None
- v_max = None
- if len(t_min.lstrip()) > 0:
- try:
- v_min = float(t_min)
- except:
- v_min = None
- if len(t_max.lstrip()) > 0:
- try:
- v_max = float(t_max)
- except:
- v_max = None
- event.zmin = v_min
- event.zmax = v_max
- event.cmap = self.cmap
- return event
-
- def __set_properties(self):
- """
- set proprieties of the dialog window
- """
- self.SetTitle("2D Color Map")
- self.SetSize((600, 595))
-
- def __do_layout(self):
- """
- fill the dialog window .
- """
- sizer_main = wx.BoxSizer(wx.VERTICAL)
- sizer_button = wx.BoxSizer(wx.HORIZONTAL)
- sizer_params = wx.GridBagSizer(5, 5)
- sizer_colormap = wx.BoxSizer(wx.VERTICAL)
- sizer_selection = wx.BoxSizer(wx.HORIZONTAL)
-
- iy = 0
- sizer_params.Add(self.label_xnpts, (iy, 0), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- sizer_params.Add(self.xnpts_ctl, (iy, 1), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- iy += 1
- sizer_params.Add(self.label_ynpts, (iy, 0), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- sizer_params.Add(self.ynpts_ctl, (iy, 1), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- iy += 1
- sizer_params.Add(self.label_qmax, (iy, 0), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- sizer_params.Add(self.qmax_ctl, (iy, 1), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- iy += 1
- sizer_params.Add(self.label_beam, (iy, 0), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- sizer_params.Add(self.beam_ctl, (iy, 1), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- iy += 1
- sizer_params.Add(self.label_zmin, (iy, 0), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- sizer_params.Add(self.zmin_ctl, (iy, 1), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- iy += 1
- sizer_params.Add(self.label_zmax, (iy, 0), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- sizer_params.Add(self.zmax_ctl, (iy, 1), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- iy += 1
- self.fig = mpl.figure.Figure(dpi=self.dpi, figsize=(4, 1))
- self.ax1 = self.fig.add_axes([0.05, 0.65, 0.9, 0.15])
- self.norm = mpl.colors.Normalize(vmin=0, vmax=100)
- self.cb1 = mpl.colorbar.ColorbarBase(self.ax1, cmap=self.cmap,
- norm=self.norm,
- orientation='horizontal')
- self.cb1.set_label('Detector Colors')
- self.canvas = Canvas(self, -1, self.fig)
- sizer_colormap.Add(self.canvas, 0, wx.LEFT | wx.EXPAND, 5)
- self.cmap_selector = wx.ComboBox(self, -1)
- self.cmap_selector.SetValue(str(self.cmap.name))
- maps = sorted(m for m in pylab.cm.datad if not m.endswith("_r"))
-
- for i, m in enumerate(maps):
- self.cmap_selector.Append(str(m), pylab.get_cmap(m))
-
- wx.EVT_COMBOBOX(self.cmap_selector, -1, self._on_select_cmap)
- sizer_selection.Add(wx.StaticText(self, -1, "Select Cmap: "), 0,
- wx.LEFT | wx.ADJUST_MINSIZE, 5)
- sizer_selection.Add(self.cmap_selector, 0, wx.EXPAND | wx.ALL, 10)
- sizer_main.Add(sizer_params, 0, wx.EXPAND | wx.ALL, 5)
- sizer_main.Add(sizer_selection, 0, wx.EXPAND | wx.ALL, 5)
- note = " Note: This is one time option. " + \
- "It will be reset on updating the image."
- note_txt = wx.StaticText(self, -1, note)
- sizer_main.Add(note_txt, 0, wx.EXPAND | wx.ALL, 5)
- sizer_main.Add(sizer_colormap, 1, wx.EXPAND | wx.ALL, 5)
- sizer_main.Add(self.static_line_3, 0, wx.EXPAND, 0)
- sizer_button.Add(self.button_reset, 0, wx.LEFT | wx.ADJUST_MINSIZE, 100)
- sizer_button.Add(self.button_ok, 0, wx.LEFT | wx.ADJUST_MINSIZE, 10)
- sizer_button.Add(self.button_cancel, 0,
- wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 10)
- sizer_main.Add(sizer_button, 0, wx.EXPAND | wx.BOTTOM | wx.TOP, 10)
- self.SetAutoLayout(True)
- self.SetSizer(sizer_main)
- self.Layout()
- self.Centre()
- # end wxGlade
-
- def _on_select_cmap(self, event):
- """
- display a new cmap
- """
- cmap_name = self.cmap_selector.GetCurrentSelection()
- current_cmap = self.cmap_selector.GetClientData(cmap_name)
- self.cmap = current_cmap
- self.cb1 = mpl.colorbar.ColorbarBase(self.ax1, cmap=self.cmap,
- norm=self.norm, orientation='horizontal')
- self.canvas.draw()
+"""
+ Widget to display a 2D map of the detector
+"""
+import wx
+import sys
+from sas.sasgui.guiframe.utils import format_number
+from sas.sasgui.guiframe.events import StatusEvent
+from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as Canvas
+import matplotlib as mpl
+from matplotlib import pylab
+# FONT size
+if sys.platform.count("win32") > 0:
+ FONT_VARIANT = 0
+else:
+ FONT_VARIANT = 1
+
+DEFAULT_CMAP = pylab.cm.get_cmap('jet')
+
+class DetectorDialog(wx.Dialog):
+ """
+ Dialog box to let the user edit detector settings
+ """
+
+ def __init__(self, parent, id=1, base=None, dpi=None,
+ cmap=DEFAULT_CMAP, reset_zmin_ctl=None,
+ reset_zmax_ctl=None, *args, **kwds):
+ """
+ """
+ kwds["style"] = wx.DEFAULT_DIALOG_STYLE
+ wx.Dialog.__init__(self, parent, id=1, *args, **kwds)
+ self.SetWindowVariant(variant=FONT_VARIANT)
+ self.parent = base
+ self.dpi = dpi
+ self.cmap = cmap
+ self.reset_zmin_ctl = reset_zmin_ctl
+ self.reset_zmax_ctl = reset_zmax_ctl
+ self.label_xnpts = wx.StaticText(self, -1, "Detector width in pixels")
+ self.label_ynpts = wx.StaticText(self, -1, "Detector Height in pixels")
+ self.label_qmax = wx.StaticText(self, -1, "Q max")
+ self.label_zmin = wx.StaticText(self, -1,
+ "Min amplitude for color map (optional)")
+ self.label_zmax = wx.StaticText(self, -1,
+ "Max amplitude for color map (optional)")
+ self.label_beam = wx.StaticText(self, -1,
+ "Beam stop radius in units of q")
+ self.xnpts_ctl = wx.StaticText(self, -1, "")
+ self.ynpts_ctl = wx.StaticText(self, -1, "")
+ self.qmax_ctl = wx.StaticText(self, -1, "")
+ self.beam_ctl = wx.StaticText(self, -1, "")
+ self.zmin_ctl = wx.TextCtrl(self, -1, size=(60, 20))
+ self.zmin_ctl.Bind(wx.EVT_SET_FOCUS, self.onSetFocus)
+ self.zmax_ctl = wx.TextCtrl(self, -1, size=(60, 20))
+ self.zmax_ctl.Bind(wx.EVT_SET_FOCUS, self.onSetFocus)
+ self.static_line_3 = wx.StaticLine(self, -1)
+ self.button_cancel = wx.Button(self, wx.ID_CANCEL, "Cancel")
+ self.button_reset = wx.Button(self, wx.NewId(), "Reset")
+ self.Bind(wx.EVT_BUTTON, self.resetValues, self.button_reset)
+ self.button_ok = wx.Button(self, wx.ID_OK, "OK")
+ self.Bind(wx.EVT_BUTTON, self.checkValues, self.button_ok)
+ self.__set_properties()
+ self.__do_layout()
+ self.Fit()
+
+ class Event(object):
+ """
+ """
+ xnpts = 0
+ ynpts = 0
+ qpax = 0
+ beam = 0
+ zmin = 0
+ zmax = 0
+ cmap = None
+ sym4 = False
+
+ def onSetFocus(self, event):
+ """
+ Highlight the txtcrtl
+ """
+ # Get a handle to the TextCtrl
+ widget = event.GetEventObject()
+ # Select the whole control, after this event resolves
+ wx.CallAfter(widget.SetSelection, -1, -1)
+
+ def resetValues(self, event):
+ """
+ reset detector info
+ """
+ try:
+ zmin = self.reset_zmin_ctl
+ zmax = self.reset_zmax_ctl
+ if zmin is None:
+ zmin = ""
+ if zmax is None:
+ zmax = ""
+ self.zmin_ctl.SetValue(str(zmin))
+ self.zmax_ctl.SetValue(str(zmax))
+ self.cmap = DEFAULT_CMAP
+ self.cmap_selector.SetStringSelection("jet")
+ self._on_select_cmap(event=None)
+ except:
+ msg = "error occurs while resetting Detector: %s" % sys.exc_value
+ wx.PostEvent(self.parent, StatusEvent(status=msg))
+
+ def checkValues(self, event):
+ """
+ Check the valitidity of zmin and zmax value
+ zmax should be a float and zmin less than zmax
+ """
+ flag = True
+ try:
+ value = self.zmin_ctl.GetValue()
+ self.zmin_ctl.SetBackgroundColour(wx.WHITE)
+ self.zmin_ctl.Refresh()
+ except:
+ flag = False
+ wx.PostEvent(self.parent, StatusEvent(status="Enter float value"))
+ self.zmin_ctl.SetBackgroundColour("pink")
+ self.zmin_ctl.Refresh()
+ try:
+ value = self.zmax_ctl.GetValue()
+ if value and float(value) == 0.0:
+ flag = False
+ wx.PostEvent(self.parent,
+ StatusEvent(status="Enter number greater than zero"))
+ self.zmax_ctl.SetBackgroundColour("pink")
+ self.zmax_ctl.Refresh()
+ else:
+ self.zmax_ctl.SetBackgroundColour(wx.WHITE)
+ self.zmax_ctl.Refresh()
+ except:
+ flag = False
+ wx.PostEvent(self.parent, StatusEvent(status="Enter Integer value"))
+ self.zmax_ctl.SetBackgroundColour("pink")
+ self.zmax_ctl.Refresh()
+ if flag:
+ event.Skip(True)
+
+ def setContent(self, xnpts, ynpts, qmax, beam,
+ zmin=None, zmax=None, sym=False):
+ """
+ received value and displayed them
+
+ :param xnpts: the number of point of the x_bins of data
+ :param ynpts: the number of point of the y_bins of data
+ :param qmax: the maxmimum value of data pixel
+ :param beam: the radius of the beam
+ :param zmin: the value to get the minimum color
+ :param zmax: the value to get the maximum color
+ :param sym:
+
+ """
+ self.xnpts_ctl.SetLabel(str(format_number(xnpts)))
+ self.ynpts_ctl.SetLabel(str(format_number(ynpts)))
+ self.qmax_ctl.SetLabel(str(format_number(qmax)))
+ self.beam_ctl.SetLabel(str(format_number(beam)))
+ if zmin is not None:
+ self.zmin_ctl.SetValue(str(format_number(zmin)))
+ if zmax is not None:
+ self.zmax_ctl.SetValue(str(format_number(zmax)))
+
+ def getContent(self):
+ """
+ return event containing value to reset the detector of a given data
+ """
+ event = self.Event()
+ t_min = self.zmin_ctl.GetValue()
+ t_max = self.zmax_ctl.GetValue()
+ v_min = None
+ v_max = None
+ if len(t_min.lstrip()) > 0:
+ try:
+ v_min = float(t_min)
+ except:
+ v_min = None
+ if len(t_max.lstrip()) > 0:
+ try:
+ v_max = float(t_max)
+ except:
+ v_max = None
+ event.zmin = v_min
+ event.zmax = v_max
+ event.cmap = self.cmap
+ return event
+
+ def __set_properties(self):
+ """
+ set proprieties of the dialog window
+ """
+ self.SetTitle("2D Color Map")
+ self.SetSize((600, 595))
+
+ def __do_layout(self):
+ """
+ fill the dialog window .
+ """
+ sizer_main = wx.BoxSizer(wx.VERTICAL)
+ sizer_button = wx.BoxSizer(wx.HORIZONTAL)
+ sizer_params = wx.GridBagSizer(5, 5)
+ sizer_colormap = wx.BoxSizer(wx.VERTICAL)
+ sizer_selection = wx.BoxSizer(wx.HORIZONTAL)
+
+ iy = 0
+ sizer_params.Add(self.label_xnpts, (iy, 0), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ sizer_params.Add(self.xnpts_ctl, (iy, 1), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ iy += 1
+ sizer_params.Add(self.label_ynpts, (iy, 0), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ sizer_params.Add(self.ynpts_ctl, (iy, 1), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ iy += 1
+ sizer_params.Add(self.label_qmax, (iy, 0), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ sizer_params.Add(self.qmax_ctl, (iy, 1), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ iy += 1
+ sizer_params.Add(self.label_beam, (iy, 0), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ sizer_params.Add(self.beam_ctl, (iy, 1), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ iy += 1
+ sizer_params.Add(self.label_zmin, (iy, 0), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ sizer_params.Add(self.zmin_ctl, (iy, 1), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ iy += 1
+ sizer_params.Add(self.label_zmax, (iy, 0), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ sizer_params.Add(self.zmax_ctl, (iy, 1), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ iy += 1
+ self.fig = mpl.figure.Figure(dpi=self.dpi, figsize=(4, 1))
+ self.ax1 = self.fig.add_axes([0.05, 0.65, 0.9, 0.15])
+ self.norm = mpl.colors.Normalize(vmin=0, vmax=100)
+ self.cb1 = mpl.colorbar.ColorbarBase(self.ax1, cmap=self.cmap,
+ norm=self.norm,
+ orientation='horizontal')
+ self.cb1.set_label('Detector Colors')
+ self.canvas = Canvas(self, -1, self.fig)
+ sizer_colormap.Add(self.canvas, 0, wx.LEFT | wx.EXPAND, 5)
+ self.cmap_selector = wx.ComboBox(self, -1)
+ self.cmap_selector.SetValue(str(self.cmap.name))
+ maps = sorted(m for m in pylab.cm.datad if not m.endswith("_r"))
+
+ for i, m in enumerate(maps):
+ self.cmap_selector.Append(str(m), pylab.get_cmap(m))
+
+ wx.EVT_COMBOBOX(self.cmap_selector, -1, self._on_select_cmap)
+ sizer_selection.Add(wx.StaticText(self, -1, "Select Cmap: "), 0,
+ wx.LEFT | wx.ADJUST_MINSIZE, 5)
+ sizer_selection.Add(self.cmap_selector, 0, wx.EXPAND | wx.ALL, 10)
+ sizer_main.Add(sizer_params, 0, wx.EXPAND | wx.ALL, 5)
+ sizer_main.Add(sizer_selection, 0, wx.EXPAND | wx.ALL, 5)
+ note = " Note: This is one time option. " + \
+ "It will be reset on updating the image."
+ note_txt = wx.StaticText(self, -1, note)
+ sizer_main.Add(note_txt, 0, wx.EXPAND | wx.ALL, 5)
+ sizer_main.Add(sizer_colormap, 1, wx.EXPAND | wx.ALL, 5)
+ sizer_main.Add(self.static_line_3, 0, wx.EXPAND, 0)
+ sizer_button.Add(self.button_reset, 0, wx.LEFT | wx.ADJUST_MINSIZE, 100)
+ sizer_button.Add(self.button_ok, 0, wx.LEFT | wx.ADJUST_MINSIZE, 10)
+ sizer_button.Add(self.button_cancel, 0,
+ wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 10)
+ sizer_main.Add(sizer_button, 0, wx.EXPAND | wx.BOTTOM | wx.TOP, 10)
+ self.SetAutoLayout(True)
+ self.SetSizer(sizer_main)
+ self.Layout()
+ self.Centre()
+ # end wxGlade
+
+ def _on_select_cmap(self, event):
+ """
+ display a new cmap
+ """
+ cmap_name = self.cmap_selector.GetCurrentSelection()
+ current_cmap = self.cmap_selector.GetClientData(cmap_name)
+ self.cmap = current_cmap
+ self.cb1 = mpl.colorbar.ColorbarBase(self.ax1, cmap=self.cmap,
+ norm=self.norm, orientation='horizontal')
+ self.canvas.draw()
diff --git a/src/sas/sasgui/guiframe/local_perspectives/plotting/masking.py b/src/sas/sasgui/guiframe/local_perspectives/plotting/masking.py
index 5b2f27d..7bb879a 100644
--- a/src/sas/sasgui/guiframe/local_perspectives/plotting/masking.py
+++ b/src/sas/sasgui/guiframe/local_perspectives/plotting/masking.py
@@ -1,741 +1,741 @@
-"""
- Mask editor
-"""
-################################################################################
-# This software was developed by the University of Tennessee as part of the
-# Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
-# project funded by the US National Science Foundation.
-#
-# If you use DANSE applications to do scientific research that leads to
-# publication, we ask that you acknowledge the use of the software with the
-# following sentence:
-#
-# This work benefited from DANSE software developed under NSF award DMR-0520547.
-#
-# copyright 2008, University of Tennessee
-################################################################################
-
-
-# #Todo: cleaning up, improving the maskplotpanel initialization, and testing.
-import wx
-import sys
-import time
-import matplotlib.cm as cm
-import math
-import copy
-import numpy
-from sas.sasgui.plottools.PlotPanel import PlotPanel
-from sas.sasgui.plottools.plottables import Graph
-from binder import BindArtist
-from sas.sasgui.guiframe.dataFitting import Data1D, Data2D
-from boxMask import BoxMask
-from sector_mask import SectorMask
-from AnnulusSlicer import CircularMask
-
-from sas.sasgui.guiframe.events import SlicerEvent
-from sas.sasgui.guiframe.events import StatusEvent
-from functools import partial
-
-(InternalEvent, EVT_INTERNAL) = wx.lib.newevent.NewEvent()
-
-DEFAULT_CMAP = cm.get_cmap('jet')
-_BOX_WIDTH = 76
-_SCALE = 1e-6
-_STATICBOX_WIDTH = 380
-
-# SLD panel size
-if sys.platform.count("win32") > 0:
- PANEL_SIZE = 350
- FONT_VARIANT = 0
-else:
- PANEL_SIZE = 300
- FONT_VARIANT = 1
-
-from sas.sascalc.data_util.calcthread import CalcThread
-
-class CalcPlot(CalcThread):
- """
- Compute Resolution
- """
- def __init__(self,
- id=-1,
- panel=None,
- image=None,
- completefn=None,
- updatefn=None,
- elapsed=0,
- yieldtime=0.01,
- worktime=0.01):
- """
- """
- CalcThread.__init__(self, completefn, updatefn, yieldtime, worktime)
- self.starttime = 0
- self.id = id
- self.panel = panel
- self.image = image
-
- def compute(self):
- """
- excuting computation
- """
- elapsed = time.time() - self.starttime
-
- self.complete(panel=self.panel, image=self.image, elapsed=elapsed)
-
-
-class MaskPanel(wx.Dialog):
- """
- Provides the Mask Editor GUI.
- """
- # # Internal nickname for the window, used by the AUI manager
- window_name = "Mask Editor"
- # # Name to appear on the window title bar
- window_caption = "Mask Editor"
- # # Flag to tell the AUI manager to put this panel in the center pane
- CENTER_PANE = True
- def __init__(self, parent=None, base=None,
- data=None, id=-1, *args, **kwds):
- kwds["style"] = wx.DEFAULT_DIALOG_STYLE
- kwds["size"] = wx.Size(_STATICBOX_WIDTH * 0.8, PANEL_SIZE)
- wx.Dialog.__init__(self, parent, id=id, *args, **kwds)
-
- if data != None:
- # Font size
- kwds = []
- self.SetWindowVariant(variant=FONT_VARIANT)
- self.SetTitle("Mask Editor for " + data.name)
- self.parent = base
- self.data = data
- self.str = self.data.__str__()
- # # mask for 2D
- self.mask = data.mask
- self.default_mask = copy.deepcopy(data.mask)
- # # masked data from GUI
- self.slicer_mask = None
- self.slicer = None
- self.slicer_z = 5
- self.data.interactive = True
- # # when 2 data have the same id override the 1 st plotted
- self.name = self.data.name
- # Panel for 2D plot
- self.plotpanel = Maskplotpanel(self, -1,
- style=wx.TRANSPARENT_WINDOW)
- self.cmap = DEFAULT_CMAP
- # # Create Artist and bind it
- self.subplot = self.plotpanel.subplot
- self.connect = BindArtist(self.subplot.figure)
- self._setup_layout()
- self.newplot = Data2D(image=self.data.data)
- self.newplot.setValues(self.data)
- self.plotpanel.add_image(self.newplot)
- self._update_mask(self.mask)
- self.Centre()
- self.Layout()
- # bind evt_close to _draw in fitpage
- self.Bind(wx.EVT_CLOSE, self.OnClose)
-
- def ShowMessage(self, msg=''):
- """
- Show error message when mask covers whole data area
- """
- mssg = 'Erase, redraw or clear the mask. \n\r'
- mssg += 'The data range can not be completely masked... \n\r'
- mssg += msg
- wx.MessageBox(mssg, 'Error', wx.OK | wx.ICON_ERROR)
-
- def _setup_layout(self):
- """
- Set up the layout
- """
- note = "Note: This masking applies\n only to %s." % self.data.name
- note_txt = wx.StaticText(self, -1, note)
- note_txt.SetForegroundColour(wx.RED)
- shape = "Select a Shape for Masking:"
- # panel
- sizer = wx.GridBagSizer(10, 10)
- #---------inputs----------------
- shape_txt = wx.StaticText(self, -1, shape)
- sizer.Add(shape_txt, (1, 1), flag=wx.TOP | wx.LEFT | wx.BOTTOM, border=5)
- self.innersector_rb = wx.RadioButton(self, -1, "Double Wings")
- self.Bind(wx.EVT_RADIOBUTTON, partial(self._on_mask, slicer=SectorMask, inside=True),
- id=self.innersector_rb.GetId())
- sizer.Add(self.innersector_rb, (2, 1),
- flag=wx.RIGHT | wx.BOTTOM, border=5)
- self.innercircle_rb = wx.RadioButton(self, -1, "Circular Disk")
- self.Bind(wx.EVT_RADIOBUTTON, partial(self._on_mask, slicer=CircularMask, inside=True),
- id=self.innercircle_rb.GetId())
- sizer.Add(self.innercircle_rb, (3, 1),
- flag=wx.RIGHT | wx.BOTTOM, border=5)
- self.innerbox_rb = wx.RadioButton(self, -1, "Rectangular Disk")
- self.Bind(wx.EVT_RADIOBUTTON, partial(self._on_mask, slicer=BoxMask, inside=True),
- id=self.innerbox_rb.GetId())
- sizer.Add(self.innerbox_rb, (4, 1), flag=wx.RIGHT | wx.BOTTOM, border=5)
- self.outersector_rb = wx.RadioButton(self, -1, "Double Wing Window")
- self.Bind(wx.EVT_RADIOBUTTON, partial(self._on_mask, slicer=SectorMask, inside=False),
- id=self.outersector_rb.GetId())
- sizer.Add(self.outersector_rb, (5, 1),
- flag=wx.RIGHT | wx.BOTTOM, border=5)
- self.outercircle_rb = wx.RadioButton(self, -1, "Circular Window")
- self.Bind(wx.EVT_RADIOBUTTON, partial(self._on_mask, slicer=CircularMask, inside=False),
- id=self.outercircle_rb.GetId())
- sizer.Add(self.outercircle_rb, (6, 1),
- flag=wx.RIGHT | wx.BOTTOM, border=5)
- self.outerbox_rb = wx.RadioButton(self, -1, "Rectangular Window")
- self.Bind(wx.EVT_RADIOBUTTON, partial(self._on_mask, slicer=BoxMask, inside=False),
- id=self.outerbox_rb.GetId())
- sizer.Add(self.outerbox_rb, (7, 1), flag=wx.RIGHT | wx.BOTTOM, border=5)
- sizer.Add(note_txt, (8, 1), flag=wx.RIGHT | wx.BOTTOM, border=5)
- self.innercircle_rb.SetValue(False)
- self.outercircle_rb.SetValue(False)
- self.innerbox_rb.SetValue(False)
- self.outerbox_rb.SetValue(False)
- self.innersector_rb.SetValue(False)
- self.outersector_rb.SetValue(False)
- sizer.Add(self.plotpanel, (0, 2), (13, 13),
- wx.EXPAND | wx.LEFT | wx.RIGHT, 15)
-
- #-----Buttons------------1
- id_button = wx.NewId()
- button_add = wx.Button(self, id_button, "Add")
- button_add.SetToolTipString("Add the mask drawn.")
- button_add.Bind(wx.EVT_BUTTON, self._on_add_mask, id=button_add.GetId())
- sizer.Add(button_add, (13, 7))
- id_button = wx.NewId()
- button_erase = wx.Button(self, id_button, "Erase")
- button_erase.SetToolTipString("Erase the mask drawn.")
- button_erase.Bind(wx.EVT_BUTTON, self._on_erase_mask,
- id=button_erase.GetId())
- sizer.Add(button_erase, (13, 8))
- id_button = wx.NewId()
- button_reset = wx.Button(self, id_button, "Reset")
- button_reset.SetToolTipString("Reset the mask.")
- button_reset.Bind(wx.EVT_BUTTON, self._on_reset_mask,
- id=button_reset.GetId())
- sizer.Add(button_reset, (13, 9), flag=wx.RIGHT | wx.BOTTOM, border=15)
- id_button = wx.NewId()
- button_reset = wx.Button(self, id_button, "Clear")
- button_reset.SetToolTipString("Clear all mask.")
- button_reset.Bind(wx.EVT_BUTTON, self._on_clear_mask,
- id=button_reset.GetId())
- sizer.Add(button_reset, (13, 10), flag=wx.RIGHT | wx.BOTTOM, border=15)
- sizer.AddGrowableCol(3)
- sizer.AddGrowableRow(2)
- self.SetSizerAndFit(sizer)
- self.Centre()
- self.Show(True)
-
- def _on_mask(self, event=None, slicer=BoxMask, inside=True):
- """
- Draw a slicer and use it as mask
- :param event: wx event
- :param slicer: Slicer class to use
- :param inside: whether we mask what's inside or outside the slicer
- """
- # get ready for next evt
- event.Skip()
- # from boxMask import BoxMask
- if event != None:
- self._on_clear_slicer(event)
- self.slicer_z += 1
- self.slicer = slicer(self, self.subplot,
- zorder=self.slicer_z, side=inside)
- self.subplot.set_ylim(self.data.ymin, self.data.ymax)
- self.subplot.set_xlim(self.data.xmin, self.data.xmax)
- self.update()
- self.slicer_mask = self.slicer.update()
-
- def _on_add_mask(self, event):
- """
- Add new mask to old mask
- """
- if not self.slicer == None:
- data = Data2D()
- data = self.data
- self.slicer_mask = self.slicer.update()
- data.mask = self.data.mask & self.slicer_mask
- self._check_display_mask(data.mask, event)
-
- def _check_display_mask(self, mask, event):
- """
- check if the mask valid and update the plot
-
- :param mask: mask data
- """
- # # Redraw the current image
- self._update_mask(mask)
-
- def _on_erase_mask(self, event):
- """
- Erase new mask from old mask
- """
- if not self.slicer == None:
- self.slicer_mask = self.slicer.update()
- mask = self.data.mask
- mask[self.slicer_mask == False] = True
- self._check_display_mask(mask, event)
-
- def _on_reset_mask(self, event):
- """
- Reset mask to the original mask
- """
- self.slicer_z += 1
- self.slicer = BoxMask(self, self.subplot,
- zorder=self.slicer_z, side=True)
- self.subplot.set_ylim(self.data.ymin, self.data.ymax)
- self.subplot.set_xlim(self.data.xmin, self.data.xmax)
- mask = copy.deepcopy(self.default_mask)
- self.data.mask = mask
- # update mask plot
- self._check_display_mask(mask, event)
-
- def _on_clear_mask(self, event):
- """
- Clear mask
- """
- self.slicer_z += 1
- self.slicer = BoxMask(self, self.subplot,
- zorder=self.slicer_z, side=True)
- self.subplot.set_ylim(self.data.ymin, self.data.ymax)
- self.subplot.set_xlim(self.data.xmin, self.data.xmax)
- mask = numpy.ones(len(self.data.mask), dtype=bool)
- self.data.mask = mask
- # update mask plot
- self._check_display_mask(mask, event)
-
- def _on_clear_slicer(self, event):
- """
- Clear the slicer on the plot
- """
- if not self.slicer == None:
- self.slicer.clear()
- self.subplot.figure.canvas.draw()
- self.slicer = None
-
- def update(self, draw=True):
- """
- Respond to changes in the model by recalculating the
- profiles and resetting the widgets.
- """
- self.plotpanel.draw()
-
- def _set_mask(self, mask):
- """
- Set mask
- """
- self.data.mask = mask
-
- def set_plot_unfocus(self):
- """
- Not implemented
- """
- pass
-
- def _update_mask(self, mask):
- """
- Respond to changes in masking
- """
- # the case of liitle numbers of True points
- if len(mask[mask]) < 10 and self.data != None:
- self.ShowMessage()
- mask = copy.deepcopy(self.mask)
- self.data.mask = mask
- else:
- self.mask = mask
- # make temperary data to plot
- temp_mask = numpy.zeros(len(mask))
- temp_data = copy.deepcopy(self.data)
- # temp_data default is None
- # This method is to distinguish between masked point and data point = 0.
- temp_mask = temp_mask / temp_mask
- temp_mask[mask] = temp_data.data[mask]
- # set temp_data value for self.mask==True, else still None
- # temp_mask[mask] = temp_data[mask]
-
- # TODO: refactor this horrible logic
- temp_data.data[mask == False] = temp_mask[mask == False]
- self.plotpanel.clear()
- if self.slicer != None:
- self.slicer.clear()
- self.slicer = None
- # Post slicer None event
- event = self._getEmptySlicerEvent()
- wx.PostEvent(self, event)
-
- # #use this method
- # set zmax and zmin to plot: Fix it w/ data.
- if self.plotpanel.scale == 'log_{10}':
- zmax = math.log10(max(self.data.data[self.data.data > 0]))
- zmin = math.log10(min(self.data.data[self.data.data > 0]))
- else:
- zmax = max(self.data.data[self.data.data > 0])
- zmin = min(self.data.data[self.data.data > 0])
- # plot
- self.plotpanel.image(data=temp_mask,
- qx_data=self.data.qx_data,
- qy_data=self.data.qy_data,
- xmin=self.data.xmin,
- xmax=self.data.xmax,
- ymin=self.data.ymin,
- ymax=self.data.ymax,
- zmin=zmin,
- zmax=zmax,
- cmap=self.cmap,
- color=0, symbol=0, label=self.data.name)
- # axis labels
- self.plotpanel.axes[0].set_xlabel('$\\rm{Q}_{x}(A^{-1})$')
- self.plotpanel.axes[0].set_ylabel('$\\rm{Q}_{y}(A^{-1})$')
- self.plotpanel.render()
- self.plotpanel.subplot.figure.canvas.draw_idle()
-
- def _getEmptySlicerEvent(self):
- """
- create an empty slicervent
- """
- self.innerbox_rb.SetValue(False)
- self.outerbox_rb.SetValue(False)
- self.innersector_rb.SetValue(False)
- self.outersector_rb.SetValue(False)
- self.innercircle_rb.SetValue(False)
- self.outercircle_rb.SetValue(False)
- return SlicerEvent(type=None,
- params=None,
- obj_class=None)
-
- def _draw_model(self, event):
- """
- on_close, update the model2d plot
- """
- pass
-
- def freeze_axes(self):
- """
- freeze axes
- """
- self.plotpanel.axes_frozen = True
-
- def thaw_axes(self):
- """
- thaw axes
- """
- self.plotpanel.axes_frozen = False
-
- def onMouseMotion(self, event):
- """
- onMotion event
- """
- pass
-
- def onWheel(self, event):
- """
- on wheel event
- """
- pass
-
- def OnClose(self, event):
- """
- Processing close event
- """
- try:
- self.parent._draw_masked_model(event)
- except:
- # when called by data panel
- event.Skip()
- pass
-
-class FloatPanel(wx.Dialog):
- """
- Provides the Mask Editor GUI.
- """
- # # Internal nickname for the window, used by the AUI manager
- window_name = "Plot"
- # # Name to appear on the window title bar
- window_caption = "Plot"
- # # Flag to tell the AUI manager to put this panel in the center pane
- CENTER_PANE = False
- ID = wx.NewId()
- def __init__(self, parent=None, base=None,
- data=None, dimension=1, id=ID, *args, **kwds):
- kwds["style"] = wx.DEFAULT_DIALOG_STYLE
- kwds["size"] = wx.Size(PANEL_SIZE * 1.5, PANEL_SIZE * 1.5)
- wx.Dialog.__init__(self, parent, id=id, *args, **kwds)
-
- if data != None:
- # Font size
- kwds = []
- self.SetWindowVariant(variant=FONT_VARIANT)
- self.SetTitle("Plot " + data.name)
- self.parent = base
- self.data = data
- self.str = self.data.__str__()
- # # when 2 data have the same id override the 1 st plotted
- self.name = self.data.name
- self.dimension = dimension
- # Panel for 2D plot
- self.plotpanel = Maskplotpanel(self, -1, dimension,
- style=wx.TRANSPARENT_WINDOW)
- self.plotpanel._SetInitialSize()
- self.plotpanel.prevXtrans = "x"
- self.plotpanel.prevYtrans = "y"
-
- self.cmap = DEFAULT_CMAP
- # # Create Artist and bind it
- self.subplot = self.plotpanel.subplot
- self._setup_layout()
- if self.dimension == 1:
- self.newplot = Data1D(x=data.x, y=data.y,
- dx=data.dx, dy=data.dy)
- self.newplot.name = data.name
- else:
- self.newplot = Data2D(image=self.data.data)
- self.newplot.setValues(self.data)
- # Compute and get the image plot
- self.get_plot()
- # self.plotpanel.add_image(self.newplot)
- self.Centre()
- self.Layout()
-
- def get_plot(self):
- """
- Get Plot panel
- """
- cal_plot = CalcPlot(panel=self.plotpanel,
- image=self.newplot,
- completefn=self.complete)
- cal_plot.queue()
-
- def complete(self, panel, image, elapsed=None):
- """
- Plot image
-
- :param image: newplot [plotpanel]
- """
- wx.CallAfter(panel.add_image, image)
-
- def _setup_layout(self):
- """
- Set up the layout
- """
- # panel
- sizer = wx.GridBagSizer(10, 10)
- if self.dimension == 3:
- note = "Note: I am very SLOW. Please be PATIENT...\n"
- if len(self.data.data) > 3600:
- note += "Rotation disabled for pixels > 60x60."
- note_txt = wx.StaticText(self, -1, note)
- note_txt.SetForegroundColour(wx.RED)
- sizer.Add(note_txt, (0, 2), flag=wx.RIGHT | wx.TOP, border=5)
-
- sizer.Add(self.plotpanel, (1, 0), (9, 9),
- wx.EXPAND | wx.ALL, 15)
-
- sizer.AddGrowableCol(3)
- sizer.AddGrowableRow(2)
-
- self.SetSizerAndFit(sizer)
- self.Centre()
- self.Show(True)
-
- def set_plot_unfocus(self):
- """
- Not implemented
- """
- pass
-
- def _draw_model(self, event):
- """
- on_close, update the model2d plot
- """
- pass
-
- def freeze_axes(self):
- """
- freeze axes
- """
- self.plotpanel.axes_frozen = True
-
- def thaw_axes(self):
- """
- thaw axes
- """
- self.plotpanel.axes_frozen = False
-
- def OnClose(self, event):
- """
- """
- try:
- self.plotpanel.subplot.figure.clf()
- self.plotpanel.Close()
- except:
- # when called by data panel
- event.Skip()
- pass
-
-class Maskplotpanel(PlotPanel):
- """
- PlotPanel for Quick plot and masking plot
- """
- def __init__(self, parent, id=-1, dimension=2, color=None, dpi=None, **kwargs):
- """
- """
- PlotPanel.__init__(self, parent, id=id, color=color, dpi=dpi, **kwargs)
-
- # Keep track of the parent Frame
- self.parent = parent
- # Internal list of plottable names (because graph
- # doesn't have a dictionary of handles for the plottables)
- self.dimension = dimension
- self.plots = {}
- self.graph = Graph()
- # add axis labels
- self.graph.xaxis('\\rm{x} ', '')
- self.graph.yaxis('\\rm{y} ', '')
-
- def add_toolbar(self):
- """
- Add toolbar
- """
- # Not implemented
- pass
-
- def on_set_focus(self, event):
- """
- send to the parenet the current panel on focus
- """
- if self.dimension == 3:
- pass
- else:
- self.draw()
-
- def add_image(self, plot):
- """
- Add Image
- """
- self.plots[plot.name] = plot
- # init graph
- self.graph = Graph()
- # add plot
- self.graph.add(plot)
- # add axes
- if self.dimension == 1:
- self.xaxis_label = '\\rm{x} '
- self.xaxis_unit = ''
- self.yaxis_label = '\\rm{y} '
- self.yaxis_unit = ''
- # draw
- # message
- status_type = 'progress'
- msg = 'Plotting...'
- self._status_info(msg, status_type)
- status_type = 'stop'
- self.graph.render(self)
- self.subplot.figure.canvas.resizing = False
- if self.dimension < 3:
- self.graph.render(self)
- self.subplot.figure.canvas.draw()
- elif FONT_VARIANT:
- self.subplot.figure.canvas.draw()
- msg = 'Plotting Completed.'
- self._status_info(msg, status_type)
-
- def onMouseMotion(self, event):
- """
- Disable dragging 2D image
- """
- pass
-
- def onWheel(self, event):
- """
- """
- pass
-
- def onLeftDown(self, event):
- """
- Disables LeftDown
- """
- pass
-
- def onPick(self, event):
- """
- Disables OnPick
- """
- pass
-
- def draw(self):
- """
- Draw
- """
- # message
- status_type = 'progress'
- msg = 'Plotting...'
- self._status_info(msg, status_type)
- status_type = 'stop'
-
- if not self.dimension == 3:
- self.subplot.figure.canvas.draw_idle()
-
- msg = 'Plotting Completed.'
- self._status_info(msg, status_type)
-
- def onContextMenu(self, event):
- """
- Default context menu for a plot panel
- """
- # Selective Slicer plot popup menu
- slicerpop = wx.Menu()
-
- id = wx.NewId()
- slicerpop.Append(id, '&Print Image', 'Print image')
- wx.EVT_MENU(self, id, self.onPrint)
-
- id = wx.NewId()
- slicerpop.Append(id, '&Copy to Clipboard', 'Copy to the clipboard')
- wx.EVT_MENU(self, id, self.OnCopyFigureMenu)
-
- if self.dimension == 1:
- id = wx.NewId()
- slicerpop.Append(id, '&Change Scale')
- wx.EVT_MENU(self, id, self._onProperties)
- else:
- slicerpop.AppendSeparator()
- id_cm = wx.NewId()
- slicerpop.Append(id_cm, '&Toggle Linear/Log scale')
- wx.EVT_MENU(self, id_cm, self._onToggleScale)
-
- pos = event.GetPosition()
- pos = self.ScreenToClient(pos)
- self.PopupMenu(slicerpop, pos)
-
- def _status_info(self, msg='', type="update"):
- """
- Status msg
- """
- if self.parent.parent.parent != None:
- wx.PostEvent(self.parent.parent.parent,
- StatusEvent(status=msg, type=type))
-
-class ViewerFrame(wx.Frame):
- """
- Add comment
- """
- def __init__(self, parent, id, title):
- """
- comment
- :param parent: parent panel/container
- """
- # Initialize the Frame object
- wx.Frame.__init__(self, parent, id, title,
- wx.DefaultPosition, wx.Size(950, 850))
- # Panel for 1D plot
- self.plotpanel = Maskplotpanel(self, -1, style=wx.RAISED_BORDER)
-
-class ViewApp(wx.App):
- def OnInit(self):
- frame = ViewerFrame(None, -1, 'testView')
- frame.Show(True)
- # self.SetTopWindow(frame)
-
- return True
-
-if __name__ == "__main__":
- app = ViewApp(0)
- app.MainLoop()
+"""
+ Mask editor
+"""
+################################################################################
+# This software was developed by the University of Tennessee as part of the
+# Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
+# project funded by the US National Science Foundation.
+#
+# If you use DANSE applications to do scientific research that leads to
+# publication, we ask that you acknowledge the use of the software with the
+# following sentence:
+#
+# This work benefited from DANSE software developed under NSF award DMR-0520547.
+#
+# copyright 2008, University of Tennessee
+################################################################################
+
+
+# #Todo: cleaning up, improving the maskplotpanel initialization, and testing.
+import wx
+import sys
+import time
+import matplotlib.cm as cm
+import math
+import copy
+import numpy as np
+from sas.sasgui.plottools.PlotPanel import PlotPanel
+from sas.sasgui.plottools.plottables import Graph
+from binder import BindArtist
+from sas.sasgui.guiframe.dataFitting import Data1D, Data2D
+from boxMask import BoxMask
+from sector_mask import SectorMask
+from AnnulusSlicer import CircularMask
+
+from sas.sasgui.guiframe.events import SlicerEvent
+from sas.sasgui.guiframe.events import StatusEvent
+from functools import partial
+
+(InternalEvent, EVT_INTERNAL) = wx.lib.newevent.NewEvent()
+
+DEFAULT_CMAP = cm.get_cmap('jet')
+_BOX_WIDTH = 76
+_SCALE = 1e-6
+_STATICBOX_WIDTH = 380
+
+# SLD panel size
+if sys.platform.count("win32") > 0:
+ PANEL_SIZE = 350
+ FONT_VARIANT = 0
+else:
+ PANEL_SIZE = 300
+ FONT_VARIANT = 1
+
+from sas.sascalc.data_util.calcthread import CalcThread
+
+class CalcPlot(CalcThread):
+ """
+ Compute Resolution
+ """
+ def __init__(self,
+ id=-1,
+ panel=None,
+ image=None,
+ completefn=None,
+ updatefn=None,
+ elapsed=0,
+ yieldtime=0.01,
+ worktime=0.01):
+ """
+ """
+ CalcThread.__init__(self, completefn, updatefn, yieldtime, worktime)
+ self.starttime = 0
+ self.id = id
+ self.panel = panel
+ self.image = image
+
+ def compute(self):
+ """
+ excuting computation
+ """
+ elapsed = time.time() - self.starttime
+
+ self.complete(panel=self.panel, image=self.image, elapsed=elapsed)
+
+
+class MaskPanel(wx.Dialog):
+ """
+ Provides the Mask Editor GUI.
+ """
+ # # Internal nickname for the window, used by the AUI manager
+ window_name = "Mask Editor"
+ # # Name to appear on the window title bar
+ window_caption = "Mask Editor"
+ # # Flag to tell the AUI manager to put this panel in the center pane
+ CENTER_PANE = True
+ def __init__(self, parent=None, base=None,
+ data=None, id=-1, *args, **kwds):
+ kwds["style"] = wx.DEFAULT_DIALOG_STYLE
+ kwds["size"] = wx.Size(_STATICBOX_WIDTH * 0.8, PANEL_SIZE)
+ wx.Dialog.__init__(self, parent, id=id, *args, **kwds)
+
+ if data is not None:
+ # Font size
+ kwds = []
+ self.SetWindowVariant(variant=FONT_VARIANT)
+ self.SetTitle("Mask Editor for " + data.name)
+ self.parent = base
+ self.data = data
+ self.str = self.data.__str__()
+ # # mask for 2D
+ self.mask = data.mask
+ self.default_mask = copy.deepcopy(data.mask)
+ # # masked data from GUI
+ self.slicer_mask = None
+ self.slicer = None
+ self.slicer_z = 5
+ self.data.interactive = True
+ # # when 2 data have the same id override the 1 st plotted
+ self.name = self.data.name
+ # Panel for 2D plot
+ self.plotpanel = Maskplotpanel(self, -1,
+ style=wx.TRANSPARENT_WINDOW)
+ self.cmap = DEFAULT_CMAP
+ # # Create Artist and bind it
+ self.subplot = self.plotpanel.subplot
+ self.connect = BindArtist(self.subplot.figure)
+ self._setup_layout()
+ self.newplot = Data2D(image=self.data.data)
+ self.newplot.setValues(self.data)
+ self.plotpanel.add_image(self.newplot)
+ self._update_mask(self.mask)
+ self.Centre()
+ self.Layout()
+ # bind evt_close to _draw in fitpage
+ self.Bind(wx.EVT_CLOSE, self.OnClose)
+
+ def ShowMessage(self, msg=''):
+ """
+ Show error message when mask covers whole data area
+ """
+ mssg = 'Erase, redraw or clear the mask. \n\r'
+ mssg += 'The data range can not be completely masked... \n\r'
+ mssg += msg
+ wx.MessageBox(mssg, 'Error', wx.OK | wx.ICON_ERROR)
+
+ def _setup_layout(self):
+ """
+ Set up the layout
+ """
+ note = "Note: This masking applies\n only to %s." % self.data.name
+ note_txt = wx.StaticText(self, -1, note)
+ note_txt.SetForegroundColour(wx.RED)
+ shape = "Select a Shape for Masking:"
+ # panel
+ sizer = wx.GridBagSizer(10, 10)
+ #---------inputs----------------
+ shape_txt = wx.StaticText(self, -1, shape)
+ sizer.Add(shape_txt, (1, 1), flag=wx.TOP | wx.LEFT | wx.BOTTOM, border=5)
+ self.innersector_rb = wx.RadioButton(self, -1, "Double Wings")
+ self.Bind(wx.EVT_RADIOBUTTON, partial(self._on_mask, slicer=SectorMask, inside=True),
+ id=self.innersector_rb.GetId())
+ sizer.Add(self.innersector_rb, (2, 1),
+ flag=wx.RIGHT | wx.BOTTOM, border=5)
+ self.innercircle_rb = wx.RadioButton(self, -1, "Circular Disk")
+ self.Bind(wx.EVT_RADIOBUTTON, partial(self._on_mask, slicer=CircularMask, inside=True),
+ id=self.innercircle_rb.GetId())
+ sizer.Add(self.innercircle_rb, (3, 1),
+ flag=wx.RIGHT | wx.BOTTOM, border=5)
+ self.innerbox_rb = wx.RadioButton(self, -1, "Rectangular Disk")
+ self.Bind(wx.EVT_RADIOBUTTON, partial(self._on_mask, slicer=BoxMask, inside=True),
+ id=self.innerbox_rb.GetId())
+ sizer.Add(self.innerbox_rb, (4, 1), flag=wx.RIGHT | wx.BOTTOM, border=5)
+ self.outersector_rb = wx.RadioButton(self, -1, "Double Wing Window")
+ self.Bind(wx.EVT_RADIOBUTTON, partial(self._on_mask, slicer=SectorMask, inside=False),
+ id=self.outersector_rb.GetId())
+ sizer.Add(self.outersector_rb, (5, 1),
+ flag=wx.RIGHT | wx.BOTTOM, border=5)
+ self.outercircle_rb = wx.RadioButton(self, -1, "Circular Window")
+ self.Bind(wx.EVT_RADIOBUTTON, partial(self._on_mask, slicer=CircularMask, inside=False),
+ id=self.outercircle_rb.GetId())
+ sizer.Add(self.outercircle_rb, (6, 1),
+ flag=wx.RIGHT | wx.BOTTOM, border=5)
+ self.outerbox_rb = wx.RadioButton(self, -1, "Rectangular Window")
+ self.Bind(wx.EVT_RADIOBUTTON, partial(self._on_mask, slicer=BoxMask, inside=False),
+ id=self.outerbox_rb.GetId())
+ sizer.Add(self.outerbox_rb, (7, 1), flag=wx.RIGHT | wx.BOTTOM, border=5)
+ sizer.Add(note_txt, (8, 1), flag=wx.RIGHT | wx.BOTTOM, border=5)
+ self.innercircle_rb.SetValue(False)
+ self.outercircle_rb.SetValue(False)
+ self.innerbox_rb.SetValue(False)
+ self.outerbox_rb.SetValue(False)
+ self.innersector_rb.SetValue(False)
+ self.outersector_rb.SetValue(False)
+ sizer.Add(self.plotpanel, (0, 2), (13, 13),
+ wx.EXPAND | wx.LEFT | wx.RIGHT, 15)
+
+ #-----Buttons------------1
+ id_button = wx.NewId()
+ button_add = wx.Button(self, id_button, "Add")
+ button_add.SetToolTipString("Add the mask drawn.")
+ button_add.Bind(wx.EVT_BUTTON, self._on_add_mask, id=button_add.GetId())
+ sizer.Add(button_add, (13, 7))
+ id_button = wx.NewId()
+ button_erase = wx.Button(self, id_button, "Erase")
+ button_erase.SetToolTipString("Erase the mask drawn.")
+ button_erase.Bind(wx.EVT_BUTTON, self._on_erase_mask,
+ id=button_erase.GetId())
+ sizer.Add(button_erase, (13, 8))
+ id_button = wx.NewId()
+ button_reset = wx.Button(self, id_button, "Reset")
+ button_reset.SetToolTipString("Reset the mask.")
+ button_reset.Bind(wx.EVT_BUTTON, self._on_reset_mask,
+ id=button_reset.GetId())
+ sizer.Add(button_reset, (13, 9), flag=wx.RIGHT | wx.BOTTOM, border=15)
+ id_button = wx.NewId()
+ button_reset = wx.Button(self, id_button, "Clear")
+ button_reset.SetToolTipString("Clear all mask.")
+ button_reset.Bind(wx.EVT_BUTTON, self._on_clear_mask,
+ id=button_reset.GetId())
+ sizer.Add(button_reset, (13, 10), flag=wx.RIGHT | wx.BOTTOM, border=15)
+ sizer.AddGrowableCol(3)
+ sizer.AddGrowableRow(2)
+ self.SetSizerAndFit(sizer)
+ self.Centre()
+ self.Show(True)
+
+ def _on_mask(self, event=None, slicer=BoxMask, inside=True):
+ """
+ Draw a slicer and use it as mask
+ :param event: wx event
+ :param slicer: Slicer class to use
+ :param inside: whether we mask what's inside or outside the slicer
+ """
+ # get ready for next evt
+ event.Skip()
+ # from boxMask import BoxMask
+ if event is not None:
+ self._on_clear_slicer(event)
+ self.slicer_z += 1
+ self.slicer = slicer(self, self.subplot,
+ zorder=self.slicer_z, side=inside)
+ self.subplot.set_ylim(self.data.ymin, self.data.ymax)
+ self.subplot.set_xlim(self.data.xmin, self.data.xmax)
+ self.update()
+ self.slicer_mask = self.slicer.update()
+
+ def _on_add_mask(self, event):
+ """
+ Add new mask to old mask
+ """
+ if self.slicer is not None:
+ data = Data2D()
+ data = self.data
+ self.slicer_mask = self.slicer.update()
+ data.mask = self.data.mask & self.slicer_mask
+ self._check_display_mask(data.mask, event)
+
+ def _check_display_mask(self, mask, event):
+ """
+ check if the mask valid and update the plot
+
+ :param mask: mask data
+ """
+ # # Redraw the current image
+ self._update_mask(mask)
+
+ def _on_erase_mask(self, event):
+ """
+ Erase new mask from old mask
+ """
+ if self.slicer is not None:
+ self.slicer_mask = self.slicer.update()
+ mask = self.data.mask
+ mask[self.slicer_mask == False] = True
+ self._check_display_mask(mask, event)
+
+ def _on_reset_mask(self, event):
+ """
+ Reset mask to the original mask
+ """
+ self.slicer_z += 1
+ self.slicer = BoxMask(self, self.subplot,
+ zorder=self.slicer_z, side=True)
+ self.subplot.set_ylim(self.data.ymin, self.data.ymax)
+ self.subplot.set_xlim(self.data.xmin, self.data.xmax)
+ mask = copy.deepcopy(self.default_mask)
+ self.data.mask = mask
+ # update mask plot
+ self._check_display_mask(mask, event)
+
+ def _on_clear_mask(self, event):
+ """
+ Clear mask
+ """
+ self.slicer_z += 1
+ self.slicer = BoxMask(self, self.subplot,
+ zorder=self.slicer_z, side=True)
+ self.subplot.set_ylim(self.data.ymin, self.data.ymax)
+ self.subplot.set_xlim(self.data.xmin, self.data.xmax)
+ mask = np.ones(len(self.data.mask), dtype=bool)
+ self.data.mask = mask
+ # update mask plot
+ self._check_display_mask(mask, event)
+
+ def _on_clear_slicer(self, event):
+ """
+ Clear the slicer on the plot
+ """
+ if self.slicer is not None:
+ self.slicer.clear()
+ self.subplot.figure.canvas.draw()
+ self.slicer = None
+
+ def update(self, draw=True):
+ """
+ Respond to changes in the model by recalculating the
+ profiles and resetting the widgets.
+ """
+ self.plotpanel.draw()
+
+ def _set_mask(self, mask):
+ """
+ Set mask
+ """
+ self.data.mask = mask
+
+ def set_plot_unfocus(self):
+ """
+ Not implemented
+ """
+ pass
+
+ def _update_mask(self, mask):
+ """
+ Respond to changes in masking
+ """
+ # the case of liitle numbers of True points
+ if len(mask[mask]) < 10 and self.data is not None:
+ self.ShowMessage()
+ mask = copy.deepcopy(self.mask)
+ self.data.mask = mask
+ else:
+ self.mask = mask
+ # make temperary data to plot
+ temp_mask = np.zeros(len(mask))
+ temp_data = copy.deepcopy(self.data)
+ # temp_data default is None
+ # This method is to distinguish between masked point and data point = 0.
+ temp_mask = temp_mask / temp_mask
+ temp_mask[mask] = temp_data.data[mask]
+ # set temp_data value for self.mask==True, else still None
+ # temp_mask[mask] = temp_data[mask]
+
+ # TODO: refactor this horrible logic
+ temp_data.data[mask == False] = temp_mask[mask == False]
+ self.plotpanel.clear()
+ if self.slicer is not None:
+ self.slicer.clear()
+ self.slicer = None
+ # Post slicer None event
+ event = self._getEmptySlicerEvent()
+ wx.PostEvent(self, event)
+
+ # #use this method
+ # set zmax and zmin to plot: Fix it w/ data.
+ if self.plotpanel.scale == 'log_{10}':
+ zmax = math.log10(max(self.data.data[self.data.data > 0]))
+ zmin = math.log10(min(self.data.data[self.data.data > 0]))
+ else:
+ zmax = max(self.data.data[self.data.data > 0])
+ zmin = min(self.data.data[self.data.data > 0])
+ # plot
+ self.plotpanel.image(data=temp_mask,
+ qx_data=self.data.qx_data,
+ qy_data=self.data.qy_data,
+ xmin=self.data.xmin,
+ xmax=self.data.xmax,
+ ymin=self.data.ymin,
+ ymax=self.data.ymax,
+ zmin=zmin,
+ zmax=zmax,
+ cmap=self.cmap,
+ color=0, symbol=0, label=self.data.name)
+ # axis labels
+ self.plotpanel.axes[0].set_xlabel('$\\rm{Q}_{x}(A^{-1})$')
+ self.plotpanel.axes[0].set_ylabel('$\\rm{Q}_{y}(A^{-1})$')
+ self.plotpanel.render()
+ self.plotpanel.subplot.figure.canvas.draw_idle()
+
+ def _getEmptySlicerEvent(self):
+ """
+ create an empty slicervent
+ """
+ self.innerbox_rb.SetValue(False)
+ self.outerbox_rb.SetValue(False)
+ self.innersector_rb.SetValue(False)
+ self.outersector_rb.SetValue(False)
+ self.innercircle_rb.SetValue(False)
+ self.outercircle_rb.SetValue(False)
+ return SlicerEvent(type=None,
+ params=None,
+ obj_class=None)
+
+ def _draw_model(self, event):
+ """
+ on_close, update the model2d plot
+ """
+ pass
+
+ def freeze_axes(self):
+ """
+ freeze axes
+ """
+ self.plotpanel.axes_frozen = True
+
+ def thaw_axes(self):
+ """
+ thaw axes
+ """
+ self.plotpanel.axes_frozen = False
+
+ def onMouseMotion(self, event):
+ """
+ onMotion event
+ """
+ pass
+
+ def onWheel(self, event):
+ """
+ on wheel event
+ """
+ pass
+
+ def OnClose(self, event):
+ """
+ Processing close event
+ """
+ try:
+ self.parent._draw_masked_model(event)
+ except:
+ # when called by data panel
+ event.Skip()
+ pass
+
+class FloatPanel(wx.Dialog):
+ """
+ Provides the Mask Editor GUI.
+ """
+ # # Internal nickname for the window, used by the AUI manager
+ window_name = "Plot"
+ # # Name to appear on the window title bar
+ window_caption = "Plot"
+ # # Flag to tell the AUI manager to put this panel in the center pane
+ CENTER_PANE = False
+ ID = wx.NewId()
+ def __init__(self, parent=None, base=None,
+ data=None, dimension=1, id=ID, *args, **kwds):
+ kwds["style"] = wx.DEFAULT_DIALOG_STYLE
+ kwds["size"] = wx.Size(PANEL_SIZE * 1.5, PANEL_SIZE * 1.5)
+ wx.Dialog.__init__(self, parent, id=id, *args, **kwds)
+
+ if data is not None:
+ # Font size
+ kwds = []
+ self.SetWindowVariant(variant=FONT_VARIANT)
+ self.SetTitle("Plot " + data.name)
+ self.parent = base
+ self.data = data
+ self.str = self.data.__str__()
+ # # when 2 data have the same id override the 1 st plotted
+ self.name = self.data.name
+ self.dimension = dimension
+ # Panel for 2D plot
+ self.plotpanel = Maskplotpanel(self, -1, dimension,
+ style=wx.TRANSPARENT_WINDOW)
+ self.plotpanel._SetInitialSize()
+ self.plotpanel.prevXtrans = "x"
+ self.plotpanel.prevYtrans = "y"
+
+ self.cmap = DEFAULT_CMAP
+ # # Create Artist and bind it
+ self.subplot = self.plotpanel.subplot
+ self._setup_layout()
+ if self.dimension == 1:
+ self.newplot = Data1D(x=data.x, y=data.y,
+ dx=data.dx, dy=data.dy)
+ self.newplot.name = data.name
+ else:
+ self.newplot = Data2D(image=self.data.data)
+ self.newplot.setValues(self.data)
+ # Compute and get the image plot
+ self.get_plot()
+ # self.plotpanel.add_image(self.newplot)
+ self.Centre()
+ self.Layout()
+
+ def get_plot(self):
+ """
+ Get Plot panel
+ """
+ cal_plot = CalcPlot(panel=self.plotpanel,
+ image=self.newplot,
+ completefn=self.complete)
+ cal_plot.queue()
+
+ def complete(self, panel, image, elapsed=None):
+ """
+ Plot image
+
+ :param image: newplot [plotpanel]
+ """
+ wx.CallAfter(panel.add_image, image)
+
+ def _setup_layout(self):
+ """
+ Set up the layout
+ """
+ # panel
+ sizer = wx.GridBagSizer(10, 10)
+ if self.dimension == 3:
+ note = "Note: I am very SLOW. Please be PATIENT...\n"
+ if len(self.data.data) > 3600:
+ note += "Rotation disabled for pixels > 60x60."
+ note_txt = wx.StaticText(self, -1, note)
+ note_txt.SetForegroundColour(wx.RED)
+ sizer.Add(note_txt, (0, 2), flag=wx.RIGHT | wx.TOP, border=5)
+
+ sizer.Add(self.plotpanel, (1, 0), (9, 9),
+ wx.EXPAND | wx.ALL, 15)
+
+ sizer.AddGrowableCol(3)
+ sizer.AddGrowableRow(2)
+
+ self.SetSizerAndFit(sizer)
+ self.Centre()
+ self.Show(True)
+
+ def set_plot_unfocus(self):
+ """
+ Not implemented
+ """
+ pass
+
+ def _draw_model(self, event):
+ """
+ on_close, update the model2d plot
+ """
+ pass
+
+ def freeze_axes(self):
+ """
+ freeze axes
+ """
+ self.plotpanel.axes_frozen = True
+
+ def thaw_axes(self):
+ """
+ thaw axes
+ """
+ self.plotpanel.axes_frozen = False
+
+ def OnClose(self, event):
+ """
+ """
+ try:
+ self.plotpanel.subplot.figure.clf()
+ self.plotpanel.Close()
+ except:
+ # when called by data panel
+ event.Skip()
+ pass
+
+class Maskplotpanel(PlotPanel):
+ """
+ PlotPanel for Quick plot and masking plot
+ """
+ def __init__(self, parent, id=-1, dimension=2, color=None, dpi=None, **kwargs):
+ """
+ """
+ PlotPanel.__init__(self, parent, id=id, color=color, dpi=dpi, **kwargs)
+
+ # Keep track of the parent Frame
+ self.parent = parent
+ # Internal list of plottable names (because graph
+ # doesn't have a dictionary of handles for the plottables)
+ self.dimension = dimension
+ self.plots = {}
+ self.graph = Graph()
+ # add axis labels
+ self.graph.xaxis('\\rm{x} ', '')
+ self.graph.yaxis('\\rm{y} ', '')
+
+ def add_toolbar(self):
+ """
+ Add toolbar
+ """
+ # Not implemented
+ pass
+
+ def on_set_focus(self, event):
+ """
+ send to the parenet the current panel on focus
+ """
+ if self.dimension == 3:
+ pass
+ else:
+ self.draw()
+
+ def add_image(self, plot):
+ """
+ Add Image
+ """
+ self.plots[plot.name] = plot
+ # init graph
+ self.graph = Graph()
+ # add plot
+ self.graph.add(plot)
+ # add axes
+ if self.dimension == 1:
+ self.xaxis_label = '\\rm{x} '
+ self.xaxis_unit = ''
+ self.yaxis_label = '\\rm{y} '
+ self.yaxis_unit = ''
+ # draw
+ # message
+ status_type = 'progress'
+ msg = 'Plotting...'
+ self._status_info(msg, status_type)
+ status_type = 'stop'
+ self.graph.render(self)
+ self.subplot.figure.canvas.resizing = False
+ if self.dimension < 3:
+ self.graph.render(self)
+ self.subplot.figure.canvas.draw()
+ elif FONT_VARIANT:
+ self.subplot.figure.canvas.draw()
+ msg = 'Plotting Completed.'
+ self._status_info(msg, status_type)
+
+ def onMouseMotion(self, event):
+ """
+ Disable dragging 2D image
+ """
+ pass
+
+ def onWheel(self, event):
+ """
+ """
+ pass
+
+ def onLeftDown(self, event):
+ """
+ Disables LeftDown
+ """
+ pass
+
+ def onPick(self, event):
+ """
+ Disables OnPick
+ """
+ pass
+
+ def draw(self):
+ """
+ Draw
+ """
+ # message
+ status_type = 'progress'
+ msg = 'Plotting...'
+ self._status_info(msg, status_type)
+ status_type = 'stop'
+
+ if not self.dimension == 3:
+ self.subplot.figure.canvas.draw_idle()
+
+ msg = 'Plotting Completed.'
+ self._status_info(msg, status_type)
+
+ def onContextMenu(self, event):
+ """
+ Default context menu for a plot panel
+ """
+ # Selective Slicer plot popup menu
+ slicerpop = wx.Menu()
+
+ id = wx.NewId()
+ slicerpop.Append(id, '&Print Image', 'Print image')
+ wx.EVT_MENU(self, id, self.onPrint)
+
+ id = wx.NewId()
+ slicerpop.Append(id, '&Copy to Clipboard', 'Copy to the clipboard')
+ wx.EVT_MENU(self, id, self.OnCopyFigureMenu)
+
+ if self.dimension == 1:
+ id = wx.NewId()
+ slicerpop.Append(id, '&Change Scale')
+ wx.EVT_MENU(self, id, self._onProperties)
+ else:
+ slicerpop.AppendSeparator()
+ id_cm = wx.NewId()
+ slicerpop.Append(id_cm, '&Toggle Linear/Log scale')
+ wx.EVT_MENU(self, id_cm, self._onToggleScale)
+
+ pos = event.GetPosition()
+ pos = self.ScreenToClient(pos)
+ self.PopupMenu(slicerpop, pos)
+
+ def _status_info(self, msg='', type="update"):
+ """
+ Status msg
+ """
+ if self.parent.parent.parent is not None:
+ wx.PostEvent(self.parent.parent.parent,
+ StatusEvent(status=msg, type=type))
+
+class ViewerFrame(wx.Frame):
+ """
+ Add comment
+ """
+ def __init__(self, parent, id, title):
+ """
+ comment
+ :param parent: parent panel/container
+ """
+ # Initialize the Frame object
+ wx.Frame.__init__(self, parent, id, title,
+ wx.DefaultPosition, wx.Size(950, 850))
+ # Panel for 1D plot
+ self.plotpanel = Maskplotpanel(self, -1, style=wx.RAISED_BORDER)
+
+class ViewApp(wx.App):
+ def OnInit(self):
+ frame = ViewerFrame(None, -1, 'testView')
+ frame.Show(True)
+ # self.SetTopWindow(frame)
+
+ return True
+
+if __name__ == "__main__":
+ app = ViewApp(0)
+ app.MainLoop()
diff --git a/src/sas/sasgui/guiframe/local_perspectives/plotting/slicerpanel.py b/src/sas/sasgui/guiframe/local_perspectives/plotting/parameters_panel_boxsum.py
similarity index 66%
rename from src/sas/sasgui/guiframe/local_perspectives/plotting/slicerpanel.py
rename to src/sas/sasgui/guiframe/local_perspectives/plotting/parameters_panel_boxsum.py
index 10d182c..777032c 100644
--- a/src/sas/sasgui/guiframe/local_perspectives/plotting/slicerpanel.py
+++ b/src/sas/sasgui/guiframe/local_perspectives/plotting/parameters_panel_boxsum.py
@@ -1,22 +1,19 @@
import wx
import wx.lib.newevent
-#from copy import deepcopy
+from parameters_panel_slicer import SlicerParameterPanel
from sas.sasgui.guiframe.utils import format_number
-from sas.sasgui.guiframe.events import SlicerParameterEvent
-from sas.sasgui.guiframe.events import EVT_SLICER_PARS
-from sas.sasgui.guiframe.events import EVT_SLICER
-
from sas.sasgui.guiframe.panel_base import PanelBase
+from sas.sasgui.guiframe.events import (SlicerParameterEvent, EVT_SLICER_PARS,
+ EVT_SLICER)
+
class SlicerPanel(wx.Panel, PanelBase):
"""
Panel class to show the slicer parameters
"""
- #TODO: show units
- #TODO: order parameters properly
- ## Internal name for the AUI manager
+ # Internal name for the AUI manager
window_name = "Slicer panel"
- ## Title to appear on top of the window
+ # Title to appear on top of the window
window_caption = "Slicer Panel"
CENTER_PANE = False
@@ -24,7 +21,7 @@ class SlicerPanel(wx.Panel, PanelBase):
params=None, *args, **kwargs):
wx.Panel.__init__(self, parent, id, *args, **kwargs)
PanelBase.__init__(self)
- ## Initialization of the class
+ # Initialization of the class
self.base = base
if params is None:
params = {}
@@ -36,30 +33,16 @@ class SlicerPanel(wx.Panel, PanelBase):
self.parameters = []
self.bck = wx.GridBagSizer(5, 5)
self.SetSizer(self.bck)
- if type == None and params == None:
+ if type is None and params is None:
label = "Right-click on 2D plot for slicer options"
title = wx.StaticText(self, -1, label, style=wx.ALIGN_LEFT)
self.bck.Add(title, (0, 0), (1, 2),
flag=wx.LEFT | wx.ALIGN_CENTER_VERTICAL, border=15)
else:
self.set_slicer(type, params)
- ## Bindings
- self.parent.Bind(EVT_SLICER, self.onEVT_SLICER)
- self.parent.Bind(EVT_SLICER_PARS, self.onParamChange)
-
- def onEVT_SLICER(self, event):
- """
- Process EVT_SLICER events
- When the slicer changes, update the panel
-
- :param event: EVT_SLICER event
-
- """
- event.Skip()
- if event.obj_class == None:
- self.set_slicer(None, None)
- else:
- self.set_slicer(event.type, event.params)
+ # Bindings
+ self.parent.Bind(EVT_SLICER, SlicerParameterPanel.on_evt_slicer)
+ self.parent.Bind(EVT_SLICER_PARS, SlicerParameterPanel.on_param_change)
def set_slicer(self, type, params):
"""
@@ -67,7 +50,7 @@ class SlicerPanel(wx.Panel, PanelBase):
"""
self.bck.Clear(True)
self.type = type
- if type == None:
+ if type is None:
label = "Right-click on 2D plot for slicer options"
title = wx.StaticText(self, -1, label, style=wx.ALIGN_LEFT)
self.bck.Add(title, (0, 0), (1, 2),
@@ -83,40 +66,47 @@ class SlicerPanel(wx.Panel, PanelBase):
keys = params.keys()
keys.sort()
for item in keys:
- if not item.lower() in ["num_points", "avg", "avg_error", "sum", "sum_error"]:
+ if not item.lower() in ["num_points", "avg", "avg_error", "sum",
+ "sum_error"]:
n += 1
text = wx.StaticText(self, -1, item, style=wx.ALIGN_LEFT)
self.bck.Add(text, (n - 1, 0),
- flag=wx.LEFT | wx.ALIGN_CENTER_VERTICAL, border=15)
+ flag=wx.LEFT | wx.ALIGN_CENTER_VERTICAL,
+ border=15)
ctl = wx.TextCtrl(self, -1, size=(80, 20),
style=wx.TE_PROCESS_ENTER)
hint_msg = "Modify the value of %s to change " % item
hint_msg += "the 2D slicer"
ctl.SetToolTipString(hint_msg)
ctl.SetValue(str(format_number(params[item])))
- self.Bind(wx.EVT_TEXT_ENTER, self.onTextEnter)
- ctl.Bind(wx.EVT_SET_FOCUS, self.onSetFocus)
- ctl.Bind(wx.EVT_KILL_FOCUS, self.onTextEnter)
+ self.Bind(wx.EVT_TEXT_ENTER, self.on_text_enter)
+ ctl.Bind(wx.EVT_SET_FOCUS, self.on_set_focus)
+ ctl.Bind(wx.EVT_KILL_FOCUS, self.on_text_enter)
self.parameters.append([item, ctl])
- self.bck.Add(ctl, (n - 1, 1), flag=wx.TOP | wx.BOTTOM, border=0)
+ self.bck.Add(ctl, (n - 1, 1), flag=wx.TOP | wx.BOTTOM,
+ border=0)
for item in keys:
- if item.lower() in ["num_points", "avg", "avg_error", "sum", "sum_error"]:
+ if item.lower() in ["num_points", "avg", "avg_error", "sum",
+ "sum_error"]:
n += 1
- text = wx.StaticText(self, -1, item + ": ", style=wx.ALIGN_LEFT)
- self.bck.Add(text, (n - 1, 0), flag=wx.LEFT | wx.ALIGN_CENTER_VERTICAL,
+ text = wx.StaticText(self, -1, item + ": ",
+ style=wx.ALIGN_LEFT)
+ self.bck.Add(text, (n - 1, 0),
+ flag=wx.LEFT | wx.ALIGN_CENTER_VERTICAL,
border=15)
ctl = wx.StaticText(self, -1,
str(format_number(params[item])),
style=wx.ALIGN_LEFT)
ctl.SetToolTipString("Result %s" % item)
- self.bck.Add(ctl, (n - 1, 1), flag=wx.TOP | wx.BOTTOM, border=0)
+ self.bck.Add(ctl, (n - 1, 1), flag=wx.TOP | wx.BOTTOM,
+ border=0)
self.bck.Layout()
self.Layout()
- psizer = self.parent.GetSizer()
- if psizer != None:
- psizer.Layout()
+ p_sizer = self.parent.GetSizer()
+ if p_sizer is not None:
+ p_sizer.Layout()
- def onSetFocus(self, evt):
+ def on_set_focus(self, evt):
"""
Highlight the txtcrtl
"""
@@ -125,20 +115,8 @@ class SlicerPanel(wx.Panel, PanelBase):
widget = evt.GetEventObject()
# Select the whole control, after this event resolves
wx.CallAfter(widget.SetSelection, -1, -1)
- return
-
- def onParamChange(self, evt):
- """
- Receive and event and reset the text field contained in self.parameters
- """
- evt.Skip()
- for item in self.parameters:
- if item[0] in evt.params:
- item[1].SetValue(format_number(evt.params[item[0]]))
- item[1].Refresh()
-
- def onTextEnter(self, evt):
+ def on_text_enter(self, evt):
"""
Parameters have changed
"""
@@ -148,16 +126,16 @@ class SlicerPanel(wx.Panel, PanelBase):
for item in self.parameters:
try:
params[item[0]] = float(item[1].GetValue())
- item[1].SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
+ item[1].SetBackgroundColour(wx.SystemSettings_GetColour(
+ wx.SYS_COLOUR_WINDOW))
item[1].Refresh()
except:
has_error = True
item[1].SetBackgroundColour("pink")
item[1].Refresh()
-
- if has_error == False:
+ if not has_error:
# Post parameter event
- ## base is guiframe is this case
+ # base is guiframe is this case
event = SlicerParameterEvent(type=self.type, params=params)
wx.PostEvent(self.base, event)
@@ -165,6 +143,6 @@ class SlicerPanel(wx.Panel, PanelBase):
"""
On Close Event
"""
- ID = self.uid
- self.parent.delete_panel(ID)
+ uid = self.uid
+ self.parent.delete_panel(uid)
self.frame.Destroy()
diff --git a/src/sas/sasgui/guiframe/local_perspectives/plotting/parameters_panel_slicer.py b/src/sas/sasgui/guiframe/local_perspectives/plotting/parameters_panel_slicer.py
new file mode 100644
index 0000000..7aa8f80
--- /dev/null
+++ b/src/sas/sasgui/guiframe/local_perspectives/plotting/parameters_panel_slicer.py
@@ -0,0 +1,536 @@
+
+
+import os
+import wx
+import wx.lib.newevent
+from sas.sascalc.dataloader.readers.cansas_reader import Reader
+from sas.sasgui.guiframe.utils import format_number
+from sas.sasgui.guiframe.events import EVT_SLICER_PARS, EVT_SLICER
+from sas.sasgui.guiframe.events import SlicerParameterEvent, StatusEvent
+from Plotter2D import ModelPanel2D
+apply_params, EVT_APPLY_PARAMS = wx.lib.newevent.NewEvent()
+save_files, EVT_AUTO_SAVE = wx.lib.newevent.NewEvent()
+
+FIT_OPTIONS = ["No fitting", "Fitting", "Batch Fitting"]
+CONVERT_KEYS = ["SectorInteractor", "AnnulusInteractor", "BoxInteractorX",
+ "BoxInteractorY"]
+CONVERT_DICT = {"SectorInteractor": "SectorQ",
+ "AnnulusInteractor": "AnnulusPhi",
+ "BoxInteractorX": "SlabX",
+ "BoxInteractorY": "SlabY"}
+BINNING_OPTIONS = {"Linear" : 0,
+ "Logarithmic" : 10,}
+
+
+class SlicerParameterPanel(wx.Dialog):
+ """
+ Panel for dynamically changing slicer parameters and apply the same slicer
+ to multiple 2D plot panels
+ """
+
+ def __init__(self, parent, *args, **kwargs):
+ """
+ Dialog window that allow to edit parameters slicer
+ by entering new values
+ """
+ wx.Dialog.__init__(self, parent, *args, **kwargs)
+ self.params = {}
+ self.iter = 0
+ self.parent = parent
+ self.main_window = parent.parent
+ self.data_panel = self.main_window._data_panel
+ self.type = None
+ self.listeners = []
+ self.parameters = []
+ self.bck = wx.GridBagSizer(5, 5)
+ self.SetSizer(self.bck)
+ self.auto_save = None
+ self.path = None
+ self.fitting_options = None
+ self.bin_ctl = None
+ self.type_list = []
+ self.loaded_data = []
+ self.always_on = None
+ self.type_select = None
+ self.append_name = None
+ self.data_list = None
+ self.default_value = ""
+ self.batch_slicer_button = None
+ label = "Right-click on 2D plot for slicer options"
+ title = wx.StaticText(self, -1, label, style=wx.ALIGN_LEFT)
+ self.bck.Add(title, (0, 0), (1, 2),
+ flag=wx.LEFT | wx.ALIGN_CENTER_VERTICAL, border=15)
+ # Bindings
+ self.parent.Bind(EVT_SLICER, self.on_evt_slicer)
+ self.Bind(EVT_SLICER_PARS, self.on_param_change)
+ self.Bind(EVT_APPLY_PARAMS, self.apply_params_list_and_process)
+ self.Bind(EVT_AUTO_SAVE, self.save_files)
+
+ def on_evt_slicer(self, event):
+ """
+ Process EVT_SLICER events
+ When the slicer changes, update the panel
+
+ :param event: EVT_SLICER event
+ """
+ event.Skip()
+ if event.obj_class is None:
+ self.set_slicer(None, None)
+ else:
+ self.set_slicer(event.type, event.params)
+
+ def set_slicer(self, type, params):
+ """
+ Rebuild the panel
+ """
+ self.bck.Clear(True)
+ self.bck.Add((5, 5), (0, 0), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 5)
+ self.type = type
+ if type is None:
+ label = "Right-click on 2D plot for slicer options"
+ title = wx.StaticText(self, -1, label, style=wx.ALIGN_LEFT)
+ self.bck.Add(title, (1, 0), (1, 2),
+ flag=wx.LEFT | wx.ALIGN_CENTER_VERTICAL, border=15)
+ else:
+ title = wx.StaticText(self, -1,
+ "Slicer Parameters:", style=wx.ALIGN_LEFT)
+ self.bck.Add(title, (1, 0), (1, 2),
+ flag=wx.LEFT | wx.ALIGN_CENTER_VERTICAL, border=15)
+ iy = 1
+ self.parameters = []
+ keys = params.keys()
+ keys.sort()
+ for item in keys:
+ ix = 0
+ iy += 1
+ if item not in ["count", "errors", "binning base"]:
+ text = wx.StaticText(self, -1, item, style=wx.ALIGN_LEFT)
+ self.bck.Add(text, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ ctl = wx.TextCtrl(self, -1, size=(80, 20),
+ style=wx.TE_PROCESS_ENTER)
+ hint_msg = "Modify the value of %s to change" % item
+ hint_msg += " the 2D slicer"
+ ctl.SetToolTipString(hint_msg)
+ ix = 1
+ ctl.SetValue(format_number(str(params[item])))
+ self.Bind(wx.EVT_TEXT_ENTER, self.on_text_enter)
+ self.parameters.append([item, ctl])
+ self.bck.Add(ctl, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix = 3
+ self.bck.Add((20, 20), (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ elif item == 'binning base':
+ text = wx.StaticText(self, -1, item, style=wx.ALIGN_LEFT)
+ self.bck.Add(text, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ options = BINNING_OPTIONS.keys()
+ self.bin_ctl = wx.ComboBox(parent=self, choices=options)
+ hint_msg = "Modify the value of %s to change" % item
+ hint_msg += " the 2D slicer"
+ self.bin_ctl.SetToolTipString(hint_msg)
+ ix = 1
+ result = ""
+ value = 0
+ for name, value in BINNING_OPTIONS.items():
+ if value == params[item]:
+ result = name
+ break
+ index = self.bin_ctl.FindString(result)
+ self.bin_ctl.SetSelection(index)
+ self.parameters.append([item, self.bin_ctl])
+ self.Bind(wx.EVT_COMBOBOX, self.on_text_enter)
+ self.bck.Add(self.bin_ctl, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix = 3
+ self.bck.Add((20, 20), (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ else:
+ text = wx.StaticText(self, -1, item + " : ",
+ style=wx.ALIGN_LEFT)
+ self.bck.Add(text, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ ctl = wx.StaticText(self, -1,
+ format_number(str(params[item])),
+ style=wx.ALIGN_LEFT)
+ ix = 1
+ self.bck.Add(ctl, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+
+ # Change slicer within the window
+ ix = 0
+ iy += 1
+ txt = "Slicer type"
+ text = wx.StaticText(self, -1, txt, style=wx.ALIGN_LEFT)
+ self.bck.Add(text, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ self.type_list = CONVERT_KEYS
+ self.type_select = wx.ComboBox(parent=self, choices=self.type_list)
+ self.type_select.Bind(wx.EVT_COMBOBOX, self.on_change_slicer)
+ index = self.type_select.FindString(type)
+ self.type_select.SetSelection(index)
+ self.bck.Add(self.type_select, (iy, 1), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+
+ # batch slicing parameters
+ title_text = "Batch Slicing Options:"
+ title = wx.StaticText(self, -1, title_text, style=wx.ALIGN_LEFT)
+ iy += 1
+ line = wx.StaticLine(self, -1, style=wx.LI_VERTICAL)
+ line.SetSize((60, 60))
+ self.bck.Add(line, (iy, ix), (1, 2),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ iy += 1
+ self.bck.Add(title, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+
+ # Create a list box with all of the 2D plots
+ iy += 1
+ self.process_list()
+ self.bck.Add(self.data_list, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+
+ # Checkbox to enable saving and fitting options
+ iy += 1
+ self.auto_save = wx.CheckBox(parent=self, id=wx.NewId(),
+ label="Auto save generated 1D:")
+ self.Bind(wx.EVT_CHECKBOX, self.on_auto_save_checked)
+ self.bck.Add(self.auto_save, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ iy += 1
+ # File browser
+ save_to = "Save files to:"
+ save = wx.StaticText(self, -1, save_to, style=wx.ALIGN_LEFT)
+ path = os.getcwd()
+ self.path = wx.DirPickerCtrl(self, id=wx.NewId(), path=path,
+ message=save_to)
+ self.path.Enable(False)
+ self.bck.Add(save, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ self.bck.Add(self.path, (iy, 1), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ # Append to file
+ iy += 1
+ self.update_file_append(params)
+ append_text = "Append to file name:"
+ append = wx.StaticText(self, -1, append_text, style=wx.ALIGN_LEFT)
+ self.append_name = wx.TextCtrl(parent=self, id=wx.NewId(),
+ name="Append to file name:")
+ append_tool_tip = "Files will be saved as <SlicerType><FileName>"
+ append_tool_tip += "<AppendToText>.txt"
+ self.append_name.SetToolTipString(append_tool_tip)
+ self.append_name.SetValue(self.default_value)
+ self.append_name.Enable(False)
+ self.bck.Add(append, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ self.bck.Add(self.append_name, (iy, 1), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+
+ # Combobox for selecting fitting options
+ iy += 1
+ fit_text = "Fitting Options:"
+ fit_text_item = wx.StaticText(self, -1, fit_text,
+ style=wx.ALIGN_LEFT)
+ self.bck.Add(fit_text_item, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ self.fitting_options = wx.ComboBox(parent=self, choices=FIT_OPTIONS)
+ self.fitting_options.SetSelection(0)
+ self.bck.Add(self.fitting_options, (iy, 1), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ self.fitting_options.Enable(False)
+ self.fitting_options.Bind(wx.EVT_COMBOBOX, None)
+
+ # Button to start batch slicing
+ iy += 1
+ button_label = "Apply Slicer to Selected Plots"
+ self.batch_slicer_button = wx.Button(parent=self,
+ label=button_label)
+ self.Bind(wx.EVT_BUTTON, self.on_batch_slicer)
+ self.bck.Add(self.batch_slicer_button, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ iy += 1
+ self.bck.Add((5, 5), (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 5)
+ self.bck.Layout()
+ self.bck.Fit(self)
+ self.parent.GetSizer().Layout()
+
+ def on_param_change(self, evt):
+ """
+ receive an event end reset value text fields
+ inside self.parameters
+ """
+ evt.Skip()
+ if evt.type == "UPDATE":
+ for item in self.parameters:
+ if item[0] in evt.params:
+ item[1].SetValue("%-5.3g" % evt.params[item[0]])
+ item[1].Refresh()
+
+ def on_text_enter(self, evt):
+ """
+ Parameters have changed
+ """
+ params = {}
+ has_error = False
+ for item in self.parameters:
+ try:
+ if item[0] == "binning base":
+ title = self.bin_ctl.GetValue()
+ params["binning base"] = BINNING_OPTIONS.get(title)
+ continue
+ params[item[0]] = float(item[1].GetValue())
+ item[1].SetBackgroundColour(
+ wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
+ item[1].Refresh()
+ except:
+ has_error = True
+ item[1].SetBackgroundColour("pink")
+ item[1].Refresh()
+
+ if not has_error:
+ # Post parameter event
+ # parent here is plotter2D
+ self.update_file_append(params)
+ self.append_name.SetValue(self.default_value)
+ self.append_name.Refresh()
+ event = SlicerParameterEvent(type=self.type, params=params)
+ wx.PostEvent(self.parent, event)
+
+ def on_batch_slicer(self, evt=None):
+ """
+ Event triggered when batch slicing button is pressed
+ :param evt: Event triggering the batch slicing
+ """
+ apply_to_list = []
+ spp = self.parent.parent
+ params = self.parent.slicer.get_params()
+ slicer_type = self.type_select.GetStringSelection()
+ save = self.auto_save.IsChecked()
+ append = self.append_name.GetValue()
+ path = self.path.GetPath()
+ fit = self.fitting_options.GetValue()
+
+ # Find desired 2D data panels
+ for key, mgr in spp.plot_panels.iteritems():
+ if mgr.graph.prop['title'] in self.data_list.CheckedStrings:
+ apply_to_list.append(mgr)
+
+ # Apply slicer type to selected panels
+ for item in apply_to_list:
+ self._apply_slicer_to_plot(item, slicer_type)
+
+ # Post an event to apply appropriate slicer params to each slicer
+ # Pass all variables, including class variables
+ event_params = apply_params(params=params, apply_to_list=apply_to_list,
+ auto_save=save, append=append, fit=fit,
+ path=path, type=slicer_type)
+ wx.PostEvent(self, event_params)
+
+ def on_change_slicer(self, evt):
+ """
+ Event driven slicer change when self.type_select changes
+ :param evt: Event triggering this change
+ """
+ self._apply_slicer_to_plot(self.parent)
+
+ def _apply_slicer_to_plot(self, plot, slicer_type=None):
+ """
+ Apply a slicer to *any* plot window, not just parent window
+ :param plot: 2D plot panel to apply a slicer to
+ :param slicer_type: The type of slicer to apply to the panel
+ """
+ # Skip redrawing the current plot if no change in slicer type
+ if self.parent == plot and self.type == slicer_type:
+ return
+ # Do not draw a slicer on a 1D plot
+ if not isinstance(plot, ModelPanel2D):
+ return
+ if slicer_type is None:
+ slicer_type = self.type_select.GetStringSelection()
+ if slicer_type == self.type_list[0]:
+ plot.onSectorQ(None)
+ elif slicer_type == self.type_list[1]:
+ plot.onSectorPhi(None)
+ elif slicer_type == self.type_list[2]:
+ plot.onBoxavgX(None)
+ elif slicer_type == self.type_list[3]:
+ plot.onBoxavgY(None)
+
+ def process_list(self):
+ """
+ Populate the check list from the currently plotted 2D data
+ """
+ # Reinitialize loaded data list on redraw
+ self.loaded_data = []
+ # Iterate over the loaded plots and find all 2D panels
+ for key, value in self.main_window.plot_panels.iteritems():
+ if isinstance(value, ModelPanel2D):
+ self.loaded_data.append(value.data2D.name)
+ if value.data2D.id == self.parent.data2D.id:
+ # Set current plot panel as uncheckable
+ self.always_on = self.loaded_data.index(value.data2D.name)
+ self.data_list = wx.CheckListBox(parent=self, id=wx.NewId(),
+ choices=self.loaded_data,
+ name="Apply Slicer to 2D Plots:")
+ # Check all items by default
+ for item in range(len(self.data_list.Items)):
+ self.data_list.Check(item)
+ self.data_list.Bind(wx.EVT_CHECKLISTBOX, self.on_check_box_list)
+
+ def on_check_box_list(self, evt=None):
+ """
+ Prevent a checkbox item from being unchecked
+ :param evt: Event triggered when a checkbox list item is checked
+ """
+ if evt is None:
+ return
+ index = evt.GetSelection()
+ if index == self.always_on:
+ self.data_list.Check(index)
+
+ def apply_params_list_and_process(self, evt=None):
+ """
+ Event based parameter setting.
+
+ :param evt: Event triggered to apply parameters to a list of plots
+ evt should have attrs plot_list and params
+
+ """
+ if evt is None:
+ return
+ # Apply parameter list to each plot as desired
+ for item in evt.apply_to_list:
+ event = SlicerParameterEvent(type=evt.type, params=evt.params)
+ wx.PostEvent(item, event)
+ # Post an event to save each data set to file
+ if evt.auto_save:
+ event = save_files(append_to_name=evt.append, path=evt.path,
+ type=evt.type, file_list=evt.apply_to_list,
+ fit=evt.fit)
+ wx.PostEvent(self, event)
+
+ def save_files(self, evt=None):
+ """
+ Automatically save the sliced data to file.
+ :param evt: Event that triggered the call to the method
+ """
+
+ # Events triggered after this event pass other events to wx that are
+ # necessary before this event is called. If this is the first time
+ # reaching this event, send it to the end of the wx event queue
+ if self.iter < 2:
+ clone = evt.Clone()
+ wx.PostEvent(self, clone)
+ self.iter += 1
+ return
+ if evt is None:
+ return
+
+ # Start definitions
+ writer = Reader()
+ data_dic = {}
+ append = evt.append_to_name
+ names = []
+ f_name_list = []
+ f_path_list = []
+
+ # Get list of 2D data names for saving
+ for f_name in evt.file_list:
+ names.append(f_name.data2D.label)
+
+ # Find the correct plots to save
+ for key, plot in self.main_window.plot_panels.iteritems():
+ if not hasattr(plot, "data2D"):
+ for item in plot.plots:
+ base = item.replace(CONVERT_DICT[evt.type], "")
+ if base in names:
+ data_dic[item] = plot.plots[item]
+
+ # Save files as Text
+ for item, data1d in data_dic.iteritems():
+ base = '.'.join(item.split('.')[:-1])
+ file_name = base + append + ".txt"
+ save_to = evt.path + "\\" + file_name
+ writer.write(save_to, data1d)
+ f_path_list.append(save_to)
+ f_name_list.append(file_name)
+
+ # Load files into GUI
+ for item in f_path_list:
+ self.main_window.load_data(item)
+
+ # Send to fitting
+ self.send_to_fitting(evt.fit, f_name_list)
+
+ def send_to_fitting(self, fit=FIT_OPTIONS[0], file_list=None):
+ """
+ Send a list of data to the fitting perspective
+ :param fit: fit type desired
+ :param file_list: list of loaded file names to send to fit
+ """
+ if fit in FIT_OPTIONS and fit != FIT_OPTIONS[0] and \
+ file_list is not None:
+ # Set perspective to fitting
+ int = self.data_panel.perspective_cbox.FindString("Fitting")
+ self.data_panel.perspective_cbox.SetSelection(int)
+ self.data_panel._on_perspective_selection(None)
+ # Unselect all loaded data
+ self.data_panel.selection_cbox.SetValue('Unselect all Data')
+ self.data_panel._on_selection_type(None)
+ # Click each sliced data file
+ for f_name in file_list:
+ num = len(f_name)
+ data_list = self.data_panel.list_cb_data
+ for key in data_list:
+ loaded_key = (key[:num]) if len(key) > num else key
+ if loaded_key == f_name:
+ selection = key
+ data_ctrl = data_list[selection][0]
+ self.check_item_and_children(data_ctrl=data_ctrl,
+ check_value=True)
+ # Switch to batch mode if selected
+ if fit == FIT_OPTIONS[2]:
+ self.data_panel.rb_single_mode.SetValue(False)
+ self.data_panel.rb_batch_mode.SetValue(True)
+ self.data_panel.on_batch_mode(None)
+ else:
+ self.data_panel.rb_single_mode.SetValue(True)
+ self.data_panel.rb_batch_mode.SetValue(False)
+ self.data_panel.on_single_mode(None)
+
+ # Post button click event to send data to fitting
+ evt = wx.PyCommandEvent(wx.EVT_BUTTON.typeId,
+ self.data_panel.bt_import.GetId())
+ wx.PostEvent(self.data_panel, evt)
+
+ def on_auto_save_checked(self, evt=None):
+ """
+ Enable/Disable auto append when checkbox is checked
+ :param evt: Event
+ """
+ self.append_name.Enable(self.auto_save.IsChecked())
+ self.path.Enable(self.auto_save.IsChecked())
+ self.fitting_options.Enable(self.auto_save.IsChecked())
+
+ def check_item_and_children(self, data_ctrl, check_value=True):
+ self.data_panel.tree_ctrl.CheckItem(data_ctrl, check_value)
+ if data_ctrl.HasChildren():
+ if check_value and not data_ctrl.IsExpanded():
+ return
+ for child_ctrl in data_ctrl.GetChildren():
+ self.data_panel.CheckItem(child_ctrl, check_value)
+
+ def update_file_append(self, params=None):
+ """
+ Update default_value when any parameters are changed
+ :param params: dictionary of parameters
+ """
+ self.default_value = ""
+ if params is None:
+ params = self.params
+ for key in params:
+ self.default_value += "_{0}".format(key).split(" [")[0]
+ self.default_value += "-{:.2f}".format(params[key])
diff --git a/src/sas/sasgui/guiframe/local_perspectives/plotting/plotting.py b/src/sas/sasgui/guiframe/local_perspectives/plotting/plotting.py
index 7cad09a..ba5d865 100644
--- a/src/sas/sasgui/guiframe/local_perspectives/plotting/plotting.py
+++ b/src/sas/sasgui/guiframe/local_perspectives/plotting/plotting.py
@@ -1,333 +1,347 @@
-
-
-
-################################################################################
-#This software was developed by the University of Tennessee as part of the
-#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
-#project funded by the US National Science Foundation.
-#
-#See the license text in license.txt
-#
-#copyright 2008, University of Tennessee
-################################################################################
-
-import wx
-import sys
-from sas.sasgui.guiframe.events import EVT_NEW_PLOT
-from sas.sasgui.guiframe.events import EVT_PLOT_QRANGE
-from sas.sasgui.guiframe.events import EVT_PLOT_LIM
-from sas.sasgui.guiframe.events import DeletePlotPanelEvent
-from sas.sasgui.guiframe.plugin_base import PluginBase
-from sas.sasgui.guiframe.dataFitting import Data1D
-from sas.sasgui.guiframe.dataFitting import Data2D
-from sas.sasgui.guiframe.gui_manager import MDIFrame
-DEFAULT_MENU_ITEM_LABEL = "No graph available"
-DEFAULT_MENU_ITEM_ID = wx.NewId()
-
-IS_WIN = True
-if sys.platform.count("win32") == 0:
- if int(str(wx.__version__).split('.')[0]) == 2:
- if int(str(wx.__version__).split('.')[1]) < 9:
- IS_WIN = False
-
-
-class Plugin(PluginBase):
- """
- Plug-in class to be instantiated by the GUI manager
- """
-
- def __init__(self):
- PluginBase.__init__(self, name="Plotting")
-
- ## Plot panels
- self.plot_panels = {}
- self._panel_on_focus = None
- self.menu_default_id = None
- # Plot menu
- self.menu = None
-
-
- def set_panel_on_focus(self, panel):
- """
- """
- self._panel_on_focus = panel
-
- def is_always_active(self):
- """
- return True is this plugin is always active even if the user is
- switching between perspectives
- """
- return True
-
- def populate_menu(self, parent):
- """
- Create a 'Plot' menu to list the panels
- available for displaying
-
- :param id: next available unique ID for wx events
- :param parent: parent window
-
- """
- return []
-
- def get_panels(self, parent):
- """
- Create and return a list of panel objects
- """
- ## Save a reference to the parent
- self.parent = parent
- # Connect to plotting events
- self.parent.Bind(EVT_NEW_PLOT, self._on_plot_event)
- self.parent.Bind(EVT_PLOT_QRANGE, self._on_plot_qrange)
- self.parent.Bind(EVT_PLOT_LIM, self._on_plot_lim)
- # We have no initial panels for this plug-in
- return []
-
- def _on_plot_qrange(self, event=None):
- """
- On Qmin Qmax vertical line event
- """
- if event == None:
- return
- if event.id in self.plot_panels.keys():
- panel = self.plot_panels[event.id]
- elif event.group_id in self.plot_panels.keys():
- panel = self.plot_panels[event.group_id]
- else:
- return
- panel.on_plot_qrange(event)
-
- def _on_plot_lim(self, event=None):
- if event == None:
- return
- if event.id in self.plot_panels.keys():
- panel = self.plot_panels[event.id]
- elif event.group_id in self.plot_panels.keys():
- panel = self.plot_panels[event.group_id]
- else:
- return
- if hasattr(event, 'xlim'):
- panel.subplot.set_xlim(event.xlim)
- if hasattr(event, 'ylim'):
- panel.subplot.set_ylim(event.ylim)
-
-
- def _on_show_panel(self, event):
- """show plug-in panel"""
- pass
-
- def remove_plot(self, group_id, id):
- """
- remove plot of ID = id from a panel of group ID =group_id
- """
-
- if group_id in self.plot_panels.keys():
- panel = self.plot_panels[group_id]
- panel.remove_data_by_id(id=id)
-
- return True
- return False
-
- def clear_panel(self):
- """
- Clear and Hide all plot panels, and remove them from menu
- """
- for group_id in self.plot_panels.keys():
- self.clear_panel_by_id(group_id)
- self.plot_panels = {}
-
- def clear_panel_by_id(self, group_id):
- """
- clear the graph
- """
- if group_id in self.plot_panels.keys():
- panel = self.plot_panels[group_id]
- for plottable in panel.graph.plottables.keys():
- self.remove_plot(group_id, plottable.id)
- panel.graph.reset()
- return True
- return False
-
- def hide_panel(self, group_id):
- """
- hide panel with group ID = group_id
- """
- # Not implemeted
- return False
-
- def create_panel_helper(self, new_panel, data, group_id, title=None):
- """
- """
- ## Set group ID if available
- ## Assign data properties to the new create panel
- new_panel.set_manager(self)
- new_panel.group_id = group_id
- if group_id not in data.list_group_id:
- data.list_group_id.append(group_id)
- if title is None:
- title = data.title
- new_panel.window_caption = title
- new_panel.window_name = data.title
- event_id = self.parent.popup_panel(new_panel)
-
- # Set UID to allow us to reference the panel later
- new_panel.uid = event_id
- # Ship the plottable to its panel
- wx.CallAfter(new_panel.plot_data, data)
- #new_panel.canvas.set_resizing(new_panel.resizing)
- self.plot_panels[new_panel.group_id] = new_panel
-
- def create_1d_panel(self, data, group_id):
- """
- """
- # Create a new plot panel if none was available
- if issubclass(data.__class__, Data1D):
- from Plotter1D import ModelPanel1D
- ## get the data representation label of the data to plot
- ## when even the user select "change scale"
- xtransform = data.xtransform
- ytransform = data.ytransform
- ## create a plotpanel for 1D Data
- win = MDIFrame(self.parent, None, 'None', (100, 200))
- new_panel = ModelPanel1D(win, -1, xtransform=xtransform,
- ytransform=ytransform, style=wx.RAISED_BORDER)
- win.set_panel(new_panel)
- win.Show(False)
- new_panel.frame = win
- #win.Show(True)
- return new_panel
-
- msg = "1D Panel of group ID %s could not be created" % str(group_id)
- raise ValueError, msg
-
- def create_2d_panel(self, data, group_id):
- """
- """
- if issubclass(data.__class__, Data2D):
- ##Create a new plotpanel for 2D data
- from Plotter2D import ModelPanel2D
- scale = data.scale
- win = MDIFrame(self.parent, None, 'None', (200, 150))
- win.Show(False)
- new_panel = ModelPanel2D(win, id=-1,
- data2d=data, scale=scale,
- style=wx.RAISED_BORDER)
- win.set_panel(new_panel)
- new_panel.frame = win
- return new_panel
- msg = "2D Panel of group ID %s could not be created" % str(group_id)
- raise ValueError, msg
-
- def update_panel(self, data, panel):
- """
- update the graph of a given panel
- """
- # Check whether we already have a graph with the same units
- # as the plottable we just received.
- _, x_unit = data.get_xaxis()
- _, y_unit = data.get_yaxis()
- flag_x = (panel.graph.prop["xunit"] is not None) and \
- (panel.graph.prop["xunit"].strip() != "") and\
- (x_unit != panel.graph.prop["xunit"]) and False
- flag_y = (panel.graph.prop["yunit"] is not None) and \
- (panel.graph.prop["yunit"].strip() != "") and\
- (y_unit != panel.graph.prop["yunit"]) and False
- if flag_x and flag_y:
- msg = "Cannot add %s" % str(data.name)
- msg += " to panel %s\n" % str(panel.window_caption)
- msg += "Please edit %s's units, labels" % str(data.name)
- raise ValueError, msg
- else:
- if panel.group_id not in data.list_group_id:
- data.list_group_id.append(panel.group_id)
- wx.CallAfter(panel.plot_data, data)
-
- def delete_panel(self, group_id):
- """
- """
- if group_id in self.plot_panels.keys():
- panel = self.plot_panels[group_id]
- uid = panel.uid
- wx.PostEvent(self.parent,
- DeletePlotPanelEvent(name=panel.window_caption,
- caption=panel.window_caption))
- del self.plot_panels[group_id]
- if uid in self.parent.plot_panels.keys():
- del self.parent.plot_panels[uid]
- panel.frame.Destroy()
- return True
-
- return False
-
- def _on_plot_event(self, event):
- """
- A new plottable is being shipped to the plotting plug-in.
- Check whether we have a panel to put in on, or create
- a new one
-
- :param event: EVT_NEW_PLOT event
-
- """
- action_check = False
- if hasattr(event, 'action'):
- action_string = event.action.lower().strip()
- if action_string == 'check':
- action_check = True
- else:
- group_id = event.group_id
- if group_id in self.plot_panels.keys():
- #remove data from panel
- if action_string == 'remove':
- return self.remove_plot(group_id, event.id)
- if action_string == 'hide':
- return self.hide_panel(group_id)
- if action_string == 'delete':
- panel = self.plot_panels[group_id]
- uid = panel.uid
- return self.parent.delete_panel(uid)
- if action_string == "clear":
- return self.clear_panel_by_id(group_id)
-
- if not hasattr(event, 'plot'):
- return
- title = None
- if hasattr(event, 'title'):
- title = 'Graph' #event.title
- data = event.plot
- group_id = data.group_id
- if group_id in self.plot_panels.keys():
- if action_check:
- # Check if the plot already exist. if it does, do nothing.
- if data.id in self.plot_panels[group_id].plots.keys():
- return
- #update a panel graph
- panel = self.plot_panels[group_id]
- self.update_panel(data, panel)
- else:
- #create a new panel
- if issubclass(data.__class__, Data1D):
- new_panel = self.create_1d_panel(data, group_id)
- else:
- # Need to make the group_id consistent with 1D thus no if below
- if len(self.plot_panels.values()) > 0:
- for p_group_id in self.plot_panels.keys():
- p_plot = self.plot_panels[p_group_id]
- if data.id in p_plot.plots.keys():
- p_plot.plots[data.id] = data
- self.plot_panels[group_id] = p_plot
- if group_id != p_group_id:
- del self.plot_panels[p_group_id]
- if p_group_id in data.list_group_id:
- data.list_group_id.remove(p_group_id)
- if group_id not in data.list_group_id:
- data.list_group_id.append(group_id)
- p_plot.group_id = group_id
- return
-
- new_panel = self.create_2d_panel(data, group_id)
- self.create_panel_helper(new_panel, data, group_id, title)
- if hasattr(event, 'xlim'):
- new_panel.subplot.set_xlim(event.xlim)
- if hasattr(event, 'ylim'):
- new_panel.subplot.set_ylim(event.ylim)
- return
+
+
+
+################################################################################
+#This software was developed by the University of Tennessee as part of the
+#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
+#project funded by the US National Science Foundation.
+#
+#See the license text in license.txt
+#
+#copyright 2008, University of Tennessee
+################################################################################
+
+import wx
+import sys
+from copy import deepcopy
+from sas.sasgui.guiframe.events import EVT_NEW_PLOT
+from sas.sasgui.guiframe.events import EVT_PLOT_QRANGE
+from sas.sasgui.guiframe.events import EVT_PLOT_LIM
+from sas.sasgui.guiframe.events import DeletePlotPanelEvent
+from sas.sasgui.guiframe.plugin_base import PluginBase
+from sas.sasgui.guiframe.dataFitting import Data1D
+from sas.sasgui.guiframe.dataFitting import Data2D
+from sas.sasgui.guiframe.gui_manager import MDIFrame
+DEFAULT_MENU_ITEM_LABEL = "No graph available"
+DEFAULT_MENU_ITEM_ID = wx.NewId()
+
+IS_WIN = True
+if sys.platform.count("win32") == 0:
+ if int(str(wx.__version__).split('.')[0]) == 2:
+ if int(str(wx.__version__).split('.')[1]) < 9:
+ IS_WIN = False
+
+
+class Plugin(PluginBase):
+ """
+ Plug-in class to be instantiated by the GUI manager
+ """
+
+ def __init__(self):
+ PluginBase.__init__(self, name="Plotting")
+
+ ## Plot panels
+ self.plot_panels = {}
+ self._panel_on_focus = None
+ self.menu_default_id = None
+ # Plot menu
+ self.menu = None
+
+
+ def set_panel_on_focus(self, panel):
+ """
+ """
+ self._panel_on_focus = panel
+
+ def is_always_active(self):
+ """
+ return True is this plugin is always active even if the user is
+ switching between perspectives
+ """
+ return True
+
+ def populate_menu(self, parent):
+ """
+ Create a 'Plot' menu to list the panels
+ available for displaying
+
+ :param id: next available unique ID for wx events
+ :param parent: parent window
+
+ """
+ return []
+
+ def get_panels(self, parent):
+ """
+ Create and return a list of panel objects
+ """
+ ## Save a reference to the parent
+ self.parent = parent
+ # Connect to plotting events
+ self.parent.Bind(EVT_NEW_PLOT, self._on_plot_event)
+ self.parent.Bind(EVT_PLOT_QRANGE, self._on_plot_qrange)
+ self.parent.Bind(EVT_PLOT_LIM, self._on_plot_lim)
+ # We have no initial panels for this plug-in
+ return []
+
+ def _on_plot_qrange(self, event=None):
+ """
+ On Qmin Qmax vertical line event
+ """
+ if event is None:
+ return
+ if event.id in self.plot_panels.keys():
+ panel = self.plot_panels[event.id]
+ elif event.group_id in self.plot_panels.keys():
+ panel = self.plot_panels[event.group_id]
+ else:
+ return
+ panel.on_plot_qrange(event)
+
+ def _on_plot_lim(self, event=None):
+ if event is None:
+ return
+ if event.id in self.plot_panels.keys():
+ panel = self.plot_panels[event.id]
+ elif event.group_id in self.plot_panels.keys():
+ panel = self.plot_panels[event.group_id]
+ else:
+ return
+ if hasattr(event, 'xlim'):
+ panel.subplot.set_xlim(event.xlim)
+ if hasattr(event, 'ylim'):
+ panel.subplot.set_ylim(event.ylim)
+
+
+ def _on_show_panel(self, event):
+ """show plug-in panel"""
+ pass
+
+ def remove_plot(self, group_id, id):
+ """
+ remove plot of ID = id from a panel of group ID =group_id
+ """
+
+ if group_id in self.plot_panels.keys():
+ panel = self.plot_panels[group_id]
+ panel.remove_data_by_id(id=id)
+
+ return True
+ return False
+
+ def clear_panel(self):
+ """
+ Clear and Hide all plot panels, and remove them from menu
+ """
+ for group_id in self.plot_panels.keys():
+ self.clear_panel_by_id(group_id)
+ self.plot_panels = {}
+
+ def clear_panel_by_id(self, group_id):
+ """
+ clear the graph
+ """
+ if group_id in self.plot_panels.keys():
+ panel = self.plot_panels[group_id]
+ for plottable in panel.graph.plottables.keys():
+ self.remove_plot(group_id, plottable.id)
+ panel.graph.reset()
+ return True
+ return False
+
+ def hide_panel(self, group_id):
+ """
+ hide panel with group ID = group_id
+ """
+ # Not implemeted
+ return False
+
+ def create_panel_helper(self, new_panel, data, group_id, title=None):
+ """
+ """
+ ## Set group ID if available
+ ## Assign data properties to the new create panel
+ new_panel.set_manager(self)
+ new_panel.group_id = group_id
+ if group_id not in data.list_group_id:
+ data.list_group_id.append(group_id)
+ if title is None:
+ title = data.title
+ new_panel.window_caption = title
+ new_panel.window_name = data.title
+ event_id = self.parent.popup_panel(new_panel)
+
+ # Set UID to allow us to reference the panel later
+ new_panel.uid = event_id
+ # Ship the plottable to its panel
+ wx.CallAfter(new_panel.plot_data, data)
+ #new_panel.canvas.set_resizing(new_panel.resizing)
+ self.plot_panels[new_panel.group_id] = new_panel
+
+ def create_1d_panel(self, data, group_id):
+ """
+ """
+ # Create a new plot panel if none was available
+ if issubclass(data.__class__, Data1D):
+ from Plotter1D import ModelPanel1D
+ ## get the data representation label of the data to plot
+ ## when even the user select "change scale"
+ xtransform = data.xtransform
+ ytransform = data.ytransform
+ ## create a plotpanel for 1D Data
+ win = MDIFrame(self.parent, None, 'None', (100, 200))
+ new_panel = ModelPanel1D(win, -1, xtransform=xtransform,
+ ytransform=ytransform, style=wx.RAISED_BORDER)
+ win.set_panel(new_panel)
+ win.Show(False)
+ new_panel.frame = win
+ #win.Show(True)
+ return new_panel
+
+ msg = "1D Panel of group ID %s could not be created" % str(group_id)
+ raise ValueError, msg
+
+ def create_2d_panel(self, data, group_id):
+ """
+ """
+ if issubclass(data.__class__, Data2D):
+ ##Create a new plotpanel for 2D data
+ from Plotter2D import ModelPanel2D
+ scale = data.scale
+ win = MDIFrame(self.parent, None, 'None', (200, 150))
+ win.Show(False)
+ new_panel = ModelPanel2D(win, id=-1,
+ data2d=data, scale=scale,
+ style=wx.RAISED_BORDER)
+ win.set_panel(new_panel)
+ new_panel.frame = win
+ return new_panel
+ msg = "2D Panel of group ID %s could not be created" % str(group_id)
+ raise ValueError, msg
+
+ def update_panel(self, data, panel):
+ """
+ update the graph of a given panel
+ """
+ # Check whether we already have a graph with the same units
+ # as the plottable we just received.
+ _, x_unit = data.get_xaxis()
+ _, y_unit = data.get_yaxis()
+ flag_x = (panel.graph.prop["xunit"] is not None) and \
+ (panel.graph.prop["xunit"].strip() != "") and\
+ (x_unit != panel.graph.prop["xunit"]) and False
+ flag_y = (panel.graph.prop["yunit"] is not None) and \
+ (panel.graph.prop["yunit"].strip() != "") and\
+ (y_unit != panel.graph.prop["yunit"]) and False
+ if flag_x and flag_y:
+ msg = "Cannot add %s" % str(data.name)
+ msg += " to panel %s\n" % str(panel.window_caption)
+ msg += "Please edit %s's units, labels" % str(data.name)
+ raise ValueError, msg
+ else:
+ if panel.group_id not in data.list_group_id:
+ data.list_group_id.append(panel.group_id)
+ wx.CallAfter(panel.plot_data, data)
+
+ def delete_panel(self, group_id):
+ """
+ """
+ if group_id in self.plot_panels.keys():
+ panel = self.plot_panels[group_id]
+ uid = panel.uid
+ wx.PostEvent(self.parent,
+ DeletePlotPanelEvent(name=panel.window_caption,
+ caption=panel.window_caption))
+ del self.plot_panels[group_id]
+ if uid in self.parent.plot_panels.keys():
+ del self.parent.plot_panels[uid]
+ panel.frame.Destroy()
+ return True
+
+ return False
+
+ def _on_plot_event(self, event):
+ """
+ A new plottable is being shipped to the plotting plug-in.
+ Check whether we have a panel to put in on, or create
+ a new one
+
+ :param event: EVT_NEW_PLOT event
+
+ """
+ action_check = False
+ if hasattr(event, 'action'):
+ action_string = event.action.lower().strip()
+ if action_string == 'check':
+ action_check = True
+ else:
+ if action_string == 'update':
+ # Update all existing plots of data with this ID
+ for data in event.plots:
+ for panel in self.plot_panels.values():
+ if data.id in panel.plots.keys():
+ plot_exists = True
+ # Pass each panel it's own copy of the data
+ # that's being updated, otherwise things like
+ # colour and line thickness are unintentionally
+ # synced across panels
+ self.update_panel(deepcopy(data), panel)
+ return
+
+ group_id = event.group_id
+ if group_id in self.plot_panels:
+ #remove data from panel
+ if action_string == 'remove':
+ return self.remove_plot(group_id, event.id)
+ if action_string == 'hide':
+ return self.hide_panel(group_id)
+ if action_string == 'delete':
+ panel = self.plot_panels[group_id]
+ uid = panel.uid
+ return self.parent.delete_panel(uid)
+ if action_string == "clear":
+ return self.clear_panel_by_id(group_id)
+
+ if not hasattr(event, 'plot'):
+ return
+ title = None
+ if hasattr(event, 'title'):
+ title = 'Graph' #event.title
+ data = event.plot
+ group_id = data.group_id
+ if group_id in self.plot_panels.keys():
+ if action_check:
+ # Check if the plot already exist. if it does, do nothing.
+ if data.id in self.plot_panels[group_id].plots.keys():
+ return
+ #update a panel graph
+ panel = self.plot_panels[group_id]
+ self.update_panel(data, panel)
+ else:
+ #create a new panel
+ if issubclass(data.__class__, Data1D):
+ new_panel = self.create_1d_panel(data, group_id)
+ else:
+ # Need to make the group_id consistent with 1D thus no if below
+ if len(self.plot_panels.values()) > 0:
+ for p_group_id in self.plot_panels.keys():
+ p_plot = self.plot_panels[p_group_id]
+ if data.id in p_plot.plots.keys():
+ p_plot.plots[data.id] = data
+ self.plot_panels[group_id] = p_plot
+ if group_id != p_group_id:
+ del self.plot_panels[p_group_id]
+ if p_group_id in data.list_group_id:
+ data.list_group_id.remove(p_group_id)
+ if group_id not in data.list_group_id:
+ data.list_group_id.append(group_id)
+ p_plot.group_id = group_id
+ return
+
+ new_panel = self.create_2d_panel(data, group_id)
+ self.create_panel_helper(new_panel, data, group_id, title)
+ if hasattr(event, 'xlim'):
+ new_panel.subplot.set_xlim(event.xlim)
+ if hasattr(event, 'ylim'):
+ new_panel.subplot.set_ylim(event.ylim)
+ return
diff --git a/src/sas/sasgui/guiframe/local_perspectives/plotting/profile_dialog.py b/src/sas/sasgui/guiframe/local_perspectives/plotting/profile_dialog.py
index 43aa9dd..e3a72ec 100644
--- a/src/sas/sasgui/guiframe/local_perspectives/plotting/profile_dialog.py
+++ b/src/sas/sasgui/guiframe/local_perspectives/plotting/profile_dialog.py
@@ -1,316 +1,316 @@
-"""
-SLD Profile Dialog for multifunctional models
-"""
-import wx
-import sys
-from copy import deepcopy
-from sas.sasgui.plottools.plottables import Graph
-from Plotter1D import ModelPanel1D as PlotPanel
-from sas.sasgui.guiframe.dataFitting import Data1D
-from sas.sasgui.guiframe.gui_style import GUIFRAME_ID
-
-DEFAULT_CMAP = None #pylab.cm.jet
-_BOX_WIDTH = 76
-_STATICBOX_WIDTH = 400
-# X Y offset on plot
-_X_OFF = 15
-_Y_OFF = 0.5
-
-#SLD panel size
-if sys.platform.count("win32") > 0:
- _STATICBOX_WIDTH = 563
- PANEL_SIZE = 425
- FONT_VARIANT = 0
-else:
- _STATICBOX_WIDTH = 605
- PANEL_SIZE = 500
- FONT_VARIANT = 1
-
-
-class SLDPanel(wx.Dialog):
- """
- Provides the SLD profile plot panel.
- """
- ## Internal nickname for the window, used by the AUI manager
- window_name = "Scattering Length Density Profile"
- ## Name to appear on the window title bar
- window_caption = "Scattering Length Density Profile"
- ## Flag to tell the AUI manager to put this panel in the center pane
- CENTER_PANE = True
- def __init__(self, parent=None, base=None, data=None, axes=['Radius'],
- id=-1, *args, **kwds):
- kwds["style"] = wx.DEFAULT_DIALOG_STYLE
- kwds["size"] = wx.Size(_STATICBOX_WIDTH, PANEL_SIZE)
- wx.Dialog.__init__(self, parent, id=id, *args, **kwds)
-
- if data != None:
- #Font size
- kwds = []
- self.SetWindowVariant(variant=FONT_VARIANT)
-
- self.SetTitle("Scattering Length Density Profile")
- self.parent = parent
- self._mgr = None
- self.data = data
- self.str = self.data.__str__()
- ## when 2 data have the same id override the 1 st plotted
- self.name = self.data.name
- # Panel for plot
- self.plotpanel = SLDplotpanel(self, axes, -1,
- style=wx.TRANSPARENT_WINDOW)
- self.cmap = DEFAULT_CMAP
- ## Create Artist and bind it
- self.subplot = self.plotpanel.subplot
- # layout
- self._setup_layout()
-
- # plot
- data_plot = deepcopy(self.data)
- data_plot.dy = self._set_dy_data()
- # unit increase to M times for users
- data_plot.y = self._set_y_data()
-
- self.newplot = Data1D(data_plot.x, data_plot.y, data_plot.dy)
- self.newplot.symbol = GUIFRAME_ID.CURVE_SYMBOL_NUM
- self.newplot.dy = None
- self.newplot.name = 'SLD'
- self.newplot.is_data = False
-
- self.newplot.id = self.newplot.name
- self.plotpanel.add_image(self.newplot)
-
- self.plotpanel.resizing = False
- self.plotpanel.canvas.set_resizing(self.plotpanel.resizing)
-
- self.plotpanel.subplot.set_ylim(min(data_plot.y) - _Y_OFF,
- max(data_plot.y) + _Y_OFF)
- self.plotpanel.subplot.set_xlim(min(data_plot.x) - _X_OFF,
- max(data_plot.x) + _X_OFF)
- self.plotpanel.graph.render(self.plotpanel)
- self.plotpanel.canvas.draw()
-
- def _set_dy_data(self):
- """
- make fake dy data
-
- :return dy:
- """
- # set dy as zero
- dy = [0 for y in self.data.y]
- return dy
-
- def _set_y_data(self):
- """
- make y data unit Mega times
-
- :return y_value:
- """
- # changes the unit
- y_value = [yvalue * 1e+006 for yvalue in self.data.y]
-
- return y_value
-
- def _setup_layout(self):
- """
- Set up the layout
- """
- # panel sizer
- sizer = wx.BoxSizer(wx.VERTICAL)
- sizer.Add(self.plotpanel, 0, wx.LEFT | wx.RIGHT, 5)
- sizer.Add(wx.StaticLine(self), 0, wx.ALL | wx.EXPAND, 5)
- sizer.Add((0, 5))
- #-----Button------------1
- button_reset = wx.Button(self, wx.NewId(), "Close")
- button_reset.SetToolTipString("Close...")
- button_reset.Bind(wx.EVT_BUTTON, self._close,
- id=button_reset.GetId())
- sizer.Add(button_reset, 0, wx.LEFT, _STATICBOX_WIDTH - 80)
- sizer.Add((0, 10))
- self.SetSizerAndFit(sizer)
- self.Centre()
- self.Show(True)
- button_reset.SetFocus()
-
- def _close(self, event):
- """
- Close the dialog
- """
- self.Close(True)
-
- def _draw_model(self, event):
- """
- on_close, update the model2d plot
- """
- pass
-
- def get_current_context_menu(self, graph=None):
- """
- When the context menu of a plot is rendered, the
- get_context_menu method will be called to give you a
- chance to add a menu item to the context menu.
- :param graph: the Graph object to which we attach the context menu
-
- :return: a list of menu items with call-back function
- """
- return []
-
- def set_schedule_full_draw(self, panel=None, func=None):
- """
- Set_schedule for full draw
- """
- # Not implemented
- pass
-
- def set_schedule(self, schedule=False):
- """
- Set schedule for redraw
- """
- # Not implemented
- pass
-
- def set_plot_unfocus(self):
- """
- Set_plot unfocus
- """
- # NOt implemented
- pass
-
- def on_change_caption(self, name, old_caption, new_caption):
- """
- """
- self.parent.parent.parent.on_change_caption(name, old_caption, new_caption)
-
- def disable_app_menu(self, panel):
- """
- Disable menu bar
- """
- # Not implemented!
- return
-
- def show_data1d(self, data, name):
- """
- Show data dialog
- """
- self.parent._manager.parent.show_data1d(data, name)
-
-class SLDplotpanel(PlotPanel):
- """
- Panel
- """
- def __init__(self, parent, axes=[], id=-1, color=None, dpi=None, **kwargs):
- """
- """
- PlotPanel.__init__(self, parent, id=id, xtransform='x', ytransform='y',
- color=color, dpi=dpi,
- size=(_STATICBOX_WIDTH, PANEL_SIZE - 100), **kwargs)
-
- # Keep track of the parent Frame
- self.parent = parent
- self.window_name = "Scattering Length Density Profile"
- self.window_caption = self.window_name
- self.prevXtrans = "x"
- self.prevYtrans = "y"
- self.viewModel = "--"
- # Internal list of plottable names (because graph
- # doesn't have a dictionary of handles for the plottables)
- self.plots = {}
- self.graph = Graph()
- self.axes_label = []
- for idx in range(0, len(axes)):
- self.axes_label.append(axes[idx])
- self.xaxis_label = ''
- self.xaxis_unit = ''
- self.yaxis_label = ''
- self.yaxis_unit = ''
- self.resizing = True
- self.xcolor = 'black'
- self.ycolor = 'black'
-
- def add_image(self, plot):
- """
- Add image(Theory1D)
- """
- self.plots[plot.id] = plot
- self.plots[plot.id].is_data = True
- #add plot
- self.graph.add(plot)
- #add axes
- x1_label = self.axes_label[0]
- self.xaxis_label = '\\rm{%s} ' % x1_label
- self.xaxis_unit = 'A'
- self.graph.xaxis(self.xaxis_label, self.xaxis_unit)
- self.yaxis_label = '\\rm{SLD} '
- self.yaxis_unit = '10^{-6}A^{-2}'
- self.graph.yaxis(self.yaxis_label, self.yaxis_unit)
- # For latter scale changes
- self.plots[plot.id].xaxis('\\rm{%s} ' % x1_label, 'A')
- self.plots[plot.id].yaxis('\\rm{SLD} ', '10^{-6}A^{-2}')
-
- def on_set_focus(self, event):
- """
- send to the parenet the current panel on focus
-
- """
- #Not implemented
- pass
-
- def on_kill_focus(self, event):
- """
- reset the panel color
-
- """
- #Not implemented
- pass
-
- def onChangeCaption(self, event):
- """
- Not implemented
- """
- pass
-
- def _onSave(self, evt):
- """
- Save a data set to a text file
-
- :param evt: Menu event
-
- """
- menu = evt.GetEventObject()
- event_id = evt.GetId()
- self.set_selected_from_menu(menu, event_id)
- data = self.plots[self.graph.selected_plottable]
- default_name = data.label
- if default_name.count('.') > 0:
- default_name = default_name.split('.')[0]
- default_name += "_out"
- if self.parent != None:
- # What an ancestor!
- fit_panel = self.parent.parent.parent
- fit_panel._manager.parent.save_data1d(data, default_name)
-
-class ViewerFrame(wx.Frame):
- """
- Add comment
- """
- def __init__(self, parent, id, title):
- """
- comment
- :param parent: parent panel/container
- """
- # Initialize the Frame object
- wx.Frame.__init__(self, parent, id, title, wx.DefaultPosition,
- wx.Size(_STATICBOX_WIDTH, PANEL_SIZE))
- # Panel for 1D plot
- self.plotpanel = SLDplotpanel(self, -1, style=wx.RAISED_BORDER)
-
-class ViewApp(wx.App):
- def OnInit(self):
- frame = ViewerFrame(None, -1, 'testView')
- frame.Show(True)
- self.SetTopWindow(frame)
-
- return True
-
-if __name__ == "__main__":
- app = ViewApp(0)
- app.MainLoop()
+"""
+SLD Profile Dialog for multifunctional models
+"""
+import wx
+import sys
+from copy import deepcopy
+from sas.sasgui.plottools.plottables import Graph
+from Plotter1D import ModelPanel1D as PlotPanel
+from sas.sasgui.guiframe.dataFitting import Data1D
+from sas.sasgui.guiframe.gui_style import GUIFRAME_ID
+
+DEFAULT_CMAP = None #pylab.cm.jet
+_BOX_WIDTH = 76
+_STATICBOX_WIDTH = 400
+# X Y offset on plot
+_X_OFF = 15
+_Y_OFF = 0.5
+
+#SLD panel size
+if sys.platform.count("win32") > 0:
+ _STATICBOX_WIDTH = 563
+ PANEL_SIZE = 425
+ FONT_VARIANT = 0
+else:
+ _STATICBOX_WIDTH = 605
+ PANEL_SIZE = 500
+ FONT_VARIANT = 1
+
+
+class SLDPanel(wx.Dialog):
+ """
+ Provides the SLD profile plot panel.
+ """
+ ## Internal nickname for the window, used by the AUI manager
+ window_name = "Scattering Length Density Profile"
+ ## Name to appear on the window title bar
+ window_caption = "Scattering Length Density Profile"
+ ## Flag to tell the AUI manager to put this panel in the center pane
+ CENTER_PANE = True
+ def __init__(self, parent=None, base=None, data=None, axes=['Radius'],
+ id=-1, *args, **kwds):
+ kwds["style"] = wx.DEFAULT_DIALOG_STYLE
+ kwds["size"] = wx.Size(_STATICBOX_WIDTH, PANEL_SIZE)
+ wx.Dialog.__init__(self, parent, id=id, *args, **kwds)
+
+ if data is not None:
+ #Font size
+ kwds = []
+ self.SetWindowVariant(variant=FONT_VARIANT)
+
+ self.SetTitle("Scattering Length Density Profile")
+ self.parent = parent
+ self._mgr = None
+ self.data = data
+ self.str = self.data.__str__()
+ ## when 2 data have the same id override the 1 st plotted
+ self.name = self.data.name
+ # Panel for plot
+ self.plotpanel = SLDplotpanel(self, axes, -1,
+ style=wx.TRANSPARENT_WINDOW)
+ self.cmap = DEFAULT_CMAP
+ ## Create Artist and bind it
+ self.subplot = self.plotpanel.subplot
+ # layout
+ self._setup_layout()
+
+ # plot
+ data_plot = deepcopy(self.data)
+ data_plot.dy = self._set_dy_data()
+ # unit increase to M times for users
+ data_plot.y = self._set_y_data()
+
+ self.newplot = Data1D(data_plot.x, data_plot.y, data_plot.dy)
+ self.newplot.symbol = GUIFRAME_ID.CURVE_SYMBOL_NUM
+ self.newplot.dy = None
+ self.newplot.name = 'SLD'
+ self.newplot.is_data = False
+
+ self.newplot.id = self.newplot.name
+ self.plotpanel.add_image(self.newplot)
+
+ self.plotpanel.resizing = False
+ self.plotpanel.canvas.set_resizing(self.plotpanel.resizing)
+
+ self.plotpanel.subplot.set_ylim(min(data_plot.y) - _Y_OFF,
+ max(data_plot.y) + _Y_OFF)
+ self.plotpanel.subplot.set_xlim(min(data_plot.x) - _X_OFF,
+ max(data_plot.x) + _X_OFF)
+ self.plotpanel.graph.render(self.plotpanel)
+ self.plotpanel.canvas.draw()
+
+ def _set_dy_data(self):
+ """
+ make fake dy data
+
+ :return dy:
+ """
+ # set dy as zero
+ dy = [0 for y in self.data.y]
+ return dy
+
+ def _set_y_data(self):
+ """
+ make y data unit Mega times
+
+ :return y_value:
+ """
+ # changes the unit
+ y_value = [yvalue * 1e+006 for yvalue in self.data.y]
+
+ return y_value
+
+ def _setup_layout(self):
+ """
+ Set up the layout
+ """
+ # panel sizer
+ sizer = wx.BoxSizer(wx.VERTICAL)
+ sizer.Add(self.plotpanel, 0, wx.LEFT | wx.RIGHT, 5)
+ sizer.Add(wx.StaticLine(self), 0, wx.ALL | wx.EXPAND, 5)
+ sizer.Add((0, 5))
+ #-----Button------------1
+ button_reset = wx.Button(self, wx.NewId(), "Close")
+ button_reset.SetToolTipString("Close...")
+ button_reset.Bind(wx.EVT_BUTTON, self._close,
+ id=button_reset.GetId())
+ sizer.Add(button_reset, 0, wx.LEFT, _STATICBOX_WIDTH - 80)
+ sizer.Add((0, 10))
+ self.SetSizerAndFit(sizer)
+ self.Centre()
+ self.Show(True)
+ button_reset.SetFocus()
+
+ def _close(self, event):
+ """
+ Close the dialog
+ """
+ self.Close(True)
+
+ def _draw_model(self, event):
+ """
+ on_close, update the model2d plot
+ """
+ pass
+
+ def get_current_context_menu(self, graph=None):
+ """
+ When the context menu of a plot is rendered, the
+ get_context_menu method will be called to give you a
+ chance to add a menu item to the context menu.
+ :param graph: the Graph object to which we attach the context menu
+
+ :return: a list of menu items with call-back function
+ """
+ return []
+
+ def set_schedule_full_draw(self, panel=None, func=None):
+ """
+ Set_schedule for full draw
+ """
+ # Not implemented
+ pass
+
+ def set_schedule(self, schedule=False):
+ """
+ Set schedule for redraw
+ """
+ # Not implemented
+ pass
+
+ def set_plot_unfocus(self):
+ """
+ Set_plot unfocus
+ """
+ # NOt implemented
+ pass
+
+ def on_change_caption(self, name, old_caption, new_caption):
+ """
+ """
+ self.parent.parent.parent.on_change_caption(name, old_caption, new_caption)
+
+ def disable_app_menu(self, panel):
+ """
+ Disable menu bar
+ """
+ # Not implemented!
+ return
+
+ def show_data1d(self, data, name):
+ """
+ Show data dialog
+ """
+ self.parent._manager.parent.show_data1d(data, name)
+
+class SLDplotpanel(PlotPanel):
+ """
+ Panel
+ """
+ def __init__(self, parent, axes=[], id=-1, color=None, dpi=None, **kwargs):
+ """
+ """
+ PlotPanel.__init__(self, parent, id=id, xtransform='x', ytransform='y',
+ color=color, dpi=dpi,
+ size=(_STATICBOX_WIDTH, PANEL_SIZE - 100), **kwargs)
+
+ # Keep track of the parent Frame
+ self.parent = parent
+ self.window_name = "Scattering Length Density Profile"
+ self.window_caption = self.window_name
+ self.prevXtrans = "x"
+ self.prevYtrans = "y"
+ self.viewModel = "--"
+ # Internal list of plottable names (because graph
+ # doesn't have a dictionary of handles for the plottables)
+ self.plots = {}
+ self.graph = Graph()
+ self.axes_label = []
+ for idx in range(0, len(axes)):
+ self.axes_label.append(axes[idx])
+ self.xaxis_label = ''
+ self.xaxis_unit = ''
+ self.yaxis_label = ''
+ self.yaxis_unit = ''
+ self.resizing = True
+ self.xcolor = 'black'
+ self.ycolor = 'black'
+
+ def add_image(self, plot):
+ """
+ Add image(Theory1D)
+ """
+ self.plots[plot.id] = plot
+ self.plots[plot.id].is_data = True
+ #add plot
+ self.graph.add(plot)
+ #add axes
+ x1_label = self.axes_label[0]
+ self.xaxis_label = '\\rm{%s} ' % x1_label
+ self.xaxis_unit = 'A'
+ self.graph.xaxis(self.xaxis_label, self.xaxis_unit)
+ self.yaxis_label = '\\rm{SLD} '
+ self.yaxis_unit = '10^{-6}A^{-2}'
+ self.graph.yaxis(self.yaxis_label, self.yaxis_unit)
+ # For latter scale changes
+ self.plots[plot.id].xaxis('\\rm{%s} ' % x1_label, 'A')
+ self.plots[plot.id].yaxis('\\rm{SLD} ', '10^{-6}A^{-2}')
+
+ def on_set_focus(self, event):
+ """
+ send to the parenet the current panel on focus
+
+ """
+ #Not implemented
+ pass
+
+ def on_kill_focus(self, event):
+ """
+ reset the panel color
+
+ """
+ #Not implemented
+ pass
+
+ def onChangeCaption(self, event):
+ """
+ Not implemented
+ """
+ pass
+
+ def _onSave(self, evt):
+ """
+ Save a data set to a text file
+
+ :param evt: Menu event
+
+ """
+ menu = evt.GetEventObject()
+ event_id = evt.GetId()
+ self.set_selected_from_menu(menu, event_id)
+ data = self.plots[self.graph.selected_plottable]
+ default_name = data.label
+ if default_name.count('.') > 0:
+ default_name = default_name.split('.')[0]
+ default_name += "_out"
+ if self.parent is not None:
+ # What an ancestor!
+ fit_panel = self.parent.parent.parent
+ fit_panel._manager.parent.save_data1d(data, default_name)
+
+class ViewerFrame(wx.Frame):
+ """
+ Add comment
+ """
+ def __init__(self, parent, id, title):
+ """
+ comment
+ :param parent: parent panel/container
+ """
+ # Initialize the Frame object
+ wx.Frame.__init__(self, parent, id, title, wx.DefaultPosition,
+ wx.Size(_STATICBOX_WIDTH, PANEL_SIZE))
+ # Panel for 1D plot
+ self.plotpanel = SLDplotpanel(self, -1, style=wx.RAISED_BORDER)
+
+class ViewApp(wx.App):
+ def OnInit(self):
+ frame = ViewerFrame(None, -1, 'testView')
+ frame.Show(True)
+ self.SetTopWindow(frame)
+
+ return True
+
+if __name__ == "__main__":
+ app = ViewApp(0)
+ app.MainLoop()
diff --git a/src/sas/sasgui/guiframe/local_perspectives/plotting/sector_mask.py b/src/sas/sasgui/guiframe/local_perspectives/plotting/sector_mask.py
index f606a64..dfa5708 100644
--- a/src/sas/sasgui/guiframe/local_perspectives/plotting/sector_mask.py
+++ b/src/sas/sasgui/guiframe/local_perspectives/plotting/sector_mask.py
@@ -1,216 +1,216 @@
-"""
- Sector mask interactor
-"""
-import math
-import wx
-#from copy import deepcopy
-from BaseInteractor import _BaseInteractor
-from SectorSlicer import SideInteractor
-from SectorSlicer import LineInteractor
-from sas.sasgui.guiframe.events import SlicerParameterEvent
-
-class SectorMask(_BaseInteractor):
- """
- Draw a sector slicer.Allow to find the data 2D inside of the sector lines
- """
- def __init__(self, base, axes, color='gray', zorder=3, side=False):
- """
- """
- _BaseInteractor.__init__(self, base, axes, color=color)
- ## Class initialization
- self.markers = []
- self.axes = axes
- self.is_inside = side
- ## connect the plot to event
- self.connect = self.base.connect
-
- ## compute qmax limit to reset the graph
- x = math.pow(max(self.base.data.xmax,
- math.fabs(self.base.data.xmin)), 2)
- y = math.pow(max(self.base.data.ymax,
- math.fabs(self.base.data.ymin)), 2)
- self.qmax = math.sqrt(x + y)
- ## Number of points on the plot
- self.nbins = 20
- ## Angle of the middle line
- self.theta2 = math.pi / 3
- ## Absolute value of the Angle between the middle line and any side line
- self.phi = math.pi / 12
-
- ## Middle line
- self.main_line = LineInteractor(self, self.base.subplot, color='blue',
- zorder=zorder, r=self.qmax, theta=self.theta2)
- self.main_line.qmax = self.qmax
- ## Right Side line
- self.right_line = SideInteractor(self, self.base.subplot, color='gray',
- zorder=zorder, r=self.qmax, phi=-1 * self.phi,
- theta2=self.theta2)
- self.right_line.qmax = self.qmax
- ## Left Side line
- self.left_line = SideInteractor(self, self.base.subplot, color='gray',
- zorder=zorder, r=self.qmax, phi=self.phi,
- theta2=self.theta2)
- self.left_line.qmax = self.qmax
- ## draw the sector
- self.update()
- self._post_data()
-
- def clear(self):
- """
- Clear the slicer and all connected events related to this slicer
- """
- self.clear_markers()
- self.main_line.clear()
- self.left_line.clear()
- self.right_line.clear()
- self.base.connect.clearall()
-
- def update(self):
- """
- Respond to changes in the model by recalculating the profiles and
- resetting the widgets.
- """
- # Update locations
- ## Check if the middle line was dragged and
- #update the picture accordingly
- if self.main_line.has_move:
- self.main_line.update()
- self.right_line.update(delta=-self.left_line.phi / 2,
- mline=self.main_line.theta)
- self.left_line.update(delta=self.left_line.phi / 2,
- mline=self.main_line.theta)
- ## Check if the left side has moved and update the slicer accordingly
- if self.left_line.has_move:
- self.main_line.update()
- self.left_line.update(phi=None, delta=None, mline=self.main_line,
- side=True, left=True)
- self.right_line.update(phi=self.left_line.phi, delta=None,
- mline=self.main_line, side=True,
- left=False, right=True)
- ## Check if the right side line has moved and
- #update the slicer accordingly
- if self.right_line.has_move:
- self.main_line.update()
- self.right_line.update(phi=None, delta=None, mline=self.main_line,
- side=True, left=False, right=True)
- self.left_line.update(phi=self.right_line.phi, delta=None,
- mline=self.main_line, side=True, left=False)
- #if self.is_inside != None:
- out = self._post_data()
- return out
-
- def save(self, ev):
- """
- Remember the roughness for this layer and the next so that we
- can restore on Esc.
- """
- self.base.freeze_axes()
- self.main_line.save(ev)
- self.right_line.save(ev)
- self.left_line.save(ev)
-
- def _post_data(self):
- """
- compute sector averaging of data into data1D
- """
- ## get the data to average
- data = self.base.data
- # If we have no data, just return
- if data == None:
- return
- ## Averaging
- from sas.sascalc.dataloader.manipulations import Sectorcut
- phimin = -self.left_line.phi + self.main_line.theta
- phimax = self.left_line.phi + self.main_line.theta
-
- mask = Sectorcut(phi_min=phimin, phi_max=phimax)
- if self.is_inside:
- out = (mask(data) == False)
- else:
- out = (mask(data))
- return out
-
- def moveend(self, ev):
- """
- Called a dragging motion ends.Get slicer event
- """
- self.base.thaw_axes()
- ## Post parameters
- event = SlicerParameterEvent()
- event.type = self.__class__.__name__
- event.params = self.get_params()
- ## Send slicer paramers to plotter2D
- wx.PostEvent(self.base, event)
- self._post_data()
-
- def restore(self):
- """
- Restore the roughness for this layer.
- """
- self.main_line.restore()
- self.left_line.restore()
- self.right_line.restore()
-
- def move(self, x, y, ev):
- """
- Process move to a new position, making sure that the move is allowed.
- """
- pass
-
- def set_cursor(self, x, y):
- pass
-
- def get_params(self):
- """
- Store a copy of values of parameters of the slicer into a dictionary.
-
- :return params: the dictionary created
-
- """
- params = {}
- ## Always make sure that the left and the right line are at phi
- ## angle of the middle line
- if math.fabs(self.left_line.phi) != math.fabs(self.right_line.phi):
- msg = "Phi left and phi right are "
- msg += "different %f, %f" % (self.left_line.phi,
- self.right_line.phi)
- raise ValueError, msg
- params["Phi"] = self.main_line.theta
- params["Delta_Phi"] = math.fabs(self.left_line.phi)
- return params
-
- def set_params(self, params):
- """
- Receive a dictionary and reset the slicer with values contained
- in the values of the dictionary.
-
- :param params: a dictionary containing name of slicer parameters and
- values the user assigned to the slicer.
- """
- main = params["Phi"]
- phi = math.fabs(params["Delta_Phi"])
-
- self.main_line.theta = main
- ## Reset the slicer parameters
- self.main_line.update()
- self.right_line.update(phi=phi, delta=None, mline=self.main_line,
- side=True, right=True)
- self.left_line.update(phi=phi, delta=None,
- mline=self.main_line, side=True)
- ## post the new corresponding data
- self._post_data()
-
- def freeze_axes(self):
- """
- """
- self.base.freeze_axes()
-
- def thaw_axes(self):
- """
- """
- self.base.thaw_axes()
-
- def draw(self):
- """
- """
- self.base.update()
+"""
+ Sector mask interactor
+"""
+import math
+import wx
+#from copy import deepcopy
+from BaseInteractor import _BaseInteractor
+from SectorSlicer import SideInteractor
+from SectorSlicer import LineInteractor
+from sas.sasgui.guiframe.events import SlicerParameterEvent
+
+class SectorMask(_BaseInteractor):
+ """
+ Draw a sector slicer.Allow to find the data 2D inside of the sector lines
+ """
+ def __init__(self, base, axes, color='gray', zorder=3, side=False):
+ """
+ """
+ _BaseInteractor.__init__(self, base, axes, color=color)
+ ## Class initialization
+ self.markers = []
+ self.axes = axes
+ self.is_inside = side
+ ## connect the plot to event
+ self.connect = self.base.connect
+
+ ## compute qmax limit to reset the graph
+ x = math.pow(max(self.base.data.xmax,
+ math.fabs(self.base.data.xmin)), 2)
+ y = math.pow(max(self.base.data.ymax,
+ math.fabs(self.base.data.ymin)), 2)
+ self.qmax = math.sqrt(x + y)
+ ## Number of points on the plot
+ self.nbins = 20
+ ## Angle of the middle line
+ self.theta2 = math.pi / 3
+ ## Absolute value of the Angle between the middle line and any side line
+ self.phi = math.pi / 12
+
+ ## Middle line
+ self.main_line = LineInteractor(self, self.base.subplot, color='blue',
+ zorder=zorder, r=self.qmax, theta=self.theta2)
+ self.main_line.qmax = self.qmax
+ ## Right Side line
+ self.right_line = SideInteractor(self, self.base.subplot, color='gray',
+ zorder=zorder, r=self.qmax, phi=-1 * self.phi,
+ theta2=self.theta2)
+ self.right_line.qmax = self.qmax
+ ## Left Side line
+ self.left_line = SideInteractor(self, self.base.subplot, color='gray',
+ zorder=zorder, r=self.qmax, phi=self.phi,
+ theta2=self.theta2)
+ self.left_line.qmax = self.qmax
+ ## draw the sector
+ self.update()
+ self._post_data()
+
+ def clear(self):
+ """
+ Clear the slicer and all connected events related to this slicer
+ """
+ self.clear_markers()
+ self.main_line.clear()
+ self.left_line.clear()
+ self.right_line.clear()
+ self.base.connect.clearall()
+
+ def update(self):
+ """
+ Respond to changes in the model by recalculating the profiles and
+ resetting the widgets.
+ """
+ # Update locations
+ ## Check if the middle line was dragged and
+ #update the picture accordingly
+ if self.main_line.has_move:
+ self.main_line.update()
+ self.right_line.update(delta=-self.left_line.phi / 2,
+ mline=self.main_line.theta)
+ self.left_line.update(delta=self.left_line.phi / 2,
+ mline=self.main_line.theta)
+ ## Check if the left side has moved and update the slicer accordingly
+ if self.left_line.has_move:
+ self.main_line.update()
+ self.left_line.update(phi=None, delta=None, mline=self.main_line,
+ side=True, left=True)
+ self.right_line.update(phi=self.left_line.phi, delta=None,
+ mline=self.main_line, side=True,
+ left=False, right=True)
+ ## Check if the right side line has moved and
+ #update the slicer accordingly
+ if self.right_line.has_move:
+ self.main_line.update()
+ self.right_line.update(phi=None, delta=None, mline=self.main_line,
+ side=True, left=False, right=True)
+ self.left_line.update(phi=self.right_line.phi, delta=None,
+ mline=self.main_line, side=True, left=False)
+ #if self.is_inside is not None:
+ out = self._post_data()
+ return out
+
+ def save(self, ev):
+ """
+ Remember the roughness for this layer and the next so that we
+ can restore on Esc.
+ """
+ self.base.freeze_axes()
+ self.main_line.save(ev)
+ self.right_line.save(ev)
+ self.left_line.save(ev)
+
+ def _post_data(self):
+ """
+ compute sector averaging of data into data1D
+ """
+ ## get the data to average
+ data = self.base.data
+ # If we have no data, just return
+ if data is None:
+ return
+ ## Averaging
+ from sas.sascalc.dataloader.manipulations import Sectorcut
+ phimin = -self.left_line.phi + self.main_line.theta
+ phimax = self.left_line.phi + self.main_line.theta
+
+ mask = Sectorcut(phi_min=phimin, phi_max=phimax)
+ if self.is_inside:
+ out = (mask(data) == False)
+ else:
+ out = (mask(data))
+ return out
+
+ def moveend(self, ev):
+ """
+ Called a dragging motion ends.Get slicer event
+ """
+ self.base.thaw_axes()
+ ## Post parameters
+ event = SlicerParameterEvent()
+ event.type = self.__class__.__name__
+ event.params = self.get_params()
+ ## Send slicer paramers to plotter2D
+ wx.PostEvent(self.base, event)
+ self._post_data()
+
+ def restore(self):
+ """
+ Restore the roughness for this layer.
+ """
+ self.main_line.restore()
+ self.left_line.restore()
+ self.right_line.restore()
+
+ def move(self, x, y, ev):
+ """
+ Process move to a new position, making sure that the move is allowed.
+ """
+ pass
+
+ def set_cursor(self, x, y):
+ pass
+
+ def get_params(self):
+ """
+ Store a copy of values of parameters of the slicer into a dictionary.
+
+ :return params: the dictionary created
+
+ """
+ params = {}
+ ## Always make sure that the left and the right line are at phi
+ ## angle of the middle line
+ if math.fabs(self.left_line.phi) != math.fabs(self.right_line.phi):
+ msg = "Phi left and phi right are "
+ msg += "different %f, %f" % (self.left_line.phi,
+ self.right_line.phi)
+ raise ValueError, msg
+ params["Phi"] = self.main_line.theta
+ params["Delta_Phi"] = math.fabs(self.left_line.phi)
+ return params
+
+ def set_params(self, params):
+ """
+ Receive a dictionary and reset the slicer with values contained
+ in the values of the dictionary.
+
+ :param params: a dictionary containing name of slicer parameters and
+ values the user assigned to the slicer.
+ """
+ main = params["Phi"]
+ phi = math.fabs(params["Delta_Phi"])
+
+ self.main_line.theta = main
+ ## Reset the slicer parameters
+ self.main_line.update()
+ self.right_line.update(phi=phi, delta=None, mline=self.main_line,
+ side=True, right=True)
+ self.left_line.update(phi=phi, delta=None,
+ mline=self.main_line, side=True)
+ ## post the new corresponding data
+ self._post_data()
+
+ def freeze_axes(self):
+ """
+ """
+ self.base.freeze_axes()
+
+ def thaw_axes(self):
+ """
+ """
+ self.base.thaw_axes()
+
+ def draw(self):
+ """
+ """
+ self.base.update()
diff --git a/src/sas/sasgui/guiframe/media/M_angles_pic.bmp b/src/sas/sasgui/guiframe/media/M_angles_pic.bmp
deleted file mode 100644
index 2c85ec1..0000000
Binary files a/src/sas/sasgui/guiframe/media/M_angles_pic.bmp and /dev/null differ
diff --git a/src/sas/sasgui/guiframe/media/M_angles_pic.png b/src/sas/sasgui/guiframe/media/M_angles_pic.png
new file mode 100644
index 0000000..c6ae531
Binary files /dev/null and b/src/sas/sasgui/guiframe/media/M_angles_pic.png differ
diff --git a/src/sas/sasgui/guiframe/media/data_formats_help.rst b/src/sas/sasgui/guiframe/media/data_formats_help.rst
index 398a138..9c944c0 100644
--- a/src/sas/sasgui/guiframe/media/data_formats_help.rst
+++ b/src/sas/sasgui/guiframe/media/data_formats_help.rst
@@ -1,95 +1,98 @@
-.. data_formats.rst
-
-.. This is a port of the original SasView html help file to ReSTructured text
-.. by S King, ISIS, during SasView CodeCamp-III in Feb 2015.
-.. WG Bouwman, DUT, added during CodeCamp-V in Oct 2016 the SESANS data format
-
-.. _Formats:
-
-Data Formats
-============
-
-SasView reads several different 1D SAS (*I(Q) vs Q*), 2D SAS(*I(Qx,Qy) vs (Qx,Qy)*) and 1D SESANS (*P(z) vs z*) data files. From SasView 4.1 onwards, a :ref:`File_Converter_Tool` allows some legacy formats to be converted into modern formats that SasView will read.
-
-1D SAS Formats
---------------
-
-SasView will read ASCII ('text') files with 2 to 4 columns of numbers in the following order:
-
- *Q, I(Q), ( dI(Q), dQ(Q) )*
-
-where *dQ(Q)* is the instrumental resolution in *Q* and assumed to have originated
-from pinhole geometry.
-
-Numbers can be separated by spaces or commas.
-
-SasView recognises the following file extensions which are not case-sensitive:
-
-* .TXT
-* .ASC
-* .DAT
-* .XML (in canSAS format v1.0 and 1.1)
-
-If using CSV output from, for example, a spreadsheet, ensure that it is not using commas as delimiters for thousands.
-
-The SasView :ref:`File_Converter_Tool` available in SasView 4.1 onwards can be used to convert data sets with separated *I(Q)* and *Q* files (for example, BSL/OTOKO, and some output from FIT2D and other SAXS-oriented software) into either the canSAS SASXML (XML) format or the NeXus NXcanSAS (HDF5) format.
-
-For a description of the CanSAS/SASXML format see:
-http://www.cansas.org/formats/canSAS1d/1.1/doc/
-
-For a description of the ISIS 1D format see:
-http://www.isis.stfc.ac.uk/instruments/loq/software/colette-ascii-file-format-descriptions9808.pdf
-
-For a description of the NXcanSAS format see:
-http://cansas-org.github.io/NXcanSAS/classes/contributed_definitions/NXcanSAS.html
-
-All the above formats are written by the `Mantid Framework <http://www.mantidproject.org/>`_.
-
-For a description of the NIST 1D format see:
-http://danse.chem.utk.edu/trac/wiki/NCNROutput1D_IQ
-
-For a description of the BSL/OTOKO format see:
-http://www.diamond.ac.uk/Beamlines/Soft-Condensed-Matter/small-angle/SAXS-Software/CCP13/BSL.html
-
-.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
-
-2D SAS Formats
---------------
-
-SasView will read ASCII ('text') files in the NIST 2D format (with the extensions .ASC or .DAT) or files in the NeXus NXcanSAS (HDF5) format (with the extension .H5). File extensions are not case-sensitive. Both of these formats are written by the `Mantid Framework <http://www.mantidproject.org/>`_.
-
-Most of the header lines in the NIST 2D format can actually be removed except the last line, and only the first three columns (*Qx, Qy,* and *I(Qx,Qy)*) are actually required.
-
-The SasView :ref:`File_Converter_Tool` available in SasView 4.1 onwards can be used to convert data sets in the 2D BSL/OTOKO format into the NeXus NXcanSAS (HDF5) format.
-
-For a description of the NIST 2D format see:
-http://danse.chem.utk.edu/trac/wiki/NCNROutput1D_2DQxQy
-
-For a description of the NXcanSAS format see:
-http://cansas-org.github.io/NXcanSAS/classes/contributed_definitions/NXcanSAS.html
-
-For a description of the BSL/OTOKO format see: For a description of the BSL/OTOKO format see:
-http://www.diamond.ac.uk/Beamlines/Soft-Condensed-Matter/small-angle/SAXS-Software/CCP13/BSL.html
-
-
-.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
-
-1D SESANS Format
-----------------
-
-SasView version 4.1 onwards will read ASCII ('text') files in a prototype SESANS standard format (with the extensions .SES or .SESANS). The file extensions are not case-sensitive.
-
-The file format has a list of name-value pairs at the top of the file which detail the general experimental parameters necessary for fitting and analyzing data. This list should contain all the information necessary for the file to be 'portable' between users.
-
-Following the header is a 6 column list of instrument experimental variables:
-
-- Spin echo length (z, in Angstroms)
-- Spin echo length error (:math:`\Delta`\ z, in Angstroms) (experimental resolution)
-- Neutron wavelength (:math:`\lambda`, in Angstroms) (essential for ToF instruments)
-- Neutron wavelength error (:math:`\Delta \lambda`, in Angstroms)
-- Normalized polarization (:math:`P/P_0`, unitless)
-- Normalized polarization error (:math:`\Delta(P/P_0)`, unitless) (measurement error)
-
-.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
-
-.. note:: This help document was last changed by Steve King, 07Oct2016
\ No newline at end of file
+.. data_formats.rst
+
+.. This is a port of the original SasView html help file to ReSTructured text
+.. by S King, ISIS, during SasView CodeCamp-III in Feb 2015.
+.. WG Bouwman, DUT, added during CodeCamp-V in Oct 2016 the SESANS data format
+.. WG Bouwman, DUT, updated during CodeCamp-VI in Apr 2017 the SESANS data format
+
+.. _Formats:
+
+Data Formats
+============
+
+SasView reads several different 1D SAS (*I(Q) vs Q*), 2D SAS(*I(Qx,Qy) vs (Qx,Qy)*) and 1D SESANS (*P(z) vs z*) data files. From SasView 4.1 onwards, a :ref:`File_Converter_Tool` allows some legacy formats to be converted into modern formats that SasView will read.
+
+1D SAS Formats
+--------------
+
+SasView will read ASCII ('text') files with 2 to 4 columns of numbers in the following order:
+
+ *Q, I(Q), ( dI(Q), dQ(Q) )*
+
+where *dQ(Q)* is the instrumental resolution in *Q* and assumed to have originated
+from pinhole geometry.
+
+Numbers can be separated by spaces or commas.
+
+SasView recognises the following file extensions which are not case-sensitive:
+
+* .TXT
+* .ASC
+* .DAT
+* .XML (in canSAS format v1.0 and 1.1)
+
+If using CSV output from, for example, a spreadsheet, ensure that it is not using commas as delimiters for thousands.
+
+The SasView :ref:`File_Converter_Tool` available in SasView 4.1 onwards can be used to convert data sets with separated *I(Q)* and *Q* files (for example, BSL/OTOKO, and some output from FIT2D and other SAXS-oriented software) into either the canSAS SASXML (XML) format or the NeXus NXcanSAS (HDF5) format.
+
+For a description of the CanSAS/SASXML format see:
+http://www.cansas.org/formats/canSAS1d/1.1/doc/
+
+For a description of the ISIS 1D format see:
+http://www.isis.stfc.ac.uk/instruments/loq/software/colette-ascii-file-format-descriptions9808.pdf
+
+For a description of the NXcanSAS format see:
+http://cansas-org.github.io/NXcanSAS/classes/contributed_definitions/NXcanSAS.html
+
+All the above formats are written by the `Mantid Framework <http://www.mantidproject.org/>`_.
+
+For a description of the NIST 1D format see:
+http://danse.chem.utk.edu/trac/wiki/NCNROutput1D_IQ
+
+For a description of the BSL/OTOKO format see:
+http://www.diamond.ac.uk/Beamlines/Soft-Condensed-Matter/small-angle/SAXS-Software/CCP13/BSL.html
+
+.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
+
+2D SAS Formats
+--------------
+
+SasView will read ASCII ('text') files in the NIST 2D format (with the extensions .ASC or .DAT) or files in the NeXus NXcanSAS (HDF5) format (with the extension .H5). File extensions are not case-sensitive. Both of these formats are written by the `Mantid Framework <http://www.mantidproject.org/>`_.
+
+Most of the header lines in the NIST 2D format can actually be removed except the last line, and only the first three columns (*Qx, Qy,* and *I(Qx,Qy)*) are actually required.
+
+The SasView :ref:`File_Converter_Tool` available in SasView 4.1 onwards can be used to convert data sets in the 2D BSL/OTOKO format into the NeXus NXcanSAS (HDF5) format.
+
+For a description of the NIST 2D format see:
+http://danse.chem.utk.edu/trac/wiki/NCNROutput1D_2DQxQy
+
+For a description of the NXcanSAS format see:
+http://cansas-org.github.io/NXcanSAS/classes/contributed_definitions/NXcanSAS.html
+
+For a description of the BSL/OTOKO format see: For a description of the BSL/OTOKO format see:
+http://www.diamond.ac.uk/Beamlines/Soft-Condensed-Matter/small-angle/SAXS-Software/CCP13/BSL.html
+
+
+.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
+
+1D SESANS Format
+----------------
+
+SasView version 4.1 onwards will read ASCII ('text') files in a prototype SESANS standard format (with the extensions .SES or .SESANS). The file extensions are not case-sensitive.
+
+The file format has a list of name-value pairs at the top of the file which detail the general experimental parameters necessary for fitting and analyzing data. This list should contain all the information necessary for the file to be 'portable' between users.
+
+Following the header is a 8 (only the first 4 are really needed) column list of instrument experimental variables:
+
+- Spin echo length (z, in Angstroms)
+- depolarization (:math:`log(P/P_0)/(lambda^2 * thickness)`, in Angstrom :sup:`-1` cm :sup:`-1`\ )
+- depolarization error in the same unit) (measurement error)
+- Spin echo length error (:math:`\Delta`\ z, in Angstroms) (experimental resolution)
+- Neutron wavelength (:math:`\lambda`, in Angstroms)
+- Neutron wavelength error (:math:`\Delta \lambda`, in Angstroms)
+- Normalized polarization (:math:`P/P_0`, unitless)
+- Normalized polarization error (:math:`\Delta(P/P_0)`, unitless) (measurement error)
+
+.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
+
+.. note:: This help document was last changed by Wim Bouwman, 05Apr2017
\ No newline at end of file
diff --git a/src/sas/sasgui/guiframe/media/graph_help.rst b/src/sas/sasgui/guiframe/media/graph_help.rst
index 5a13784..1dffe43 100644
--- a/src/sas/sasgui/guiframe/media/graph_help.rst
+++ b/src/sas/sasgui/guiframe/media/graph_help.rst
@@ -8,8 +8,8 @@ Plotting Data/Models
====================
SasView generates three different types of graph window: one that displays *1D data*
-(ie, I(Q) vs Q), one that displays *1D residuals* (ie, the difference between the
-experimental data and the theory at the same Q values), and *2D color maps*.
+(i.e., $I(Q)$ vs $Q$), one that displays *1D residuals* (ie, the difference between the
+experimental data and the theory at the same $Q$ values), and *2D color maps*.
Graph window options
--------------------
@@ -41,7 +41,7 @@ minimised window.
To delete a plot, click the *Close* (x) icon in the top-right corner of the
plot window.
-.. note::
+.. note::
*If a residuals graph (when fitting data) is hidden, it will not show up
after computation.*
@@ -137,7 +137,7 @@ and selecting *Modify Graph Appearance* (for axis labels, grid overlay and
legend position) or *Add Text* to add textual annotations, selecting font, color,
style and size. *Remove Text* will remove the last annotation added. To change
the legend. *Window Title* allows a custom title to be entered instead of Graph
-x.
+x.
Changing scales
^^^^^^^^^^^^^^^
@@ -225,7 +225,7 @@ formats (see :ref:`Formats`).
Making a linear fit
^^^^^^^^^^^^^^^^^^^
-Linear fit performs a simple ( y(x)=ax+b ) linear fit within the plot window.
+Linear fit performs a simple $y(x)=ax+b$ linear fit within the plot window.
In the *Dataset Menu* (see Invoking_the_dataset_menu_), select *Linear Fit*. A
fitting dialog will appear. Set some initial parameters and data limits and
@@ -233,7 +233,7 @@ click *Fit*. The fitted parameter values are displayed and the resulting line
calculated from them is added to the plot.
This option is most useful for performing simple Guinier, XS Guinier, and
-Porod type analyses, for example, to estimate Rg, a rod diameter, or incoherent
+Porod type analyses, for example, to estimate $R_g$, a rod diameter, or incoherent
background level, respectively.
The following figure shows an example of a Guinier analysis using this option
@@ -318,7 +318,7 @@ To remove a 'slicer', bring back the *Dataset menu* and select *Clear Slicer*.
Unmasked circular average
^^^^^^^^^^^^^^^^^^^^^^^^^
-This operation will perform an average in constant Q-rings around the (x,y)
+This operation will perform an average in constant $Q$ rings around the (x,y)
pixel location of the beam center.
Masked circular average
@@ -330,18 +330,18 @@ masked region is excluded.
Sector average [Q View]
^^^^^^^^^^^^^^^^^^^^^^^
-This operation averages in constant Q-arcs.
+This operation averages in constant $Q$ arcs.
-The width of the sector is specified in degrees (+/- |delta|\|phi|\) each side
-of the central angle (|phi|\).
+The width of the sector is specified in degrees ($\pm\delta|\phi|$) each side
+of the central angle $\phi$.
-Annular average [|phi| View]
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Annular average [:math:`\phi`]
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-This operation performs an average between two Q-values centered on (0,0),
+This operation performs an average between two $Q$ values centered on (0,0),
and averaged over a specified number of pixels.
-The data is returned as a function of angle (|phi|\) in degrees with zero
+The data is returned as a function of angle $\phi$ in degrees with zero
degrees at the 3 O'clock position.
Box sum
@@ -355,21 +355,21 @@ the rectangular slicer and the coordinates of the center of the rectangle.
Box Averaging in Qx
^^^^^^^^^^^^^^^^^^^
-This operation computes an average I(Qx) for the region of interest.
+This operation computes an average $I(Q_x)$ for the region of interest.
When editing the slicer parameters, the user can control the length and the
width the rectangular slicer. The averaged output is calculated from constant
-bins with rectangular shape. The resultant Q values are nominal values, that
+bins with rectangular shape. The resultant $Q$ values are nominal values, that
is, the central value of each bin on the x-axis.
Box Averaging in Qy
^^^^^^^^^^^^^^^^^^^
-This operation computes an average I(Qy) for the region of interest.
+This operation computes an average $I(Q_y)$ for the region of interest.
When editing the slicer parameters, the user can control the length and the
width the rectangular slicer. The averaged output is calculated from constant
-bins with rectangular shape. The resultant Q values are nominal values, that
+bins with rectangular shape. The resultant $Q$ values are nominal values, that
is, the central value of each bin on the x-axis.
.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
diff --git a/src/sas/sasgui/guiframe/panel_base.py b/src/sas/sasgui/guiframe/panel_base.py
index 96ea956..815d519 100644
--- a/src/sas/sasgui/guiframe/panel_base.py
+++ b/src/sas/sasgui/guiframe/panel_base.py
@@ -1,454 +1,454 @@
-
-
-################################################################################
-#This software was developed by the University of Tennessee as part of the
-#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
-#project funded by the US National Science Foundation.
-#
-#See the license text in license.txt
-#
-#copyright 2008, University of Tennessee
-################################################################################
-
-
-from sas.sasgui.guiframe.events import PanelOnFocusEvent
-from sas.sasgui.guiframe.events import EVT_NEW_BATCH
-import wx
-
-class PanelBase:
- """
- Defines the API for a panels to work with
- the ViewerFrame toolbar and menu bar
- """
- ## Internal nickname for the window, used by the AUI manager
- #window_name = "default"
- ## Name to appear on the window title bar
- #window_caption = "Welcome panel"
- ## Flag to tell the AUI manager to put this panel in the center pane
- group_id = None
- uid = None
-
- def __init__(self, parent=None):
- """
- Initialize some flag that Viewerframe used
- """
- #panel manager
- self._manager = None
- self.parent = parent
- if self.parent is not None and hasattr(self.parent, '_manager'):
- self._manager = self.parent._manager
- self._print_flag = False
- self._undo_flag = False
- self._redo_flag = False
- self._copy_flag = False
- self._paste_flag = False
- self._preview_flag = False
- self._bookmark_flag = False
- self._zoom_in_flag = False
- self._zoom_out_flag = False
- self._zoom_flag = False
- self._save_flag = False
- self._drag_flag = False
- self._reset_flag = False
- self._has_changed = False
- self.batch_on = False
- if self.parent is not None and hasattr(self.parent, "batch_on"):
- self.batch_on = self.parent.batch_on
-
- self.group_id = None
- self.help_string = ''
-
- def on_batch_selection(self, event):
- """
- :param event: contains parameter enable. When enable is set to True
- the application is in Batch mode otherwise the application is
- in Single mode.
- """
- self.batch_on = event.enable
- def save_project(self, doc=None):
- """
- return an xml node containing state of the panel
- that guiframe can write to file
- """
- return None
-
- def has_changed(self):
- """
- """
- return self._has_changed
-
- def _set_print_flag(self, flag=True):
- """
- The derivative class sets the print flag value to indicate that it can
- be printed
- """
- if flag == self._print_flag:
- self._has_changed = False
- return
- self._has_changed = True
- self._print_flag = flag
- if self._manager is not None and self._manager.parent is not None:
- self._manager.parent.cpanel_on_focus = self
- self._manager.parent.enable_print()
-
- def get_print_flag(self):
- """
- Get the print flag to update appropriately the tool bar
- """
- return self._print_flag
-
- def _set_undo_flag(self, flag=True):
- """
- The derivative class sets the undo flag value to indicate that the
- current action done can be canceled
- """
- if flag == self._undo_flag:
- self._has_changed = False
- return
- self._has_changed = True
- self._undo_flag = flag
- if self._manager is not None and self._manager.parent is not None:
- self._manager.parent.cpanel_on_focus = self
- self._manager.parent.enable_undo()
-
- def get_undo_flag(self):
- """
- Get the undo flag to update appropriately the tool bar
- """
- return self._undo_flag
-
- def _set_redo_flag(self, flag=True):
- """
- The derivative class sets the redo flag value to indicate that the
- action done can be recovered
- """
- if flag == self._redo_flag:
- self._has_changed = False
- return
- self._has_changed = True
- self._redo_flag = flag
- if self._manager is not None and self._manager.parent is not None:
- self._manager.parent.cpanel_on_focus = self
- self._manager.parent.enable_redo()
-
- def get_redo_flag(self):
- """
- Get the redo flag to update appropriately the tool bar
- """
- return self._redo_flag
-
- def _set_copy_flag(self, flag=True):
- """
- The derivative class sets the copy flag value to indicate that the
- action done can be recovered
- """
- if flag == self._copy_flag:
- self._has_changed = False
- return
- self._has_changed = True
- self._copy_flag = flag
- if self._manager is not None and self._manager.parent is not None:
- self._manager.parent.cpanel_on_focus = self
- self._manager.parent.enable_copy()
-
- def get_copy_flag(self):
- """
- Get the copy flag to update appropriately the tool bar
- """
- return self._copy_flag
-
- def _set_paste_flag(self, flag=True):
- """
- The derivative class sets the paste flag value to indicate that the
- action done can be recovered
- """
- if flag == self._paste_flag:
- self._has_changed = False
- return
- self._has_changed = True
- self._paste_flag = flag
- if self._manager is not None and self._manager.parent is not None:
- self._manager.parent.cpanel_on_focus = self
- self._manager.parent.enable_paste()
-
- def get_paste_flag(self):
- """
- Get the copy flag to update appropriately the tool bar
- """
- return self._copy_flag
-
- def _set_zoomed_in_flag(self, flag=True):
- """
- The derivative class sets the zoom in flag value to indicate that it
- can be zoomed in
- """
- if self._zoom_in_flag == flag:
- self._has_changed = False
- return
- self._has_changed = True
- self._zoom_in_flag = flag
- if self._manager is not None and self._manager.parent is not None:
- self._manager.parent.cpanel_on_focus = self
- self._manager.parent.enable_zoom_in()
-
- def get_zoom_in_flag(self):
- """
- Get the zoom in flag to update appropriately the tool bar
- """
- return self._zoom_in_flag
-
- def _set_zoomed_out_flag(self, flag=True):
- """
- The derivative class sets the zoom out flag value to indicate that it
- can be zoomed out
- """
- if self._zoom_out_flag == flag:
- self._has_changed = False
- return
- self._has_changed = True
- self._zoom_out_flag = flag
- if self._manager is not None and self._manager.parent is not None:
- self._manager.parent.panel_on_focus = self
- self._manager.parent.enable_zoom_out()
-
- def get_zoom_out_flag(self):
- """
- Get the zoom out flag to update appropriately the tool bar
- """
- return self._zoom_out_flag
-
- def _set_zoom_flag(self, flag=True):
- """
- The derivative class sets the zoom flag value to indicate that it
- can be zoomed
- """
- if flag == self._zoom_flag:
- self._has_changed = False
- return
- self._has_changed = True
- self._zoom_flag = flag
- if self._manager is not None and self._manager.parent is not None:
- self._manager.parent.cpanel_on_focus = self
- self._manager.parent.enable_zoom()
-
- def get_zoom_flag(self):
- """
- Get the zoom flag to update appropriately the tool bar
- """
- return self._zoom_flag
-
- def _set_bookmark_flag(self, flag=True):
- """
- The derivative class sets the bookmark flag value to indicate that it
- can be bookmarked
- """
- if flag == self._bookmark_flag:
- self._has_changed = False
- return
- self._has_changed = True
- self._bookmark_flag = flag
- if self._manager is not None and self._manager.parent is not None:
- self._manager.parent.cpanel_on_focus = self
- self._manager.parent.enable_bookmark()
-
- def get_bookmark_flag(self):
- """
- Get the bookmark flag to update appropriately the tool bar
- """
- return self._bookmark_flag
-
- def _set_preview_flag(self, flag=True):
- """
- The derivative class sets the preview flag value to indicate that it
- can be previewed
- """
- if flag == self._preview_flag:
- self._has_changed = False
- return
- self._has_changed = True
- self._preview_flag = flag
- if self._manager is not None and self._manager.parent is not None:
- self._manager.parent.cpanel_on_focus = self
- self._manager.parent.enable_preview()
-
- def get_preview_flag(self):
- """
- Get the preview flag to update appropriately the tool bar
- """
- return self._preview_flag
-
- def _set_save_flag(self, flag=True):
- """
- The derivative class sets the drag flag value to indicate that it
- can be saved
- """
- if flag == self._save_flag:
- self._has_changed = False
- return
- self._has_changed = True
- self._save_flag = flag
- if self._manager is not None and self._manager.parent is not None:
- self._manager.parent.cpanel_on_focus = self
- self._manager.parent.enable_save()
-
- def get_save_flag(self):
- """
- Get the save flag to update appropriately the tool bar
- """
- return self._save_flag
-
- def _set_drag_flag(self, flag=True):
- """
- The derivative class sets the drag flag value to indicate that
- dragging motion is possible
- """
- if self._drag_flag == flag:
- self._has_changed = False
- return
- self._has_changed = True
- self._drag_flag = flag
- if self._manager is not None and self._manager.parent is not None:
- self._manager.parent.cpanel_on_focus = self
- self._manager.parent.enable_drag()
-
- def get_drag_flag(self):
- """
- Get the drag flag to update appropriately the tool bar
- """
- return self._drag_flag
-
+
+
+################################################################################
+#This software was developed by the University of Tennessee as part of the
+#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
+#project funded by the US National Science Foundation.
+#
+#See the license text in license.txt
+#
+#copyright 2008, University of Tennessee
+################################################################################
+
+
+from sas.sasgui.guiframe.events import PanelOnFocusEvent
+from sas.sasgui.guiframe.events import EVT_NEW_BATCH
+import wx
+
+class PanelBase:
+ """
+ Defines the API for a panels to work with
+ the ViewerFrame toolbar and menu bar
+ """
+ ## Internal nickname for the window, used by the AUI manager
+ #window_name = "default"
+ ## Name to appear on the window title bar
+ #window_caption = "Welcome panel"
+ ## Flag to tell the AUI manager to put this panel in the center pane
+ group_id = None
+ uid = None
+
+ def __init__(self, parent=None):
+ """
+ Initialize some flag that Viewerframe used
+ """
+ #panel manager
+ self._manager = None
+ self.parent = parent
+ if self.parent is not None and hasattr(self.parent, '_manager'):
+ self._manager = self.parent._manager
+ self._print_flag = False
+ self._undo_flag = False
+ self._redo_flag = False
+ self._copy_flag = False
+ self._paste_flag = False
+ self._preview_flag = False
+ self._bookmark_flag = False
+ self._zoom_in_flag = False
+ self._zoom_out_flag = False
+ self._zoom_flag = False
+ self._save_flag = False
+ self._drag_flag = False
+ self._reset_flag = False
+ self._has_changed = False
+ self.batch_on = False
+ if self.parent is not None and hasattr(self.parent, "batch_on"):
+ self.batch_on = self.parent.batch_on
+
+ self.group_id = None
+ self.help_string = ''
+
+ def on_batch_selection(self, event):
+ """
+ :param event: contains parameter enable. When enable is set to True
+ the application is in Batch mode otherwise the application is
+ in Single mode.
+ """
+ self.batch_on = event.enable
+ def save_project(self, doc=None):
+ """
+ return an xml node containing state of the panel
+ that guiframe can write to file
+ """
+ return None
+
+ def has_changed(self):
+ """
+ """
+ return self._has_changed
+
+ def _set_print_flag(self, flag=True):
+ """
+ The derivative class sets the print flag value to indicate that it can
+ be printed
+ """
+ if flag == self._print_flag:
+ self._has_changed = False
+ return
+ self._has_changed = True
+ self._print_flag = flag
+ if self._manager is not None and self._manager.parent is not None:
+ self._manager.parent.cpanel_on_focus = self
+ self._manager.parent.enable_print()
+
+ def get_print_flag(self):
+ """
+ Get the print flag to update appropriately the tool bar
+ """
+ return self._print_flag
+
+ def _set_undo_flag(self, flag=True):
+ """
+ The derivative class sets the undo flag value to indicate that the
+ current action done can be canceled
+ """
+ if flag == self._undo_flag:
+ self._has_changed = False
+ return
+ self._has_changed = True
+ self._undo_flag = flag
+ if self._manager is not None and self._manager.parent is not None:
+ self._manager.parent.cpanel_on_focus = self
+ self._manager.parent.enable_undo()
+
+ def get_undo_flag(self):
+ """
+ Get the undo flag to update appropriately the tool bar
+ """
+ return self._undo_flag
+
+ def _set_redo_flag(self, flag=True):
+ """
+ The derivative class sets the redo flag value to indicate that the
+ action done can be recovered
+ """
+ if flag == self._redo_flag:
+ self._has_changed = False
+ return
+ self._has_changed = True
+ self._redo_flag = flag
+ if self._manager is not None and self._manager.parent is not None:
+ self._manager.parent.cpanel_on_focus = self
+ self._manager.parent.enable_redo()
+
+ def get_redo_flag(self):
+ """
+ Get the redo flag to update appropriately the tool bar
+ """
+ return self._redo_flag
+
+ def _set_copy_flag(self, flag=True):
+ """
+ The derivative class sets the copy flag value to indicate that the
+ action done can be recovered
+ """
+ if flag == self._copy_flag:
+ self._has_changed = False
+ return
+ self._has_changed = True
+ self._copy_flag = flag
+ if self._manager is not None and self._manager.parent is not None:
+ self._manager.parent.cpanel_on_focus = self
+ self._manager.parent.enable_copy()
+
+ def get_copy_flag(self):
+ """
+ Get the copy flag to update appropriately the tool bar
+ """
+ return self._copy_flag
+
+ def _set_paste_flag(self, flag=True):
+ """
+ The derivative class sets the paste flag value to indicate that the
+ action done can be recovered
+ """
+ if flag == self._paste_flag:
+ self._has_changed = False
+ return
+ self._has_changed = True
+ self._paste_flag = flag
+ if self._manager is not None and self._manager.parent is not None:
+ self._manager.parent.cpanel_on_focus = self
+ self._manager.parent.enable_paste()
+
+ def get_paste_flag(self):
+ """
+ Get the copy flag to update appropriately the tool bar
+ """
+ return self._copy_flag
+
+ def _set_zoomed_in_flag(self, flag=True):
+ """
+ The derivative class sets the zoom in flag value to indicate that it
+ can be zoomed in
+ """
+ if self._zoom_in_flag == flag:
+ self._has_changed = False
+ return
+ self._has_changed = True
+ self._zoom_in_flag = flag
+ if self._manager is not None and self._manager.parent is not None:
+ self._manager.parent.cpanel_on_focus = self
+ self._manager.parent.enable_zoom_in()
+
+ def get_zoom_in_flag(self):
+ """
+ Get the zoom in flag to update appropriately the tool bar
+ """
+ return self._zoom_in_flag
+
+ def _set_zoomed_out_flag(self, flag=True):
+ """
+ The derivative class sets the zoom out flag value to indicate that it
+ can be zoomed out
+ """
+ if self._zoom_out_flag == flag:
+ self._has_changed = False
+ return
+ self._has_changed = True
+ self._zoom_out_flag = flag
+ if self._manager is not None and self._manager.parent is not None:
+ self._manager.parent.panel_on_focus = self
+ self._manager.parent.enable_zoom_out()
+
+ def get_zoom_out_flag(self):
+ """
+ Get the zoom out flag to update appropriately the tool bar
+ """
+ return self._zoom_out_flag
+
+ def _set_zoom_flag(self, flag=True):
+ """
+ The derivative class sets the zoom flag value to indicate that it
+ can be zoomed
+ """
+ if flag == self._zoom_flag:
+ self._has_changed = False
+ return
+ self._has_changed = True
+ self._zoom_flag = flag
+ if self._manager is not None and self._manager.parent is not None:
+ self._manager.parent.cpanel_on_focus = self
+ self._manager.parent.enable_zoom()
+
+ def get_zoom_flag(self):
+ """
+ Get the zoom flag to update appropriately the tool bar
+ """
+ return self._zoom_flag
+
+ def _set_bookmark_flag(self, flag=True):
+ """
+ The derivative class sets the bookmark flag value to indicate that it
+ can be bookmarked
+ """
+ if flag == self._bookmark_flag:
+ self._has_changed = False
+ return
+ self._has_changed = True
+ self._bookmark_flag = flag
+ if self._manager is not None and self._manager.parent is not None:
+ self._manager.parent.cpanel_on_focus = self
+ self._manager.parent.enable_bookmark()
+
+ def get_bookmark_flag(self):
+ """
+ Get the bookmark flag to update appropriately the tool bar
+ """
+ return self._bookmark_flag
+
+ def _set_preview_flag(self, flag=True):
+ """
+ The derivative class sets the preview flag value to indicate that it
+ can be previewed
+ """
+ if flag == self._preview_flag:
+ self._has_changed = False
+ return
+ self._has_changed = True
+ self._preview_flag = flag
+ if self._manager is not None and self._manager.parent is not None:
+ self._manager.parent.cpanel_on_focus = self
+ self._manager.parent.enable_preview()
+
+ def get_preview_flag(self):
+ """
+ Get the preview flag to update appropriately the tool bar
+ """
+ return self._preview_flag
+
+ def _set_save_flag(self, flag=True):
+ """
+ The derivative class sets the drag flag value to indicate that it
+ can be saved
+ """
+ if flag == self._save_flag:
+ self._has_changed = False
+ return
+ self._has_changed = True
+ self._save_flag = flag
+ if self._manager is not None and self._manager.parent is not None:
+ self._manager.parent.cpanel_on_focus = self
+ self._manager.parent.enable_save()
+
+ def get_save_flag(self):
+ """
+ Get the save flag to update appropriately the tool bar
+ """
+ return self._save_flag
+
+ def _set_drag_flag(self, flag=True):
+ """
+ The derivative class sets the drag flag value to indicate that
+ dragging motion is possible
+ """
+ if self._drag_flag == flag:
+ self._has_changed = False
+ return
+ self._has_changed = True
+ self._drag_flag = flag
+ if self._manager is not None and self._manager.parent is not None:
+ self._manager.parent.cpanel_on_focus = self
+ self._manager.parent.enable_drag()
+
+ def get_drag_flag(self):
+ """
+ Get the drag flag to update appropriately the tool bar
+ """
+ return self._drag_flag
+
def _set_analysis(self, flag):
- """
- Set the Analysis Save state flag and informs the manager
- so it refreshes the menu/whole panel
+ """
+ Set the Analysis Save state flag and informs the manager
+ so it refreshes the menu/whole panel
"""
self._set_save_flag(flag)
if self._manager is not None:
- wx.PostEvent(self._manager.parent, PanelOnFocusEvent(panel=self))
-
- def _set_reset_flag(self, flag=True):
- """
- The derivative class sets the reset flag value to indicate that it
- can be reset
- """
- if self._reset_flag == flag:
- self._has_changed = False
- return
- self._has_changed = True
- self._reset_flag = flag
- if self._manager is not None and self._manager.parent is not None:
- self._manager.parent.cpanel_on_focus = self
- self._manager.parent.enable_reset()
-
- def on_tap_focus(self):
- """
- Update menu on clicking the panel tap
- """
- #Implemented only on fitting note book
- pass
-
- def get_reset_flag(self):
- """
- Get the reset flag to update appropriately the tool bar
- """
- return self._reset_flag
-
- def on_reset(self, event):
- """
- The derivative class state is restored
- """
- def on_drag(self, event):
- """
- The derivative class allows dragging motion if implemented
- """
- def on_preview(self, event):
- """
- Display a printable version of the class derivative
- """
- def on_save(self, event):
- """
- The state of the derivative class is restored
- """
- def on_redo(self, event):
- """
- The previous action is restored if possible
- """
- def on_undo(self, event):
- """
- The current action is canceled
- """
- def on_copy(self, event):
- """
- The copy action if possible
- """
- def on_paste(self, event):
- """
- The paste action if possible
- """
- def on_bookmark(self, event):
- """
- The derivative class is on bookmark mode if implemented
- """
- def on_zoom_in(self, event):
- """
- The derivative class is on zoom in mode if implemented
- """
- def on_zoom_out(self, event):
- """
- The derivative class is on zoom out mode if implemented
- """
- def on_zoom(self, event):
- """
- The derivative class is on zoom mode (using pane)
- if zoom mode is implemented
- """
- def on_set_focus(self, event=None):
- """
- The derivative class is on focus if implemented
- """
- if self.parent is not None:
- wx.PostEvent(self.parent, PanelOnFocusEvent(panel=self))
-
- def on_kill_focus(self, event=None):
- """
- The derivative class is on unfocus if implemented
- """
- pass
-
- def get_data(self):
- """
- return list of current data
- """
- return
-
- def get_state(self):
- """
- return the current state
- """
- return
-
- def set_manager(self, manager):
- """
- """
- self._manager = manager
-
- def get_manager(self):
- """
- """
- return self._manager
-
- def get_frame(self):
- """
- """
- if self._manager == None:
- return None
- return self._manager.frame
-
- def on_close(self, event):
- """
- Close event. Hide the whole window.
- """
- parent = self.GetParent()
- if parent is not None:
- parent.Hide()
+ wx.PostEvent(self._manager.parent, PanelOnFocusEvent(panel=self))
+
+ def _set_reset_flag(self, flag=True):
+ """
+ The derivative class sets the reset flag value to indicate that it
+ can be reset
+ """
+ if self._reset_flag == flag:
+ self._has_changed = False
+ return
+ self._has_changed = True
+ self._reset_flag = flag
+ if self._manager is not None and self._manager.parent is not None:
+ self._manager.parent.cpanel_on_focus = self
+ self._manager.parent.enable_reset()
+
+ def on_tap_focus(self):
+ """
+ Update menu on clicking the panel tap
+ """
+ #Implemented only on fitting note book
+ pass
+
+ def get_reset_flag(self):
+ """
+ Get the reset flag to update appropriately the tool bar
+ """
+ return self._reset_flag
+
+ def on_reset(self, event):
+ """
+ The derivative class state is restored
+ """
+ def on_drag(self, event):
+ """
+ The derivative class allows dragging motion if implemented
+ """
+ def on_preview(self, event):
+ """
+ Display a printable version of the class derivative
+ """
+ def on_save(self, event):
+ """
+ The state of the derivative class is restored
+ """
+ def on_redo(self, event):
+ """
+ The previous action is restored if possible
+ """
+ def on_undo(self, event):
+ """
+ The current action is canceled
+ """
+ def on_copy(self, event):
+ """
+ The copy action if possible
+ """
+ def on_paste(self, event):
+ """
+ The paste action if possible
+ """
+ def on_bookmark(self, event):
+ """
+ The derivative class is on bookmark mode if implemented
+ """
+ def on_zoom_in(self, event):
+ """
+ The derivative class is on zoom in mode if implemented
+ """
+ def on_zoom_out(self, event):
+ """
+ The derivative class is on zoom out mode if implemented
+ """
+ def on_zoom(self, event):
+ """
+ The derivative class is on zoom mode (using pane)
+ if zoom mode is implemented
+ """
+ def on_set_focus(self, event=None):
+ """
+ The derivative class is on focus if implemented
+ """
+ if self.parent is not None:
+ wx.PostEvent(self.parent, PanelOnFocusEvent(panel=self))
+
+ def on_kill_focus(self, event=None):
+ """
+ The derivative class is on unfocus if implemented
+ """
+ pass
+
+ def get_data(self):
+ """
+ return list of current data
+ """
+ return
+
+ def get_state(self):
+ """
+ return the current state
+ """
+ return
+
+ def set_manager(self, manager):
+ """
+ """
+ self._manager = manager
+
+ def get_manager(self):
+ """
+ """
+ return self._manager
+
+ def get_frame(self):
+ """
+ """
+ if self._manager is None:
+ return None
+ return self._manager.frame
+
+ def on_close(self, event):
+ """
+ Close event. Hide the whole window.
+ """
+ parent = self.GetParent()
+ if parent is not None:
+ parent.Hide()
\ No newline at end of file
diff --git a/src/sas/sasgui/guiframe/pdfview.py b/src/sas/sasgui/guiframe/pdfview.py
index c1bd133..0fa4db0 100644
--- a/src/sas/sasgui/guiframe/pdfview.py
+++ b/src/sas/sasgui/guiframe/pdfview.py
@@ -1,169 +1,169 @@
-# Read PDF files by embeding the Adobe Acrobat Reader
-# wx.activex module uses class ActiveX control
-
-import wx
-import os
-if wx.Platform == '__WXMSW__':
- from wx.lib.pdfwin import PDFWindow
-
-from wx.lib.scrolledpanel import ScrolledPanel
-STYLE = wx.TE_MULTILINE|wx.TE_READONLY|wx.SUNKEN_BORDER|wx.HSCROLL
-
-class TextPanel(ScrolledPanel):
- """
- Panel that contains the text
- """
- def __init__(self, parent, text=None):
- """
- """
- ScrolledPanel.__init__(self, parent, id=-1)
- self.SetupScrolling()
- self.parent = parent
- self.text = text
- sizer = wx.BoxSizer(wx.VERTICAL)
- self.textctl = wx.TextCtrl(self, -1, size=(-1, -1), style=STYLE)
- self.textctl.SetValue(self.text)
- sizer.Add(self.textctl, proportion=1, flag=wx.EXPAND)
- self.SetSizer(sizer)
- self.SetAutoLayout(True)
- wx.EVT_CLOSE(self.parent, self.OnClose)
-
- def OnClose(self, event):
- """
- Close panel
- """
- self.parent.Destroy()
-
-class TextFrame(wx.Frame):
- """
- Frame for PDF panel
- """
- def __init__(self, parent, id, title, text):
- """
- Init
-
- :param parent: parent panel/container
- :param path: full path of the pdf file
- """
- # Initialize the Frame object
- wx.Frame.__init__(self, parent, id, title,
- wx.DefaultPosition, wx.Size(600, 830))
- # make an instance of the class
- TextPanel(self, text)
- self.SetFocus()
-
-class PDFPanel(wx.Panel):
- """
- Panel that contains the pdf reader
- """
- def __init__(self, parent, path=None):
- """
- """
- wx.Panel.__init__(self, parent, id=-1)
-
- self.parent = parent
- self.path = path
- sizer = wx.BoxSizer(wx.VERTICAL)
- btnSizer = wx.BoxSizer(wx.HORIZONTAL)
-
- self.pdf = PDFWindow(self, style=wx.SUNKEN_BORDER)
-
- sizer.Add(self.pdf, proportion=1, flag=wx.EXPAND)
-
- btn = wx.Button(self, wx.NewId(), "Open PDF File")
- self.Bind(wx.EVT_BUTTON, self.OnOpenButton, btn)
- btnSizer.Add(btn, proportion=1, flag=wx.EXPAND|wx.ALL, border=5)
-
- self.pdf.LoadFile(self.path)
- btn = wx.Button(self, wx.NewId(), "Previous Page")
- self.Bind(wx.EVT_BUTTON, self.OnPrevPageButton, btn)
- btnSizer.Add(btn, proportion=1, flag=wx.EXPAND|wx.ALL, border=5)
-
- btn = wx.Button(self, wx.NewId(), "Next Page")
- self.Bind(wx.EVT_BUTTON, self.OnNextPageButton, btn)
- btnSizer.Add(btn, proportion=1, flag=wx.EXPAND|wx.ALL, border=5)
-
- btn = wx.Button(self, wx.NewId(), "Close")
- self.Bind(wx.EVT_BUTTON, self.OnClose, btn)
- btnSizer.Add(btn, proportion=1, flag=wx.EXPAND|wx.ALL, border=5)
- btnSizer.Add((50,-1), proportion=2, flag=wx.EXPAND)
- sizer.Add(btnSizer, proportion=0, flag=wx.EXPAND)
-
- self.SetSizer(sizer)
- self.SetAutoLayout(True)
- wx.EVT_CLOSE(self.parent, self.OnClose)
-
- def OnOpenButton(self, event):
- """
- Open file button
- """
- # make sure you have PDF files available on your drive
- dlg = wx.FileDialog(self, wildcard="*.pdf")
- dlg.SetDirectory(os.path.dirname(self.path))
- if dlg.ShowModal() == wx.ID_OK:
- wx.BeginBusyCursor()
- file = dlg.GetPath()
- self.pdf.LoadFile(file)
- self.parent.SetTitle(os.path.basename(file.split('.')[0]))
- wx.EndBusyCursor()
- dlg.Destroy()
- # Let Panel know the file changed: Avoiding C++ error
- self.Update()
-
- def OnLoad(self, event=None, path=None):
- """
- Load a pdf file
-
- : Param path: full path to the file
- """
- self.pdf.LoadFile(path)
-
-
- def OnPrevPageButton(self, event):
- """
- Goes to Previous page
- """
- self.pdf.gotoPreviousPage()
-
- def OnNextPageButton(self, event):
- """
- Goes to Next page
- """
- self.pdf.gotoNextPage()
-
- def OnClose(self, event):
- """
- Close panel
- """
- self.parent.Destroy()
-
-class PDFFrame(wx.Frame):
- """
- Frame for PDF panel
- """
- def __init__(self, parent, id, title, path):
- """
- Init
-
- :param parent: parent panel/container
- :param path: full path of the pdf file
- """
- # Initialize the Frame object
- wx.Frame.__init__(self, parent, id, title,
- wx.DefaultPosition, wx.Size(600, 830))
- # make an instance of the class
- PDFPanel(self, path)
-
-class ViewApp(wx.App):
- def OnInit(self):
- path = None
- frame = PDFFrame(None, -1, "PDFView", path=path)
-
- frame.Show(True)
- #self.SetTopWindow(frame)
-
- return True
-
-if __name__ == "__main__":
- app = ViewApp(0)
- app.MainLoop()
+# Read PDF files by embeding the Adobe Acrobat Reader
+# wx.activex module uses class ActiveX control
+
+import wx
+import os
+if wx.Platform == '__WXMSW__':
+ from wx.lib.pdfwin import PDFWindow
+
+from wx.lib.scrolledpanel import ScrolledPanel
+STYLE = wx.TE_MULTILINE|wx.TE_READONLY|wx.SUNKEN_BORDER|wx.HSCROLL
+
+class TextPanel(ScrolledPanel):
+ """
+ Panel that contains the text
+ """
+ def __init__(self, parent, text=None):
+ """
+ """
+ ScrolledPanel.__init__(self, parent, id=-1)
+ self.SetupScrolling()
+ self.parent = parent
+ self.text = text
+ sizer = wx.BoxSizer(wx.VERTICAL)
+ self.textctl = wx.TextCtrl(self, -1, size=(-1, -1), style=STYLE)
+ self.textctl.SetValue(self.text)
+ sizer.Add(self.textctl, proportion=1, flag=wx.EXPAND)
+ self.SetSizer(sizer)
+ self.SetAutoLayout(True)
+ wx.EVT_CLOSE(self.parent, self.OnClose)
+
+ def OnClose(self, event):
+ """
+ Close panel
+ """
+ self.parent.Destroy()
+
+class TextFrame(wx.Frame):
+ """
+ Frame for PDF panel
+ """
+ def __init__(self, parent, id, title, text):
+ """
+ Init
+
+ :param parent: parent panel/container
+ :param path: full path of the pdf file
+ """
+ # Initialize the Frame object
+ wx.Frame.__init__(self, parent, id, title,
+ wx.DefaultPosition, wx.Size(600, 830))
+ # make an instance of the class
+ TextPanel(self, text)
+ self.SetFocus()
+
+class PDFPanel(wx.Panel):
+ """
+ Panel that contains the pdf reader
+ """
+ def __init__(self, parent, path=None):
+ """
+ """
+ wx.Panel.__init__(self, parent, id=-1)
+
+ self.parent = parent
+ self.path = path
+ sizer = wx.BoxSizer(wx.VERTICAL)
+ btnSizer = wx.BoxSizer(wx.HORIZONTAL)
+
+ self.pdf = PDFWindow(self, style=wx.SUNKEN_BORDER)
+
+ sizer.Add(self.pdf, proportion=1, flag=wx.EXPAND)
+
+ btn = wx.Button(self, wx.NewId(), "Open PDF File")
+ self.Bind(wx.EVT_BUTTON, self.OnOpenButton, btn)
+ btnSizer.Add(btn, proportion=1, flag=wx.EXPAND|wx.ALL, border=5)
+
+ self.pdf.LoadFile(self.path)
+ btn = wx.Button(self, wx.NewId(), "Previous Page")
+ self.Bind(wx.EVT_BUTTON, self.OnPrevPageButton, btn)
+ btnSizer.Add(btn, proportion=1, flag=wx.EXPAND|wx.ALL, border=5)
+
+ btn = wx.Button(self, wx.NewId(), "Next Page")
+ self.Bind(wx.EVT_BUTTON, self.OnNextPageButton, btn)
+ btnSizer.Add(btn, proportion=1, flag=wx.EXPAND|wx.ALL, border=5)
+
+ btn = wx.Button(self, wx.NewId(), "Close")
+ self.Bind(wx.EVT_BUTTON, self.OnClose, btn)
+ btnSizer.Add(btn, proportion=1, flag=wx.EXPAND|wx.ALL, border=5)
+ btnSizer.Add((50,-1), proportion=2, flag=wx.EXPAND)
+ sizer.Add(btnSizer, proportion=0, flag=wx.EXPAND)
+
+ self.SetSizer(sizer)
+ self.SetAutoLayout(True)
+ wx.EVT_CLOSE(self.parent, self.OnClose)
+
+ def OnOpenButton(self, event):
+ """
+ Open file button
+ """
+ # make sure you have PDF files available on your drive
+ dlg = wx.FileDialog(self, wildcard="*.pdf")
+ dlg.SetDirectory(os.path.dirname(self.path))
+ if dlg.ShowModal() == wx.ID_OK:
+ wx.BeginBusyCursor()
+ file = dlg.GetPath()
+ self.pdf.LoadFile(file)
+ self.parent.SetTitle(os.path.basename(file.split('.')[0]))
+ wx.EndBusyCursor()
+ dlg.Destroy()
+ # Let Panel know the file changed: Avoiding C++ error
+ self.Update()
+
+ def OnLoad(self, event=None, path=None):
+ """
+ Load a pdf file
+
+ : Param path: full path to the file
+ """
+ self.pdf.LoadFile(path)
+
+
+ def OnPrevPageButton(self, event):
+ """
+ Goes to Previous page
+ """
+ self.pdf.gotoPreviousPage()
+
+ def OnNextPageButton(self, event):
+ """
+ Goes to Next page
+ """
+ self.pdf.gotoNextPage()
+
+ def OnClose(self, event):
+ """
+ Close panel
+ """
+ self.parent.Destroy()
+
+class PDFFrame(wx.Frame):
+ """
+ Frame for PDF panel
+ """
+ def __init__(self, parent, id, title, path):
+ """
+ Init
+
+ :param parent: parent panel/container
+ :param path: full path of the pdf file
+ """
+ # Initialize the Frame object
+ wx.Frame.__init__(self, parent, id, title,
+ wx.DefaultPosition, wx.Size(600, 830))
+ # make an instance of the class
+ PDFPanel(self, path)
+
+class ViewApp(wx.App):
+ def OnInit(self):
+ path = None
+ frame = PDFFrame(None, -1, "PDFView", path=path)
+
+ frame.Show(True)
+ #self.SetTopWindow(frame)
+
+ return True
+
+if __name__ == "__main__":
+ app = ViewApp(0)
+ app.MainLoop()
diff --git a/src/sas/sasgui/guiframe/plugin_base.py b/src/sas/sasgui/guiframe/plugin_base.py
index ffa8bc7..32408b7 100644
--- a/src/sas/sasgui/guiframe/plugin_base.py
+++ b/src/sas/sasgui/guiframe/plugin_base.py
@@ -160,7 +160,7 @@ class PluginBase(object):
"""
Sets default frame config
"""
- if self.frame != None:
+ if self.frame is not None:
self.frame.EnableCloseButton(False)
self.frame.Show(False)
@@ -229,14 +229,14 @@ class PluginBase(object):
"""
old_frame = None
old_persp = self.parent.get_current_perspective()
- if old_persp != None:
+ if old_persp is not None:
old_frame = old_persp.get_frame()
self.parent.check_multimode(self)
self.parent.set_current_perspective(self)
self.parent.set_perspective(self.perspective)
- if self.frame != None:
- if old_frame != None:
+ if self.frame is not None:
+ if old_frame is not None:
pos_x, pos_y = old_frame.GetPositionTuple()
self.frame.SetPosition((pos_x, pos_y))
if not self.frame.IsShown():
diff --git a/src/sas/sasgui/guiframe/proxy.py b/src/sas/sasgui/guiframe/proxy.py
index f6bfb7c..54ec7e7 100644
--- a/src/sas/sasgui/guiframe/proxy.py
+++ b/src/sas/sasgui/guiframe/proxy.py
@@ -1,11 +1,16 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
+from __future__ import print_function
+
import urllib2
import sys
import json
import logging
import re
+
+logger = logging.getLogger(__name__)
+
'''
HTTP Proxy parser and Connection
@@ -70,13 +75,13 @@ class Connection(object):
'''
proxy_url_list = []
for this_pac_url in pac_urls_list:
- logging.debug('Trying pac file (%s)...' % this_pac_url)
+ logger.debug('Trying pac file (%s)...' % this_pac_url)
try:
response = urllib2.urlopen(
this_pac_url, timeout=self.timeout)
- logging.debug('Succeeded (%s)...' % this_pac_url)
+ logger.debug('Succeeded (%s)...' % this_pac_url)
except Exception:
- logging.debug('Failled (%s)...' % this_pac_url)
+ logger.debug('Failled (%s)...' % this_pac_url)
continue
pacStr = response.read()
possProxies = re.findall(
@@ -119,32 +124,32 @@ class Connection(object):
req = urllib2.Request(self.url)
response = None
try:
- logging.debug("Trying Direct connection to %s..."%self.url)
+ logger.debug("Trying Direct connection to %s..."%self.url)
response = urllib2.urlopen(req, timeout=self.timeout)
except Exception, e:
- logging.debug("Failed!")
- logging.debug(e)
+ logger.debug("Failed!")
+ logger.debug(e)
try:
- logging.debug("Trying to use system proxy if it exists...")
+ logger.debug("Trying to use system proxy if it exists...")
self._set_proxy()
response = urllib2.urlopen(req, timeout=self.timeout)
except Exception, e:
- logging.debug("Failed!")
- logging.debug(e)
+ logger.debug("Failed!")
+ logger.debug(e)
pac_urls = self._get_addresses_of_proxy_pac()
proxy_urls = self._parse_proxy_pac(pac_urls)
for proxy in proxy_urls:
try:
- logging.debug("Trying to use the proxy %s found in proxy.pac configuration"%proxy)
+ logger.debug("Trying to use the proxy %s found in proxy.pac configuration"%proxy)
self._set_proxy(proxy)
response = urllib2.urlopen(req, timeout=self.timeout)
except Exception, e:
- logging.debug("Failed!")
- logging.debug(e)
+ logger.debug("Failed!")
+ logger.debug(e)
if response is not None:
- logging.debug("The connection to %s was successful."%self.url)
+ logger.debug("The connection to %s was successful."%self.url)
else:
- logging.warning("Connection to %s failed..."%self.url)
+ logger.warning("Connection to %s failed..."%self.url)
return response
@@ -153,6 +158,6 @@ if __name__ == "__main__":
c = Connection()
response = c.connect()
if response is not None:
- print 50 * '-'
+ print(50 * '-')
content = json.loads(response.read().strip())
pprint(content)
diff --git a/src/sas/sasgui/guiframe/report_dialog.py b/src/sas/sasgui/guiframe/report_dialog.py
index 0fc747a..56e6d4f 100644
--- a/src/sas/sasgui/guiframe/report_dialog.py
+++ b/src/sas/sasgui/guiframe/report_dialog.py
@@ -7,10 +7,12 @@ import logging
import sys
import wx.html as html
+logger = logging.getLogger(__name__)
+
ISPDF = False
if sys.platform == "win32":
_STATICBOX_WIDTH = 450
- PANEL_WIDTH = 500
+ PANEL_WIDTH = 500
PANEL_HEIGHT = 700
FONT_VARIANT = 0
ISPDF = True
@@ -23,11 +25,11 @@ else:
ISPDF = True
class BaseReportDialog(wx.Dialog):
-
+
def __init__(self, report_list, *args, **kwds):
"""
Initialization. The parameters added to Dialog are:
-
+
:param report_list: list of html_str, text_str, image for report
"""
kwds["style"] = wx.RESIZE_BORDER|wx.DEFAULT_DIALOG_STYLE
@@ -45,9 +47,8 @@ class BaseReportDialog(wx.Dialog):
# report string
self.report_list = report_list
# wild card
- # pdf supporting only on MAC
- if self.is_pdf:
- self.wild_card = ' PDF files (*.pdf)|*.pdf|'
+ if self.is_pdf: # pdf writer is available
+ self.wild_card = 'PDF files (*.pdf)|*.pdf|'
self.index_offset = 0
else:
self.wild_card = ''
@@ -60,7 +61,7 @@ class BaseReportDialog(wx.Dialog):
Set up layout
"""
hbox = wx.BoxSizer(wx.HORIZONTAL)
-
+
# buttons
button_close = wx.Button(self, wx.ID_OK, "Close")
button_close.SetToolTipString("Close this report window.")
@@ -72,19 +73,19 @@ class BaseReportDialog(wx.Dialog):
button_print.Bind(wx.EVT_BUTTON, self.onPrint,
id=button_print.GetId())
hbox.Add(button_print)
-
+
button_save = wx.Button(self, wx.NewId(), "Save")
button_save.SetToolTipString("Save this report.")
button_save.Bind(wx.EVT_BUTTON, self.onSave, id=button_save.GetId())
hbox.Add(button_save)
-
+
# panel for report page
vbox = wx.BoxSizer(wx.VERTICAL)
# html window
self.hwindow = html.HtmlWindow(self, style=wx.BORDER)
# set the html page with the report string
self.hwindow.SetPage(self.report_html)
-
+
# add panels to boxsizers
vbox.Add(hbox)
vbox.Add(self.hwindow, 1, wx.EXPAND|wx.ALL,0)
@@ -100,7 +101,7 @@ class BaseReportDialog(wx.Dialog):
"""
previewh = html.HtmlEasyPrinting(name="Printing", parentWindow=self)
previewh.PreviewText(self.report_html)
-
+
def onPrint(self, event=None):
"""
Print
@@ -115,11 +116,11 @@ class BaseReportDialog(wx.Dialog):
: event: Close button event
"""
self.Close()
-
+
def HTML2PDF(self, data, filename):
"""
Create a PDF file from html source string.
- Returns True is the file creation was successful.
+ Returns True is the file creation was successful.
: data: html string
: filename: name of file to be saved
"""
@@ -133,7 +134,6 @@ class BaseReportDialog(wx.Dialog):
resultFile.close()
self.Update()
return pisaStatus.err
- except:
- logging.error("Error creating pdf: %s" % sys.exc_value)
+ except Exception:
+ logger.error("Error creating pdf: %s" % sys.exc_value)
return False
-
diff --git a/src/sas/sasgui/guiframe/startup_configuration.py b/src/sas/sasgui/guiframe/startup_configuration.py
index 76d6f29..abd5c34 100644
--- a/src/sas/sasgui/guiframe/startup_configuration.py
+++ b/src/sas/sasgui/guiframe/startup_configuration.py
@@ -1,216 +1,204 @@
-
-################################################################################
-#This software was developed by the University of Tennessee as part of the
-#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
-#project funded by the US National Science Foundation.
-#
-#See the license text in license.txt
-#
-#copyright 2009, University of Tennessee
-################################################################################
-import wx
-import os
-import sys
-import copy
-#import sas.sasgui.guiframe.gui_manager as gui
-from sas.sasgui.guiframe.events import StatusEvent
-from sas.sasgui.guiframe.gui_style import GUIFRAME
-from sas.sasgui.guiframe import gui_manager as CURRENT
-from sas.sasgui.guiframe.customdir import SetupCustom
-# default configuration
-DEFAULT_STRINGS = {'GUIFRAME_WIDTH':-1,
- 'GUIFRAME_HEIGHT':-1,
- 'CONTROL_WIDTH':-1,
- 'CONTROL_HEIGHT':-1,
- 'PLOPANEL_WIDTH':-1,
- 'DATAPANEL_WIDTH':-1,
- 'DATALOADER_SHOW':True,
- 'TOOLBAR_SHOW':True,
- 'FIXED_PANEL':True,
- 'WELCOME_PANEL_SHOW':False,
- 'CLEANUP_PLOT':False,
- 'DEFAULT_PERSPECTIVE':'Fitting',
- 'DEFAULT_OPEN_FOLDER': None,
- 'SAS_OPENCL': None}
-try:
- CURRENT_STRINGS = {'GUIFRAME_WIDTH':CURRENT.GUIFRAME_WIDTH,
- 'GUIFRAME_HEIGHT':CURRENT.GUIFRAME_HEIGHT,
- 'CONTROL_WIDTH':CURRENT.CONTROL_WIDTH,
- 'CONTROL_HEIGHT':CURRENT.CONTROL_HEIGHT,
- 'PLOPANEL_WIDTH':CURRENT.PLOPANEL_WIDTH,
- 'DATAPANEL_WIDTH':CURRENT.DATAPANEL_WIDTH,
- 'DATALOADER_SHOW':CURRENT.DATALOADER_SHOW,
- 'TOOLBAR_SHOW':CURRENT.TOOLBAR_SHOW,
- 'FIXED_PANEL':CURRENT.FIXED_PANEL,
- 'WELCOME_PANEL_SHOW':CURRENT.WELCOME_PANEL_SHOW,
- 'CLEANUP_PLOT':CURRENT.CLEANUP_PLOT,
- 'DEFAULT_PERSPECTIVE':CURRENT.DEFAULT_PERSPECTIVE,
- 'DEFAULT_OPEN_FOLDER':CURRENT.DEFAULT_OPEN_FOLDER,
- 'SAS_OPENCL': None}
-except:
- CURRENT_STRINGS = DEFAULT_STRINGS
-FONT_VARIANT = 0
-PANEL_WIDTH = 285
-PANEL_HEIGHT = 215
-
-"""
-Dialog to set Appication startup configuration
-"""
-class StartupConfiguration(wx.Dialog):
- """
- Dialog for Startup Configuration
- """
- def __init__(self, parent, gui, id=-1, title="Startup Setting"):
- wx.Dialog.__init__(self, parent, id, title,
- size=(PANEL_WIDTH, PANEL_HEIGHT))
- # parent
- self.parent = parent
- self.path = SetupCustom().find_dir()
- self._gui = gui
- # font size
- self.SetWindowVariant(variant=FONT_VARIANT)
- self.current_string = copy.deepcopy(CURRENT_STRINGS)
- self.return_string = copy.deepcopy(DEFAULT_STRINGS)
- # build layout
- vbox = wx.BoxSizer(wx.VERTICAL)
- title_text = wx.StaticText(self, id=wx.NewId(), label='Set interface configuration')
-
- default_bt = wx.RadioButton(self, -1, 'Default View', (15, 30),
- style=wx.RB_GROUP)
- default_bt.Bind(wx.EVT_RADIOBUTTON, self.OnDefault)
- default_bt.SetValue(True)
- current_bt = wx.RadioButton(self, -1, 'Current View', (15, 55))
- current_bt.SetValue(False)
- current_bt.Bind(wx.EVT_RADIOBUTTON, self.OnCurrent)
- msg = "\nThis new configuration will take effect when\n"
- msg += "running this application next time."
- note_txt = wx.StaticText(self, -1, msg, (15, 75))
- note_txt.SetForegroundColour("black")
-
- hbox = wx.BoxSizer(wx.HORIZONTAL)
- okButton = wx.Button(self, wx.ID_OK, 'Set', size=(70, 25))
- closeButton = wx.Button(self,wx.ID_CANCEL, 'Cancel', size=(70, 25))
- hbox.Add(closeButton, 1, wx.RIGHT, 5)
- hbox.Add(okButton, 1, wx.RIGHT, 5)
-
- vbox.Add(title_text, 0, wx.ALIGN_CENTER | wx.TOP | wx.BOTTOM, 10)
- vbox.Add(default_bt, 0, wx.LEFT, 20)
- vbox.Add(current_bt, 0, wx.LEFT, 20)
- vbox.Add(note_txt, 0, wx.ALIGN_CENTER | wx.TOP | wx.BOTTOM, 10)
- vbox.Add(hbox, 0, wx.ALIGN_CENTER | wx.TOP | wx.BOTTOM, 10)
-
- self.SetSizer(vbox)
-
-
- def OnDefault(self, event=None):
- """
- Set to default
- """
- event.Skip()
- # event object and selection
- self.return_string = copy.deepcopy(DEFAULT_STRINGS)
- return self.return_string
-
- def OnCurrent(self, event=None):
- """
- Set to curent setup
- """
- event.Skip()
- if self.parent.IsMaximized():
- gui_pw, gui_ph = (0, 0)
- else:
- gui_pw, gui_ph = self.parent.get_window_size()
- self.current_string['GUIFRAME_WIDTH'] = gui_pw
- self.current_string['GUIFRAME_HEIGHT'] = gui_ph
- try:
- p_size = None
- for panel in self.parent.plot_panels.values():
- #p_panel = self.parent._mgr.GetPane(panel.window_name)
- width, _ = panel.frame.GetSizeTuple()
- if panel.frame.IsShown():
- if p_size == None or width > p_size:
- p_size = width
- if p_size == None:
- p_size = CURRENT_STRINGS['PLOPANEL_WIDTH']
- self.current_string['PLOPANEL_WIDTH'] = p_size
-
- try:
- control_frame = self.parent.get_current_perspective().frame
- control_w, control_h = control_frame.GetSizeTuple()
- self.current_string['CONTROL_WIDTH'] = control_w
- self.current_string['CONTROL_HEIGHT'] = control_h
- except:
- self.current_string['CONTROL_WIDTH'] = -1
- self.current_string['CONTROL_HEIGHT'] = -1
-
- data_pw, _ = self.parent.panels["data_panel"].frame.GetSizeTuple()
- if data_pw == None:
- data_pw = CURRENT_STRINGS['DATAPANEL_WIDTH']
- self.current_string['DATAPANEL_WIDTH'] = data_pw
-
- #label = self.parent._data_panel_menu.GetText()
- label = self.parent.panels['data_panel'].frame.IsShown()
- if label:# == 'Hide Data Explorer':
- self.current_string['DATALOADER_SHOW'] = True
- else:
- self.current_string['DATALOADER_SHOW'] = False
-
- if self.parent._toolbar.IsShown():
- self.current_string['TOOLBAR_SHOW'] = True
- else:
- self.current_string['TOOLBAR_SHOW'] = False
-
- style = self._gui & GUIFRAME.FLOATING_PANEL
- if style == GUIFRAME.FLOATING_PANEL:
- self.current_string['FIXED_PANEL'] = False
- else:
- self.current_string['FIXED_PANEL'] = True
-
- if self.parent.panels['default'].frame.IsShown():
- self.current_string['WELCOME_PANEL_SHOW'] = True
- else:
- self.current_string['WELCOME_PANEL_SHOW'] = False
- self.current_string['CLEANUP_PLOT'] = \
- self.parent.cleanup_plots
- perspective = self.parent.get_current_perspective()
- self.current_string['DEFAULT_PERSPECTIVE'] =\
- str(perspective.sub_menu)
- location = ''
- temp = self.parent._default_save_location.split("\\")
- for strings in temp:
- location += (strings + "/")
- self.current_string['DEFAULT_OPEN_FOLDER'] = location
- #self.parent._default_save_location.ascii_letters
-
- except:
- raise
- # event object and selection
- self.return_string = self.current_string
- return self.return_string
-
- def write_custom_config(self):
- """
- Write custom configuration
- """
- fname = os.path.join(self.path, 'custom_config.py')
- self.write_string(fname, self.return_string)
-
- def write_string(self, fname, strings):
- """
- Write and Save file
- """
-
- try:
- out_f = open(fname,'w')
- except :
- raise #RuntimeError, "Error: Can not change the configuration..."
- out_f.write("#Application appearance custom configuration\n" )
- for key, item in strings.iteritems():
- if (key == 'DEFAULT_PERSPECTIVE') or \
- (key == 'DEFAULT_OPEN_FOLDER' and item != None):
- out_f.write("%s = \"%s\"\n" % (key,str(item)))
- else:
- out_f.write("%s = %s\n" % (key,str(item)))
-
- out_f.close()
-
\ No newline at end of file
+################################################################################
+#This software was developed by the University of Tennessee as part of the
+#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
+#project funded by the US National Science Foundation.
+#
+#See the license text in license.txt
+#
+#copyright 2009, University of Tennessee
+################################################################################
+import os
+import copy
+
+import wx
+
+from sas import make_custom_config_path
+from sas.sasgui.guiframe.events import StatusEvent
+from sas.sasgui.guiframe.gui_style import GUIFRAME
+from sas.sasgui.guiframe import gui_manager as CURRENT
+
+
+# default configuration
+DEFAULT_STRINGS = {'GUIFRAME_WIDTH':-1,
+ 'GUIFRAME_HEIGHT':-1,
+ 'CONTROL_WIDTH':-1,
+ 'CONTROL_HEIGHT':-1,
+ 'PLOPANEL_WIDTH':-1,
+ 'DATAPANEL_WIDTH':-1,
+ 'DATALOADER_SHOW':True,
+ 'TOOLBAR_SHOW':True,
+ 'FIXED_PANEL':True,
+ 'WELCOME_PANEL_SHOW':False,
+ 'CLEANUP_PLOT':False,
+ 'DEFAULT_PERSPECTIVE':'Fitting',
+ 'DEFAULT_OPEN_FOLDER': None,
+ 'SAS_OPENCL': None}
+try:
+ CURRENT_STRINGS = {'GUIFRAME_WIDTH':CURRENT.GUIFRAME_WIDTH,
+ 'GUIFRAME_HEIGHT':CURRENT.GUIFRAME_HEIGHT,
+ 'CONTROL_WIDTH':CURRENT.CONTROL_WIDTH,
+ 'CONTROL_HEIGHT':CURRENT.CONTROL_HEIGHT,
+ 'PLOPANEL_WIDTH':CURRENT.PLOPANEL_WIDTH,
+ 'DATAPANEL_WIDTH':CURRENT.DATAPANEL_WIDTH,
+ 'DATALOADER_SHOW':CURRENT.DATALOADER_SHOW,
+ 'TOOLBAR_SHOW':CURRENT.TOOLBAR_SHOW,
+ 'FIXED_PANEL':CURRENT.FIXED_PANEL,
+ 'WELCOME_PANEL_SHOW':CURRENT.WELCOME_PANEL_SHOW,
+ 'CLEANUP_PLOT':CURRENT.CLEANUP_PLOT,
+ 'DEFAULT_PERSPECTIVE':CURRENT.DEFAULT_PERSPECTIVE,
+ 'DEFAULT_OPEN_FOLDER':CURRENT.DEFAULT_OPEN_FOLDER,
+ 'SAS_OPENCL': None}
+except:
+ CURRENT_STRINGS = DEFAULT_STRINGS
+FONT_VARIANT = 0
+PANEL_WIDTH = 285
+PANEL_HEIGHT = 215
+
+"""
+Dialog to set Appication startup configuration
+"""
+class StartupConfiguration(wx.Dialog):
+ """
+ Dialog for Startup Configuration
+ """
+ def __init__(self, parent, gui, id=-1, title="Startup Setting"):
+ wx.Dialog.__init__(self, parent, id, title,
+ size=(PANEL_WIDTH, PANEL_HEIGHT))
+ # parent
+ self.parent = parent
+ self._gui = gui
+ # font size
+ self.SetWindowVariant(variant=FONT_VARIANT)
+ self.current_string = copy.deepcopy(CURRENT_STRINGS)
+ self.return_string = copy.deepcopy(DEFAULT_STRINGS)
+ # build layout
+ vbox = wx.BoxSizer(wx.VERTICAL)
+ title_text = wx.StaticText(self, id=wx.NewId(), label='Set interface configuration')
+
+ default_bt = wx.RadioButton(self, -1, 'Default View', (15, 30),
+ style=wx.RB_GROUP)
+ default_bt.Bind(wx.EVT_RADIOBUTTON, self.OnDefault)
+ default_bt.SetValue(True)
+ current_bt = wx.RadioButton(self, -1, 'Current View', (15, 55))
+ current_bt.SetValue(False)
+ current_bt.Bind(wx.EVT_RADIOBUTTON, self.OnCurrent)
+ msg = "\nThis new configuration will take effect when\n"
+ msg += "running this application next time."
+ note_txt = wx.StaticText(self, -1, msg, (15, 75))
+ note_txt.SetForegroundColour("black")
+
+ hbox = wx.BoxSizer(wx.HORIZONTAL)
+ okButton = wx.Button(self, wx.ID_OK, 'Set', size=(70, 25))
+ closeButton = wx.Button(self, wx.ID_CANCEL, 'Cancel', size=(70, 25))
+ hbox.Add(closeButton, 1, wx.RIGHT, 5)
+ hbox.Add(okButton, 1, wx.RIGHT, 5)
+
+ vbox.Add(title_text, 0, wx.ALIGN_CENTER | wx.TOP | wx.BOTTOM, 10)
+ vbox.Add(default_bt, 0, wx.LEFT, 20)
+ vbox.Add(current_bt, 0, wx.LEFT, 20)
+ vbox.Add(note_txt, 0, wx.ALIGN_CENTER | wx.TOP | wx.BOTTOM, 10)
+ vbox.Add(hbox, 0, wx.ALIGN_CENTER | wx.TOP | wx.BOTTOM, 10)
+
+ self.SetSizer(vbox)
+
+
+ def OnDefault(self, event=None):
+ """
+ Set to default
+ """
+ event.Skip()
+ # event object and selection
+ self.return_string = copy.deepcopy(DEFAULT_STRINGS)
+ return self.return_string
+
+ def OnCurrent(self, event=None):
+ """
+ Set to curent setup
+ """
+ event.Skip()
+ if self.parent.IsMaximized():
+ gui_pw, gui_ph = (0, 0)
+ else:
+ gui_pw, gui_ph = self.parent.get_window_size()
+ self.current_string['GUIFRAME_WIDTH'] = gui_pw
+ self.current_string['GUIFRAME_HEIGHT'] = gui_ph
+ try:
+ p_size = None
+ for panel in self.parent.plot_panels.values():
+ #p_panel = self.parent._mgr.GetPane(panel.window_name)
+ width, _ = panel.frame.GetSizeTuple()
+ if panel.frame.IsShown():
+ if p_size is None or width > p_size:
+ p_size = width
+ if p_size is None:
+ p_size = CURRENT_STRINGS['PLOPANEL_WIDTH']
+ self.current_string['PLOPANEL_WIDTH'] = p_size
+
+ try:
+ control_frame = self.parent.get_current_perspective().frame
+ control_w, control_h = control_frame.GetSizeTuple()
+ self.current_string['CONTROL_WIDTH'] = control_w
+ self.current_string['CONTROL_HEIGHT'] = control_h
+ except:
+ self.current_string['CONTROL_WIDTH'] = -1
+ self.current_string['CONTROL_HEIGHT'] = -1
+
+ data_pw, _ = self.parent.panels["data_panel"].frame.GetSizeTuple()
+ if data_pw is None:
+ data_pw = CURRENT_STRINGS['DATAPANEL_WIDTH']
+ self.current_string['DATAPANEL_WIDTH'] = data_pw
+
+ #label = self.parent._data_panel_menu.GetText()
+ label = self.parent.panels['data_panel'].frame.IsShown()
+ if label:# == 'Hide Data Explorer':
+ self.current_string['DATALOADER_SHOW'] = True
+ else:
+ self.current_string['DATALOADER_SHOW'] = False
+
+ if self.parent._toolbar.IsShown():
+ self.current_string['TOOLBAR_SHOW'] = True
+ else:
+ self.current_string['TOOLBAR_SHOW'] = False
+
+ style = self._gui & GUIFRAME.FLOATING_PANEL
+ if style == GUIFRAME.FLOATING_PANEL:
+ self.current_string['FIXED_PANEL'] = False
+ else:
+ self.current_string['FIXED_PANEL'] = True
+
+ if self.parent.panels['default'].frame.IsShown():
+ self.current_string['WELCOME_PANEL_SHOW'] = True
+ else:
+ self.current_string['WELCOME_PANEL_SHOW'] = False
+ self.current_string['CLEANUP_PLOT'] = \
+ self.parent.cleanup_plots
+ perspective = self.parent.get_current_perspective()
+ self.current_string['DEFAULT_PERSPECTIVE'] =\
+ str(perspective.sub_menu)
+ location = ''
+ temp = self.parent._default_save_location.split("\\")
+ for strings in temp:
+ location += (strings + "/")
+ self.current_string['DEFAULT_OPEN_FOLDER'] = location
+ #self.parent._default_save_location.ascii_letters
+
+ except:
+ raise
+ # event object and selection
+ self.return_string = self.current_string
+ return self.return_string
+
+
+ def write_custom_config(self):
+ """
+ Write custom configuration
+ """
+ path = make_custom_config_path()
+ with open(path, 'w') as out_f:
+ out_f.write("#Application appearance custom configuration\n")
+ for key, item in self.return_string.iteritems():
+ if (key == 'DEFAULT_PERSPECTIVE') or \
+ (key == 'DEFAULT_OPEN_FOLDER' and item != None):
+ out_f.write("%s = \"%s\"\n" % (key, str(item)))
+ else:
+ out_f.write("%s = %s\n" % (key, str(item)))
diff --git a/src/sas/sasgui/guiframe/utils.py b/src/sas/sasgui/guiframe/utils.py
index 515495b..08d912c 100644
--- a/src/sas/sasgui/guiframe/utils.py
+++ b/src/sas/sasgui/guiframe/utils.py
@@ -1,213 +1,213 @@
-"""
-Contains common classes and functions
-"""
-import wx
-import re
-
-def parse_name(name, expression):
- """
- remove "_" in front of a name
- """
- if re.match(expression, name) is not None:
- word = re.split(expression, name, 1)
- for item in word:
- if item.lstrip().rstrip() != '':
- return item
- else:
- return name
-def format_number(value, high=False):
- """
- Return a float in a standardized, human-readable formatted string
- """
- try:
- value = float(value)
- except:
- output = "NaN"
- return output.lstrip().rstrip()
- if high:
- output = "%-7.5g" % value
- else:
- output = "%-5.3g" % value
- return output.lstrip().rstrip()
-
-def check_float(item):
- """
- :param item: txtcrtl containing a value
- """
- flag = True
- try:
- mini = float(item.GetValue())
- item.SetBackgroundColour(wx.WHITE)
- item.Refresh()
- except:
- flag = False
- item.SetBackgroundColour("pink")
- item.Refresh()
- return flag
-
-
-def check_int(item):
- """
- :param item: txtcrtl containing a value
- """
- flag = True
- try:
- mini = int(item.GetValue())
- item.SetBackgroundColour(wx.WHITE)
- item.Refresh()
- except:
- flag = False
- item.SetBackgroundColour("pink")
- item.Refresh()
- return flag
-
-
-class PanelMenu(wx.Menu):
- """
- """
- plots = None
- graph = None
-
- def set_plots(self, plots):
- """
- """
- self.plots = plots
-
- def set_graph(self, graph):
- """
- """
- self.graph = graph
-
-
-def split_list(separator, mylist, n=0):
- """
- returns a list of string without white space of separator
-
- :param separator: the string to remove
-
- """
- list = []
- for item in mylist:
- if re.search(separator,item)!= None:
- if n > 0:
- word = re.split(separator, item, int(n))
- else:
- word = re.split(separator, item)
- for new_item in word:
- if new_item.lstrip().rstrip() != '':
- list.append(new_item.lstrip().rstrip())
- return list
-
-def split_text(separator, string1, n=0):
- """
- return a list of string without white space of separator
-
- :param separator: the string to remove
-
- """
- list = []
- if re.search(separator, string1) is not None:
- if n > 0:
- word = re.split(separator,string1,int(n))
- else:
- word = re.split(separator,string1)
- for item in word:
- if item.lstrip().rstrip() != '':
- list.append(item.lstrip().rstrip())
- return list
-
-def look_for_tag(string1, begin, end=None):
- """
- this method remove the begin and end tags given by the user
- from the string .
-
- :param begin: the initial tag
- :param end: the final tag
- :param string: the string to check
-
- :return: begin_flag==True if begin was found,
- end_flag==if end was found else return false, false
-
- """
- begin_flag = False
- end_flag = False
- if re.search(begin,string1) is not None:
- begin_flag = True
- if end is not None:
- if re.search(end,string1) is not None:
- end_flag = True
- return begin_flag, end_flag
-
-class IdList:
- """
- Create a list of wx ids that can be reused.
-
- Ids for items need to be unique within their context. In a dynamic
- application where the number of ids needed different each time the
- form is created, depending for example, on the number of items that
- need to be shown in the context menu, you cannot preallocate the
- ids that you are going to use for the form. Instead, you can use
- an IdList, which will reuse ids from context to context, adding new
- ones if the new context requires more than a previous context.
-
- IdList is set up as an iterator, which returns new ids forever
- or until it runs out. This makes it pretty useful for defining
- menus::
-
- class Form(wx.Dialog):
- _form_id_pool = IdList()
- def __init__(self):
- ...
- menu = wx.Menu()
- for item, wx_id in zip(menu_items, self._form_id_pool):
- name, description, callback = item
- menu.Append(wx_id, name, description)
- wx.EVT_MENU(self, wx_id, callback)
- ...
-
- It is a little unusual to use an iterator outside of a loop, but it is
- supported. For example, when defining a form, your class definition
- might look something like::
-
- class Form(wx.Dialog):
- _form_id_pool = IdList()
- def __init__(self, pairs, ...):
- ids = iter(_form_id_pool)
- ...
- wx.StaticText(self, ids.next(), "Some key-value pairs")
- for name, value in pairs:
- label = wx.StaticText(self, ids.next(), name)
- input = wx.TextCtrl(self, ids.next(), value=str(value))
- ...
- ...
-
- If the dialog is really dynamic, and not defined all in one place, then
- save the id list iterator as *self._ids = iter(_form_id_pool)* in the
- constructor.
-
- The wx documentation is not clear on whether ids need to be unique.
- Clearly different dialogs can use the same ids, as this is done for the
- standard button ids such as wx.ID_HELP. Presumably each widget on the
- form needs its own id, but whether these ids can match the ids of menu
- items is not indicated, or whether different submenus need their own
- ids. Using different id lists for menu items and widgets is safest,
- but probably not necessary. And what about notebook tabs. Do the
- ids need to be unique across all tabs?
- """
- def __init__(self):
- self._ids = []
- def __iter__(self):
- return _IdListIterator(self)
- def __getitem__(self, index):
- while index >= len(self._ids):
- self._ids.append(wx.NewId())
- return self._ids[index]
-
-class _IdListIterator:
- def __init__(self, id_list):
- self.id_list = id_list
- self.index = -1
- def next(self):
- self.index += 1
- return self.id_list[self.index]
-
+"""
+Contains common classes and functions
+"""
+import wx
+import re
+
+def parse_name(name, expression):
+ """
+ remove "_" in front of a name
+ """
+ if re.match(expression, name) is not None:
+ word = re.split(expression, name, 1)
+ for item in word:
+ if item.lstrip().rstrip() != '':
+ return item
+ else:
+ return name
+def format_number(value, high=False):
+ """
+ Return a float in a standardized, human-readable formatted string
+ """
+ try:
+ value = float(value)
+ except:
+ output = "NaN"
+ return output.lstrip().rstrip()
+ if high:
+ output = "%-7.5g" % value
+ else:
+ output = "%-5.3g" % value
+ return output.lstrip().rstrip()
+
+def check_float(item):
+ """
+ :param item: txtcrtl containing a value
+ """
+ flag = True
+ try:
+ mini = float(item.GetValue())
+ item.SetBackgroundColour(wx.WHITE)
+ item.Refresh()
+ except:
+ flag = False
+ item.SetBackgroundColour("pink")
+ item.Refresh()
+ return flag
+
+
+def check_int(item):
+ """
+ :param item: txtcrtl containing a value
+ """
+ flag = True
+ try:
+ mini = int(item.GetValue())
+ item.SetBackgroundColour(wx.WHITE)
+ item.Refresh()
+ except:
+ flag = False
+ item.SetBackgroundColour("pink")
+ item.Refresh()
+ return flag
+
+
+class PanelMenu(wx.Menu):
+ """
+ """
+ plots = None
+ graph = None
+
+ def set_plots(self, plots):
+ """
+ """
+ self.plots = plots
+
+ def set_graph(self, graph):
+ """
+ """
+ self.graph = graph
+
+
+def split_list(separator, mylist, n=0):
+ """
+ returns a list of string without white space of separator
+
+ :param separator: the string to remove
+
+ """
+ list = []
+ for item in mylist:
+ if re.search(separator,item)is not None:
+ if n > 0:
+ word = re.split(separator, item, int(n))
+ else:
+ word = re.split(separator, item)
+ for new_item in word:
+ if new_item.lstrip().rstrip() != '':
+ list.append(new_item.lstrip().rstrip())
+ return list
+
+def split_text(separator, string1, n=0):
+ """
+ return a list of string without white space of separator
+
+ :param separator: the string to remove
+
+ """
+ list = []
+ if re.search(separator, string1) is not None:
+ if n > 0:
+ word = re.split(separator,string1,int(n))
+ else:
+ word = re.split(separator,string1)
+ for item in word:
+ if item.lstrip().rstrip() != '':
+ list.append(item.lstrip().rstrip())
+ return list
+
+def look_for_tag(string1, begin, end=None):
+ """
+ this method remove the begin and end tags given by the user
+ from the string .
+
+ :param begin: the initial tag
+ :param end: the final tag
+ :param string: the string to check
+
+ :return: begin_flag==True if begin was found,
+ end_flag==if end was found else return false, false
+
+ """
+ begin_flag = False
+ end_flag = False
+ if re.search(begin,string1) is not None:
+ begin_flag = True
+ if end is not None:
+ if re.search(end,string1) is not None:
+ end_flag = True
+ return begin_flag, end_flag
+
+class IdList:
+ """
+ Create a list of wx ids that can be reused.
+
+ Ids for items need to be unique within their context. In a dynamic
+ application where the number of ids needed different each time the
+ form is created, depending for example, on the number of items that
+ need to be shown in the context menu, you cannot preallocate the
+ ids that you are going to use for the form. Instead, you can use
+ an IdList, which will reuse ids from context to context, adding new
+ ones if the new context requires more than a previous context.
+
+ IdList is set up as an iterator, which returns new ids forever
+ or until it runs out. This makes it pretty useful for defining
+ menus::
+
+ class Form(wx.Dialog):
+ _form_id_pool = IdList()
+ def __init__(self):
+ ...
+ menu = wx.Menu()
+ for item, wx_id in zip(menu_items, self._form_id_pool):
+ name, description, callback = item
+ menu.Append(wx_id, name, description)
+ wx.EVT_MENU(self, wx_id, callback)
+ ...
+
+ It is a little unusual to use an iterator outside of a loop, but it is
+ supported. For example, when defining a form, your class definition
+ might look something like::
+
+ class Form(wx.Dialog):
+ _form_id_pool = IdList()
+ def __init__(self, pairs, ...):
+ ids = iter(_form_id_pool)
+ ...
+ wx.StaticText(self, ids.next(), "Some key-value pairs")
+ for name, value in pairs:
+ label = wx.StaticText(self, ids.next(), name)
+ input = wx.TextCtrl(self, ids.next(), value=str(value))
+ ...
+ ...
+
+ If the dialog is really dynamic, and not defined all in one place, then
+ save the id list iterator as *self._ids = iter(_form_id_pool)* in the
+ constructor.
+
+ The wx documentation is not clear on whether ids need to be unique.
+ Clearly different dialogs can use the same ids, as this is done for the
+ standard button ids such as wx.ID_HELP. Presumably each widget on the
+ form needs its own id, but whether these ids can match the ids of menu
+ items is not indicated, or whether different submenus need their own
+ ids. Using different id lists for menu items and widgets is safest,
+ but probably not necessary. And what about notebook tabs. Do the
+ ids need to be unique across all tabs?
+ """
+ def __init__(self):
+ self._ids = []
+ def __iter__(self):
+ return _IdListIterator(self)
+ def __getitem__(self, index):
+ while index >= len(self._ids):
+ self._ids.append(wx.NewId())
+ return self._ids[index]
+
+class _IdListIterator:
+ def __init__(self, id_list):
+ self.id_list = id_list
+ self.index = -1
+ def next(self):
+ self.index += 1
+ return self.id_list[self.index]
+
diff --git a/src/sas/sasgui/perspectives/calculator/__init__.py b/src/sas/sasgui/perspectives/calculator/__init__.py
index 46406dd..fe222ea 100644
--- a/src/sas/sasgui/perspectives/calculator/__init__.py
+++ b/src/sas/sasgui/perspectives/calculator/__init__.py
@@ -1,47 +1,45 @@
-PLUGIN_ID = "Calculator plug-in 1.0"
-import os
-from distutils.filelist import findall
-from calculator import *
-N_DIR = 12
-def get_data_path(media):
- """
- """
- # Check for data path in the package
- path = os.path.join(os.path.dirname(__file__), media)
- if os.path.isdir(path):
- return path
- # Check for data path next to exe/zip file.
- # If we are inside a py2exe zip file, we need to go up
- # two levels to get to the directory containing the exe
- # We will check if the exe and the xsf are in the same
- # directory.
- path = os.path.dirname(__file__)
- #Look for maximum n_dir up of the current dir to find media
-
- #for i in range(n_dir):
- i = 0
- while(i < N_DIR):
- path, _ = os.path.split(path)
- media_path = os.path.join(path, media)
- if os.path.isdir(media_path):
- module_media_path = os.path.join(media_path,'calculator_%s'% media)
- if os.path.isdir(module_media_path):
- return module_media_path
- return media_path
- i += 1
-
- raise RuntimeError('Could not find calculator media files')
-
-def data_files():
- """
- Return the data files associated with media calculator.
-
- The format is a list of (directory, [files...]) pairs which can be
- used directly in setup(...,data_files=...) for setup.py.
-
- """
- data_files = []
- path = get_data_path(media="media")
- for f in findall(path):
- data_files.append(('media/calculator_media', [f]))
- return data_files
\ No newline at end of file
+PLUGIN_ID = "Calculator plug-in 1.0"
+import os
+from distutils.filelist import findall
+from calculator import *
+N_DIR = 12
+def get_data_path(media):
+ """
+ """
+ # Check for data path in the package
+ path = os.path.join(os.path.dirname(__file__), media)
+ if os.path.isdir(path):
+ return path
+ # Check for data path next to exe/zip file.
+ # If we are inside a py2exe zip file, we need to go up
+ # two levels to get to the directory containing the exe
+ # We will check if the exe and the xsf are in the same
+ # directory.
+ path = os.path.dirname(__file__)
+ #Look for maximum n_dir up of the current dir to find media
+
+ #for i in range(n_dir):
+ i = 0
+ while(i < N_DIR):
+ path, _ = os.path.split(path)
+ media_path = os.path.join(path, media)
+ if os.path.isdir(media_path):
+ module_media_path = os.path.join(media_path,'calculator_%s'% media)
+ if os.path.isdir(module_media_path):
+ return module_media_path
+ return media_path
+ i += 1
+
+ raise RuntimeError('Could not find calculator media files')
+
+def data_files():
+ """
+ Return the data files associated with media calculator.
+
+ The format is a list of (directory, [files...]) pairs which can be
+ used directly in setup(...,data_files=...) for setup.py.
+
+ """
+ data_files = []
+ data_files.append(('media/calculator_media', findall(get_data_path("media"))))
+ return data_files
diff --git a/src/sas/sasgui/perspectives/calculator/aperture_editor.py b/src/sas/sasgui/perspectives/calculator/aperture_editor.py
index 392f3a0..4d7af9c 100644
--- a/src/sas/sasgui/perspectives/calculator/aperture_editor.py
+++ b/src/sas/sasgui/perspectives/calculator/aperture_editor.py
@@ -1,378 +1,378 @@
-
-import wx
-import sys
-from copy import deepcopy
-from sas.sasgui.guiframe.utils import check_float
-
-_BOX_WIDTH = 60
-if sys.platform.count("win32") > 0:
- _STATICBOX_WIDTH = 450
- PANEL_WIDTH = 500
- PANEL_HEIGHT = 290
- FONT_VARIANT = 0
-else:
- _STATICBOX_WIDTH = 480
- PANEL_WIDTH = 530
- PANEL_HEIGHT = 320
- FONT_VARIANT = 1
-
-class ApertureDialog(wx.Dialog):
- def __init__(self, parent=None, manager=None, aperture=None, *args, **kwds):
- """
- Dialog allows to enter values for aperture
- """
- kwds['size'] = (PANEL_WIDTH, PANEL_HEIGHT)
- kwds['title'] = "Aperture Editor"
- wx.Dialog.__init__(self, parent=parent, *args, **kwds)
- self.parent = parent
- self.manager = manager
- self._aperture = aperture
- self._reset_aperture = deepcopy(aperture)
- self._notes = ""
-
- #Attributes for panel
- self.aperture_name_tcl = None
- self.main_sizer = None
- self.box_aperture = None
- self.boxsizer_aperture = None
- self.name_sizer = None
- self.name_sizer = None
- self.size_name_tcl = None
- self.type_sizer = None
- self.distance_sizer = None
- self.size_name_sizer = None
- self.aperture_size_unit_tcl = None
- self.aperture_size_sizer = None
- self.button_sizer = None
- self.aperture_name_tcl = None
- self.type_tcl = None
- self.distance_tcl = None
- self.distance_unit_tcl = None
- self.x_aperture_size_tcl = None
- self.y_aperture_size_tcl = None
- self.z_aperture_size_tcl = None
- self.bt_apply = None
- self.bt_cancel = None
- self.bt_close = None
-
- self._do_layout()
- self.set_values()
-
- def _define_structure(self):
- """
- define initial sizer
- """
- self.main_sizer = wx.BoxSizer(wx.VERTICAL)
- self.box_aperture = wx.StaticBox(self, -1, str("Aperture"))
- self.boxsizer_aperture = wx.StaticBoxSizer(self.box_aperture, wx.VERTICAL)
- self.name_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.type_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.distance_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.size_name_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.aperture_size_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.button_sizer = wx.BoxSizer(wx.HORIZONTAL)
-
- def _layout_name(self):
- """
- Do the layout for aperture name related widgets
- """
- #Aperture name [string]
- aperture_name_txt = wx.StaticText(self, -1, 'Aperture Name : ')
- self.aperture_name_tcl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH * 5, 20), style=0)
- self.name_sizer.AddMany([(aperture_name_txt, 0, wx.LEFT | wx.RIGHT, 10),
- (self.aperture_name_tcl, 0, wx.EXPAND)])
- def _layout_type(self):
- """
- Do the layout for aperture type related widgets
- """
- #Aperture type [string]
- type_txt = wx.StaticText(self, -1, 'Type: ')
- self.type_tcl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, 20), style=0)
- self.type_sizer.AddMany([(type_txt, 0, wx.LEFT | wx.RIGHT, 10),
- (self.type_tcl, 0, wx.LEFT, 20)])
-
- def _layout_distance(self):
- """
- Do the layout for aperture distance related widgets
- """
- #Aperture distance [float]
- distance_txt = wx.StaticText(self, -1, 'Distance:')
- self.distance_tcl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, 20),
- style=0)
- distance_unit_txt = wx.StaticText(self, -1, 'Unit: ')
- self.distance_unit_tcl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, 20), style=0)
- self.distance_sizer.AddMany([(distance_txt, 0, wx.LEFT | wx.RIGHT, 10),
- (self.distance_tcl, 0, wx.LEFT, 10),
- (distance_unit_txt, 0, wx.LEFT | wx.RIGHT, 10),
- (self.distance_unit_tcl, 0, wx.EXPAND)])
- def _layout_size_name(self):
- """
- Do the layout for size name related widgets
- """
- # Size name [string]
- size_name_txt = wx.StaticText(self, -1, 'Size Name : ')
- self.size_name_tcl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH * 5, 20), style=0)
- self.size_name_sizer.AddMany([(size_name_txt, 0, wx.LEFT | wx.RIGHT, 10),
- (self.size_name_tcl, 0, wx.EXPAND)])
-
- def _layout_size(self):
- """
- Do the layout for aperture size related widgets
- """
- #Aperture size [Vector]
- aperture_size_txt = wx.StaticText(self, -1, 'Size:')
- x_aperture_size_txt = wx.StaticText(self, -1, 'x = ')
- self.x_aperture_size_tcl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, 20), style=0)
- y_aperture_size_txt = wx.StaticText(self, -1, 'y = ')
- self.y_aperture_size_tcl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, 20), style=0)
- z_aperture_size_txt = wx.StaticText(self, -1, 'z = ')
- self.z_aperture_size_tcl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, 20), style=0)
- aperture_size_unit_txt = wx.StaticText(self, -1, 'Unit: ')
- self.aperture_size_unit_tcl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, 20), style=0)
- self.aperture_size_sizer.AddMany([(aperture_size_txt, 0, wx.LEFT | wx.RIGHT, 10),
- (x_aperture_size_txt, 0, wx.LEFT, 17),
- (self.x_aperture_size_tcl, 0, wx.RIGHT, 10),
- (y_aperture_size_txt, 0, wx.EXPAND),
- (self.y_aperture_size_tcl, 0, wx.RIGHT, 10),
- (z_aperture_size_txt, 0, wx.EXPAND),
- (self.z_aperture_size_tcl, 0, wx.RIGHT, 10),
- (aperture_size_unit_txt, 0, wx.EXPAND),
- (self.aperture_size_unit_tcl, 0, wx.RIGHT, 10)])
-
- def _layout_button(self):
- """
- Do the layout for the button widgets
- """
- self.bt_apply = wx.Button(self, -1, 'Apply')
- self.bt_apply.Bind(wx.EVT_BUTTON, self.on_click_apply)
- self.bt_apply.SetToolTipString("Apply current changes to aperture.")
- self.bt_cancel = wx.Button(self, -1, 'Cancel')
- self.bt_cancel.SetToolTipString("Cancel current changes.")
- self.bt_cancel.Bind(wx.EVT_BUTTON, self.on_click_cancel)
- self.bt_close = wx.Button(self, wx.ID_CANCEL, 'Close')
- self.bt_close.SetToolTipString("Close window.")
- self.button_sizer.AddMany([(self.bt_apply, 0, wx.LEFT, 200),
- (self.bt_cancel, 0, wx.LEFT, 10),
- (self.bt_close, 0, wx.LEFT, 10)])
-
- def _do_layout(self):#, data=None):
- """
- Draw the current panel
- """
- self._define_structure()
- self._layout_name()
- self._layout_type()
- self._layout_distance()
- self._layout_size_name()
- self._layout_size()
- self._layout_button()
- self.boxsizer_aperture.AddMany([(self.name_sizer, 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
- (self.type_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
- (self.distance_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
- (self.size_name_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
- (self.aperture_size_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
- self.main_sizer.AddMany([(self.boxsizer_aperture, 0, wx.ALL, 10),
- (self.button_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
- self.SetSizer(self.main_sizer)
- self.SetAutoLayout(True)
-
- def set_manager(self, manager):
- """
- Set manager of this window
- """
- self.manager = manager
-
- def reset_aperture(self):
- """
- put the default value of the detector back to the current aperture
- """
- self._aperture.name = self._reset_aperture.name
- self._aperture.type = self._reset_aperture.type
- self._aperture.size_name = self._reset_aperture.size_name
- self._aperture.size.x = self._reset_aperture.size.x
- self._aperture.size.y = self._reset_aperture.size.y
- self._aperture.size.z = self._reset_aperture.size.z
- self._aperture.size_unit = self._reset_aperture.size_unit
- self._aperture.distance = self._reset_aperture.distance
- self._aperture.distance_unit = self._reset_aperture.distance_unit
-
- def set_values(self):
- """
- take the aperture values of the current data and display them
- through the panel
- """
- aperture = self._aperture
- #Name
- self.aperture_name_tcl.SetValue(str(aperture.name))
- #Type
- self.type_tcl.SetValue(str(aperture.type))
- #distance
- self.distance_tcl.SetValue(str(aperture.distance))
- #distance unit
- self.distance_unit_tcl.SetValue(str(aperture.distance_unit))
- #Size name
- self.size_name_tcl.SetValue(str(aperture.size_name))
- #Aperture size as a vector
- x, y, z = aperture.size.x, aperture.size.y, aperture.size.z
- self.x_aperture_size_tcl.SetValue(str(x))
- self.y_aperture_size_tcl.SetValue(str(y))
- self.z_aperture_size_tcl.SetValue(str(z))
- self.aperture_size_unit_tcl.SetValue(str(aperture.size_unit))
-
- def get_aperture(self):
- """
- return the current aperture
- """
- return self._aperture
-
- def get_notes(self):
- """
- return notes
- """
- return self._notes
-
- def on_change_name(self):
- """
- Change name
- """
- #Change the name of the aperture
- name = self.aperture_name_tcl.GetValue().lstrip().rstrip()
- if name == "":
- name = str(None)
- if self._aperture.name != name:
- self._notes += "Change sample 's "
- self._notes += "name from %s to %s \n" % (self._aperture.name, name)
- self._aperture.name = name
-
- def on_change_type(self):
- """
- Change aperture type
- """
- #Change type
- type_value = self.type_tcl.GetValue().lstrip().rstrip()
- self._aperture.type = type_value
- self._notes += " Change type from"
- self._notes += " %s to %s \n" % (self._aperture.type, type_value)
-
- def on_change_distance(self):
- """
- Change distance of the aperture
- """
- #Change distance
- distance = self.distance_tcl.GetValue().lstrip().rstrip()
- if distance == "" or distance == str(None):
- distance = None
- self._aperture.distance = distance
- else:
- if check_float(self.distance_tcl):
- if self._aperture.distance != float(distance):
- self._notes += "Change distance from "
- self._notes += "%s to %s \n" % (self._aperture.distance, distance)
- self._aperture.distance = float(distance)
- else:
- self._notes += "Error: Expected a float for distance "
- self._notes += "won't changes distance from "
- self._notes += "%s to %s" % (self._aperture.distance, distance)
- #change the distance unit
- unit = self.distance_unit_tcl.GetValue().lstrip().rstrip()
- if self._aperture.distance_unit != unit:
- self._notes += " Change distance 's unit from "
- self._notes += "%s to %s" % (self._aperture.distance_unit, unit)
-
- def on_change_size_name(self):
- """
- Change the size's name
- """
- #Change size name
- size_name = self.size_name_tcl.GetValue().lstrip().rstrip()
- self._aperture.size_name = size_name
- self._notes += " Change size name from"
- self._notes += " %s to %s \n" % (self._aperture.size_name, size_name)
-
- def on_change_size(self):
- """
- Change aperture size
- """
- #Change x coordinate
- x_aperture_size = self.x_aperture_size_tcl.GetValue().lstrip().rstrip()
- if x_aperture_size == "" or x_aperture_size == str(None):
- x_aperture_size = None
- else:
- if check_float(self.x_aperture_size_tcl):
- if self._aperture.size.x != float(x_aperture_size):
- self._notes += "Change x of aperture size from "
- self._notes += "%s to %s \n" % (self._aperture.size.x, x_aperture_size)
- self._aperture.aperture_size.x = float(x_aperture_size)
- else:
- self._notes += "Error: Expected a"
- self._notes += " float for the aperture size 's x "
- self._notes += "won't changes x aperture size from "
- self._notes += "%s to %s" % (self._aperture.size.x, x_aperture_size)
- #Change y coordinate
- y_aperture_size = self.y_aperture_size_tcl.GetValue().lstrip().rstrip()
- if y_aperture_size == "" or y_aperture_size == str(None):
- y_aperture_size = None
- self._aperture.size.y = y_aperture_size
- else:
- if check_float(self.y_aperture_size_tcl):
- if self._aperture.size.y != float(y_aperture_size):
- self._notes += "Change y of aperture size from "
- self._notes += "%s to %s \n" % (self._aperture.size.y, y_aperture_size)
- self._aperture.size.y = float(y_aperture_size)
- else:
- self._notes += "Error: Expected a float for the"
- self._notes += " aperture size's y "
- self._notes += "won't changes y aperture size from "
- self._notes += "%s to %s" % (self._aperture.size.y, y_aperture_size)
- #Change z coordinate
- z_aperture_size = self.z_aperture_size_tcl.GetValue().lstrip().rstrip()
- if z_aperture_size == "" or z_aperture_size == str(None):
- z_aperture_size = None
- self._aperture.size.z = z_aperture_size
- else:
- if check_float(self.z_aperture_size_tcl):
- if self._aperture.size.z != float(z_aperture_size):
- self._notes += "Change z of aperture size from "
- self._notes += "%s to %s \n" % (self._aperture.size.z, z_aperture_size)
- self._aperture.size.z = float(z_aperture_size)
- else:
- self._notes += "Error: Expected a float for the offset 's x "
- self._notes += "won't changes z aperture size from "
- self._notes += "%s to %s" % (self._aperture.size.z, z_aperture_size)
- #change the aperture center unit
- unit = self.aperture_size_unit_tcl.GetValue().lstrip().rstrip()
- if self._aperture.size_unit != unit:
- self._notes += " Change aperture size's unit from "
- self._notes += "%s to %s" % (self._aperture.size_unit, unit)
- self._aperture.size_unit = unit
-
- def on_click_apply(self, event):
- """
- Apply user values to the aperture
- """
- self.on_change_name()
- self.on_change_type()
- self.on_change_distance()
- self.on_change_size_name()
- self.on_change_size()
- self.set_values()
- if self.manager is not None:
- self.manager.set_aperture(self._aperture)
- if event is not None:
- event.Skip()
-
- def on_click_cancel(self, event):
- """
- reset the current aperture to its initial values
- """
- self.reset_aperture()
- self.set_values()
- if self.manager is not None:
- self.manager.set_aperture(self._aperture)
- if event is not None:
- event.Skip()
+
+import wx
+import sys
+from copy import deepcopy
+from sas.sasgui.guiframe.utils import check_float
+
+_BOX_WIDTH = 60
+if sys.platform.count("win32") > 0:
+ _STATICBOX_WIDTH = 450
+ PANEL_WIDTH = 500
+ PANEL_HEIGHT = 290
+ FONT_VARIANT = 0
+else:
+ _STATICBOX_WIDTH = 480
+ PANEL_WIDTH = 530
+ PANEL_HEIGHT = 320
+ FONT_VARIANT = 1
+
+class ApertureDialog(wx.Dialog):
+ def __init__(self, parent=None, manager=None, aperture=None, *args, **kwds):
+ """
+ Dialog allows to enter values for aperture
+ """
+ kwds['size'] = (PANEL_WIDTH, PANEL_HEIGHT)
+ kwds['title'] = "Aperture Editor"
+ wx.Dialog.__init__(self, parent=parent, *args, **kwds)
+ self.parent = parent
+ self.manager = manager
+ self._aperture = aperture
+ self._reset_aperture = deepcopy(aperture)
+ self._notes = ""
+
+ #Attributes for panel
+ self.aperture_name_tcl = None
+ self.main_sizer = None
+ self.box_aperture = None
+ self.boxsizer_aperture = None
+ self.name_sizer = None
+ self.name_sizer = None
+ self.size_name_tcl = None
+ self.type_sizer = None
+ self.distance_sizer = None
+ self.size_name_sizer = None
+ self.aperture_size_unit_tcl = None
+ self.aperture_size_sizer = None
+ self.button_sizer = None
+ self.aperture_name_tcl = None
+ self.type_tcl = None
+ self.distance_tcl = None
+ self.distance_unit_tcl = None
+ self.x_aperture_size_tcl = None
+ self.y_aperture_size_tcl = None
+ self.z_aperture_size_tcl = None
+ self.bt_apply = None
+ self.bt_cancel = None
+ self.bt_close = None
+
+ self._do_layout()
+ self.set_values()
+
+ def _define_structure(self):
+ """
+ define initial sizer
+ """
+ self.main_sizer = wx.BoxSizer(wx.VERTICAL)
+ self.box_aperture = wx.StaticBox(self, -1, str("Aperture"))
+ self.boxsizer_aperture = wx.StaticBoxSizer(self.box_aperture, wx.VERTICAL)
+ self.name_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.type_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.distance_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.size_name_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.aperture_size_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.button_sizer = wx.BoxSizer(wx.HORIZONTAL)
+
+ def _layout_name(self):
+ """
+ Do the layout for aperture name related widgets
+ """
+ #Aperture name [string]
+ aperture_name_txt = wx.StaticText(self, -1, 'Aperture Name : ')
+ self.aperture_name_tcl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH * 5, 20), style=0)
+ self.name_sizer.AddMany([(aperture_name_txt, 0, wx.LEFT | wx.RIGHT, 10),
+ (self.aperture_name_tcl, 0, wx.EXPAND)])
+ def _layout_type(self):
+ """
+ Do the layout for aperture type related widgets
+ """
+ #Aperture type [string]
+ type_txt = wx.StaticText(self, -1, 'Type: ')
+ self.type_tcl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, 20), style=0)
+ self.type_sizer.AddMany([(type_txt, 0, wx.LEFT | wx.RIGHT, 10),
+ (self.type_tcl, 0, wx.LEFT, 20)])
+
+ def _layout_distance(self):
+ """
+ Do the layout for aperture distance related widgets
+ """
+ #Aperture distance [float]
+ distance_txt = wx.StaticText(self, -1, 'Distance:')
+ self.distance_tcl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, 20),
+ style=0)
+ distance_unit_txt = wx.StaticText(self, -1, 'Unit: ')
+ self.distance_unit_tcl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, 20), style=0)
+ self.distance_sizer.AddMany([(distance_txt, 0, wx.LEFT | wx.RIGHT, 10),
+ (self.distance_tcl, 0, wx.LEFT, 10),
+ (distance_unit_txt, 0, wx.LEFT | wx.RIGHT, 10),
+ (self.distance_unit_tcl, 0, wx.EXPAND)])
+ def _layout_size_name(self):
+ """
+ Do the layout for size name related widgets
+ """
+ # Size name [string]
+ size_name_txt = wx.StaticText(self, -1, 'Size Name : ')
+ self.size_name_tcl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH * 5, 20), style=0)
+ self.size_name_sizer.AddMany([(size_name_txt, 0, wx.LEFT | wx.RIGHT, 10),
+ (self.size_name_tcl, 0, wx.EXPAND)])
+
+ def _layout_size(self):
+ """
+ Do the layout for aperture size related widgets
+ """
+ #Aperture size [Vector]
+ aperture_size_txt = wx.StaticText(self, -1, 'Size:')
+ x_aperture_size_txt = wx.StaticText(self, -1, 'x = ')
+ self.x_aperture_size_tcl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, 20), style=0)
+ y_aperture_size_txt = wx.StaticText(self, -1, 'y = ')
+ self.y_aperture_size_tcl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, 20), style=0)
+ z_aperture_size_txt = wx.StaticText(self, -1, 'z = ')
+ self.z_aperture_size_tcl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, 20), style=0)
+ aperture_size_unit_txt = wx.StaticText(self, -1, 'Unit: ')
+ self.aperture_size_unit_tcl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, 20), style=0)
+ self.aperture_size_sizer.AddMany([(aperture_size_txt, 0, wx.LEFT | wx.RIGHT, 10),
+ (x_aperture_size_txt, 0, wx.LEFT, 17),
+ (self.x_aperture_size_tcl, 0, wx.RIGHT, 10),
+ (y_aperture_size_txt, 0, wx.EXPAND),
+ (self.y_aperture_size_tcl, 0, wx.RIGHT, 10),
+ (z_aperture_size_txt, 0, wx.EXPAND),
+ (self.z_aperture_size_tcl, 0, wx.RIGHT, 10),
+ (aperture_size_unit_txt, 0, wx.EXPAND),
+ (self.aperture_size_unit_tcl, 0, wx.RIGHT, 10)])
+
+ def _layout_button(self):
+ """
+ Do the layout for the button widgets
+ """
+ self.bt_apply = wx.Button(self, -1, 'Apply')
+ self.bt_apply.Bind(wx.EVT_BUTTON, self.on_click_apply)
+ self.bt_apply.SetToolTipString("Apply current changes to aperture.")
+ self.bt_cancel = wx.Button(self, -1, 'Cancel')
+ self.bt_cancel.SetToolTipString("Cancel current changes.")
+ self.bt_cancel.Bind(wx.EVT_BUTTON, self.on_click_cancel)
+ self.bt_close = wx.Button(self, wx.ID_CANCEL, 'Close')
+ self.bt_close.SetToolTipString("Close window.")
+ self.button_sizer.AddMany([(self.bt_apply, 0, wx.LEFT, 200),
+ (self.bt_cancel, 0, wx.LEFT, 10),
+ (self.bt_close, 0, wx.LEFT, 10)])
+
+ def _do_layout(self):#, data=None):
+ """
+ Draw the current panel
+ """
+ self._define_structure()
+ self._layout_name()
+ self._layout_type()
+ self._layout_distance()
+ self._layout_size_name()
+ self._layout_size()
+ self._layout_button()
+ self.boxsizer_aperture.AddMany([(self.name_sizer, 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
+ (self.type_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
+ (self.distance_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
+ (self.size_name_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
+ (self.aperture_size_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
+ self.main_sizer.AddMany([(self.boxsizer_aperture, 0, wx.ALL, 10),
+ (self.button_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
+ self.SetSizer(self.main_sizer)
+ self.SetAutoLayout(True)
+
+ def set_manager(self, manager):
+ """
+ Set manager of this window
+ """
+ self.manager = manager
+
+ def reset_aperture(self):
+ """
+ put the default value of the detector back to the current aperture
+ """
+ self._aperture.name = self._reset_aperture.name
+ self._aperture.type = self._reset_aperture.type
+ self._aperture.size_name = self._reset_aperture.size_name
+ self._aperture.size.x = self._reset_aperture.size.x
+ self._aperture.size.y = self._reset_aperture.size.y
+ self._aperture.size.z = self._reset_aperture.size.z
+ self._aperture.size_unit = self._reset_aperture.size_unit
+ self._aperture.distance = self._reset_aperture.distance
+ self._aperture.distance_unit = self._reset_aperture.distance_unit
+
+ def set_values(self):
+ """
+ take the aperture values of the current data and display them
+ through the panel
+ """
+ aperture = self._aperture
+ #Name
+ self.aperture_name_tcl.SetValue(str(aperture.name))
+ #Type
+ self.type_tcl.SetValue(str(aperture.type))
+ #distance
+ self.distance_tcl.SetValue(str(aperture.distance))
+ #distance unit
+ self.distance_unit_tcl.SetValue(str(aperture.distance_unit))
+ #Size name
+ self.size_name_tcl.SetValue(str(aperture.size_name))
+ #Aperture size as a vector
+ x, y, z = aperture.size.x, aperture.size.y, aperture.size.z
+ self.x_aperture_size_tcl.SetValue(str(x))
+ self.y_aperture_size_tcl.SetValue(str(y))
+ self.z_aperture_size_tcl.SetValue(str(z))
+ self.aperture_size_unit_tcl.SetValue(str(aperture.size_unit))
+
+ def get_aperture(self):
+ """
+ return the current aperture
+ """
+ return self._aperture
+
+ def get_notes(self):
+ """
+ return notes
+ """
+ return self._notes
+
+ def on_change_name(self):
+ """
+ Change name
+ """
+ #Change the name of the aperture
+ name = self.aperture_name_tcl.GetValue().lstrip().rstrip()
+ if name == "":
+ name = str(None)
+ if self._aperture.name != name:
+ self._notes += "Change sample 's "
+ self._notes += "name from %s to %s \n" % (self._aperture.name, name)
+ self._aperture.name = name
+
+ def on_change_type(self):
+ """
+ Change aperture type
+ """
+ #Change type
+ type_value = self.type_tcl.GetValue().lstrip().rstrip()
+ self._aperture.type = type_value
+ self._notes += " Change type from"
+ self._notes += " %s to %s \n" % (self._aperture.type, type_value)
+
+ def on_change_distance(self):
+ """
+ Change distance of the aperture
+ """
+ #Change distance
+ distance = self.distance_tcl.GetValue().lstrip().rstrip()
+ if distance == "" or distance == str(None):
+ distance = None
+ self._aperture.distance = distance
+ else:
+ if check_float(self.distance_tcl):
+ if self._aperture.distance != float(distance):
+ self._notes += "Change distance from "
+ self._notes += "%s to %s \n" % (self._aperture.distance, distance)
+ self._aperture.distance = float(distance)
+ else:
+ self._notes += "Error: Expected a float for distance "
+ self._notes += "won't changes distance from "
+ self._notes += "%s to %s" % (self._aperture.distance, distance)
+ #change the distance unit
+ unit = self.distance_unit_tcl.GetValue().lstrip().rstrip()
+ if self._aperture.distance_unit != unit:
+ self._notes += " Change distance 's unit from "
+ self._notes += "%s to %s" % (self._aperture.distance_unit, unit)
+
+ def on_change_size_name(self):
+ """
+ Change the size's name
+ """
+ #Change size name
+ size_name = self.size_name_tcl.GetValue().lstrip().rstrip()
+ self._aperture.size_name = size_name
+ self._notes += " Change size name from"
+ self._notes += " %s to %s \n" % (self._aperture.size_name, size_name)
+
+ def on_change_size(self):
+ """
+ Change aperture size
+ """
+ #Change x coordinate
+ x_aperture_size = self.x_aperture_size_tcl.GetValue().lstrip().rstrip()
+ if x_aperture_size == "" or x_aperture_size == str(None):
+ x_aperture_size = None
+ else:
+ if check_float(self.x_aperture_size_tcl):
+ if self._aperture.size.x != float(x_aperture_size):
+ self._notes += "Change x of aperture size from "
+ self._notes += "%s to %s \n" % (self._aperture.size.x, x_aperture_size)
+ self._aperture.aperture_size.x = float(x_aperture_size)
+ else:
+ self._notes += "Error: Expected a"
+ self._notes += " float for the aperture size 's x "
+ self._notes += "won't changes x aperture size from "
+ self._notes += "%s to %s" % (self._aperture.size.x, x_aperture_size)
+ #Change y coordinate
+ y_aperture_size = self.y_aperture_size_tcl.GetValue().lstrip().rstrip()
+ if y_aperture_size == "" or y_aperture_size == str(None):
+ y_aperture_size = None
+ self._aperture.size.y = y_aperture_size
+ else:
+ if check_float(self.y_aperture_size_tcl):
+ if self._aperture.size.y != float(y_aperture_size):
+ self._notes += "Change y of aperture size from "
+ self._notes += "%s to %s \n" % (self._aperture.size.y, y_aperture_size)
+ self._aperture.size.y = float(y_aperture_size)
+ else:
+ self._notes += "Error: Expected a float for the"
+ self._notes += " aperture size's y "
+ self._notes += "won't changes y aperture size from "
+ self._notes += "%s to %s" % (self._aperture.size.y, y_aperture_size)
+ #Change z coordinate
+ z_aperture_size = self.z_aperture_size_tcl.GetValue().lstrip().rstrip()
+ if z_aperture_size == "" or z_aperture_size == str(None):
+ z_aperture_size = None
+ self._aperture.size.z = z_aperture_size
+ else:
+ if check_float(self.z_aperture_size_tcl):
+ if self._aperture.size.z != float(z_aperture_size):
+ self._notes += "Change z of aperture size from "
+ self._notes += "%s to %s \n" % (self._aperture.size.z, z_aperture_size)
+ self._aperture.size.z = float(z_aperture_size)
+ else:
+ self._notes += "Error: Expected a float for the offset 's x "
+ self._notes += "won't changes z aperture size from "
+ self._notes += "%s to %s" % (self._aperture.size.z, z_aperture_size)
+ #change the aperture center unit
+ unit = self.aperture_size_unit_tcl.GetValue().lstrip().rstrip()
+ if self._aperture.size_unit != unit:
+ self._notes += " Change aperture size's unit from "
+ self._notes += "%s to %s" % (self._aperture.size_unit, unit)
+ self._aperture.size_unit = unit
+
+ def on_click_apply(self, event):
+ """
+ Apply user values to the aperture
+ """
+ self.on_change_name()
+ self.on_change_type()
+ self.on_change_distance()
+ self.on_change_size_name()
+ self.on_change_size()
+ self.set_values()
+ if self.manager is not None:
+ self.manager.set_aperture(self._aperture)
+ if event is not None:
+ event.Skip()
+
+ def on_click_cancel(self, event):
+ """
+ reset the current aperture to its initial values
+ """
+ self.reset_aperture()
+ self.set_values()
+ if self.manager is not None:
+ self.manager.set_aperture(self._aperture)
+ if event is not None:
+ event.Skip()
diff --git a/src/sas/sasgui/perspectives/calculator/calculator.py b/src/sas/sasgui/perspectives/calculator/calculator.py
index 3a27649..14f4f78 100644
--- a/src/sas/sasgui/perspectives/calculator/calculator.py
+++ b/src/sas/sasgui/perspectives/calculator/calculator.py
@@ -1,233 +1,235 @@
-"""
-Calculator Module
-"""
-################################################################################
-#This software was developed by the University of Tennessee as part of the
-#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
-#project funded by the US National Science Foundation.
-#
-#See the license text in license.txt
-#
-#copyright 2010, University of Tennessee
-################################################################################
-
-import wx
-from sas.sasgui.guiframe.plugin_base import PluginBase
-from sas.sasgui.perspectives.calculator.data_operator import DataOperatorWindow
-from sas.sasgui.perspectives.calculator.data_editor import DataEditorWindow
-from sas.sasgui.perspectives.calculator.kiessig_calculator_panel import KiessigWindow
-from sas.sasgui.perspectives.calculator.sld_panel import SldWindow
-from sas.sasgui.perspectives.calculator.density_panel import DensityWindow
-from sas.sasgui.perspectives.calculator.slit_length_calculator_panel \
- import SlitLengthCalculatorWindow
-from sas.sasgui.perspectives.calculator.resolution_calculator_panel \
- import ResolutionWindow
-from sas.sasgui.perspectives.calculator.gen_scatter_panel import SasGenWindow
-from sas.sasgui.perspectives.calculator.image_viewer import ImageView
-from sas.sasgui.perspectives.calculator.pyconsole import PyConsole
-import logging
-
-class Plugin(PluginBase):
- """
- This class defines the interface for a Plugin class
- for calculator perspective
- """
- def __init__(self):
- PluginBase.__init__(self, name="Calculator")
- # Log startup
- logging.info("Calculator plug-in started")
- self.sub_menu = "Tool"
- self.data_edit_frame = None
- # data operator use one frame all the time
- self.data_operator_frame = None
- self.kiessig_frame = None
- self.sld_frame = None
- self.cal_md_frame = None
- self.cal_slit_frame = None
- self.cal_res_frame = None
- self.gen_frame = None
- self.image_view = None
- self.py_frame = None
-
-
- def get_tools(self):
- """
- Returns a set of menu entries for tools
- """
- data_oper_help = "Perform arithmetic data operation (+...) "
- data_oper_help += "and combination (|)"
- kiessig_help = "Approximately computes the "
- kiessig_help += "thickness of a shell or the size of "
- kiessig_help += "particles \n from the width of a Kiessig fringe."
- sld_help = "Computes the Scattering Length Density."
- slit_length_help = "Computes the slit length from the beam profile."
- resolution_help = "Approximately estimates the "
- resolution_help += "resolution of Q in 2D based on the SAS "
- resolution_help += "instrumental parameter values."
- mass_volume_help = "Based on the chemical formula, "
- mass_volume_help += "compute the mass density or the molar volume."
- gensas_help = "Generic SAS"
- pyconsole_help = "Python Console."
- imageviewer_help = "Load an image file and display the image."
- #data_editor_help = "Meta Data Editor"
- return [("Data Operation",
- data_oper_help, self.on_data_operation),
- ("SLD Calculator", sld_help, self.on_calculate_sld),
- ("Density/Volume Calculator", mass_volume_help,
- self.on_calculate_dv),
- ("Slit Size Calculator", slit_length_help,
- self.on_calculate_slit_size),
- ("Kiessig Thickness Calculator",
- kiessig_help, self.on_calculate_kiessig),
- ("Q Resolution Estimator",
- resolution_help, self.on_calculate_resoltuion),
- ("Generic Scattering Calculator",
- gensas_help, self.on_gen_model),
- ("Python Shell/Editor", pyconsole_help, self.on_python_console),
- ("Image Viewer", imageviewer_help, self.on_image_viewer), ]
-
- def on_edit_data(self, event):
- """
- Edit meta data
- """
- if self.data_edit_frame == None:
- self.data_edit_frame = DataEditorWindow(parent=self.parent,
- manager=self, data=[],
- title="Data Editor")
- self.put_icon(self.data_edit_frame)
- else:
- self.data_edit_frame.Show(False)
- self.data_edit_frame.Show(True)
-
- def on_data_operation(self, event):
- """
- Data operation
- """
- if self.data_operator_frame == None:
- # Use one frame all the time
- self.data_operator_frame = DataOperatorWindow(parent=self.parent,
- manager=self,
- title="Data Operation")
- self.put_icon(self.data_operator_frame)
- else:
- self.data_operator_frame.Show(False)
- self.data_operator_frame.panel.set_panel_on_focus(None)
- self.data_operator_frame.Show(True)
-
- def on_calculate_kiessig(self, event):
- """
- Compute the Kiessig thickness
- """
- if self.kiessig_frame == None:
- frame = KiessigWindow(parent=self.parent, manager=self)
- self.put_icon(frame)
- self.kiessig_frame = frame
- else:
- self.kiessig_frame.Show(False)
- self.kiessig_frame.Show(True)
-
- def on_calculate_sld(self, event):
- """
- Compute the scattering length density of molecula
- """
- if self.sld_frame == None:
- frame = SldWindow(parent=self.parent,
- base=self.parent, manager=self)
- self.put_icon(frame)
- self.sld_frame = frame
- else:
- self.sld_frame.Show(False)
- self.sld_frame.Show(True)
-
- def on_calculate_dv(self, event):
- """
- Compute the mass density or molar voulme
- """
- if self.cal_md_frame == None:
- frame = DensityWindow(parent=self.parent,
- base=self.parent, manager=self)
- self.put_icon(frame)
- self.cal_md_frame = frame
- else:
- self.cal_md_frame.Show(False)
- self.cal_md_frame.Show(True)
-
- def on_calculate_slit_size(self, event):
- """
- Compute the slit size a given data
- """
- if self.cal_slit_frame == None:
- frame = SlitLengthCalculatorWindow(parent=self.parent, manager=self)
- self.put_icon(frame)
- self.cal_slit_frame = frame
- else:
- self.cal_slit_frame.Show(False)
- self.cal_slit_frame.Show(True)
-
- def on_calculate_resoltuion(self, event):
- """
- Estimate the instrumental resolution
- """
- if self.cal_res_frame == None:
- frame = ResolutionWindow(parent=self.parent, manager=self)
- self.put_icon(frame)
- self.cal_res_frame = frame
- else:
- self.cal_res_frame.Show(False)
- self.cal_res_frame.Show(True)
-
- def on_gen_model(self, event):
- """
- On Generic model menu event
- """
- if self.gen_frame == None:
- frame = SasGenWindow(parent=self.parent, manager=self)
- self.put_icon(frame)
- self.gen_frame = frame
- else:
- self.gen_frame.Show(False)
- self.gen_frame.Show(True)
-
- def on_image_viewer(self, event):
- """
- Get choose an image file dialog
-
- :param event: menu event
- """
- self.image_view = ImageView(parent=self.parent)
- self.image_view.load()
-
- def on_python_console(self, event):
- """
- Open Python Console
-
- :param event: menu event
- """
- self.get_python_panel(filename=None)
-
- def get_python_panel(self, filename=None):
- """
- Get the python shell panel
-
- :param filename: file name to open in editor
- """
- if self.py_frame == None:
- frame = PyConsole(parent=self.parent, base=self,
- filename=filename)
- self.put_icon(frame)
- self.py_frame = frame
- else:
- self.py_frame.Show(False)
- self.py_frame.Show(True)
-
- def put_icon(self, frame):
- """
- Put icon in the frame title bar
- """
- if hasattr(frame, "IsIconized"):
- if not frame.IsIconized():
- try:
- icon = self.parent.GetIcon()
- frame.SetIcon(icon)
- except:
- pass
+"""
+Calculator Module
+"""
+################################################################################
+#This software was developed by the University of Tennessee as part of the
+#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
+#project funded by the US National Science Foundation.
+#
+#See the license text in license.txt
+#
+#copyright 2010, University of Tennessee
+################################################################################
+
+import wx
+from sas.sasgui.guiframe.plugin_base import PluginBase
+from sas.sasgui.perspectives.calculator.data_operator import DataOperatorWindow
+from sas.sasgui.perspectives.calculator.data_editor import DataEditorWindow
+from sas.sasgui.perspectives.calculator.kiessig_calculator_panel import KiessigWindow
+from sas.sasgui.perspectives.calculator.sld_panel import SldWindow
+from sas.sasgui.perspectives.calculator.density_panel import DensityWindow
+from sas.sasgui.perspectives.calculator.slit_length_calculator_panel \
+ import SlitLengthCalculatorWindow
+from sas.sasgui.perspectives.calculator.resolution_calculator_panel \
+ import ResolutionWindow
+from sas.sasgui.perspectives.calculator.gen_scatter_panel import SasGenWindow
+from sas.sasgui.perspectives.calculator.image_viewer import ImageView
+from sas.sasgui.perspectives.calculator.pyconsole import PyConsole
+import logging
+
+logger = logging.getLogger(__name__)
+
+class Plugin(PluginBase):
+ """
+ This class defines the interface for a Plugin class
+ for calculator perspective
+ """
+ def __init__(self):
+ PluginBase.__init__(self, name="Calculator")
+ # Log startup
+ logger.info("Calculator plug-in started")
+ self.sub_menu = "Tool"
+ self.data_edit_frame = None
+ # data operator use one frame all the time
+ self.data_operator_frame = None
+ self.kiessig_frame = None
+ self.sld_frame = None
+ self.cal_md_frame = None
+ self.cal_slit_frame = None
+ self.cal_res_frame = None
+ self.gen_frame = None
+ self.image_view = None
+ self.py_frame = None
+
+
+ def get_tools(self):
+ """
+ Returns a set of menu entries for tools
+ """
+ data_oper_help = "Perform arithmetic data operation (+...) "
+ data_oper_help += "and combination (|)"
+ kiessig_help = "Approximately computes the "
+ kiessig_help += "thickness of a shell or the size of "
+ kiessig_help += "particles \n from the width of a Kiessig fringe."
+ sld_help = "Computes the Scattering Length Density."
+ slit_length_help = "Computes the slit length from the beam profile."
+ resolution_help = "Approximately estimates the "
+ resolution_help += "resolution of Q in 2D based on the SAS "
+ resolution_help += "instrumental parameter values."
+ mass_volume_help = "Based on the chemical formula, "
+ mass_volume_help += "compute the mass density or the molar volume."
+ gensas_help = "Generic SAS"
+ pyconsole_help = "Python Console."
+ imageviewer_help = "Load an image file and display the image."
+ #data_editor_help = "Meta Data Editor"
+ return [("Data Operation",
+ data_oper_help, self.on_data_operation),
+ ("SLD Calculator", sld_help, self.on_calculate_sld),
+ ("Density/Volume Calculator", mass_volume_help,
+ self.on_calculate_dv),
+ ("Slit Size Calculator", slit_length_help,
+ self.on_calculate_slit_size),
+ ("Kiessig Thickness Calculator",
+ kiessig_help, self.on_calculate_kiessig),
+ ("Q Resolution Estimator",
+ resolution_help, self.on_calculate_resoltuion),
+ ("Generic Scattering Calculator",
+ gensas_help, self.on_gen_model),
+ ("Python Shell/Editor", pyconsole_help, self.on_python_console),
+ ("Image Viewer", imageviewer_help, self.on_image_viewer), ]
+
+ def on_edit_data(self, event):
+ """
+ Edit meta data
+ """
+ if self.data_edit_frame is None:
+ self.data_edit_frame = DataEditorWindow(parent=self.parent,
+ manager=self, data=[],
+ title="Data Editor")
+ self.put_icon(self.data_edit_frame)
+ else:
+ self.data_edit_frame.Show(False)
+ self.data_edit_frame.Show(True)
+
+ def on_data_operation(self, event):
+ """
+ Data operation
+ """
+ if self.data_operator_frame is None:
+ # Use one frame all the time
+ self.data_operator_frame = DataOperatorWindow(parent=self.parent,
+ manager=self,
+ title="Data Operation")
+ self.put_icon(self.data_operator_frame)
+ else:
+ self.data_operator_frame.Show(False)
+ self.data_operator_frame.panel.set_panel_on_focus(None)
+ self.data_operator_frame.Show(True)
+
+ def on_calculate_kiessig(self, event):
+ """
+ Compute the Kiessig thickness
+ """
+ if self.kiessig_frame is None:
+ frame = KiessigWindow(parent=self.parent, manager=self)
+ self.put_icon(frame)
+ self.kiessig_frame = frame
+ else:
+ self.kiessig_frame.Show(False)
+ self.kiessig_frame.Show(True)
+
+ def on_calculate_sld(self, event):
+ """
+ Compute the scattering length density of molecula
+ """
+ if self.sld_frame is None:
+ frame = SldWindow(parent=self.parent,
+ base=self.parent, manager=self)
+ self.put_icon(frame)
+ self.sld_frame = frame
+ else:
+ self.sld_frame.Show(False)
+ self.sld_frame.Show(True)
+
+ def on_calculate_dv(self, event):
+ """
+ Compute the mass density or molar voulme
+ """
+ if self.cal_md_frame is None:
+ frame = DensityWindow(parent=self.parent,
+ base=self.parent, manager=self)
+ self.put_icon(frame)
+ self.cal_md_frame = frame
+ else:
+ self.cal_md_frame.Show(False)
+ self.cal_md_frame.Show(True)
+
+ def on_calculate_slit_size(self, event):
+ """
+ Compute the slit size a given data
+ """
+ if self.cal_slit_frame is None:
+ frame = SlitLengthCalculatorWindow(parent=self.parent, manager=self)
+ self.put_icon(frame)
+ self.cal_slit_frame = frame
+ else:
+ self.cal_slit_frame.Show(False)
+ self.cal_slit_frame.Show(True)
+
+ def on_calculate_resoltuion(self, event):
+ """
+ Estimate the instrumental resolution
+ """
+ if self.cal_res_frame is None:
+ frame = ResolutionWindow(parent=self.parent, manager=self)
+ self.put_icon(frame)
+ self.cal_res_frame = frame
+ else:
+ self.cal_res_frame.Show(False)
+ self.cal_res_frame.Show(True)
+
+ def on_gen_model(self, event):
+ """
+ On Generic model menu event
+ """
+ if self.gen_frame is None:
+ frame = SasGenWindow(parent=self.parent, manager=self)
+ self.put_icon(frame)
+ self.gen_frame = frame
+ else:
+ self.gen_frame.Show(False)
+ self.gen_frame.Show(True)
+
+ def on_image_viewer(self, event):
+ """
+ Get choose an image file dialog
+
+ :param event: menu event
+ """
+ self.image_view = ImageView(parent=self.parent)
+ self.image_view.load()
+
+ def on_python_console(self, event):
+ """
+ Open Python Console
+
+ :param event: menu event
+ """
+ self.get_python_panel(filename=None)
+
+ def get_python_panel(self, filename=None):
+ """
+ Get the python shell panel
+
+ :param filename: file name to open in editor
+ """
+ if self.py_frame is None:
+ frame = PyConsole(parent=self.parent, base=self,
+ filename=filename)
+ self.put_icon(frame)
+ self.py_frame = frame
+ else:
+ self.py_frame.Show(False)
+ self.py_frame.Show(True)
+
+ def put_icon(self, frame):
+ """
+ Put icon in the frame title bar
+ """
+ if hasattr(frame, "IsIconized"):
+ if not frame.IsIconized():
+ try:
+ icon = self.parent.GetIcon()
+ frame.SetIcon(icon)
+ except:
+ pass
diff --git a/src/sas/sasgui/perspectives/calculator/calculator_widgets.py b/src/sas/sasgui/perspectives/calculator/calculator_widgets.py
index a267060..df2e996 100644
--- a/src/sas/sasgui/perspectives/calculator/calculator_widgets.py
+++ b/src/sas/sasgui/perspectives/calculator/calculator_widgets.py
@@ -1,97 +1,97 @@
-"""
-This software was developed by the University of Tennessee as part of the
-Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
-project funded by the US National Science Foundation.
-
-See the license text in license.txt
-
-copyright 2009, University of Tennessee
-"""
-import wx
-import sys
-CHILD_FRAME = wx.MDIChildFrame
-if sys.platform.count("win32") < 1:
- if sys.platform.count("darwin") < 1:
- CHILD_FRAME = wx.Frame
-
-class InputTextCtrl(wx.TextCtrl):
- """
- Text control for model and fit parameters.
- Binds the appropriate events for user interactions.
- """
- def __init__(self, parent=None, *args, **kwds):
-
- wx.TextCtrl.__init__(self, parent, *args, **kwds)
-
- ## Set to True when the mouse is clicked while the whole
- #string is selected
- self.full_selection = False
- ## Call back for EVT_SET_FOCUS events
- _on_set_focus_callback = None
- # Bind appropriate events
- self.Bind(wx.EVT_LEFT_UP, self._highlight_text)
- self.Bind(wx.EVT_SET_FOCUS, self._on_set_focus)
- self.Bind(wx.EVT_TEXT_ENTER, parent._onparamEnter)
-
- def _on_set_focus(self, event):
- """
- Catch when the text control is set in focus to highlight the whole
- text if necessary
- @param event: mouse event
- """
- event.Skip()
- self.full_selection = True
-
- def _highlight_text(self, event):
- """
- Highlight text of a TextCtrl only of no text has be selected
- @param event: mouse event
- """
- # Make sure the mouse event is available to other listeners
- event.Skip()
- control = event.GetEventObject()
- if self.full_selection:
- self.full_selection = False
- # Check that we have a TextCtrl
- if issubclass(control.__class__, wx.TextCtrl):
- # Check whether text has been selected,
- # if not, select the whole string
- (start, end) = control.GetSelection()
- if start == end:
- control.SetSelection(-1, -1)
-
-
-class InterActiveOutputTextCtrl(wx.TextCtrl):
- """
- Text control used to display outputs.
- No editing allowed. The background is
- grayed out. User can't select text.
- """
- def __init__(self, *args, **kwds):
- wx.TextCtrl.__init__(self, *args, **kwds)
- self.SetEditable(False)
- self.SetBackgroundColour(self.GetParent().GetBackgroundColour())
-
-class OutputTextCtrl(InterActiveOutputTextCtrl):
- """
- Text control used to display outputs.
- No editing allowed. The background is
- grayed out. User can't select text.
- """
- def __init__(self, *args, **kwds):
- InterActiveOutputTextCtrl.__init__(self, *args, **kwds)
- self.SetEditable(False)
- self.SetBackgroundColour(self.GetParent().GetBackgroundColour())
-
- # Bind to mouse event to avoid text highlighting
- # The event will be skipped once the call-back
- # is called.
- self.Bind(wx.EVT_MOUSE_EVENTS, self._click)
-
- def _click(self, event):
- """
- Prevent further handling of the mouse event
- by not calling Skip().
- """
- pass
-
+"""
+This software was developed by the University of Tennessee as part of the
+Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
+project funded by the US National Science Foundation.
+
+See the license text in license.txt
+
+copyright 2009, University of Tennessee
+"""
+import wx
+import sys
+CHILD_FRAME = wx.MDIChildFrame
+if sys.platform.count("win32") < 1:
+ if sys.platform.count("darwin") < 1:
+ CHILD_FRAME = wx.Frame
+
+class InputTextCtrl(wx.TextCtrl):
+ """
+ Text control for model and fit parameters.
+ Binds the appropriate events for user interactions.
+ """
+ def __init__(self, parent=None, *args, **kwds):
+
+ wx.TextCtrl.__init__(self, parent, *args, **kwds)
+
+ ## Set to True when the mouse is clicked while the whole
+ #string is selected
+ self.full_selection = False
+ ## Call back for EVT_SET_FOCUS events
+ _on_set_focus_callback = None
+ # Bind appropriate events
+ self.Bind(wx.EVT_LEFT_UP, self._highlight_text)
+ self.Bind(wx.EVT_SET_FOCUS, self._on_set_focus)
+ self.Bind(wx.EVT_TEXT_ENTER, parent._onparamEnter)
+
+ def _on_set_focus(self, event):
+ """
+ Catch when the text control is set in focus to highlight the whole
+ text if necessary
+ @param event: mouse event
+ """
+ event.Skip()
+ self.full_selection = True
+
+ def _highlight_text(self, event):
+ """
+ Highlight text of a TextCtrl only of no text has be selected
+ @param event: mouse event
+ """
+ # Make sure the mouse event is available to other listeners
+ event.Skip()
+ control = event.GetEventObject()
+ if self.full_selection:
+ self.full_selection = False
+ # Check that we have a TextCtrl
+ if issubclass(control.__class__, wx.TextCtrl):
+ # Check whether text has been selected,
+ # if not, select the whole string
+ (start, end) = control.GetSelection()
+ if start == end:
+ control.SetSelection(-1, -1)
+
+
+class InterActiveOutputTextCtrl(wx.TextCtrl):
+ """
+ Text control used to display outputs.
+ No editing allowed. The background is
+ grayed out. User can't select text.
+ """
+ def __init__(self, *args, **kwds):
+ wx.TextCtrl.__init__(self, *args, **kwds)
+ self.SetEditable(False)
+ self.SetBackgroundColour(self.GetParent().GetBackgroundColour())
+
+class OutputTextCtrl(InterActiveOutputTextCtrl):
+ """
+ Text control used to display outputs.
+ No editing allowed. The background is
+ grayed out. User can't select text.
+ """
+ def __init__(self, *args, **kwds):
+ InterActiveOutputTextCtrl.__init__(self, *args, **kwds)
+ self.SetEditable(False)
+ self.SetBackgroundColour(self.GetParent().GetBackgroundColour())
+
+ # Bind to mouse event to avoid text highlighting
+ # The event will be skipped once the call-back
+ # is called.
+ self.Bind(wx.EVT_MOUSE_EVENTS, self._click)
+
+ def _click(self, event):
+ """
+ Prevent further handling of the mouse event
+ by not calling Skip().
+ """
+ pass
+
diff --git a/src/sas/sasgui/perspectives/calculator/collimation_editor.py b/src/sas/sasgui/perspectives/calculator/collimation_editor.py
index 8536d5b..16647a1 100644
--- a/src/sas/sasgui/perspectives/calculator/collimation_editor.py
+++ b/src/sas/sasgui/perspectives/calculator/collimation_editor.py
@@ -1,547 +1,547 @@
-"""
-"""
-import wx
-import sys
-from copy import deepcopy
-from sas.sascalc.dataloader.loader import Loader
-from sas.sascalc.dataloader.data_info import Aperture, Collimation
-from aperture_editor import ApertureDialog
-
-from sas.sasgui.guiframe.utils import check_float
-_BOX_WIDTH = 60
-
-if sys.platform.count("win32") > 0:
- _STATICBOX_WIDTH = 500
- PANEL_WIDTH = 530
- PANEL_HEIGHT = 430
- FONT_VARIANT = 0
-else:
- _STATICBOX_WIDTH = 550
- PANEL_WIDTH = 600
- PANEL_HEIGHT = 480
- FONT_VARIANT = 1
-
-class CollimationDialog(wx.Dialog):
- """
- """
- def __init__(self, parent=None, manager=None,
- collimation=[], *args, **kwds):
- """
- """
- kwds['size'] = (PANEL_WIDTH, PANEL_HEIGHT)
- kwds['title'] = "Collimation Editor"
- wx.Dialog.__init__(self, parent=parent, *args, **kwds)
- self.parent = parent
- self.manager = manager
- self._collimation = collimation
- self._reset_collimation = deepcopy(collimation)
- self._notes = ""
- self._description = "Edit collimation"
- #layout attributes
- self.main_sizer = None
- self.box_collimation = None
- self.boxsizer_collimation = None
-
-
- self._do_layout()
- self.set_values()
-
- def _define_structure(self):
- """
- define initial sizer
- """
- self.main_sizer = wx.BoxSizer(wx.VERTICAL)
- self.box_collimation = wx.StaticBox(self, -1,
- str("Edit Selected Collimation"))
- self.boxsizer_collimation = wx.StaticBoxSizer(self.box_collimation,
- wx.VERTICAL)
-
- collimation_box = wx.StaticBox(self, -1, "Edit Number of Collimations")
- self.collimation_sizer = wx.StaticBoxSizer(collimation_box, wx.VERTICAL)
- self.collimation_sizer.SetMinSize((_STATICBOX_WIDTH, -1))
- self.collimation_button_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.collimation_hint_sizer = wx.BoxSizer(wx.HORIZONTAL)
-
- self.name_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.length_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.button_sizer = wx.BoxSizer(wx.HORIZONTAL)
-
- aperture_box = wx.StaticBox(self, -1, "Edit Aperture")
- self.aperture_sizer = wx.StaticBoxSizer(aperture_box, wx.VERTICAL)
- self.aperture_button_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.aperture_hint_sizer = wx.BoxSizer(wx.HORIZONTAL)
-
- def _layout_collimation(self):
- """
- Do the layout for collimation related widgets
- """
- collimation_name_txt = wx.StaticText(self, -1, "Collimation:")
- hint_collimation_txt = 'Current available collimation.'
- collimation_name_txt.SetToolTipString(hint_collimation_txt)
- self.collimation_cbox = wx.ComboBox(self, -1, style=wx.CB_READONLY)
- wx.EVT_COMBOBOX(self.collimation_cbox, -1, self.on_select_collimation)
- hint_collimation_name_txt = 'Name of collimations.'
- self.collimation_cbox.SetToolTipString(hint_collimation_name_txt)
-
- self.bt_add_collimation = wx.Button(self, -1, "Add")
- self.bt_add_collimation.SetToolTipString("Edit data's collimation.")
- self.bt_add_collimation.Bind(wx.EVT_BUTTON, self.add_collimation)
-
- self.bt_remove_collimation = wx.Button(self, -1, "Remove")
- hint = "Remove data's collimation."
- self.bt_remove_collimation.SetToolTipString(hint)
- self.bt_remove_collimation.Bind(wx.EVT_BUTTON, self.remove_collimation)
-
- self.collimation_button_sizer.AddMany([(collimation_name_txt, 0,
- wx.LEFT, 15),
- (self.collimation_cbox, 0, wx.LEFT, 5),
- (self.bt_add_collimation, 0, wx.LEFT, 10),
- (self.bt_remove_collimation,
- 0, wx.LEFT, 5)])
- collimation_hint_txt = 'No collimation is available for this data.'
- self.collimation_txt = wx.StaticText(self, -1, collimation_hint_txt)
- self.collimation_hint_sizer.Add(self.collimation_txt, 0, wx.LEFT, 10)
- self.collimation_sizer.AddMany([(self.collimation_button_sizer,
- 0, wx.ALL, 10),
- (self.collimation_hint_sizer,
- 0, wx.ALL, 10)])
-
- self.fill_collimation_combox()
- self.enable_collimation()
-
-
- def _layout_name(self):
- """
- Do the layout for collimation name related widgets
- """
- #Collimation name [string]
- name_txt = wx.StaticText(self, -1, 'Name : ')
- self.name_tcl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH * 5, 20), style=0)
- self.name_sizer.AddMany([(name_txt, 0, wx.LEFT | wx.RIGHT, 10),
- (self.name_tcl, 0, wx.EXPAND)])
-
- def _layout_length(self):
- """
- Do the layout for length related widgets
- """
- #Collimation length
- length_txt = wx.StaticText(self, -1, 'Length:')
- self.length_tcl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, 20), style=0)
- length_unit_txt = wx.StaticText(self, -1, 'Unit: ')
- self.length_unit_tcl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, 20),
- style=0)
- self.length_sizer.AddMany([(length_txt, 0, wx.LEFT | wx.RIGHT, 10),
- (self.length_tcl, 0, wx.LEFT, 12),
- (length_unit_txt, 0, wx.LEFT | wx.RIGHT, 10),
- (self.length_unit_tcl, 0, wx.EXPAND)])
-
- def _layout_button(self):
- """
- Do the layout for the button widgets
- """
- self.bt_apply = wx.Button(self, -1, 'Apply')
- self.bt_apply.Bind(wx.EVT_BUTTON, self.on_click_apply)
- self.bt_apply.SetToolTipString("Apply current changes to collimation.")
- self.bt_cancel = wx.Button(self, -1, 'Cancel')
- self.bt_cancel.SetToolTipString("Cancel current changes.")
- self.bt_cancel.Bind(wx.EVT_BUTTON, self.on_click_cancel)
- self.bt_close = wx.Button(self, wx.ID_CANCEL, 'Close')
- self.bt_close.SetToolTipString("Close window.")
- self.button_sizer.AddMany([(self.bt_apply, 0, wx.LEFT, 200),
- (self.bt_cancel, 0, wx.LEFT, 10),
- (self.bt_close, 0, wx.LEFT, 10)])
- def _layout_aperture(self):
- """
- Do the layout for aperture related widgets
- """
- aperture_name_txt = wx.StaticText(self, -1, "Aperture:")
- hint_aperture_txt = 'Current available aperture.'
- aperture_name_txt.SetToolTipString(hint_aperture_txt)
- self.aperture_cbox = wx.ComboBox(self, -1, style=wx.CB_READONLY)
- hint_aperture_name_txt = 'Name of apertures.'
- self.aperture_cbox.SetToolTipString(hint_aperture_name_txt)
-
- self.bt_add_aperture = wx.Button(self, -1, "Add")
- self.bt_add_aperture.SetToolTipString("Edit data's aperture.")
- self.bt_add_aperture.Bind(wx.EVT_BUTTON, self.add_aperture)
- self.bt_edit_aperture = wx.Button(self, -1, "Edit")
- self.bt_edit_aperture.SetToolTipString("Edit data's aperture.")
- self.bt_edit_aperture.Bind(wx.EVT_BUTTON, self.edit_aperture)
- self.bt_remove_aperture = wx.Button(self, -1, "Remove")
- self.bt_remove_aperture.SetToolTipString("Remove data's aperture.")
- self.bt_remove_aperture.Bind(wx.EVT_BUTTON, self.remove_aperture)
-
- self.aperture_button_sizer.AddMany([(aperture_name_txt, 0, wx.LEFT, 15),
- (self.aperture_cbox, 0, wx.LEFT, 5),
- (self.bt_add_aperture, 0, wx.LEFT, 10),
- (self.bt_edit_aperture, 0, wx.LEFT, 5),
- (self.bt_remove_aperture, 0, wx.LEFT, 5)])
- aperture_hint_txt = 'No aperture is available for this data.'
- self.aperture_txt = wx.StaticText(self, -1, aperture_hint_txt)
- self.aperture_hint_sizer.Add(self.aperture_txt, 0, wx.LEFT, 10)
- self.aperture_sizer.AddMany([(self.aperture_button_sizer,
- 0, wx.ALL, 10),
- (self.aperture_hint_sizer, 0, wx.ALL, 10)])
- self.fill_aperture_combox()
- self.enable_aperture()
-
- def _do_layout(self):
- """
- Draw the current panel
- """
- self._define_structure()
- self._layout_collimation()
- self._layout_name()
- self._layout_length()
- self._layout_aperture()
- self._layout_button()
-
- self.boxsizer_collimation.AddMany([(self.name_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
- (self.length_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
- (self.aperture_sizer, 0,
- wx.EXPAND | wx.ALL, 10)])
- self.main_sizer.AddMany([(self.collimation_sizer, 0, wx.ALL, 10),
- (self.boxsizer_collimation, 0, wx.ALL, 10),
- (self.button_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
- self.SetSizer(self.main_sizer)
- self.SetAutoLayout(True)
-
- def get_current_collimation(self):
- """
- """
- if not self.collimation_cbox.IsEnabled():
- return None, None, None
- position = self.collimation_cbox.GetSelection()
- if position == wx.NOT_FOUND:
- return None, None, None
- collimation_name = self.collimation_cbox.GetStringSelection()
- collimation = self.collimation_cbox.GetClientData(position)
- return collimation, collimation_name, position
-
- def fill_collimation_combox(self):
- """
- fill the current combobox with the available collimation
- """
- if self._collimation is None or self._collimation == []:
- return
- for collimation in self._collimation:
- pos = self.collimation_cbox.Append(str(collimation.name))
- self.collimation_cbox.SetClientData(pos, collimation)
- self.collimation_cbox.SetSelection(pos)
- self.collimation_cbox.SetStringSelection(str(collimation.name))
-
- def add_collimation(self, event):
- """
- Append empty collimation to data's list of collimation
- """
-
- if not self.collimation_cbox.IsEnabled():
- self.collimation_cbox.Enable()
- collimation = Collimation()
- self._collimation.append(collimation)
- position = self.collimation_cbox.Append(str(collimation.name))
- self.collimation_cbox.SetClientData(position, collimation)
- self.collimation_cbox.SetSelection(position)
- self.enable_collimation()
- self.bt_add_aperture.Enable()
- self.fill_aperture_combox()
- self.enable_aperture()
- self.set_values()
-
- def remove_collimation(self, event):
- """
- Remove collimation to data's list of collimation
- """
- if self.collimation_cbox.IsEnabled():
- if self.collimation_cbox.GetCount() > 0:
- position = self.collimation_cbox.GetCurrentSelection()
- collimation = self.collimation_cbox.GetClientData(position)
- if collimation in self._collimation:
- self._collimation.remove(collimation)
- self.collimation_cbox.Delete(position)
- #set the combo box box the next available item
- position = self.collimation_cbox.GetCount()
- if position > 0:
- position -= 1
- self.collimation_cbox.SetSelection(position)
- if not self._collimation and self.collimation_cbox.GetCount() == 0:
- self.bt_add_aperture.Disable()
- self.name_tcl.Clear()
- self.length_tcl.Clear()
- self.length_unit_tcl.Clear()
- self.aperture_cbox.Clear()
- self.aperture_cbox.Disable()
- #disable or enable the combo box when necessary
- self.enable_collimation()
- self.enable_aperture()
-
- def on_select_collimation(self, event):
- """
- fill the control on the panel according to
- the current selected collimation
- """
- self.set_values()
- self.fill_aperture_combox()
- self.enable_aperture()
-
- def enable_collimation(self):
- """
- Enable /disable widgets related to collimation
- """
- if self._collimation is not None and \
- self.collimation_cbox.GetCount() > 0:
- self.collimation_cbox.Enable()
- self.bt_remove_collimation.Enable()
- n_collimation = self.collimation_cbox.GetCount()
- collimation_hint_txt = "collimations"
- collimation_hint_txt += " available: %s " % str(n_collimation)
- if len(self._collimation) > 0:
- self.bt_remove_collimation.Enable()
- else:
- self.bt_remove_collimation.Disable()
- else:
- self.collimation_cbox.Disable()
- self.bt_remove_collimation.Disable()
- collimation_hint_txt = 'No collimation is available for this data.'
- self.collimation_txt.SetLabel(collimation_hint_txt)
-
-
- def reset_collimation_combobox(self, edited_collimation):
- """
- take all edited editor and reset clientdata of collimation combo box
- """
- for position in range(self.collimation_cbox.GetCount()):
- collimation = self.collimation_cbox.GetClientData(position)
- if collimation == edited_collimation:
- collimation = edited_collimation
- self.collimation_cbox.SetString(position, str(collimation.name))
- self.collimation_cbox.SetClientData(position, collimation)
- self.collimation_cbox.SetStringSelection(str(collimation.name))
-
- def add_aperture(self, event):
- """
- Append empty aperture to data's list of aperture
- """
- collimation, _, _ = self.get_current_collimation()
- if not self.aperture_cbox.IsEnabled():
- self.aperture_cbox.Enable()
- aperture = Aperture()
- collimation.aperture.append(aperture)
- position = self.aperture_cbox.Append(str(aperture.name))
- self.aperture_cbox.SetClientData(position, aperture)
- self.aperture_cbox.SetSelection(position)
- self.enable_aperture()
-
- def edit_aperture(self, event):
- """
- Edit the selected aperture
- """
- if self._collimation is None or not self.aperture_cbox.IsEnabled():
- return
- position = self.aperture_cbox.GetSelection()
- if position != wx.NOT_FOUND:
- name = self.aperture_cbox.GetStringSelection()
- aperture = self.aperture_cbox.GetClientData(position)
- dlg = ApertureDialog(parent=self, aperture=aperture)
- dlg.set_manager(self)
- dlg.ShowModal()
-
- def remove_aperture(self, event):
- """
- Remove aperture to data's list of aperture
- """
- if self._collimation is None or not self._collimation:
- return
- collimation, _, _ = self.get_current_collimation()
- if self.aperture_cbox.IsEnabled():
- if self.aperture_cbox.GetCount() > 1:
- position = self.aperture_cbox.GetCurrentSelection()
- aperture = self.aperture_cbox.GetClientData(position)
- if aperture in collimation.aperture:
- collimation.aperture.remove(aperture)
- self.aperture_cbox.Delete(position)
- #set the combo box box the next available item
- position = self.aperture_cbox.GetCount()
- if position > 0:
- position -= 1
- self.aperture_cbox.SetSelection(position)
-
- #disable or enable the combo box when necessary
- self.enable_aperture()
-
- def set_aperture(self, aperture):
- """
- set aperture for data
- """
- if self._collimation is None or not self._collimation:
- return
- collimation, _, _ = self.get_current_collimation()
- if collimation.aperture:
- for item in collimation.aperture:
- if item == aperture:
- item = aperture
- self.reset_aperture_combobox(edited_aperture=aperture)
- return
-
- def enable_aperture(self):
- """
- Enable /disable widgets crelated to aperture
- """
- collimation, _, _ = self.get_current_collimation()
- if self.aperture_cbox.GetCount() > 0:
- self.aperture_cbox.Enable()
- self.bt_edit_aperture.Enable()
- self.bt_remove_aperture.Enable()
- n_aperture = self.aperture_cbox.GetCount()
- aperture_hint_txt = 'apertures available: %s ' % str(n_aperture)
- if len(collimation.aperture) > 0:
- self.bt_remove_aperture.Enable()
- else:
- self.bt_remove_aperture.Disable()
- else:
- self.aperture_cbox.Disable()
- self.bt_edit_aperture.Disable()
- self.bt_remove_aperture.Disable()
- aperture_hint_txt = 'No aperture is available for this data.'
- self.aperture_txt.SetLabel(aperture_hint_txt)
-
- def reset_aperture_combobox(self, edited_aperture):
- """
- take all edited editor and reset clientdata of aperture combo box
- """
- for position in range(self.aperture_cbox.GetCount()):
- aperture = self.aperture_cbox.GetClientData(position)
- if aperture == edited_aperture:
- aperture = edited_aperture
- self.aperture_cbox.SetString(position, str(aperture.name))
- self.aperture_cbox.SetClientData(position, aperture)
- self.aperture_cbox.SetStringSelection(str(aperture.name))
-
- def fill_aperture_combox(self):
- """
- fill the current combobox with the available aperture
- """
- self.aperture_cbox.Clear()
- collimation, _, _ = self.get_current_collimation()
- if collimation is None or not collimation.aperture:
- return
- for aperture in collimation.aperture:
- pos = self.aperture_cbox.Append(str(aperture.name))
- self.aperture_cbox.SetClientData(pos, aperture)
- self.aperture_cbox.SetSelection(pos)
- self.aperture_cbox.SetStringSelection(str(aperture.name))
-
- def set_manager(self, manager):
- """
- Set manager of this window
- """
- self.manager = manager
-
- def set_values(self):
- """
- take the collimation values of the current data and display them
- through the panel
- """
- collimation, _, _ = self.get_current_collimation()
- if collimation is None:
- self.bt_add_aperture.Disable()
- self.length_tcl.SetValue("")
- self.name_tcl.SetValue("")
- self.length_unit_tcl.SetValue("")
- return
- #Name
- self.name_tcl.SetValue(str(collimation.name))
- #length
- self.length_tcl.SetValue(str(collimation.length))
- #Length unit
- self.length_unit_tcl.SetValue(str(collimation.length_unit))
-
- def get_collimation(self):
- """
- return the current collimation
- """
- return self._collimation
-
- def get_notes(self):
- """
- return notes
- """
- return self._notes
-
- def on_change_name(self):
- """
- Change name
- """
- collimation, collimation_name, position = self.get_current_collimation()
- if collimation is None:
- return
- #Change the name of the collimation
- name = self.name_tcl.GetValue().lstrip().rstrip()
- if name == "" or name == str(None):
- name = None
- if collimation.name != name:
- self._notes += "Change collimation 's "
- self._notes += "name from %s to %s \n" % (collimation.name, name)
- collimation.name = name
- self.collimation_cbox.SetString(position, str(collimation.name))
- self.collimation_cbox.SetClientData(position, collimation)
- self.collimation_cbox.SetStringSelection(str(collimation.name))
-
- def on_change_length(self):
- """
- Change the length
- """
- collimation, collimation_name, position = self.get_current_collimation()
- if collimation is None:
- return
- #Change length
- length = self.length_tcl.GetValue().lstrip().rstrip()
- if length == "" or length == str(None):
- length = None
- collimation.length = length
- else:
- if check_float(self.length_tcl):
- if collimation.length != float(length):
- self._notes += "Change Collimation length from "
- self._notes += "%s to %s \n" % (collimation.length, length)
- collimation.length = float(length)
- else:
- self._notes += "Error: Expected a float for collimation length"
- self._notes += " won't changes length from "
- self._notes += "%s to %s" % (collimation.length, length)
- #change length unit
- unit = self.length_unit_tcl.GetValue().lstrip().rstrip()
- if collimation.length_unit != unit:
- self._notes += " Change length's unit from "
- self._notes += "%s to %s" % (collimation.length_unit, unit)
- collimation.length_unit = unit
-
- def on_click_apply(self, event):
- """
- Apply user values to the collimation
- """
- self.on_change_name()
- self.on_change_length()
- self.set_values()
- if self.manager is not None:
- self.manager.set_collimation(self._collimation, self._notes)
-
- def on_click_cancel(self, event):
- """
- leave the collimation as it is and close
- """
- self._collimation = deepcopy(self._reset_collimation)
- self.set_values()
- if self.manager is not None:
- self.manager.set_collimation(self._collimation)
-
-
-if __name__ == "__main__":
-
- app = wx.App()
- dlg = CollimationDialog(collimation=[Collimation()])
- dlg.ShowModal()
- app.MainLoop()
+"""
+"""
+import wx
+import sys
+from copy import deepcopy
+from sas.sascalc.dataloader.loader import Loader
+from sas.sascalc.dataloader.data_info import Aperture, Collimation
+from aperture_editor import ApertureDialog
+
+from sas.sasgui.guiframe.utils import check_float
+_BOX_WIDTH = 60
+
+if sys.platform.count("win32") > 0:
+ _STATICBOX_WIDTH = 500
+ PANEL_WIDTH = 530
+ PANEL_HEIGHT = 430
+ FONT_VARIANT = 0
+else:
+ _STATICBOX_WIDTH = 550
+ PANEL_WIDTH = 600
+ PANEL_HEIGHT = 480
+ FONT_VARIANT = 1
+
+class CollimationDialog(wx.Dialog):
+ """
+ """
+ def __init__(self, parent=None, manager=None,
+ collimation=[], *args, **kwds):
+ """
+ """
+ kwds['size'] = (PANEL_WIDTH, PANEL_HEIGHT)
+ kwds['title'] = "Collimation Editor"
+ wx.Dialog.__init__(self, parent=parent, *args, **kwds)
+ self.parent = parent
+ self.manager = manager
+ self._collimation = collimation
+ self._reset_collimation = deepcopy(collimation)
+ self._notes = ""
+ self._description = "Edit collimation"
+ #layout attributes
+ self.main_sizer = None
+ self.box_collimation = None
+ self.boxsizer_collimation = None
+
+
+ self._do_layout()
+ self.set_values()
+
+ def _define_structure(self):
+ """
+ define initial sizer
+ """
+ self.main_sizer = wx.BoxSizer(wx.VERTICAL)
+ self.box_collimation = wx.StaticBox(self, -1,
+ str("Edit Selected Collimation"))
+ self.boxsizer_collimation = wx.StaticBoxSizer(self.box_collimation,
+ wx.VERTICAL)
+
+ collimation_box = wx.StaticBox(self, -1, "Edit Number of Collimations")
+ self.collimation_sizer = wx.StaticBoxSizer(collimation_box, wx.VERTICAL)
+ self.collimation_sizer.SetMinSize((_STATICBOX_WIDTH, -1))
+ self.collimation_button_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.collimation_hint_sizer = wx.BoxSizer(wx.HORIZONTAL)
+
+ self.name_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.length_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.button_sizer = wx.BoxSizer(wx.HORIZONTAL)
+
+ aperture_box = wx.StaticBox(self, -1, "Edit Aperture")
+ self.aperture_sizer = wx.StaticBoxSizer(aperture_box, wx.VERTICAL)
+ self.aperture_button_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.aperture_hint_sizer = wx.BoxSizer(wx.HORIZONTAL)
+
+ def _layout_collimation(self):
+ """
+ Do the layout for collimation related widgets
+ """
+ collimation_name_txt = wx.StaticText(self, -1, "Collimation:")
+ hint_collimation_txt = 'Current available collimation.'
+ collimation_name_txt.SetToolTipString(hint_collimation_txt)
+ self.collimation_cbox = wx.ComboBox(self, -1, style=wx.CB_READONLY)
+ wx.EVT_COMBOBOX(self.collimation_cbox, -1, self.on_select_collimation)
+ hint_collimation_name_txt = 'Name of collimations.'
+ self.collimation_cbox.SetToolTipString(hint_collimation_name_txt)
+
+ self.bt_add_collimation = wx.Button(self, -1, "Add")
+ self.bt_add_collimation.SetToolTipString("Edit data's collimation.")
+ self.bt_add_collimation.Bind(wx.EVT_BUTTON, self.add_collimation)
+
+ self.bt_remove_collimation = wx.Button(self, -1, "Remove")
+ hint = "Remove data's collimation."
+ self.bt_remove_collimation.SetToolTipString(hint)
+ self.bt_remove_collimation.Bind(wx.EVT_BUTTON, self.remove_collimation)
+
+ self.collimation_button_sizer.AddMany([(collimation_name_txt, 0,
+ wx.LEFT, 15),
+ (self.collimation_cbox, 0, wx.LEFT, 5),
+ (self.bt_add_collimation, 0, wx.LEFT, 10),
+ (self.bt_remove_collimation,
+ 0, wx.LEFT, 5)])
+ collimation_hint_txt = 'No collimation is available for this data.'
+ self.collimation_txt = wx.StaticText(self, -1, collimation_hint_txt)
+ self.collimation_hint_sizer.Add(self.collimation_txt, 0, wx.LEFT, 10)
+ self.collimation_sizer.AddMany([(self.collimation_button_sizer,
+ 0, wx.ALL, 10),
+ (self.collimation_hint_sizer,
+ 0, wx.ALL, 10)])
+
+ self.fill_collimation_combox()
+ self.enable_collimation()
+
+
+ def _layout_name(self):
+ """
+ Do the layout for collimation name related widgets
+ """
+ #Collimation name [string]
+ name_txt = wx.StaticText(self, -1, 'Name : ')
+ self.name_tcl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH * 5, 20), style=0)
+ self.name_sizer.AddMany([(name_txt, 0, wx.LEFT | wx.RIGHT, 10),
+ (self.name_tcl, 0, wx.EXPAND)])
+
+ def _layout_length(self):
+ """
+ Do the layout for length related widgets
+ """
+ #Collimation length
+ length_txt = wx.StaticText(self, -1, 'Length:')
+ self.length_tcl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, 20), style=0)
+ length_unit_txt = wx.StaticText(self, -1, 'Unit: ')
+ self.length_unit_tcl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, 20),
+ style=0)
+ self.length_sizer.AddMany([(length_txt, 0, wx.LEFT | wx.RIGHT, 10),
+ (self.length_tcl, 0, wx.LEFT, 12),
+ (length_unit_txt, 0, wx.LEFT | wx.RIGHT, 10),
+ (self.length_unit_tcl, 0, wx.EXPAND)])
+
+ def _layout_button(self):
+ """
+ Do the layout for the button widgets
+ """
+ self.bt_apply = wx.Button(self, -1, 'Apply')
+ self.bt_apply.Bind(wx.EVT_BUTTON, self.on_click_apply)
+ self.bt_apply.SetToolTipString("Apply current changes to collimation.")
+ self.bt_cancel = wx.Button(self, -1, 'Cancel')
+ self.bt_cancel.SetToolTipString("Cancel current changes.")
+ self.bt_cancel.Bind(wx.EVT_BUTTON, self.on_click_cancel)
+ self.bt_close = wx.Button(self, wx.ID_CANCEL, 'Close')
+ self.bt_close.SetToolTipString("Close window.")
+ self.button_sizer.AddMany([(self.bt_apply, 0, wx.LEFT, 200),
+ (self.bt_cancel, 0, wx.LEFT, 10),
+ (self.bt_close, 0, wx.LEFT, 10)])
+ def _layout_aperture(self):
+ """
+ Do the layout for aperture related widgets
+ """
+ aperture_name_txt = wx.StaticText(self, -1, "Aperture:")
+ hint_aperture_txt = 'Current available aperture.'
+ aperture_name_txt.SetToolTipString(hint_aperture_txt)
+ self.aperture_cbox = wx.ComboBox(self, -1, style=wx.CB_READONLY)
+ hint_aperture_name_txt = 'Name of apertures.'
+ self.aperture_cbox.SetToolTipString(hint_aperture_name_txt)
+
+ self.bt_add_aperture = wx.Button(self, -1, "Add")
+ self.bt_add_aperture.SetToolTipString("Edit data's aperture.")
+ self.bt_add_aperture.Bind(wx.EVT_BUTTON, self.add_aperture)
+ self.bt_edit_aperture = wx.Button(self, -1, "Edit")
+ self.bt_edit_aperture.SetToolTipString("Edit data's aperture.")
+ self.bt_edit_aperture.Bind(wx.EVT_BUTTON, self.edit_aperture)
+ self.bt_remove_aperture = wx.Button(self, -1, "Remove")
+ self.bt_remove_aperture.SetToolTipString("Remove data's aperture.")
+ self.bt_remove_aperture.Bind(wx.EVT_BUTTON, self.remove_aperture)
+
+ self.aperture_button_sizer.AddMany([(aperture_name_txt, 0, wx.LEFT, 15),
+ (self.aperture_cbox, 0, wx.LEFT, 5),
+ (self.bt_add_aperture, 0, wx.LEFT, 10),
+ (self.bt_edit_aperture, 0, wx.LEFT, 5),
+ (self.bt_remove_aperture, 0, wx.LEFT, 5)])
+ aperture_hint_txt = 'No aperture is available for this data.'
+ self.aperture_txt = wx.StaticText(self, -1, aperture_hint_txt)
+ self.aperture_hint_sizer.Add(self.aperture_txt, 0, wx.LEFT, 10)
+ self.aperture_sizer.AddMany([(self.aperture_button_sizer,
+ 0, wx.ALL, 10),
+ (self.aperture_hint_sizer, 0, wx.ALL, 10)])
+ self.fill_aperture_combox()
+ self.enable_aperture()
+
+ def _do_layout(self):
+ """
+ Draw the current panel
+ """
+ self._define_structure()
+ self._layout_collimation()
+ self._layout_name()
+ self._layout_length()
+ self._layout_aperture()
+ self._layout_button()
+
+ self.boxsizer_collimation.AddMany([(self.name_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
+ (self.length_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
+ (self.aperture_sizer, 0,
+ wx.EXPAND | wx.ALL, 10)])
+ self.main_sizer.AddMany([(self.collimation_sizer, 0, wx.ALL, 10),
+ (self.boxsizer_collimation, 0, wx.ALL, 10),
+ (self.button_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
+ self.SetSizer(self.main_sizer)
+ self.SetAutoLayout(True)
+
+ def get_current_collimation(self):
+ """
+ """
+ if not self.collimation_cbox.IsEnabled():
+ return None, None, None
+ position = self.collimation_cbox.GetSelection()
+ if position == wx.NOT_FOUND:
+ return None, None, None
+ collimation_name = self.collimation_cbox.GetStringSelection()
+ collimation = self.collimation_cbox.GetClientData(position)
+ return collimation, collimation_name, position
+
+ def fill_collimation_combox(self):
+ """
+ fill the current combobox with the available collimation
+ """
+ if self._collimation is None or self._collimation == []:
+ return
+ for collimation in self._collimation:
+ pos = self.collimation_cbox.Append(str(collimation.name))
+ self.collimation_cbox.SetClientData(pos, collimation)
+ self.collimation_cbox.SetSelection(pos)
+ self.collimation_cbox.SetStringSelection(str(collimation.name))
+
+ def add_collimation(self, event):
+ """
+ Append empty collimation to data's list of collimation
+ """
+
+ if not self.collimation_cbox.IsEnabled():
+ self.collimation_cbox.Enable()
+ collimation = Collimation()
+ self._collimation.append(collimation)
+ position = self.collimation_cbox.Append(str(collimation.name))
+ self.collimation_cbox.SetClientData(position, collimation)
+ self.collimation_cbox.SetSelection(position)
+ self.enable_collimation()
+ self.bt_add_aperture.Enable()
+ self.fill_aperture_combox()
+ self.enable_aperture()
+ self.set_values()
+
+ def remove_collimation(self, event):
+ """
+ Remove collimation to data's list of collimation
+ """
+ if self.collimation_cbox.IsEnabled():
+ if self.collimation_cbox.GetCount() > 0:
+ position = self.collimation_cbox.GetCurrentSelection()
+ collimation = self.collimation_cbox.GetClientData(position)
+ if collimation in self._collimation:
+ self._collimation.remove(collimation)
+ self.collimation_cbox.Delete(position)
+ #set the combo box box the next available item
+ position = self.collimation_cbox.GetCount()
+ if position > 0:
+ position -= 1
+ self.collimation_cbox.SetSelection(position)
+ if not self._collimation and self.collimation_cbox.GetCount() == 0:
+ self.bt_add_aperture.Disable()
+ self.name_tcl.Clear()
+ self.length_tcl.Clear()
+ self.length_unit_tcl.Clear()
+ self.aperture_cbox.Clear()
+ self.aperture_cbox.Disable()
+ #disable or enable the combo box when necessary
+ self.enable_collimation()
+ self.enable_aperture()
+
+ def on_select_collimation(self, event):
+ """
+ fill the control on the panel according to
+ the current selected collimation
+ """
+ self.set_values()
+ self.fill_aperture_combox()
+ self.enable_aperture()
+
+ def enable_collimation(self):
+ """
+ Enable /disable widgets related to collimation
+ """
+ if self._collimation is not None and \
+ self.collimation_cbox.GetCount() > 0:
+ self.collimation_cbox.Enable()
+ self.bt_remove_collimation.Enable()
+ n_collimation = self.collimation_cbox.GetCount()
+ collimation_hint_txt = "collimations"
+ collimation_hint_txt += " available: %s " % str(n_collimation)
+ if len(self._collimation) > 0:
+ self.bt_remove_collimation.Enable()
+ else:
+ self.bt_remove_collimation.Disable()
+ else:
+ self.collimation_cbox.Disable()
+ self.bt_remove_collimation.Disable()
+ collimation_hint_txt = 'No collimation is available for this data.'
+ self.collimation_txt.SetLabel(collimation_hint_txt)
+
+
+ def reset_collimation_combobox(self, edited_collimation):
+ """
+ take all edited editor and reset clientdata of collimation combo box
+ """
+ for position in range(self.collimation_cbox.GetCount()):
+ collimation = self.collimation_cbox.GetClientData(position)
+ if collimation == edited_collimation:
+ collimation = edited_collimation
+ self.collimation_cbox.SetString(position, str(collimation.name))
+ self.collimation_cbox.SetClientData(position, collimation)
+ self.collimation_cbox.SetStringSelection(str(collimation.name))
+
+ def add_aperture(self, event):
+ """
+ Append empty aperture to data's list of aperture
+ """
+ collimation, _, _ = self.get_current_collimation()
+ if not self.aperture_cbox.IsEnabled():
+ self.aperture_cbox.Enable()
+ aperture = Aperture()
+ collimation.aperture.append(aperture)
+ position = self.aperture_cbox.Append(str(aperture.name))
+ self.aperture_cbox.SetClientData(position, aperture)
+ self.aperture_cbox.SetSelection(position)
+ self.enable_aperture()
+
+ def edit_aperture(self, event):
+ """
+ Edit the selected aperture
+ """
+ if self._collimation is None or not self.aperture_cbox.IsEnabled():
+ return
+ position = self.aperture_cbox.GetSelection()
+ if position != wx.NOT_FOUND:
+ name = self.aperture_cbox.GetStringSelection()
+ aperture = self.aperture_cbox.GetClientData(position)
+ dlg = ApertureDialog(parent=self, aperture=aperture)
+ dlg.set_manager(self)
+ dlg.ShowModal()
+
+ def remove_aperture(self, event):
+ """
+ Remove aperture to data's list of aperture
+ """
+ if self._collimation is None or not self._collimation:
+ return
+ collimation, _, _ = self.get_current_collimation()
+ if self.aperture_cbox.IsEnabled():
+ if self.aperture_cbox.GetCount() > 1:
+ position = self.aperture_cbox.GetCurrentSelection()
+ aperture = self.aperture_cbox.GetClientData(position)
+ if aperture in collimation.aperture:
+ collimation.aperture.remove(aperture)
+ self.aperture_cbox.Delete(position)
+ #set the combo box box the next available item
+ position = self.aperture_cbox.GetCount()
+ if position > 0:
+ position -= 1
+ self.aperture_cbox.SetSelection(position)
+
+ #disable or enable the combo box when necessary
+ self.enable_aperture()
+
+ def set_aperture(self, aperture):
+ """
+ set aperture for data
+ """
+ if self._collimation is None or not self._collimation:
+ return
+ collimation, _, _ = self.get_current_collimation()
+ if collimation.aperture:
+ for item in collimation.aperture:
+ if item == aperture:
+ item = aperture
+ self.reset_aperture_combobox(edited_aperture=aperture)
+ return
+
+ def enable_aperture(self):
+ """
+ Enable /disable widgets crelated to aperture
+ """
+ collimation, _, _ = self.get_current_collimation()
+ if self.aperture_cbox.GetCount() > 0:
+ self.aperture_cbox.Enable()
+ self.bt_edit_aperture.Enable()
+ self.bt_remove_aperture.Enable()
+ n_aperture = self.aperture_cbox.GetCount()
+ aperture_hint_txt = 'apertures available: %s ' % str(n_aperture)
+ if len(collimation.aperture) > 0:
+ self.bt_remove_aperture.Enable()
+ else:
+ self.bt_remove_aperture.Disable()
+ else:
+ self.aperture_cbox.Disable()
+ self.bt_edit_aperture.Disable()
+ self.bt_remove_aperture.Disable()
+ aperture_hint_txt = 'No aperture is available for this data.'
+ self.aperture_txt.SetLabel(aperture_hint_txt)
+
+ def reset_aperture_combobox(self, edited_aperture):
+ """
+ take all edited editor and reset clientdata of aperture combo box
+ """
+ for position in range(self.aperture_cbox.GetCount()):
+ aperture = self.aperture_cbox.GetClientData(position)
+ if aperture == edited_aperture:
+ aperture = edited_aperture
+ self.aperture_cbox.SetString(position, str(aperture.name))
+ self.aperture_cbox.SetClientData(position, aperture)
+ self.aperture_cbox.SetStringSelection(str(aperture.name))
+
+ def fill_aperture_combox(self):
+ """
+ fill the current combobox with the available aperture
+ """
+ self.aperture_cbox.Clear()
+ collimation, _, _ = self.get_current_collimation()
+ if collimation is None or not collimation.aperture:
+ return
+ for aperture in collimation.aperture:
+ pos = self.aperture_cbox.Append(str(aperture.name))
+ self.aperture_cbox.SetClientData(pos, aperture)
+ self.aperture_cbox.SetSelection(pos)
+ self.aperture_cbox.SetStringSelection(str(aperture.name))
+
+ def set_manager(self, manager):
+ """
+ Set manager of this window
+ """
+ self.manager = manager
+
+ def set_values(self):
+ """
+ take the collimation values of the current data and display them
+ through the panel
+ """
+ collimation, _, _ = self.get_current_collimation()
+ if collimation is None:
+ self.bt_add_aperture.Disable()
+ self.length_tcl.SetValue("")
+ self.name_tcl.SetValue("")
+ self.length_unit_tcl.SetValue("")
+ return
+ #Name
+ self.name_tcl.SetValue(str(collimation.name))
+ #length
+ self.length_tcl.SetValue(str(collimation.length))
+ #Length unit
+ self.length_unit_tcl.SetValue(str(collimation.length_unit))
+
+ def get_collimation(self):
+ """
+ return the current collimation
+ """
+ return self._collimation
+
+ def get_notes(self):
+ """
+ return notes
+ """
+ return self._notes
+
+ def on_change_name(self):
+ """
+ Change name
+ """
+ collimation, collimation_name, position = self.get_current_collimation()
+ if collimation is None:
+ return
+ #Change the name of the collimation
+ name = self.name_tcl.GetValue().lstrip().rstrip()
+ if name == "" or name == str(None):
+ name = None
+ if collimation.name != name:
+ self._notes += "Change collimation 's "
+ self._notes += "name from %s to %s \n" % (collimation.name, name)
+ collimation.name = name
+ self.collimation_cbox.SetString(position, str(collimation.name))
+ self.collimation_cbox.SetClientData(position, collimation)
+ self.collimation_cbox.SetStringSelection(str(collimation.name))
+
+ def on_change_length(self):
+ """
+ Change the length
+ """
+ collimation, collimation_name, position = self.get_current_collimation()
+ if collimation is None:
+ return
+ #Change length
+ length = self.length_tcl.GetValue().lstrip().rstrip()
+ if length == "" or length == str(None):
+ length = None
+ collimation.length = length
+ else:
+ if check_float(self.length_tcl):
+ if collimation.length != float(length):
+ self._notes += "Change Collimation length from "
+ self._notes += "%s to %s \n" % (collimation.length, length)
+ collimation.length = float(length)
+ else:
+ self._notes += "Error: Expected a float for collimation length"
+ self._notes += " won't changes length from "
+ self._notes += "%s to %s" % (collimation.length, length)
+ #change length unit
+ unit = self.length_unit_tcl.GetValue().lstrip().rstrip()
+ if collimation.length_unit != unit:
+ self._notes += " Change length's unit from "
+ self._notes += "%s to %s" % (collimation.length_unit, unit)
+ collimation.length_unit = unit
+
+ def on_click_apply(self, event):
+ """
+ Apply user values to the collimation
+ """
+ self.on_change_name()
+ self.on_change_length()
+ self.set_values()
+ if self.manager is not None:
+ self.manager.set_collimation(self._collimation, self._notes)
+
+ def on_click_cancel(self, event):
+ """
+ leave the collimation as it is and close
+ """
+ self._collimation = deepcopy(self._reset_collimation)
+ self.set_values()
+ if self.manager is not None:
+ self.manager.set_collimation(self._collimation)
+
+
+if __name__ == "__main__":
+
+ app = wx.App()
+ dlg = CollimationDialog(collimation=[Collimation()])
+ dlg.ShowModal()
+ app.MainLoop()
diff --git a/src/sas/sasgui/perspectives/calculator/console.py b/src/sas/sasgui/perspectives/calculator/console.py
index 9803604..f729749 100644
--- a/src/sas/sasgui/perspectives/calculator/console.py
+++ b/src/sas/sasgui/perspectives/calculator/console.py
@@ -1,66 +1,66 @@
-"""
-Console Module display message of a dialog
-"""
-import wx
-import sys
-from sas.sascalc.dataloader.loader import Loader
-
-_BOX_WIDTH = 60
-CONSOLE_WIDTH = 340
-CONSOLE_HEIGHT = 240
-if sys.platform.count("win32") > 0:
- _STATICBOX_WIDTH = 450
- PANEL_WIDTH = 500
- PANEL_HEIGHT = 550
- FONT_VARIANT = 0
-else:
- _STATICBOX_WIDTH = 480
- PANEL_WIDTH = 530
- PANEL_HEIGHT = 560
- FONT_VARIANT = 1
-
-class ConsoleDialog(wx.Dialog):
- """
- Data summary dialog
- """
- def __init__(self, parent=None, manager=None, data=None,
- title="Data Summary", size=(PANEL_WIDTH, PANEL_HEIGHT)):
- wx.Dialog.__init__(self, parent=parent, title=title, size=size)
-
- self.parent = parent
- self._manager = manager
- self._data = data
- self.sizer = wx.BoxSizer(wx.VERTICAL)
- self.msg_txt = wx.TextCtrl(self, size=(PANEL_WIDTH - 40,
- PANEL_HEIGHT - 60),
- style=wx.TE_MULTILINE)
- self.msg_txt.SetEditable(False)
- self.msg_txt.SetValue('No message available')
- self.sizer.Add(self.msg_txt, 1, wx.EXPAND | wx.ALL, 10)
- if self._data is not None:
- self.set_message(msg=self._data.__str__())
-
- self.SetSizer(self.sizer)
-
- def set_manager(self, manager):
- """
- Set the manager of this window
- """
- self._manager = manager
-
- def set_message(self, msg=""):
- """
- Display the message received
- """
- self.msg_txt.SetValue(str(msg))
-
-if __name__ == "__main__":
-
- app = wx.App()
- # Instantiate a loader
- loader = Loader()
- # Load data
- test_data = loader.load("MAR07232_rest.ASC")
- dlg = ConsoleDialog(data=test_data)
- dlg.ShowModal()
- app.MainLoop()
+"""
+Console Module display message of a dialog
+"""
+import wx
+import sys
+from sas.sascalc.dataloader.loader import Loader
+
+_BOX_WIDTH = 60
+CONSOLE_WIDTH = 340
+CONSOLE_HEIGHT = 240
+if sys.platform.count("win32") > 0:
+ _STATICBOX_WIDTH = 450
+ PANEL_WIDTH = 500
+ PANEL_HEIGHT = 550
+ FONT_VARIANT = 0
+else:
+ _STATICBOX_WIDTH = 480
+ PANEL_WIDTH = 530
+ PANEL_HEIGHT = 560
+ FONT_VARIANT = 1
+
+class ConsoleDialog(wx.Dialog):
+ """
+ Data summary dialog
+ """
+ def __init__(self, parent=None, manager=None, data=None,
+ title="Data Summary", size=(PANEL_WIDTH, PANEL_HEIGHT)):
+ wx.Dialog.__init__(self, parent=parent, title=title, size=size)
+
+ self.parent = parent
+ self._manager = manager
+ self._data = data
+ self.sizer = wx.BoxSizer(wx.VERTICAL)
+ self.msg_txt = wx.TextCtrl(self, size=(PANEL_WIDTH - 40,
+ PANEL_HEIGHT - 60),
+ style=wx.TE_MULTILINE)
+ self.msg_txt.SetEditable(False)
+ self.msg_txt.SetValue('No message available')
+ self.sizer.Add(self.msg_txt, 1, wx.EXPAND | wx.ALL, 10)
+ if self._data is not None:
+ self.set_message(msg=self._data.__str__())
+
+ self.SetSizer(self.sizer)
+
+ def set_manager(self, manager):
+ """
+ Set the manager of this window
+ """
+ self._manager = manager
+
+ def set_message(self, msg=""):
+ """
+ Display the message received
+ """
+ self.msg_txt.SetValue(str(msg))
+
+if __name__ == "__main__":
+
+ app = wx.App()
+ # Instantiate a loader
+ loader = Loader()
+ # Load data
+ test_data = loader.load("MAR07232_rest.ASC")
+ dlg = ConsoleDialog(data=test_data)
+ dlg.ShowModal()
+ app.MainLoop()
diff --git a/src/sas/sasgui/perspectives/calculator/data_editor.py b/src/sas/sasgui/perspectives/calculator/data_editor.py
index 217fc11..cec0f3f 100644
--- a/src/sas/sasgui/perspectives/calculator/data_editor.py
+++ b/src/sas/sasgui/perspectives/calculator/data_editor.py
@@ -1,652 +1,652 @@
-
-import wx
-import sys
-import os
-from copy import deepcopy
-
-from sas.sascalc.dataloader.loader import Loader
-from sas.sascalc.dataloader.data_info import Data2D
-from detector_editor import DetectorDialog
-from collimation_editor import CollimationDialog
-from console import ConsoleDialog
-
-from sas.sasgui.guiframe.events import StatusEvent
-
-
-_QMIN_DEFAULT = 0.001
-_QMAX_DEFAULT = 0.13
-_NPTS_DEFAULT = 50
-#Control panel width
-if sys.platform.count("darwin") == 0:
- PANEL_WIDTH = 500
- PANEL_HEIGTH = 350
- FONT_VARIANT = 0
- _BOX_WIDTH = 51
- ON_MAC = False
-else:
- _BOX_WIDTH = 76
- PANEL_WIDTH = 550
- PANEL_HEIGTH = 400
- FONT_VARIANT = 1
- ON_MAC = True
-
-def load_error(error=None):
- """
- Pop up an error message.
-
- @param error: details error message to be displayed
- """
- message = "You had to try this, didn't you?\n\n"
- message += "The data file you selected could not be loaded.\n"
- message += "Make sure the content of your file is properly formatted.\n\n"
-
- if error is not None:
- message += "When contacting the SasView team,"
- message += " mention the following:\n%s" % str(error)
-
- dial = wx.MessageDialog(None, message,
- 'Error Loading File', wx.OK | wx.ICON_EXCLAMATION)
- dial.ShowModal()
-
-
-class DataEditorPanel(wx.ScrolledWindow):
- """
- :param data: when not empty the class can
- same information into a dat object
- and post event containing the changed data object to some other frame
- """
- def __init__(self, parent, data=[], *args, **kwds):
- kwds['name'] = "Data Editor"
- kwds["size"] = (PANEL_WIDTH, PANEL_HEIGTH)
- wx.ScrolledWindow.__init__(self, parent, *args, **kwds)
- self.parent = parent
- self._data = data
- self._reset_data = deepcopy(data)
- self.reader = None
- self._notes = ""
- self._description = "Edit Data"
- self._default_save_location = os.getcwd()
- self._do_layout()
- self.reset_panel()
- self.bt_apply.Disable()
- if data:
- self.complete_loading(data=data)
- self.bt_apply.Enable()
-
- def _define_structure(self):
- """
- define initial sizer
- """
- self.main_sizer = wx.BoxSizer(wx.VERTICAL)
- name_box = wx.StaticBox(self, -1, "Load Data")
- self.name_sizer = wx.StaticBoxSizer(name_box, wx.HORIZONTAL)
-
- self.title_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.run_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.instrument_sizer = wx.BoxSizer(wx.HORIZONTAL)
-
- edit_box = wx.StaticBox(self, -1, "Edit ")
- self.edit_sizer = wx.StaticBoxSizer(edit_box, wx.HORIZONTAL)
-
- self.button_sizer = wx.BoxSizer(wx.HORIZONTAL)
-
- def _layout_name(self):
- """
- Do the layout for data name related widgets
- """
- #data name [string]
- data_name_txt = wx.StaticText(self, -1, 'Data : ')
- self.data_cbox = wx.ComboBox(self, -1, style=wx.CB_READONLY)
- wx.EVT_COMBOBOX(self.data_cbox, -1, self.on_select_data)
- hint_data = "Loaded data."
- self.data_cbox.SetToolTipString(hint_data)
- id = wx.NewId()
- self.browse_button = wx.Button(self, id, "Browse")
- hint_on_browse = "Click on this button to import data in this panel."
- self.browse_button.SetToolTipString(hint_on_browse)
- self.Bind(wx.EVT_BUTTON, self.on_click_browse, id=id)
- self.name_sizer.AddMany([(data_name_txt, 0, wx.LEFT, 15),
- (self.data_cbox, 0, wx.LEFT, 10),
- (self.browse_button, 0, wx.LEFT, 10)])
-
- def _layout_title(self):
- """
- Do the layout for data title related widgets
- """
- #title name [string]
- data_title_txt = wx.StaticText(self, -1, 'Title : ')
- self.data_title_tcl = wx.TextCtrl(self, -1, size=(PANEL_WIDTH * 3 / 5, -1))
- self.data_title_tcl.Bind(wx.EVT_TEXT_ENTER, self.on_change_title)
- hint_title = "Data's title."
- self.data_title_tcl.SetToolTipString(hint_title)
- self.title_sizer.AddMany([(data_title_txt, 0, wx.LEFT, 15),
- (self.data_title_tcl, 0, wx.LEFT, 10)])
-
- def _layout_run(self):
- """
- Do the layout for data run related widgets
- """
- data_run_txt = wx.StaticText(self, -1, 'Run : ')
- data_run_txt.SetToolTipString('')
- self.data_run_tcl = wx.TextCtrl(self, -1, size=(PANEL_WIDTH * 3 / 5, -1),
- style=wx.TE_MULTILINE)
- hint_run = "Data's run."
- self.data_run_tcl.SetToolTipString(hint_run)
- self.run_sizer.AddMany([(data_run_txt, 0, wx.LEFT, 15),
- (self.data_run_tcl, 0, wx.LEFT, 10)])
-
- def _layout_instrument(self):
- """
- Do the layout for instrument related widgets
- """
- instrument_txt = wx.StaticText(self, -1, 'Instrument : ')
- hint_instrument_txt = ''
- instrument_txt.SetToolTipString(hint_instrument_txt)
- self.instrument_tcl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH * 5, 20))
- hint_instrument = "Instrument."
- self.instrument_tcl.SetToolTipString(hint_instrument)
- self.instrument_sizer.AddMany([(instrument_txt, 0, wx.LEFT, 15),
- (self.instrument_tcl, 0, wx.LEFT, 10)])
-
- def _layout_editor(self):
- """
- Do the layout for sample related widgets
- """
- self.detector_rb = wx.RadioButton(self, -1, "Detector",
- style=wx.RB_GROUP)
- self.sample_rb = wx.RadioButton(self, -1, "Sample")
- self.source_rb = wx.RadioButton(self, -1, "Source")
- self.collimation_rb = wx.RadioButton(self, -1, "Collimation")
-
- self.bt_edit = wx.Button(self, -1, "Edit")
- self.bt_edit.SetToolTipString("Edit data.")
- self.bt_edit.Bind(wx.EVT_BUTTON, self.on_edit)
- self.edit_sizer.AddMany([(self.detector_rb, 0, wx.ALL, 10),
- (self.sample_rb, 0, wx.RIGHT | wx.BOTTOM | wx.TOP, 10),
- (self.source_rb, 0, wx.RIGHT | wx.BOTTOM | wx.TOP, 10),
- (self.collimation_rb, 0, wx.RIGHT | wx.BOTTOM | wx.TOP, 10),
- (self.bt_edit, 0,
- wx.RIGHT | wx.BOTTOM | wx.TOP, 10)])
- self.reset_radiobox()
-
-
- def _layout_source(self):
- """
- Do the layout for source related widgets
- """
- source_txt = wx.StaticText(self, -1, 'Source ')
- hint_source_txt = ''
- source_txt.SetToolTipString(hint_source_txt)
- self.bt_edit_source = wx.Button(self, -1, "Edit")
- self.bt_edit_source.SetToolTipString("Edit data's sample.")
- self.bt_edit_source.Bind(wx.EVT_BUTTON, self.edit_source)
- #self.source_sizer.AddMany([(source_txt, 0, wx.ALL, 10),
- # (self.bt_edit_source, 0,
- # wx.RIGHT|wx.BOTTOM|wx.TOP, 10)])
-
- def _layout_summary(self):
- """
- Layout widgets related to data's summary
- """
- self.data_summary = wx.TextCtrl(self, -1,
- style=wx.TE_MULTILINE | wx.HSCROLL,
- size=(-1, 200))
- summary = 'No data info available...'
- self.data_summary.SetValue(summary)
- #self.summary_sizer.Add(self.data_summary, 1, wx.EXPAND|wx.ALL, 10)
-
- def _layout_button(self):
- """
- Do the layout for the button widgets
- """
- self.bt_summary = wx.Button(self, -1, "View", size=(_BOX_WIDTH, -1))
- self.bt_summary.SetToolTipString("View final changes on data.")
- self.bt_summary.Bind(wx.EVT_BUTTON, self.on_click_view)
-
- self.bt_save = wx.Button(self, -1, "Save As", size=(_BOX_WIDTH, -1))
- self.bt_save.SetToolTipString("Save changes in a file.")
- self.bt_save.Bind(wx.EVT_BUTTON, self.on_click_save)
-
- self.bt_apply = wx.Button(self, -1, "Apply", size=(_BOX_WIDTH, -1))
- self.bt_apply.SetToolTipString("Save changes into the imported data.")
- self.bt_apply.Bind(wx.EVT_BUTTON, self.on_click_apply)
-
- self.bt_reset = wx.Button(self, -1, 'Reset', size=(_BOX_WIDTH, -1))
- self.bt_reset.Bind(wx.EVT_BUTTON, self.on_click_reset)
- self.bt_reset.SetToolTipString("Reset data to its initial state.")
-
- self.bt_close = wx.Button(self, -1, 'Close', size=(_BOX_WIDTH, -1))
- self.bt_close.Bind(wx.EVT_BUTTON, self.on_close)
- self.bt_close.SetToolTipString("Close this panel.")
-
- self.button_sizer.AddMany([(self.bt_save, 0, wx.LEFT, 120),
- (self.bt_apply, 0, wx.LEFT, 10),
- (self.bt_reset, 0, wx.LEFT | wx.RIGHT, 10),
- (self.bt_summary, 0, wx.RIGHT, 10),
- (self.bt_close, 0, wx.RIGHT, 10)])
-
- def _do_layout(self):
- """
- Draw the current panel
- """
- self._define_structure()
- self._layout_name()
- self._layout_title()
- self._layout_run()
- self._layout_editor()
- self._layout_button()
- self.main_sizer.AddMany([(self.name_sizer, 0, wx.EXPAND | wx.ALL, 10),
- (self.title_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
- (self.run_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
- (self.instrument_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
- (self.edit_sizer, 0,
- wx.EXPAND | wx.LEFT | wx.RIGHT | wx.TOP, 10),
- (self.button_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
- self.SetSizer(self.main_sizer)
- self.SetScrollbars(20, 20, 25, 65)
- self.SetAutoLayout(True)
-
- def fill_data_combox(self):
- """
- fill the current combobox with the available data
- """
- if not self._data:
- return
- self.data_cbox.Clear()
- for data in self._data:
- name = data.title
- if data.run:
- name = data.run[0]
- if name.lstrip().rstrip() == "":
- name = data.filename
- pos = self.data_cbox.Append(str(name))
- self.data_cbox.SetClientData(pos, data)
- self.data_cbox.SetSelection(pos)
- self.data_cbox.SetStringSelection(str(name))
-
- def reset_panel(self):
- """
- """
- self.enable_data_cbox()
- self.data_title_tcl.SetValue("")
- self.data_run_tcl.SetValue("")
-
- def on_select_data(self, event=None):
- """
- """
- data, _, _ = self.get_current_data()
- self.reset_panel()
- if data is None:
- return
- self.data_title_tcl.SetValue(str(data.title))
- text = ""
- if data.run:
- for item in data.run:
- text += item + "\n"
- self.data_run_tcl.SetValue(str(text))
-
- def get_current_data(self):
- """
- """
- position = self.data_cbox.GetSelection()
- if position == wx.NOT_FOUND:
- return None, None, None
- data_name = self.data_cbox.GetStringSelection()
- data = self.data_cbox.GetClientData(position)
- return data, data_name, position
-
- def enable_data_cbox(self):
- """
- """
- if self._data:
- self.data_cbox.Enable()
- self.bt_summary.Enable()
- self.bt_reset.Enable()
- self.bt_save.Enable()
- self.bt_edit.Enable()
- else:
- self.data_cbox.Disable()
- self.bt_summary.Disable()
- self.bt_reset.Disable()
- self.bt_save.Disable()
- self.bt_edit.Disable()
-
- def reset_radiobox(self):
- """
- """
- self.detector_rb.SetValue(True)
- self.source_rb.SetValue(False)
- self.sample_rb.SetValue(False)
- self.collimation_rb.SetValue(False)
-
- def set_sample(self, sample, notes=None):
- """
- set sample for data
- """
- data, _, _ = self.get_current_data()
- if data is None:
- return
- data.sample = sample
- if notes is not None:
- data.process.append(notes)
-
- def set_source(self, source, notes=None):
- """
- set source for data
- """
- data, data_name, position = self.get_current_data()
- if data is None:
- return
- data.source = source
- if notes is not None:
- data.process.append(notes)
-
- def set_detector(self, detector, notes=None):
- """
- set detector for data
- """
- data, data_name, position = self.get_current_data()
- if data is None:
- return
- data.detector = detector
- if notes is not None:
- data.process.append(notes)
-
- def set_collimation(self, collimation, notes=None):
- """
- set collimation for data
- """
- data, data_name, position = self.get_current_data()
- if data is None:
- return
- data.collimation = collimation
- if notes is not None:
- data.process.append(notes)
-
- def edit_collimation(self):
- """
- Edit the selected collimation
- """
- data, data_name, position = self.get_current_data()
- if data is None:
- return
- dlg = CollimationDialog(collimation=data.collimation)
- dlg.set_manager(self)
- dlg.ShowModal()
-
- def edit_detector(self):
- """
- Edit the selected detector
- """
- data, data_name, position = self.get_current_data()
- if data is None:
- return
- dlg = DetectorDialog(detector=data.detector)
- dlg.set_manager(self)
- dlg.ShowModal()
-
- def edit_sample(self):
- """
- Open the dialog to edit the sample of the current data
- """
- data, _, _ = self.get_current_data()
- if data is None:
- return
- from sample_editor import SampleDialog
- dlg = SampleDialog(parent=self, sample=data.sample)
- dlg.set_manager(self)
- dlg.ShowModal()
-
- def edit_source(self):
- """
- Open the dialog to edit the saource of the current data
- """
- data, data_name, position = self.get_current_data()
- if data is None:
- return
- from source_editor import SourceDialog
- dlg = SourceDialog(parent=self, source=data.source)
- dlg.set_manager(self)
- dlg.ShowModal()
-
- def choose_data_file(self, location=None):
- """
- Open a file dialog to allow loading a file
- """
- path = None
- if location == None:
- location = os.getcwd()
-
- l = Loader()
- cards = l.get_wildcards()
- wlist = '|'.join(cards)
-
- dlg = wx.FileDialog(self, "Choose a file", location, "", wlist, wx.OPEN)
- if dlg.ShowModal() == wx.ID_OK:
- path = dlg.GetPath()
- mypath = os.path.basename(path)
- dlg.Destroy()
- return path
-
-
- def complete_loading(self, data=None, filename=''):
- """
- Complete the loading and compute the slit size
- """
- self.done = True
- self._data = []
- if data is None:
- msg = "Couldn't load data"
- wx.PostEvent(self.parent.parent, StatusEvent(status=msg,
- info="warning", type='stop'))
- return
- if not data.__class__.__name__ == "list":
- self._data.append(data)
- self._reset_data.append(deepcopy(data))
- else:
- self._data = deepcopy(data)
- self._reset_data = deepcopy(data)
- self.set_values()
- if self.parent.parent is None:
- return
- msg = "Load Complete"
- wx.PostEvent(self.parent.parent, StatusEvent(status=msg,
- info="info", type='stop'))
-
- def set_values(self):
- """
- take the aperture values of the current data and display them
- through the panel
- """
- if self._data:
- self.fill_data_combox()
- self.on_select_data(event=None)
-
- def get_data(self):
- """
- return the current data
- """
- return self._data
-
- def get_notes(self):
- """
- return notes
- """
- return self._notes
-
- def on_change_run(self, event=None):
- """
- Change run
- """
- run = []
- data, _, _ = self.get_current_data()
- for i in range(self.data_run_tcl.GetNumberOfLines()):
- text = self.data_run_tcl.GetLineText(i).lstrip().rstrip()
- if text != "":
- run.append(text)
- if data.run != run:
- self._notes += "Change data 's "
- self._notes += "run from %s to %s \n" % (data.run, str(run))
- data.run = run
- if event is not None:
- event.Skip()
-
- def on_change_title(self, event=None):
- """
- Change title
- """
- data, _, _ = self.get_current_data()
- #Change data's name
- title = self.data_title_tcl.GetValue().lstrip().rstrip()
-
- if data.title != title:
- self._notes += "Change data 's "
- self._notes += "title from %s to %s \n" % (data.title, str(title))
- data.title = title
- if event is not None:
- event.Skip()
-
- def on_click_browse(self, event):
- """
- Open a file dialog to allow the user to select a given file.
- Display the loaded data if available.
- """
- path = self.choose_data_file(location=self._default_save_location)
- if path is None:
- return
- if self.parent.parent is not None:
- wx.PostEvent(self.parent.parent, StatusEvent(status="Loading...",
- info="info", type="progress"))
-
- self.done = False
- self._default_save_location = path
- try:
- #Load data
- from load_thread import DataReader
- ## If a thread is already started, stop it
- if self.reader is not None and self.reader.isrunning():
- self.reader.stop()
- self.reader = DataReader(path=path,
- completefn=self.complete_loading,
- updatefn=None)
- self.reader.queue()
- except:
- msg = "Data Editor: %s" % (sys.exc_value)
- load_error(msg)
- return
- event.Skip()
-
- def on_edit(self, event):
- """
- """
- if self.detector_rb.GetValue():
- self.edit_detector()
- if self.sample_rb.GetValue():
- self.edit_sample()
- if self.source_rb.GetValue():
- self.edit_source()
- if self.collimation_rb.GetValue():
- self.edit_collimation()
- event.Skip()
-
- def on_click_apply(self, event):
- """
- changes are saved in data object imported to edit
- """
- data, _, _ = self.get_current_data()
- if data is None:
- return
- self.on_change_run(event=None)
- self.on_change_title(event=None)
- #must post event here
- event.Skip()
-
- def on_click_save(self, event):
- """
- Save change into a file
- """
- if not self._data:
- return
- self.on_change_run(event=None)
- self.on_change_title(event=None)
- path = None
- wildcard = "CanSAS 1D files(*.xml)|*.xml"
- dlg = wx.FileDialog(self, "Choose a file",
- self._default_save_location, "", wildcard , wx.SAVE)
-
- for data in self._data:
- if issubclass(data.__class__, Data2D):
- msg = "No conventional writing format for \n\n"
- msg += "Data2D at this time.\n"
- dlg = wx.MessageDialog(None, msg, 'Error Loading File',
- wx.OK | wx.ICON_EXCLAMATION)
- dlg.ShowModal()
- else:
- if dlg.ShowModal() == wx.ID_OK:
- path = dlg.GetPath()
- mypath = os.path.basename(path)
- loader = Loader()
- format = ".xml"
- if os.path.splitext(mypath)[1].lower() == format:
- loader.save(path, data, format)
- try:
- self._default_save_location = os.path.dirname(path)
- except:
- pass
- dlg.Destroy()
- event.Skip()
-
- def on_click_view(self, event):
- """
- Display data info
- """
- data, data_name, position = self.get_current_data()
- if data is None:
- return
- self.on_change_run(event=None)
- self.on_change_title(event=None)
- dlg = ConsoleDialog(data=data)
- dlg.ShowModal()
- event.Skip()
-
- def on_click_reset(self, event):
- """
- """
- data, data_name, position = self.get_current_data()
- if data is None:
- return
- self._data[position] = deepcopy(self._reset_data[position])
- self.set_values()
- event.Skip()
-
- def on_close(self, event):
- """
- leave data as it is and close
- """
- self.parent.Close()
- event.Skip()
-
-class DataEditorWindow(wx.Frame):
- def __init__(self, parent, manager, data=None, *args, **kwds):
- kwds["size"] = (PANEL_WIDTH, PANEL_HEIGTH)
- wx.Frame.__init__(self, parent, *args, **kwds)
- self.parent = parent
- self.manager = manager
- self.panel = DataEditorPanel(parent=self, data=data)
- self.Show()
-
- def get_data(self):
- """
- return the current data
- """
- return self.panel.get_data()
-
-if __name__ == "__main__":
-
- app = wx.App()
- window = DataEditorWindow(parent=None, data=[], title="Data Editor")
- app.MainLoop()
+
+import wx
+import sys
+import os
+from copy import deepcopy
+
+from sas.sascalc.dataloader.loader import Loader
+from sas.sascalc.dataloader.data_info import Data2D
+from detector_editor import DetectorDialog
+from collimation_editor import CollimationDialog
+from console import ConsoleDialog
+
+from sas.sasgui.guiframe.events import StatusEvent
+
+
+_QMIN_DEFAULT = 0.001
+_QMAX_DEFAULT = 0.13
+_NPTS_DEFAULT = 50
+#Control panel width
+if sys.platform.count("darwin") == 0:
+ PANEL_WIDTH = 500
+ PANEL_HEIGTH = 350
+ FONT_VARIANT = 0
+ _BOX_WIDTH = 51
+ ON_MAC = False
+else:
+ _BOX_WIDTH = 76
+ PANEL_WIDTH = 550
+ PANEL_HEIGTH = 400
+ FONT_VARIANT = 1
+ ON_MAC = True
+
+def load_error(error=None):
+ """
+ Pop up an error message.
+
+ @param error: details error message to be displayed
+ """
+ message = "You had to try this, didn't you?\n\n"
+ message += "The data file you selected could not be loaded.\n"
+ message += "Make sure the content of your file is properly formatted.\n\n"
+
+ if error is not None:
+ message += "When contacting the SasView team,"
+ message += " mention the following:\n%s" % str(error)
+
+ dial = wx.MessageDialog(None, message,
+ 'Error Loading File', wx.OK | wx.ICON_EXCLAMATION)
+ dial.ShowModal()
+
+
+class DataEditorPanel(wx.ScrolledWindow):
+ """
+ :param data: when not empty the class can
+ same information into a dat object
+ and post event containing the changed data object to some other frame
+ """
+ def __init__(self, parent, data=[], *args, **kwds):
+ kwds['name'] = "Data Editor"
+ kwds["size"] = (PANEL_WIDTH, PANEL_HEIGTH)
+ wx.ScrolledWindow.__init__(self, parent, *args, **kwds)
+ self.parent = parent
+ self._data = data
+ self._reset_data = deepcopy(data)
+ self.reader = None
+ self._notes = ""
+ self._description = "Edit Data"
+ self._default_save_location = os.getcwd()
+ self._do_layout()
+ self.reset_panel()
+ self.bt_apply.Disable()
+ if data:
+ self.complete_loading(data=data)
+ self.bt_apply.Enable()
+
+ def _define_structure(self):
+ """
+ define initial sizer
+ """
+ self.main_sizer = wx.BoxSizer(wx.VERTICAL)
+ name_box = wx.StaticBox(self, -1, "Load Data")
+ self.name_sizer = wx.StaticBoxSizer(name_box, wx.HORIZONTAL)
+
+ self.title_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.run_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.instrument_sizer = wx.BoxSizer(wx.HORIZONTAL)
+
+ edit_box = wx.StaticBox(self, -1, "Edit ")
+ self.edit_sizer = wx.StaticBoxSizer(edit_box, wx.HORIZONTAL)
+
+ self.button_sizer = wx.BoxSizer(wx.HORIZONTAL)
+
+ def _layout_name(self):
+ """
+ Do the layout for data name related widgets
+ """
+ #data name [string]
+ data_name_txt = wx.StaticText(self, -1, 'Data : ')
+ self.data_cbox = wx.ComboBox(self, -1, style=wx.CB_READONLY)
+ wx.EVT_COMBOBOX(self.data_cbox, -1, self.on_select_data)
+ hint_data = "Loaded data."
+ self.data_cbox.SetToolTipString(hint_data)
+ id = wx.NewId()
+ self.browse_button = wx.Button(self, id, "Browse")
+ hint_on_browse = "Click on this button to import data in this panel."
+ self.browse_button.SetToolTipString(hint_on_browse)
+ self.Bind(wx.EVT_BUTTON, self.on_click_browse, id=id)
+ self.name_sizer.AddMany([(data_name_txt, 0, wx.LEFT, 15),
+ (self.data_cbox, 0, wx.LEFT, 10),
+ (self.browse_button, 0, wx.LEFT, 10)])
+
+ def _layout_title(self):
+ """
+ Do the layout for data title related widgets
+ """
+ #title name [string]
+ data_title_txt = wx.StaticText(self, -1, 'Title : ')
+ self.data_title_tcl = wx.TextCtrl(self, -1, size=(PANEL_WIDTH * 3 / 5, -1))
+ self.data_title_tcl.Bind(wx.EVT_TEXT_ENTER, self.on_change_title)
+ hint_title = "Data's title."
+ self.data_title_tcl.SetToolTipString(hint_title)
+ self.title_sizer.AddMany([(data_title_txt, 0, wx.LEFT, 15),
+ (self.data_title_tcl, 0, wx.LEFT, 10)])
+
+ def _layout_run(self):
+ """
+ Do the layout for data run related widgets
+ """
+ data_run_txt = wx.StaticText(self, -1, 'Run : ')
+ data_run_txt.SetToolTipString('')
+ self.data_run_tcl = wx.TextCtrl(self, -1, size=(PANEL_WIDTH * 3 / 5, -1),
+ style=wx.TE_MULTILINE)
+ hint_run = "Data's run."
+ self.data_run_tcl.SetToolTipString(hint_run)
+ self.run_sizer.AddMany([(data_run_txt, 0, wx.LEFT, 15),
+ (self.data_run_tcl, 0, wx.LEFT, 10)])
+
+ def _layout_instrument(self):
+ """
+ Do the layout for instrument related widgets
+ """
+ instrument_txt = wx.StaticText(self, -1, 'Instrument : ')
+ hint_instrument_txt = ''
+ instrument_txt.SetToolTipString(hint_instrument_txt)
+ self.instrument_tcl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH * 5, 20))
+ hint_instrument = "Instrument."
+ self.instrument_tcl.SetToolTipString(hint_instrument)
+ self.instrument_sizer.AddMany([(instrument_txt, 0, wx.LEFT, 15),
+ (self.instrument_tcl, 0, wx.LEFT, 10)])
+
+ def _layout_editor(self):
+ """
+ Do the layout for sample related widgets
+ """
+ self.detector_rb = wx.RadioButton(self, -1, "Detector",
+ style=wx.RB_GROUP)
+ self.sample_rb = wx.RadioButton(self, -1, "Sample")
+ self.source_rb = wx.RadioButton(self, -1, "Source")
+ self.collimation_rb = wx.RadioButton(self, -1, "Collimation")
+
+ self.bt_edit = wx.Button(self, -1, "Edit")
+ self.bt_edit.SetToolTipString("Edit data.")
+ self.bt_edit.Bind(wx.EVT_BUTTON, self.on_edit)
+ self.edit_sizer.AddMany([(self.detector_rb, 0, wx.ALL, 10),
+ (self.sample_rb, 0, wx.RIGHT | wx.BOTTOM | wx.TOP, 10),
+ (self.source_rb, 0, wx.RIGHT | wx.BOTTOM | wx.TOP, 10),
+ (self.collimation_rb, 0, wx.RIGHT | wx.BOTTOM | wx.TOP, 10),
+ (self.bt_edit, 0,
+ wx.RIGHT | wx.BOTTOM | wx.TOP, 10)])
+ self.reset_radiobox()
+
+
+ def _layout_source(self):
+ """
+ Do the layout for source related widgets
+ """
+ source_txt = wx.StaticText(self, -1, 'Source ')
+ hint_source_txt = ''
+ source_txt.SetToolTipString(hint_source_txt)
+ self.bt_edit_source = wx.Button(self, -1, "Edit")
+ self.bt_edit_source.SetToolTipString("Edit data's sample.")
+ self.bt_edit_source.Bind(wx.EVT_BUTTON, self.edit_source)
+ #self.source_sizer.AddMany([(source_txt, 0, wx.ALL, 10),
+ # (self.bt_edit_source, 0,
+ # wx.RIGHT|wx.BOTTOM|wx.TOP, 10)])
+
+ def _layout_summary(self):
+ """
+ Layout widgets related to data's summary
+ """
+ self.data_summary = wx.TextCtrl(self, -1,
+ style=wx.TE_MULTILINE | wx.HSCROLL,
+ size=(-1, 200))
+ summary = 'No data info available...'
+ self.data_summary.SetValue(summary)
+ #self.summary_sizer.Add(self.data_summary, 1, wx.EXPAND|wx.ALL, 10)
+
+ def _layout_button(self):
+ """
+ Do the layout for the button widgets
+ """
+ self.bt_summary = wx.Button(self, -1, "View", size=(_BOX_WIDTH, -1))
+ self.bt_summary.SetToolTipString("View final changes on data.")
+ self.bt_summary.Bind(wx.EVT_BUTTON, self.on_click_view)
+
+ self.bt_save = wx.Button(self, -1, "Save As", size=(_BOX_WIDTH, -1))
+ self.bt_save.SetToolTipString("Save changes in a file.")
+ self.bt_save.Bind(wx.EVT_BUTTON, self.on_click_save)
+
+ self.bt_apply = wx.Button(self, -1, "Apply", size=(_BOX_WIDTH, -1))
+ self.bt_apply.SetToolTipString("Save changes into the imported data.")
+ self.bt_apply.Bind(wx.EVT_BUTTON, self.on_click_apply)
+
+ self.bt_reset = wx.Button(self, -1, 'Reset', size=(_BOX_WIDTH, -1))
+ self.bt_reset.Bind(wx.EVT_BUTTON, self.on_click_reset)
+ self.bt_reset.SetToolTipString("Reset data to its initial state.")
+
+ self.bt_close = wx.Button(self, -1, 'Close', size=(_BOX_WIDTH, -1))
+ self.bt_close.Bind(wx.EVT_BUTTON, self.on_close)
+ self.bt_close.SetToolTipString("Close this panel.")
+
+ self.button_sizer.AddMany([(self.bt_save, 0, wx.LEFT, 120),
+ (self.bt_apply, 0, wx.LEFT, 10),
+ (self.bt_reset, 0, wx.LEFT | wx.RIGHT, 10),
+ (self.bt_summary, 0, wx.RIGHT, 10),
+ (self.bt_close, 0, wx.RIGHT, 10)])
+
+ def _do_layout(self):
+ """
+ Draw the current panel
+ """
+ self._define_structure()
+ self._layout_name()
+ self._layout_title()
+ self._layout_run()
+ self._layout_editor()
+ self._layout_button()
+ self.main_sizer.AddMany([(self.name_sizer, 0, wx.EXPAND | wx.ALL, 10),
+ (self.title_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
+ (self.run_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
+ (self.instrument_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
+ (self.edit_sizer, 0,
+ wx.EXPAND | wx.LEFT | wx.RIGHT | wx.TOP, 10),
+ (self.button_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
+ self.SetSizer(self.main_sizer)
+ self.SetScrollbars(20, 20, 25, 65)
+ self.SetAutoLayout(True)
+
+ def fill_data_combox(self):
+ """
+ fill the current combobox with the available data
+ """
+ if not self._data:
+ return
+ self.data_cbox.Clear()
+ for data in self._data:
+ name = data.title
+ if data.run:
+ name = data.run[0]
+ if name.lstrip().rstrip() == "":
+ name = data.filename
+ pos = self.data_cbox.Append(str(name))
+ self.data_cbox.SetClientData(pos, data)
+ self.data_cbox.SetSelection(pos)
+ self.data_cbox.SetStringSelection(str(name))
+
+ def reset_panel(self):
+ """
+ """
+ self.enable_data_cbox()
+ self.data_title_tcl.SetValue("")
+ self.data_run_tcl.SetValue("")
+
+ def on_select_data(self, event=None):
+ """
+ """
+ data, _, _ = self.get_current_data()
+ self.reset_panel()
+ if data is None:
+ return
+ self.data_title_tcl.SetValue(str(data.title))
+ text = ""
+ if data.run:
+ for item in data.run:
+ text += item + "\n"
+ self.data_run_tcl.SetValue(str(text))
+
+ def get_current_data(self):
+ """
+ """
+ position = self.data_cbox.GetSelection()
+ if position == wx.NOT_FOUND:
+ return None, None, None
+ data_name = self.data_cbox.GetStringSelection()
+ data = self.data_cbox.GetClientData(position)
+ return data, data_name, position
+
+ def enable_data_cbox(self):
+ """
+ """
+ if self._data:
+ self.data_cbox.Enable()
+ self.bt_summary.Enable()
+ self.bt_reset.Enable()
+ self.bt_save.Enable()
+ self.bt_edit.Enable()
+ else:
+ self.data_cbox.Disable()
+ self.bt_summary.Disable()
+ self.bt_reset.Disable()
+ self.bt_save.Disable()
+ self.bt_edit.Disable()
+
+ def reset_radiobox(self):
+ """
+ """
+ self.detector_rb.SetValue(True)
+ self.source_rb.SetValue(False)
+ self.sample_rb.SetValue(False)
+ self.collimation_rb.SetValue(False)
+
+ def set_sample(self, sample, notes=None):
+ """
+ set sample for data
+ """
+ data, _, _ = self.get_current_data()
+ if data is None:
+ return
+ data.sample = sample
+ if notes is not None:
+ data.process.append(notes)
+
+ def set_source(self, source, notes=None):
+ """
+ set source for data
+ """
+ data, data_name, position = self.get_current_data()
+ if data is None:
+ return
+ data.source = source
+ if notes is not None:
+ data.process.append(notes)
+
+ def set_detector(self, detector, notes=None):
+ """
+ set detector for data
+ """
+ data, data_name, position = self.get_current_data()
+ if data is None:
+ return
+ data.detector = detector
+ if notes is not None:
+ data.process.append(notes)
+
+ def set_collimation(self, collimation, notes=None):
+ """
+ set collimation for data
+ """
+ data, data_name, position = self.get_current_data()
+ if data is None:
+ return
+ data.collimation = collimation
+ if notes is not None:
+ data.process.append(notes)
+
+ def edit_collimation(self):
+ """
+ Edit the selected collimation
+ """
+ data, data_name, position = self.get_current_data()
+ if data is None:
+ return
+ dlg = CollimationDialog(collimation=data.collimation)
+ dlg.set_manager(self)
+ dlg.ShowModal()
+
+ def edit_detector(self):
+ """
+ Edit the selected detector
+ """
+ data, data_name, position = self.get_current_data()
+ if data is None:
+ return
+ dlg = DetectorDialog(detector=data.detector)
+ dlg.set_manager(self)
+ dlg.ShowModal()
+
+ def edit_sample(self):
+ """
+ Open the dialog to edit the sample of the current data
+ """
+ data, _, _ = self.get_current_data()
+ if data is None:
+ return
+ from sample_editor import SampleDialog
+ dlg = SampleDialog(parent=self, sample=data.sample)
+ dlg.set_manager(self)
+ dlg.ShowModal()
+
+ def edit_source(self):
+ """
+ Open the dialog to edit the saource of the current data
+ """
+ data, data_name, position = self.get_current_data()
+ if data is None:
+ return
+ from source_editor import SourceDialog
+ dlg = SourceDialog(parent=self, source=data.source)
+ dlg.set_manager(self)
+ dlg.ShowModal()
+
+ def choose_data_file(self, location=None):
+ """
+ Open a file dialog to allow loading a file
+ """
+ path = None
+ if location is None:
+ location = os.getcwd()
+
+ l = Loader()
+ cards = l.get_wildcards()
+ wlist = '|'.join(cards)
+
+ dlg = wx.FileDialog(self, "Choose a file", location, "", wlist, wx.OPEN)
+ if dlg.ShowModal() == wx.ID_OK:
+ path = dlg.GetPath()
+ mypath = os.path.basename(path)
+ dlg.Destroy()
+ return path
+
+
+ def complete_loading(self, data=None, filename=''):
+ """
+ Complete the loading and compute the slit size
+ """
+ self.done = True
+ self._data = []
+ if data is None:
+ msg = "Couldn't load data"
+ wx.PostEvent(self.parent.parent, StatusEvent(status=msg,
+ info="warning", type='stop'))
+ return
+ if not data.__class__.__name__ == "list":
+ self._data.append(data)
+ self._reset_data.append(deepcopy(data))
+ else:
+ self._data = deepcopy(data)
+ self._reset_data = deepcopy(data)
+ self.set_values()
+ if self.parent.parent is None:
+ return
+ msg = "Load Complete"
+ wx.PostEvent(self.parent.parent, StatusEvent(status=msg,
+ info="info", type='stop'))
+
+ def set_values(self):
+ """
+ take the aperture values of the current data and display them
+ through the panel
+ """
+ if self._data:
+ self.fill_data_combox()
+ self.on_select_data(event=None)
+
+ def get_data(self):
+ """
+ return the current data
+ """
+ return self._data
+
+ def get_notes(self):
+ """
+ return notes
+ """
+ return self._notes
+
+ def on_change_run(self, event=None):
+ """
+ Change run
+ """
+ run = []
+ data, _, _ = self.get_current_data()
+ for i in range(self.data_run_tcl.GetNumberOfLines()):
+ text = self.data_run_tcl.GetLineText(i).lstrip().rstrip()
+ if text != "":
+ run.append(text)
+ if data.run != run:
+ self._notes += "Change data 's "
+ self._notes += "run from %s to %s \n" % (data.run, str(run))
+ data.run = run
+ if event is not None:
+ event.Skip()
+
+ def on_change_title(self, event=None):
+ """
+ Change title
+ """
+ data, _, _ = self.get_current_data()
+ #Change data's name
+ title = self.data_title_tcl.GetValue().lstrip().rstrip()
+
+ if data.title != title:
+ self._notes += "Change data 's "
+ self._notes += "title from %s to %s \n" % (data.title, str(title))
+ data.title = title
+ if event is not None:
+ event.Skip()
+
+ def on_click_browse(self, event):
+ """
+ Open a file dialog to allow the user to select a given file.
+ Display the loaded data if available.
+ """
+ path = self.choose_data_file(location=self._default_save_location)
+ if path is None:
+ return
+ if self.parent.parent is not None:
+ wx.PostEvent(self.parent.parent, StatusEvent(status="Loading...",
+ info="info", type="progress"))
+
+ self.done = False
+ self._default_save_location = path
+ try:
+ #Load data
+ from load_thread import DataReader
+ ## If a thread is already started, stop it
+ if self.reader is not None and self.reader.isrunning():
+ self.reader.stop()
+ self.reader = DataReader(path=path,
+ completefn=self.complete_loading,
+ updatefn=None)
+ self.reader.queue()
+ except:
+ msg = "Data Editor: %s" % (sys.exc_value)
+ load_error(msg)
+ return
+ event.Skip()
+
+ def on_edit(self, event):
+ """
+ """
+ if self.detector_rb.GetValue():
+ self.edit_detector()
+ if self.sample_rb.GetValue():
+ self.edit_sample()
+ if self.source_rb.GetValue():
+ self.edit_source()
+ if self.collimation_rb.GetValue():
+ self.edit_collimation()
+ event.Skip()
+
+ def on_click_apply(self, event):
+ """
+ changes are saved in data object imported to edit
+ """
+ data, _, _ = self.get_current_data()
+ if data is None:
+ return
+ self.on_change_run(event=None)
+ self.on_change_title(event=None)
+ #must post event here
+ event.Skip()
+
+ def on_click_save(self, event):
+ """
+ Save change into a file
+ """
+ if not self._data:
+ return
+ self.on_change_run(event=None)
+ self.on_change_title(event=None)
+ path = None
+ wildcard = "CanSAS 1D files(*.xml)|*.xml"
+ dlg = wx.FileDialog(self, "Choose a file",
+ self._default_save_location, "", wildcard , wx.SAVE)
+
+ for data in self._data:
+ if issubclass(data.__class__, Data2D):
+ msg = "No conventional writing format for \n\n"
+ msg += "Data2D at this time.\n"
+ dlg = wx.MessageDialog(None, msg, 'Error Loading File',
+ wx.OK | wx.ICON_EXCLAMATION)
+ dlg.ShowModal()
+ else:
+ if dlg.ShowModal() == wx.ID_OK:
+ path = dlg.GetPath()
+ mypath = os.path.basename(path)
+ loader = Loader()
+ format = ".xml"
+ if os.path.splitext(mypath)[1].lower() == format:
+ loader.save(path, data, format)
+ try:
+ self._default_save_location = os.path.dirname(path)
+ except:
+ pass
+ dlg.Destroy()
+ event.Skip()
+
+ def on_click_view(self, event):
+ """
+ Display data info
+ """
+ data, data_name, position = self.get_current_data()
+ if data is None:
+ return
+ self.on_change_run(event=None)
+ self.on_change_title(event=None)
+ dlg = ConsoleDialog(data=data)
+ dlg.ShowModal()
+ event.Skip()
+
+ def on_click_reset(self, event):
+ """
+ """
+ data, data_name, position = self.get_current_data()
+ if data is None:
+ return
+ self._data[position] = deepcopy(self._reset_data[position])
+ self.set_values()
+ event.Skip()
+
+ def on_close(self, event):
+ """
+ leave data as it is and close
+ """
+ self.parent.Close()
+ event.Skip()
+
+class DataEditorWindow(wx.Frame):
+ def __init__(self, parent, manager, data=None, *args, **kwds):
+ kwds["size"] = (PANEL_WIDTH, PANEL_HEIGTH)
+ wx.Frame.__init__(self, parent, *args, **kwds)
+ self.parent = parent
+ self.manager = manager
+ self.panel = DataEditorPanel(parent=self, data=data)
+ self.Show()
+
+ def get_data(self):
+ """
+ return the current data
+ """
+ return self.panel.get_data()
+
+if __name__ == "__main__":
+
+ app = wx.App()
+ window = DataEditorWindow(parent=None, data=[], title="Data Editor")
+ app.MainLoop()
diff --git a/src/sas/sasgui/perspectives/calculator/data_operator.py b/src/sas/sasgui/perspectives/calculator/data_operator.py
index 4e38f4a..61b05c9 100644
--- a/src/sas/sasgui/perspectives/calculator/data_operator.py
+++ b/src/sas/sasgui/perspectives/calculator/data_operator.py
@@ -1,996 +1,996 @@
-"""
-GUI for the data operations panel (sum and multiply)
-"""
-import wx
-import sys
-import time
-import numpy
-from sas.sascalc.dataloader.data_info import Data1D
-from sas.sasgui.plottools.PlotPanel import PlotPanel
-from sas.sasgui.plottools.plottables import Graph
-from sas.sasgui.plottools import transform
-from matplotlib.font_manager import FontProperties
-from sas.sasgui.guiframe.events import StatusEvent
-from sas.sasgui.perspectives.calculator import calculator_widgets as widget
-from sas.sasgui.guiframe.documentation_window import DocumentationWindow
-
-#Control panel width
-if sys.platform.count("win32") > 0:
- PANEL_TOP = 0
- PANEL_WIDTH = 790
- PANEL_HEIGTH = 370
- FONT_VARIANT = 0
- _BOX_WIDTH = 200
- ON_MAC = False
-else:
- PANEL_TOP = 60
- _BOX_WIDTH = 230
- PANEL_WIDTH = 900
- PANEL_HEIGTH = 430
- FONT_VARIANT = 1
- ON_MAC = True
-
-class DataOperPanel(wx.ScrolledWindow):
- """
- """
- def __init__(self, parent, *args, **kwds):
- kwds['name'] = "Data Operation"
- kwds["size"] = (PANEL_WIDTH, PANEL_HEIGTH)
- wx.ScrolledWindow.__init__(self, parent, *args, **kwds)
- self.parent = parent
- #sizers etc.
- self.main_sizer = None
- self.name_sizer = None
- self.button_sizer = None
- self.data_namectr = None
- self.numberctr = None
- self.data1_cbox = None
- self.operator_cbox = None
- self.data2_cbox = None
- self.data_title_tcl = None
- self.out_pic = None
- self.equal_pic = None
- self.data1_pic = None
- self.operator_pic = None
- self.data2_pic = None
- self.output = None
- self._notes = None
- #text grayed color
- self.color = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BACKGROUND)
- #data
- self._data = self.get_datalist()
- self._do_layout()
- self.fill_data_combox()
- self.fill_oprator_combox()
- self.Bind(wx.EVT_SET_FOCUS, self.set_panel_on_focus)
-
- def _define_structure(self):
- """
- define initial sizer
- """
- self.main_sizer = wx.BoxSizer(wx.VERTICAL)
- title = "Data Operation "
- title += "[ + (add); - (subtract); "
- title += "* (multiply); / (divide); "
- title += "| (append) ]"
- name_box = wx.StaticBox(self, -1, title)
- self.name_sizer = wx.StaticBoxSizer(name_box, wx.HORIZONTAL)
- self.button_sizer = wx.BoxSizer(wx.HORIZONTAL)
-
- def _layout_name(self):
- """
- Do the layout for data name related widgets
- """
- new_data_sizer = wx.BoxSizer(wx.VERTICAL)
- equal_sizer = wx.BoxSizer(wx.VERTICAL)
- old_data1_sizer = wx.BoxSizer(wx.VERTICAL)
- operator_sizer = wx.BoxSizer(wx.VERTICAL)
- old_data2_sizer = wx.BoxSizer(wx.VERTICAL)
- data2_hori_sizer = wx.BoxSizer(wx.HORIZONTAL)
- data_name = wx.StaticText(self, -1, 'Output Data Name')
- equal_name = wx.StaticText(self, -1, ' =', size=(50, 25))
- data1_name = wx.StaticText(self, -1, 'Data1')
- operator_name = wx.StaticText(self, -1, 'Operator')
- data2_name = wx.StaticText(self, -1, 'Data2 (or Number)')
- self.data_namectr = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, 25), style=wx.TE_PROCESS_ENTER)
- self.data_namectr.SetToolTipString("Hit 'Enter' key after typing.")
- self.data_namectr.SetValue(str('MyNewDataName'))
- self.numberctr = wx.TextCtrl(self, -1, size=(_BOX_WIDTH / 3, 25), style=wx.TE_PROCESS_ENTER)
- self.numberctr.SetToolTipString("Hit 'Enter' key after typing.")
- self.numberctr.SetValue(str(1.0))
- self.data1_cbox = wx.ComboBox(self, -1, size=(_BOX_WIDTH, 25),
- style=wx.CB_READONLY)
- self.operator_cbox = wx.ComboBox(self, -1, size=(70, 25),
- style=wx.CB_READONLY)
- operation_tip = "Add: +, Subtract: -, "
- operation_tip += "Multiply: *, Divide: /, "
- operation_tip += "Append(Combine): | "
- self.operator_cbox.SetToolTipString(operation_tip)
- self.data2_cbox = wx.ComboBox(self, -1, size=(_BOX_WIDTH * 2 / 3, 25),
- style=wx.CB_READONLY)
-
- self.out_pic = SmallPanel(self, -1, True,
- size=(_BOX_WIDTH, _BOX_WIDTH),
- style=wx.NO_BORDER)
- self.equal_pic = SmallPanel(self, -1, True, '=',
- size=(50, _BOX_WIDTH),
- style=wx.NO_BORDER)
- self.data1_pic = SmallPanel(self, -1, True,
- size=(_BOX_WIDTH, _BOX_WIDTH),
- style=wx.NO_BORDER)
- self.operator_pic = SmallPanel(self, -1, True, '+',
- size=(70, _BOX_WIDTH),
- style=wx.NO_BORDER)
- self.data2_pic = SmallPanel(self, -1, True,
- size=(_BOX_WIDTH, _BOX_WIDTH),
- style=wx.NO_BORDER)
- for ax in self.equal_pic.axes:
- ax.set_frame_on(False)
- for ax in self.operator_pic.axes:
- ax.set_frame_on(False)
-
- new_data_sizer.AddMany([(data_name, 0, wx.LEFT, 3),
- (self.data_namectr, 0, wx.LEFT, 3),
- (self.out_pic, 0, wx.LEFT, 3)])
- equal_sizer.AddMany([(13, 13), (equal_name, 0, wx.LEFT, 3),
- (self.equal_pic, 0, wx.LEFT, 3)])
- old_data1_sizer.AddMany([(data1_name, 0, wx.LEFT, 3),
- (self.data1_cbox, 0, wx.LEFT, 3),
- (self.data1_pic, 0, wx.LEFT, 3)])
- operator_sizer.AddMany([(operator_name, 0, wx.LEFT, 3),
- (self.operator_cbox, 0, wx.LEFT, 3),
- (self.operator_pic, 0, wx.LEFT, 3)])
- data2_hori_sizer.AddMany([(self.data2_cbox, 0, wx.LEFT, 0),
- (self.numberctr, 0, wx.RIGHT, 0)])
- old_data2_sizer.AddMany([(data2_name, 0, wx.LEFT, 3),
- (data2_hori_sizer, 0, wx.LEFT, 3),
- (self.data2_pic, 0, wx.LEFT, 3)])
- self.name_sizer.AddMany([(new_data_sizer, 0, wx.LEFT | wx.TOP, 5),
- (equal_sizer, 0, wx.TOP, 5),
- (old_data1_sizer, 0, wx.TOP, 5),
- (operator_sizer, 0, wx.TOP, 5),
- (old_data2_sizer, 0, wx.TOP, 5)])
- self.data2_cbox.Show(True)
-
- self._show_numctrl(self.numberctr, False)
-
- wx.EVT_TEXT_ENTER(self.data_namectr, -1, self.on_name)
- wx.EVT_TEXT(self.numberctr, -1, self.on_number)
- wx.EVT_COMBOBOX(self.data1_cbox, -1, self.on_select_data1)
- wx.EVT_COMBOBOX(self.operator_cbox, -1, self.on_select_operator)
- wx.EVT_COMBOBOX(self.data2_cbox, -1, self.on_select_data2)
-
- def _show_numctrl(self, ctrl, enable=True):
- """
- Show/Hide on Win
- Enable/Disable on MAC
- """
- if ON_MAC:
- ctrl.Enable(enable)
- children = ctrl.GetChildren()
- if len(children) > 0:
- ctrl.GetChildren()[0].SetBackGroundColour(self.color)
- if enable:
- wx.EVT_TEXT_ENTER(self.numberctr, -1, self.on_number)
- else:
- if not ctrl.IsEnabled():
- ctrl.Enable(True)
- ctrl.Show(enable)
-
- def on_name(self, event=None):
- """
- On data name typing
- """
- if event != None:
- event.Skip()
- item = event.GetEventObject()
- if item.IsEnabled():
- self._set_textctrl_color(item, 'white')
- else:
- self._set_textctrl_color(item, self.color)
- text = item.GetValue().strip()
- self._check_newname(text)
-
- def _check_newname(self, name=None):
- """
- Check name ctr strings
- """
- self.send_warnings('')
- msg = ''
- if name == None:
- text = self.data_namectr.GetValue().strip()
- else:
- text = name
- state_list = self.get_datalist().values()
- name_list = []
- for state in state_list:
- if state.data == None:
- theory_list = state.get_theory()
- theory, _ = theory_list.values()[0]
- d_name = str(theory.name)
- else:
- d_name = str(state.data.name)
- name_list.append(d_name)
- if text in name_list:
- self._set_textctrl_color(self.data_namectr, 'pink')
- msg = "DataOperation: The name already exists."
- if len(text) == 0:
- self._set_textctrl_color(self.data_namectr, 'pink')
- msg = "DataOperation: Type the data name first."
- if self._notes:
- self.send_warnings(msg, 'error')
- self.name_sizer.Layout()
- self.Refresh()
-
- def _set_textctrl_color(self, ctrl, color):
- """
- Set TextCtrl color
- """
- if ON_MAC:
- children = ctrl.GetChildren()
- if len(children) > 0:
- children[0].SetBackgroundColour(color)
- else:
- ctrl.SetBackgroundColour(color)
- self.name_sizer.Layout()
-
- def on_number(self, event=None, control=None):
- """
- On selecting Number for Data2
- """
- self.send_warnings('')
- item = control
- if item is None and event is not None:
- item = event.GetEventObject()
- elif item is None:
- raise ValueError("Event or control must be supplied")
- text = item.GetValue().strip()
- if self.numberctr.IsShown():
- if self.numberctr.IsEnabled():
- self._set_textctrl_color(self.numberctr, 'white')
- try:
- val = float(text)
- pos = self.data2_cbox.GetCurrentSelection()
- self.data2_cbox.SetClientData(pos, val)
- except:
- self._set_textctrl_color(self.numberctr, 'pink')
- if event is None:
- msg = "DataOperation: Number requires a float number."
- self.send_warnings(msg, 'error')
- return False
- else:
- self._set_textctrl_color(self.numberctr, self.color)
-
- self.put_text_pic(self.data2_pic, content=str(val))
- self.check_data_inputs()
- if self.output != None:
- self.output.name = str(self.data_namectr.GetValue())
- self.draw_output(self.output)
- self.Refresh()
- return True
-
- def on_select_data1(self, event=None):
- """
- On select data1
- """
- self.send_warnings('')
- item = event.GetEventObject()
- pos = item.GetCurrentSelection()
- data = item.GetClientData(pos)
- if data == None:
- content = "?"
- self.put_text_pic(self.data1_pic, content)
- else:
- self.data1_pic.add_image(data)
- self.check_data_inputs()
- if self.output != None:
- self.output.name = str(self.data_namectr.GetValue())
- self.draw_output(self.output)
-
- def on_select_operator(self, event=None):
- """
- On Select an Operator
- """
- self.send_warnings('')
- item = event.GetEventObject()
- text = item.GetValue().strip()
- self.put_text_pic(self.operator_pic, content=text)
- self.check_data_inputs()
- if self.output != None:
- self.output.name = str(self.data_namectr.GetValue())
- self.draw_output(self.output)
-
- def on_select_data2(self, event=None):
- """
- On Selecting Data2
- """
- self.send_warnings('')
- item = event.GetEventObject()
- text = item.GetValue().strip().lower()
- self._show_numctrl(self.numberctr, text == 'number')
- pos = item.GetCurrentSelection()
- data = item.GetClientData(pos)
- content = "?"
- if not (self.numberctr.IsShown() and self.numberctr.IsEnabled()):
- if data == None:
- content = "?"
- self.put_text_pic(self.data2_pic, content)
- else:
- self.data2_pic.add_image(data)
- self.check_data_inputs()
- else:
- content = str(self.numberctr.GetValue().strip())
- try:
- content = float(content)
- data = content
- except:
- self._set_textctrl_color(self.numberctr, 'pink')
- content = "?"
- data = None
- item.SetClientData(pos, data)
- if data != None:
- self.check_data_inputs()
-
- self.put_text_pic(self.data2_pic, content)
-
- if self.output != None:
- self.output.name = str(self.data_namectr.GetValue())
- self.draw_output(self.output)
-
- def put_text_pic(self, pic=None, content=''):
- """
- Put text to the pic
- """
- pic.set_content(content)
- pic.add_text()
- pic.draw()
-
- def check_data_inputs(self):
- """
- Check data1 and data2 whether or not they are ready for operation
- """
- self._set_textctrl_color(self.data1_cbox, 'white')
- self._set_textctrl_color(self.data2_cbox, 'white')
- flag = False
- pos1 = self.data1_cbox.GetCurrentSelection()
- data1 = self.data1_cbox.GetClientData(pos1)
- if data1 == None:
- self.output = None
- return flag
- pos2 = self.data2_cbox.GetCurrentSelection()
- data2 = self.data2_cbox.GetClientData(pos2)
-
- if data2 == None:
- self.output = None
- return flag
- if self.numberctr.IsShown():
- if self.numberctr.IsEnabled():
- self._set_textctrl_color(self.numberctr, 'white')
- try:
- float(data2)
- if self.operator_cbox.GetValue().strip() == '|':
- msg = "DataOperation: This operation can not accept "
- msg += "a float number."
- self.send_warnings(msg, 'error')
- self._set_textctrl_color(self.numberctr, 'pink')
- self.output = None
- return flag
- except:
- msg = "DataOperation: Number requires a float number."
- self.send_warnings(msg, 'error')
- self._set_textctrl_color(self.numberctr, 'pink')
- self.output = None
- return flag
- else:
- self._set_textctrl_color(self.numberctr, self.color)
- elif data1.__class__.__name__ != data2.__class__.__name__:
- self._set_textctrl_color(self.data1_cbox, 'pink')
- self._set_textctrl_color(self.data2_cbox, 'pink')
- msg = "DataOperation: Data types must be same."
- self.send_warnings(msg, 'error')
- self.output = None
- return flag
- try:
- self.output = self.make_data_out(data1, data2)
- except:
- self._check_newname()
- self._set_textctrl_color(self.data1_cbox, 'pink')
- self._set_textctrl_color(self.data2_cbox, 'pink')
- msg = "DataOperation: %s" % sys.exc_value
- self.send_warnings(msg, 'error')
- self.output = None
- return flag
- return True
-
- def make_data_out(self, data1, data2):
- """
- Make a temp. data output set
- """
- output = None
- pos = self.operator_cbox.GetCurrentSelection()
- operator = self.operator_cbox.GetClientData(pos)
- try:
- exec "output = data1 %s data2" % operator
- except:
- raise
- return output
-
-
- def draw_output(self, output):
- """
- Draw output data(temp)
- """
- out = self.out_pic
- if output == None:
- content = "?"
- self.put_text_pic(out, content)
- else:
- out.add_image(output)
- wx.CallAfter(self.name_sizer.Layout)
- self.Layout()
- self.Refresh()
-
- def _layout_button(self):
- """
- Do the layout for the button widgets
- """
- self.bt_apply = wx.Button(self, -1, "Apply", size=(_BOX_WIDTH / 2, -1))
- app_tip = "Generate the Data and send to Data Explorer."
- self.bt_apply.SetToolTipString(app_tip)
- self.bt_apply.Bind(wx.EVT_BUTTON, self.on_click_apply)
-
- self.bt_help = wx.Button(self, -1, "HELP")
- app_tip = "Get help on Data Operations."
- self.bt_help.SetToolTipString(app_tip)
- self.bt_help.Bind(wx.EVT_BUTTON, self.on_help)
-
- self.bt_close = wx.Button(self, -1, 'Close', size=(_BOX_WIDTH / 2, -1))
- self.bt_close.Bind(wx.EVT_BUTTON, self.on_close)
- self.bt_close.SetToolTipString("Close this panel.")
-
- self.button_sizer.AddMany([(PANEL_WIDTH / 2, 25),
- (self.bt_apply, 0, wx.RIGHT, 10),
- (self.bt_help, 0, wx.RIGHT, 10),
- (self.bt_close, 0, wx.RIGHT, 10)])
-
- def _do_layout(self):
- """
- Draw the current panel
- """
- self._define_structure()
- self._layout_name()
- self._layout_button()
- self.main_sizer.AddMany([(self.name_sizer, 0, wx.EXPAND | wx.ALL, 10),
- (self.button_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
- self.SetSizer(self.main_sizer)
- self.SetScrollbars(20, 20, 25, 65)
- self.SetAutoLayout(True)
-
- def set_panel_on_focus(self, event):
- """
- On Focus at this window
- """
- if event != None:
- event.Skip()
- self._data = self.get_datalist()
- if ON_MAC:
- self.fill_data_combox()
- else:
- children = self.GetChildren()
- # update the list only when it is on the top
- if self.FindFocus() in children:
- self.fill_data_combox()
-
- def fill_oprator_combox(self):
- """
- fill the current combobox with the operator
- """
- operator_list = [' +', ' -', ' *', " /", " |"]
- for oper in operator_list:
- pos = self.operator_cbox.Append(str(oper))
- self.operator_cbox.SetClientData(pos, str(oper.strip()))
- self.operator_cbox.SetSelection(0)
-
-
- def fill_data_combox(self):
- """
- fill the current combobox with the available data
- """
- pos_pre1 = self.data1_cbox.GetCurrentSelection()
- pos_pre2 = self.data2_cbox.GetCurrentSelection()
- current1 = self.data1_cbox.GetLabel()
- current2 = self.data2_cbox.GetLabel()
- if pos_pre1 < 0:
- pos_pre1 = 0
- if pos_pre2 < 0:
- pos_pre2 = 0
- self.data1_cbox.Clear()
- self.data2_cbox.Clear()
-
- if not self._data:
- pos = self.data1_cbox.Append('No Data Available')
- self.data1_cbox.SetSelection(pos)
- self.data1_cbox.SetClientData(pos, None)
- pos2 = self.data2_cbox.Append('No Data Available')
- self.data2_cbox.SetSelection(pos2)
- self.data2_cbox.SetClientData(pos2, None)
- return
- pos1 = self.data1_cbox.Append('Select Data')
- self.data1_cbox.SetSelection(pos1)
- self.data1_cbox.SetClientData(pos1, None)
- pos2 = self.data2_cbox.Append('Select Data')
- self.data2_cbox.SetSelection(pos2)
- self.data2_cbox.SetClientData(pos2, None)
- pos3 = self.data2_cbox.Append('Number')
- val = None
- if (self.numberctr.IsShown() and self.numberctr.IsEnabled()):
- try:
- val = float(self.numberctr.GetValue())
- except:
- val = None
- self.data2_cbox.SetClientData(pos3, val)
- dnames = []
- ids = self._data.keys()
- for id in ids:
- if id != None:
- if self._data[id].data != None:
- dnames.append(self._data[id].data.name)
- else:
- theory_list = self._data[id].get_theory()
- theory, _ = theory_list.values()[0]
- dnames.append(theory.name)
- ind = numpy.argsort(dnames)
- if len(ind) > 0:
- val_list = numpy.array(self._data.values())[ind]
- for datastate in val_list:
- data = datastate.data
- if data != None:
- name = data.name
- pos1 = self.data1_cbox.Append(str(name))
- self.data1_cbox.SetClientData(pos1, data)
- pos2 = self.data2_cbox.Append(str(name))
- self.data2_cbox.SetClientData(pos2, data)
- if str(current1) == str(name):
- pos_pre1 = pos1
- if str(current2) == str(name):
- pos_pre2 = pos2
- try:
- theory_list = datastate.get_theory()
- for theory, _ in theory_list.values():
- th_name = theory.name
- posth1 = self.data1_cbox.Append(str(th_name))
- self.data1_cbox.SetClientData(posth1, theory)
- posth2 = self.data2_cbox.Append(str(th_name))
- self.data2_cbox.SetClientData(posth2, theory)
- if str(current1) == str(th_name):
- pos_pre1 = posth1
- if str(current2) == str(th_name):
- pos_pre2 = posth2
- except:
- continue
- self.data1_cbox.SetSelection(pos_pre1)
- self.data2_cbox.SetSelection(pos_pre2)
-
- def get_datalist(self):
- """
- """
- data_manager = self.parent.parent.get_data_manager()
- if data_manager != None:
- return data_manager.get_all_data()
- else:
- return {}
-
- def on_click_apply(self, event):
- """
- changes are saved in data object imported to edit
- """
- self.send_warnings('')
- self.data_namectr.SetBackgroundColour('white')
- state_list = self.get_datalist().values()
- name = self.data_namectr.GetValue().strip()
- name_list = []
- for state in state_list:
- if state.data == None:
- theory_list = state.get_theory()
- theory, _ = theory_list.values()[0]
- d_name = str(theory.name)
- else:
- d_name = str(state.data.name)
- name_list.append(d_name)
- if name in name_list:
- self._set_textctrl_color(self.data_namectr, 'pink')
- msg = "The Output Data Name already exists... "
- wx.MessageBox(msg, 'Error')
- return
- if name == '':
- self._set_textctrl_color(self.data_namectr, 'pink')
- msg = "Please type the output data name first... "
- wx.MessageBox(msg, 'Error')
- return
- if self.output == None:
- msg = "No Output Data has been generated... "
- wx.MessageBox(msg, 'Error')
- return
- if self.numberctr.IsEnabled() and self.numberctr.IsShown():
- valid_num = self.on_number(control=self.numberctr)
- if not valid_num:
- return
- # send data to data manager
- self.output.name = name
- self.output.run = "Data Operation"
- self.output.instrument = "SasView"
- self.output.id = str(name) + str(time.time())
- data = {self.output.id :self.output}
- self.parent.parent.add_data(data)
- self.name_sizer.Layout()
- self.Refresh()
- #must post event here
- event.Skip()
-
- def on_help(self, event):
- """
- Bring up the Data Operations Panel Documentation whenever
- the HELP button is clicked.
-
- Calls DocumentationWindow with the path of the location within the
- documentation tree (after /doc/ ....". Note that when using old
- versions of Wx (before 2.9) and thus not the release version of
- installers, the help comes up at the top level of the file as
- webbrowser does not pass anything past the # to the browser when it is
- running "file:///...."
-
- :param evt: Triggers on clicking the help button
- """
-
- _TreeLocation = "user/sasgui/perspectives/calculator/"
- _TreeLocation += "data_operator_help.html"
- _doc_viewer = DocumentationWindow(self, -1, _TreeLocation, "",
- "Data Operation Help")
-
- def disconnect_panels(self):
- """
- """
- self.out_pic.connect.disconnect()
- self.equal_pic.connect.disconnect()
- self.data1_pic.connect.disconnect()
- self.operator_pic.connect.disconnect()
- self.data2_pic.connect.disconnect()
-
- def on_close(self, event):
- """
- leave data as it is and close
- """
- self.parent.OnClose()
-
- def set_plot_unfocus(self):
- """
- Unfocus on right click
- """
-
- def send_warnings(self, msg='', info='info'):
- """
- Send warning to status bar
- """
- wx.PostEvent(self.parent.parent, StatusEvent(status=msg, info=info))
-
-class SmallPanel(PlotPanel):
- """
- PlotPanel for Quick plot and masking plot
- """
- def __init__(self, parent, id= -1, is_number=False, content='?', **kwargs):
- """
- """
- PlotPanel.__init__(self, parent, id=id, **kwargs)
- self.is_number = is_number
- self.content = content
- self.point = None
- self.position = (0.4, 0.5)
- self.scale = 'linear'
- self.prevXtrans = "x"
- self.prevYtrans = "y"
- self.viewModel = "--"
- self.subplot.set_xticks([])
- self.subplot.set_yticks([])
- self.add_text()
- self.figure.subplots_adjust(left=0.1, bottom=0.1)
-
- def set_content(self, content=''):
- """
- Set text content
- """
- self.content = str(content)
-
- def add_toolbar(self):
- """
- Add toolbar
- """
- # Not implemented
- pass
-
- def on_set_focus(self, event):
- """
- send to the parenet the current panel on focus
- """
- pass
-
- def add_image(self, plot):
- """
- Add Image
- """
- self.content = ''
- self.textList = []
- self.plots = {}
- self.clear()
- self.point = plot
- try:
- self.figure.delaxes(self.figure.axes[0])
- self.subplot = self.figure.add_subplot(111)
- #self.figure.delaxes(self.figure.axes[1])
- except:
- pass
- try:
- name = plot.name
- except:
- name = plot.filename
- self.plots[name] = plot
-
- #init graph
- self.graph = Graph()
-
- #add plot
- self.graph.add(plot)
- #draw
- self.graph.render(self)
-
- try:
- self.figure.delaxes(self.figure.axes[1])
- except:
- pass
- self.subplot.figure.canvas.resizing = False
- self.subplot.tick_params(axis='both', labelsize=9)
- # Draw zero axis lines
- self.subplot.axhline(linewidth=1, color='r')
- self.subplot.axvline(linewidth=1, color='r')
-
- self.erase_legend()
- try:
- # mpl >= 1.1.0
- self.figure.tight_layout()
- except:
- self.figure.subplots_adjust(left=0.1, bottom=0.1)
- self.subplot.figure.canvas.draw()
-
- def add_text(self):
- """
- Text in the plot
- """
- if not self.is_number:
- return
-
- self.clear()
- try:
- self.figure.delaxes(self.figure.axes[0])
- self.subplot = self.figure.add_subplot(111)
- self.figure.delaxes(self.figure.axes[1])
- except:
- pass
- self.subplot.set_xticks([])
- self.subplot.set_yticks([])
- label = self.content
- FONT = FontProperties()
- xpos, ypos = (0.4, 0.5)
- font = FONT.copy()
- font.set_size(14)
-
- self.textList = []
- self.subplot.set_xlim((0, 1))
- self.subplot.set_ylim((0, 1))
-
- try:
- if self.content != '?':
- float(label)
- except:
- self.subplot.set_frame_on(False)
- try:
- # mpl >= 1.1.0
- self.figure.tight_layout()
- except:
- self.figure.subplots_adjust(left=0.1, bottom=0.1)
- if len(label) > 0 and xpos > 0 and ypos > 0:
- new_text = self.subplot.text(str(xpos), str(ypos), str(label),
- fontproperties=font)
- self.textList.append(new_text)
-
- def erase_legend(self):
- """
- Remove Legend
- """
- #for ax in self.axes:
- self.remove_legend(self.subplot)
-
- def onMouseMotion(self, event):
- """
- Disable dragging 2D image
- """
-
- def onWheel(self, event):
- """
- """
-
- def onLeftDown(self, event):
- """
- Disables LeftDown
- """
-
- def onPick(self, event):
- """
- Remove Legend
- """
- for ax in self.axes:
- self.remove_legend(ax)
-
-
- def draw(self):
- """
- Draw
- """
- if self.dimension == 3:
- pass
- else:
- self.subplot.figure.canvas.resizing = False
- self.subplot.tick_params(axis='both', labelsize=9)
- self.erase_legend()
- self.subplot.figure.canvas.draw_idle()
- try:
- self.figure.delaxes(self.figure.axes[1])
- except:
- pass
-
-
- def onContextMenu(self, event):
- """
- Default context menu for a plot panel
- """
- id = wx.NewId()
- slicerpop = wx.Menu()
- data = self.point
- if issubclass(data.__class__, Data1D):
- slicerpop.Append(id, '&Change Scale')
- wx.EVT_MENU(self, id, self._onProperties)
- else:
- slicerpop.Append(id, '&Toggle Linear/Log Scale')
- wx.EVT_MENU(self, id, self.ontogglescale)
- try:
- # mouse event
- pos_evt = event.GetPosition()
- pos = self.ScreenToClient(pos_evt)
- except:
- # toolbar event
- pos_x, pos_y = self.toolbar.GetPositionTuple()
- pos = (pos_x, pos_y + 5)
- self.PopupMenu(slicerpop, pos)
-
- def ontogglescale(self, event):
- """
- On toggle 2d scale
- """
- self._onToggleScale(event)
- try:
- # mpl >= 1.1.0
- self.figure.tight_layout()
- except:
- self.figure.subplots_adjust(left=0.1, bottom=0.1)
- try:
- self.figure.delaxes(self.figure.axes[1])
- except:
- pass
-
- def _onProperties(self, event):
- """
- when clicking on Properties on context menu ,
- The Property dialog is displayed
- The user selects a transformation for x or y value and
- a new plot is displayed
- """
- list = []
- list = self.graph.returnPlottable()
- if len(list.keys()) > 0:
- first_item = list.keys()[0]
- if first_item.x != []:
- from sas.sasgui.plottools.PropertyDialog import Properties
- dial = Properties(self, -1, 'Change Scale')
- # type of view or model used
- dial.xvalue.Clear()
- dial.yvalue.Clear()
- dial.view.Clear()
- dial.xvalue.Insert("x", 0)
- dial.xvalue.Insert("log10(x)", 1)
- dial.yvalue.Insert("y", 0)
- dial.yvalue.Insert("log10(y)", 1)
- dial.view.Insert("--", 0)
- dial.view.Insert("Linear y vs x", 1)
- dial.setValues(self.prevXtrans, self.prevYtrans, self.viewModel)
- dial.Update()
- if dial.ShowModal() == wx.ID_OK:
- self.xLabel, self.yLabel, self.viewModel = dial.getValues()
- if self.viewModel == "Linear y vs x":
- self.xLabel = "x"
- self.yLabel = "y"
- self.viewModel = "--"
- dial.setValues(self.xLabel, self.yLabel, self.viewModel)
- self._onEVT_FUNC_PROPERTY()
- dial.Destroy()
-
- def _onEVT_FUNC_PROPERTY(self, remove_fit=True):
- """
- Receive the x and y transformation from myDialog,
- Transforms x and y in View
- and set the scale
- """
- list = []
- list = self.graph.returnPlottable()
- # Changing the scale might be incompatible with
- # currently displayed data (for instance, going
- # from ln to log when all plotted values have
- # negative natural logs).
- # Go linear and only change the scale at the end.
- self.set_xscale("linear")
- self.set_yscale("linear")
- _xscale = 'linear'
- _yscale = 'linear'
- for item in list:
- item.setLabel(self.xLabel, self.yLabel)
- # control axis labels from the panel itself
- yname, yunits = item.get_yaxis()
- xname, xunits = item.get_xaxis()
- # Goes through all possible scales
- # Goes through all possible scales
- if(self.xLabel == "x"):
- item.transformX(transform.toX, transform.errToX)
- self.graph._xaxis_transformed("%s" % xname, "%s" % xunits)
- if(self.xLabel == "log10(x)"):
- item.transformX(transform.toX_pos, transform.errToX_pos)
- _xscale = 'log'
- self.graph._xaxis_transformed("%s" % xname, "%s" % xunits)
- if(self.yLabel == "y"):
- item.transformY(transform.toX, transform.errToX)
- self.graph._yaxis_transformed("%s" % yname, "%s" % yunits)
- if(self.yLabel == "log10(y)"):
- item.transformY(transform.toX_pos, transform.errToX_pos)
- _yscale = 'log'
- self.graph._yaxis_transformed("%s" % yname, "%s" % yunits)
- item.transformView()
- self.prevXtrans = self.xLabel
- self.prevYtrans = self.yLabel
- self.set_xscale(_xscale)
- self.set_yscale(_yscale)
- self.draw()
-
-class DataOperatorWindow(widget.CHILD_FRAME):
- def __init__(self, parent, manager, *args, **kwds):
- kwds["size"] = (PANEL_WIDTH, PANEL_HEIGTH)
- widget.CHILD_FRAME.__init__(self, parent, *args, **kwds)
- self.parent = parent
- self.manager = manager
- self.panel = DataOperPanel(parent=self)
- wx.EVT_CLOSE(self, self.OnClose)
- self.SetPosition((wx.LEFT, PANEL_TOP))
- self.Show()
-
- def OnClose(self, event=None):
- """
- On close event
- """
- if self.manager != None:
- self.manager.data_operator_frame = None
- self.panel.disconnect_panels()
- self.Destroy()
-
-
-if __name__ == "__main__":
-
- app = wx.App()
- widget.CHILD_FRAME = wx.Frame
- window = DataOperatorWindow(parent=None, data=[], title="Data Editor")
- app.MainLoop()
+"""
+GUI for the data operations panel (sum and multiply)
+"""
+import wx
+import sys
+import time
+import numpy as np
+from sas.sascalc.dataloader.data_info import Data1D
+from sas.sasgui.plottools.PlotPanel import PlotPanel
+from sas.sasgui.plottools.plottables import Graph
+from sas.sasgui.plottools import transform
+from matplotlib.font_manager import FontProperties
+from sas.sasgui.guiframe.events import StatusEvent
+from sas.sasgui.perspectives.calculator import calculator_widgets as widget
+from sas.sasgui.guiframe.documentation_window import DocumentationWindow
+
+#Control panel width
+if sys.platform.count("win32") > 0:
+ PANEL_TOP = 0
+ PANEL_WIDTH = 790
+ PANEL_HEIGTH = 370
+ FONT_VARIANT = 0
+ _BOX_WIDTH = 200
+ ON_MAC = False
+else:
+ PANEL_TOP = 60
+ _BOX_WIDTH = 230
+ PANEL_WIDTH = 900
+ PANEL_HEIGTH = 430
+ FONT_VARIANT = 1
+ ON_MAC = True
+
+class DataOperPanel(wx.ScrolledWindow):
+ """
+ """
+ def __init__(self, parent, *args, **kwds):
+ kwds['name'] = "Data Operation"
+ kwds["size"] = (PANEL_WIDTH, PANEL_HEIGTH)
+ wx.ScrolledWindow.__init__(self, parent, *args, **kwds)
+ self.parent = parent
+ #sizers etc.
+ self.main_sizer = None
+ self.name_sizer = None
+ self.button_sizer = None
+ self.data_namectr = None
+ self.numberctr = None
+ self.data1_cbox = None
+ self.operator_cbox = None
+ self.data2_cbox = None
+ self.data_title_tcl = None
+ self.out_pic = None
+ self.equal_pic = None
+ self.data1_pic = None
+ self.operator_pic = None
+ self.data2_pic = None
+ self.output = None
+ self._notes = None
+ #text grayed color
+ self.color = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BACKGROUND)
+ #data
+ self._data = self.get_datalist()
+ self._do_layout()
+ self.fill_data_combox()
+ self.fill_oprator_combox()
+ self.Bind(wx.EVT_SET_FOCUS, self.set_panel_on_focus)
+
+ def _define_structure(self):
+ """
+ define initial sizer
+ """
+ self.main_sizer = wx.BoxSizer(wx.VERTICAL)
+ title = "Data Operation "
+ title += "[ + (add); - (subtract); "
+ title += "* (multiply); / (divide); "
+ title += "| (append) ]"
+ name_box = wx.StaticBox(self, -1, title)
+ self.name_sizer = wx.StaticBoxSizer(name_box, wx.HORIZONTAL)
+ self.button_sizer = wx.BoxSizer(wx.HORIZONTAL)
+
+ def _layout_name(self):
+ """
+ Do the layout for data name related widgets
+ """
+ new_data_sizer = wx.BoxSizer(wx.VERTICAL)
+ equal_sizer = wx.BoxSizer(wx.VERTICAL)
+ old_data1_sizer = wx.BoxSizer(wx.VERTICAL)
+ operator_sizer = wx.BoxSizer(wx.VERTICAL)
+ old_data2_sizer = wx.BoxSizer(wx.VERTICAL)
+ data2_hori_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ data_name = wx.StaticText(self, -1, 'Output Data Name')
+ equal_name = wx.StaticText(self, -1, ' =', size=(50, 25))
+ data1_name = wx.StaticText(self, -1, 'Data1')
+ operator_name = wx.StaticText(self, -1, 'Operator')
+ data2_name = wx.StaticText(self, -1, 'Data2 (or Number)')
+ self.data_namectr = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, 25), style=wx.TE_PROCESS_ENTER)
+ self.data_namectr.SetToolTipString("Hit 'Enter' key after typing.")
+ self.data_namectr.SetValue(str('MyNewDataName'))
+ self.numberctr = wx.TextCtrl(self, -1, size=(_BOX_WIDTH / 3, 25), style=wx.TE_PROCESS_ENTER)
+ self.numberctr.SetToolTipString("Hit 'Enter' key after typing.")
+ self.numberctr.SetValue(str(1.0))
+ self.data1_cbox = wx.ComboBox(self, -1, size=(_BOX_WIDTH, 25),
+ style=wx.CB_READONLY)
+ self.operator_cbox = wx.ComboBox(self, -1, size=(70, 25),
+ style=wx.CB_READONLY)
+ operation_tip = "Add: +, Subtract: -, "
+ operation_tip += "Multiply: *, Divide: /, "
+ operation_tip += "Append(Combine): | "
+ self.operator_cbox.SetToolTipString(operation_tip)
+ self.data2_cbox = wx.ComboBox(self, -1, size=(_BOX_WIDTH * 2 / 3, 25),
+ style=wx.CB_READONLY)
+
+ self.out_pic = SmallPanel(self, -1, True,
+ size=(_BOX_WIDTH, _BOX_WIDTH),
+ style=wx.NO_BORDER)
+ self.equal_pic = SmallPanel(self, -1, True, '=',
+ size=(50, _BOX_WIDTH),
+ style=wx.NO_BORDER)
+ self.data1_pic = SmallPanel(self, -1, True,
+ size=(_BOX_WIDTH, _BOX_WIDTH),
+ style=wx.NO_BORDER)
+ self.operator_pic = SmallPanel(self, -1, True, '+',
+ size=(70, _BOX_WIDTH),
+ style=wx.NO_BORDER)
+ self.data2_pic = SmallPanel(self, -1, True,
+ size=(_BOX_WIDTH, _BOX_WIDTH),
+ style=wx.NO_BORDER)
+ for ax in self.equal_pic.axes:
+ ax.set_frame_on(False)
+ for ax in self.operator_pic.axes:
+ ax.set_frame_on(False)
+
+ new_data_sizer.AddMany([(data_name, 0, wx.LEFT, 3),
+ (self.data_namectr, 0, wx.LEFT, 3),
+ (self.out_pic, 0, wx.LEFT, 3)])
+ equal_sizer.AddMany([(13, 13), (equal_name, 0, wx.LEFT, 3),
+ (self.equal_pic, 0, wx.LEFT, 3)])
+ old_data1_sizer.AddMany([(data1_name, 0, wx.LEFT, 3),
+ (self.data1_cbox, 0, wx.LEFT, 3),
+ (self.data1_pic, 0, wx.LEFT, 3)])
+ operator_sizer.AddMany([(operator_name, 0, wx.LEFT, 3),
+ (self.operator_cbox, 0, wx.LEFT, 3),
+ (self.operator_pic, 0, wx.LEFT, 3)])
+ data2_hori_sizer.AddMany([(self.data2_cbox, 0, wx.LEFT, 0),
+ (self.numberctr, 0, wx.RIGHT, 0)])
+ old_data2_sizer.AddMany([(data2_name, 0, wx.LEFT, 3),
+ (data2_hori_sizer, 0, wx.LEFT, 3),
+ (self.data2_pic, 0, wx.LEFT, 3)])
+ self.name_sizer.AddMany([(new_data_sizer, 0, wx.LEFT | wx.TOP, 5),
+ (equal_sizer, 0, wx.TOP, 5),
+ (old_data1_sizer, 0, wx.TOP, 5),
+ (operator_sizer, 0, wx.TOP, 5),
+ (old_data2_sizer, 0, wx.TOP, 5)])
+ self.data2_cbox.Show(True)
+
+ self._show_numctrl(self.numberctr, False)
+
+ wx.EVT_TEXT_ENTER(self.data_namectr, -1, self.on_name)
+ wx.EVT_TEXT(self.numberctr, -1, self.on_number)
+ wx.EVT_COMBOBOX(self.data1_cbox, -1, self.on_select_data1)
+ wx.EVT_COMBOBOX(self.operator_cbox, -1, self.on_select_operator)
+ wx.EVT_COMBOBOX(self.data2_cbox, -1, self.on_select_data2)
+
+ def _show_numctrl(self, ctrl, enable=True):
+ """
+ Show/Hide on Win
+ Enable/Disable on MAC
+ """
+ if ON_MAC:
+ ctrl.Enable(enable)
+ children = ctrl.GetChildren()
+ if len(children) > 0:
+ ctrl.GetChildren()[0].SetBackGroundColour(self.color)
+ if enable:
+ wx.EVT_TEXT_ENTER(self.numberctr, -1, self.on_number)
+ else:
+ if not ctrl.IsEnabled():
+ ctrl.Enable(True)
+ ctrl.Show(enable)
+
+ def on_name(self, event=None):
+ """
+ On data name typing
+ """
+ if event is not None:
+ event.Skip()
+ item = event.GetEventObject()
+ if item.IsEnabled():
+ self._set_textctrl_color(item, 'white')
+ else:
+ self._set_textctrl_color(item, self.color)
+ text = item.GetValue().strip()
+ self._check_newname(text)
+
+ def _check_newname(self, name=None):
+ """
+ Check name ctr strings
+ """
+ self.send_warnings('')
+ msg = ''
+ if name is None:
+ text = self.data_namectr.GetValue().strip()
+ else:
+ text = name
+ state_list = self.get_datalist().values()
+ name_list = []
+ for state in state_list:
+ if state.data is None:
+ theory_list = state.get_theory()
+ theory, _ = theory_list.values()[0]
+ d_name = str(theory.name)
+ else:
+ d_name = str(state.data.name)
+ name_list.append(d_name)
+ if text in name_list:
+ self._set_textctrl_color(self.data_namectr, 'pink')
+ msg = "DataOperation: The name already exists."
+ if len(text) == 0:
+ self._set_textctrl_color(self.data_namectr, 'pink')
+ msg = "DataOperation: Type the data name first."
+ if self._notes:
+ self.send_warnings(msg, 'error')
+ self.name_sizer.Layout()
+ self.Refresh()
+
+ def _set_textctrl_color(self, ctrl, color):
+ """
+ Set TextCtrl color
+ """
+ if ON_MAC:
+ children = ctrl.GetChildren()
+ if len(children) > 0:
+ children[0].SetBackgroundColour(color)
+ else:
+ ctrl.SetBackgroundColour(color)
+ self.name_sizer.Layout()
+
+ def on_number(self, event=None, control=None):
+ """
+ On selecting Number for Data2
+ """
+ self.send_warnings('')
+ item = control
+ if item is None and event is not None:
+ item = event.GetEventObject()
+ elif item is None:
+ raise ValueError("Event or control must be supplied")
+ text = item.GetValue().strip()
+ if self.numberctr.IsShown():
+ if self.numberctr.IsEnabled():
+ self._set_textctrl_color(self.numberctr, 'white')
+ try:
+ val = float(text)
+ pos = self.data2_cbox.GetCurrentSelection()
+ self.data2_cbox.SetClientData(pos, val)
+ except:
+ self._set_textctrl_color(self.numberctr, 'pink')
+ if event is None:
+ msg = "DataOperation: Number requires a float number."
+ self.send_warnings(msg, 'error')
+ return False
+ else:
+ self._set_textctrl_color(self.numberctr, self.color)
+
+ self.put_text_pic(self.data2_pic, content=str(val))
+ self.check_data_inputs()
+ if self.output is not None:
+ self.output.name = str(self.data_namectr.GetValue())
+ self.draw_output(self.output)
+ self.Refresh()
+ return True
+
+ def on_select_data1(self, event=None):
+ """
+ On select data1
+ """
+ self.send_warnings('')
+ item = event.GetEventObject()
+ pos = item.GetCurrentSelection()
+ data = item.GetClientData(pos)
+ if data is None:
+ content = "?"
+ self.put_text_pic(self.data1_pic, content)
+ else:
+ self.data1_pic.add_image(data)
+ self.check_data_inputs()
+ if self.output is not None:
+ self.output.name = str(self.data_namectr.GetValue())
+ self.draw_output(self.output)
+
+ def on_select_operator(self, event=None):
+ """
+ On Select an Operator
+ """
+ self.send_warnings('')
+ item = event.GetEventObject()
+ text = item.GetValue().strip()
+ self.put_text_pic(self.operator_pic, content=text)
+ self.check_data_inputs()
+ if self.output is not None:
+ self.output.name = str(self.data_namectr.GetValue())
+ self.draw_output(self.output)
+
+ def on_select_data2(self, event=None):
+ """
+ On Selecting Data2
+ """
+ self.send_warnings('')
+ item = event.GetEventObject()
+ text = item.GetValue().strip().lower()
+ self._show_numctrl(self.numberctr, text == 'number')
+ pos = item.GetCurrentSelection()
+ data = item.GetClientData(pos)
+ content = "?"
+ if not (self.numberctr.IsShown() and self.numberctr.IsEnabled()):
+ if data is None:
+ content = "?"
+ self.put_text_pic(self.data2_pic, content)
+ else:
+ self.data2_pic.add_image(data)
+ self.check_data_inputs()
+ else:
+ content = str(self.numberctr.GetValue().strip())
+ try:
+ content = float(content)
+ data = content
+ except:
+ self._set_textctrl_color(self.numberctr, 'pink')
+ content = "?"
+ data = None
+ item.SetClientData(pos, data)
+ if data is not None:
+ self.check_data_inputs()
+
+ self.put_text_pic(self.data2_pic, content)
+
+ if self.output is not None:
+ self.output.name = str(self.data_namectr.GetValue())
+ self.draw_output(self.output)
+
+ def put_text_pic(self, pic=None, content=''):
+ """
+ Put text to the pic
+ """
+ pic.set_content(content)
+ pic.add_text()
+ pic.draw()
+
+ def check_data_inputs(self):
+ """
+ Check data1 and data2 whether or not they are ready for operation
+ """
+ self._set_textctrl_color(self.data1_cbox, 'white')
+ self._set_textctrl_color(self.data2_cbox, 'white')
+ flag = False
+ pos1 = self.data1_cbox.GetCurrentSelection()
+ data1 = self.data1_cbox.GetClientData(pos1)
+ if data1 is None:
+ self.output = None
+ return flag
+ pos2 = self.data2_cbox.GetCurrentSelection()
+ data2 = self.data2_cbox.GetClientData(pos2)
+
+ if data2 is None:
+ self.output = None
+ return flag
+ if self.numberctr.IsShown():
+ if self.numberctr.IsEnabled():
+ self._set_textctrl_color(self.numberctr, 'white')
+ try:
+ float(data2)
+ if self.operator_cbox.GetValue().strip() == '|':
+ msg = "DataOperation: This operation can not accept "
+ msg += "a float number."
+ self.send_warnings(msg, 'error')
+ self._set_textctrl_color(self.numberctr, 'pink')
+ self.output = None
+ return flag
+ except:
+ msg = "DataOperation: Number requires a float number."
+ self.send_warnings(msg, 'error')
+ self._set_textctrl_color(self.numberctr, 'pink')
+ self.output = None
+ return flag
+ else:
+ self._set_textctrl_color(self.numberctr, self.color)
+ elif data1.__class__.__name__ != data2.__class__.__name__:
+ self._set_textctrl_color(self.data1_cbox, 'pink')
+ self._set_textctrl_color(self.data2_cbox, 'pink')
+ msg = "DataOperation: Data types must be same."
+ self.send_warnings(msg, 'error')
+ self.output = None
+ return flag
+ try:
+ self.output = self.make_data_out(data1, data2)
+ except:
+ self._check_newname()
+ self._set_textctrl_color(self.data1_cbox, 'pink')
+ self._set_textctrl_color(self.data2_cbox, 'pink')
+ msg = "DataOperation: %s" % sys.exc_value
+ self.send_warnings(msg, 'error')
+ self.output = None
+ return flag
+ return True
+
+ def make_data_out(self, data1, data2):
+ """
+ Make a temp. data output set
+ """
+ output = None
+ pos = self.operator_cbox.GetCurrentSelection()
+ operator = self.operator_cbox.GetClientData(pos)
+ try:
+ exec "output = data1 %s data2" % operator
+ except:
+ raise
+ return output
+
+
+ def draw_output(self, output):
+ """
+ Draw output data(temp)
+ """
+ out = self.out_pic
+ if output is None:
+ content = "?"
+ self.put_text_pic(out, content)
+ else:
+ out.add_image(output)
+ wx.CallAfter(self.name_sizer.Layout)
+ self.Layout()
+ self.Refresh()
+
+ def _layout_button(self):
+ """
+ Do the layout for the button widgets
+ """
+ self.bt_apply = wx.Button(self, -1, "Apply", size=(_BOX_WIDTH / 2, -1))
+ app_tip = "Generate the Data and send to Data Explorer."
+ self.bt_apply.SetToolTipString(app_tip)
+ self.bt_apply.Bind(wx.EVT_BUTTON, self.on_click_apply)
+
+ self.bt_help = wx.Button(self, -1, "HELP")
+ app_tip = "Get help on Data Operations."
+ self.bt_help.SetToolTipString(app_tip)
+ self.bt_help.Bind(wx.EVT_BUTTON, self.on_help)
+
+ self.bt_close = wx.Button(self, -1, 'Close', size=(_BOX_WIDTH / 2, -1))
+ self.bt_close.Bind(wx.EVT_BUTTON, self.on_close)
+ self.bt_close.SetToolTipString("Close this panel.")
+
+ self.button_sizer.AddMany([(PANEL_WIDTH / 2, 25),
+ (self.bt_apply, 0, wx.RIGHT, 10),
+ (self.bt_help, 0, wx.RIGHT, 10),
+ (self.bt_close, 0, wx.RIGHT, 10)])
+
+ def _do_layout(self):
+ """
+ Draw the current panel
+ """
+ self._define_structure()
+ self._layout_name()
+ self._layout_button()
+ self.main_sizer.AddMany([(self.name_sizer, 0, wx.EXPAND | wx.ALL, 10),
+ (self.button_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
+ self.SetSizer(self.main_sizer)
+ self.SetScrollbars(20, 20, 25, 65)
+ self.SetAutoLayout(True)
+
+ def set_panel_on_focus(self, event):
+ """
+ On Focus at this window
+ """
+ if event is not None:
+ event.Skip()
+ self._data = self.get_datalist()
+ if ON_MAC:
+ self.fill_data_combox()
+ else:
+ children = self.GetChildren()
+ # update the list only when it is on the top
+ if self.FindFocus() in children:
+ self.fill_data_combox()
+
+ def fill_oprator_combox(self):
+ """
+ fill the current combobox with the operator
+ """
+ operator_list = [' +', ' -', ' *', " /", " |"]
+ for oper in operator_list:
+ pos = self.operator_cbox.Append(str(oper))
+ self.operator_cbox.SetClientData(pos, str(oper.strip()))
+ self.operator_cbox.SetSelection(0)
+
+
+ def fill_data_combox(self):
+ """
+ fill the current combobox with the available data
+ """
+ pos_pre1 = self.data1_cbox.GetCurrentSelection()
+ pos_pre2 = self.data2_cbox.GetCurrentSelection()
+ current1 = self.data1_cbox.GetLabel()
+ current2 = self.data2_cbox.GetLabel()
+ if pos_pre1 < 0:
+ pos_pre1 = 0
+ if pos_pre2 < 0:
+ pos_pre2 = 0
+ self.data1_cbox.Clear()
+ self.data2_cbox.Clear()
+
+ if not self._data:
+ pos = self.data1_cbox.Append('No Data Available')
+ self.data1_cbox.SetSelection(pos)
+ self.data1_cbox.SetClientData(pos, None)
+ pos2 = self.data2_cbox.Append('No Data Available')
+ self.data2_cbox.SetSelection(pos2)
+ self.data2_cbox.SetClientData(pos2, None)
+ return
+ pos1 = self.data1_cbox.Append('Select Data')
+ self.data1_cbox.SetSelection(pos1)
+ self.data1_cbox.SetClientData(pos1, None)
+ pos2 = self.data2_cbox.Append('Select Data')
+ self.data2_cbox.SetSelection(pos2)
+ self.data2_cbox.SetClientData(pos2, None)
+ pos3 = self.data2_cbox.Append('Number')
+ val = None
+ if (self.numberctr.IsShown() and self.numberctr.IsEnabled()):
+ try:
+ val = float(self.numberctr.GetValue())
+ except:
+ val = None
+ self.data2_cbox.SetClientData(pos3, val)
+ dnames = []
+ ids = self._data.keys()
+ for id in ids:
+ if id is not None:
+ if self._data[id].data is not None:
+ dnames.append(self._data[id].data.name)
+ else:
+ theory_list = self._data[id].get_theory()
+ theory, _ = theory_list.values()[0]
+ dnames.append(theory.name)
+ ind = np.argsort(dnames)
+ if len(ind) > 0:
+ val_list = np.array(self._data.values())[ind]
+ for datastate in val_list:
+ data = datastate.data
+ if data is not None:
+ name = data.name
+ pos1 = self.data1_cbox.Append(str(name))
+ self.data1_cbox.SetClientData(pos1, data)
+ pos2 = self.data2_cbox.Append(str(name))
+ self.data2_cbox.SetClientData(pos2, data)
+ if str(current1) == str(name):
+ pos_pre1 = pos1
+ if str(current2) == str(name):
+ pos_pre2 = pos2
+ try:
+ theory_list = datastate.get_theory()
+ for theory, _ in theory_list.values():
+ th_name = theory.name
+ posth1 = self.data1_cbox.Append(str(th_name))
+ self.data1_cbox.SetClientData(posth1, theory)
+ posth2 = self.data2_cbox.Append(str(th_name))
+ self.data2_cbox.SetClientData(posth2, theory)
+ if str(current1) == str(th_name):
+ pos_pre1 = posth1
+ if str(current2) == str(th_name):
+ pos_pre2 = posth2
+ except:
+ continue
+ self.data1_cbox.SetSelection(pos_pre1)
+ self.data2_cbox.SetSelection(pos_pre2)
+
+ def get_datalist(self):
+ """
+ """
+ data_manager = self.parent.parent.get_data_manager()
+ if data_manager is not None:
+ return data_manager.get_all_data()
+ else:
+ return {}
+
+ def on_click_apply(self, event):
+ """
+ changes are saved in data object imported to edit
+ """
+ self.send_warnings('')
+ self.data_namectr.SetBackgroundColour('white')
+ state_list = self.get_datalist().values()
+ name = self.data_namectr.GetValue().strip()
+ name_list = []
+ for state in state_list:
+ if state.data is None:
+ theory_list = state.get_theory()
+ theory, _ = theory_list.values()[0]
+ d_name = str(theory.name)
+ else:
+ d_name = str(state.data.name)
+ name_list.append(d_name)
+ if name in name_list:
+ self._set_textctrl_color(self.data_namectr, 'pink')
+ msg = "The Output Data Name already exists... "
+ wx.MessageBox(msg, 'Error')
+ return
+ if name == '':
+ self._set_textctrl_color(self.data_namectr, 'pink')
+ msg = "Please type the output data name first... "
+ wx.MessageBox(msg, 'Error')
+ return
+ if self.output is None:
+ msg = "No Output Data has been generated... "
+ wx.MessageBox(msg, 'Error')
+ return
+ if self.numberctr.IsEnabled() and self.numberctr.IsShown():
+ valid_num = self.on_number(control=self.numberctr)
+ if not valid_num:
+ return
+ # send data to data manager
+ self.output.name = name
+ self.output.run = "Data Operation"
+ self.output.instrument = "SasView"
+ self.output.id = str(name) + str(time.time())
+ data = {self.output.id :self.output}
+ self.parent.parent.add_data(data)
+ self.name_sizer.Layout()
+ self.Refresh()
+ #must post event here
+ event.Skip()
+
+ def on_help(self, event):
+ """
+ Bring up the Data Operations Panel Documentation whenever
+ the HELP button is clicked.
+
+ Calls DocumentationWindow with the path of the location within the
+ documentation tree (after /doc/ ....". Note that when using old
+ versions of Wx (before 2.9) and thus not the release version of
+ installers, the help comes up at the top level of the file as
+ webbrowser does not pass anything past the # to the browser when it is
+ running "file:///...."
+
+ :param evt: Triggers on clicking the help button
+ """
+
+ _TreeLocation = "user/sasgui/perspectives/calculator/"
+ _TreeLocation += "data_operator_help.html"
+ _doc_viewer = DocumentationWindow(self, -1, _TreeLocation, "",
+ "Data Operation Help")
+
+ def disconnect_panels(self):
+ """
+ """
+ self.out_pic.connect.disconnect()
+ self.equal_pic.connect.disconnect()
+ self.data1_pic.connect.disconnect()
+ self.operator_pic.connect.disconnect()
+ self.data2_pic.connect.disconnect()
+
+ def on_close(self, event):
+ """
+ leave data as it is and close
+ """
+ self.parent.OnClose()
+
+ def set_plot_unfocus(self):
+ """
+ Unfocus on right click
+ """
+
+ def send_warnings(self, msg='', info='info'):
+ """
+ Send warning to status bar
+ """
+ wx.PostEvent(self.parent.parent, StatusEvent(status=msg, info=info))
+
+class SmallPanel(PlotPanel):
+ """
+ PlotPanel for Quick plot and masking plot
+ """
+ def __init__(self, parent, id= -1, is_number=False, content='?', **kwargs):
+ """
+ """
+ PlotPanel.__init__(self, parent, id=id, **kwargs)
+ self.is_number = is_number
+ self.content = content
+ self.point = None
+ self.position = (0.4, 0.5)
+ self.scale = 'linear'
+ self.prevXtrans = "x"
+ self.prevYtrans = "y"
+ self.viewModel = "--"
+ self.subplot.set_xticks([])
+ self.subplot.set_yticks([])
+ self.add_text()
+ self.figure.subplots_adjust(left=0.1, bottom=0.1)
+
+ def set_content(self, content=''):
+ """
+ Set text content
+ """
+ self.content = str(content)
+
+ def add_toolbar(self):
+ """
+ Add toolbar
+ """
+ # Not implemented
+ pass
+
+ def on_set_focus(self, event):
+ """
+ send to the parenet the current panel on focus
+ """
+ pass
+
+ def add_image(self, plot):
+ """
+ Add Image
+ """
+ self.content = ''
+ self.textList = []
+ self.plots = {}
+ self.clear()
+ self.point = plot
+ try:
+ self.figure.delaxes(self.figure.axes[0])
+ self.subplot = self.figure.add_subplot(111)
+ #self.figure.delaxes(self.figure.axes[1])
+ except:
+ pass
+ try:
+ name = plot.name
+ except:
+ name = plot.filename
+ self.plots[name] = plot
+
+ #init graph
+ self.graph = Graph()
+
+ #add plot
+ self.graph.add(plot)
+ #draw
+ self.graph.render(self)
+
+ try:
+ self.figure.delaxes(self.figure.axes[1])
+ except:
+ pass
+ self.subplot.figure.canvas.resizing = False
+ self.subplot.tick_params(axis='both', labelsize=9)
+ # Draw zero axis lines
+ self.subplot.axhline(linewidth=1, color='r')
+ self.subplot.axvline(linewidth=1, color='r')
+
+ self.erase_legend()
+ try:
+ # mpl >= 1.1.0
+ self.figure.tight_layout()
+ except:
+ self.figure.subplots_adjust(left=0.1, bottom=0.1)
+ self.subplot.figure.canvas.draw()
+
+ def add_text(self):
+ """
+ Text in the plot
+ """
+ if not self.is_number:
+ return
+
+ self.clear()
+ try:
+ self.figure.delaxes(self.figure.axes[0])
+ self.subplot = self.figure.add_subplot(111)
+ self.figure.delaxes(self.figure.axes[1])
+ except:
+ pass
+ self.subplot.set_xticks([])
+ self.subplot.set_yticks([])
+ label = self.content
+ FONT = FontProperties()
+ xpos, ypos = (0.4, 0.5)
+ font = FONT.copy()
+ font.set_size(14)
+
+ self.textList = []
+ self.subplot.set_xlim((0, 1))
+ self.subplot.set_ylim((0, 1))
+
+ try:
+ if self.content != '?':
+ float(label)
+ except:
+ self.subplot.set_frame_on(False)
+ try:
+ # mpl >= 1.1.0
+ self.figure.tight_layout()
+ except:
+ self.figure.subplots_adjust(left=0.1, bottom=0.1)
+ if len(label) > 0 and xpos > 0 and ypos > 0:
+ new_text = self.subplot.text(str(xpos), str(ypos), str(label),
+ fontproperties=font)
+ self.textList.append(new_text)
+
+ def erase_legend(self):
+ """
+ Remove Legend
+ """
+ #for ax in self.axes:
+ self.remove_legend(self.subplot)
+
+ def onMouseMotion(self, event):
+ """
+ Disable dragging 2D image
+ """
+
+ def onWheel(self, event):
+ """
+ """
+
+ def onLeftDown(self, event):
+ """
+ Disables LeftDown
+ """
+
+ def onPick(self, event):
+ """
+ Remove Legend
+ """
+ for ax in self.axes:
+ self.remove_legend(ax)
+
+
+ def draw(self):
+ """
+ Draw
+ """
+ if self.dimension == 3:
+ pass
+ else:
+ self.subplot.figure.canvas.resizing = False
+ self.subplot.tick_params(axis='both', labelsize=9)
+ self.erase_legend()
+ self.subplot.figure.canvas.draw_idle()
+ try:
+ self.figure.delaxes(self.figure.axes[1])
+ except:
+ pass
+
+
+ def onContextMenu(self, event):
+ """
+ Default context menu for a plot panel
+ """
+ id = wx.NewId()
+ slicerpop = wx.Menu()
+ data = self.point
+ if issubclass(data.__class__, Data1D):
+ slicerpop.Append(id, '&Change Scale')
+ wx.EVT_MENU(self, id, self._onProperties)
+ else:
+ slicerpop.Append(id, '&Toggle Linear/Log Scale')
+ wx.EVT_MENU(self, id, self.ontogglescale)
+ try:
+ # mouse event
+ pos_evt = event.GetPosition()
+ pos = self.ScreenToClient(pos_evt)
+ except:
+ # toolbar event
+ pos_x, pos_y = self.toolbar.GetPositionTuple()
+ pos = (pos_x, pos_y + 5)
+ self.PopupMenu(slicerpop, pos)
+
+ def ontogglescale(self, event):
+ """
+ On toggle 2d scale
+ """
+ self._onToggleScale(event)
+ try:
+ # mpl >= 1.1.0
+ self.figure.tight_layout()
+ except:
+ self.figure.subplots_adjust(left=0.1, bottom=0.1)
+ try:
+ self.figure.delaxes(self.figure.axes[1])
+ except:
+ pass
+
+ def _onProperties(self, event):
+ """
+ when clicking on Properties on context menu ,
+ The Property dialog is displayed
+ The user selects a transformation for x or y value and
+ a new plot is displayed
+ """
+ list = []
+ list = self.graph.returnPlottable()
+ if len(list.keys()) > 0:
+ first_item = list.keys()[0]
+ if first_item.x != []:
+ from sas.sasgui.plottools.PropertyDialog import Properties
+ dial = Properties(self, -1, 'Change Scale')
+ # type of view or model used
+ dial.xvalue.Clear()
+ dial.yvalue.Clear()
+ dial.view.Clear()
+ dial.xvalue.Insert("x", 0)
+ dial.xvalue.Insert("log10(x)", 1)
+ dial.yvalue.Insert("y", 0)
+ dial.yvalue.Insert("log10(y)", 1)
+ dial.view.Insert("--", 0)
+ dial.view.Insert("Linear y vs x", 1)
+ dial.setValues(self.prevXtrans, self.prevYtrans, self.viewModel)
+ dial.Update()
+ if dial.ShowModal() == wx.ID_OK:
+ self.xLabel, self.yLabel, self.viewModel = dial.getValues()
+ if self.viewModel == "Linear y vs x":
+ self.xLabel = "x"
+ self.yLabel = "y"
+ self.viewModel = "--"
+ dial.setValues(self.xLabel, self.yLabel, self.viewModel)
+ self._onEVT_FUNC_PROPERTY()
+ dial.Destroy()
+
+ def _onEVT_FUNC_PROPERTY(self, remove_fit=True):
+ """
+ Receive the x and y transformation from myDialog,
+ Transforms x and y in View
+ and set the scale
+ """
+ list = []
+ list = self.graph.returnPlottable()
+ # Changing the scale might be incompatible with
+ # currently displayed data (for instance, going
+ # from ln to log when all plotted values have
+ # negative natural logs).
+ # Go linear and only change the scale at the end.
+ self.set_xscale("linear")
+ self.set_yscale("linear")
+ _xscale = 'linear'
+ _yscale = 'linear'
+ for item in list:
+ item.setLabel(self.xLabel, self.yLabel)
+ # control axis labels from the panel itself
+ yname, yunits = item.get_yaxis()
+ xname, xunits = item.get_xaxis()
+ # Goes through all possible scales
+ # Goes through all possible scales
+ if(self.xLabel == "x"):
+ item.transformX(transform.toX, transform.errToX)
+ self.graph._xaxis_transformed("%s" % xname, "%s" % xunits)
+ if(self.xLabel == "log10(x)"):
+ item.transformX(transform.toX_pos, transform.errToX_pos)
+ _xscale = 'log'
+ self.graph._xaxis_transformed("%s" % xname, "%s" % xunits)
+ if(self.yLabel == "y"):
+ item.transformY(transform.toX, transform.errToX)
+ self.graph._yaxis_transformed("%s" % yname, "%s" % yunits)
+ if(self.yLabel == "log10(y)"):
+ item.transformY(transform.toX_pos, transform.errToX_pos)
+ _yscale = 'log'
+ self.graph._yaxis_transformed("%s" % yname, "%s" % yunits)
+ item.transformView()
+ self.prevXtrans = self.xLabel
+ self.prevYtrans = self.yLabel
+ self.set_xscale(_xscale)
+ self.set_yscale(_yscale)
+ self.draw()
+
+class DataOperatorWindow(widget.CHILD_FRAME):
+ def __init__(self, parent, manager, *args, **kwds):
+ kwds["size"] = (PANEL_WIDTH, PANEL_HEIGTH)
+ widget.CHILD_FRAME.__init__(self, parent, *args, **kwds)
+ self.parent = parent
+ self.manager = manager
+ self.panel = DataOperPanel(parent=self)
+ wx.EVT_CLOSE(self, self.OnClose)
+ self.SetPosition((wx.LEFT, PANEL_TOP))
+ self.Show()
+
+ def OnClose(self, event=None):
+ """
+ On close event
+ """
+ if self.manager is not None:
+ self.manager.data_operator_frame = None
+ self.panel.disconnect_panels()
+ self.Destroy()
+
+
+if __name__ == "__main__":
+
+ app = wx.App()
+ widget.CHILD_FRAME = wx.Frame
+ window = DataOperatorWindow(parent=None, data=[], title="Data Editor")
+ app.MainLoop()
diff --git a/src/sas/sasgui/perspectives/calculator/density_panel.py b/src/sas/sasgui/perspectives/calculator/density_panel.py
index 891ade4..7355a3c 100644
--- a/src/sas/sasgui/perspectives/calculator/density_panel.py
+++ b/src/sas/sasgui/perspectives/calculator/density_panel.py
@@ -1,460 +1,460 @@
-"""
-This module provide GUI for the mass density calculator
-
-"""
-import wx
-import sys
-from sas.sasgui.guiframe.panel_base import PanelBase
-from wx.lib.scrolledpanel import ScrolledPanel
-from sas.sasgui.guiframe.utils import check_float
-from sas.sasgui.guiframe.events import StatusEvent
-from periodictable import formula as Formula
-from sas.sasgui.perspectives.calculator import calculator_widgets as widget
-from sas.sasgui.guiframe.documentation_window import DocumentationWindow
-
-AVOGADRO = 6.02214129e23
-_INPUTS = ['Mass Density', 'Molar Volume']
-_UNITS = ['g/cm^(3) ', 'cm^(3)/mol ']
-#Density panel size
-if sys.platform.count("win32") > 0:
- PANEL_TOP = 0
- _STATICBOX_WIDTH = 410
- _BOX_WIDTH = 200
- PANEL_SIZE = 440
- FONT_VARIANT = 0
-else:
- PANEL_TOP = 60
- _STATICBOX_WIDTH = 430
- _BOX_WIDTH = 200
- PANEL_SIZE = 460
- FONT_VARIANT = 1
-
-class DensityPanel(ScrolledPanel, PanelBase):
- """
- Provides the mass density calculator GUI.
- """
- ## Internal nickname for the window, used by the AUI manager
- window_name = "Mass Density Calculator"
- ## Name to appear on the window title bar
- window_caption = "Mass Density Calculator"
- ## Flag to tell the AUI manager to put this panel in the center pane
- CENTER_PANE = True
-
- def __init__(self, parent, base=None, *args, **kwds):
- """
- """
- ScrolledPanel.__init__(self, parent, *args, **kwds)
- PanelBase.__init__(self)
- self.SetupScrolling()
- #Font size
- self.SetWindowVariant(variant=FONT_VARIANT)
- # Object that receive status event
- self.base = base
- self.parent = parent
- # chemeical formula, string
- self.compound = ''
- # value of the density/volume, float
- self.input = None
- # text controls
- self.compound_ctl = None
- self.input_ctl = None
- self.molar_mass_ctl = None
- self.output_ctl = None
- self.ctr_color = self.GetBackgroundColour()
- # button
- self.button_calculate = None
- # list
- self._input_list = _INPUTS
- self._input = self._input_list[1]
- self._output = self._input_list[0]
- self._unit_list = _UNITS
- #Draw the panel
- self._do_layout()
- self.SetAutoLayout(True)
- self.Layout()
-
- def _do_layout(self):
- """
- Draw window content
- """
- # units
- unit_density = self._unit_list[0]
- unit_volume = self._unit_list[1]
-
- # sizers
- sizer_input = wx.GridBagSizer(5, 5)
- sizer_output = wx.GridBagSizer(5, 5)
- sizer_button = wx.BoxSizer(wx.HORIZONTAL)
- self.sizer1 = wx.BoxSizer(wx.HORIZONTAL)
- self.sizer2 = wx.BoxSizer(wx.HORIZONTAL)
- sizer3 = wx.BoxSizer(wx.HORIZONTAL)
- vbox = wx.BoxSizer(wx.VERTICAL)
-
- # inputs
- inputbox = wx.StaticBox(self, -1, "Inputs")
- boxsizer1 = wx.StaticBoxSizer(inputbox, wx.VERTICAL)
- boxsizer1.SetMinSize((_STATICBOX_WIDTH, -1))
- compound_txt = wx.StaticText(self, -1, 'Molecular Formula ')
- self.compound_ctl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, -1))
- self.compound_eg1 = wx.StaticText(self, -1, ' e.g., H2O')
- self.compound_eg2 = wx.StaticText(self, -1, 'e.g., D2O')
- self.input_cb = wx.ComboBox(self, -1, style=wx.CB_READONLY)
- wx.EVT_COMBOBOX(self.input_cb, -1, self.on_select_input)
- hint_input_name_txt = 'Mass or volume.'
- self.input_cb.SetToolTipString(hint_input_name_txt)
- unit_density1 = " " + unit_density
- self.input_ctl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, -1))
- self.unit_input_density = wx.StaticText(self, -1, unit_density1)
- self.unit_input_volume = wx.StaticText(self, -1, unit_volume)
- iy = 0
- ix = 0
- sizer_input.Add(compound_txt, (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- ix += 1
- sizer_input.Add(self.compound_ctl, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 1
- sizer_input.Add(self.compound_eg1, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
-
- ix += 1
- sizer_input.Add(self.compound_eg2, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- self.compound_eg1.Show(False)
- iy += 1
- ix = 0
- sizer_input.Add(self.input_cb, (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- ix += 1
- sizer_input.Add(self.input_ctl, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 1
- sizer_input.Add(self.unit_input_density, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 1
- self.unit_input_density.Show(False)
- sizer_input.Add(self.unit_input_volume, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- boxsizer1.Add(sizer_input)
- self.sizer1.Add(boxsizer1, 0, wx.EXPAND | wx.ALL, 10)
-
- # outputs
- outputbox = wx.StaticBox(self, -1, "Outputs")
- boxsizer2 = wx.StaticBoxSizer(outputbox, wx.VERTICAL)
- boxsizer2.SetMinSize((_STATICBOX_WIDTH, -1))
-
- molar_mass_txt = wx.StaticText(self, -1, 'Molar Mass ')
- self.molar_mass_ctl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, -1))
- self.molar_mass_ctl.SetEditable(False)
- self.molar_mass_ctl.SetBackgroundColour(self.ctr_color)
- self.molar_mass_unit1 = wx.StaticText(self, -1, ' g/mol')
- self.molar_mass_unit2 = wx.StaticText(self, -1, 'g/mol')
-
- self.output_cb = wx.ComboBox(self, -1, style=wx.CB_READONLY)
- wx.EVT_COMBOBOX(self.output_cb, -1, self.on_select_output)
- hint_output_name_txt = 'Mass or volume.'
- self.output_cb.SetToolTipString(hint_output_name_txt)
- list = []
- for item in self._input_list:
- name = str(item)
- list.append(name)
- list.sort()
- for idx in range(len(list)):
- self.input_cb.Append(list[idx], idx)
- self.output_cb.Append(list[idx], idx)
- self.input_cb.SetStringSelection("Molar Volume")
- self.output_cb.SetStringSelection("Mass Density")
- unit_volume = " " + unit_volume
- self.output_ctl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, -1))
- self.output_ctl.SetEditable(False)
- self.output_ctl.SetBackgroundColour(self.ctr_color)
- self.unit_output_density = wx.StaticText(self, -1, unit_density)
- self.unit_output_volume = wx.StaticText(self, -1, unit_volume)
- iy = 0
- ix = 0
- sizer_output.Add(molar_mass_txt, (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- ix += 1
- sizer_output.Add(self.molar_mass_ctl, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 1
- sizer_output.Add(self.molar_mass_unit1, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 1
- sizer_output.Add(self.molar_mass_unit2, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- self.molar_mass_unit1.Show(False)
- iy += 1
- ix = 0
- sizer_output.Add(self.output_cb, (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- ix += 1
- sizer_output.Add(self.output_ctl, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 1
- sizer_output.Add(self.unit_output_volume,
- (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 1
- sizer_output.Add(self.unit_output_density,
- (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
-
- self.unit_output_volume.Show(False)
- boxsizer2.Add(sizer_output)
- self.sizer2.Add(boxsizer2, 0, wx.EXPAND | wx.ALL, 10)
-
- # buttons
- id = wx.NewId()
- self.button_calculate = wx.Button(self, id, "Calculate")
- self.button_calculate.SetToolTipString("Calculate.")
- self.Bind(wx.EVT_BUTTON, self.calculate, id=id)
-
- id = wx.NewId()
- self.button_help = wx.Button(self, id, "HELP")
- self.button_help.SetToolTipString("Help for density calculator.")
- self.Bind(wx.EVT_BUTTON, self.on_help, id=id)
-
- self.button_close = wx.Button(self, wx.ID_CANCEL, 'Close')
- self.button_close.Bind(wx.EVT_BUTTON, self.on_close)
- self.button_close.SetToolTipString("Close this window.")
-
- sizer_button.Add((100, 20), 1, wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- sizer_button.Add(self.button_calculate, 0,
- wx.RIGHT | wx.ADJUST_MINSIZE, 20)
- sizer_button.Add(self.button_help, 0,
- wx.RIGHT | wx.ADJUST_MINSIZE, 20)
- sizer_button.Add(self.button_close, 0,
- wx.RIGHT | wx.ADJUST_MINSIZE, 20)
- sizer3.Add(sizer_button)
-
- # layout
- vbox.Add(self.sizer1)
- vbox.Add(self.sizer2)
- vbox.Add(sizer3)
- vbox.Fit(self)
- self.SetSizer(vbox)
-
- def on_select_input(self, event):
- """
- On selection of input combobox,
- update units and output combobox
- """
- if event == None:
- return
- event.Skip()
-
- combo = event.GetEventObject()
- self._input = combo.GetValue()
- for name in self._input_list:
- if self._input != name:
- self._output = name
- break
-
- self.set_values()
-
- def on_select_output(self, event):
- """
- On selection of output combobox,
- update units and input combobox
- """
- if event == None:
- return
- event.Skip()
-
- combo = event.GetEventObject()
- self._output = combo.GetValue()
- for name in self._input_list:
- if self._output != name:
- self._input = name
- break
-
- self.set_values()
-
- def set_values(self):
- """
- Sets units and combobox values
- """
- input, output = self.get_input()
- if input is None:
- return
- # input
- self.input_cb.SetValue(str(input))
- # output
- self.output_cb.SetValue(str(output))
- # unit
- if self._input_list.index(input) == 0:
- self.molar_mass_unit1.Show(True)
- self.molar_mass_unit2.Show(False)
- self.compound_eg1.Show(True)
- self.compound_eg2.Show(False)
- self.unit_input_density.Show(True)
- self.unit_output_volume.Show(True)
- self.unit_input_volume.Show(False)
- self.unit_output_density.Show(False)
- else:
- self.molar_mass_unit1.Show(False)
- self.molar_mass_unit2.Show(True)
- self.compound_eg1.Show(False)
- self.compound_eg2.Show(True)
- self.unit_input_volume.Show(True)
- self.unit_output_density.Show(True)
- self.unit_input_density.Show(False)
- self.unit_output_volume.Show(False)
- # layout
- self.clear_outputs()
- self.sizer1.Layout()
- self.sizer2.Layout()
-
- def get_input(self):
- """
- Return the current input and output combobox values
- """
- return self._input, self._output
-
- def check_inputs(self):
- """
- Check validity user inputs
- """
- flag = True
- msg = ""
- if check_float(self.input_ctl):
- self.input = float(self.input_ctl.GetValue())
- else:
- flag = False
- input_type = str(self.input_cb.GetValue())
- msg += "Error for %s value :expect float" % input_type
-
- self.compound = self.compound_ctl.GetValue().lstrip().rstrip()
- if self.compound != "":
- try :
- Formula(self.compound)
- self.compound_ctl.SetBackgroundColour(wx.WHITE)
- self.compound_ctl.Refresh()
- except:
- self.compound_ctl.SetBackgroundColour("pink")
- self.compound_ctl.Refresh()
- flag = False
- msg += "Enter correct formula"
- else:
- self.compound_ctl.SetBackgroundColour("pink")
- self.compound_ctl.Refresh()
- flag = False
- msg += "Enter Formula"
- return flag, msg
-
-
- def calculate(self, event):
- """
- Calculate the mass Density/molar Volume of the molecules
- """
- self.clear_outputs()
- try:
- #Check validity user inputs
- flag, msg = self.check_inputs()
- if self.base is not None and msg.lstrip().rstrip() != "":
- msg = "Density/Volume Calculator: %s" % str(msg)
- wx.PostEvent(self.base, StatusEvent(status=msg))
- if not flag:
- return
- #get ready to compute
- mol_formula = Formula(self.compound)
- molar_mass = float(mol_formula.molecular_mass) * AVOGADRO
- output = self._format_number(molar_mass / self.input)
- self.molar_mass_ctl.SetValue(str(self._format_number(molar_mass)))
- self.output_ctl.SetValue(str(output))
- except:
- if self.base is not None:
- msg = "Density/Volume Calculator: %s" % (sys.exc_value)
- wx.PostEvent(self.base, StatusEvent(status=msg))
- if event is not None:
- event.Skip()
-
- def on_help(self, event):
- """
- Bring up the density/volume calculator Documentation whenever
- the HELP button is clicked.
-
- Calls DocumentationWindow with the path of the location within the
- documentation tree (after /doc/ ....". Note that when using old
- versions of Wx (before 2.9) and thus not the release version of
- installers, the help comes up at the top level of the file as
- webbrowser does not pass anything past the # to the browser when it is
- running "file:///...."
-
- :param evt: Triggers on clicking the help button
- """
-
- _TreeLocation = "user/sasgui/perspectives/calculator/"
- _TreeLocation += "density_calculator_help.html"
- _doc_viewer = DocumentationWindow(self, -1, _TreeLocation, "",
- "Density/Volume Calculator Help")
-
- def on_close(self, event):
- """
- close the window containing this panel
- """
- self.parent.Close()
-
- def clear_outputs(self):
- """
- Clear the outputs textctrl
- """
- self.molar_mass_ctl.SetValue("")
- self.output_ctl.SetValue("")
-
- def _format_number(self, value=None):
- """
- Return a float in a standardized, human-readable formatted string
- """
- try:
- value = float(value)
- except:
- output = ''
- return output
-
- output = "%-12.5f" % value
- return output.lstrip().rstrip()
-
-class DensityWindow(widget.CHILD_FRAME):
- """
- """
- def __init__(self, parent=None, title="Density/Volume Calculator",
- base=None, manager=None,
- size=(PANEL_SIZE * 1.05, PANEL_SIZE / 1.55), *args, **kwds):
- """
- """
- kwds['title'] = title
- kwds['size'] = size
- widget.CHILD_FRAME.__init__(self, parent, *args, **kwds)
- """
- """
- self.manager = manager
- self.panel = DensityPanel(self, base=base)
- self.Bind(wx.EVT_CLOSE, self.on_close)
- self.SetPosition((wx.LEFT, PANEL_TOP))
- self.Show(True)
-
- def on_close(self, event):
- """
- On close event
- """
- if self.manager != None:
- self.manager.cal_md_frame = None
- self.Destroy()
-
-
-class ViewApp(wx.App):
- """
- """
- def OnInit(self):
- """
- """
- widget.CHILD_FRAME = wx.Frame
- frame = DensityWindow(None, title="Density/Volume Calculator")
- frame.Show(True)
- self.SetTopWindow(frame)
- return True
-
-
-if __name__ == "__main__":
- app = ViewApp(0)
- app.MainLoop()
+"""
+This module provide GUI for the mass density calculator
+
+"""
+import wx
+import sys
+from sas.sasgui.guiframe.panel_base import PanelBase
+from wx.lib.scrolledpanel import ScrolledPanel
+from sas.sasgui.guiframe.utils import check_float
+from sas.sasgui.guiframe.events import StatusEvent
+from periodictable import formula as Formula
+from sas.sasgui.perspectives.calculator import calculator_widgets as widget
+from sas.sasgui.guiframe.documentation_window import DocumentationWindow
+
+AVOGADRO = 6.02214129e23
+_INPUTS = ['Mass Density', 'Molar Volume']
+_UNITS = ['g/cm^(3) ', 'cm^(3)/mol ']
+#Density panel size
+if sys.platform.count("win32") > 0:
+ PANEL_TOP = 0
+ _STATICBOX_WIDTH = 410
+ _BOX_WIDTH = 200
+ PANEL_SIZE = 440
+ FONT_VARIANT = 0
+else:
+ PANEL_TOP = 60
+ _STATICBOX_WIDTH = 430
+ _BOX_WIDTH = 200
+ PANEL_SIZE = 460
+ FONT_VARIANT = 1
+
+class DensityPanel(ScrolledPanel, PanelBase):
+ """
+ Provides the mass density calculator GUI.
+ """
+ ## Internal nickname for the window, used by the AUI manager
+ window_name = "Mass Density Calculator"
+ ## Name to appear on the window title bar
+ window_caption = "Mass Density Calculator"
+ ## Flag to tell the AUI manager to put this panel in the center pane
+ CENTER_PANE = True
+
+ def __init__(self, parent, base=None, *args, **kwds):
+ """
+ """
+ ScrolledPanel.__init__(self, parent, *args, **kwds)
+ PanelBase.__init__(self)
+ self.SetupScrolling()
+ #Font size
+ self.SetWindowVariant(variant=FONT_VARIANT)
+ # Object that receive status event
+ self.base = base
+ self.parent = parent
+ # chemeical formula, string
+ self.compound = ''
+ # value of the density/volume, float
+ self.input = None
+ # text controls
+ self.compound_ctl = None
+ self.input_ctl = None
+ self.molar_mass_ctl = None
+ self.output_ctl = None
+ self.ctr_color = self.GetBackgroundColour()
+ # button
+ self.button_calculate = None
+ # list
+ self._input_list = _INPUTS
+ self._input = self._input_list[1]
+ self._output = self._input_list[0]
+ self._unit_list = _UNITS
+ #Draw the panel
+ self._do_layout()
+ self.SetAutoLayout(True)
+ self.Layout()
+
+ def _do_layout(self):
+ """
+ Draw window content
+ """
+ # units
+ unit_density = self._unit_list[0]
+ unit_volume = self._unit_list[1]
+
+ # sizers
+ sizer_input = wx.GridBagSizer(5, 5)
+ sizer_output = wx.GridBagSizer(5, 5)
+ sizer_button = wx.BoxSizer(wx.HORIZONTAL)
+ self.sizer1 = wx.BoxSizer(wx.HORIZONTAL)
+ self.sizer2 = wx.BoxSizer(wx.HORIZONTAL)
+ sizer3 = wx.BoxSizer(wx.HORIZONTAL)
+ vbox = wx.BoxSizer(wx.VERTICAL)
+
+ # inputs
+ inputbox = wx.StaticBox(self, -1, "Inputs")
+ boxsizer1 = wx.StaticBoxSizer(inputbox, wx.VERTICAL)
+ boxsizer1.SetMinSize((_STATICBOX_WIDTH, -1))
+ compound_txt = wx.StaticText(self, -1, 'Molecular Formula ')
+ self.compound_ctl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, -1))
+ self.compound_eg1 = wx.StaticText(self, -1, ' e.g., H2O')
+ self.compound_eg2 = wx.StaticText(self, -1, 'e.g., D2O')
+ self.input_cb = wx.ComboBox(self, -1, style=wx.CB_READONLY)
+ wx.EVT_COMBOBOX(self.input_cb, -1, self.on_select_input)
+ hint_input_name_txt = 'Mass or volume.'
+ self.input_cb.SetToolTipString(hint_input_name_txt)
+ unit_density1 = " " + unit_density
+ self.input_ctl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, -1))
+ self.unit_input_density = wx.StaticText(self, -1, unit_density1)
+ self.unit_input_volume = wx.StaticText(self, -1, unit_volume)
+ iy = 0
+ ix = 0
+ sizer_input.Add(compound_txt, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ ix += 1
+ sizer_input.Add(self.compound_ctl, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix += 1
+ sizer_input.Add(self.compound_eg1, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+
+ ix += 1
+ sizer_input.Add(self.compound_eg2, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ self.compound_eg1.Show(False)
+ iy += 1
+ ix = 0
+ sizer_input.Add(self.input_cb, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ ix += 1
+ sizer_input.Add(self.input_ctl, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix += 1
+ sizer_input.Add(self.unit_input_density, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix += 1
+ self.unit_input_density.Show(False)
+ sizer_input.Add(self.unit_input_volume, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ boxsizer1.Add(sizer_input)
+ self.sizer1.Add(boxsizer1, 0, wx.EXPAND | wx.ALL, 10)
+
+ # outputs
+ outputbox = wx.StaticBox(self, -1, "Outputs")
+ boxsizer2 = wx.StaticBoxSizer(outputbox, wx.VERTICAL)
+ boxsizer2.SetMinSize((_STATICBOX_WIDTH, -1))
+
+ molar_mass_txt = wx.StaticText(self, -1, 'Molar Mass ')
+ self.molar_mass_ctl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, -1))
+ self.molar_mass_ctl.SetEditable(False)
+ self.molar_mass_ctl.SetBackgroundColour(self.ctr_color)
+ self.molar_mass_unit1 = wx.StaticText(self, -1, ' g/mol')
+ self.molar_mass_unit2 = wx.StaticText(self, -1, 'g/mol')
+
+ self.output_cb = wx.ComboBox(self, -1, style=wx.CB_READONLY)
+ wx.EVT_COMBOBOX(self.output_cb, -1, self.on_select_output)
+ hint_output_name_txt = 'Mass or volume.'
+ self.output_cb.SetToolTipString(hint_output_name_txt)
+ list = []
+ for item in self._input_list:
+ name = str(item)
+ list.append(name)
+ list.sort()
+ for idx in range(len(list)):
+ self.input_cb.Append(list[idx], idx)
+ self.output_cb.Append(list[idx], idx)
+ self.input_cb.SetStringSelection("Molar Volume")
+ self.output_cb.SetStringSelection("Mass Density")
+ unit_volume = " " + unit_volume
+ self.output_ctl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, -1))
+ self.output_ctl.SetEditable(False)
+ self.output_ctl.SetBackgroundColour(self.ctr_color)
+ self.unit_output_density = wx.StaticText(self, -1, unit_density)
+ self.unit_output_volume = wx.StaticText(self, -1, unit_volume)
+ iy = 0
+ ix = 0
+ sizer_output.Add(molar_mass_txt, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ ix += 1
+ sizer_output.Add(self.molar_mass_ctl, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix += 1
+ sizer_output.Add(self.molar_mass_unit1, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix += 1
+ sizer_output.Add(self.molar_mass_unit2, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ self.molar_mass_unit1.Show(False)
+ iy += 1
+ ix = 0
+ sizer_output.Add(self.output_cb, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ ix += 1
+ sizer_output.Add(self.output_ctl, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix += 1
+ sizer_output.Add(self.unit_output_volume,
+ (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix += 1
+ sizer_output.Add(self.unit_output_density,
+ (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+
+ self.unit_output_volume.Show(False)
+ boxsizer2.Add(sizer_output)
+ self.sizer2.Add(boxsizer2, 0, wx.EXPAND | wx.ALL, 10)
+
+ # buttons
+ id = wx.NewId()
+ self.button_calculate = wx.Button(self, id, "Calculate")
+ self.button_calculate.SetToolTipString("Calculate.")
+ self.Bind(wx.EVT_BUTTON, self.calculate, id=id)
+
+ id = wx.NewId()
+ self.button_help = wx.Button(self, id, "HELP")
+ self.button_help.SetToolTipString("Help for density calculator.")
+ self.Bind(wx.EVT_BUTTON, self.on_help, id=id)
+
+ self.button_close = wx.Button(self, wx.ID_CANCEL, 'Close')
+ self.button_close.Bind(wx.EVT_BUTTON, self.on_close)
+ self.button_close.SetToolTipString("Close this window.")
+
+ sizer_button.Add((100, 20), 1, wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ sizer_button.Add(self.button_calculate, 0,
+ wx.RIGHT | wx.ADJUST_MINSIZE, 20)
+ sizer_button.Add(self.button_help, 0,
+ wx.RIGHT | wx.ADJUST_MINSIZE, 20)
+ sizer_button.Add(self.button_close, 0,
+ wx.RIGHT | wx.ADJUST_MINSIZE, 20)
+ sizer3.Add(sizer_button)
+
+ # layout
+ vbox.Add(self.sizer1)
+ vbox.Add(self.sizer2)
+ vbox.Add(sizer3)
+ vbox.Fit(self)
+ self.SetSizer(vbox)
+
+ def on_select_input(self, event):
+ """
+ On selection of input combobox,
+ update units and output combobox
+ """
+ if event is None:
+ return
+ event.Skip()
+
+ combo = event.GetEventObject()
+ self._input = combo.GetValue()
+ for name in self._input_list:
+ if self._input != name:
+ self._output = name
+ break
+
+ self.set_values()
+
+ def on_select_output(self, event):
+ """
+ On selection of output combobox,
+ update units and input combobox
+ """
+ if event is None:
+ return
+ event.Skip()
+
+ combo = event.GetEventObject()
+ self._output = combo.GetValue()
+ for name in self._input_list:
+ if self._output != name:
+ self._input = name
+ break
+
+ self.set_values()
+
+ def set_values(self):
+ """
+ Sets units and combobox values
+ """
+ input, output = self.get_input()
+ if input is None:
+ return
+ # input
+ self.input_cb.SetValue(str(input))
+ # output
+ self.output_cb.SetValue(str(output))
+ # unit
+ if self._input_list.index(input) == 0:
+ self.molar_mass_unit1.Show(True)
+ self.molar_mass_unit2.Show(False)
+ self.compound_eg1.Show(True)
+ self.compound_eg2.Show(False)
+ self.unit_input_density.Show(True)
+ self.unit_output_volume.Show(True)
+ self.unit_input_volume.Show(False)
+ self.unit_output_density.Show(False)
+ else:
+ self.molar_mass_unit1.Show(False)
+ self.molar_mass_unit2.Show(True)
+ self.compound_eg1.Show(False)
+ self.compound_eg2.Show(True)
+ self.unit_input_volume.Show(True)
+ self.unit_output_density.Show(True)
+ self.unit_input_density.Show(False)
+ self.unit_output_volume.Show(False)
+ # layout
+ self.clear_outputs()
+ self.sizer1.Layout()
+ self.sizer2.Layout()
+
+ def get_input(self):
+ """
+ Return the current input and output combobox values
+ """
+ return self._input, self._output
+
+ def check_inputs(self):
+ """
+ Check validity user inputs
+ """
+ flag = True
+ msg = ""
+ if check_float(self.input_ctl):
+ self.input = float(self.input_ctl.GetValue())
+ else:
+ flag = False
+ input_type = str(self.input_cb.GetValue())
+ msg += "Error for %s value :expect float" % input_type
+
+ self.compound = self.compound_ctl.GetValue().lstrip().rstrip()
+ if self.compound != "":
+ try :
+ Formula(self.compound)
+ self.compound_ctl.SetBackgroundColour(wx.WHITE)
+ self.compound_ctl.Refresh()
+ except:
+ self.compound_ctl.SetBackgroundColour("pink")
+ self.compound_ctl.Refresh()
+ flag = False
+ msg += "Enter correct formula"
+ else:
+ self.compound_ctl.SetBackgroundColour("pink")
+ self.compound_ctl.Refresh()
+ flag = False
+ msg += "Enter Formula"
+ return flag, msg
+
+
+ def calculate(self, event):
+ """
+ Calculate the mass Density/molar Volume of the molecules
+ """
+ self.clear_outputs()
+ try:
+ #Check validity user inputs
+ flag, msg = self.check_inputs()
+ if self.base is not None and msg.lstrip().rstrip() != "":
+ msg = "Density/Volume Calculator: %s" % str(msg)
+ wx.PostEvent(self.base, StatusEvent(status=msg))
+ if not flag:
+ return
+ #get ready to compute
+ mol_formula = Formula(self.compound)
+ molar_mass = float(mol_formula.molecular_mass) * AVOGADRO
+ output = self._format_number(molar_mass / self.input)
+ self.molar_mass_ctl.SetValue(str(self._format_number(molar_mass)))
+ self.output_ctl.SetValue(str(output))
+ except:
+ if self.base is not None:
+ msg = "Density/Volume Calculator: %s" % (sys.exc_value)
+ wx.PostEvent(self.base, StatusEvent(status=msg))
+ if event is not None:
+ event.Skip()
+
+ def on_help(self, event):
+ """
+ Bring up the density/volume calculator Documentation whenever
+ the HELP button is clicked.
+
+ Calls DocumentationWindow with the path of the location within the
+ documentation tree (after /doc/ ....". Note that when using old
+ versions of Wx (before 2.9) and thus not the release version of
+ installers, the help comes up at the top level of the file as
+ webbrowser does not pass anything past the # to the browser when it is
+ running "file:///...."
+
+ :param evt: Triggers on clicking the help button
+ """
+
+ _TreeLocation = "user/sasgui/perspectives/calculator/"
+ _TreeLocation += "density_calculator_help.html"
+ _doc_viewer = DocumentationWindow(self, -1, _TreeLocation, "",
+ "Density/Volume Calculator Help")
+
+ def on_close(self, event):
+ """
+ close the window containing this panel
+ """
+ self.parent.Close()
+
+ def clear_outputs(self):
+ """
+ Clear the outputs textctrl
+ """
+ self.molar_mass_ctl.SetValue("")
+ self.output_ctl.SetValue("")
+
+ def _format_number(self, value=None):
+ """
+ Return a float in a standardized, human-readable formatted string
+ """
+ try:
+ value = float(value)
+ except:
+ output = ''
+ return output
+
+ output = "%-12.5f" % value
+ return output.lstrip().rstrip()
+
+class DensityWindow(widget.CHILD_FRAME):
+ """
+ """
+ def __init__(self, parent=None, title="Density/Volume Calculator",
+ base=None, manager=None,
+ size=(PANEL_SIZE * 1.05, PANEL_SIZE / 1.55), *args, **kwds):
+ """
+ """
+ kwds['title'] = title
+ kwds['size'] = size
+ widget.CHILD_FRAME.__init__(self, parent, *args, **kwds)
+ """
+ """
+ self.manager = manager
+ self.panel = DensityPanel(self, base=base)
+ self.Bind(wx.EVT_CLOSE, self.on_close)
+ self.SetPosition((wx.LEFT, PANEL_TOP))
+ self.Show(True)
+
+ def on_close(self, event):
+ """
+ On close event
+ """
+ if self.manager is not None:
+ self.manager.cal_md_frame = None
+ self.Destroy()
+
+
+class ViewApp(wx.App):
+ """
+ """
+ def OnInit(self):
+ """
+ """
+ widget.CHILD_FRAME = wx.Frame
+ frame = DensityWindow(None, title="Density/Volume Calculator")
+ frame.Show(True)
+ self.SetTopWindow(frame)
+ return True
+
+
+if __name__ == "__main__":
+ app = ViewApp(0)
+ app.MainLoop()
diff --git a/src/sas/sasgui/perspectives/calculator/detector_editor.py b/src/sas/sasgui/perspectives/calculator/detector_editor.py
index cdf1332..e854716 100644
--- a/src/sas/sasgui/perspectives/calculator/detector_editor.py
+++ b/src/sas/sasgui/perspectives/calculator/detector_editor.py
@@ -1,859 +1,860 @@
-
-import wx
-import sys
-from copy import deepcopy
-from sas.sascalc.dataloader.data_info import Detector
-from sas.sasgui.guiframe.utils import check_float
-
-_BOX_WIDTH = 60
-if sys.platform.count("win32") > 0:
- _STATICBOX_WIDTH = 465
- PANEL_WIDTH = 500
- PANEL_HEIGHT = 450
- FONT_VARIANT = 0
-else:
- _STATICBOX_WIDTH = 480
- PANEL_WIDTH = 550
- PANEL_HEIGHT = 480
- FONT_VARIANT = 1
-
-class DetectorDialog(wx.Dialog):
- def __init__(self, parent=None, manager=None, detector=None,
- title="Detector Editor",
- size=(PANEL_WIDTH, PANEL_HEIGHT)):
- wx.Dialog.__init__(self, parent=parent, id=id, title=title, size=size)
- try:
- self.parent = parent
- self.manager = manager
- self._detector = detector
-
- self._reset_detector = deepcopy(detector)
- self._notes = ""
- self._description = "Edit Detector"
- self._do_layout()
- self.set_values()
- except:
- print "error", sys.exc_value
-
- def _define_structure(self):
- """
- define initial sizer
- """
- self.main_sizer = wx.BoxSizer(wx.VERTICAL)
- self.box_detector = wx.StaticBox(self, -1, str("Edit Selected Detector"))
- self.boxsizer_detector = wx.StaticBoxSizer(self.box_detector,
- wx.VERTICAL)
- detector_box = wx.StaticBox(self, -1, "Edit Number of Detectors")
- self.detector_sizer = wx.StaticBoxSizer(detector_box, wx.VERTICAL)
- self.detector_sizer.SetMinSize((_STATICBOX_WIDTH, -1))
- self.detector_button_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.detector_hint_sizer = wx.BoxSizer(wx.HORIZONTAL)
-
- self.detector_button_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.detector_hint_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.instrument_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.distance_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.offset_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.orientation_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.beam_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.pixel_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.slit_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.button_sizer = wx.BoxSizer(wx.HORIZONTAL)
-
- def _layout_detector(self):
- """
- Do the layout for detector related widgets
- """
- detector_name_txt = wx.StaticText(self, -1, "Detector:")
- hint_detector_txt = 'Current available detector.'
- detector_name_txt.SetToolTipString(hint_detector_txt)
- self.detector_cbox = wx.ComboBox(self, -1, style=wx.CB_READONLY)
- hint_detector_name_txt = 'Name of detectors.'
- self.detector_cbox.SetToolTipString(hint_detector_name_txt)
-
- self.bt_add_detector = wx.Button(self, -1, "Add")
- self.bt_add_detector.SetToolTipString("Add data's detector.")
- self.bt_add_detector.Bind(wx.EVT_BUTTON, self.add_detector)
-
- self.bt_remove_detector = wx.Button(self, -1, "Remove")
- self.bt_remove_detector.SetToolTipString("Remove data's detector.")
- self.bt_remove_detector.Bind(wx.EVT_BUTTON, self.remove_detector)
-
- self.detector_button_sizer.AddMany([(detector_name_txt, 0, wx.LEFT, 15),
- (self.detector_cbox, 0, wx.LEFT, 5),
- (self.bt_add_detector, 0, wx.LEFT, 10),
- (self.bt_remove_detector, 0, wx.LEFT, 5)])
- detector_hint_txt = 'No detector is available for this data.'
- self.detector_txt = wx.StaticText(self, -1, detector_hint_txt)
- self.detector_hint_sizer.Add(self.detector_txt, 0, wx.LEFT, 10)
- self.detector_sizer.AddMany([(self.detector_button_sizer, 0,
- wx.ALL, 10),
- (self.detector_hint_sizer, 0, wx.ALL, 10)])
-
- self.fill_detector_combox()
- self.enable_detector()
-
- def _layout_instrument_sizer(self):
- """
- Do the layout for instrument related widgets
- """
- #Instrument
- instrument_name_txt = wx.StaticText(self, -1, 'Instrument Name : ')
- self.instrument_name_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH * 5, 20), style=0)
- self.instrument_sizer.AddMany([(instrument_name_txt, 0,
- wx.LEFT | wx.RIGHT, 10),
- (self.instrument_name_tcl, 0, wx.EXPAND)])
- def _layout_distance(self):
- """
- Do the layout for distance related widgets
- """
- distance_txt = wx.StaticText(self, -1, 'Sample to Detector Distance : ')
- self.distance_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, 20), style=0)
- distance_unit_txt = wx.StaticText(self, -1, 'Unit: ')
- self.distance_unit_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, 20), style=0)
- self.distance_sizer.AddMany([(distance_txt, 0, wx.LEFT | wx.RIGHT, 10),
- (self.distance_tcl, 0, wx.RIGHT, 10),
- (distance_unit_txt, 0, wx.EXPAND),
- (self.distance_unit_tcl, 0, wx.RIGHT, 10)])
-
- def _layout_offset(self):
- """
- Do the layout for offset related widgets
- """
- #Offset
- offset_txt = wx.StaticText(self, -1, 'Offset:')
- x_offset_txt = wx.StaticText(self, -1, 'x = ')
- self.x_offset_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, 20), style=0)
- y_offset_txt = wx.StaticText(self, -1, 'y = ')
- self.y_offset_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, 20), style=0)
- z_offset_txt = wx.StaticText(self, -1, 'z = ')
- self.z_offset_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, 20), style=0)
- offset_unit_txt = wx.StaticText(self, -1, 'Unit: ')
- self.offset_unit_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, 20), style=0)
- self.offset_sizer.AddMany([(offset_txt, 0, wx.LEFT | wx.RIGHT, 10),
- (x_offset_txt, 0, wx.LEFT, 30),
- (self.x_offset_tcl, 0, wx.RIGHT, 10),
- (y_offset_txt, 0, wx.EXPAND),
- (self.y_offset_tcl, 0, wx.RIGHT, 10),
- (z_offset_txt, 0, wx.EXPAND),
- (self.z_offset_tcl, 0, wx.RIGHT, 10),
- (offset_unit_txt, 0, wx.EXPAND),
- (self.offset_unit_tcl, 0, wx.RIGHT, 10)])
-
- def _layout_orientation(self):
- """
- Do the layout for orientation related widgets
- """
- #Orientation
- orientation_txt = wx.StaticText(self, -1, 'Orientation:')
- x_orientation_txt = wx.StaticText(self, -1, 'x = ')
- self.x_orientation_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, 20), style=0)
- y_orientation_txt = wx.StaticText(self, -1, 'y = ')
- self.y_orientation_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, 20), style=0)
- z_orientation_txt = wx.StaticText(self, -1, 'z = ')
- self.z_orientation_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, 20), style=0)
- orientation_unit_txt = wx.StaticText(self, -1, 'Unit: ')
- self.orientation_unit_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, 20), style=0)
- self.orientation_sizer.AddMany([(orientation_txt, 0,
- wx.LEFT | wx.RIGHT, 10),
- (x_orientation_txt, 0, wx.LEFT, 7),
- (self.x_orientation_tcl, 0, wx.RIGHT, 10),
- (y_orientation_txt, 0, wx.EXPAND),
- (self.y_orientation_tcl, 0, wx.RIGHT, 10),
- (z_orientation_txt, 0, wx.EXPAND),
- (self.z_orientation_tcl, 0, wx.RIGHT, 10),
- (orientation_unit_txt, 0, wx.EXPAND),
- (self.orientation_unit_tcl, 0, wx.RIGHT, 10)])
-
- def _layout_beam_center(self):
- """
- Do the layout for beam center related widgets
- """
- #Beam center
- beam_center_txt = wx.StaticText(self, -1, 'Beam Center:')
- x_beam_center_txt = wx.StaticText(self, -1, 'x = ')
- self.x_beam_center_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, 20), style=0)
- y_beam_center_txt = wx.StaticText(self, -1, 'y = ')
- self.y_beam_center_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, 20), style=0)
- z_beam_center_txt = wx.StaticText(self, -1, 'z = ')
- self.z_beam_center_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, 20), style=0)
- beam_center_unit_txt = wx.StaticText(self, -1, 'Unit: ')
- self.beam_center_unit_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, 20), style=0)
- self.beam_sizer.AddMany([(beam_center_txt, 0, wx.LEFT | wx.RIGHT, 10),
- (x_beam_center_txt, 0, wx.EXPAND),
- (self.x_beam_center_tcl, 0, wx.RIGHT, 10),
- (y_beam_center_txt, 0, wx.EXPAND),
- (self.y_beam_center_tcl, 0, wx.RIGHT, 10),
- (z_beam_center_txt, 0, wx.EXPAND),
- (self.z_beam_center_tcl, 0, wx.RIGHT, 10),
- (beam_center_unit_txt, 0, wx.EXPAND),
- (self.beam_center_unit_tcl, 0, wx.RIGHT, 10)])
-
- def _layout_pixel_size(self):
- """
- Do the layout for pixel size related widgets
- """
- #Pixel Size
- pixel_size_txt = wx.StaticText(self, -1, 'Pixel Size:')
- x_pixel_size_txt = wx.StaticText(self, -1, 'x = ')
- self.x_pixel_size_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, 20), style=0)
- y_pixel_size_txt = wx.StaticText(self, -1, 'y = ')
- self.y_pixel_size_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, 20), style=0)
- z_pixel_size_txt = wx.StaticText(self, -1, 'z = ')
- self.z_pixel_size_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, 20), style=0)
- pixel_size_unit_txt = wx.StaticText(self, -1, 'Unit: ')
- self.pixel_size_unit_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, 20), style=0)
- self.pixel_sizer.AddMany([(pixel_size_txt, 0, wx.LEFT | wx.RIGHT, 10),
- (x_pixel_size_txt, 0, wx.LEFT, 17),
- (self.x_pixel_size_tcl, 0, wx.RIGHT, 10),
- (y_pixel_size_txt, 0, wx.EXPAND),
- (self.y_pixel_size_tcl, 0, wx.RIGHT, 10),
- (z_pixel_size_txt, 0, wx.EXPAND),
- (self.z_pixel_size_tcl, 0, wx.RIGHT, 10),
- (pixel_size_unit_txt, 0, wx.EXPAND),
- (self.pixel_size_unit_tcl, 0, wx.RIGHT, 10)])
-
- def _layout_slit_length(self):
- """
- Do the layout for slit length related widgets
- """
- #slit length
- slit_length_txt = wx.StaticText(self, -1, 'Slit Length: ')
- self.slit_length_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, 20), style=0)
- slit_length_unit_txt = wx.StaticText(self, -1, 'Unit: ')
- self.slit_length_unit_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, 20), style=0)
- self.slit_sizer.AddMany([(slit_length_txt, 0, wx.LEFT, 10),
- (self.slit_length_tcl, 0, wx.RIGHT, 10),
- (slit_length_unit_txt, 0, wx.EXPAND),
- (self.slit_length_unit_tcl, 0, wx.RIGHT, 10)])
-
- def _layout_button(self):
- """
- Do the layout for the button widgets
- """
- self.bt_apply = wx.Button(self, -1, 'Apply')
- self.bt_apply.Bind(wx.EVT_BUTTON, self.on_click_apply)
- self.bt_apply.SetToolTipString("Apply current changes to the detector.")
- self.bt_cancel = wx.Button(self, -1, 'Cancel')
- self.bt_cancel.SetToolTipString("Cancel current changes.")
- self.bt_cancel.Bind(wx.EVT_BUTTON, self.on_click_cancel)
- self.bt_close = wx.Button(self, wx.ID_CANCEL, 'Close')
- self.bt_close.SetToolTipString("Close window.")
- self.button_sizer.AddMany([(self.bt_apply, 0, wx.LEFT, 200),
- (self.bt_cancel, 0, wx.LEFT, 10),
- (self.bt_close, 0, wx.LEFT, 10)])
-
- def _do_layout(self, data=None):
- """
- Draw the current panel
- """
- self._define_structure()
- self._layout_detector()
- self._layout_instrument_sizer()
- self._layout_distance()
- self._layout_offset()
- self._layout_orientation()
- self._layout_beam_center()
- self._layout_pixel_size()
- self._layout_slit_length()
- self._layout_button()
-
- self.boxsizer_detector.AddMany([(self.instrument_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
- (self.distance_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
- (self.offset_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
- (self.orientation_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
- (self.beam_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
- (self.pixel_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
- (self.slit_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
- self.main_sizer.AddMany([(self.detector_sizer, 0, wx.ALL, 10),
- (self.boxsizer_detector, 0, wx.ALL, 10),
- (self.button_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
-
- self.SetSizer(self.main_sizer)
- self.SetAutoLayout(True)
-
- def reset_detector(self):
- """
- put the default value of the detector back to the current detector
- """
- self._detector = deepcopy(self._reset_detector)
- self.detector_cbox.Clear()
- self.fill_detector_combox()
- self.set_values()
-
- def set_manager(self, manager):
- """
- Set manager of this window
- """
- self.manager = manager
-
- def fill_detector_combox(self):
- """
- fill the current combobox with the available detector
- """
- for detector in self._detector:
- pos = self.detector_cbox.Append(str(detector.name))
- self.detector_cbox.SetClientData(pos, detector)
- self.detector_cbox.SetSelection(pos)
- self.detector_cbox.SetStringSelection(str(detector.name))
-
- def reset_detector_combobox(self, edited_detector):
- """
- take all edited editor and reset clientdata of detector combo box
- """
- for position in range(self.detector_cbox.GetCount()):
- detector = self.detector_cbox.GetClientData(position)
- if detector == edited_detector:
- detector = edited_detector
- self.detector_cbox.SetString(position, str(detector.name))
- self.detector_cbox.SetClientData(position, detector)
- self.detector_cbox.SetStringSelection(str(detector.name))
-
- def add_detector(self, event):
- """
- Append empty detector to data's list of detector
- """
-
- if not self.detector_cbox.IsEnabled():
- self.detector_cbox.Enable()
- detector = Detector()
- self._detector.append(detector)
- position = self.detector_cbox.Append(str(detector.name))
- self.detector_cbox.SetClientData(position, detector)
- self.detector_cbox.SetSelection(position)
- self.enable_detector()
- self.set_values()
-
- def remove_detector(self, event):
- """
- Remove detector to data's list of detector
- """
- if self.detector_cbox.IsEnabled():
- if self.detector_cbox.GetCount() > 1:
- position = self.detector_cbox.GetCurrentSelection()
- detector = self.detector_cbox.GetClientData(position)
- if detector in self._detector:
- self._detector.remove(detector)
- self.detector_cbox.Delete(position)
- #set the combo box box the next available item
- position = self.detector_cbox.GetCount()
- if position > 0:
- position -= 1
- self.detector_cbox.SetSelection(position)
- self.set_values()
- #disable or enable the combo box when necessary
- self.enable_detector()
-
- def enable_detector(self):
- """
- Enable /disable widgets crelated to detector
- """
- if self._detector is not None and self.detector_cbox.GetCount() > 0:
- self.detector_cbox.Enable()
- self.bt_remove_detector.Enable()
- n_detector = self.detector_cbox.GetCount()
- detector_hint_txt = 'Detectors available: %s ' % str(n_detector)
- if len(self._detector) > 1:
- self.bt_remove_detector.Enable()
- else:
- self.bt_remove_detector.Disable()
- else:
- self.detector_cbox.Disable()
- self.bt_remove_detector.Disable()
- detector_hint_txt = 'No detector is available for this data.'
- self.detector_txt.SetLabel(detector_hint_txt)
-
- def set_detector(self, detector):
- """
- set detector for data
- """
- if self._detector is None:
- return
- if self._detector:
- for item in self._detector:
- if item == detector:
- item = detector
- self.reset_detector_combobox(edited_detector=detector)
- return
-
- def get_current_detector(self):
- """
- """
- if not self.detector_cbox.IsEnabled():
- return None, None, None
- position = self.detector_cbox.GetSelection()
- if position == wx.NOT_FOUND:
- return None, None, None
- detector_name = self.detector_cbox.GetStringSelection()
- detector = self.detector_cbox.GetClientData(position)
- return detector, detector_name, position
-
- def set_values(self):
- """
- take the detector values of the current data and display them
- through the panel
- """
- detector, _, _ = self.get_current_detector()
- if detector is None:
- return
- self.instrument_name_tcl.SetValue(str(detector.name))
- #Distance
- distance = detector.distance
- self.distance_tcl.SetValue(str(distance))
- self.distance_unit_tcl.SetValue(str(detector.distance_unit))
- #Offset
- x, y, z = detector.offset.x, detector.offset.y , detector.offset.z
- self.x_offset_tcl.SetValue(str(x))
- self.y_offset_tcl.SetValue(str(y))
- self.z_offset_tcl.SetValue(str(z))
- self.offset_unit_tcl.SetValue(str(detector.offset_unit))
- #Orientation
- x, y = detector.orientation.x, detector.orientation.y
- z = detector.orientation.z
- self.x_orientation_tcl.SetValue(str(x))
- self.y_orientation_tcl.SetValue(str(y))
- self.z_orientation_tcl.SetValue(str(z))
- self.orientation_unit_tcl.SetValue(str(detector.orientation_unit))
- #Beam center
- x, y = detector.beam_center.x, detector.beam_center.y
- z = detector.beam_center.z
- self.x_beam_center_tcl.SetValue(str(x))
- self.y_beam_center_tcl.SetValue(str(y))
- self.z_beam_center_tcl.SetValue(str(z))
- self.beam_center_unit_tcl.SetValue(str(detector.beam_center_unit))
- #Pixel size
- x, y = detector.pixel_size.x, detector.pixel_size.y
- z = detector.pixel_size.z
- self.x_pixel_size_tcl.SetValue(str(x))
- self.y_pixel_size_tcl.SetValue(str(y))
- self.z_pixel_size_tcl.SetValue(str(z))
- self.pixel_size_unit_tcl.SetValue(str(detector.pixel_size_unit))
- #Slit length
- slit_length = detector.slit_length
- self.slit_length_tcl.SetValue(str(detector.slit_length))
- self.slit_length_unit_tcl.SetValue(str(detector.slit_length_unit))
-
- def get_detector(self):
- """
- return the current detector
- """
- return self._detector
-
- def get_notes(self):
- """
- return notes
- """
- return self._notes
-
- def on_change_instrument(self):
- """
- Change instrument
- """
- detector, detector_name, position = self.get_current_detector()
- if detector is None:
- return
- #Change the name of the detector
- name = self.instrument_name_tcl.GetValue().lstrip().rstrip()
- if name == "" or name == str(None):
- name = None
- if detector_name != name:
- self._notes += " Instrument's "
- self._notes += "name from %s to %s \n" % (detector_name, name)
- detector.name = name
- self.detector_cbox.SetString(position, str(detector.name))
- self.detector_cbox.SetClientData(position, detector)
- self.detector_cbox.SetStringSelection(str(detector.name))
-
- def on_change_distance(self):
- """
- Change distance of the sample to the detector
- """
- detector, _, position = self.get_current_detector()
- if detector is None:
- return
- #Change the distance
- distance = self.distance_tcl.GetValue().lstrip().rstrip()
- if distance == "" or distance == str(None):
- distance = None
- detector.distance = distance
- else:
- if check_float(self.distance_tcl):
- if detector.distance != float(distance):
- self._notes += " Change Distance from"
- self._notes += " %s to %s \n" % (detector.distance, distance)
- detector.distance = float(distance)
- else:
- self._notes += "Error: Expected a float for "
- self._notes += " the distance won't changes "
- self._notes += "%s to %s" % (detector.distance, distance)
- #change the distance unit
- unit = self.distance_unit_tcl.GetValue().lstrip().rstrip()
- if detector.distance_unit != unit:
- self._notes += " Change distance's unit from "
- self._notes += "%s to %s" % (detector.distance_unit, unit)
-
- self.detector_cbox.SetString(position, str(detector.name))
- self.detector_cbox.SetClientData(position, detector)
- self.detector_cbox.SetStringSelection(str(detector.name))
-
- def on_change_offset(self):
- """
- Change the detector offset
- """
- detector, _, position = self.get_current_detector()
- if detector is None:
- return
- #Change x coordinate
- x_offset = self.x_offset_tcl.GetValue().lstrip().rstrip()
- if x_offset == "" or x_offset == str(None):
- x_offset = None
- detector.offset.x = x_offset
- else:
- if check_float(self.x_offset_tcl):
- if detector.offset.x != float(x_offset):
- self._notes += "Change x of offset from"
- self._notes += " %s to %s \n" % (detector.offset.x,
- x_offset)
- detector.offset.x = float(x_offset)
- else:
- self._notes += "Error: Expected a float for the offset 's x "
- self._notes += "won't changes x offset"
- self._notes += " from %s to %s" % (detector.offset.x, x_offset)
- #Change y coordinate
- y_offset = self.y_offset_tcl.GetValue().lstrip().rstrip()
- if y_offset == "" or y_offset == str(None):
- y_offset = None
- detector.offset.y = y_offset
- else:
- if check_float(self.y_offset_tcl):
- if detector.offset.y != float(y_offset):
- self._notes += "Change y of offset from "
- self._notes += "%s to %s \n" % (detector.offset.y, y_offset)
- detector.offset.y = float(y_offset)
- else:
- self._notes += "Error: Expected a float for the offset 's y "
- self._notes += "won't changes y "
- self._notes += "offset from %s to %s" % (detector.offset.y,
- y_offset)
- #Change z coordinate
- z_offset = self.z_offset_tcl.GetValue().lstrip().rstrip()
- if z_offset == "" or z_offset == str(None):
- z_offset = None
- detector.offset.z = z_offset
- else:
- if check_float(self.z_offset_tcl):
- if detector.offset.z != float(z_offset):
- self._notes += "Change z of offset from"
- self._notes += " %s to %s \n" % (detector.offset.z,
- z_offset)
- detector.offset.z = float(z_offset)
- else:
- self._notes += "Error: Expected a float for the offset 's x "
- self._notes += "won't changes z"
- self._notes += "offset from %s to %s" % (detector.offset.z,
- z_offset)
- #change the offset unit
- unit = self.offset_unit_tcl.GetValue().lstrip().rstrip()
- if detector.offset_unit != unit:
- self._notes += " Change Offset's"
- self._notes += "unit from %s to %s" % (detector.offset_unit, unit)
-
- self.detector_cbox.SetString(position, str(detector.name))
- self.detector_cbox.SetClientData(position, detector)
- self.detector_cbox.SetStringSelection(str(detector.name))
-
- def on_change_orientation(self):
- """
- Change the detector orientation
- """
- detector, _, position = self.get_current_detector()
- if detector is None:
- return
- #Change x coordinate
- x_orientation = self.x_orientation_tcl.GetValue().lstrip().rstrip()
- if x_orientation == "" or x_orientation == str(None):
- x_orientation = None
- detector.orientation.x = x_orientation
- else:
- if check_float(self.x_orientation_tcl):
- if detector.orientation.x != float(x_orientation):
- self._notes += "Change x of orientation from "
- self._notes += "%s to %s \n" % (detector.orientation.x,
- x_orientation)
- detector.orientation.x = float(x_orientation)
- else:
- self._notes += "Error: Expected a float for the orientation "
- self._notes += "'s x won't changes x orientation from "
- self._notes += "%s to %s" % (detector.orientation.x,
- x_orientation)
- #Change y coordinate
- y_orientation = self.y_orientation_tcl.GetValue().lstrip().rstrip()
- if y_orientation == "" or y_orientation == str(None):
- y_orientation = None
- detector.orientation.y = y_orientation
- else:
- if check_float(self.y_orientation_tcl):
- if detector.orientation.y != float(y_orientation):
- self._notes += "Change y of orientation from "
- self._notes += "%s to %s \n" % (detector.orientation.y,
- y_orientation)
- detector.orientation.y = float(y_orientation)
- else:
- self._notes += "Error: Expected a float for the orientation's "
- self._notes += " y won't changes y orientation from "
- self._notes += "%s to %s" % (detector.orientation.y,
- y_orientation)
- #Change z coordinate
- z_orientation = self.z_orientation_tcl.GetValue().lstrip().rstrip()
- if z_orientation == "" or z_orientation == str(None):
- z_orientation = None
- detector.orientation.z = z_orientation
- else:
- if check_float(self.z_orientation_tcl):
- if detector.orientation.z != float(z_orientation):
- self._notes += "Change z of offset from "
- self._notes += "%s to %s \n" % (detector.orientation.z,
- z_orientation)
- detector.orientation.z = float(z_orientation)
- else:
- self._notes += "Error: Expected a float for the orientation 's"
- self._notes += " x won't changes z orientation from "
- self._notes += "%s to %s" % (detector.orientation.z,
- z_orientation)
- #change the orientation unit
- unit = self.orientation_unit_tcl.GetValue().lstrip().rstrip()
- if detector.orientation_unit != unit:
- self._notes += " Change orientation's unit from "
- self._notes += "%s to %s" % (detector.orientation_unit, unit)
-
- self.detector_cbox.SetString(position, str(detector.name))
- self.detector_cbox.SetClientData(position, detector)
- self.detector_cbox.SetStringSelection(str(detector.name))
-
- def on_change_beam_center(self):
- """
- Change the detector beam center
- """
-
- detector, _, position = self.get_current_detector()
- if detector is None:
- return
- #Change x coordinate
- x_beam_center = self.x_beam_center_tcl.GetValue().lstrip().rstrip()
- if x_beam_center == "" or x_beam_center == str(None):
- x_beam_center = None
- detector.beam_center.x = x_beam_center
- else:
- if check_float(self.x_beam_center_tcl):
- if detector.beam_center.x != float(x_beam_center):
- self._notes += "Change x of offset from "
- self._notes += "%s to %s \n" % (detector.beam_center.x,
- x_beam_center)
- detector.beam_center.x = float(x_beam_center)
- else:
- self._notes += "Error: Expected a float for the beam "
- self._notes += "center 's x won't changes x beam center from "
- self._notes += "%s to %s" % (detector.beam_center.x,
- x_beam_center)
- #Change y coordinate
- y_beam_center = self.y_beam_center_tcl.GetValue().lstrip().rstrip()
- if y_beam_center == "" or y_beam_center == str(None):
- y_beam_center = None
- detector.beam_center.y = y_beam_center
- else:
- if check_float(self.y_beam_center_tcl):
- if detector.beam_center.y != float(y_beam_center):
- self._notes += "Change y of beam center from "
- self._notes += "%s to %s \n" % (detector.beam_center.y,
- y_beam_center)
- detector.beam_center.y = float(y_beam_center)
- else:
- self._notes += "Error: Expected a float for the beam "
- self._notes += "center 's y won't changes y beam center from "
- self._notes += "%s to %s" % (detector.beam_center.y,
- y_beam_center)
- #Change z coordinate
- z_beam_center = self.z_beam_center_tcl.GetValue().lstrip().rstrip()
- if z_beam_center == "" or z_beam_center == str(None):
- z_beam_center = None
- detector.beam_center.z = z_beam_center
- else:
- if check_float(self.z_beam_center_tcl):
- if detector.beam_center.z != float(z_beam_center):
- self._notes += "Change z of beam center from "
- self._notes += "%s to %s \n" % (detector.beam_center.z,
- z_beam_center)
- detector.beam_center.z = float(z_beam_center)
- else:
- self._notes += "Error: Expected a float for the offset 's x "
- self._notes += "won't changes z beam center from "
- self._notes += "%s to %s" % (detector.beam_center.z,
- z_beam_center)
- #change the beam center unit
- unit = self.beam_center_unit_tcl.GetValue().lstrip().rstrip()
- if detector.beam_center_unit != unit:
- self._notes += " Change beam center's unit from "
- self._notes += "%s to %s" % (detector.beam_center_unit, unit)
-
- self.detector_cbox.SetString(position, str(detector.name))
- self.detector_cbox.SetClientData(position, detector)
- self.detector_cbox.SetStringSelection(str(detector.name))
-
- def on_change_pixel_size(self):
- """
- Change the detector pixel size
- """
- detector, _, position = self.get_current_detector()
- if detector is None:
- return
- #Change x coordinate
- x_pixel_size = self.x_pixel_size_tcl.GetValue().lstrip().rstrip()
- if x_pixel_size == "" or x_pixel_size == str(None):
- x_pixel_size = None
- else:
- if check_float(self.x_pixel_size_tcl):
- if detector.pixel_size.x != float(x_pixel_size) :
- self._notes += "Change x of pixel size from "
- self._notes += "%s to %s \n" % (detector.pixel_size.x,
- x_pixel_size)
- detector.pixel_size.x = float(x_pixel_size)
- else:
- self._notes += "Error: Expected a float for the pixel"
- self._notes += " size 's x won't changes x pixel size from "
- self._notes += "%s to %s" % (detector.pixel_size.x,
- x_pixel_size)
- #Change y coordinate
- y_pixel_size = self.y_pixel_size_tcl.GetValue().lstrip().rstrip()
- if y_pixel_size == "" or y_pixel_size == str(None):
- y_pixel_size = None
- detector.pixel_size.y = y_pixel_size
- else:
- if check_float(self.y_pixel_size_tcl):
- if detector.pixel_size.y != float(y_pixel_size):
- self._notes += "Change y of pixel size from "
- self._notes += "%s to %s \n" % (detector.pixel_size.y,
- y_pixel_size)
- detector.pixel_size.y = float(y_pixel_size)
- else:
- self._notes += "Error: Expected a float for the pixel "
- self._notes += "size's y won't changes y pixel size from "
- self._notes += "%s to %s" % (detector.pixel_size.y,
- y_pixel_size)
- #Change z coordinate
- z_pixel_size = self.z_pixel_size_tcl.GetValue().lstrip().rstrip()
- if z_pixel_size == "" or z_pixel_size == str(None):
- z_pixel_size = None
- detector.pixel_size.z = z_pixel_size
- else:
- if check_float(self.z_pixel_size_tcl):
- if detector.pixel_size.z != float(z_pixel_size):
- self._notes += "Change z of pixel size from "
- self._notes += "%s to %s \n" % (detector.pixel_size.z,
- z_pixel_size)
- detector.pixel_size.z = float(z_pixel_size)
- else:
- self._notes += "Error: Expected a float for the offset 's x "
- self._notes += "won't changes z pixel size from "
- self._notes += "%s to %s" % (detector.pixel_size.z, z_pixel_size)
- #change the beam center unit
- unit = self.pixel_size_unit_tcl.GetValue().lstrip().rstrip()
- if detector.pixel_size_unit != unit:
- self._notes += " Change pixel size's unit from "
- self._notes += "%s to %s" % (detector.pixel_size_unit, unit)
-
- self.detector_cbox.SetString(position, str(detector.name))
- self.detector_cbox.SetClientData(position, detector)
- self.detector_cbox.SetStringSelection(str(detector.name))
-
- def on_change_slit_length(self):
- """
- Change slit length of the detector
- """
- detector, _, position = self.get_current_detector()
- if detector is None:
- return
- #Change the distance
- slit_length = self.slit_length_tcl.GetValue().lstrip().rstrip()
- if slit_length == "" or slit_length == str(None):
- slit_length = None
- detector.slit_length = slit_length
- else:
- if check_float(self.slit_length_tcl):
- if detector.slit_length != float(slit_length):
- self._notes += " Change slit length from"
- self._notes += " %s to %s \n" % (detector.slit_length,
- slit_length)
- detector.slit_length = float(slit_length)
- else:
- self._notes += "Error: Expected a float"
- self._notes += " for the slit length won't changes "
- self._notes += "%s to %s" % (detector.slit_length, slit_length)
- #change the distance unit
- unit = self.slit_length_unit_tcl.GetValue().lstrip().rstrip()
- if detector.slit_length_unit != unit:
- self._notes += " Change slit length's unit from "
- self._notes += "%s to %s" % (detector.slit_length_unit_tcl, unit)
-
- self.detector_cbox.SetString(position, str(detector.name))
- self.detector_cbox.SetClientData(position, detector)
- self.detector_cbox.SetStringSelection(str(detector.name))
-
- def on_click_cancel(self, event):
- """
- reset the current detector to its initial values
- """
- self.reset_detector()
- self.set_values()
- if self.manager is not None:
- self.manager.set_detector(self._detector)
-
- def on_click_apply(self, event):
- """
- Apply user values to the detector
- """
- self.on_change_instrument()
- self.on_change_distance()
- self.on_change_instrument()
- self.on_change_beam_center()
- self.on_change_offset()
- self.on_change_orientation()
- self.on_change_pixel_size()
- self.on_change_slit_length()
- for detector in self._detector:
- self.manager.set_detector(self._detector, self._notes)
-
-if __name__ == "__main__":
- app = wx.App()
- test_detector = Detector()
- dlg = DetectorDialog(detector=[test_detector])
- dlg.ShowModal()
- app.MainLoop()
+from __future__ import print_function
+
+import wx
+import sys
+from copy import deepcopy
+from sas.sascalc.dataloader.data_info import Detector
+from sas.sasgui.guiframe.utils import check_float
+
+_BOX_WIDTH = 60
+if sys.platform.count("win32") > 0:
+ _STATICBOX_WIDTH = 465
+ PANEL_WIDTH = 500
+ PANEL_HEIGHT = 450
+ FONT_VARIANT = 0
+else:
+ _STATICBOX_WIDTH = 480
+ PANEL_WIDTH = 550
+ PANEL_HEIGHT = 480
+ FONT_VARIANT = 1
+
+class DetectorDialog(wx.Dialog):
+ def __init__(self, parent=None, manager=None, detector=None,
+ title="Detector Editor",
+ size=(PANEL_WIDTH, PANEL_HEIGHT)):
+ wx.Dialog.__init__(self, parent=parent, id=id, title=title, size=size)
+ try:
+ self.parent = parent
+ self.manager = manager
+ self._detector = detector
+
+ self._reset_detector = deepcopy(detector)
+ self._notes = ""
+ self._description = "Edit Detector"
+ self._do_layout()
+ self.set_values()
+ except:
+ print("error", sys.exc_value)
+
+ def _define_structure(self):
+ """
+ define initial sizer
+ """
+ self.main_sizer = wx.BoxSizer(wx.VERTICAL)
+ self.box_detector = wx.StaticBox(self, -1, str("Edit Selected Detector"))
+ self.boxsizer_detector = wx.StaticBoxSizer(self.box_detector,
+ wx.VERTICAL)
+ detector_box = wx.StaticBox(self, -1, "Edit Number of Detectors")
+ self.detector_sizer = wx.StaticBoxSizer(detector_box, wx.VERTICAL)
+ self.detector_sizer.SetMinSize((_STATICBOX_WIDTH, -1))
+ self.detector_button_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.detector_hint_sizer = wx.BoxSizer(wx.HORIZONTAL)
+
+ self.detector_button_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.detector_hint_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.instrument_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.distance_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.offset_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.orientation_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.beam_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.pixel_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.slit_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.button_sizer = wx.BoxSizer(wx.HORIZONTAL)
+
+ def _layout_detector(self):
+ """
+ Do the layout for detector related widgets
+ """
+ detector_name_txt = wx.StaticText(self, -1, "Detector:")
+ hint_detector_txt = 'Current available detector.'
+ detector_name_txt.SetToolTipString(hint_detector_txt)
+ self.detector_cbox = wx.ComboBox(self, -1, style=wx.CB_READONLY)
+ hint_detector_name_txt = 'Name of detectors.'
+ self.detector_cbox.SetToolTipString(hint_detector_name_txt)
+
+ self.bt_add_detector = wx.Button(self, -1, "Add")
+ self.bt_add_detector.SetToolTipString("Add data's detector.")
+ self.bt_add_detector.Bind(wx.EVT_BUTTON, self.add_detector)
+
+ self.bt_remove_detector = wx.Button(self, -1, "Remove")
+ self.bt_remove_detector.SetToolTipString("Remove data's detector.")
+ self.bt_remove_detector.Bind(wx.EVT_BUTTON, self.remove_detector)
+
+ self.detector_button_sizer.AddMany([(detector_name_txt, 0, wx.LEFT, 15),
+ (self.detector_cbox, 0, wx.LEFT, 5),
+ (self.bt_add_detector, 0, wx.LEFT, 10),
+ (self.bt_remove_detector, 0, wx.LEFT, 5)])
+ detector_hint_txt = 'No detector is available for this data.'
+ self.detector_txt = wx.StaticText(self, -1, detector_hint_txt)
+ self.detector_hint_sizer.Add(self.detector_txt, 0, wx.LEFT, 10)
+ self.detector_sizer.AddMany([(self.detector_button_sizer, 0,
+ wx.ALL, 10),
+ (self.detector_hint_sizer, 0, wx.ALL, 10)])
+
+ self.fill_detector_combox()
+ self.enable_detector()
+
+ def _layout_instrument_sizer(self):
+ """
+ Do the layout for instrument related widgets
+ """
+ #Instrument
+ instrument_name_txt = wx.StaticText(self, -1, 'Instrument Name : ')
+ self.instrument_name_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH * 5, 20), style=0)
+ self.instrument_sizer.AddMany([(instrument_name_txt, 0,
+ wx.LEFT | wx.RIGHT, 10),
+ (self.instrument_name_tcl, 0, wx.EXPAND)])
+ def _layout_distance(self):
+ """
+ Do the layout for distance related widgets
+ """
+ distance_txt = wx.StaticText(self, -1, 'Sample to Detector Distance : ')
+ self.distance_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, 20), style=0)
+ distance_unit_txt = wx.StaticText(self, -1, 'Unit: ')
+ self.distance_unit_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, 20), style=0)
+ self.distance_sizer.AddMany([(distance_txt, 0, wx.LEFT | wx.RIGHT, 10),
+ (self.distance_tcl, 0, wx.RIGHT, 10),
+ (distance_unit_txt, 0, wx.EXPAND),
+ (self.distance_unit_tcl, 0, wx.RIGHT, 10)])
+
+ def _layout_offset(self):
+ """
+ Do the layout for offset related widgets
+ """
+ #Offset
+ offset_txt = wx.StaticText(self, -1, 'Offset:')
+ x_offset_txt = wx.StaticText(self, -1, 'x = ')
+ self.x_offset_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, 20), style=0)
+ y_offset_txt = wx.StaticText(self, -1, 'y = ')
+ self.y_offset_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, 20), style=0)
+ z_offset_txt = wx.StaticText(self, -1, 'z = ')
+ self.z_offset_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, 20), style=0)
+ offset_unit_txt = wx.StaticText(self, -1, 'Unit: ')
+ self.offset_unit_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, 20), style=0)
+ self.offset_sizer.AddMany([(offset_txt, 0, wx.LEFT | wx.RIGHT, 10),
+ (x_offset_txt, 0, wx.LEFT, 30),
+ (self.x_offset_tcl, 0, wx.RIGHT, 10),
+ (y_offset_txt, 0, wx.EXPAND),
+ (self.y_offset_tcl, 0, wx.RIGHT, 10),
+ (z_offset_txt, 0, wx.EXPAND),
+ (self.z_offset_tcl, 0, wx.RIGHT, 10),
+ (offset_unit_txt, 0, wx.EXPAND),
+ (self.offset_unit_tcl, 0, wx.RIGHT, 10)])
+
+ def _layout_orientation(self):
+ """
+ Do the layout for orientation related widgets
+ """
+ #Orientation
+ orientation_txt = wx.StaticText(self, -1, 'Orientation:')
+ x_orientation_txt = wx.StaticText(self, -1, 'x = ')
+ self.x_orientation_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, 20), style=0)
+ y_orientation_txt = wx.StaticText(self, -1, 'y = ')
+ self.y_orientation_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, 20), style=0)
+ z_orientation_txt = wx.StaticText(self, -1, 'z = ')
+ self.z_orientation_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, 20), style=0)
+ orientation_unit_txt = wx.StaticText(self, -1, 'Unit: ')
+ self.orientation_unit_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, 20), style=0)
+ self.orientation_sizer.AddMany([(orientation_txt, 0,
+ wx.LEFT | wx.RIGHT, 10),
+ (x_orientation_txt, 0, wx.LEFT, 7),
+ (self.x_orientation_tcl, 0, wx.RIGHT, 10),
+ (y_orientation_txt, 0, wx.EXPAND),
+ (self.y_orientation_tcl, 0, wx.RIGHT, 10),
+ (z_orientation_txt, 0, wx.EXPAND),
+ (self.z_orientation_tcl, 0, wx.RIGHT, 10),
+ (orientation_unit_txt, 0, wx.EXPAND),
+ (self.orientation_unit_tcl, 0, wx.RIGHT, 10)])
+
+ def _layout_beam_center(self):
+ """
+ Do the layout for beam center related widgets
+ """
+ #Beam center
+ beam_center_txt = wx.StaticText(self, -1, 'Beam Center:')
+ x_beam_center_txt = wx.StaticText(self, -1, 'x = ')
+ self.x_beam_center_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, 20), style=0)
+ y_beam_center_txt = wx.StaticText(self, -1, 'y = ')
+ self.y_beam_center_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, 20), style=0)
+ z_beam_center_txt = wx.StaticText(self, -1, 'z = ')
+ self.z_beam_center_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, 20), style=0)
+ beam_center_unit_txt = wx.StaticText(self, -1, 'Unit: ')
+ self.beam_center_unit_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, 20), style=0)
+ self.beam_sizer.AddMany([(beam_center_txt, 0, wx.LEFT | wx.RIGHT, 10),
+ (x_beam_center_txt, 0, wx.EXPAND),
+ (self.x_beam_center_tcl, 0, wx.RIGHT, 10),
+ (y_beam_center_txt, 0, wx.EXPAND),
+ (self.y_beam_center_tcl, 0, wx.RIGHT, 10),
+ (z_beam_center_txt, 0, wx.EXPAND),
+ (self.z_beam_center_tcl, 0, wx.RIGHT, 10),
+ (beam_center_unit_txt, 0, wx.EXPAND),
+ (self.beam_center_unit_tcl, 0, wx.RIGHT, 10)])
+
+ def _layout_pixel_size(self):
+ """
+ Do the layout for pixel size related widgets
+ """
+ #Pixel Size
+ pixel_size_txt = wx.StaticText(self, -1, 'Pixel Size:')
+ x_pixel_size_txt = wx.StaticText(self, -1, 'x = ')
+ self.x_pixel_size_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, 20), style=0)
+ y_pixel_size_txt = wx.StaticText(self, -1, 'y = ')
+ self.y_pixel_size_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, 20), style=0)
+ z_pixel_size_txt = wx.StaticText(self, -1, 'z = ')
+ self.z_pixel_size_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, 20), style=0)
+ pixel_size_unit_txt = wx.StaticText(self, -1, 'Unit: ')
+ self.pixel_size_unit_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, 20), style=0)
+ self.pixel_sizer.AddMany([(pixel_size_txt, 0, wx.LEFT | wx.RIGHT, 10),
+ (x_pixel_size_txt, 0, wx.LEFT, 17),
+ (self.x_pixel_size_tcl, 0, wx.RIGHT, 10),
+ (y_pixel_size_txt, 0, wx.EXPAND),
+ (self.y_pixel_size_tcl, 0, wx.RIGHT, 10),
+ (z_pixel_size_txt, 0, wx.EXPAND),
+ (self.z_pixel_size_tcl, 0, wx.RIGHT, 10),
+ (pixel_size_unit_txt, 0, wx.EXPAND),
+ (self.pixel_size_unit_tcl, 0, wx.RIGHT, 10)])
+
+ def _layout_slit_length(self):
+ """
+ Do the layout for slit length related widgets
+ """
+ #slit length
+ slit_length_txt = wx.StaticText(self, -1, 'Slit Length: ')
+ self.slit_length_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, 20), style=0)
+ slit_length_unit_txt = wx.StaticText(self, -1, 'Unit: ')
+ self.slit_length_unit_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, 20), style=0)
+ self.slit_sizer.AddMany([(slit_length_txt, 0, wx.LEFT, 10),
+ (self.slit_length_tcl, 0, wx.RIGHT, 10),
+ (slit_length_unit_txt, 0, wx.EXPAND),
+ (self.slit_length_unit_tcl, 0, wx.RIGHT, 10)])
+
+ def _layout_button(self):
+ """
+ Do the layout for the button widgets
+ """
+ self.bt_apply = wx.Button(self, -1, 'Apply')
+ self.bt_apply.Bind(wx.EVT_BUTTON, self.on_click_apply)
+ self.bt_apply.SetToolTipString("Apply current changes to the detector.")
+ self.bt_cancel = wx.Button(self, -1, 'Cancel')
+ self.bt_cancel.SetToolTipString("Cancel current changes.")
+ self.bt_cancel.Bind(wx.EVT_BUTTON, self.on_click_cancel)
+ self.bt_close = wx.Button(self, wx.ID_CANCEL, 'Close')
+ self.bt_close.SetToolTipString("Close window.")
+ self.button_sizer.AddMany([(self.bt_apply, 0, wx.LEFT, 200),
+ (self.bt_cancel, 0, wx.LEFT, 10),
+ (self.bt_close, 0, wx.LEFT, 10)])
+
+ def _do_layout(self, data=None):
+ """
+ Draw the current panel
+ """
+ self._define_structure()
+ self._layout_detector()
+ self._layout_instrument_sizer()
+ self._layout_distance()
+ self._layout_offset()
+ self._layout_orientation()
+ self._layout_beam_center()
+ self._layout_pixel_size()
+ self._layout_slit_length()
+ self._layout_button()
+
+ self.boxsizer_detector.AddMany([(self.instrument_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
+ (self.distance_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
+ (self.offset_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
+ (self.orientation_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
+ (self.beam_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
+ (self.pixel_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
+ (self.slit_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
+ self.main_sizer.AddMany([(self.detector_sizer, 0, wx.ALL, 10),
+ (self.boxsizer_detector, 0, wx.ALL, 10),
+ (self.button_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
+
+ self.SetSizer(self.main_sizer)
+ self.SetAutoLayout(True)
+
+ def reset_detector(self):
+ """
+ put the default value of the detector back to the current detector
+ """
+ self._detector = deepcopy(self._reset_detector)
+ self.detector_cbox.Clear()
+ self.fill_detector_combox()
+ self.set_values()
+
+ def set_manager(self, manager):
+ """
+ Set manager of this window
+ """
+ self.manager = manager
+
+ def fill_detector_combox(self):
+ """
+ fill the current combobox with the available detector
+ """
+ for detector in self._detector:
+ pos = self.detector_cbox.Append(str(detector.name))
+ self.detector_cbox.SetClientData(pos, detector)
+ self.detector_cbox.SetSelection(pos)
+ self.detector_cbox.SetStringSelection(str(detector.name))
+
+ def reset_detector_combobox(self, edited_detector):
+ """
+ take all edited editor and reset clientdata of detector combo box
+ """
+ for position in range(self.detector_cbox.GetCount()):
+ detector = self.detector_cbox.GetClientData(position)
+ if detector == edited_detector:
+ detector = edited_detector
+ self.detector_cbox.SetString(position, str(detector.name))
+ self.detector_cbox.SetClientData(position, detector)
+ self.detector_cbox.SetStringSelection(str(detector.name))
+
+ def add_detector(self, event):
+ """
+ Append empty detector to data's list of detector
+ """
+
+ if not self.detector_cbox.IsEnabled():
+ self.detector_cbox.Enable()
+ detector = Detector()
+ self._detector.append(detector)
+ position = self.detector_cbox.Append(str(detector.name))
+ self.detector_cbox.SetClientData(position, detector)
+ self.detector_cbox.SetSelection(position)
+ self.enable_detector()
+ self.set_values()
+
+ def remove_detector(self, event):
+ """
+ Remove detector to data's list of detector
+ """
+ if self.detector_cbox.IsEnabled():
+ if self.detector_cbox.GetCount() > 1:
+ position = self.detector_cbox.GetCurrentSelection()
+ detector = self.detector_cbox.GetClientData(position)
+ if detector in self._detector:
+ self._detector.remove(detector)
+ self.detector_cbox.Delete(position)
+ #set the combo box box the next available item
+ position = self.detector_cbox.GetCount()
+ if position > 0:
+ position -= 1
+ self.detector_cbox.SetSelection(position)
+ self.set_values()
+ #disable or enable the combo box when necessary
+ self.enable_detector()
+
+ def enable_detector(self):
+ """
+ Enable /disable widgets crelated to detector
+ """
+ if self._detector is not None and self.detector_cbox.GetCount() > 0:
+ self.detector_cbox.Enable()
+ self.bt_remove_detector.Enable()
+ n_detector = self.detector_cbox.GetCount()
+ detector_hint_txt = 'Detectors available: %s ' % str(n_detector)
+ if len(self._detector) > 1:
+ self.bt_remove_detector.Enable()
+ else:
+ self.bt_remove_detector.Disable()
+ else:
+ self.detector_cbox.Disable()
+ self.bt_remove_detector.Disable()
+ detector_hint_txt = 'No detector is available for this data.'
+ self.detector_txt.SetLabel(detector_hint_txt)
+
+ def set_detector(self, detector):
+ """
+ set detector for data
+ """
+ if self._detector is None:
+ return
+ if self._detector:
+ for item in self._detector:
+ if item == detector:
+ item = detector
+ self.reset_detector_combobox(edited_detector=detector)
+ return
+
+ def get_current_detector(self):
+ """
+ """
+ if not self.detector_cbox.IsEnabled():
+ return None, None, None
+ position = self.detector_cbox.GetSelection()
+ if position == wx.NOT_FOUND:
+ return None, None, None
+ detector_name = self.detector_cbox.GetStringSelection()
+ detector = self.detector_cbox.GetClientData(position)
+ return detector, detector_name, position
+
+ def set_values(self):
+ """
+ take the detector values of the current data and display them
+ through the panel
+ """
+ detector, _, _ = self.get_current_detector()
+ if detector is None:
+ return
+ self.instrument_name_tcl.SetValue(str(detector.name))
+ #Distance
+ distance = detector.distance
+ self.distance_tcl.SetValue(str(distance))
+ self.distance_unit_tcl.SetValue(str(detector.distance_unit))
+ #Offset
+ x, y, z = detector.offset.x, detector.offset.y , detector.offset.z
+ self.x_offset_tcl.SetValue(str(x))
+ self.y_offset_tcl.SetValue(str(y))
+ self.z_offset_tcl.SetValue(str(z))
+ self.offset_unit_tcl.SetValue(str(detector.offset_unit))
+ #Orientation
+ x, y = detector.orientation.x, detector.orientation.y
+ z = detector.orientation.z
+ self.x_orientation_tcl.SetValue(str(x))
+ self.y_orientation_tcl.SetValue(str(y))
+ self.z_orientation_tcl.SetValue(str(z))
+ self.orientation_unit_tcl.SetValue(str(detector.orientation_unit))
+ #Beam center
+ x, y = detector.beam_center.x, detector.beam_center.y
+ z = detector.beam_center.z
+ self.x_beam_center_tcl.SetValue(str(x))
+ self.y_beam_center_tcl.SetValue(str(y))
+ self.z_beam_center_tcl.SetValue(str(z))
+ self.beam_center_unit_tcl.SetValue(str(detector.beam_center_unit))
+ #Pixel size
+ x, y = detector.pixel_size.x, detector.pixel_size.y
+ z = detector.pixel_size.z
+ self.x_pixel_size_tcl.SetValue(str(x))
+ self.y_pixel_size_tcl.SetValue(str(y))
+ self.z_pixel_size_tcl.SetValue(str(z))
+ self.pixel_size_unit_tcl.SetValue(str(detector.pixel_size_unit))
+ #Slit length
+ slit_length = detector.slit_length
+ self.slit_length_tcl.SetValue(str(detector.slit_length))
+ self.slit_length_unit_tcl.SetValue(str(detector.slit_length_unit))
+
+ def get_detector(self):
+ """
+ return the current detector
+ """
+ return self._detector
+
+ def get_notes(self):
+ """
+ return notes
+ """
+ return self._notes
+
+ def on_change_instrument(self):
+ """
+ Change instrument
+ """
+ detector, detector_name, position = self.get_current_detector()
+ if detector is None:
+ return
+ #Change the name of the detector
+ name = self.instrument_name_tcl.GetValue().lstrip().rstrip()
+ if name == "" or name == str(None):
+ name = None
+ if detector_name != name:
+ self._notes += " Instrument's "
+ self._notes += "name from %s to %s \n" % (detector_name, name)
+ detector.name = name
+ self.detector_cbox.SetString(position, str(detector.name))
+ self.detector_cbox.SetClientData(position, detector)
+ self.detector_cbox.SetStringSelection(str(detector.name))
+
+ def on_change_distance(self):
+ """
+ Change distance of the sample to the detector
+ """
+ detector, _, position = self.get_current_detector()
+ if detector is None:
+ return
+ #Change the distance
+ distance = self.distance_tcl.GetValue().lstrip().rstrip()
+ if distance == "" or distance == str(None):
+ distance = None
+ detector.distance = distance
+ else:
+ if check_float(self.distance_tcl):
+ if detector.distance != float(distance):
+ self._notes += " Change Distance from"
+ self._notes += " %s to %s \n" % (detector.distance, distance)
+ detector.distance = float(distance)
+ else:
+ self._notes += "Error: Expected a float for "
+ self._notes += " the distance won't changes "
+ self._notes += "%s to %s" % (detector.distance, distance)
+ #change the distance unit
+ unit = self.distance_unit_tcl.GetValue().lstrip().rstrip()
+ if detector.distance_unit != unit:
+ self._notes += " Change distance's unit from "
+ self._notes += "%s to %s" % (detector.distance_unit, unit)
+
+ self.detector_cbox.SetString(position, str(detector.name))
+ self.detector_cbox.SetClientData(position, detector)
+ self.detector_cbox.SetStringSelection(str(detector.name))
+
+ def on_change_offset(self):
+ """
+ Change the detector offset
+ """
+ detector, _, position = self.get_current_detector()
+ if detector is None:
+ return
+ #Change x coordinate
+ x_offset = self.x_offset_tcl.GetValue().lstrip().rstrip()
+ if x_offset == "" or x_offset == str(None):
+ x_offset = None
+ detector.offset.x = x_offset
+ else:
+ if check_float(self.x_offset_tcl):
+ if detector.offset.x != float(x_offset):
+ self._notes += "Change x of offset from"
+ self._notes += " %s to %s \n" % (detector.offset.x,
+ x_offset)
+ detector.offset.x = float(x_offset)
+ else:
+ self._notes += "Error: Expected a float for the offset 's x "
+ self._notes += "won't changes x offset"
+ self._notes += " from %s to %s" % (detector.offset.x, x_offset)
+ #Change y coordinate
+ y_offset = self.y_offset_tcl.GetValue().lstrip().rstrip()
+ if y_offset == "" or y_offset == str(None):
+ y_offset = None
+ detector.offset.y = y_offset
+ else:
+ if check_float(self.y_offset_tcl):
+ if detector.offset.y != float(y_offset):
+ self._notes += "Change y of offset from "
+ self._notes += "%s to %s \n" % (detector.offset.y, y_offset)
+ detector.offset.y = float(y_offset)
+ else:
+ self._notes += "Error: Expected a float for the offset 's y "
+ self._notes += "won't changes y "
+ self._notes += "offset from %s to %s" % (detector.offset.y,
+ y_offset)
+ #Change z coordinate
+ z_offset = self.z_offset_tcl.GetValue().lstrip().rstrip()
+ if z_offset == "" or z_offset == str(None):
+ z_offset = None
+ detector.offset.z = z_offset
+ else:
+ if check_float(self.z_offset_tcl):
+ if detector.offset.z != float(z_offset):
+ self._notes += "Change z of offset from"
+ self._notes += " %s to %s \n" % (detector.offset.z,
+ z_offset)
+ detector.offset.z = float(z_offset)
+ else:
+ self._notes += "Error: Expected a float for the offset 's x "
+ self._notes += "won't changes z"
+ self._notes += "offset from %s to %s" % (detector.offset.z,
+ z_offset)
+ #change the offset unit
+ unit = self.offset_unit_tcl.GetValue().lstrip().rstrip()
+ if detector.offset_unit != unit:
+ self._notes += " Change Offset's"
+ self._notes += "unit from %s to %s" % (detector.offset_unit, unit)
+
+ self.detector_cbox.SetString(position, str(detector.name))
+ self.detector_cbox.SetClientData(position, detector)
+ self.detector_cbox.SetStringSelection(str(detector.name))
+
+ def on_change_orientation(self):
+ """
+ Change the detector orientation
+ """
+ detector, _, position = self.get_current_detector()
+ if detector is None:
+ return
+ #Change x coordinate
+ x_orientation = self.x_orientation_tcl.GetValue().lstrip().rstrip()
+ if x_orientation == "" or x_orientation == str(None):
+ x_orientation = None
+ detector.orientation.x = x_orientation
+ else:
+ if check_float(self.x_orientation_tcl):
+ if detector.orientation.x != float(x_orientation):
+ self._notes += "Change x of orientation from "
+ self._notes += "%s to %s \n" % (detector.orientation.x,
+ x_orientation)
+ detector.orientation.x = float(x_orientation)
+ else:
+ self._notes += "Error: Expected a float for the orientation "
+ self._notes += "'s x won't changes x orientation from "
+ self._notes += "%s to %s" % (detector.orientation.x,
+ x_orientation)
+ #Change y coordinate
+ y_orientation = self.y_orientation_tcl.GetValue().lstrip().rstrip()
+ if y_orientation == "" or y_orientation == str(None):
+ y_orientation = None
+ detector.orientation.y = y_orientation
+ else:
+ if check_float(self.y_orientation_tcl):
+ if detector.orientation.y != float(y_orientation):
+ self._notes += "Change y of orientation from "
+ self._notes += "%s to %s \n" % (detector.orientation.y,
+ y_orientation)
+ detector.orientation.y = float(y_orientation)
+ else:
+ self._notes += "Error: Expected a float for the orientation's "
+ self._notes += " y won't changes y orientation from "
+ self._notes += "%s to %s" % (detector.orientation.y,
+ y_orientation)
+ #Change z coordinate
+ z_orientation = self.z_orientation_tcl.GetValue().lstrip().rstrip()
+ if z_orientation == "" or z_orientation == str(None):
+ z_orientation = None
+ detector.orientation.z = z_orientation
+ else:
+ if check_float(self.z_orientation_tcl):
+ if detector.orientation.z != float(z_orientation):
+ self._notes += "Change z of offset from "
+ self._notes += "%s to %s \n" % (detector.orientation.z,
+ z_orientation)
+ detector.orientation.z = float(z_orientation)
+ else:
+ self._notes += "Error: Expected a float for the orientation 's"
+ self._notes += " x won't changes z orientation from "
+ self._notes += "%s to %s" % (detector.orientation.z,
+ z_orientation)
+ #change the orientation unit
+ unit = self.orientation_unit_tcl.GetValue().lstrip().rstrip()
+ if detector.orientation_unit != unit:
+ self._notes += " Change orientation's unit from "
+ self._notes += "%s to %s" % (detector.orientation_unit, unit)
+
+ self.detector_cbox.SetString(position, str(detector.name))
+ self.detector_cbox.SetClientData(position, detector)
+ self.detector_cbox.SetStringSelection(str(detector.name))
+
+ def on_change_beam_center(self):
+ """
+ Change the detector beam center
+ """
+
+ detector, _, position = self.get_current_detector()
+ if detector is None:
+ return
+ #Change x coordinate
+ x_beam_center = self.x_beam_center_tcl.GetValue().lstrip().rstrip()
+ if x_beam_center == "" or x_beam_center == str(None):
+ x_beam_center = None
+ detector.beam_center.x = x_beam_center
+ else:
+ if check_float(self.x_beam_center_tcl):
+ if detector.beam_center.x != float(x_beam_center):
+ self._notes += "Change x of offset from "
+ self._notes += "%s to %s \n" % (detector.beam_center.x,
+ x_beam_center)
+ detector.beam_center.x = float(x_beam_center)
+ else:
+ self._notes += "Error: Expected a float for the beam "
+ self._notes += "center 's x won't changes x beam center from "
+ self._notes += "%s to %s" % (detector.beam_center.x,
+ x_beam_center)
+ #Change y coordinate
+ y_beam_center = self.y_beam_center_tcl.GetValue().lstrip().rstrip()
+ if y_beam_center == "" or y_beam_center == str(None):
+ y_beam_center = None
+ detector.beam_center.y = y_beam_center
+ else:
+ if check_float(self.y_beam_center_tcl):
+ if detector.beam_center.y != float(y_beam_center):
+ self._notes += "Change y of beam center from "
+ self._notes += "%s to %s \n" % (detector.beam_center.y,
+ y_beam_center)
+ detector.beam_center.y = float(y_beam_center)
+ else:
+ self._notes += "Error: Expected a float for the beam "
+ self._notes += "center 's y won't changes y beam center from "
+ self._notes += "%s to %s" % (detector.beam_center.y,
+ y_beam_center)
+ #Change z coordinate
+ z_beam_center = self.z_beam_center_tcl.GetValue().lstrip().rstrip()
+ if z_beam_center == "" or z_beam_center == str(None):
+ z_beam_center = None
+ detector.beam_center.z = z_beam_center
+ else:
+ if check_float(self.z_beam_center_tcl):
+ if detector.beam_center.z != float(z_beam_center):
+ self._notes += "Change z of beam center from "
+ self._notes += "%s to %s \n" % (detector.beam_center.z,
+ z_beam_center)
+ detector.beam_center.z = float(z_beam_center)
+ else:
+ self._notes += "Error: Expected a float for the offset 's x "
+ self._notes += "won't changes z beam center from "
+ self._notes += "%s to %s" % (detector.beam_center.z,
+ z_beam_center)
+ #change the beam center unit
+ unit = self.beam_center_unit_tcl.GetValue().lstrip().rstrip()
+ if detector.beam_center_unit != unit:
+ self._notes += " Change beam center's unit from "
+ self._notes += "%s to %s" % (detector.beam_center_unit, unit)
+
+ self.detector_cbox.SetString(position, str(detector.name))
+ self.detector_cbox.SetClientData(position, detector)
+ self.detector_cbox.SetStringSelection(str(detector.name))
+
+ def on_change_pixel_size(self):
+ """
+ Change the detector pixel size
+ """
+ detector, _, position = self.get_current_detector()
+ if detector is None:
+ return
+ #Change x coordinate
+ x_pixel_size = self.x_pixel_size_tcl.GetValue().lstrip().rstrip()
+ if x_pixel_size == "" or x_pixel_size == str(None):
+ x_pixel_size = None
+ else:
+ if check_float(self.x_pixel_size_tcl):
+ if detector.pixel_size.x != float(x_pixel_size) :
+ self._notes += "Change x of pixel size from "
+ self._notes += "%s to %s \n" % (detector.pixel_size.x,
+ x_pixel_size)
+ detector.pixel_size.x = float(x_pixel_size)
+ else:
+ self._notes += "Error: Expected a float for the pixel"
+ self._notes += " size 's x won't changes x pixel size from "
+ self._notes += "%s to %s" % (detector.pixel_size.x,
+ x_pixel_size)
+ #Change y coordinate
+ y_pixel_size = self.y_pixel_size_tcl.GetValue().lstrip().rstrip()
+ if y_pixel_size == "" or y_pixel_size == str(None):
+ y_pixel_size = None
+ detector.pixel_size.y = y_pixel_size
+ else:
+ if check_float(self.y_pixel_size_tcl):
+ if detector.pixel_size.y != float(y_pixel_size):
+ self._notes += "Change y of pixel size from "
+ self._notes += "%s to %s \n" % (detector.pixel_size.y,
+ y_pixel_size)
+ detector.pixel_size.y = float(y_pixel_size)
+ else:
+ self._notes += "Error: Expected a float for the pixel "
+ self._notes += "size's y won't changes y pixel size from "
+ self._notes += "%s to %s" % (detector.pixel_size.y,
+ y_pixel_size)
+ #Change z coordinate
+ z_pixel_size = self.z_pixel_size_tcl.GetValue().lstrip().rstrip()
+ if z_pixel_size == "" or z_pixel_size == str(None):
+ z_pixel_size = None
+ detector.pixel_size.z = z_pixel_size
+ else:
+ if check_float(self.z_pixel_size_tcl):
+ if detector.pixel_size.z != float(z_pixel_size):
+ self._notes += "Change z of pixel size from "
+ self._notes += "%s to %s \n" % (detector.pixel_size.z,
+ z_pixel_size)
+ detector.pixel_size.z = float(z_pixel_size)
+ else:
+ self._notes += "Error: Expected a float for the offset 's x "
+ self._notes += "won't changes z pixel size from "
+ self._notes += "%s to %s" % (detector.pixel_size.z, z_pixel_size)
+ #change the beam center unit
+ unit = self.pixel_size_unit_tcl.GetValue().lstrip().rstrip()
+ if detector.pixel_size_unit != unit:
+ self._notes += " Change pixel size's unit from "
+ self._notes += "%s to %s" % (detector.pixel_size_unit, unit)
+
+ self.detector_cbox.SetString(position, str(detector.name))
+ self.detector_cbox.SetClientData(position, detector)
+ self.detector_cbox.SetStringSelection(str(detector.name))
+
+ def on_change_slit_length(self):
+ """
+ Change slit length of the detector
+ """
+ detector, _, position = self.get_current_detector()
+ if detector is None:
+ return
+ #Change the distance
+ slit_length = self.slit_length_tcl.GetValue().lstrip().rstrip()
+ if slit_length == "" or slit_length == str(None):
+ slit_length = None
+ detector.slit_length = slit_length
+ else:
+ if check_float(self.slit_length_tcl):
+ if detector.slit_length != float(slit_length):
+ self._notes += " Change slit length from"
+ self._notes += " %s to %s \n" % (detector.slit_length,
+ slit_length)
+ detector.slit_length = float(slit_length)
+ else:
+ self._notes += "Error: Expected a float"
+ self._notes += " for the slit length won't changes "
+ self._notes += "%s to %s" % (detector.slit_length, slit_length)
+ #change the distance unit
+ unit = self.slit_length_unit_tcl.GetValue().lstrip().rstrip()
+ if detector.slit_length_unit != unit:
+ self._notes += " Change slit length's unit from "
+ self._notes += "%s to %s" % (detector.slit_length_unit_tcl, unit)
+
+ self.detector_cbox.SetString(position, str(detector.name))
+ self.detector_cbox.SetClientData(position, detector)
+ self.detector_cbox.SetStringSelection(str(detector.name))
+
+ def on_click_cancel(self, event):
+ """
+ reset the current detector to its initial values
+ """
+ self.reset_detector()
+ self.set_values()
+ if self.manager is not None:
+ self.manager.set_detector(self._detector)
+
+ def on_click_apply(self, event):
+ """
+ Apply user values to the detector
+ """
+ self.on_change_instrument()
+ self.on_change_distance()
+ self.on_change_instrument()
+ self.on_change_beam_center()
+ self.on_change_offset()
+ self.on_change_orientation()
+ self.on_change_pixel_size()
+ self.on_change_slit_length()
+ for detector in self._detector:
+ self.manager.set_detector(self._detector, self._notes)
+
+if __name__ == "__main__":
+ app = wx.App()
+ test_detector = Detector()
+ dlg = DetectorDialog(detector=[test_detector])
+ dlg.ShowModal()
+ app.MainLoop()
diff --git a/src/sas/sasgui/perspectives/calculator/gen_scatter_panel.py b/src/sas/sasgui/perspectives/calculator/gen_scatter_panel.py
index 7318ec7..1db0c7e 100644
--- a/src/sas/sasgui/perspectives/calculator/gen_scatter_panel.py
+++ b/src/sas/sasgui/perspectives/calculator/gen_scatter_panel.py
@@ -1,2059 +1,2062 @@
-"""
-Generic Scattering panel.
-This module relies on guiframe manager.
-"""
-
-import wx
-import sys
-import os
-import numpy
-#import math
-import wx.aui as aui
-#import wx.lib.agw.aui as aui
-import logging
-import time
-
-import matplotlib
-matplotlib.interactive(False)
-#Use the WxAgg back end. The Wx one takes too long to render
-matplotlib.use('WXAgg')
-
-#from sas.sasgui.guiframe.gui_manager import MDIFrame
-from sas.sascalc.data_util.calcthread import CalcThread
-from sas.sasgui.guiframe.local_perspectives.plotting.SimplePlot import PlotFrame
-from sas.sasgui.guiframe.dataFitting import Data2D
-from sas.sasgui.guiframe.dataFitting import Data1D
-from sas.sascalc.dataloader.data_info import Detector
-from sas.sascalc.dataloader.data_info import Source
-from sas.sasgui.guiframe.panel_base import PanelBase
-from sas.sasgui.guiframe.utils import format_number
-from sas.sasgui.guiframe.events import StatusEvent
-from sas.sascalc.calculator import sas_gen
-from sas.sasgui.perspectives.calculator.calculator_widgets import OutputTextCtrl
-from sas.sasgui.perspectives.calculator.calculator_widgets import InputTextCtrl
-from wx.lib.scrolledpanel import ScrolledPanel
-from sas.sasgui.perspectives.calculator.load_thread import GenReader
-from sas.sasgui.plottools.arrow3d import Arrow3D
-from sas.sasgui.perspectives.calculator import calculator_widgets as widget
-from sas.sasgui.guiframe.events import NewPlotEvent
-from sas.sasgui.guiframe.documentation_window import DocumentationWindow
-
-_BOX_WIDTH = 76
-#Slit length panel size
-if sys.platform.count("win32") > 0:
- PANEL_TOP = 0
- PANEL_WIDTH = 570
- PANEL_HEIGHT = 370
- FONT_VARIANT = 0
-else:
- PANEL_TOP = 60
- PANEL_WIDTH = 620
- PANEL_HEIGHT = 370
- FONT_VARIANT = 1
-_QMAX_DEFAULT = 0.3
-_NPTS_DEFAULT = 50
-_Q1D_MIN = 0.001
-
-def add_icon(parent, frame):
- """
- Add icon in the frame
- """
- if parent != None:
- if hasattr(frame, "IsIconized"):
- if not frame.IsIconized():
- try:
- icon = parent.GetIcon()
- frame.SetIcon(icon)
- except:
- pass
-
-def _set_error(panel, item, show_msg=False):
- """
- Set_error dialog
- """
- if item != None:
- item.SetBackgroundColour("pink")
- item.Refresh()
- if show_msg:
- msg = "Error: wrong (or out of range) value entered."
- if panel.parent.parent != None:
- wx.PostEvent(panel.parent.parent,
- StatusEvent(status=msg, info='Error'))
- panel.SetFocus()
- return False
-
-
-
-class CalcGen(CalcThread):
- """
- Computation
- """
- def __init__(self,
- id= -1,
- input=None,
- completefn=None,
- updatefn=None,
- #elapsed = 0,
- yieldtime=0.01,
- worktime=0.01):
- """
- """
- CalcThread.__init__(self, completefn,
- updatefn,
- yieldtime,
- worktime)
- self.starttime = 0
- self.id = id
- self.input = input
- self.update_fn = updatefn
-
- def compute(self):
- """
- excuting computation
- """
- #elapsed = time.time() - self.starttime
- self.starttime = time.time()
- self.complete(input=self.input, update=self.update_fn)
-
-class SasGenPanel(ScrolledPanel, PanelBase):
- """
- Provides the sas gen calculator GUI.
- """
- ## Internal nickname for the window, used by the AUI manager
- window_name = "Generic SAS Calculator"
- ## Name to appear on the window title bar
- window_caption = "Generic SAS "
-
- def __init__(self, parent, *args, **kwds):
- ScrolledPanel.__init__(self, parent, style=wx.RAISED_BORDER,
- *args, **kwds)
- #kwds['style'] = wx.SUNKEN_BORDER
- PanelBase.__init__(self)
- #Font size
- self.SetWindowVariant(variant=FONT_VARIANT)
- self.SetupScrolling()
- #thread to read data
- self.reader = None
- self.ext = None
- self.id = 'GenSAS'
- self.file_name = ''
- self.time_text = None
- self.orient_combo = None
- self.omfreader = sas_gen.OMFReader()
- self.sldreader = sas_gen.SLDReader()
- self.pdbreader = sas_gen.PDBReader()
- self.model = sas_gen.GenSAS()
- self.param_dic = self.model.params
- self.parameters = []
- self.data = None
- self.scale2d = None
- self.is_avg = False
- self.plot_frame = None
- self.qmax_x = _QMAX_DEFAULT
- self.npts_x = _NPTS_DEFAULT
- self.sld_data = None
- self.graph_num = 1
- self.default_shape = 'rectangular'
- # Object that receive status event
- self.parent = parent
- self._do_layout()
- self._create_default_sld_data()
- self._create_default_2d_data()
- wx.CallAfter(self._set_sld_data_helper)
-
- def _define_structure(self):
- """
- Define the main sizers building to build this application.
- """
- self.main_sizer = wx.BoxSizer(wx.VERTICAL)
- self.box_source = wx.StaticBox(self, -1, str("SLD Data File"))
- self.box_parameters = wx.StaticBox(self, -1, str("Input Parameters"))
- self.box_qrange = wx.StaticBox(self, -1, str("Q Range"))
- self.boxsizer_source = wx.StaticBoxSizer(self.box_source,
- wx.VERTICAL)
- self.boxsizer_parameters = wx.StaticBoxSizer(self.box_parameters,
- wx.VERTICAL)
- self.boxsizer_qrange = wx.StaticBoxSizer(self.box_qrange,
- wx.VERTICAL)
- self.data_name_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.param_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.shape_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.hint_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.qrange_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.button_sizer = wx.BoxSizer(wx.VERTICAL)
- self.button_sizer1 = wx.BoxSizer(wx.HORIZONTAL)
- self.button_sizer2 = wx.BoxSizer(wx.HORIZONTAL)
-
- def _layout_data_name(self):
- """
- Fill the sizer containing data's name
- """
- data_name_txt = wx.StaticText(self, -1, 'Data: ')
- self.data_name_tcl = OutputTextCtrl(self, -1,
- size=(_BOX_WIDTH * 4, -1))
- data_hint = "Loaded data"
- self.data_name_tcl.SetToolTipString(data_hint)
- #control that triggers importing data
- id = wx.NewId()
- self.browse_button = wx.Button(self, id, "Load")
- hint_on_browse = "Click to load data into this panel."
- self.browse_button.SetToolTipString(hint_on_browse)
- self.Bind(wx.EVT_BUTTON, self.on_load_data, id=id)
- self.data_name_sizer.AddMany([(data_name_txt, 0, wx.LEFT, 15),
- (self.data_name_tcl, 0, wx.LEFT, 10),
- (self.browse_button, 0, wx.LEFT, 10)])
- def _layout_param_size(self):
- """
- Fill the sizer containing slit size information
- """
- self.parameters = []
- sizer = wx.GridBagSizer(3, 6)
- model = self.model
- details = self.model.details
- params = self.model.params
- ix = 0
- iy = 0
- param_title = wx.StaticText(self, -1, 'Parameter')
- sizer.Add(param_title, (iy, ix), (1, 1), \
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 1
- value_title = wx.StaticText(self, -1, 'Value')
- sizer.Add(value_title, (iy, ix), (1, 1), \
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 1
- unit_title = wx.StaticText(self, -1, 'Unit')
- sizer.Add(unit_title, (iy, ix), (1, 1), \
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- key_list = params.keys()
- key_list.sort()
- for param in key_list:
- iy += 1
- ix = 0
- p_name = wx.StaticText(self, -1, param)
- sizer.Add(p_name, (iy, ix), (1, 1), \
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ## add parameter value
- ix += 1
- value = model.getParam(param)
- ctl = InputTextCtrl(self, -1, size=(_BOX_WIDTH * 2, 20),
- style=wx.TE_PROCESS_ENTER)
- #ctl.SetToolTipString(\
- # "Hit 'Enter' after typing to update the plot.")
- ctl.SetValue(format_number(value, True))
- sizer.Add(ctl, (iy, ix), (1, 1), wx.EXPAND)
- ## add unit
- ix += 1
- unit = wx.StaticText(self, -1, details[param][0])
- sizer.Add(unit, (iy, ix), (1, 1), \
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- self.parameters.append([p_name, ctl, unit])
-
- self.param_sizer.Add(sizer, 0, wx.LEFT, 10)
-
- def _layout_hint(self):
- """
- Fill the sizer containing hint
- """
- hint_msg = "We support omf, sld or pdb data files only."
- hint_msg += " "
- if FONT_VARIANT < 1:
- hint_msg += "Very "
- hint_msg += "SLOW drawing -->"
- hint_txt = wx.StaticText(self, -1, hint_msg)
-
- id = wx.NewId()
- self.draw_button = wx.Button(self, id, "Arrow Draw")
- hint_on_draw = "Draw with arrows. Caution: it is a very slow drawing."
- self.draw_button.SetToolTipString(hint_on_draw)
- self.draw_button.Bind(wx.EVT_BUTTON, self.sld_draw, id=id)
-
- self.draw_button.Enable(False)
- self.hint_sizer.AddMany([(hint_txt, 0, wx.LEFT, 15),
- (self.draw_button, 0, wx.LEFT, 7)])
-
- def _layout_shape(self):
- """
- Fill the shape sizer
- """
- label_txt = wx.StaticText(self, -1, "Shape:")
- self.shape_combo = self._fill_shape_combo()
- self.shape_sizer.AddMany([(label_txt, 0, wx.LEFT, 15),
- (self.shape_combo, 0, wx.LEFT, 5)])
-
- def _fill_shape_combo(self):
- """
- Fill up the shape combo box
- """
- shape_combo = wx.ComboBox(self, -1, size=(150, -1),
- style=wx.CB_READONLY)
- shape_combo.Append('Rectangular')
- shape_combo.Append('Ellipsoid')
- shape_combo.Bind(wx.EVT_COMBOBOX, self._on_shape_select)
- shape_combo.SetSelection(0)
- return shape_combo
-
- def _on_shape_select(self, event):
- """
- On selecting a shape
- """
- event.Skip()
- label = event.GetEventObject().GetValue().lower()
- self.default_shape = label
- self.parent.set_omfpanel_default_shap(self.default_shape)
- self.parent.set_omfpanel_npts()
-
- def _fill_orient_combo(self):
- """
- Fill up the orientation combo box: used only for atomic structure
- """
- orient_combo = wx.ComboBox(self, -1, size=(150, -1),
- style=wx.CB_READONLY)
- orient_combo.Append('Fixed orientation')
- orient_combo.Append('Debye full avg.')
- #orient_combo.Append('Debye sph. sym.')
-
- orient_combo.Bind(wx.EVT_COMBOBOX, self._on_orient_select)
- orient_combo.SetSelection(0)
- return orient_combo
-
- def _on_orient_select(self, event):
- """
- On selecting a orientation
- """
- event.Skip()
- cb = event.GetEventObject()
- if cb.GetCurrentSelection() == 2:
- self.is_avg = None
- else:
- is_avg = cb.GetCurrentSelection() == 1
- self.is_avg = is_avg
- self.model.set_is_avg(self.is_avg)
- self.set_est_time()
-
- def _layout_qrange(self):
- """
- Fill the sizer containing qrange
- """
- sizer = wx.GridBagSizer(2, 3)
- ix = 0
- iy = 0
- #key_list.sort()
- name = wx.StaticText(self, -1, 'No. of Qx (Qy) bins: ')
- sizer.Add(name, (iy, ix), (1, 1), \
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ## add parameter value
- ix += 1
- self.npt_ctl = InputTextCtrl(self, -1, size=(_BOX_WIDTH * 1.5, 20),
- style=wx.TE_PROCESS_ENTER)
- self.npt_ctl.Bind(wx.EVT_TEXT, self._onparamEnter)
- self.npt_ctl.SetValue(format_number(self.npts_x, True))
- sizer.Add(self.npt_ctl, (iy, ix), (1, 1), wx.EXPAND)
- ## add unit
- ix += 1
- unit = wx.StaticText(self, -1, '')
- sizer.Add(unit, (iy, ix), (1, 1), \
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- iy += 1
- ix = 0
- name = wx.StaticText(self, -1, 'Qx (Qy) Max: ')
- sizer.Add(name, (iy, ix), (1, 1), \
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ## add parameter value
- ix += 1
- self.qmax_ctl = InputTextCtrl(self, -1, size=(_BOX_WIDTH * 1.5, 20),
- style=wx.TE_PROCESS_ENTER)
- self.qmax_ctl.Bind(wx.EVT_TEXT, self._onparamEnter)
- self.qmax_ctl.SetValue(format_number(self.qmax_x, True))
- sizer.Add(self.qmax_ctl, (iy, ix), (1, 1), wx.EXPAND)
- ## add unit
- ix += 1
- unit = wx.StaticText(self, -1, '[1/A]')
- sizer.Add(unit, (iy, ix), (1, 1), \
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- self.qrange_sizer.Add(sizer, 0, wx.LEFT, 10)
-
- def _layout_button(self):
- """
- Do the layout for the button widgets
- """
- self.est_time = '*Estimated Computation time :\n %s'
- self.time_text = wx.StaticText(self, -1, self.est_time % str('2 sec'))
- self.orient_combo = self._fill_orient_combo()
- self.orient_combo.Show(False)
-
- self.bt_compute = wx.Button(self, wx.NewId(), 'Compute')
- self.bt_compute.Bind(wx.EVT_BUTTON, self.on_compute)
- self.bt_compute.SetToolTipString("Compute 2D Scattering Pattern.")
-
- self.bt_help = wx.Button(self, wx.NewId(), 'HELP')
- self.bt_help.Bind(wx.EVT_BUTTON, self.on_help)
- self.bt_help.SetToolTipString("Help on Scatter Calculator")
-
- self.bt_close = wx.Button(self, wx.ID_CANCEL, 'Close')
- self.bt_close.Bind(wx.EVT_BUTTON, self.on_panel_close)
- self.bt_close.SetToolTipString("Close this window")
-
- self.button_sizer1.AddMany([(self.bt_compute, 0, wx.LEFT, 20),
- (self.orient_combo , 0, wx.LEFT, 20)])
- self.button_sizer2.AddMany([(self.time_text , 0, wx.LEFT, 20),
- (self.bt_help, 0, wx.LEFT, 20),
- (self.bt_close, 0, wx.LEFT, 20)])
- self.button_sizer.AddMany([(self.button_sizer1 , 0, wx.BOTTOM|wx.LEFT, 10),
- (self.button_sizer2 , 0, wx.LEFT, 10)])
-
- def estimate_ctime(self):
- """
- Calculation time estimation
- """
- # magic equation: not very accurate
- factor = 1
- n_qbins = float(self.npt_ctl.GetValue())
- n_qbins *= n_qbins
- n_pixs = float(self.parent.get_npix())
- if self.is_avg:
- factor = 6
- n_pixs *= (n_pixs / 200)
- x_in = n_qbins * n_pixs / 100000
- etime = factor + 0.085973 * x_in
- return int(etime)
-
- def set_est_time(self):
- """
- Set text for est. computation time
- """
- unit = 'sec'
- if self.time_text != None:
- self.time_text.SetForegroundColour('black')
- etime = self.estimate_ctime()
- if etime > 60:
- etime /= 60
- unit = 'min'
- self.time_text.SetForegroundColour('red')
- time_str = str(etime) + ' ' + unit
- self.time_text.SetLabel(self.est_time % time_str)
-
- def _do_layout(self):
- """
- Draw window content
- """
- self._define_structure()
- self._layout_data_name()
- self._layout_param_size()
- self._layout_qrange()
- self._layout_hint()
- self._layout_shape()
- self._layout_button()
- self.boxsizer_source.AddMany([(self.data_name_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
- (self.hint_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
- (self.shape_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
- self.boxsizer_parameters.AddMany([(self.param_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5), ])
- self.boxsizer_qrange.AddMany([(self.qrange_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5), ])
- self.main_sizer.AddMany([(self.boxsizer_source, 0,
- wx.EXPAND | wx.ALL, 10),
- (self.boxsizer_parameters, 0,
- wx.EXPAND | wx.ALL, 10),
- (self.boxsizer_qrange, 0,
- wx.EXPAND | wx.ALL, 10),
- (self.button_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
- self.SetSizer(self.main_sizer)
- self.SetAutoLayout(True)
-
- def _create_default_sld_data(self):
- """
- Making default sld-data
- """
- sld_n_default = 6.97e-06
- omfdata = sas_gen.OMFData()
- omf2sld = sas_gen.OMF2SLD()
- omf2sld.set_data(omfdata, self.default_shape)
- self.sld_data = omf2sld.output
- self.sld_data.is_data = False
- self.sld_data.filename = "Default SLD Profile"
- self.sld_data.set_sldn(sld_n_default)
- self.data_name_tcl.SetValue(self.sld_data.filename)
-
- def choose_data_file(self, location=None):
- """
- Choosing a dtata file
- """
- path = None
- filename = ''
- if location == None:
- location = os.getcwd()
-
- exts = "*" + self.omfreader.ext[0]
- exts += ", *" + self.sldreader.ext[0]
- exts += ", *" + self.pdbreader.ext[0]
- all_type = "All GEN files (%s, %s) | %s" % (exts.upper(), exts.lower(),
- exts.lower().replace(',', ';'))
- wildcard = [all_type]
- omf_type = self.omfreader.type
- sld_type = self.sldreader.type
- pdb_type = self.pdbreader.type
-
- for type in sld_type:
- wildcard.append(type)
- for type in omf_type:
- wildcard.append(type)
- for type in pdb_type:
- wildcard.append(type)
- wildcard = '|'.join(wildcard)
- dlg = wx.FileDialog(self, "Choose a file", location,
- "", wildcard, wx.OPEN)
- if dlg.ShowModal() == wx.ID_OK:
- path = dlg.GetPath()
- filename = os.path.basename(path)
- dlg.Destroy()
- return path
-
- def on_load_data(self, event):
- """
- Open a file dialog to allow the user to select a given file.
- The user is only allow to load file with extension .omf, .txt, .sld.
- Display the slit size corresponding to the loaded data.
- """
- location = self.parent.get_path()
- path = self.choose_data_file(location=location)
- if path is None:
- return
-
- self.shape_sizer.ShowItems(False)
- self.default_shape = 'rectangular'
- self.parent.set_omfpanel_default_shap(self.default_shape)
-
- self.parent.set_file_location(os.path.dirname(path))
- try:
- #Load data
- self.ext = os.path.splitext(path)[-1]
- if self.ext in self.omfreader.ext:
- loader = self.omfreader
- elif self.ext in self.sldreader.ext:
- loader = self.sldreader
- elif self.ext in self.pdbreader.ext:
- loader = self.pdbreader
- else:
- loader = None
- if self.reader is not None and self.reader.isrunning():
- self.reader.stop()
- self.browse_button.Enable(False)
- self.browse_button.SetLabel("Loading...")
- if self.parent.parent is not None:
- wx.PostEvent(self.parent.parent,
- StatusEvent(status="Loading...",
- type="progress"))
- self.reader = GenReader(path=path, loader=loader,
- completefn=self.complete_loading,
- updatefn=self.load_update)
- self.reader.queue()
- #self.load_update()
- except:
- self.ext = None
- if self.parent.parent is None:
- return
- msg = "Generic SAS Calculator: %s" % (sys.exc_value)
- wx.PostEvent(self.parent.parent,
- StatusEvent(status=msg, type='stop'))
- self.SetFocus()
- return
-
- def load_update(self):
- """
- print update on the status bar
- """
- if self.parent.parent is None:
- return
- if self.reader.isrunning():
- type = "progress"
- else:
- type = "stop"
- wx.PostEvent(self.parent.parent, StatusEvent(status="",
- type=type))
-
- def complete_loading(self, data=None, filename=''):
- """
- Complete the loading
- """
- #compute the slit size
- self.browse_button.Enable(True)
- self.browse_button.SetLabel('Load')
- try:
- is_pdbdata = False
- filename = data.filename
- self.data_name_tcl.SetValue(str(filename))
- self.file_name = filename.split('.')[0]
- self.orient_combo.SetSelection(0)
- self.is_avg = False
- if self.ext in self.omfreader.ext:
- gen = sas_gen.OMF2SLD()
- gen.set_data(data)
- #omf_data = data
- self.sld_data = gen.get_magsld()
- elif self.ext in self.sldreader.ext:
- self.sld_data = data
- elif self.ext in self.pdbreader.ext:
- self.sld_data = data
- is_pdbdata = True
- #omf_data = None
- else:
- raise
- self.orient_combo.Show(is_pdbdata)
- #self.button_sizer.Layout()
- self.FitInside()
- self._set_sld_data_helper(True)
- except:
- if self.parent.parent is None:
- raise
- msg = "Loading Error: This file format is not supported "
- msg += "for GenSAS."
- wx.PostEvent(self.parent.parent,
- StatusEvent(status=msg, type='stop', info='Error'))
- self.SetFocus()
- return
- if self.parent.parent is None:
- return
-
- msg = "Load Complete"
- wx.PostEvent(self.parent.parent, StatusEvent(status=msg, type='stop'))
- self.SetFocus()
-
- def _set_sld_data_helper(self, is_draw=False):
- """
- Set sld data helper
- """
- #is_avg = self.orient_combo.GetCurrentSelection() == 1
- self.model.set_is_avg(self.is_avg)
- self.model.set_sld_data(self.sld_data)
-
- self.draw_button.Enable(self.sld_data != None)
- wx.CallAfter(self.parent.set_sld_data, self.sld_data)
- self._update_model_params()
- if is_draw:
- wx.CallAfter(self.sld_draw, None, False)
-
- def _update_model_params(self):
- """
- Update the model parameter values
- """
- for list in self.parameters:
- param_name = list[0].GetLabelText()
- val = str(self.model.params[param_name])
- list[1].SetValue(val)
-
- def set_volume_ctl_val(self, val):
- """
- Set volume txtctrl value
- """
- for list in self.parameters:
- param_name = list[0].GetLabelText()
- if param_name.lower() == 'total_volume':
- list[1].SetValue(val)
- list[1].Refresh()
- break
-
- def _onparamEnter(self, event):
- """
- On param enter
- """
- try:
- item = event.GetEventObject()
- self._check_value()
- item.Refresh()
- except:
- pass
-
- def sld_draw(self, event=None, has_arrow=True):
- """
- Draw 3D sld profile
- """
- flag = self.parent.check_omfpanel_inputs()
- if not flag:
- infor = 'Error'
- msg = 'Error: Wrong inputs in the SLD info panel.'
- # inform msg to wx
- wx.PostEvent(self.parent.parent,
- StatusEvent(status=msg, info=infor))
- self.SetFocus()
- return
-
- self.sld_data = self.parent.get_sld_from_omf()
- output = self.sld_data
- #frame_size = wx.Size(470, 470)
- self.plot_frame = PlotFrame(self, -1, 'testView')
- frame = self.plot_frame
- frame.Show(False)
- add_icon(self.parent, frame)
- panel = frame.plotpanel
- try:
- # mpl >= 1.0.0
- ax = panel.figure.gca(projection='3d')
- except:
- # mpl < 1.0.0
- try:
- from mpl_toolkits.mplot3d import Axes3D
- ax = Axes3D(panel.figure)
- except:
- logging.error("PlotPanel could not import Axes3D")
- raise
- panel.dimension = 3
- graph_title = self._sld_plot_helper(ax, output, has_arrow)
- # Use y, z axes (in mpl 3d) as z, y axes
- # that consistent with our SAS detector coords.
- ax.set_xlabel('x ($\A%s$)' % output.pos_unit)
- ax.set_ylabel('z ($\A%s$)' % output.pos_unit)
- ax.set_zlabel('y ($\A%s$)' % output.pos_unit)
- panel.subplot.figure.subplots_adjust(left=0.05, right=0.95,
- bottom=0.05, top=0.96)
- if output.pix_type == 'atom':
- ax.legend(loc='upper left', prop={'size':10})
- num_graph = str(self.graph_num)
- frame.SetTitle('Graph %s: %s' % (num_graph, graph_title))
- wx.CallAfter(frame.Show, True)
- self.graph_num += 1
-
- def _sld_plot_helper(self, ax, output, has_arrow=False):
- """
- Actual plot definition happens here
- :Param ax: axis3d
- :Param output: sld_data [MagSLD]
- :Param has_arrow: whether or not draws M vector [bool]
- """
- # Set the locals
- color_dic = {'H':'blue', 'D':'purple', 'N': 'orange',
- 'O':'red', 'C':'green', 'P':'cyan', 'Other':'k'}
- marker = ','
- m_size = 2
- graph_title = self.file_name
- graph_title += " 3D SLD Profile "
- pos_x = output.pos_x
- pos_y = output.pos_y
- pos_z = output.pos_z
- sld_mx = output.sld_mx
- sld_my = output.sld_my
- sld_mz = output.sld_mz
- pix_symbol = output.pix_symbol
- if output.pix_type == 'atom':
- marker = 'o'
- m_size = 3.5
- sld_tot = (numpy.fabs(sld_mx) + numpy.fabs(sld_my) + \
- numpy.fabs(sld_mz) + numpy.fabs(output.sld_n))
- is_nonzero = sld_tot > 0.0
- is_zero = sld_tot == 0.0
- # I. Plot null points
- if is_zero.any():
- ax.plot(pos_x[is_zero], pos_z[is_zero], pos_y[is_zero], marker,
- c="y", alpha=0.5, markeredgecolor='y', markersize=m_size)
- pos_x = pos_x[is_nonzero]
- pos_y = pos_y[is_nonzero]
- pos_z = pos_z[is_nonzero]
- sld_mx = sld_mx[is_nonzero]
- sld_my = sld_my[is_nonzero]
- sld_mz = sld_mz[is_nonzero]
- pix_symbol = output.pix_symbol[is_nonzero]
- # II. Plot selective points in color
- other_color = numpy.ones(len(pix_symbol), dtype='bool')
- for key in color_dic.keys():
- chosen_color = pix_symbol == key
- if numpy.any(chosen_color):
- other_color = other_color & (chosen_color != True)
- color = color_dic[key]
- ax.plot(pos_x[chosen_color], pos_z[chosen_color],
- pos_y[chosen_color], marker, c=color, alpha=0.5,
- markeredgecolor=color, markersize=m_size, label=key)
- # III. Plot All others
- if numpy.any(other_color):
- a_name = ''
- if output.pix_type == 'atom':
- # Get atom names not in the list
- a_names = [symb for symb in pix_symbol \
- if symb not in color_dic.keys()]
- a_name = a_names[0]
- for name in a_names:
- new_name = ", " + name
- if a_name.count(name) == 0:
- a_name += new_name
- # plot in black
- ax.plot(pos_x[other_color], pos_z[other_color], pos_y[other_color],
- marker, c="k", alpha=0.5, markeredgecolor="k",
- markersize=m_size, label=a_name)
- # IV. Draws atomic bond with grey lines if any
- if output.has_conect:
- for ind in range(len(output.line_x)):
- ax.plot(output.line_x[ind], output.line_z[ind],
- output.line_y[ind], '-', lw=0.6, c="grey", alpha=0.3)
- # V. Draws magnetic vectors
- if has_arrow and len(pos_x) > 0:
- graph_title += " - Magnetic Vector as Arrow -"
- panel = self.plot_frame.plotpanel
- def _draw_arrow(input=None, update=None):
- """
- draw magnetic vectors w/arrow
- """
- max_mx = max(numpy.fabs(sld_mx))
- max_my = max(numpy.fabs(sld_my))
- max_mz = max(numpy.fabs(sld_mz))
- max_m = max(max_mx, max_my, max_mz)
- try:
- max_step = max(output.xstepsize, output.ystepsize,
- output.zstepsize)
- except:
- max_step = 0
- if max_step <= 0:
- max_step = 5
- try:
- if max_m != 0:
- unit_x2 = sld_mx / max_m
- unit_y2 = sld_my / max_m
- unit_z2 = sld_mz / max_m
- # 0.8 is for avoiding the color becomes white=(1,1,1))
- color_x = numpy.fabs(unit_x2 * 0.8)
- color_y = numpy.fabs(unit_y2 * 0.8)
- color_z = numpy.fabs(unit_z2 * 0.8)
- x2 = pos_x + unit_x2 * max_step
- y2 = pos_y + unit_y2 * max_step
- z2 = pos_z + unit_z2 * max_step
- x_arrow = numpy.column_stack((pos_x, x2))
- y_arrow = numpy.column_stack((pos_y, y2))
- z_arrow = numpy.column_stack((pos_z, z2))
- colors = numpy.column_stack((color_x, color_y, color_z))
- arrows = Arrow3D(panel, x_arrow, z_arrow, y_arrow,
- colors, mutation_scale=10, lw=1,
- arrowstyle="->", alpha=0.5)
- ax.add_artist(arrows)
- except:
- pass
- msg = "Arrow Drawing completed.\n"
- status_type = 'stop'
- self._status_info(msg, status_type)
- msg = "Arrow Drawing is in progress..."
- status_type = 'progress'
- self._status_info(msg, status_type)
- draw_out = CalcGen(input=ax,
- completefn=_draw_arrow, updatefn=self._update)
- draw_out.queue()
- return graph_title
-
- def set_input_params(self):
- """
- Set model parameters
- """
- for list in self.parameters:
- param_name = list[0].GetLabelText()
- param_value = float(list[1].GetValue())
- self.model.setParam(param_name, param_value)
-
- def on_compute(self, event):
- """
- Compute I(qx, qy)
- """
- flag = self.parent.check_omfpanel_inputs()
- if not flag and self.parent.parent != None:
- infor = 'Error'
- msg = 'Error: Wrong inputs in the SLD info panel.'
- # inform msg to wx
- wx.PostEvent(self.parent.parent,
- StatusEvent(status=msg, info=infor))
- self.SetFocus()
- return
- self.sld_data = self.parent.get_sld_from_omf()
- if self.sld_data == None:
- if self.parent.parent != None:
- infor = 'Error'
- msg = 'Error: No data has been selected.'
- # inform msg to wx
- wx.PostEvent(self.parent.parent,
- StatusEvent(status=msg, info=infor))
- self.SetFocus()
- return
- flag = self._check_value()
- if not flag:
- _set_error(self, None, True)
- return
- try:
- self.model.set_sld_data(self.sld_data)
- self.set_input_params()
- if self.is_avg or self.is_avg == None:
- self._create_default_1d_data()
- i_out = numpy.zeros(len(self.data.y))
- inputs = [self.data.x, [], i_out]
- else:
- self._create_default_2d_data()
- i_out = numpy.zeros(len(self.data.data))
- inputs = [self.data.qx_data, self.data.qy_data, i_out]
-
- msg = "Computation is in progress..."
- status_type = 'progress'
- self._status_info(msg, status_type)
- cal_out = CalcGen(input=inputs,
- completefn=self.complete,
- updatefn=self._update)
- cal_out.queue()
-
- except:
- msg = "%s." % sys.exc_value
- status_type = 'stop'
- self._status_info(msg, status_type)
- wx.PostEvent(self.parent.parent,
- StatusEvent(status=msg, info='Error'))
- self.SetFocus()
-
- def on_help(self, event):
- """
- Bring up the General scattering Calculator Documentation whenever
- the HELP button is clicked.
-
- Calls DocumentationWindow with the path of the location within the
- documentation tree (after /doc/ ....". Note that when using old
- versions of Wx (before 2.9) and thus not the release version of
- installers, the help comes up at the top level of the file as
- webbrowser does not pass anything past the # to the browser when it is
- running "file:///...."
-
- :param evt: Triggers on clicking the help button
- """
-
- _TreeLocation = "user/sasgui/perspectives/calculator/"
- _TreeLocation += "sas_calculator_help.html"
- _doc_viewer = DocumentationWindow(self, -1, _TreeLocation, "",
- "General Scattering Calculator Help")
-
- def _check_value(self):
- """
- Check input values if float
- """
- flag = True
- self.npt_ctl.SetBackgroundColour("white")
- self.qmax_ctl.SetBackgroundColour("white")
- try:
- npt_val = float(self.npt_ctl.GetValue())
- if npt_val < 2 or npt_val > 1000:
- raise
- self.npt_ctl.SetValue(str(int(npt_val)))
- self.set_est_time()
- except:
- flag = _set_error(self, self.npt_ctl)
- try:
- qmax_val = float(self.qmax_ctl.GetValue())
- if qmax_val <= 0 or qmax_val > 1000:
- raise
- except:
- flag = _set_error(self, self.qmax_ctl)
- for list in self.parameters:
- list[1].SetBackgroundColour("white")
- param_name = list[0].GetLabelText()
- try:
- param_val = float(list[1].GetValue())
- if param_name.count('frac') > 0:
- if param_val < 0 or param_val > 1:
- raise
- except:
- flag = _set_error(self, list[1])
- return flag
-
- def _status_info(self, msg='', type="update"):
- """
- Status msg
- """
- if type == "stop":
- label = "Compute"
- able = True
- else:
- label = "Wait..."
- able = False
- self.bt_compute.Enable(able)
- self.bt_compute.SetLabel(label)
- self.bt_compute.SetToolTipString(label)
- if self.parent.parent != None:
- wx.PostEvent(self.parent.parent,
- StatusEvent(status=msg, type=type))
-
- def _update(self, time=None):
- """
- Update the progress bar
- """
- if self.parent.parent == None:
- return
- type = "progress"
- msg = "Please wait. Computing... (Note: Window may look frozen.)"
- wx.PostEvent(self.parent.parent, StatusEvent(status=msg,
- type=type))
-
- def complete(self, input, update=None):
- """
- Gen compute complete function
- :Param input: input list [qx_data, qy_data, i_out]
- """
- out = numpy.empty(0)
- #s = time.time()
- for ind in range(len(input[0])):
- if self.is_avg:
- if ind % 1 == 0 and update != None:
- update()
- time.sleep(0.1)
- inputi = [input[0][ind:ind + 1], [], input[2][ind:ind + 1]]
- outi = self.model.run(inputi)
- out = numpy.append(out, outi)
- else:
- if ind % 50 == 0 and update != None:
- update()
- time.sleep(0.001)
- inputi = [input[0][ind:ind + 1], input[1][ind:ind + 1],
- input[2][ind:ind + 1]]
- outi = self.model.runXY(inputi)
- out = numpy.append(out, outi)
- #print time.time() - s
- if self.is_avg or self.is_avg == None:
- self._draw1D(out)
- else:
- #out = self.model.runXY(input)
- self._draw2D(out)
-
- msg = "Gen computation completed.\n"
- status_type = 'stop'
- self._status_info(msg, status_type)
-
- def _create_default_2d_data(self):
- """
- Create 2D data by default
- Only when the page is on theory mode.
- :warning: This data is never plotted.
- """
- self.qmax_x = float(self.qmax_ctl.GetValue())
- self.npts_x = int(float(self.npt_ctl.GetValue()))
- self.data = Data2D()
- qmax = self.qmax_x #/ numpy.sqrt(2)
- self.data.xaxis('\\rm{Q_{x}}', '\AA^{-1}')
- self.data.yaxis('\\rm{Q_{y}}', '\AA^{-1}')
- self.data.is_data = False
- self.data.id = str(self.uid) + " GenData"
- self.data.group_id = str(self.uid) + " Model2D"
- ## Default values
- self.data.detector.append(Detector())
- index = len(self.data.detector) - 1
- self.data.detector[index].distance = 8000 # mm
- self.data.source.wavelength = 6 # A
- self.data.detector[index].pixel_size.x = 5 # mm
- self.data.detector[index].pixel_size.y = 5 # mm
- self.data.detector[index].beam_center.x = qmax
- self.data.detector[index].beam_center.y = qmax
- xmax = qmax
- xmin = -qmax
- ymax = qmax
- ymin = -qmax
- qstep = self.npts_x
-
- x = numpy.linspace(start=xmin, stop=xmax, num=qstep, endpoint=True)
- y = numpy.linspace(start=ymin, stop=ymax, num=qstep, endpoint=True)
- ## use data info instead
- new_x = numpy.tile(x, (len(y), 1))
- new_y = numpy.tile(y, (len(x), 1))
- new_y = new_y.swapaxes(0, 1)
- # all data reuire now in 1d array
- qx_data = new_x.flatten()
- qy_data = new_y.flatten()
- q_data = numpy.sqrt(qx_data * qx_data + qy_data * qy_data)
- # set all True (standing for unmasked) as default
- mask = numpy.ones(len(qx_data), dtype=bool)
- # store x and y bin centers in q space
- x_bins = x
- y_bins = y
- self.data.source = Source()
- self.data.data = numpy.ones(len(mask))
- self.data.err_data = numpy.ones(len(mask))
- self.data.qx_data = qx_data
- self.data.qy_data = qy_data
- self.data.q_data = q_data
- self.data.mask = mask
- self.data.x_bins = x_bins
- self.data.y_bins = y_bins
- # max and min taking account of the bin sizes
- self.data.xmin = xmin
- self.data.xmax = xmax
- self.data.ymin = ymin
- self.data.ymax = ymax
-
- def _create_default_1d_data(self):
- """
- Create 2D data by default
- Only when the page is on theory mode.
- :warning: This data is never plotted.
- residuals.x = data_copy.x[index]
- residuals.dy = numpy.ones(len(residuals.y))
- residuals.dx = None
- residuals.dxl = None
- residuals.dxw = None
- """
- self.qmax_x = float(self.qmax_ctl.GetValue())
- self.npts_x = int(float(self.npt_ctl.GetValue()))
- qmax = self.qmax_x #/ numpy.sqrt(2)
- ## Default values
- xmax = qmax
- xmin = qmax * _Q1D_MIN
- qstep = self.npts_x
- x = numpy.linspace(start=xmin, stop=xmax, num=qstep, endpoint=True)
- # store x and y bin centers in q space
- #self.data.source = Source()
- y = numpy.ones(len(x))
- dy = numpy.zeros(len(x))
- dx = numpy.zeros(len(x))
- self.data = Data1D(x=x, y=y)
- self.data.dx = dx
- self.data.dy = dy
-
- def _draw1D(self, y_out):
- """
- Complete get the result of modelthread and create model 2D
- that can be plot.
- """
- page_id = self.id
- data = self.data
-
- model = self.model
- state = None
-
- new_plot = Data1D(x=data.x, y=y_out)
- new_plot.dx = data.dx
- new_plot.dy = data.dy
- new_plot.xaxis('\\rm{Q_{x}}', '\AA^{-1}')
- new_plot.yaxis('\\rm{Intensity}', 'cm^{-1}')
- new_plot.is_data = False
- new_plot.id = str(self.uid) + " GenData1D"
- new_plot.group_id = str(self.uid) + " Model1D"
- new_plot.name = model.name + '1d'
- new_plot.title = "Generic model1D "
- new_plot.id = str(page_id) + ': ' + self.file_name \
- + ' #%s' % str(self.graph_num) + "_1D"
- new_plot.group_id = str(page_id) + " Model1D" + \
- ' #%s' % str(self.graph_num) + "_1D"
- new_plot.is_data = False
-
- title = new_plot.title
- _yaxis, _yunit = new_plot.get_yaxis()
- _xaxis, _xunit = new_plot.get_xaxis()
- new_plot.xaxis(str(_xaxis), str(_xunit))
- new_plot.yaxis(str(_yaxis), str(_yunit))
-
- if new_plot.is_data:
- data_name = str(new_plot.name)
- else:
- data_name = str(model.__class__.__name__) + '1d'
-
- if len(title) > 1:
- new_plot.title = "Gen Theory for %s " % model.name + data_name
- new_plot.name = new_plot.id
- new_plot.label = new_plot.id
- #theory_data = deepcopy(new_plot)
- if self.parent.parent != None:
- self.parent.parent.update_theory(data_id=new_plot.id,
- theory=new_plot,
- state=state)
- title = new_plot.title
- num_graph = str(self.graph_num)
- wx.CallAfter(self.parent.draw_graph, new_plot,
- title="GEN Graph %s: " % num_graph + new_plot.id)
- self.graph_num += 1
-
- def _draw2D(self, image):
- """
- Complete get the result of modelthread and create model 2D
- that can be plot.
- """
- page_id = self.id
- data = self.data
-
- model = self.model
- qmin = 0.0
- state = None
-
- numpy.nan_to_num(image)
- new_plot = Data2D(image=image, err_image=data.err_data)
- new_plot.name = model.name + '2d'
- new_plot.title = "Generic model 2D "
- new_plot.id = str(page_id) + ': ' + self.file_name \
- + ' #%s' % str(self.graph_num) + "_2D"
- new_plot.group_id = str(page_id) + " Model2D" \
- + ' #%s' % str(self.graph_num) + "_2D"
- new_plot.detector = data.detector
- new_plot.source = data.source
- new_plot.is_data = False
- new_plot.qx_data = data.qx_data
- new_plot.qy_data = data.qy_data
- new_plot.q_data = data.q_data
- new_plot.mask = data.mask
- ## plot boundaries
- new_plot.ymin = data.ymin
- new_plot.ymax = data.ymax
- new_plot.xmin = data.xmin
- new_plot.xmax = data.xmax
- title = data.title
- _yaxis, _yunit = data.get_yaxis()
- _xaxis, _xunit = data.get_xaxis()
- new_plot.xaxis(str(_xaxis), str(_xunit))
- new_plot.yaxis(str(_yaxis), str(_yunit))
-
- new_plot.is_data = False
- if data.is_data:
- data_name = str(data.name)
- else:
- data_name = str(model.__class__.__name__) + '2d'
-
- if len(title) > 1:
- new_plot.title = "Gen Theory for %s " % model.name + data_name
- new_plot.name = new_plot.id
- new_plot.label = new_plot.id
- #theory_data = deepcopy(new_plot)
- if self.parent.parent != None:
- self.parent.parent.update_theory(data_id=data.id,
- theory=new_plot,
- state=state)
- title = new_plot.title
- num_graph = str(self.graph_num)
- wx.CallAfter(self.parent.draw_graph, new_plot,
- title="GEN Graph %s: " % num_graph + new_plot.id)
- self.graph_num += 1
-
- def set_scale2d(self, scale):
- """
- Set SLD plot scale
- """
- self.scale2d = None
-
- def on_panel_close(self, event):
- """
- close the window containing this panel
- """
- self.parent.Close()
-
-class OmfPanel(ScrolledPanel, PanelBase):
- """
- Provides the sas gen calculator GUI.
- """
- ## Internal nickname for the window, used by the AUI manager
- window_name = "SLD Pixel Info"
- ## Name to appear on the window title bar
- window_caption = "SLD Pixel Info "
-
- def __init__(self, parent, *args, **kwds):
- ScrolledPanel.__init__(self, parent, style=wx.RAISED_BORDER,
- *args, **kwds)
- PanelBase.__init__(self)
- #Font size
- self.SetWindowVariant(variant=FONT_VARIANT)
- self.SetupScrolling()
- # Object that receive status event
- self.parent = parent
- self.sld_data = sas_gen.MagSLD([0], [0], [0])
- self.sld_ctl = None
- self.default_shape = 'rectangular'
- self._do_layout()
-
- def set_slddata(self, slddata):
- """
- Set sld data related items
- """
- self.sld_data = slddata
- self._set_slddata_ctr_val(slddata)
- # Make sure that self._set_slddata_ctr_val() is finished
- wx.CallAfter(self._set_omfdata_ctr, slddata)
-
- def get_sld_val(self):
- """
- Set sld_n of slddata on sld input
- """
- sld_sets = {}
- if not self.sld_data.is_data:
- self._get_other_val()
- for list in self.slds:
- if list[1].IsEnabled():
- list[1].SetBackgroundColour("white")
- list[1].Refresh()
- try:
- val = float(list[1].GetValue())
- sld_sets[list[0]] = val
- except:
- flag = _set_error(self, list[1])
- if not flag:
- return self.sld_data
- else:
- sld_sets[list[0]] = None
- for key in sld_sets.keys():
- key_low = key.lower()
- if key_low.count('mx') > 0:
- if sld_sets[key] == None:
- sld_sets[key] = self.sld_data.sld_mx
- mx = sld_sets[key]
- elif key_low.count('my') > 0:
- if sld_sets[key] == None:
- sld_sets[key] = self.sld_data.sld_my
- my = sld_sets[key]
- elif key_low.count('mz') > 0:
- if sld_sets[key] == None:
- sld_sets[key] = self.sld_data.sld_mz
- mz = sld_sets[key]
- else:
- if sld_sets[key] != None:
- self.sld_data.set_sldn(sld_sets[key])
- self.sld_data.set_sldms(mx, my, mz)
- self._set_slddata_ctr_val(self.sld_data)
-
- return self.sld_data
-
- def get_pix_volumes(self):
- """
- Get the pixel volume
- """
- vol = self.sld_data.vol_pix
-
- return vol
-
- def _get_other_val(self):
- """
- """
- omfdata = sas_gen.OMFData()
- sets = {}
- try:
- for lst in self.stepsize:
- if lst[1].IsEnabled():
- val = float(lst[1].GetValue())
- sets[lst[0]] = val
- else:
- sets[lst[0]] = None
- return
- for lst in self.nodes:
- if lst[1].IsEnabled():
- val = float(lst[1].GetValue())
- sets[lst[0]] = val
- else:
- sets[lst[0]] = None
- return
-
- for key in sets.keys():
- setattr(omfdata, key, sets[key])
-
- omf2sld = sas_gen.OMF2SLD()
- omf2sld.set_data(omfdata, self.default_shape)
- self.sld_data = omf2sld.output
- self.sld_data.is_data = False
- self.sld_data.filename = "Default SLD Profile"
- except:
- msg = "OMF Panel: %s" % sys.exc_value
- infor = 'Error'
- #logging.error(msg)
- if self.parent.parent != None:
- # inform msg to wx
- wx.PostEvent(self.parent.parent,
- StatusEvent(status=msg, info=infor))
- self.SetFocus()
-
- def _set_slddata_ctr_val(self, slddata):
- """
- Set slddata crl
- """
- try:
- val = str(len(slddata.sld_n))
- except:
- val = 'Unknown'
- self.npix_ctl.SetValue(val)
-
- def _set_omfdata_ctr(self, omfdata):
- """
- Set the textctr box values
- """
-
- if omfdata == None:
- self._set_none_text()
- return
- nodes_list = self._get_nodes_key_list(omfdata)
- step_list = self._get_step_key_list(omfdata)
- for ctr_list in self.nodes:
- for key in nodes_list.keys():
- if ctr_list[0] == key:
- ctr_list[1].SetValue(format_number(nodes_list[key], True))
- ctr_list[1].Enable(not omfdata.is_data)
- break
- for ctr_list in self.stepsize:
- for key in step_list.keys():
- if ctr_list[0] == key:
- ctr_list[1].SetValue(format_number(step_list[key], True))
- ctr_list[1].Enable(not omfdata.is_data)
- break
-
- def _set_none_text(self):
- """
- Set Unknown in textctrls
- """
- val = 'Unknown'
- for ctr_list in self.nodes:
- ctr_list[1].SetValue(val)
- for ctr_list in self.stepsize:
- ctr_list[1].SetValue(val)
-
- def _define_structure(self):
- """
- Define the main sizers building to build this application.
- """
- self.main_sizer = wx.BoxSizer(wx.VERTICAL)
-
- self.npixels_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.box_sld = wx.StaticBox(self, -1,
- str("Mean SLD"))
- self.box_node = wx.StaticBox(self, -1, str("Nodes"))
- self.boxsizer_sld = wx.StaticBoxSizer(self.box_sld, wx.VERTICAL)
- self.box_stepsize = wx.StaticBox(self, -1, str("Step Size"))
- self.boxsizer_node = wx.StaticBoxSizer(self.box_node, wx.VERTICAL)
- self.boxsizer_stepsize = wx.StaticBoxSizer(self.box_stepsize,
- wx.VERTICAL)
- self.sld_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.node_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.step_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.hint_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.button_sizer = wx.BoxSizer(wx.HORIZONTAL)
-
- def _layout_npix(self):
- """
- Build No of pixels sizer
- """
- num_pix_text = wx.StaticText(self, -1, "No. of Pixels: ")
- self.npix_ctl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH, 20),
- style=wx.TE_PROCESS_ENTER)
- self._set_slddata_ctr_val(self.sld_data)
- self._set_omfdata_ctr(self.sld_data)
- self.npixels_sizer.AddMany([(num_pix_text, 0,
- wx.EXPAND | wx.LEFT | wx.TOP, 5),
- (self.npix_ctl, 0,
- wx.EXPAND | wx.TOP, 5)])
-
- def _layout_slds(self):
- """
- Build nuclear sld sizer
- """
- self.slds = []
- omfdata = self.sld_data
- if omfdata == None:
- raise
- sld_key_list = self._get_slds_key_list(omfdata)
- # Dic is not sorted
- key_list = [key for key in sld_key_list.keys()]
- # Sort here
- key_list.sort()
- is_data = self.sld_data.is_data
- sizer = wx.GridBagSizer(2, 3)
- ix = 0
- iy = -1
- for key in key_list:
- value = sld_key_list[key]
- iy += 1
- ix = 0
- name = wx.StaticText(self, -1, key)
- sizer.Add(name, (iy, ix), (1, 1), \
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ## add parameter value
- ix += 1
- ctl = InputTextCtrl(self, -1, size=(_BOX_WIDTH, 20),
- style=wx.TE_PROCESS_ENTER)
- ctl.SetValue(format_number(value, True))
- ctl.Enable(not is_data)
- sizer.Add(ctl, (iy, ix), (1, 1), wx.EXPAND)
- ## add unit
- ix += 1
- s_unit = '[' + omfdata.sld_unit + ']'
- unit = wx.StaticText(self, -1, s_unit)
- sizer.Add(unit, (iy, ix), (1, 1), \
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- self.slds.append([key, ctl, unit])
- self.sld_sizer.Add(sizer, 0, wx.LEFT, 10)
-
- def _layout_nodes(self):
- """
- Fill the sizer containing data's name
- """
- self.nodes = []
- omfdata = self.sld_data
- if omfdata == None:
- raise
- key_list = self._get_nodes_key_list(omfdata)
- is_data = self.sld_data.is_data
- sizer = wx.GridBagSizer(2, 3)
- ix = 0
- iy = -1
- for key, value in key_list.iteritems():
- iy += 1
- ix = 0
- name = wx.StaticText(self, -1, key)
- sizer.Add(name, (iy, ix), (1, 1), \
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ## add parameter value
- ix += 1
- ctl = InputTextCtrl(self, -1, size=(_BOX_WIDTH, 20),
- style=wx.TE_PROCESS_ENTER)
- ctl.Bind(wx.EVT_TEXT, self._onparamEnter)
- ctl.SetValue(format_number(value, True))
- ctl.Enable(not is_data)
- sizer.Add(ctl, (iy, ix), (1, 1), wx.EXPAND)
- ## add unit
- ix += 1
- unit = wx.StaticText(self, -1, '')
- sizer.Add(unit, (iy, ix), (1, 1), \
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- self.nodes.append([key, ctl, unit])
- self.node_sizer.Add(sizer, 0, wx.LEFT, 10)
-
- def _layout_stepsize(self):
- """
- Fill the sizer containing slit size information
- """
- self.stepsize = []
- omfdata = self.sld_data
- if omfdata == None:
- raise
- key_list = self._get_step_key_list(omfdata)
- is_data = self.sld_data.is_data
- sizer = wx.GridBagSizer(2, 3)
- ix = 0
- iy = -1
- #key_list.sort()
- for key, value in key_list.iteritems():
- iy += 1
- ix = 0
- name = wx.StaticText(self, -1, key)
- sizer.Add(name, (iy, ix), (1, 1), \
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ## add parameter value
- ix += 1
- ctl = InputTextCtrl(self, -1, size=(_BOX_WIDTH, 20),
- style=wx.TE_PROCESS_ENTER)
- ctl.Bind(wx.EVT_TEXT, self._onstepsize)
- ctl.SetValue(format_number(value, True))
- ctl.Enable(not is_data)
- sizer.Add(ctl, (iy, ix), (1, 1), wx.EXPAND)
- ## add unit
- ix += 1
- p_unit = '[' + omfdata.pos_unit + ']'
- unit = wx.StaticText(self, -1, p_unit)
- sizer.Add(unit, (iy, ix), (1, 1), \
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- self.stepsize.append([key, ctl, unit])
- self.step_sizer.Add(sizer, 0, wx.LEFT, 10)
-
- def _layout_hint(self):
- """
- Fill the sizer containing hint
- """
- hint_msg = "Load an omf or 3d sld profile data file."
- self.hint_txt = wx.StaticText(self, -1, hint_msg)
- self.hint_sizer.AddMany([(self.hint_txt, 0, wx.LEFT, 15)])
-
- def _layout_button(self):
- """
- Do the layout for the button widgets
- """
- self.bt_draw = wx.Button(self, wx.NewId(), 'Draw Points')
- self.bt_draw.Bind(wx.EVT_BUTTON, self.on_sld_draw)
- self.bt_draw.SetToolTipString("Draw a scatter plot for sld profile.")
- self.bt_save = wx.Button(self, wx.NewId(), 'Save SLD Data')
- self.bt_save.Bind(wx.EVT_BUTTON, self.on_save)
- self.bt_save.Enable(False)
- self.bt_save.SetToolTipString("Save SLD data.")
- self.button_sizer.AddMany([(self.bt_draw, 0, wx.LEFT, 10),
- (self.bt_save, 0, wx.LEFT, 10)])
-
- def _do_layout(self):
- """
- Draw omf panel content, used to define sld s.
-
- """
- self._define_structure()
- self._layout_nodes()
- self._layout_stepsize()
- self._layout_npix()
- self._layout_slds()
- #self._layout_hint()
- self._layout_button()
- self.boxsizer_node.AddMany([(self.node_sizer, 0,
- wx.EXPAND | wx.TOP, 5),
- (self.hint_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
- self.boxsizer_stepsize.AddMany([(self.step_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5), ])
- self.boxsizer_sld.AddMany([(self.sld_sizer, 0,
- wx.EXPAND | wx.BOTTOM, 5), ])
- self.main_sizer.AddMany([(self.npixels_sizer, 0, wx.EXPAND | wx.ALL, 10),
- (self.boxsizer_sld, 0, wx.EXPAND | wx.ALL, 10),
- (self.boxsizer_node, 0, wx.EXPAND | wx.ALL, 10),
- (self.boxsizer_stepsize, 0, wx.EXPAND | wx.ALL, 10),
- (self.button_sizer, 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
- self.SetSizer(self.main_sizer)
- self.SetAutoLayout(True)
-
- def _get_nodes_key_list(self, data):
- """
- Return nodes key list
-
- :Param data: OMFData
- """
- key_list = {'xnodes' : data.xnodes,
- 'ynodes' : data.ynodes,
- 'znodes' : data.znodes}
- return key_list
-
- def _get_slds_key_list(self, data):
- """
- Return nodes key list
-
- :Param data: OMFData
- """
- key_list = {'Nucl.' : data.sld_n,
- 'Mx' : data.sld_mx,
- 'My' : data.sld_my,
- 'Mz' : data.sld_mz}
- return key_list
-
- def _get_step_key_list(self, data):
- """
- Return step key list
-
- :Param data: OMFData
- """
- key_list = {'xstepsize' : data.xstepsize,
- 'ystepsize' : data.ystepsize,
- 'zstepsize' : data.zstepsize}
- return key_list
-
- def set_sld_ctr(self, sld_data):
- """
- Set sld textctrls
- """
- if sld_data == None:
- for ctr_list in self.slds:
- ctr_list[1].Enable(False)
- #break
- return
-
- self.sld_data = sld_data
- sld_list = self._get_slds_key_list(sld_data)
- for ctr_list in self.slds:
- for key in sld_list.keys():
- if ctr_list[0] == key:
- min_val = numpy.min(sld_list[key])
- max_val = numpy.max(sld_list[key])
- mean_val = numpy.mean(sld_list[key])
- enable = (min_val == max_val) and \
- sld_data.pix_type == 'pixel'
- ctr_list[1].SetValue(format_number(mean_val, True))
- ctr_list[1].Enable(enable)
- #ctr_list[2].SetLabel("[" + sld_data.sld_unit + "]")
- break
-
- def on_sld_draw(self, event):
- """
- Draw sld profile as scattered plot
- """
- self.parent.sld_draw()
-
- def on_save(self, event):
- """
- Close the window containing this panel
- """
- flag = True
- flag = self.check_inputs()
- if not flag:
- return
- self.sld_data = self.get_sld_val()
- self.parent.set_main_panel_sld_data(self.sld_data)
-
- reader = sas_gen.SLDReader()
- extension = '*.sld'
- path = None
- data = None
- location = self.parent.get_path()
- dlg = wx.FileDialog(self, "Save sld file",
- location, "sld_file",
- extension,
- wx.SAVE)
- if dlg.ShowModal() == wx.ID_OK:
- path = dlg.GetPath()
- self.parent.set_file_location(os.path.dirname(path))
- else:
- return None
- dlg.Destroy()
- try:
- if path is None:
- return
-
- data = self.parent.get_sld_data()
- fName = os.path.splitext(path)[0] + '.' + extension.split('.')[-1]
- if data != None:
- try:
- reader.write(fName, data)
- except:
- raise
- else:
- msg = "%s cannot write %s\n" % ('Generic Scattering', str(path))
- infor = 'Error'
- #logging.error(msg)
- if self.parent.parent != None:
- # inform msg to wx
- wx.PostEvent(self.parent.parent,
- StatusEvent(status=msg, info=infor))
- self.SetFocus()
- return
- except:
- msg = "Error occurred while saving. "
- infor = 'Error'
- if self.parent.parent != None:
- # inform msg to wx
- wx.PostEvent(self.parent.parent,
- StatusEvent(status=msg, info=infor))
- self.SetFocus()
-
- def _onparamEnter(self, event):
- """
- """
- flag = True
- if event != None:
- event.Skip()
- ctl = event.GetEventObject()
- ctl.SetBackgroundColour("white")
- #_set_error(self, ctl)
- try:
- float(ctl.GetValue())
- except:
- flag = _set_error(self, ctl)
- if flag:
- npts = 1
- for item in self.nodes:
- n_val = float(item[1].GetValue())
- if n_val <= 0:
- item[1].SetBackgroundColour("pink")
- npts = -1
- break
- if numpy.isfinite(n_val):
- npts *= int(n_val)
- if npts > 0:
- nop = self.set_npts_from_slddata()
- if nop == None:
- nop = npts
- self.display_npts(nop)
-
- ctl.Refresh()
- return flag
-
- def _set_volume_ctr_val(self, npts):
- """
- Set total volume
- """
- total_volume = npts * self.sld_data.vol_pix[0]
- self.parent.set_volume_ctr_val(total_volume)
-
- def _onstepsize(self, event):
- """
- On stepsize event
- """
- flag = True
- if event != None:
- event.Skip()
- ctl = event.GetEventObject()
- ctl.SetBackgroundColour("white")
-
- if flag and not self.sld_data.is_data:#ctl.IsEnabled():
- s_size = 1.0
- try:
- for item in self.stepsize:
- s_val = float(item[1].GetValue())
- if s_val <= 0:
- item[1].SetBackgroundColour("pink")
- ctl.Refresh()
- return
- if numpy.isfinite(s_val):
- s_size *= s_val
- self.sld_data.set_pixel_volumes(s_size)
- if ctl.IsEnabled():
- total_volume = sum(self.sld_data.vol_pix)
- self.parent.set_volume_ctr_val(total_volume)
- except:
- pass
- ctl.Refresh()
-
-
- def set_npts_from_slddata(self):
- """
- Set total n. of points form the sld data
- """
- try:
- sld_data = self.parent.get_sld_from_omf()
- #nop = (nop * numpy.pi) / 6
- nop = len(sld_data.sld_n)
- except:
- nop = None
- return nop
-
- def display_npts(self, nop):
- """
- Displays Npts ctrl
- """
- try:
- self.npix_ctl.SetValue(str(nop))
- self.npix_ctl.Refresh()
- self.parent.set_etime()
- wx.CallAfter(self._set_volume_ctr_val, nop)
- except:
- # On Init
- pass
-
- def check_inputs(self):
- """
- check if the inputs are valid
- """
- flag = self._check_input_helper(self.slds)
- if flag:
- flag = self._check_input_helper(self.nodes)
- if flag:
- flag = self._check_input_helper(self.stepsize)
- return flag
-
- def _check_input_helper(self, list):
- """
- Check list values
- """
- flag = True
- for item in list:
- item[1].SetBackgroundColour("white")
- item[1].Refresh()
- try:
- float(item[1].GetValue())
- except:
- flag = _set_error(self, item[1])
- break
- return flag
-
-class SasGenWindow(widget.CHILD_FRAME):
- """
- GEN SAS main window
- """
- def __init__(self, parent=None, manager=None, title="Generic Scattering Calculator",
- size=(PANEL_WIDTH * 1.4, PANEL_HEIGHT * 1.65), *args, **kwds):
- """
- Init
- """
- kwds['size'] = size
- kwds['title'] = title
- widget.CHILD_FRAME.__init__(self, parent, *args, **kwds)
- self.parent = parent
- self.base = manager
- self.omfpanel = OmfPanel(parent=self)
- self.panel = SasGenPanel(parent=self)
- self.data = None
- self.omfdata = sas_gen.OMFData()
- self.sld_data = None
- self._default_save_location = os.getcwd()
-
- self._mgr = aui.AuiManager(self)
- self._mgr.SetDockSizeConstraint(0.5, 0.5)
- self._plot_title = ''
- self.scale2d = 'log_{10}'
- self.Bind(wx.EVT_CLOSE, self.on_close)
-
-
- self.build_panels()
- self.SetPosition((wx.LEFT, PANEL_TOP))
- self.Show(True)
-
- def build_panels(self):
- """
- """
-
- self.set_sld_data(self.sld_data)
- self._mgr.AddPane(self.panel, aui.AuiPaneInfo().
- Name(self.panel.window_name).
- CenterPane().
- # This is where we set the size of
- # the application window
- BestSize(wx.Size(PANEL_WIDTH,
- PANEL_HEIGHT)).
- Show())
- self._mgr.AddPane(self.omfpanel, aui.AuiPaneInfo().
- Name(self.omfpanel.window_name).
- Caption(self.omfpanel.window_caption).
- CloseButton(False).
- Right().
- Floatable(False).
- BestSize(wx.Size(PANEL_WIDTH / 2.5, PANEL_HEIGHT)).
- Show())
- self._mgr.Update()
-
- def get_sld_data(self):
- """
- Return slddata
- """
- return self.sld_data
-
- def get_sld_from_omf(self):
- """
- """
- self.sld_data = self.omfpanel.get_sld_val()
- return self.sld_data
-
- def set_sld_n(self, sld):
- """
- """
- self.panel.sld_data = sld
- self.panel.model.set_sld_data(sld)
-
- def set_sld_data(self, data):
- """
- Set omfdata
- """
- if data == None:
- return
- self.sld_data = data
- enable = (not data == None)
- self._set_omfpanel_sld_data(self.sld_data)
- self.omfpanel.bt_save.Enable(enable)
- self.set_etime()
-
- def set_omfpanel_npts(self):
- """
- Set Npts in omf panel
- """
- nop = self.omfpanel.set_npts_from_slddata()
- self.omfpanel.display_npts(nop)
-
- def _set_omfpanel_sld_data(self, data):
- """
- Set sld_data in omf panel
- """
- self.omfpanel.set_slddata(data)
- self.omfpanel.set_sld_ctr(data)
-
- def check_omfpanel_inputs(self):
- """
- Check OMF panel inputs
- """
- return self.omfpanel.check_inputs()
-
- def set_main_panel_sld_data(self, sld_data):
- """
- """
- self.sld_data = sld_data
-
- def set_file_location(self, path):
- """
- File location
- """
- self._default_save_location = path
-
- def get_path(self):
- """
- File location
- """
- return self._default_save_location
-
- def draw_graph(self, plot, title=''):
- """
- """
- try:
- wx.PostEvent(self.parent, NewPlotEvent(plot=plot, title=title))
- except:
- # standalone
- frame = PlotFrame(self, -1, 'testView', self.scale2d)
- #add_icon(self.parent, frame)
- frame.add_plot(plot)
- frame.SetTitle(title)
- frame.Show(True)
- frame.SetFocus()
-
- def set_schedule_full_draw(self, panel=None, func='del'):
- """
- Send full draw to gui frame
- """
- if self.parent != None:
- self.parent.set_schedule_full_draw(panel, func)
-
- def get_npix(self):
- """
- Get no. of pixels from omf panel
- """
- n_pix = self.omfpanel.npix_ctl.GetValue()
- return n_pix
-
- def get_pix_volumes(self):
- """
- Get a pixel volume
- """
- vol = self.omfpanel.get_pix_volumes()
- return vol
-
- def set_volume_ctr_val(self, val):
- """
- Set volume txtctl value
- """
- try:
- self.panel.set_volume_ctl_val(str(val))
- except:
- print "self.panel is not initialized yet"
-
- def set_omfpanel_default_shap(self, shape):
- """
- Set default_shape in omfpanel
- """
- self.omfpanel.default_shape = shape
-
- def set_etime(self):
- """
- Sets est. computation time on panel
- """
- self.panel.set_est_time()
-
- def get_sld_data_from_omf(self):
- """
- """
- data = self.omfpanel.get_sld_val()
- return data
-
- def set_scale2d(self, scale):
- """
- """
- self.scale2d = scale
-
- def on_panel_close(self, event):
- """
- """
- #Not implemented
-
- def on_open_file(self, event):
- """
- On Open
- """
- self.panel.on_load_data(event)
-
- def sld_draw(self):
- """
- sld draw
- """
- self.panel.sld_draw(event=None, has_arrow=False)
-
- def on_save_file(self, event):
- """
- On Close
- """
- self.omfpanel.on_save(event)
-
- def on_close(self, event):
- """
- Close
- """
- if self.base != None:
- self.base.gen_frame = None
- self.Destroy()
-
-if __name__ == "__main__":
- app = wx.PySimpleApp()
- widget.CHILD_FRAME = wx.Frame
- SGframe = SasGenWindow()
- SGframe.Show(True)
- app.MainLoop()
+"""
+Generic Scattering panel.
+This module relies on guiframe manager.
+"""
+from __future__ import print_function
+
+import wx
+import sys
+import os
+import numpy as np
+#import math
+import wx.aui as aui
+#import wx.lib.agw.aui as aui
+import logging
+import time
+
+import matplotlib
+matplotlib.interactive(False)
+#Use the WxAgg back end. The Wx one takes too long to render
+matplotlib.use('WXAgg')
+
+#from sas.sasgui.guiframe.gui_manager import MDIFrame
+from sas.sascalc.data_util.calcthread import CalcThread
+from sas.sasgui.guiframe.local_perspectives.plotting.SimplePlot import PlotFrame
+from sas.sasgui.guiframe.dataFitting import Data2D
+from sas.sasgui.guiframe.dataFitting import Data1D
+from sas.sascalc.dataloader.data_info import Detector
+from sas.sascalc.dataloader.data_info import Source
+from sas.sasgui.guiframe.panel_base import PanelBase
+from sas.sasgui.guiframe.utils import format_number
+from sas.sasgui.guiframe.events import StatusEvent
+from sas.sascalc.calculator import sas_gen
+from sas.sasgui.perspectives.calculator.calculator_widgets import OutputTextCtrl
+from sas.sasgui.perspectives.calculator.calculator_widgets import InputTextCtrl
+from wx.lib.scrolledpanel import ScrolledPanel
+from sas.sasgui.perspectives.calculator.load_thread import GenReader
+from sas.sasgui.plottools.arrow3d import Arrow3D
+from sas.sasgui.perspectives.calculator import calculator_widgets as widget
+from sas.sasgui.guiframe.events import NewPlotEvent
+from sas.sasgui.guiframe.documentation_window import DocumentationWindow
+
+logger = logging.getLogger(__name__)
+
+_BOX_WIDTH = 76
+#Slit length panel size
+if sys.platform.count("win32") > 0:
+ PANEL_TOP = 0
+ PANEL_WIDTH = 570
+ PANEL_HEIGHT = 370
+ FONT_VARIANT = 0
+else:
+ PANEL_TOP = 60
+ PANEL_WIDTH = 620
+ PANEL_HEIGHT = 370
+ FONT_VARIANT = 1
+_QMAX_DEFAULT = 0.3
+_NPTS_DEFAULT = 50
+_Q1D_MIN = 0.001
+
+def add_icon(parent, frame):
+ """
+ Add icon in the frame
+ """
+ if parent is not None:
+ if hasattr(frame, "IsIconized"):
+ if not frame.IsIconized():
+ try:
+ icon = parent.GetIcon()
+ frame.SetIcon(icon)
+ except:
+ pass
+
+def _set_error(panel, item, show_msg=False):
+ """
+ Set_error dialog
+ """
+ if item is not None:
+ item.SetBackgroundColour("pink")
+ item.Refresh()
+ if show_msg:
+ msg = "Error: wrong (or out of range) value entered."
+ if panel.parent.parent is not None:
+ wx.PostEvent(panel.parent.parent,
+ StatusEvent(status=msg, info='Error'))
+ panel.SetFocus()
+ return False
+
+
+
+class CalcGen(CalcThread):
+ """
+ Computation
+ """
+ def __init__(self,
+ id= -1,
+ input=None,
+ completefn=None,
+ updatefn=None,
+ #elapsed = 0,
+ yieldtime=0.01,
+ worktime=0.01):
+ """
+ """
+ CalcThread.__init__(self, completefn,
+ updatefn,
+ yieldtime,
+ worktime)
+ self.starttime = 0
+ self.id = id
+ self.input = input
+ self.update_fn = updatefn
+
+ def compute(self):
+ """
+ excuting computation
+ """
+ #elapsed = time.time() - self.starttime
+ self.starttime = time.time()
+ self.complete(input=self.input, update=self.update_fn)
+
+class SasGenPanel(ScrolledPanel, PanelBase):
+ """
+ Provides the sas gen calculator GUI.
+ """
+ ## Internal nickname for the window, used by the AUI manager
+ window_name = "Generic SAS Calculator"
+ ## Name to appear on the window title bar
+ window_caption = "Generic SAS "
+
+ def __init__(self, parent, *args, **kwds):
+ ScrolledPanel.__init__(self, parent, style=wx.RAISED_BORDER,
+ *args, **kwds)
+ #kwds['style'] = wx.SUNKEN_BORDER
+ PanelBase.__init__(self)
+ #Font size
+ self.SetWindowVariant(variant=FONT_VARIANT)
+ self.SetupScrolling()
+ #thread to read data
+ self.reader = None
+ self.ext = None
+ self.id = 'GenSAS'
+ self.file_name = ''
+ self.time_text = None
+ self.orient_combo = None
+ self.omfreader = sas_gen.OMFReader()
+ self.sldreader = sas_gen.SLDReader()
+ self.pdbreader = sas_gen.PDBReader()
+ self.model = sas_gen.GenSAS()
+ self.param_dic = self.model.params
+ self.parameters = []
+ self.data = None
+ self.scale2d = None
+ self.is_avg = False
+ self.plot_frame = None
+ self.qmax_x = _QMAX_DEFAULT
+ self.npts_x = _NPTS_DEFAULT
+ self.sld_data = None
+ self.graph_num = 1
+ self.default_shape = 'rectangular'
+ # Object that receive status event
+ self.parent = parent
+ self._do_layout()
+ self._create_default_sld_data()
+ self._create_default_2d_data()
+ wx.CallAfter(self._set_sld_data_helper)
+
+ def _define_structure(self):
+ """
+ Define the main sizers building to build this application.
+ """
+ self.main_sizer = wx.BoxSizer(wx.VERTICAL)
+ self.box_source = wx.StaticBox(self, -1, str("SLD Data File"))
+ self.box_parameters = wx.StaticBox(self, -1, str("Input Parameters"))
+ self.box_qrange = wx.StaticBox(self, -1, str("Q Range"))
+ self.boxsizer_source = wx.StaticBoxSizer(self.box_source,
+ wx.VERTICAL)
+ self.boxsizer_parameters = wx.StaticBoxSizer(self.box_parameters,
+ wx.VERTICAL)
+ self.boxsizer_qrange = wx.StaticBoxSizer(self.box_qrange,
+ wx.VERTICAL)
+ self.data_name_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.param_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.shape_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.hint_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.qrange_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.button_sizer = wx.BoxSizer(wx.VERTICAL)
+ self.button_sizer1 = wx.BoxSizer(wx.HORIZONTAL)
+ self.button_sizer2 = wx.BoxSizer(wx.HORIZONTAL)
+
+ def _layout_data_name(self):
+ """
+ Fill the sizer containing data's name
+ """
+ data_name_txt = wx.StaticText(self, -1, 'Data: ')
+ self.data_name_tcl = OutputTextCtrl(self, -1,
+ size=(_BOX_WIDTH * 4, -1))
+ data_hint = "Loaded data"
+ self.data_name_tcl.SetToolTipString(data_hint)
+ #control that triggers importing data
+ id = wx.NewId()
+ self.browse_button = wx.Button(self, id, "Load")
+ hint_on_browse = "Click to load data into this panel."
+ self.browse_button.SetToolTipString(hint_on_browse)
+ self.Bind(wx.EVT_BUTTON, self.on_load_data, id=id)
+ self.data_name_sizer.AddMany([(data_name_txt, 0, wx.LEFT, 15),
+ (self.data_name_tcl, 0, wx.LEFT, 10),
+ (self.browse_button, 0, wx.LEFT, 10)])
+ def _layout_param_size(self):
+ """
+ Fill the sizer containing slit size information
+ """
+ self.parameters = []
+ sizer = wx.GridBagSizer(3, 6)
+ model = self.model
+ details = self.model.details
+ params = self.model.params
+ ix = 0
+ iy = 0
+ param_title = wx.StaticText(self, -1, 'Parameter')
+ sizer.Add(param_title, (iy, ix), (1, 1), \
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix += 1
+ value_title = wx.StaticText(self, -1, 'Value')
+ sizer.Add(value_title, (iy, ix), (1, 1), \
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix += 1
+ unit_title = wx.StaticText(self, -1, 'Unit')
+ sizer.Add(unit_title, (iy, ix), (1, 1), \
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ key_list = params.keys()
+ key_list.sort()
+ for param in key_list:
+ iy += 1
+ ix = 0
+ p_name = wx.StaticText(self, -1, param)
+ sizer.Add(p_name, (iy, ix), (1, 1), \
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ## add parameter value
+ ix += 1
+ value = model.getParam(param)
+ ctl = InputTextCtrl(self, -1, size=(_BOX_WIDTH * 2, 20),
+ style=wx.TE_PROCESS_ENTER)
+ #ctl.SetToolTipString(\
+ # "Hit 'Enter' after typing to update the plot.")
+ ctl.SetValue(format_number(value, True))
+ sizer.Add(ctl, (iy, ix), (1, 1), wx.EXPAND)
+ ## add unit
+ ix += 1
+ unit = wx.StaticText(self, -1, details[param][0])
+ sizer.Add(unit, (iy, ix), (1, 1), \
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ self.parameters.append([p_name, ctl, unit])
+
+ self.param_sizer.Add(sizer, 0, wx.LEFT, 10)
+
+ def _layout_hint(self):
+ """
+ Fill the sizer containing hint
+ """
+ hint_msg = "We support omf, sld or pdb data files only."
+ hint_msg += " "
+ if FONT_VARIANT < 1:
+ hint_msg += "Very "
+ hint_msg += "SLOW drawing -->"
+ hint_txt = wx.StaticText(self, -1, hint_msg)
+
+ id = wx.NewId()
+ self.draw_button = wx.Button(self, id, "Arrow Draw")
+ hint_on_draw = "Draw with arrows. Caution: it is a very slow drawing."
+ self.draw_button.SetToolTipString(hint_on_draw)
+ self.draw_button.Bind(wx.EVT_BUTTON, self.sld_draw, id=id)
+
+ self.draw_button.Enable(False)
+ self.hint_sizer.AddMany([(hint_txt, 0, wx.LEFT, 15),
+ (self.draw_button, 0, wx.LEFT, 7)])
+
+ def _layout_shape(self):
+ """
+ Fill the shape sizer
+ """
+ label_txt = wx.StaticText(self, -1, "Shape:")
+ self.shape_combo = self._fill_shape_combo()
+ self.shape_sizer.AddMany([(label_txt, 0, wx.LEFT, 15),
+ (self.shape_combo, 0, wx.LEFT, 5)])
+
+ def _fill_shape_combo(self):
+ """
+ Fill up the shape combo box
+ """
+ shape_combo = wx.ComboBox(self, -1, size=(150, -1),
+ style=wx.CB_READONLY)
+ shape_combo.Append('Rectangular')
+ shape_combo.Append('Ellipsoid')
+ shape_combo.Bind(wx.EVT_COMBOBOX, self._on_shape_select)
+ shape_combo.SetSelection(0)
+ return shape_combo
+
+ def _on_shape_select(self, event):
+ """
+ On selecting a shape
+ """
+ event.Skip()
+ label = event.GetEventObject().GetValue().lower()
+ self.default_shape = label
+ self.parent.set_omfpanel_default_shap(self.default_shape)
+ self.parent.set_omfpanel_npts()
+
+ def _fill_orient_combo(self):
+ """
+ Fill up the orientation combo box: used only for atomic structure
+ """
+ orient_combo = wx.ComboBox(self, -1, size=(150, -1),
+ style=wx.CB_READONLY)
+ orient_combo.Append('Fixed orientation')
+ orient_combo.Append('Debye full avg.')
+ #orient_combo.Append('Debye sph. sym.')
+
+ orient_combo.Bind(wx.EVT_COMBOBOX, self._on_orient_select)
+ orient_combo.SetSelection(0)
+ return orient_combo
+
+ def _on_orient_select(self, event):
+ """
+ On selecting a orientation
+ """
+ event.Skip()
+ cb = event.GetEventObject()
+ if cb.GetCurrentSelection() == 2:
+ self.is_avg = None
+ else:
+ is_avg = cb.GetCurrentSelection() == 1
+ self.is_avg = is_avg
+ self.model.set_is_avg(self.is_avg)
+ self.set_est_time()
+
+ def _layout_qrange(self):
+ """
+ Fill the sizer containing qrange
+ """
+ sizer = wx.GridBagSizer(2, 3)
+ ix = 0
+ iy = 0
+ #key_list.sort()
+ name = wx.StaticText(self, -1, 'No. of Qx (Qy) bins: ')
+ sizer.Add(name, (iy, ix), (1, 1), \
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ## add parameter value
+ ix += 1
+ self.npt_ctl = InputTextCtrl(self, -1, size=(_BOX_WIDTH * 1.5, 20),
+ style=wx.TE_PROCESS_ENTER)
+ self.npt_ctl.Bind(wx.EVT_TEXT, self._onparamEnter)
+ self.npt_ctl.SetValue(format_number(self.npts_x, True))
+ sizer.Add(self.npt_ctl, (iy, ix), (1, 1), wx.EXPAND)
+ ## add unit
+ ix += 1
+ unit = wx.StaticText(self, -1, '')
+ sizer.Add(unit, (iy, ix), (1, 1), \
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ iy += 1
+ ix = 0
+ name = wx.StaticText(self, -1, 'Qx (Qy) Max: ')
+ sizer.Add(name, (iy, ix), (1, 1), \
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ## add parameter value
+ ix += 1
+ self.qmax_ctl = InputTextCtrl(self, -1, size=(_BOX_WIDTH * 1.5, 20),
+ style=wx.TE_PROCESS_ENTER)
+ self.qmax_ctl.Bind(wx.EVT_TEXT, self._onparamEnter)
+ self.qmax_ctl.SetValue(format_number(self.qmax_x, True))
+ sizer.Add(self.qmax_ctl, (iy, ix), (1, 1), wx.EXPAND)
+ ## add unit
+ ix += 1
+ unit = wx.StaticText(self, -1, '[1/A]')
+ sizer.Add(unit, (iy, ix), (1, 1), \
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ self.qrange_sizer.Add(sizer, 0, wx.LEFT, 10)
+
+ def _layout_button(self):
+ """
+ Do the layout for the button widgets
+ """
+ self.est_time = '*Estimated Computation time :\n %s'
+ self.time_text = wx.StaticText(self, -1, self.est_time % str('2 sec'))
+ self.orient_combo = self._fill_orient_combo()
+ self.orient_combo.Show(False)
+
+ self.bt_compute = wx.Button(self, wx.NewId(), 'Compute')
+ self.bt_compute.Bind(wx.EVT_BUTTON, self.on_compute)
+ self.bt_compute.SetToolTipString("Compute 2D Scattering Pattern.")
+
+ self.bt_help = wx.Button(self, wx.NewId(), 'HELP')
+ self.bt_help.Bind(wx.EVT_BUTTON, self.on_help)
+ self.bt_help.SetToolTipString("Help on Scatter Calculator")
+
+ self.bt_close = wx.Button(self, wx.ID_CANCEL, 'Close')
+ self.bt_close.Bind(wx.EVT_BUTTON, self.on_panel_close)
+ self.bt_close.SetToolTipString("Close this window")
+
+ self.button_sizer1.AddMany([(self.bt_compute, 0, wx.LEFT, 20),
+ (self.orient_combo , 0, wx.LEFT, 20)])
+ self.button_sizer2.AddMany([(self.time_text , 0, wx.LEFT, 20),
+ (self.bt_help, 0, wx.LEFT, 20),
+ (self.bt_close, 0, wx.LEFT, 20)])
+ self.button_sizer.AddMany([(self.button_sizer1 , 0, wx.BOTTOM|wx.LEFT, 10),
+ (self.button_sizer2 , 0, wx.LEFT, 10)])
+
+ def estimate_ctime(self):
+ """
+ Calculation time estimation
+ """
+ # magic equation: not very accurate
+ factor = 1
+ n_qbins = float(self.npt_ctl.GetValue())
+ n_qbins *= n_qbins
+ n_pixs = float(self.parent.get_npix())
+ if self.is_avg:
+ factor = 6
+ n_pixs *= (n_pixs / 200)
+ x_in = n_qbins * n_pixs / 100000
+ etime = factor + 0.085973 * x_in
+ return int(etime)
+
+ def set_est_time(self):
+ """
+ Set text for est. computation time
+ """
+ unit = 'sec'
+ if self.time_text is not None:
+ self.time_text.SetForegroundColour('black')
+ etime = self.estimate_ctime()
+ if etime > 60:
+ etime /= 60
+ unit = 'min'
+ self.time_text.SetForegroundColour('red')
+ time_str = str(etime) + ' ' + unit
+ self.time_text.SetLabel(self.est_time % time_str)
+
+ def _do_layout(self):
+ """
+ Draw window content
+ """
+ self._define_structure()
+ self._layout_data_name()
+ self._layout_param_size()
+ self._layout_qrange()
+ self._layout_hint()
+ self._layout_shape()
+ self._layout_button()
+ self.boxsizer_source.AddMany([(self.data_name_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
+ (self.hint_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
+ (self.shape_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
+ self.boxsizer_parameters.AddMany([(self.param_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5), ])
+ self.boxsizer_qrange.AddMany([(self.qrange_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5), ])
+ self.main_sizer.AddMany([(self.boxsizer_source, 0,
+ wx.EXPAND | wx.ALL, 10),
+ (self.boxsizer_parameters, 0,
+ wx.EXPAND | wx.ALL, 10),
+ (self.boxsizer_qrange, 0,
+ wx.EXPAND | wx.ALL, 10),
+ (self.button_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
+ self.SetSizer(self.main_sizer)
+ self.SetAutoLayout(True)
+
+ def _create_default_sld_data(self):
+ """
+ Making default sld-data
+ """
+ sld_n_default = 6.97e-06
+ omfdata = sas_gen.OMFData()
+ omf2sld = sas_gen.OMF2SLD()
+ omf2sld.set_data(omfdata, self.default_shape)
+ self.sld_data = omf2sld.output
+ self.sld_data.is_data = False
+ self.sld_data.filename = "Default SLD Profile"
+ self.sld_data.set_sldn(sld_n_default)
+ self.data_name_tcl.SetValue(self.sld_data.filename)
+
+ def choose_data_file(self, location=None):
+ """
+ Choosing a dtata file
+ """
+ path = None
+ filename = ''
+ if location is None:
+ location = os.getcwd()
+
+ exts = "*" + self.omfreader.ext[0]
+ exts += ", *" + self.sldreader.ext[0]
+ exts += ", *" + self.pdbreader.ext[0]
+ all_type = "All GEN files (%s, %s) | %s" % (exts.upper(), exts.lower(),
+ exts.lower().replace(',', ';'))
+ wildcard = [all_type]
+ omf_type = self.omfreader.type
+ sld_type = self.sldreader.type
+ pdb_type = self.pdbreader.type
+
+ for type in sld_type:
+ wildcard.append(type)
+ for type in omf_type:
+ wildcard.append(type)
+ for type in pdb_type:
+ wildcard.append(type)
+ wildcard = '|'.join(wildcard)
+ dlg = wx.FileDialog(self, "Choose a file", location,
+ "", wildcard, wx.OPEN)
+ if dlg.ShowModal() == wx.ID_OK:
+ path = dlg.GetPath()
+ filename = os.path.basename(path)
+ dlg.Destroy()
+ return path
+
+ def on_load_data(self, event):
+ """
+ Open a file dialog to allow the user to select a given file.
+ The user is only allow to load file with extension .omf, .txt, .sld.
+ Display the slit size corresponding to the loaded data.
+ """
+ location = self.parent.get_path()
+ path = self.choose_data_file(location=location)
+ if path is None:
+ return
+
+ self.shape_sizer.ShowItems(False)
+ self.default_shape = 'rectangular'
+ self.parent.set_omfpanel_default_shap(self.default_shape)
+
+ self.parent.set_file_location(os.path.dirname(path))
+ try:
+ #Load data
+ self.ext = os.path.splitext(path)[-1]
+ if self.ext in self.omfreader.ext:
+ loader = self.omfreader
+ elif self.ext in self.sldreader.ext:
+ loader = self.sldreader
+ elif self.ext in self.pdbreader.ext:
+ loader = self.pdbreader
+ else:
+ loader = None
+ if self.reader is not None and self.reader.isrunning():
+ self.reader.stop()
+ self.browse_button.Enable(False)
+ self.browse_button.SetLabel("Loading...")
+ if self.parent.parent is not None:
+ wx.PostEvent(self.parent.parent,
+ StatusEvent(status="Loading...",
+ type="progress"))
+ self.reader = GenReader(path=path, loader=loader,
+ completefn=self.complete_loading,
+ updatefn=self.load_update)
+ self.reader.queue()
+ #self.load_update()
+ except:
+ self.ext = None
+ if self.parent.parent is None:
+ return
+ msg = "Generic SAS Calculator: %s" % (sys.exc_value)
+ wx.PostEvent(self.parent.parent,
+ StatusEvent(status=msg, type='stop'))
+ self.SetFocus()
+ return
+
+ def load_update(self):
+ """
+ print update on the status bar
+ """
+ if self.parent.parent is None:
+ return
+ if self.reader.isrunning():
+ type = "progress"
+ else:
+ type = "stop"
+ wx.PostEvent(self.parent.parent, StatusEvent(status="",
+ type=type))
+
+ def complete_loading(self, data=None, filename=''):
+ """
+ Complete the loading
+ """
+ #compute the slit size
+ self.browse_button.Enable(True)
+ self.browse_button.SetLabel('Load')
+ try:
+ is_pdbdata = False
+ filename = data.filename
+ self.data_name_tcl.SetValue(str(filename))
+ self.file_name = filename.split('.')[0]
+ self.orient_combo.SetSelection(0)
+ self.is_avg = False
+ if self.ext in self.omfreader.ext:
+ gen = sas_gen.OMF2SLD()
+ gen.set_data(data)
+ #omf_data = data
+ self.sld_data = gen.get_magsld()
+ elif self.ext in self.sldreader.ext:
+ self.sld_data = data
+ elif self.ext in self.pdbreader.ext:
+ self.sld_data = data
+ is_pdbdata = True
+ #omf_data = None
+ else:
+ raise
+ self.orient_combo.Show(is_pdbdata)
+ #self.button_sizer.Layout()
+ self.FitInside()
+ self._set_sld_data_helper(True)
+ except:
+ if self.parent.parent is None:
+ raise
+ msg = "Loading Error: This file format is not supported "
+ msg += "for GenSAS."
+ wx.PostEvent(self.parent.parent,
+ StatusEvent(status=msg, type='stop', info='Error'))
+ self.SetFocus()
+ return
+ if self.parent.parent is None:
+ return
+
+ msg = "Load Complete"
+ wx.PostEvent(self.parent.parent, StatusEvent(status=msg, type='stop'))
+ self.SetFocus()
+
+ def _set_sld_data_helper(self, is_draw=False):
+ """
+ Set sld data helper
+ """
+ #is_avg = self.orient_combo.GetCurrentSelection() == 1
+ self.model.set_is_avg(self.is_avg)
+ self.model.set_sld_data(self.sld_data)
+
+ self.draw_button.Enable(self.sld_data is not None)
+ wx.CallAfter(self.parent.set_sld_data, self.sld_data)
+ self._update_model_params()
+ if is_draw:
+ wx.CallAfter(self.sld_draw, None, False)
+
+ def _update_model_params(self):
+ """
+ Update the model parameter values
+ """
+ for list in self.parameters:
+ param_name = list[0].GetLabelText()
+ val = str(self.model.params[param_name])
+ list[1].SetValue(val)
+
+ def set_volume_ctl_val(self, val):
+ """
+ Set volume txtctrl value
+ """
+ for list in self.parameters:
+ param_name = list[0].GetLabelText()
+ if param_name.lower() == 'total_volume':
+ list[1].SetValue(val)
+ list[1].Refresh()
+ break
+
+ def _onparamEnter(self, event):
+ """
+ On param enter
+ """
+ try:
+ item = event.GetEventObject()
+ self._check_value()
+ item.Refresh()
+ except:
+ pass
+
+ def sld_draw(self, event=None, has_arrow=True):
+ """
+ Draw 3D sld profile
+ """
+ flag = self.parent.check_omfpanel_inputs()
+ if not flag:
+ infor = 'Error'
+ msg = 'Error: Wrong inputs in the SLD info panel.'
+ # inform msg to wx
+ wx.PostEvent(self.parent.parent,
+ StatusEvent(status=msg, info=infor))
+ self.SetFocus()
+ return
+
+ self.sld_data = self.parent.get_sld_from_omf()
+ output = self.sld_data
+ #frame_size = wx.Size(470, 470)
+ self.plot_frame = PlotFrame(self, -1, 'testView')
+ frame = self.plot_frame
+ frame.Show(False)
+ add_icon(self.parent, frame)
+ panel = frame.plotpanel
+ try:
+ # mpl >= 1.0.0
+ ax = panel.figure.gca(projection='3d')
+ except:
+ # mpl < 1.0.0
+ try:
+ from mpl_toolkits.mplot3d import Axes3D
+ ax = Axes3D(panel.figure)
+ except:
+ logger.error("PlotPanel could not import Axes3D")
+ raise
+ panel.dimension = 3
+ graph_title = self._sld_plot_helper(ax, output, has_arrow)
+ # Use y, z axes (in mpl 3d) as z, y axes
+ # that consistent with our SAS detector coords.
+ ax.set_xlabel('x ($\A%s$)' % output.pos_unit)
+ ax.set_ylabel('z ($\A%s$)' % output.pos_unit)
+ ax.set_zlabel('y ($\A%s$)' % output.pos_unit)
+ panel.subplot.figure.subplots_adjust(left=0.05, right=0.95,
+ bottom=0.05, top=0.96)
+ if output.pix_type == 'atom':
+ ax.legend(loc='upper left', prop={'size':10})
+ num_graph = str(self.graph_num)
+ frame.SetTitle('Graph %s: %s' % (num_graph, graph_title))
+ wx.CallAfter(frame.Show, True)
+ self.graph_num += 1
+
+ def _sld_plot_helper(self, ax, output, has_arrow=False):
+ """
+ Actual plot definition happens here
+ :Param ax: axis3d
+ :Param output: sld_data [MagSLD]
+ :Param has_arrow: whether or not draws M vector [bool]
+ """
+ # Set the locals
+ color_dic = {'H':'blue', 'D':'purple', 'N': 'orange',
+ 'O':'red', 'C':'green', 'P':'cyan', 'Other':'k'}
+ marker = ','
+ m_size = 2
+ graph_title = self.file_name
+ graph_title += " 3D SLD Profile "
+ pos_x = output.pos_x
+ pos_y = output.pos_y
+ pos_z = output.pos_z
+ sld_mx = output.sld_mx
+ sld_my = output.sld_my
+ sld_mz = output.sld_mz
+ pix_symbol = output.pix_symbol
+ if output.pix_type == 'atom':
+ marker = 'o'
+ m_size = 3.5
+ sld_tot = (np.fabs(sld_mx) + np.fabs(sld_my) + \
+ np.fabs(sld_mz) + np.fabs(output.sld_n))
+ is_nonzero = sld_tot > 0.0
+ is_zero = sld_tot == 0.0
+ # I. Plot null points
+ if is_zero.any():
+ ax.plot(pos_x[is_zero], pos_z[is_zero], pos_y[is_zero], marker,
+ c="y", alpha=0.5, markeredgecolor='y', markersize=m_size)
+ pos_x = pos_x[is_nonzero]
+ pos_y = pos_y[is_nonzero]
+ pos_z = pos_z[is_nonzero]
+ sld_mx = sld_mx[is_nonzero]
+ sld_my = sld_my[is_nonzero]
+ sld_mz = sld_mz[is_nonzero]
+ pix_symbol = output.pix_symbol[is_nonzero]
+ # II. Plot selective points in color
+ other_color = np.ones(len(pix_symbol), dtype='bool')
+ for key in color_dic.keys():
+ chosen_color = pix_symbol == key
+ if np.any(chosen_color):
+ other_color = other_color & (chosen_color != True)
+ color = color_dic[key]
+ ax.plot(pos_x[chosen_color], pos_z[chosen_color],
+ pos_y[chosen_color], marker, c=color, alpha=0.5,
+ markeredgecolor=color, markersize=m_size, label=key)
+ # III. Plot All others
+ if np.any(other_color):
+ a_name = ''
+ if output.pix_type == 'atom':
+ # Get atom names not in the list
+ a_names = [symb for symb in pix_symbol \
+ if symb not in color_dic.keys()]
+ a_name = a_names[0]
+ for name in a_names:
+ new_name = ", " + name
+ if a_name.count(name) == 0:
+ a_name += new_name
+ # plot in black
+ ax.plot(pos_x[other_color], pos_z[other_color], pos_y[other_color],
+ marker, c="k", alpha=0.5, markeredgecolor="k",
+ markersize=m_size, label=a_name)
+ # IV. Draws atomic bond with grey lines if any
+ if output.has_conect:
+ for ind in range(len(output.line_x)):
+ ax.plot(output.line_x[ind], output.line_z[ind],
+ output.line_y[ind], '-', lw=0.6, c="grey", alpha=0.3)
+ # V. Draws magnetic vectors
+ if has_arrow and len(pos_x) > 0:
+ graph_title += " - Magnetic Vector as Arrow -"
+ panel = self.plot_frame.plotpanel
+ def _draw_arrow(input=None, update=None):
+ """
+ draw magnetic vectors w/arrow
+ """
+ max_mx = max(np.fabs(sld_mx))
+ max_my = max(np.fabs(sld_my))
+ max_mz = max(np.fabs(sld_mz))
+ max_m = max(max_mx, max_my, max_mz)
+ try:
+ max_step = max(output.xstepsize, output.ystepsize,
+ output.zstepsize)
+ except:
+ max_step = 0
+ if max_step <= 0:
+ max_step = 5
+ try:
+ if max_m != 0:
+ unit_x2 = sld_mx / max_m
+ unit_y2 = sld_my / max_m
+ unit_z2 = sld_mz / max_m
+ # 0.8 is for avoiding the color becomes white=(1,1,1))
+ color_x = np.fabs(unit_x2 * 0.8)
+ color_y = np.fabs(unit_y2 * 0.8)
+ color_z = np.fabs(unit_z2 * 0.8)
+ x2 = pos_x + unit_x2 * max_step
+ y2 = pos_y + unit_y2 * max_step
+ z2 = pos_z + unit_z2 * max_step
+ x_arrow = np.column_stack((pos_x, x2))
+ y_arrow = np.column_stack((pos_y, y2))
+ z_arrow = np.column_stack((pos_z, z2))
+ colors = np.column_stack((color_x, color_y, color_z))
+ arrows = Arrow3D(panel, x_arrow, z_arrow, y_arrow,
+ colors, mutation_scale=10, lw=1,
+ arrowstyle="->", alpha=0.5)
+ ax.add_artist(arrows)
+ except:
+ pass
+ msg = "Arrow Drawing completed.\n"
+ status_type = 'stop'
+ self._status_info(msg, status_type)
+ msg = "Arrow Drawing is in progress..."
+ status_type = 'progress'
+ self._status_info(msg, status_type)
+ draw_out = CalcGen(input=ax,
+ completefn=_draw_arrow, updatefn=self._update)
+ draw_out.queue()
+ return graph_title
+
+ def set_input_params(self):
+ """
+ Set model parameters
+ """
+ for list in self.parameters:
+ param_name = list[0].GetLabelText()
+ param_value = float(list[1].GetValue())
+ self.model.setParam(param_name, param_value)
+
+ def on_compute(self, event):
+ """
+ Compute I(qx, qy)
+ """
+ flag = self.parent.check_omfpanel_inputs()
+ if not flag and self.parent.parent is not None:
+ infor = 'Error'
+ msg = 'Error: Wrong inputs in the SLD info panel.'
+ # inform msg to wx
+ wx.PostEvent(self.parent.parent,
+ StatusEvent(status=msg, info=infor))
+ self.SetFocus()
+ return
+ self.sld_data = self.parent.get_sld_from_omf()
+ if self.sld_data is None:
+ if self.parent.parent is not None:
+ infor = 'Error'
+ msg = 'Error: No data has been selected.'
+ # inform msg to wx
+ wx.PostEvent(self.parent.parent,
+ StatusEvent(status=msg, info=infor))
+ self.SetFocus()
+ return
+ flag = self._check_value()
+ if not flag:
+ _set_error(self, None, True)
+ return
+ try:
+ self.model.set_sld_data(self.sld_data)
+ self.set_input_params()
+ if self.is_avg or self.is_avg is None:
+ self._create_default_1d_data()
+ i_out = np.zeros(len(self.data.y))
+ inputs = [self.data.x, [], i_out]
+ else:
+ self._create_default_2d_data()
+ i_out = np.zeros(len(self.data.data))
+ inputs = [self.data.qx_data, self.data.qy_data, i_out]
+
+ msg = "Computation is in progress..."
+ status_type = 'progress'
+ self._status_info(msg, status_type)
+ cal_out = CalcGen(input=inputs,
+ completefn=self.complete,
+ updatefn=self._update)
+ cal_out.queue()
+
+ except:
+ msg = "%s." % sys.exc_value
+ status_type = 'stop'
+ self._status_info(msg, status_type)
+ wx.PostEvent(self.parent.parent,
+ StatusEvent(status=msg, info='Error'))
+ self.SetFocus()
+
+ def on_help(self, event):
+ """
+ Bring up the General scattering Calculator Documentation whenever
+ the HELP button is clicked.
+
+ Calls DocumentationWindow with the path of the location within the
+ documentation tree (after /doc/ ....". Note that when using old
+ versions of Wx (before 2.9) and thus not the release version of
+ installers, the help comes up at the top level of the file as
+ webbrowser does not pass anything past the # to the browser when it is
+ running "file:///...."
+
+ :param evt: Triggers on clicking the help button
+ """
+
+ _TreeLocation = "user/sasgui/perspectives/calculator/"
+ _TreeLocation += "sas_calculator_help.html"
+ _doc_viewer = DocumentationWindow(self, -1, _TreeLocation, "",
+ "General Scattering Calculator Help")
+
+ def _check_value(self):
+ """
+ Check input values if float
+ """
+ flag = True
+ self.npt_ctl.SetBackgroundColour("white")
+ self.qmax_ctl.SetBackgroundColour("white")
+ try:
+ npt_val = float(self.npt_ctl.GetValue())
+ if npt_val < 2 or npt_val > 1000:
+ raise
+ self.npt_ctl.SetValue(str(int(npt_val)))
+ self.set_est_time()
+ except:
+ flag = _set_error(self, self.npt_ctl)
+ try:
+ qmax_val = float(self.qmax_ctl.GetValue())
+ if qmax_val <= 0 or qmax_val > 1000:
+ raise
+ except:
+ flag = _set_error(self, self.qmax_ctl)
+ for list in self.parameters:
+ list[1].SetBackgroundColour("white")
+ param_name = list[0].GetLabelText()
+ try:
+ param_val = float(list[1].GetValue())
+ if param_name.count('frac') > 0:
+ if param_val < 0 or param_val > 1:
+ raise
+ except:
+ flag = _set_error(self, list[1])
+ return flag
+
+ def _status_info(self, msg='', type="update"):
+ """
+ Status msg
+ """
+ if type == "stop":
+ label = "Compute"
+ able = True
+ else:
+ label = "Wait..."
+ able = False
+ self.bt_compute.Enable(able)
+ self.bt_compute.SetLabel(label)
+ self.bt_compute.SetToolTipString(label)
+ if self.parent.parent is not None:
+ wx.PostEvent(self.parent.parent,
+ StatusEvent(status=msg, type=type))
+
+ def _update(self, time=None):
+ """
+ Update the progress bar
+ """
+ if self.parent.parent is None:
+ return
+ type = "progress"
+ msg = "Please wait. Computing... (Note: Window may look frozen.)"
+ wx.PostEvent(self.parent.parent, StatusEvent(status=msg,
+ type=type))
+
+ def complete(self, input, update=None):
+ """
+ Gen compute complete function
+ :Param input: input list [qx_data, qy_data, i_out]
+ """
+ out = np.empty(0)
+ #s = time.time()
+ for ind in range(len(input[0])):
+ if self.is_avg:
+ if ind % 1 == 0 and update is not None:
+ update()
+ time.sleep(0.1)
+ inputi = [input[0][ind:ind + 1], [], input[2][ind:ind + 1]]
+ outi = self.model.run(inputi)
+ out = np.append(out, outi)
+ else:
+ if ind % 50 == 0 and update is not None:
+ update()
+ time.sleep(0.001)
+ inputi = [input[0][ind:ind + 1], input[1][ind:ind + 1],
+ input[2][ind:ind + 1]]
+ outi = self.model.runXY(inputi)
+ out = np.append(out, outi)
+ #print time.time() - s
+ if self.is_avg or self.is_avg is None:
+ self._draw1D(out)
+ else:
+ #out = self.model.runXY(input)
+ self._draw2D(out)
+
+ msg = "Gen computation completed.\n"
+ status_type = 'stop'
+ self._status_info(msg, status_type)
+
+ def _create_default_2d_data(self):
+ """
+ Create 2D data by default
+ Only when the page is on theory mode.
+ :warning: This data is never plotted.
+ """
+ self.qmax_x = float(self.qmax_ctl.GetValue())
+ self.npts_x = int(float(self.npt_ctl.GetValue()))
+ self.data = Data2D()
+ qmax = self.qmax_x #/ np.sqrt(2)
+ self.data.xaxis('\\rm{Q_{x}}', '\AA^{-1}')
+ self.data.yaxis('\\rm{Q_{y}}', '\AA^{-1}')
+ self.data.is_data = False
+ self.data.id = str(self.uid) + " GenData"
+ self.data.group_id = str(self.uid) + " Model2D"
+ ## Default values
+ self.data.detector.append(Detector())
+ index = len(self.data.detector) - 1
+ self.data.detector[index].distance = 8000 # mm
+ self.data.source.wavelength = 6 # A
+ self.data.detector[index].pixel_size.x = 5 # mm
+ self.data.detector[index].pixel_size.y = 5 # mm
+ self.data.detector[index].beam_center.x = qmax
+ self.data.detector[index].beam_center.y = qmax
+ xmax = qmax
+ xmin = -qmax
+ ymax = qmax
+ ymin = -qmax
+ qstep = self.npts_x
+
+ x = np.linspace(start=xmin, stop=xmax, num=qstep, endpoint=True)
+ y = np.linspace(start=ymin, stop=ymax, num=qstep, endpoint=True)
+ ## use data info instead
+ new_x = np.tile(x, (len(y), 1))
+ new_y = np.tile(y, (len(x), 1))
+ new_y = new_y.swapaxes(0, 1)
+ # all data reuire now in 1d array
+ qx_data = new_x.flatten()
+ qy_data = new_y.flatten()
+ q_data = np.sqrt(qx_data * qx_data + qy_data * qy_data)
+ # set all True (standing for unmasked) as default
+ mask = np.ones(len(qx_data), dtype=bool)
+ # store x and y bin centers in q space
+ x_bins = x
+ y_bins = y
+ self.data.source = Source()
+ self.data.data = np.ones(len(mask))
+ self.data.err_data = np.ones(len(mask))
+ self.data.qx_data = qx_data
+ self.data.qy_data = qy_data
+ self.data.q_data = q_data
+ self.data.mask = mask
+ self.data.x_bins = x_bins
+ self.data.y_bins = y_bins
+ # max and min taking account of the bin sizes
+ self.data.xmin = xmin
+ self.data.xmax = xmax
+ self.data.ymin = ymin
+ self.data.ymax = ymax
+
+ def _create_default_1d_data(self):
+ """
+ Create 2D data by default
+ Only when the page is on theory mode.
+ :warning: This data is never plotted.
+ residuals.x = data_copy.x[index]
+ residuals.dy = np.ones(len(residuals.y))
+ residuals.dx = None
+ residuals.dxl = None
+ residuals.dxw = None
+ """
+ self.qmax_x = float(self.qmax_ctl.GetValue())
+ self.npts_x = int(float(self.npt_ctl.GetValue()))
+ qmax = self.qmax_x #/ np.sqrt(2)
+ ## Default values
+ xmax = qmax
+ xmin = qmax * _Q1D_MIN
+ qstep = self.npts_x
+ x = np.linspace(start=xmin, stop=xmax, num=qstep, endpoint=True)
+ # store x and y bin centers in q space
+ #self.data.source = Source()
+ y = np.ones(len(x))
+ dy = np.zeros(len(x))
+ dx = np.zeros(len(x))
+ self.data = Data1D(x=x, y=y)
+ self.data.dx = dx
+ self.data.dy = dy
+
+ def _draw1D(self, y_out):
+ """
+ Complete get the result of modelthread and create model 2D
+ that can be plot.
+ """
+ page_id = self.id
+ data = self.data
+
+ model = self.model
+ state = None
+
+ new_plot = Data1D(x=data.x, y=y_out)
+ new_plot.dx = data.dx
+ new_plot.dy = data.dy
+ new_plot.xaxis('\\rm{Q_{x}}', '\AA^{-1}')
+ new_plot.yaxis('\\rm{Intensity}', 'cm^{-1}')
+ new_plot.is_data = False
+ new_plot.id = str(self.uid) + " GenData1D"
+ new_plot.group_id = str(self.uid) + " Model1D"
+ new_plot.name = model.name + '1d'
+ new_plot.title = "Generic model1D "
+ new_plot.id = str(page_id) + ': ' + self.file_name \
+ + ' #%s' % str(self.graph_num) + "_1D"
+ new_plot.group_id = str(page_id) + " Model1D" + \
+ ' #%s' % str(self.graph_num) + "_1D"
+ new_plot.is_data = False
+
+ title = new_plot.title
+ _yaxis, _yunit = new_plot.get_yaxis()
+ _xaxis, _xunit = new_plot.get_xaxis()
+ new_plot.xaxis(str(_xaxis), str(_xunit))
+ new_plot.yaxis(str(_yaxis), str(_yunit))
+
+ if new_plot.is_data:
+ data_name = str(new_plot.name)
+ else:
+ data_name = str(model.__class__.__name__) + '1d'
+
+ if len(title) > 1:
+ new_plot.title = "Gen Theory for %s " % model.name + data_name
+ new_plot.name = new_plot.id
+ new_plot.label = new_plot.id
+ #theory_data = deepcopy(new_plot)
+ if self.parent.parent is not None:
+ self.parent.parent.update_theory(data_id=new_plot.id,
+ theory=new_plot,
+ state=state)
+ title = new_plot.title
+ num_graph = str(self.graph_num)
+ wx.CallAfter(self.parent.draw_graph, new_plot,
+ title="GEN Graph %s: " % num_graph + new_plot.id)
+ self.graph_num += 1
+
+ def _draw2D(self, image):
+ """
+ Complete get the result of modelthread and create model 2D
+ that can be plot.
+ """
+ page_id = self.id
+ data = self.data
+
+ model = self.model
+ qmin = 0.0
+ state = None
+
+ np.nan_to_num(image)
+ new_plot = Data2D(image=image, err_image=data.err_data)
+ new_plot.name = model.name + '2d'
+ new_plot.title = "Generic model 2D "
+ new_plot.id = str(page_id) + ': ' + self.file_name \
+ + ' #%s' % str(self.graph_num) + "_2D"
+ new_plot.group_id = str(page_id) + " Model2D" \
+ + ' #%s' % str(self.graph_num) + "_2D"
+ new_plot.detector = data.detector
+ new_plot.source = data.source
+ new_plot.is_data = False
+ new_plot.qx_data = data.qx_data
+ new_plot.qy_data = data.qy_data
+ new_plot.q_data = data.q_data
+ new_plot.mask = data.mask
+ ## plot boundaries
+ new_plot.ymin = data.ymin
+ new_plot.ymax = data.ymax
+ new_plot.xmin = data.xmin
+ new_plot.xmax = data.xmax
+ title = data.title
+ _yaxis, _yunit = data.get_yaxis()
+ _xaxis, _xunit = data.get_xaxis()
+ new_plot.xaxis(str(_xaxis), str(_xunit))
+ new_plot.yaxis(str(_yaxis), str(_yunit))
+
+ new_plot.is_data = False
+ if data.is_data:
+ data_name = str(data.name)
+ else:
+ data_name = str(model.__class__.__name__) + '2d'
+
+ if len(title) > 1:
+ new_plot.title = "Gen Theory for %s " % model.name + data_name
+ new_plot.name = new_plot.id
+ new_plot.label = new_plot.id
+ #theory_data = deepcopy(new_plot)
+ if self.parent.parent is not None:
+ self.parent.parent.update_theory(data_id=data.id,
+ theory=new_plot,
+ state=state)
+ title = new_plot.title
+ num_graph = str(self.graph_num)
+ wx.CallAfter(self.parent.draw_graph, new_plot,
+ title="GEN Graph %s: " % num_graph + new_plot.id)
+ self.graph_num += 1
+
+ def set_scale2d(self, scale):
+ """
+ Set SLD plot scale
+ """
+ self.scale2d = None
+
+ def on_panel_close(self, event):
+ """
+ close the window containing this panel
+ """
+ self.parent.Close()
+
+class OmfPanel(ScrolledPanel, PanelBase):
+ """
+ Provides the sas gen calculator GUI.
+ """
+ ## Internal nickname for the window, used by the AUI manager
+ window_name = "SLD Pixel Info"
+ ## Name to appear on the window title bar
+ window_caption = "SLD Pixel Info "
+
+ def __init__(self, parent, *args, **kwds):
+ ScrolledPanel.__init__(self, parent, style=wx.RAISED_BORDER,
+ *args, **kwds)
+ PanelBase.__init__(self)
+ #Font size
+ self.SetWindowVariant(variant=FONT_VARIANT)
+ self.SetupScrolling()
+ # Object that receive status event
+ self.parent = parent
+ self.sld_data = sas_gen.MagSLD([0], [0], [0])
+ self.sld_ctl = None
+ self.default_shape = 'rectangular'
+ self._do_layout()
+
+ def set_slddata(self, slddata):
+ """
+ Set sld data related items
+ """
+ self.sld_data = slddata
+ self._set_slddata_ctr_val(slddata)
+ # Make sure that self._set_slddata_ctr_val() is finished
+ wx.CallAfter(self._set_omfdata_ctr, slddata)
+
+ def get_sld_val(self):
+ """
+ Set sld_n of slddata on sld input
+ """
+ sld_sets = {}
+ if not self.sld_data.is_data:
+ self._get_other_val()
+ for list in self.slds:
+ if list[1].IsEnabled():
+ list[1].SetBackgroundColour("white")
+ list[1].Refresh()
+ try:
+ val = float(list[1].GetValue())
+ sld_sets[list[0]] = val
+ except:
+ flag = _set_error(self, list[1])
+ if not flag:
+ return self.sld_data
+ else:
+ sld_sets[list[0]] = None
+ for key in sld_sets.keys():
+ key_low = key.lower()
+ if key_low.count('mx') > 0:
+ if sld_sets[key] is None:
+ sld_sets[key] = self.sld_data.sld_mx
+ mx = sld_sets[key]
+ elif key_low.count('my') > 0:
+ if sld_sets[key] is None:
+ sld_sets[key] = self.sld_data.sld_my
+ my = sld_sets[key]
+ elif key_low.count('mz') > 0:
+ if sld_sets[key] is None:
+ sld_sets[key] = self.sld_data.sld_mz
+ mz = sld_sets[key]
+ else:
+ if sld_sets[key] is not None:
+ self.sld_data.set_sldn(sld_sets[key])
+ self.sld_data.set_sldms(mx, my, mz)
+ self._set_slddata_ctr_val(self.sld_data)
+
+ return self.sld_data
+
+ def get_pix_volumes(self):
+ """
+ Get the pixel volume
+ """
+ vol = self.sld_data.vol_pix
+
+ return vol
+
+ def _get_other_val(self):
+ """
+ """
+ omfdata = sas_gen.OMFData()
+ sets = {}
+ try:
+ for lst in self.stepsize:
+ if lst[1].IsEnabled():
+ val = float(lst[1].GetValue())
+ sets[lst[0]] = val
+ else:
+ sets[lst[0]] = None
+ return
+ for lst in self.nodes:
+ if lst[1].IsEnabled():
+ val = float(lst[1].GetValue())
+ sets[lst[0]] = val
+ else:
+ sets[lst[0]] = None
+ return
+
+ for key in sets.keys():
+ setattr(omfdata, key, sets[key])
+
+ omf2sld = sas_gen.OMF2SLD()
+ omf2sld.set_data(omfdata, self.default_shape)
+ self.sld_data = omf2sld.output
+ self.sld_data.is_data = False
+ self.sld_data.filename = "Default SLD Profile"
+ except:
+ msg = "OMF Panel: %s" % sys.exc_value
+ infor = 'Error'
+ #logger.error(msg)
+ if self.parent.parent is not None:
+ # inform msg to wx
+ wx.PostEvent(self.parent.parent,
+ StatusEvent(status=msg, info=infor))
+ self.SetFocus()
+
+ def _set_slddata_ctr_val(self, slddata):
+ """
+ Set slddata crl
+ """
+ try:
+ val = str(len(slddata.sld_n))
+ except:
+ val = 'Unknown'
+ self.npix_ctl.SetValue(val)
+
+ def _set_omfdata_ctr(self, omfdata):
+ """
+ Set the textctr box values
+ """
+
+ if omfdata is None:
+ self._set_none_text()
+ return
+ nodes_list = self._get_nodes_key_list(omfdata)
+ step_list = self._get_step_key_list(omfdata)
+ for ctr_list in self.nodes:
+ for key in nodes_list.keys():
+ if ctr_list[0] == key:
+ ctr_list[1].SetValue(format_number(nodes_list[key], True))
+ ctr_list[1].Enable(not omfdata.is_data)
+ break
+ for ctr_list in self.stepsize:
+ for key in step_list.keys():
+ if ctr_list[0] == key:
+ ctr_list[1].SetValue(format_number(step_list[key], True))
+ ctr_list[1].Enable(not omfdata.is_data)
+ break
+
+ def _set_none_text(self):
+ """
+ Set Unknown in textctrls
+ """
+ val = 'Unknown'
+ for ctr_list in self.nodes:
+ ctr_list[1].SetValue(val)
+ for ctr_list in self.stepsize:
+ ctr_list[1].SetValue(val)
+
+ def _define_structure(self):
+ """
+ Define the main sizers building to build this application.
+ """
+ self.main_sizer = wx.BoxSizer(wx.VERTICAL)
+
+ self.npixels_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.box_sld = wx.StaticBox(self, -1,
+ str("Mean SLD"))
+ self.box_node = wx.StaticBox(self, -1, str("Nodes"))
+ self.boxsizer_sld = wx.StaticBoxSizer(self.box_sld, wx.VERTICAL)
+ self.box_stepsize = wx.StaticBox(self, -1, str("Step Size"))
+ self.boxsizer_node = wx.StaticBoxSizer(self.box_node, wx.VERTICAL)
+ self.boxsizer_stepsize = wx.StaticBoxSizer(self.box_stepsize,
+ wx.VERTICAL)
+ self.sld_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.node_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.step_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.hint_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.button_sizer = wx.BoxSizer(wx.HORIZONTAL)
+
+ def _layout_npix(self):
+ """
+ Build No of pixels sizer
+ """
+ num_pix_text = wx.StaticText(self, -1, "No. of Pixels: ")
+ self.npix_ctl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH, 20),
+ style=wx.TE_PROCESS_ENTER)
+ self._set_slddata_ctr_val(self.sld_data)
+ self._set_omfdata_ctr(self.sld_data)
+ self.npixels_sizer.AddMany([(num_pix_text, 0,
+ wx.EXPAND | wx.LEFT | wx.TOP, 5),
+ (self.npix_ctl, 0,
+ wx.EXPAND | wx.TOP, 5)])
+
+ def _layout_slds(self):
+ """
+ Build nuclear sld sizer
+ """
+ self.slds = []
+ omfdata = self.sld_data
+ if omfdata is None:
+ raise
+ sld_key_list = self._get_slds_key_list(omfdata)
+ # Dic is not sorted
+ key_list = [key for key in sld_key_list.keys()]
+ # Sort here
+ key_list.sort()
+ is_data = self.sld_data.is_data
+ sizer = wx.GridBagSizer(2, 3)
+ ix = 0
+ iy = -1
+ for key in key_list:
+ value = sld_key_list[key]
+ iy += 1
+ ix = 0
+ name = wx.StaticText(self, -1, key)
+ sizer.Add(name, (iy, ix), (1, 1), \
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ## add parameter value
+ ix += 1
+ ctl = InputTextCtrl(self, -1, size=(_BOX_WIDTH, 20),
+ style=wx.TE_PROCESS_ENTER)
+ ctl.SetValue(format_number(value, True))
+ ctl.Enable(not is_data)
+ sizer.Add(ctl, (iy, ix), (1, 1), wx.EXPAND)
+ ## add unit
+ ix += 1
+ s_unit = '[' + omfdata.sld_unit + ']'
+ unit = wx.StaticText(self, -1, s_unit)
+ sizer.Add(unit, (iy, ix), (1, 1), \
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ self.slds.append([key, ctl, unit])
+ self.sld_sizer.Add(sizer, 0, wx.LEFT, 10)
+
+ def _layout_nodes(self):
+ """
+ Fill the sizer containing data's name
+ """
+ self.nodes = []
+ omfdata = self.sld_data
+ if omfdata is None:
+ raise
+ key_list = self._get_nodes_key_list(omfdata)
+ is_data = self.sld_data.is_data
+ sizer = wx.GridBagSizer(2, 3)
+ ix = 0
+ iy = -1
+ for key, value in key_list.iteritems():
+ iy += 1
+ ix = 0
+ name = wx.StaticText(self, -1, key)
+ sizer.Add(name, (iy, ix), (1, 1), \
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ## add parameter value
+ ix += 1
+ ctl = InputTextCtrl(self, -1, size=(_BOX_WIDTH, 20),
+ style=wx.TE_PROCESS_ENTER)
+ ctl.Bind(wx.EVT_TEXT, self._onparamEnter)
+ ctl.SetValue(format_number(value, True))
+ ctl.Enable(not is_data)
+ sizer.Add(ctl, (iy, ix), (1, 1), wx.EXPAND)
+ ## add unit
+ ix += 1
+ unit = wx.StaticText(self, -1, '')
+ sizer.Add(unit, (iy, ix), (1, 1), \
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ self.nodes.append([key, ctl, unit])
+ self.node_sizer.Add(sizer, 0, wx.LEFT, 10)
+
+ def _layout_stepsize(self):
+ """
+ Fill the sizer containing slit size information
+ """
+ self.stepsize = []
+ omfdata = self.sld_data
+ if omfdata is None:
+ raise
+ key_list = self._get_step_key_list(omfdata)
+ is_data = self.sld_data.is_data
+ sizer = wx.GridBagSizer(2, 3)
+ ix = 0
+ iy = -1
+ #key_list.sort()
+ for key, value in key_list.iteritems():
+ iy += 1
+ ix = 0
+ name = wx.StaticText(self, -1, key)
+ sizer.Add(name, (iy, ix), (1, 1), \
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ## add parameter value
+ ix += 1
+ ctl = InputTextCtrl(self, -1, size=(_BOX_WIDTH, 20),
+ style=wx.TE_PROCESS_ENTER)
+ ctl.Bind(wx.EVT_TEXT, self._onstepsize)
+ ctl.SetValue(format_number(value, True))
+ ctl.Enable(not is_data)
+ sizer.Add(ctl, (iy, ix), (1, 1), wx.EXPAND)
+ ## add unit
+ ix += 1
+ p_unit = '[' + omfdata.pos_unit + ']'
+ unit = wx.StaticText(self, -1, p_unit)
+ sizer.Add(unit, (iy, ix), (1, 1), \
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ self.stepsize.append([key, ctl, unit])
+ self.step_sizer.Add(sizer, 0, wx.LEFT, 10)
+
+ def _layout_hint(self):
+ """
+ Fill the sizer containing hint
+ """
+ hint_msg = "Load an omf or 3d sld profile data file."
+ self.hint_txt = wx.StaticText(self, -1, hint_msg)
+ self.hint_sizer.AddMany([(self.hint_txt, 0, wx.LEFT, 15)])
+
+ def _layout_button(self):
+ """
+ Do the layout for the button widgets
+ """
+ self.bt_draw = wx.Button(self, wx.NewId(), 'Draw Points')
+ self.bt_draw.Bind(wx.EVT_BUTTON, self.on_sld_draw)
+ self.bt_draw.SetToolTipString("Draw a scatter plot for sld profile.")
+ self.bt_save = wx.Button(self, wx.NewId(), 'Save SLD Data')
+ self.bt_save.Bind(wx.EVT_BUTTON, self.on_save)
+ self.bt_save.Enable(False)
+ self.bt_save.SetToolTipString("Save SLD data.")
+ self.button_sizer.AddMany([(self.bt_draw, 0, wx.LEFT, 10),
+ (self.bt_save, 0, wx.LEFT, 10)])
+
+ def _do_layout(self):
+ """
+ Draw omf panel content, used to define sld s.
+
+ """
+ self._define_structure()
+ self._layout_nodes()
+ self._layout_stepsize()
+ self._layout_npix()
+ self._layout_slds()
+ #self._layout_hint()
+ self._layout_button()
+ self.boxsizer_node.AddMany([(self.node_sizer, 0,
+ wx.EXPAND | wx.TOP, 5),
+ (self.hint_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
+ self.boxsizer_stepsize.AddMany([(self.step_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5), ])
+ self.boxsizer_sld.AddMany([(self.sld_sizer, 0,
+ wx.EXPAND | wx.BOTTOM, 5), ])
+ self.main_sizer.AddMany([(self.npixels_sizer, 0, wx.EXPAND | wx.ALL, 10),
+ (self.boxsizer_sld, 0, wx.EXPAND | wx.ALL, 10),
+ (self.boxsizer_node, 0, wx.EXPAND | wx.ALL, 10),
+ (self.boxsizer_stepsize, 0, wx.EXPAND | wx.ALL, 10),
+ (self.button_sizer, 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
+ self.SetSizer(self.main_sizer)
+ self.SetAutoLayout(True)
+
+ def _get_nodes_key_list(self, data):
+ """
+ Return nodes key list
+
+ :Param data: OMFData
+ """
+ key_list = {'xnodes' : data.xnodes,
+ 'ynodes' : data.ynodes,
+ 'znodes' : data.znodes}
+ return key_list
+
+ def _get_slds_key_list(self, data):
+ """
+ Return nodes key list
+
+ :Param data: OMFData
+ """
+ key_list = {'Nucl.' : data.sld_n,
+ 'Mx' : data.sld_mx,
+ 'My' : data.sld_my,
+ 'Mz' : data.sld_mz}
+ return key_list
+
+ def _get_step_key_list(self, data):
+ """
+ Return step key list
+
+ :Param data: OMFData
+ """
+ key_list = {'xstepsize' : data.xstepsize,
+ 'ystepsize' : data.ystepsize,
+ 'zstepsize' : data.zstepsize}
+ return key_list
+
+ def set_sld_ctr(self, sld_data):
+ """
+ Set sld textctrls
+ """
+ if sld_data is None:
+ for ctr_list in self.slds:
+ ctr_list[1].Enable(False)
+ #break
+ return
+
+ self.sld_data = sld_data
+ sld_list = self._get_slds_key_list(sld_data)
+ for ctr_list in self.slds:
+ for key in sld_list.keys():
+ if ctr_list[0] == key:
+ min_val = np.min(sld_list[key])
+ max_val = np.max(sld_list[key])
+ mean_val = np.mean(sld_list[key])
+ enable = (min_val == max_val) and \
+ sld_data.pix_type == 'pixel'
+ ctr_list[1].SetValue(format_number(mean_val, True))
+ ctr_list[1].Enable(enable)
+ #ctr_list[2].SetLabel("[" + sld_data.sld_unit + "]")
+ break
+
+ def on_sld_draw(self, event):
+ """
+ Draw sld profile as scattered plot
+ """
+ self.parent.sld_draw()
+
+ def on_save(self, event):
+ """
+ Close the window containing this panel
+ """
+ flag = True
+ flag = self.check_inputs()
+ if not flag:
+ return
+ self.sld_data = self.get_sld_val()
+ self.parent.set_main_panel_sld_data(self.sld_data)
+
+ reader = sas_gen.SLDReader()
+ extension = '*.sld'
+ path = None
+ data = None
+ location = self.parent.get_path()
+ dlg = wx.FileDialog(self, "Save sld file",
+ location, "sld_file",
+ extension,
+ wx.SAVE)
+ if dlg.ShowModal() == wx.ID_OK:
+ path = dlg.GetPath()
+ self.parent.set_file_location(os.path.dirname(path))
+ else:
+ return None
+ dlg.Destroy()
+ try:
+ if path is None:
+ return
+
+ data = self.parent.get_sld_data()
+ fName = os.path.splitext(path)[0] + '.' + extension.split('.')[-1]
+ if data is not None:
+ try:
+ reader.write(fName, data)
+ except:
+ raise
+ else:
+ msg = "%s cannot write %s\n" % ('Generic Scattering', str(path))
+ infor = 'Error'
+ #logger.error(msg)
+ if self.parent.parent is not None:
+ # inform msg to wx
+ wx.PostEvent(self.parent.parent,
+ StatusEvent(status=msg, info=infor))
+ self.SetFocus()
+ return
+ except:
+ msg = "Error occurred while saving. "
+ infor = 'Error'
+ if self.parent.parent is not None:
+ # inform msg to wx
+ wx.PostEvent(self.parent.parent,
+ StatusEvent(status=msg, info=infor))
+ self.SetFocus()
+
+ def _onparamEnter(self, event):
+ """
+ """
+ flag = True
+ if event is not None:
+ event.Skip()
+ ctl = event.GetEventObject()
+ ctl.SetBackgroundColour("white")
+ #_set_error(self, ctl)
+ try:
+ float(ctl.GetValue())
+ except:
+ flag = _set_error(self, ctl)
+ if flag:
+ npts = 1
+ for item in self.nodes:
+ n_val = float(item[1].GetValue())
+ if n_val <= 0:
+ item[1].SetBackgroundColour("pink")
+ npts = -1
+ break
+ if np.isfinite(n_val):
+ npts *= int(n_val)
+ if npts > 0:
+ nop = self.set_npts_from_slddata()
+ if nop is None:
+ nop = npts
+ self.display_npts(nop)
+
+ ctl.Refresh()
+ return flag
+
+ def _set_volume_ctr_val(self, npts):
+ """
+ Set total volume
+ """
+ total_volume = npts * self.sld_data.vol_pix[0]
+ self.parent.set_volume_ctr_val(total_volume)
+
+ def _onstepsize(self, event):
+ """
+ On stepsize event
+ """
+ flag = True
+ if event is not None:
+ event.Skip()
+ ctl = event.GetEventObject()
+ ctl.SetBackgroundColour("white")
+
+ if flag and not self.sld_data.is_data:#ctl.IsEnabled():
+ s_size = 1.0
+ try:
+ for item in self.stepsize:
+ s_val = float(item[1].GetValue())
+ if s_val <= 0:
+ item[1].SetBackgroundColour("pink")
+ ctl.Refresh()
+ return
+ if np.isfinite(s_val):
+ s_size *= s_val
+ self.sld_data.set_pixel_volumes(s_size)
+ if ctl.IsEnabled():
+ total_volume = sum(self.sld_data.vol_pix)
+ self.parent.set_volume_ctr_val(total_volume)
+ except:
+ pass
+ ctl.Refresh()
+
+
+ def set_npts_from_slddata(self):
+ """
+ Set total n. of points form the sld data
+ """
+ try:
+ sld_data = self.parent.get_sld_from_omf()
+ #nop = (nop * np.pi) / 6
+ nop = len(sld_data.sld_n)
+ except:
+ nop = None
+ return nop
+
+ def display_npts(self, nop):
+ """
+ Displays Npts ctrl
+ """
+ try:
+ self.npix_ctl.SetValue(str(nop))
+ self.npix_ctl.Refresh()
+ self.parent.set_etime()
+ wx.CallAfter(self._set_volume_ctr_val, nop)
+ except:
+ # On Init
+ pass
+
+ def check_inputs(self):
+ """
+ check if the inputs are valid
+ """
+ flag = self._check_input_helper(self.slds)
+ if flag:
+ flag = self._check_input_helper(self.nodes)
+ if flag:
+ flag = self._check_input_helper(self.stepsize)
+ return flag
+
+ def _check_input_helper(self, list):
+ """
+ Check list values
+ """
+ flag = True
+ for item in list:
+ item[1].SetBackgroundColour("white")
+ item[1].Refresh()
+ try:
+ float(item[1].GetValue())
+ except:
+ flag = _set_error(self, item[1])
+ break
+ return flag
+
+class SasGenWindow(widget.CHILD_FRAME):
+ """
+ GEN SAS main window
+ """
+ def __init__(self, parent=None, manager=None, title="Generic Scattering Calculator",
+ size=(PANEL_WIDTH * 1.4, PANEL_HEIGHT * 1.65), *args, **kwds):
+ """
+ Init
+ """
+ kwds['size'] = size
+ kwds['title'] = title
+ widget.CHILD_FRAME.__init__(self, parent, *args, **kwds)
+ self.parent = parent
+ self.base = manager
+ self.omfpanel = OmfPanel(parent=self)
+ self.panel = SasGenPanel(parent=self)
+ self.data = None
+ self.omfdata = sas_gen.OMFData()
+ self.sld_data = None
+ self._default_save_location = os.getcwd()
+
+ self._mgr = aui.AuiManager(self)
+ self._mgr.SetDockSizeConstraint(0.5, 0.5)
+ self._plot_title = ''
+ self.scale2d = 'log_{10}'
+ self.Bind(wx.EVT_CLOSE, self.on_close)
+
+
+ self.build_panels()
+ self.SetPosition((wx.LEFT, PANEL_TOP))
+ self.Show(True)
+
+ def build_panels(self):
+ """
+ """
+
+ self.set_sld_data(self.sld_data)
+ self._mgr.AddPane(self.panel, aui.AuiPaneInfo().
+ Name(self.panel.window_name).
+ CenterPane().
+ # This is where we set the size of
+ # the application window
+ BestSize(wx.Size(PANEL_WIDTH,
+ PANEL_HEIGHT)).
+ Show())
+ self._mgr.AddPane(self.omfpanel, aui.AuiPaneInfo().
+ Name(self.omfpanel.window_name).
+ Caption(self.omfpanel.window_caption).
+ CloseButton(False).
+ Right().
+ Floatable(False).
+ BestSize(wx.Size(PANEL_WIDTH / 2.5, PANEL_HEIGHT)).
+ Show())
+ self._mgr.Update()
+
+ def get_sld_data(self):
+ """
+ Return slddata
+ """
+ return self.sld_data
+
+ def get_sld_from_omf(self):
+ """
+ """
+ self.sld_data = self.omfpanel.get_sld_val()
+ return self.sld_data
+
+ def set_sld_n(self, sld):
+ """
+ """
+ self.panel.sld_data = sld
+ self.panel.model.set_sld_data(sld)
+
+ def set_sld_data(self, data):
+ """
+ Set omfdata
+ """
+ if data is None:
+ return
+ self.sld_data = data
+ enable = (data is not None)
+ self._set_omfpanel_sld_data(self.sld_data)
+ self.omfpanel.bt_save.Enable(enable)
+ self.set_etime()
+
+ def set_omfpanel_npts(self):
+ """
+ Set Npts in omf panel
+ """
+ nop = self.omfpanel.set_npts_from_slddata()
+ self.omfpanel.display_npts(nop)
+
+ def _set_omfpanel_sld_data(self, data):
+ """
+ Set sld_data in omf panel
+ """
+ self.omfpanel.set_slddata(data)
+ self.omfpanel.set_sld_ctr(data)
+
+ def check_omfpanel_inputs(self):
+ """
+ Check OMF panel inputs
+ """
+ return self.omfpanel.check_inputs()
+
+ def set_main_panel_sld_data(self, sld_data):
+ """
+ """
+ self.sld_data = sld_data
+
+ def set_file_location(self, path):
+ """
+ File location
+ """
+ self._default_save_location = path
+
+ def get_path(self):
+ """
+ File location
+ """
+ return self._default_save_location
+
+ def draw_graph(self, plot, title=''):
+ """
+ """
+ try:
+ wx.PostEvent(self.parent, NewPlotEvent(plot=plot, title=title))
+ except:
+ # standalone
+ frame = PlotFrame(self, -1, 'testView', self.scale2d)
+ #add_icon(self.parent, frame)
+ frame.add_plot(plot)
+ frame.SetTitle(title)
+ frame.Show(True)
+ frame.SetFocus()
+
+ def set_schedule_full_draw(self, panel=None, func='del'):
+ """
+ Send full draw to gui frame
+ """
+ if self.parent is not None:
+ self.parent.set_schedule_full_draw(panel, func)
+
+ def get_npix(self):
+ """
+ Get no. of pixels from omf panel
+ """
+ n_pix = self.omfpanel.npix_ctl.GetValue()
+ return n_pix
+
+ def get_pix_volumes(self):
+ """
+ Get a pixel volume
+ """
+ vol = self.omfpanel.get_pix_volumes()
+ return vol
+
+ def set_volume_ctr_val(self, val):
+ """
+ Set volume txtctl value
+ """
+ try:
+ self.panel.set_volume_ctl_val(str(val))
+ except:
+ print("self.panel is not initialized yet")
+
+ def set_omfpanel_default_shap(self, shape):
+ """
+ Set default_shape in omfpanel
+ """
+ self.omfpanel.default_shape = shape
+
+ def set_etime(self):
+ """
+ Sets est. computation time on panel
+ """
+ self.panel.set_est_time()
+
+ def get_sld_data_from_omf(self):
+ """
+ """
+ data = self.omfpanel.get_sld_val()
+ return data
+
+ def set_scale2d(self, scale):
+ """
+ """
+ self.scale2d = scale
+
+ def on_panel_close(self, event):
+ """
+ """
+ #Not implemented
+
+ def on_open_file(self, event):
+ """
+ On Open
+ """
+ self.panel.on_load_data(event)
+
+ def sld_draw(self):
+ """
+ sld draw
+ """
+ self.panel.sld_draw(event=None, has_arrow=False)
+
+ def on_save_file(self, event):
+ """
+ On Close
+ """
+ self.omfpanel.on_save(event)
+
+ def on_close(self, event):
+ """
+ Close
+ """
+ if self.base is not None:
+ self.base.gen_frame = None
+ self.Destroy()
+
+if __name__ == "__main__":
+ app = wx.PySimpleApp()
+ widget.CHILD_FRAME = wx.Frame
+ SGframe = SasGenWindow()
+ SGframe.Show(True)
+ app.MainLoop()
diff --git a/src/sas/sasgui/perspectives/calculator/image_viewer.py b/src/sas/sasgui/perspectives/calculator/image_viewer.py
index d43a772..7f805e5 100644
--- a/src/sas/sasgui/perspectives/calculator/image_viewer.py
+++ b/src/sas/sasgui/perspectives/calculator/image_viewer.py
@@ -1,438 +1,456 @@
-import os
-import sys
-import wx
-import numpy as np
-import matplotlib
-matplotlib.interactive(False)
-#Use the WxAgg back end. The Wx one takes too long to render
-matplotlib.use('WXAgg')
-from sas.sasgui.guiframe.local_perspectives.plotting.SimplePlot import PlotFrame
-#import matplotlib.pyplot as plt
-import matplotlib.image as mpimg
-import matplotlib.colors as colors
-from sas.sasgui.guiframe.events import StatusEvent
-from sas.sasgui.perspectives.calculator.calculator_widgets import InputTextCtrl
-from sas.sascalc.dataloader.data_info import Data2D
-from sas.sascalc.dataloader.data_info import Detector
-from sas.sascalc.dataloader.manipulations import reader2D_converter
-from sas.sasgui.guiframe.documentation_window import DocumentationWindow
-
-_BOX_WIDTH = 60
-IS_WIN = True
-if sys.platform.count("win32") > 0:
- _DIALOG_WIDTH = 400
-else:
- _DIALOG_WIDTH = 480
- IS_WIN = False
-
-class ImageView:
- """
- Open a file dialog to allow the user to select a given file.
- Display the loaded data if available.
- """
- def __init__(self, parent=None):
- """
- Init
- """
- self.parent = parent
-
- def load(self):
- """
- load image files
- """
- parent = self.parent
- if parent == None:
- location = os.getcwd()
- else:
- location = parent._default_save_location
- path_list = self.choose_data_file(location=location)
- if path_list == None:
- return
- if len(path_list) >= 0 and not(path_list[0]is None):
- if parent != None:
- parent._default_save_location = os.path.dirname(path_list[0])
- err_msg = ''
- for file_path in path_list:
- basename = os.path.basename(file_path)
- _, extension = os.path.splitext(basename)
- try:
- img = mpimg.imread(file_path)
- is_png = extension.lower() == '.png'
- plot_frame = ImageFrame(parent, -1, basename, img)
- plot_frame.Show(False)
- ax = plot_frame.plotpanel
- if not is_png:
- ax.subplot.set_ylim(ax.subplot.get_ylim()[::-1])
- ax.subplot.set_xlabel('x [pixel]')
- ax.subplot.set_ylabel('y [pixel]')
- ax.figure.subplots_adjust(left=0.15, bottom=0.1,
- right=0.95, top=0.95)
- plot_frame.SetTitle('Picture -- %s --' % basename)
- plot_frame.Show(True)
- if parent != None:
- parent.put_icon(plot_frame)
- except:
- err_msg += "Failed to load '%s'.\n" % basename
- if err_msg:
- if parent is not None:
- wx.PostEvent(parent, StatusEvent(status=err_msg, info="error"))
- else:
- print err_msg
-
- def choose_data_file(self, location=None):
- """
- Open a file dialog to allow loading a file
- """
- path = None
- if location == None:
- location = os.getcwd()
- dlg = wx.FileDialog(self.parent, "Image Viewer: Choose a image file",
- location, "", "", style=wx.FD_OPEN | wx.FD_MULTIPLE)
- if dlg.ShowModal() == wx.ID_OK:
- path = dlg.GetPaths()
- else:
- return None
- dlg.Destroy()
- return path
-
-class ImageFrame(PlotFrame):
- """
- Frame for simple plot
- """
- def __init__(self, parent, id, title, image=None, scale='log_{10}',
- size=wx.Size(550, 470)):
- """
- comment
- :Param data: image array got from imread() of matplotlib [narray]
- :param parent: parent panel/container
- """
- # Initialize the Frame object
- PlotFrame.__init__(self, parent, id, title, scale, size,
- show_menu_icons=False)
- self.parent = parent
- self.data = image
- self.file_name = title
-
- menu = wx.Menu()
- id = wx.NewId()
- item = wx.MenuItem(menu, id, "&Convert to Data")
- menu.AppendItem(item)
- wx.EVT_MENU(self, id, self.on_set_data)
- self.menu_bar.Append(menu, "&Image")
-
- menu_help = wx.Menu()
- id = wx.NewId()
- item = wx.MenuItem(menu_help, id, "&HowTo")
- menu_help.AppendItem(item)
- wx.EVT_MENU(self, id, self.on_help)
- self.menu_bar.Append(menu_help, "&Help")
-
- self.SetMenuBar(self.menu_bar)
- self.im_show(image)
-
- def on_set_data(self, event):
- """
- Rescale the x y range, make 2D data and send it to data explore
- """
- title = self.file_name
- self.panel = SetDialog(parent=self, title=title, image=self.data)
- self.panel.ShowModal()
-
- def on_help(self, event):
- """
- Bring up Image Viewer Documentation from the image viewer window
- whenever the help menu item "how to" is clicked. Calls
- DocumentationWindow with the path of the location within the
- documentation tree (after /doc/ ....".
-
- :param evt: Triggers on clicking "how to" in help menu
- """
-
- _TreeLocation = "user/sasgui/perspectives/calculator/"
- _TreeLocation += "image_viewer_help.html"
- _doc_viewer = DocumentationWindow(self, -1, _TreeLocation, "",
- "Image Viewer Help")
-
-
-class SetDialog(wx.Dialog):
- """
- Dialog for Data Set
- """
- def __init__(self, parent, id= -1, title="Convert to Data", image=None,
- size=(_DIALOG_WIDTH, 270)):
- wx.Dialog.__init__(self, parent, id, title, size)
- # parent
- self.parent = parent
- self.base = parent.parent
- self.title = title
- self.image = np.array(image)
- self.z_ctrl = None
- self.xy_ctrls = []
- self.is_png = self._get_is_png()
- self._build_layout()
- my_title = "Convert Image to Data - %s -" % self.title
- self.SetTitle(my_title)
- self.SetSize(size)
-
- def _get_is_png(self):
- """
- Get if the image file is png
- """
- _, extension = os.path.splitext(self.title)
- return extension.lower() == '.png'
-
- def _build_layout(self):
- """
- Layout
- """
- vbox = wx.BoxSizer(wx.VERTICAL)
- zbox = wx.BoxSizer(wx.HORIZONTAL)
- xbox = wx.BoxSizer(wx.HORIZONTAL)
- ybox = wx.BoxSizer(wx.HORIZONTAL)
- btnbox = wx.BoxSizer(wx.VERTICAL)
-
- sb_title = wx.StaticBox(self, -1, 'Transform Axes')
- boxsizer = wx.StaticBoxSizer(sb_title, wx.VERTICAL)
- z_title = wx.StaticText(self, -1, 'z values (range: 0 - 255) to:')
- ztime_title = wx.StaticText(self, -1, 'z *')
- x_title = wx.StaticText(self, -1, 'x values from pixel # to:')
- xmin_title = wx.StaticText(self, -1, 'xmin:')
- xmax_title = wx.StaticText(self, -1, 'xmax:')
- y_title = wx.StaticText(self, -1, 'y values from pixel # to:')
- ymin_title = wx.StaticText(self, -1, 'ymin: ')
- ymax_title = wx.StaticText(self, -1, 'ymax:')
- z_ctl = InputTextCtrl(self, -1, size=(_BOX_WIDTH , 20),
- style=wx.TE_PROCESS_ENTER)
-
- xmin_ctl = InputTextCtrl(self, -1, size=(_BOX_WIDTH, 20),
- style=wx.TE_PROCESS_ENTER)
- xmax_ctl = InputTextCtrl(self, -1, size=(_BOX_WIDTH, 20),
- style=wx.TE_PROCESS_ENTER)
- ymin_ctl = InputTextCtrl(self, -1, size=(_BOX_WIDTH, 20),
- style=wx.TE_PROCESS_ENTER)
- ymax_ctl = InputTextCtrl(self, -1, size=(_BOX_WIDTH, 20),
- style=wx.TE_PROCESS_ENTER)
- z_ctl.SetValue('1.0')
- xmin_ctl.SetValue('-0.3')
- xmax_ctl.SetValue('0.3')
- ymin_ctl.SetValue('-0.3')
- ymax_ctl.SetValue('0.3')
- z_ctl.Bind(wx.EVT_TEXT, self._on_z_enter)
- xmin_ctl.Bind(wx.EVT_TEXT, self._onparam)
- xmax_ctl.Bind(wx.EVT_TEXT, self._onparam)
- ymin_ctl.Bind(wx.EVT_TEXT, self._onparam)
- ymax_ctl.Bind(wx.EVT_TEXT, self._onparam)
- xbox.AddMany([(x_title , 0, wx.LEFT, 0),
- (xmin_title , 0, wx.LEFT, 10),
- (xmin_ctl , 0, wx.LEFT, 10),
- (xmax_title , 0, wx.LEFT, 10),
- (xmax_ctl , 0, wx.LEFT, 10)])
- ybox.AddMany([(y_title , 0, wx.LEFT, 0),
- (ymin_title , 0, wx.LEFT, 10),
- (ymin_ctl , 0, wx.LEFT, 10),
- (ymax_title , 0, wx.LEFT, 10),
- (ymax_ctl , 0, wx.LEFT, 10)])
- zbox.AddMany([(z_title , 0, wx.LEFT, 0),
- (ztime_title, 0, wx.LEFT, 10),
- (z_ctl , 0, wx.LEFT, 7),
- ])
- msg = "The data rescaled will show up in the Data Explorer. \n"
- msg += "*Note: Recommend to use an image with 8 bit Grey \n"
- msg += " scale (and with No. of pixels < 300 x 300).\n"
- msg += " Otherwise, z = 0.299R + 0.587G + 0.114B."
- note_txt = wx.StaticText(self, -1, msg)
- note_txt.SetForegroundColour("black")
- hbox = wx.BoxSizer(wx.HORIZONTAL)
- okButton = wx.Button(self, -1, 'OK')
- okButton.Bind(wx.EVT_BUTTON, self.on_set)
- cancelButton = wx.Button(self, -1, 'Cancel')
- cancelButton.Bind(wx.EVT_BUTTON, self.OnClose)
- btnbox.Add(okButton, 0, wx.LEFT | wx.BOTTOM, 5)
- btnbox.Add(cancelButton, 0, wx.LEFT | wx.TOP, 5)
- hbox.Add(note_txt, 0, wx.LEFT, 5)
- hbox.Add(btnbox, 0, wx.LEFT, 15)
- vbox.Add((10, 15))
- boxsizer.Add(xbox, 1, wx.LEFT | wx.BOTTOM, 5)
- boxsizer.Add(ybox, 1, wx.LEFT | wx.BOTTOM, 5)
- boxsizer.Add(zbox, 1, wx.LEFT | wx.BOTTOM, 5)
- vbox.Add(boxsizer, 0, wx.LEFT, 20)
- vbox.Add(hbox, 0, wx.LEFT | wx.TOP, 15)
- okButton.SetFocus()
- # set sizer
- self.SetSizer(vbox)
- #pos = self.parent.GetPosition()
- #self.SetPosition(pos)
- self.z_ctrl = z_ctl
- self.xy_ctrls = [[xmin_ctl, xmax_ctl], [ymin_ctl, ymax_ctl]]
-
- def _onparamEnter(self, event=None):
- """
- By pass original txtcrl binding
- """
- pass
-
- def _onparam(self, event=None):
- """
- Set to default
- """
- item = event.GetEventObject()
- self._check_ctrls(item)
-
- def _check_ctrls(self, item, is_button=False):
- """
- """
- flag = True
- item.SetBackgroundColour("white")
- try:
- val = float(item.GetValue())
- if val < -10.0 or val > 10.0:
- item.SetBackgroundColour("pink")
- item.Refresh()
- flag = False
- except:
- item.SetBackgroundColour("pink")
- item.Refresh()
- flag = False
- if not flag and is_button:
- err_msg = "The allowed range of the min and max values are \n"
- err_msg += "between -10 and 10."
- if self.base is not None:
- wx.PostEvent(self.base, StatusEvent(status=err_msg,
- info="error"))
- else:
- print err_msg
- return flag
-
- def _on_z_enter(self, event=None):
- """
- On z factor enter
- """
- item = event.GetEventObject()
- self._check_z_ctrl(item)
-
- def _check_z_ctrl(self, item, is_button=False):
- """
- """
- flag = True
- item.SetBackgroundColour("white")
- try:
- val = float(item.GetValue())
- if val <= 0:
- item.SetBackgroundColour("pink")
- item.Refresh()
- flag = False
- except:
- item.SetBackgroundColour("pink")
- item.Refresh()
- flag = False
- if not flag and is_button:
- err_msg = "The z scale value should be larger than 0."
- if self.base is not None:
- wx.PostEvent(self.base, StatusEvent(status=err_msg,
- info="error"))
- else:
- print err_msg
- return flag
-
- def on_set(self, event):
- """
- Set image as data
- """
- event.Skip()
- # Check the textctrl values
- for item_list in self.xy_ctrls:
- for item in item_list:
- if not self._check_ctrls(item, True):
- return
- if not self._check_z_ctrl(self.z_ctrl, True):
- return
- try:
- image = self.image
- xmin = float(self.xy_ctrls[0][0].GetValue())
- xmax = float(self.xy_ctrls[0][1].GetValue())
- ymin = float(self.xy_ctrls[1][0].GetValue())
- ymax = float(self.xy_ctrls[1][1].GetValue())
- zscale = float(self.z_ctrl.GetValue())
- self.convert_image(image, xmin, xmax, ymin, ymax, zscale)
- except:
- err_msg = "Error occurred while converting Image to Data."
- if self.base is not None:
- wx.PostEvent(self.base, StatusEvent(status=err_msg,
- info="error"))
- else:
- print err_msg
-
- self.OnClose(event)
-
- def convert_image(self, rgb, xmin, xmax, ymin, ymax, zscale):
- """
- Convert image to data2D
- """
- x_len = len(rgb[0])
- y_len = len(rgb)
- x_vals = np.linspace(xmin, xmax, num=x_len)
- y_vals = np.linspace(ymin, ymax, num=y_len)
- # Instantiate data object
- output = Data2D()
- output.filename = os.path.basename(self.title)
- output.id = output.filename
- detector = Detector()
- detector.pixel_size.x = None
- detector.pixel_size.y = None
- # Store the sample to detector distance
- detector.distance = None
- output.detector.append(detector)
- # Initiazed the output data object
- output.data = zscale * self.rgb2gray(rgb)
- output.err_data = np.zeros([x_len, y_len])
- output.mask = np.ones([x_len, y_len], dtype=bool)
- output.xbins = x_len
- output.ybins = y_len
- output.x_bins = x_vals
- output.y_bins = y_vals
- output.qx_data = np.array(x_vals)
- output.qy_data = np.array(y_vals)
- output.xmin = xmin
- output.xmax = xmax
- output.ymin = ymin
- output.ymax = ymax
- output.xaxis('\\rm{Q_{x}}', '\AA^{-1}')
- output.yaxis('\\rm{Q_{y}}', '\AA^{-1}')
- # Store loading process information
- output.meta_data['loader'] = self.title.split('.')[-1] + "Reader"
- output.is_data = True
- output = reader2D_converter(output)
- if self.base != None:
- data = self.base.create_gui_data(output, self.title)
- self.base.add_data({data.id:data})
-
- def rgb2gray(self, rgb):
- """
- RGB to Grey
- """
- if self.is_png:
- # png image limits: 0 to 1, others 0 to 255
- #factor = 255.0
- rgb = rgb[::-1]
- if rgb.ndim == 2:
- grey = np.rollaxis(rgb, axis=0)
- else:
- red, green, blue = np.rollaxis(rgb[..., :3], axis= -1)
- grey = 0.299 * red + 0.587 * green + 0.114 * blue
- max_i = rgb.max()
- factor = 255.0 / max_i
- grey *= factor
- return np.array(grey)
-
- def OnClose(self, event):
- """
- Close event
- """
- # clear event
- event.Skip()
- self.Destroy()
-
-if __name__ == "__main__":
- app = wx.App()
- ImageView(None).load()
- app.MainLoop()
+from __future__ import print_function
+
+import os
+import sys
+import wx
+import numpy as np
+import matplotlib
+matplotlib.interactive(False)
+#Use the WxAgg back end. The Wx one takes too long to render
+matplotlib.use('WXAgg')
+from sas.sasgui.guiframe.local_perspectives.plotting.SimplePlot import PlotFrame
+#import matplotlib.pyplot as plt
+import matplotlib.image as mpimg
+import matplotlib.colors as colors
+from sas.sasgui.guiframe.events import StatusEvent
+from sas.sasgui.perspectives.calculator.calculator_widgets import InputTextCtrl
+from sas.sascalc.dataloader.data_info import Data2D
+from sas.sascalc.dataloader.data_info import Detector
+from sas.sascalc.dataloader.manipulations import reader2D_converter
+from sas.sasgui.guiframe.documentation_window import DocumentationWindow
+
+_BOX_WIDTH = 60
+IS_WIN = True
+if sys.platform.count("win32") > 0:
+ _DIALOG_WIDTH = 400
+else:
+ _DIALOG_WIDTH = 480
+ IS_WIN = False
+
+class ImageView:
+ """
+ Open a file dialog to allow the user to select a given file.
+ Display the loaded data if available.
+ """
+ def __init__(self, parent=None):
+ """
+ Init
+ """
+ self.parent = parent
+
+ def load(self):
+ """
+ load image files
+ """
+ parent = self.parent
+ if parent is None:
+ location = os.getcwd()
+ else:
+ location = parent._default_save_location
+ path_list = self.choose_data_file(location=location)
+ if path_list is None:
+ return
+ if len(path_list) >= 0 and path_list[0] is not None:
+ if parent is not None:
+ parent._default_save_location = os.path.dirname(path_list[0])
+ err_msg = ''
+ for file_path in path_list:
+ basename = os.path.basename(file_path)
+ _, extension = os.path.splitext(basename)
+ try:
+ # Note that matplotlib only reads png natively.
+ # Any other formats (tiff, jpeg, etc) are passed
+ # to PIL which seems to have a problem in version
+ # 1.1.7 that causes a close error which shows up in
+ # the log file. This does not seem to have any adverse
+ # effects. PDB --- September 17, 2017.
+ img = mpimg.imread(file_path)
+ is_png = extension.lower() == '.png'
+ plot_frame = ImageFrame(parent, -1, basename, img)
+ plot_frame.Show(False)
+ ax = plot_frame.plotpanel
+ if not is_png:
+ ax.subplot.set_ylim(ax.subplot.get_ylim()[::-1])
+ ax.subplot.set_xlabel('x [pixel]')
+ ax.subplot.set_ylabel('y [pixel]')
+ ax.figure.subplots_adjust(left=0.15, bottom=0.1,
+ right=0.95, top=0.95)
+ plot_frame.SetTitle('Picture -- %s --' % basename)
+ plot_frame.Show(True)
+ if parent is not None:
+ parent.put_icon(plot_frame)
+ except:
+ err_msg += "Failed to load '%s'.\n" % basename
+ if err_msg:
+ if parent is not None:
+ wx.PostEvent(parent, StatusEvent(status=err_msg, info="error"))
+ else:
+ print(err_msg)
+
+ def choose_data_file(self, location=None):
+ """
+ Open a file dialog to allow loading a file
+ """
+ path = None
+ if location is None:
+ location = os.getcwd()
+ wildcard="Images (*.bmp;*.gif;*jpeg,*jpg;*.png;*tif;*.tiff)|*bmp;\
+ *.gif; *.jpg; *.jpeg;*png;*.png;*.tif;*.tiff|"\
+ "Bitmap (*.bmp)|*.bmp|"\
+ "GIF (*.gif)|*.gif|"\
+ "JPEG (*.jpg;*.jpeg)|*.jpg;*.jpeg|"\
+ "PNG (*.png)|*.png|"\
+ "TIFF (*.tif;*.tiff)|*.tif;*tiff|"\
+ "All Files (*.*)|*.*|"
+
+ dlg = wx.FileDialog(self.parent, "Image Viewer: Choose an image file",
+ location, "", wildcard, style=wx.FD_OPEN
+ | wx.FD_MULTIPLE)
+ if dlg.ShowModal() == wx.ID_OK:
+ path = dlg.GetPaths()
+ else:
+ return None
+ dlg.Destroy()
+ return path
+
+class ImageFrame(PlotFrame):
+ """
+ Frame for simple plot
+ """
+ def __init__(self, parent, id, title, image=None, scale='log_{10}',
+ size=wx.Size(550, 470)):
+ """
+ comment
+ :Param data: image array got from imread() of matplotlib [narray]
+ :param parent: parent panel/container
+ """
+ # Initialize the Frame object
+ PlotFrame.__init__(self, parent, id, title, scale, size,
+ show_menu_icons=False)
+ self.parent = parent
+ self.data = image
+ self.file_name = title
+
+ menu = wx.Menu()
+ id = wx.NewId()
+ item = wx.MenuItem(menu, id, "&Convert to Data")
+ menu.AppendItem(item)
+ wx.EVT_MENU(self, id, self.on_set_data)
+ self.menu_bar.Append(menu, "&Image")
+
+ menu_help = wx.Menu()
+ id = wx.NewId()
+ item = wx.MenuItem(menu_help, id, "&HowTo")
+ menu_help.AppendItem(item)
+ wx.EVT_MENU(self, id, self.on_help)
+ self.menu_bar.Append(menu_help, "&Help")
+
+ self.SetMenuBar(self.menu_bar)
+ self.im_show(image)
+
+ def on_set_data(self, event):
+ """
+ Rescale the x y range, make 2D data and send it to data explore
+ """
+ title = self.file_name
+ self.panel = SetDialog(parent=self, title=title, image=self.data)
+ self.panel.ShowModal()
+
+ def on_help(self, event):
+ """
+ Bring up Image Viewer Documentation from the image viewer window
+ whenever the help menu item "how to" is clicked. Calls
+ DocumentationWindow with the path of the location within the
+ documentation tree (after /doc/ ....".
+
+ :param evt: Triggers on clicking "how to" in help menu
+ """
+
+ _TreeLocation = "user/sasgui/perspectives/calculator/"
+ _TreeLocation += "image_viewer_help.html"
+ _doc_viewer = DocumentationWindow(self, -1, _TreeLocation, "",
+ "Image Viewer Help")
+
+
+class SetDialog(wx.Dialog):
+ """
+ Dialog for Data Set
+ """
+ def __init__(self, parent, id= -1, title="Convert to Data", image=None,
+ size=(_DIALOG_WIDTH, 270)):
+ wx.Dialog.__init__(self, parent, id, title, size)
+ # parent
+ self.parent = parent
+ self.base = parent.parent
+ self.title = title
+ self.image = np.array(image)
+ self.z_ctrl = None
+ self.xy_ctrls = []
+ self.is_png = self._get_is_png()
+ self._build_layout()
+ my_title = "Convert Image to Data - %s -" % self.title
+ self.SetTitle(my_title)
+ self.SetSize(size)
+
+ def _get_is_png(self):
+ """
+ Get if the image file is png
+ """
+ _, extension = os.path.splitext(self.title)
+ return extension.lower() == '.png'
+
+ def _build_layout(self):
+ """
+ Layout
+ """
+ vbox = wx.BoxSizer(wx.VERTICAL)
+ zbox = wx.BoxSizer(wx.HORIZONTAL)
+ xbox = wx.BoxSizer(wx.HORIZONTAL)
+ ybox = wx.BoxSizer(wx.HORIZONTAL)
+ btnbox = wx.BoxSizer(wx.VERTICAL)
+
+ sb_title = wx.StaticBox(self, -1, 'Transform Axes')
+ boxsizer = wx.StaticBoxSizer(sb_title, wx.VERTICAL)
+ z_title = wx.StaticText(self, -1, 'z values (range: 0 - 255) to:')
+ ztime_title = wx.StaticText(self, -1, 'z *')
+ x_title = wx.StaticText(self, -1, 'x values from pixel # to:')
+ xmin_title = wx.StaticText(self, -1, 'xmin:')
+ xmax_title = wx.StaticText(self, -1, 'xmax:')
+ y_title = wx.StaticText(self, -1, 'y values from pixel # to:')
+ ymin_title = wx.StaticText(self, -1, 'ymin: ')
+ ymax_title = wx.StaticText(self, -1, 'ymax:')
+ z_ctl = InputTextCtrl(self, -1, size=(_BOX_WIDTH , 20),
+ style=wx.TE_PROCESS_ENTER)
+
+ xmin_ctl = InputTextCtrl(self, -1, size=(_BOX_WIDTH, 20),
+ style=wx.TE_PROCESS_ENTER)
+ xmax_ctl = InputTextCtrl(self, -1, size=(_BOX_WIDTH, 20),
+ style=wx.TE_PROCESS_ENTER)
+ ymin_ctl = InputTextCtrl(self, -1, size=(_BOX_WIDTH, 20),
+ style=wx.TE_PROCESS_ENTER)
+ ymax_ctl = InputTextCtrl(self, -1, size=(_BOX_WIDTH, 20),
+ style=wx.TE_PROCESS_ENTER)
+ z_ctl.SetValue('1.0')
+ xmin_ctl.SetValue('-0.3')
+ xmax_ctl.SetValue('0.3')
+ ymin_ctl.SetValue('-0.3')
+ ymax_ctl.SetValue('0.3')
+ z_ctl.Bind(wx.EVT_TEXT, self._on_z_enter)
+ xmin_ctl.Bind(wx.EVT_TEXT, self._onparam)
+ xmax_ctl.Bind(wx.EVT_TEXT, self._onparam)
+ ymin_ctl.Bind(wx.EVT_TEXT, self._onparam)
+ ymax_ctl.Bind(wx.EVT_TEXT, self._onparam)
+ xbox.AddMany([(x_title , 0, wx.LEFT, 0),
+ (xmin_title , 0, wx.LEFT, 10),
+ (xmin_ctl , 0, wx.LEFT, 10),
+ (xmax_title , 0, wx.LEFT, 10),
+ (xmax_ctl , 0, wx.LEFT, 10)])
+ ybox.AddMany([(y_title , 0, wx.LEFT, 0),
+ (ymin_title , 0, wx.LEFT, 10),
+ (ymin_ctl , 0, wx.LEFT, 10),
+ (ymax_title , 0, wx.LEFT, 10),
+ (ymax_ctl , 0, wx.LEFT, 10)])
+ zbox.AddMany([(z_title , 0, wx.LEFT, 0),
+ (ztime_title, 0, wx.LEFT, 10),
+ (z_ctl , 0, wx.LEFT, 7),
+ ])
+ msg = "The data rescaled will show up in the Data Explorer. \n"
+ msg += "*Note: Recommend to use an image with 8 bit Grey \n"
+ msg += " scale (and with No. of pixels < 300 x 300).\n"
+ msg += " Otherwise, z = 0.299R + 0.587G + 0.114B."
+ note_txt = wx.StaticText(self, -1, msg)
+ note_txt.SetForegroundColour("black")
+ hbox = wx.BoxSizer(wx.HORIZONTAL)
+ okButton = wx.Button(self, -1, 'OK')
+ okButton.Bind(wx.EVT_BUTTON, self.on_set)
+ cancelButton = wx.Button(self, -1, 'Cancel')
+ cancelButton.Bind(wx.EVT_BUTTON, self.OnClose)
+ btnbox.Add(okButton, 0, wx.LEFT | wx.BOTTOM, 5)
+ btnbox.Add(cancelButton, 0, wx.LEFT | wx.TOP, 5)
+ hbox.Add(note_txt, 0, wx.LEFT, 5)
+ hbox.Add(btnbox, 0, wx.LEFT, 15)
+ vbox.Add((10, 15))
+ boxsizer.Add(xbox, 1, wx.LEFT | wx.BOTTOM, 5)
+ boxsizer.Add(ybox, 1, wx.LEFT | wx.BOTTOM, 5)
+ boxsizer.Add(zbox, 1, wx.LEFT | wx.BOTTOM, 5)
+ vbox.Add(boxsizer, 0, wx.LEFT, 20)
+ vbox.Add(hbox, 0, wx.LEFT | wx.TOP, 15)
+ okButton.SetFocus()
+ # set sizer
+ self.SetSizer(vbox)
+ #pos = self.parent.GetPosition()
+ #self.SetPosition(pos)
+ self.z_ctrl = z_ctl
+ self.xy_ctrls = [[xmin_ctl, xmax_ctl], [ymin_ctl, ymax_ctl]]
+
+ def _onparamEnter(self, event=None):
+ """
+ By pass original txtcrl binding
+ """
+ pass
+
+ def _onparam(self, event=None):
+ """
+ Set to default
+ """
+ item = event.GetEventObject()
+ self._check_ctrls(item)
+
+ def _check_ctrls(self, item, is_button=False):
+ """
+ """
+ flag = True
+ item.SetBackgroundColour("white")
+ try:
+ val = float(item.GetValue())
+ if val < -10.0 or val > 10.0:
+ item.SetBackgroundColour("pink")
+ item.Refresh()
+ flag = False
+ except:
+ item.SetBackgroundColour("pink")
+ item.Refresh()
+ flag = False
+ if not flag and is_button:
+ err_msg = "The allowed range of the min and max values are \n"
+ err_msg += "between -10 and 10."
+ if self.base is not None:
+ wx.PostEvent(self.base, StatusEvent(status=err_msg,
+ info="error"))
+ else:
+ print(err_msg)
+ return flag
+
+ def _on_z_enter(self, event=None):
+ """
+ On z factor enter
+ """
+ item = event.GetEventObject()
+ self._check_z_ctrl(item)
+
+ def _check_z_ctrl(self, item, is_button=False):
+ """
+ """
+ flag = True
+ item.SetBackgroundColour("white")
+ try:
+ val = float(item.GetValue())
+ if val <= 0:
+ item.SetBackgroundColour("pink")
+ item.Refresh()
+ flag = False
+ except:
+ item.SetBackgroundColour("pink")
+ item.Refresh()
+ flag = False
+ if not flag and is_button:
+ err_msg = "The z scale value should be larger than 0."
+ if self.base is not None:
+ wx.PostEvent(self.base, StatusEvent(status=err_msg,
+ info="error"))
+ else:
+ print(err_msg)
+ return flag
+
+ def on_set(self, event):
+ """
+ Set image as data
+ """
+ event.Skip()
+ # Check the textctrl values
+ for item_list in self.xy_ctrls:
+ for item in item_list:
+ if not self._check_ctrls(item, True):
+ return
+ if not self._check_z_ctrl(self.z_ctrl, True):
+ return
+ try:
+ image = self.image
+ xmin = float(self.xy_ctrls[0][0].GetValue())
+ xmax = float(self.xy_ctrls[0][1].GetValue())
+ ymin = float(self.xy_ctrls[1][0].GetValue())
+ ymax = float(self.xy_ctrls[1][1].GetValue())
+ zscale = float(self.z_ctrl.GetValue())
+ self.convert_image(image, xmin, xmax, ymin, ymax, zscale)
+ except:
+ err_msg = "Error occurred while converting Image to Data."
+ if self.base is not None:
+ wx.PostEvent(self.base, StatusEvent(status=err_msg,
+ info="error"))
+ else:
+ print(err_msg)
+
+ self.OnClose(event)
+
+ def convert_image(self, rgb, xmin, xmax, ymin, ymax, zscale):
+ """
+ Convert image to data2D
+ """
+ x_len = len(rgb[0])
+ y_len = len(rgb)
+ x_vals = np.linspace(xmin, xmax, num=x_len)
+ y_vals = np.linspace(ymin, ymax, num=y_len)
+ # Instantiate data object
+ output = Data2D()
+ output.filename = os.path.basename(self.title)
+ output.id = output.filename
+ detector = Detector()
+ detector.pixel_size.x = None
+ detector.pixel_size.y = None
+ # Store the sample to detector distance
+ detector.distance = None
+ output.detector.append(detector)
+ # Initiazed the output data object
+ output.data = zscale * self.rgb2gray(rgb)
+ output.err_data = np.zeros([x_len, y_len])
+ output.mask = np.ones([x_len, y_len], dtype=bool)
+ output.xbins = x_len
+ output.ybins = y_len
+ output.x_bins = x_vals
+ output.y_bins = y_vals
+ output.qx_data = np.array(x_vals)
+ output.qy_data = np.array(y_vals)
+ output.xmin = xmin
+ output.xmax = xmax
+ output.ymin = ymin
+ output.ymax = ymax
+ output.xaxis('\\rm{Q_{x}}', '\AA^{-1}')
+ output.yaxis('\\rm{Q_{y}}', '\AA^{-1}')
+ # Store loading process information
+ output.meta_data['loader'] = self.title.split('.')[-1] + "Reader"
+ output.is_data = True
+ output = reader2D_converter(output)
+ if self.base is not None:
+ data = self.base.create_gui_data(output, self.title)
+ self.base.add_data({data.id:data})
+
+ def rgb2gray(self, rgb):
+ """
+ RGB to Grey
+ """
+ if self.is_png:
+ # png image limits: 0 to 1, others 0 to 255
+ #factor = 255.0
+ rgb = rgb[::-1]
+ if rgb.ndim == 2:
+ grey = np.rollaxis(rgb, axis=0)
+ else:
+ red, green, blue = np.rollaxis(rgb[..., :3], axis= -1)
+ grey = 0.299 * red + 0.587 * green + 0.114 * blue
+ max_i = rgb.max()
+ factor = 255.0 / max_i
+ grey *= factor
+ return np.array(grey)
+
+ def OnClose(self, event):
+ """
+ Close event
+ """
+ # clear event
+ event.Skip()
+ self.Destroy()
+
+if __name__ == "__main__":
+ app = wx.App()
+ ImageView(None).load()
+ app.MainLoop()
diff --git a/src/sas/sasgui/perspectives/calculator/kiessig_calculator_panel.py b/src/sas/sasgui/perspectives/calculator/kiessig_calculator_panel.py
index 8999838..7913c3c 100644
--- a/src/sas/sasgui/perspectives/calculator/kiessig_calculator_panel.py
+++ b/src/sas/sasgui/perspectives/calculator/kiessig_calculator_panel.py
@@ -1,248 +1,248 @@
-"""
-This software was developed by the University of Tennessee as part of the
-Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
-project funded by the US National Science Foundation.
-
-See the license text in license.txt
-
-copyright 2008, 2009, University of Tennessee
-"""
-
-import wx
-import sys
-
-from sas.sasgui.guiframe.panel_base import PanelBase
-from sas.sascalc.calculator.kiessig_calculator import KiessigThicknessCalculator
-from calculator_widgets import OutputTextCtrl
-from calculator_widgets import InputTextCtrl
-from sas.sasgui.perspectives.calculator import calculator_widgets as widget
-from sas.sasgui.guiframe.documentation_window import DocumentationWindow
-
-_BOX_WIDTH = 77
-#Slit length panel size
-if sys.platform.count("win32") > 0:
- PANEL_TOP = 0
- PANEL_WIDTH = 500
- PANEL_HEIGHT = 230
- FONT_VARIANT = 0
-else:
- PANEL_TOP = 60
- PANEL_WIDTH = 560
- PANEL_HEIGHT = 230
- FONT_VARIANT = 1
-
-class KiessigThicknessCalculatorPanel(wx.Panel, PanelBase):
- """
- Provides the Kiessig thickness calculator GUI.
- """
- ## Internal nickname for the window, used by the AUI manager
- window_name = "Kiessig Thickness Calculator"
- ## Name to appear on the window title bar
- window_caption = "Kiessig Thickness Calculator"
- ## Flag to tell the AUI manager to put this panel in the center pane
- CENTER_PANE = True
-
- def __init__(self, parent, *args, **kwds):
- wx.Panel.__init__(self, parent, *args, **kwds)
- PanelBase.__init__(self)
- #Font size
- self.SetWindowVariant(variant=FONT_VARIANT)
- # Object that receive status event
- self.parent = parent
- self.kiessig = KiessigThicknessCalculator()
- #layout attribute
- self.hint_sizer = None
- self._do_layout()
-
- def _define_structure(self):
- """
- Define the main sizers building to build this application.
- """
- self.main_sizer = wx.BoxSizer(wx.VERTICAL)
- self.box_source = wx.StaticBox(self, -1,
- str("Kiessig Thickness Calculator"))
- self.boxsizer_source = wx.StaticBoxSizer(self.box_source,
- wx.VERTICAL)
- self.dq_name_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.thickness_size_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.hint_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.button_sizer = wx.BoxSizer(wx.HORIZONTAL)
-
- def _layout_dq_name(self):
- """
- Fill the sizer containing dq name
- """
- # get the default dq
- dq_value = str(self.kiessig.get_deltaq())
- dq_unit_txt = wx.StaticText(self, -1, '[1/A]')
- dq_name_txt = wx.StaticText(self, -1,
- 'Kiessig Fringe Width (Delta Q): ')
- self.dq_name_tcl = InputTextCtrl(self, -1,
- size=(_BOX_WIDTH,-1))
- dq_hint = "Type the Kiessig Fringe Width (Delta Q)"
- self.dq_name_tcl.SetValue(dq_value)
- self.dq_name_tcl.SetToolTipString(dq_hint)
- #control that triggers importing data
- id = wx.NewId()
- self.compute_button = wx.Button(self, id, "Compute")
- hint_on_compute = "Compute the diameter/thickness in the real space."
- self.compute_button.SetToolTipString(hint_on_compute)
- self.Bind(wx.EVT_BUTTON, self.on_compute, id=id)
- self.dq_name_sizer.AddMany([(dq_name_txt, 0, wx.LEFT, 15),
- (self.dq_name_tcl, 0, wx.LEFT, 15),
- (dq_unit_txt, 0, wx.LEFT, 10),
- (self.compute_button, 0, wx.LEFT, 30)])
-
- def _layout_thickness_size(self):
- """
- Fill the sizer containing thickness information
- """
- thick_unit = '['+self.kiessig.get_thickness_unit() +']'
- thickness_size_txt = wx.StaticText(self, -1,
- 'Thickness (or Diameter): ')
- self.thickness_size_tcl = OutputTextCtrl(self, -1,
- size=(_BOX_WIDTH,-1))
- thickness_size_hint = " Estimated Size in Real Space"
- self.thickness_size_tcl.SetToolTipString(thickness_size_hint)
- thickness_size_unit_txt = wx.StaticText(self, -1, thick_unit)
-
- self.thickness_size_sizer.AddMany([(thickness_size_txt, 0, wx.LEFT, 15),
- (self.thickness_size_tcl, 0, wx.LEFT, 15),
- (thickness_size_unit_txt, 0, wx.LEFT, 10)])
-
- def _layout_hint(self):
- """
- Fill the sizer containing hint
- """
- hint_msg = "This tool is to approximately estimate "
- hint_msg += "the thickness of a layer"
- hint_msg += " or the diameter of particles\n "
- hint_msg += "from the Kiessig fringe width in SAS/NR data."
- hint_msg += ""
- self.hint_txt = wx.StaticText(self, -1, hint_msg)
- self.hint_sizer.AddMany([(self.hint_txt, 0, wx.LEFT, 15)])
-
- def _layout_button(self):
- """
- Do the layout for the button widgets
- """
- id = wx.NewId()
- self.bt_help = wx.Button(self, id, 'HELP')
- self.bt_help.Bind(wx.EVT_BUTTON, self.on_help)
- self.bt_help.SetToolTipString("Help using the Kiessig fringe calculator.")
-
- self.bt_close = wx.Button(self, wx.ID_CANCEL, 'Close')
- self.bt_close.Bind(wx.EVT_BUTTON, self.on_close)
- self.bt_close.SetToolTipString("Close this window.")
- self.button_sizer.AddMany([(self.bt_help, 0, wx.LEFT, 260),
- (self.bt_close, 0, wx.LEFT, 20)])
-
- def _do_layout(self):
- """
- Draw window content
- """
- self._define_structure()
- self._layout_dq_name()
- self._layout_thickness_size()
- self._layout_hint()
- self._layout_button()
- self.boxsizer_source.AddMany([(self.dq_name_sizer, 0,
- wx.EXPAND|wx.TOP|wx.BOTTOM, 5),
- (self.thickness_size_sizer, 0,
- wx.EXPAND|wx.TOP|wx.BOTTOM, 5),
- (self.hint_sizer, 0,
- wx.EXPAND|wx.TOP|wx.BOTTOM, 5)])
- self.main_sizer.AddMany([(self.boxsizer_source, 0, wx.ALL, 10),
- (self.button_sizer, 0,
- wx.EXPAND|wx.TOP|wx.BOTTOM, 5)])
- self.SetSizer(self.main_sizer)
- self.SetAutoLayout(True)
-
- def on_help(self, event):
- """
- Bring up the Kiessig fringe calculator Documentation whenever
- the HELP button is clicked.
- Calls DocumentationWindow with the path of the location within the
- documentation tree (after /doc/ ....". Note that when using old
- versions of Wx (before 2.9) and thus not the release version of
- installers, the help comes up at the top level of the file as
- webbrowser does not pass anything past the # to the browser when it is
- running "file:///...."
-
- :param evt: Triggers on clicking the help button
- """
- _TreeLocation = "user/sasgui/perspectives/calculator/"
- _TreeLocation += "kiessig_calculator_help.html"
- _doc_viewer = DocumentationWindow(self, -1, _TreeLocation, "",
- "Density/Volume Calculator Help")
-
- def on_close(self, event):
- """
- close the window containing this panel
- """
- self.parent.Close()
- if event is not None:
- event.Skip()
-
- def on_compute(self, event):
- """
- Execute the computation of thickness
- """
- # skip for another event
- if event != None:
- event.Skip()
- dq = self.dq_name_tcl.GetValue()
- self.kiessig.set_deltaq(dq)
- # calculate the thickness
- output = self.kiessig.compute_thickness()
- thickness = self.format_number(output)
- # set tcl
- self.thickness_size_tcl.SetValue(str(thickness))
-
- def format_number(self, value=None):
- """
- Return a float in a standardized, human-readable formatted string
- """
- try:
- value = float(value)
- except:
- output = None
- return output
-
- output = "%-7.4g" % value
- return output.lstrip().rstrip()
-
- def _onparamEnter(self, event = None):
- """
- On Text_enter_callback, perform compute
- """
- self.on_compute(event)
-
-class KiessigWindow(widget.CHILD_FRAME):
- def __init__(self, parent=None, manager=None,
- title="Kiessig Thickness Calculator",
- size=(PANEL_WIDTH,PANEL_HEIGHT), *args, **kwds):
- kwds['title'] = title
- kwds['size'] = size
- widget.CHILD_FRAME.__init__(self, parent, *args, **kwds)
- self.parent = parent
- self.manager = manager
- self.panel = KiessigThicknessCalculatorPanel(parent=self)
- self.Bind(wx.EVT_CLOSE, self.on_close)
- self.SetPosition((wx.LEFT, PANEL_TOP))
- self.Show(True)
-
- def on_close(self, event):
- """
- Close event
- """
- if self.manager != None:
- self.manager.kiessig_frame = None
- self.Destroy()
-
-if __name__ == "__main__":
- app = wx.PySimpleApp()
- widget.CHILD_FRAME = wx.Frame
- frame = KiessigWindow()
- frame.Show(True)
- app.MainLoop()
+"""
+This software was developed by the University of Tennessee as part of the
+Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
+project funded by the US National Science Foundation.
+
+See the license text in license.txt
+
+copyright 2008, 2009, University of Tennessee
+"""
+
+import wx
+import sys
+
+from sas.sasgui.guiframe.panel_base import PanelBase
+from sas.sascalc.calculator.kiessig_calculator import KiessigThicknessCalculator
+from calculator_widgets import OutputTextCtrl
+from calculator_widgets import InputTextCtrl
+from sas.sasgui.perspectives.calculator import calculator_widgets as widget
+from sas.sasgui.guiframe.documentation_window import DocumentationWindow
+
+_BOX_WIDTH = 77
+#Slit length panel size
+if sys.platform.count("win32") > 0:
+ PANEL_TOP = 0
+ PANEL_WIDTH = 500
+ PANEL_HEIGHT = 230
+ FONT_VARIANT = 0
+else:
+ PANEL_TOP = 60
+ PANEL_WIDTH = 560
+ PANEL_HEIGHT = 230
+ FONT_VARIANT = 1
+
+class KiessigThicknessCalculatorPanel(wx.Panel, PanelBase):
+ """
+ Provides the Kiessig thickness calculator GUI.
+ """
+ ## Internal nickname for the window, used by the AUI manager
+ window_name = "Kiessig Thickness Calculator"
+ ## Name to appear on the window title bar
+ window_caption = "Kiessig Thickness Calculator"
+ ## Flag to tell the AUI manager to put this panel in the center pane
+ CENTER_PANE = True
+
+ def __init__(self, parent, *args, **kwds):
+ wx.Panel.__init__(self, parent, *args, **kwds)
+ PanelBase.__init__(self)
+ #Font size
+ self.SetWindowVariant(variant=FONT_VARIANT)
+ # Object that receive status event
+ self.parent = parent
+ self.kiessig = KiessigThicknessCalculator()
+ #layout attribute
+ self.hint_sizer = None
+ self._do_layout()
+
+ def _define_structure(self):
+ """
+ Define the main sizers building to build this application.
+ """
+ self.main_sizer = wx.BoxSizer(wx.VERTICAL)
+ self.box_source = wx.StaticBox(self, -1,
+ str("Kiessig Thickness Calculator"))
+ self.boxsizer_source = wx.StaticBoxSizer(self.box_source,
+ wx.VERTICAL)
+ self.dq_name_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.thickness_size_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.hint_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.button_sizer = wx.BoxSizer(wx.HORIZONTAL)
+
+ def _layout_dq_name(self):
+ """
+ Fill the sizer containing dq name
+ """
+ # get the default dq
+ dq_value = str(self.kiessig.get_deltaq())
+ dq_unit_txt = wx.StaticText(self, -1, '[1/A]')
+ dq_name_txt = wx.StaticText(self, -1,
+ 'Kiessig Fringe Width (Delta Q): ')
+ self.dq_name_tcl = InputTextCtrl(self, -1,
+ size=(_BOX_WIDTH,-1))
+ dq_hint = "Type the Kiessig Fringe Width (Delta Q)"
+ self.dq_name_tcl.SetValue(dq_value)
+ self.dq_name_tcl.SetToolTipString(dq_hint)
+ #control that triggers importing data
+ id = wx.NewId()
+ self.compute_button = wx.Button(self, id, "Compute")
+ hint_on_compute = "Compute the diameter/thickness in the real space."
+ self.compute_button.SetToolTipString(hint_on_compute)
+ self.Bind(wx.EVT_BUTTON, self.on_compute, id=id)
+ self.dq_name_sizer.AddMany([(dq_name_txt, 0, wx.LEFT, 15),
+ (self.dq_name_tcl, 0, wx.LEFT, 15),
+ (dq_unit_txt, 0, wx.LEFT, 10),
+ (self.compute_button, 0, wx.LEFT, 30)])
+
+ def _layout_thickness_size(self):
+ """
+ Fill the sizer containing thickness information
+ """
+ thick_unit = '['+self.kiessig.get_thickness_unit() +']'
+ thickness_size_txt = wx.StaticText(self, -1,
+ 'Thickness (or Diameter): ')
+ self.thickness_size_tcl = OutputTextCtrl(self, -1,
+ size=(_BOX_WIDTH,-1))
+ thickness_size_hint = " Estimated Size in Real Space"
+ self.thickness_size_tcl.SetToolTipString(thickness_size_hint)
+ thickness_size_unit_txt = wx.StaticText(self, -1, thick_unit)
+
+ self.thickness_size_sizer.AddMany([(thickness_size_txt, 0, wx.LEFT, 15),
+ (self.thickness_size_tcl, 0, wx.LEFT, 15),
+ (thickness_size_unit_txt, 0, wx.LEFT, 10)])
+
+ def _layout_hint(self):
+ """
+ Fill the sizer containing hint
+ """
+ hint_msg = "This tool is to approximately estimate "
+ hint_msg += "the thickness of a layer"
+ hint_msg += " or the diameter of particles\n "
+ hint_msg += "from the Kiessig fringe width in SAS/NR data."
+ hint_msg += ""
+ self.hint_txt = wx.StaticText(self, -1, hint_msg)
+ self.hint_sizer.AddMany([(self.hint_txt, 0, wx.LEFT, 15)])
+
+ def _layout_button(self):
+ """
+ Do the layout for the button widgets
+ """
+ id = wx.NewId()
+ self.bt_help = wx.Button(self, id, 'HELP')
+ self.bt_help.Bind(wx.EVT_BUTTON, self.on_help)
+ self.bt_help.SetToolTipString("Help using the Kiessig fringe calculator.")
+
+ self.bt_close = wx.Button(self, wx.ID_CANCEL, 'Close')
+ self.bt_close.Bind(wx.EVT_BUTTON, self.on_close)
+ self.bt_close.SetToolTipString("Close this window.")
+ self.button_sizer.AddMany([(self.bt_help, 0, wx.LEFT, 260),
+ (self.bt_close, 0, wx.LEFT, 20)])
+
+ def _do_layout(self):
+ """
+ Draw window content
+ """
+ self._define_structure()
+ self._layout_dq_name()
+ self._layout_thickness_size()
+ self._layout_hint()
+ self._layout_button()
+ self.boxsizer_source.AddMany([(self.dq_name_sizer, 0,
+ wx.EXPAND|wx.TOP|wx.BOTTOM, 5),
+ (self.thickness_size_sizer, 0,
+ wx.EXPAND|wx.TOP|wx.BOTTOM, 5),
+ (self.hint_sizer, 0,
+ wx.EXPAND|wx.TOP|wx.BOTTOM, 5)])
+ self.main_sizer.AddMany([(self.boxsizer_source, 0, wx.ALL, 10),
+ (self.button_sizer, 0,
+ wx.EXPAND|wx.TOP|wx.BOTTOM, 5)])
+ self.SetSizer(self.main_sizer)
+ self.SetAutoLayout(True)
+
+ def on_help(self, event):
+ """
+ Bring up the Kiessig fringe calculator Documentation whenever
+ the HELP button is clicked.
+ Calls DocumentationWindow with the path of the location within the
+ documentation tree (after /doc/ ....". Note that when using old
+ versions of Wx (before 2.9) and thus not the release version of
+ installers, the help comes up at the top level of the file as
+ webbrowser does not pass anything past the # to the browser when it is
+ running "file:///...."
+
+ :param evt: Triggers on clicking the help button
+ """
+ _TreeLocation = "user/sasgui/perspectives/calculator/"
+ _TreeLocation += "kiessig_calculator_help.html"
+ _doc_viewer = DocumentationWindow(self, -1, _TreeLocation, "",
+ "Density/Volume Calculator Help")
+
+ def on_close(self, event):
+ """
+ close the window containing this panel
+ """
+ self.parent.Close()
+ if event is not None:
+ event.Skip()
+
+ def on_compute(self, event):
+ """
+ Execute the computation of thickness
+ """
+ # skip for another event
+ if event is not None:
+ event.Skip()
+ dq = self.dq_name_tcl.GetValue()
+ self.kiessig.set_deltaq(dq)
+ # calculate the thickness
+ output = self.kiessig.compute_thickness()
+ thickness = self.format_number(output)
+ # set tcl
+ self.thickness_size_tcl.SetValue(str(thickness))
+
+ def format_number(self, value=None):
+ """
+ Return a float in a standardized, human-readable formatted string
+ """
+ try:
+ value = float(value)
+ except:
+ output = None
+ return output
+
+ output = "%-7.4g" % value
+ return output.lstrip().rstrip()
+
+ def _onparamEnter(self, event = None):
+ """
+ On Text_enter_callback, perform compute
+ """
+ self.on_compute(event)
+
+class KiessigWindow(widget.CHILD_FRAME):
+ def __init__(self, parent=None, manager=None,
+ title="Kiessig Thickness Calculator",
+ size=(PANEL_WIDTH,PANEL_HEIGHT), *args, **kwds):
+ kwds['title'] = title
+ kwds['size'] = size
+ widget.CHILD_FRAME.__init__(self, parent, *args, **kwds)
+ self.parent = parent
+ self.manager = manager
+ self.panel = KiessigThicknessCalculatorPanel(parent=self)
+ self.Bind(wx.EVT_CLOSE, self.on_close)
+ self.SetPosition((wx.LEFT, PANEL_TOP))
+ self.Show(True)
+
+ def on_close(self, event):
+ """
+ Close event
+ """
+ if self.manager is not None:
+ self.manager.kiessig_frame = None
+ self.Destroy()
+
+if __name__ == "__main__":
+ app = wx.PySimpleApp()
+ widget.CHILD_FRAME = wx.Frame
+ frame = KiessigWindow()
+ frame.Show(True)
+ app.MainLoop()
diff --git a/src/sas/sasgui/perspectives/calculator/load_thread.py b/src/sas/sasgui/perspectives/calculator/load_thread.py
index 7ad2a7a..0be3932 100644
--- a/src/sas/sasgui/perspectives/calculator/load_thread.py
+++ b/src/sas/sasgui/perspectives/calculator/load_thread.py
@@ -1,89 +1,89 @@
-"""
- Thread handler used to load data
-"""
-import time
-from sas.sascalc.data_util.calcthread import CalcThread
-from sas.sascalc.dataloader.loader import Loader
-
-class DataReader(CalcThread):
- """
- Load a data given a filename
- """
- def __init__(self, path, completefn=None,
- updatefn=None,
- yieldtime=0.01,
- worktime=0.01
- ):
- CalcThread.__init__(self, completefn,
- updatefn,
- yieldtime,
- worktime)
- self.path = path
- #Instantiate a loader
- self.loader = Loader()
- self.starttime = 0
-
- def isquit(self):
- """
- @raise KeyboardInterrupt: when the thread is interrupted
- """
- try:
- CalcThread.isquit(self)
- except KeyboardInterrupt:
- raise KeyboardInterrupt
-
-
- def compute(self):
- """
- read some data
- """
- self.starttime = time.time()
- try:
- data = self.loader.load(self.path)
- self.complete(data=data)
- except KeyboardInterrupt:
- # Thread was interrupted, just proceed and re-raise.
- # Real code should not print, but this is an example...
- raise
-
-class GenReader(CalcThread):
- """
- Load a sld data given a filename
- """
- def __init__(self, path, loader,
- completefn=None,
- updatefn=None,
- yieldtime=0.01,
- worktime=0.01
- ):
- CalcThread.__init__(self, completefn,
- updatefn,
- yieldtime,
- worktime)
- self.path = path
- #Instantiate a loader
- self.loader = loader
- self.starttime = 0
-
- def isquit(self):
- """
- @raise KeyboardInterrupt: when the thread is interrupted
- """
- try:
- CalcThread.isquit(self)
- except KeyboardInterrupt:
- raise KeyboardInterrupt
-
-
- def compute(self):
- """
- read some data
- """
- self.starttime = time.time()
- try:
- data = self.loader.read(self.path)
- self.complete(data=data)
- except:
- # Thread was interrupted, just proceed and re-raise.
- # Real code should not print, but this is an example...
- raise
+"""
+ Thread handler used to load data
+"""
+import time
+from sas.sascalc.data_util.calcthread import CalcThread
+from sas.sascalc.dataloader.loader import Loader
+
+class DataReader(CalcThread):
+ """
+ Load a data given a filename
+ """
+ def __init__(self, path, completefn=None,
+ updatefn=None,
+ yieldtime=0.01,
+ worktime=0.01
+ ):
+ CalcThread.__init__(self, completefn,
+ updatefn,
+ yieldtime,
+ worktime)
+ self.path = path
+ #Instantiate a loader
+ self.loader = Loader()
+ self.starttime = 0
+
+ def isquit(self):
+ """
+ @raise KeyboardInterrupt: when the thread is interrupted
+ """
+ try:
+ CalcThread.isquit(self)
+ except KeyboardInterrupt:
+ raise KeyboardInterrupt
+
+
+ def compute(self):
+ """
+ read some data
+ """
+ self.starttime = time.time()
+ try:
+ data = self.loader.load(self.path)
+ self.complete(data=data)
+ except KeyboardInterrupt:
+ # Thread was interrupted, just proceed and re-raise.
+ # Real code should not print, but this is an example...
+ raise
+
+class GenReader(CalcThread):
+ """
+ Load a sld data given a filename
+ """
+ def __init__(self, path, loader,
+ completefn=None,
+ updatefn=None,
+ yieldtime=0.01,
+ worktime=0.01
+ ):
+ CalcThread.__init__(self, completefn,
+ updatefn,
+ yieldtime,
+ worktime)
+ self.path = path
+ #Instantiate a loader
+ self.loader = loader
+ self.starttime = 0
+
+ def isquit(self):
+ """
+ @raise KeyboardInterrupt: when the thread is interrupted
+ """
+ try:
+ CalcThread.isquit(self)
+ except KeyboardInterrupt:
+ raise KeyboardInterrupt
+
+
+ def compute(self):
+ """
+ read some data
+ """
+ self.starttime = time.time()
+ try:
+ data = self.loader.read(self.path)
+ self.complete(data=data)
+ except:
+ # Thread was interrupted, just proceed and re-raise.
+ # Real code should not print, but this is an example...
+ raise
diff --git a/src/sas/sasgui/perspectives/calculator/media/.DS_Store b/src/sas/sasgui/perspectives/calculator/media/.DS_Store
new file mode 100644
index 0000000..5008ddf
Binary files /dev/null and b/src/sas/sasgui/perspectives/calculator/media/.DS_Store differ
diff --git a/src/sas/sasgui/perspectives/calculator/media/density_calculator_help.rst b/src/sas/sasgui/perspectives/calculator/media/density_calculator_help.rst
index 3f00e10..091a22c 100644
--- a/src/sas/sasgui/perspectives/calculator/media/density_calculator_help.rst
+++ b/src/sas/sasgui/perspectives/calculator/media/density_calculator_help.rst
@@ -28,7 +28,7 @@ Using the tool
4) Click the 'Calculate' button to perform the calculation.
-.. image:: density_tutor.gif
+.. image:: density_tutor.png
.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
diff --git a/src/sas/sasgui/perspectives/calculator/media/density_tutor.gif b/src/sas/sasgui/perspectives/calculator/media/density_tutor.gif
deleted file mode 100644
index 8b4c939..0000000
Binary files a/src/sas/sasgui/perspectives/calculator/media/density_tutor.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/calculator/media/density_tutor.png b/src/sas/sasgui/perspectives/calculator/media/density_tutor.png
new file mode 100644
index 0000000..66a845c
Binary files /dev/null and b/src/sas/sasgui/perspectives/calculator/media/density_tutor.png differ
diff --git a/src/sas/sasgui/perspectives/calculator/media/dm_eq.gif b/src/sas/sasgui/perspectives/calculator/media/dm_eq.gif
deleted file mode 100644
index f95b013..0000000
Binary files a/src/sas/sasgui/perspectives/calculator/media/dm_eq.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/calculator/media/dm_eq.png b/src/sas/sasgui/perspectives/calculator/media/dm_eq.png
new file mode 100644
index 0000000..1d23f47
Binary files /dev/null and b/src/sas/sasgui/perspectives/calculator/media/dm_eq.png differ
diff --git a/src/sas/sasgui/perspectives/calculator/media/gen_debye_eq.gif b/src/sas/sasgui/perspectives/calculator/media/gen_debye_eq.gif
deleted file mode 100644
index ae14cc8..0000000
Binary files a/src/sas/sasgui/perspectives/calculator/media/gen_debye_eq.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/calculator/media/gen_debye_eq.png b/src/sas/sasgui/perspectives/calculator/media/gen_debye_eq.png
new file mode 100644
index 0000000..7ce063d
Binary files /dev/null and b/src/sas/sasgui/perspectives/calculator/media/gen_debye_eq.png differ
diff --git a/src/sas/sasgui/perspectives/calculator/media/gen_gui_help.bmp b/src/sas/sasgui/perspectives/calculator/media/gen_gui_help.bmp
deleted file mode 100644
index 5758023..0000000
Binary files a/src/sas/sasgui/perspectives/calculator/media/gen_gui_help.bmp and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/calculator/media/gen_gui_help.png b/src/sas/sasgui/perspectives/calculator/media/gen_gui_help.png
new file mode 100644
index 0000000..9b6bc95
Binary files /dev/null and b/src/sas/sasgui/perspectives/calculator/media/gen_gui_help.png differ
diff --git a/src/sas/sasgui/perspectives/calculator/media/gen_i.gif b/src/sas/sasgui/perspectives/calculator/media/gen_i.gif
deleted file mode 100644
index ed494dc..0000000
Binary files a/src/sas/sasgui/perspectives/calculator/media/gen_i.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/calculator/media/gen_i.png b/src/sas/sasgui/perspectives/calculator/media/gen_i.png
new file mode 100644
index 0000000..da749df
Binary files /dev/null and b/src/sas/sasgui/perspectives/calculator/media/gen_i.png differ
diff --git a/src/sas/sasgui/perspectives/calculator/media/gen_mag_pic.bmp b/src/sas/sasgui/perspectives/calculator/media/gen_mag_pic.bmp
deleted file mode 100644
index fa4bb2b..0000000
Binary files a/src/sas/sasgui/perspectives/calculator/media/gen_mag_pic.bmp and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/calculator/media/gen_mag_pic.png b/src/sas/sasgui/perspectives/calculator/media/gen_mag_pic.png
new file mode 100644
index 0000000..4b9cff0
Binary files /dev/null and b/src/sas/sasgui/perspectives/calculator/media/gen_mag_pic.png differ
diff --git a/src/sas/sasgui/perspectives/calculator/media/gen_sas_help.html b/src/sas/sasgui/perspectives/calculator/media/gen_sas_help.html
index 4cc3166..9f4c985 100644
--- a/src/sas/sasgui/perspectives/calculator/media/gen_sas_help.html
+++ b/src/sas/sasgui/perspectives/calculator/media/gen_sas_help.html
@@ -18,14 +18,14 @@ Assuming that
all the pixel sizes are same, the elastic scattering intensity
by the particle
<p>
-<img src="gen_i.gif"/>
+<img src="gen_i.png"/>
</p>
<br>
where β<sub>j</sub> and r<sub>j</sub> are the scattering
length density and the position
of the j'th pixel respectively. And the total volume
<p>
-<img src="v_j.gif"/>
+<img src="v_j.png"/>
</p>
<br>
for β<sub>j</sub> ≠ 0 where v<sub>j</sub> is the volume of the j'th pixel
@@ -43,12 +43,12 @@ For magnetic scattering, only the magnetization component, <b>M</b><sub>perp</su
perpendicular to the scattering vector <b>Q</b> contributes to the the magnetic
scattering length. (Figure below).
<p>
-<img src="mag_vector.bmp"/>
+<img src="mag_vector.png"/>
</p>
<br>
The magnetic scattering length density is then
<p>
-<img src="dm_eq.gif"/>
+<img src="dm_eq.png"/>
</p>
<br>
where γ = -1.913 the gyromagnetic ratio, μ<sub>B</sub> is the Bohr magneton,
@@ -65,7 +65,7 @@ The possible out-coming states then are + and - states for both incident states.
- Spin-flips: (+ -) and (- +)
<br>
<p>
-<img src="gen_mag_pic.bmp"/>
+<img src="gen_mag_pic.png"/>
</p>
<br>
<br>
@@ -74,31 +74,31 @@ are φ and θ<sub>up</sub>, respectively (See Figure above).
Then, depending upon the polarization (spin) state of neutrons, the scattering length
densities , including the nuclear scattering length density (β <sub>N</sub>) are given as, for non-spin-flips,
<p>
-<img src="sld1.gif"/>
+<img src="sld1.png"/>
</p>
<br>
<br>
for spin-flips,
<p>
-<img src="sld2.gif"/>
+<img src="sld2.png"/>
</p>
<br>
<br>
where
<p>
-<img src="mxp.gif"/>
+<img src="mxp.png"/>
</p>
<p>
-<img src="myp.gif"/>
+<img src="myp.png"/>
</p>
<p>
-<img src="mzp.gif"/>
+<img src="mzp.png"/>
</p>
<p>
-<img src="mqx.gif"/>
+<img src="mqx.png"/>
</p>
<p>
-<img src="mqy.gif"/>
+<img src="mqy.png"/>
</p>
<br>
<br>
@@ -109,7 +109,7 @@ components of the magnetization vector given in the xyz lab frame.
<b>2. <a name="gui">GUI</a> </b>
<br>
<p>
-<img src="gen_gui_help.bmp"/>
+<img src="gen_gui_help.png"/>
</p>
<br>
<p>
@@ -135,7 +135,7 @@ This Generic scattering calculator also supports some pdb files without consider
so that the related parameters such as Up_*** will be ignored (see the Picture below). The calculation for fixed orientation uses (the first) Equation above resulting
in a 2D output, whileas the scattering calculation averaged over all the orientations uses the Debye equation providing a 1D output:
<p>
-<img src="gen_debye_eq.gif"/>
+<img src="gen_debye_eq.png"/>
</p>
<br>
where v<sub>j</sub>β<sub>j</sub> ≡ b<sub>j</sub> is the scattering length of the j'th atom.
diff --git a/src/sas/sasgui/perspectives/calculator/media/image_viewer_help.rst b/src/sas/sasgui/perspectives/calculator/media/image_viewer_help.rst
index d5ed5c2..b3e5fcd 100644
--- a/src/sas/sasgui/perspectives/calculator/media/image_viewer_help.rst
+++ b/src/sas/sasgui/perspectives/calculator/media/image_viewer_help.rst
@@ -33,12 +33,12 @@ Using the tool
2) Select a file and then click *Open*. If the loading is successful the image
will be displayed.
-.. image:: load_image.bmp
+.. image:: load_image.png
3) To save, print, or copy the image, or to apply a grid overlay, right-click
anywhere in the plot.
-.. image:: pic_plot.bmp
+.. image:: pic_plot.png
4. If the image is taken from a 2D detector, SasView can attempt to convert
the colour/grey scale into pseudo-intensity 2D data using
@@ -50,7 +50,7 @@ Using the tool
5. In the *Convert to Data* dialog, set the parameters relevant to the data and
then click the OK.
-.. image:: pic_convert.bmp
+.. image:: pic_convert.png
.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
diff --git a/src/sas/sasgui/perspectives/calculator/media/kiessig_calculator_help.rst b/src/sas/sasgui/perspectives/calculator/media/kiessig_calculator_help.rst
index 900a80a..37d3458 100644
--- a/src/sas/sasgui/perspectives/calculator/media/kiessig_calculator_help.rst
+++ b/src/sas/sasgui/perspectives/calculator/media/kiessig_calculator_help.rst
@@ -9,21 +9,25 @@ Kiessig Thickness Calculator Tool
Description
-----------
-This tool is approximately estimates the thickness of a layer or the diameter
-of particles from the position of the Kiessig fringe/Bragg peak in NR/SAS data
-using the relation
+This tool estimates real space dimensions from the position or spacing of
+features in recipricol space. In particular a particle of size $d$ will
+give rise to Bragg peaks with spacing $\Delta q$ according to the relation
+
+.. math::
+
+ d = 2\pi / \Delta q
+
+Similarly, the spacing between the peaks in Kiessig fringes in reflectometry
+data arise from layers of thickness $d$.
-(thickness *or* size) = 2 * |pi| / (fringe_width *or* peak position)
-
.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
Using the tool
--------------
-To get a rough thickness or particle size, simply type the fringe or peak
+To get a rough thickness or particle size, simply type the fringe or peak
position (in units of 1/|Ang|\) and click on the *Compute* button.
.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
-.. note:: This help document was last changed by Steve King, 01May2015
-
+.. note:: This help document was last changed by Paul Kienzle, 05Apr2017
\ No newline at end of file
diff --git a/src/sas/sasgui/perspectives/calculator/media/load_image.bmp b/src/sas/sasgui/perspectives/calculator/media/load_image.bmp
deleted file mode 100644
index 602e22f..0000000
Binary files a/src/sas/sasgui/perspectives/calculator/media/load_image.bmp and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/calculator/media/load_image.png b/src/sas/sasgui/perspectives/calculator/media/load_image.png
new file mode 100644
index 0000000..4cb5388
Binary files /dev/null and b/src/sas/sasgui/perspectives/calculator/media/load_image.png differ
diff --git a/src/sas/sasgui/perspectives/calculator/media/mag_vector.bmp b/src/sas/sasgui/perspectives/calculator/media/mag_vector.bmp
deleted file mode 100644
index 869a144..0000000
Binary files a/src/sas/sasgui/perspectives/calculator/media/mag_vector.bmp and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/calculator/media/mag_vector.png b/src/sas/sasgui/perspectives/calculator/media/mag_vector.png
new file mode 100644
index 0000000..03ce419
Binary files /dev/null and b/src/sas/sasgui/perspectives/calculator/media/mag_vector.png differ
diff --git a/src/sas/sasgui/perspectives/calculator/media/mqx.gif b/src/sas/sasgui/perspectives/calculator/media/mqx.gif
deleted file mode 100644
index a2f60a0..0000000
Binary files a/src/sas/sasgui/perspectives/calculator/media/mqx.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/calculator/media/mqx.png b/src/sas/sasgui/perspectives/calculator/media/mqx.png
new file mode 100644
index 0000000..e661a36
Binary files /dev/null and b/src/sas/sasgui/perspectives/calculator/media/mqx.png differ
diff --git a/src/sas/sasgui/perspectives/calculator/media/mqy.gif b/src/sas/sasgui/perspectives/calculator/media/mqy.gif
deleted file mode 100644
index db1fef2..0000000
Binary files a/src/sas/sasgui/perspectives/calculator/media/mqy.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/calculator/media/mqy.png b/src/sas/sasgui/perspectives/calculator/media/mqy.png
new file mode 100644
index 0000000..29d6c95
Binary files /dev/null and b/src/sas/sasgui/perspectives/calculator/media/mqy.png differ
diff --git a/src/sas/sasgui/perspectives/calculator/media/mxp.gif b/src/sas/sasgui/perspectives/calculator/media/mxp.gif
deleted file mode 100644
index d1d42ca..0000000
Binary files a/src/sas/sasgui/perspectives/calculator/media/mxp.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/calculator/media/mxp.png b/src/sas/sasgui/perspectives/calculator/media/mxp.png
new file mode 100644
index 0000000..9b630cf
Binary files /dev/null and b/src/sas/sasgui/perspectives/calculator/media/mxp.png differ
diff --git a/src/sas/sasgui/perspectives/calculator/media/myp.gif b/src/sas/sasgui/perspectives/calculator/media/myp.gif
deleted file mode 100644
index 87dc8ae..0000000
Binary files a/src/sas/sasgui/perspectives/calculator/media/myp.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/calculator/media/myp.png b/src/sas/sasgui/perspectives/calculator/media/myp.png
new file mode 100644
index 0000000..6ddfd2b
Binary files /dev/null and b/src/sas/sasgui/perspectives/calculator/media/myp.png differ
diff --git a/src/sas/sasgui/perspectives/calculator/media/mzp.gif b/src/sas/sasgui/perspectives/calculator/media/mzp.gif
deleted file mode 100644
index 3699f89..0000000
Binary files a/src/sas/sasgui/perspectives/calculator/media/mzp.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/calculator/media/mzp.png b/src/sas/sasgui/perspectives/calculator/media/mzp.png
new file mode 100644
index 0000000..72c476e
Binary files /dev/null and b/src/sas/sasgui/perspectives/calculator/media/mzp.png differ
diff --git a/src/sas/sasgui/perspectives/calculator/media/pic_convert.bmp b/src/sas/sasgui/perspectives/calculator/media/pic_convert.bmp
deleted file mode 100644
index a6e8c4f..0000000
Binary files a/src/sas/sasgui/perspectives/calculator/media/pic_convert.bmp and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/calculator/media/pic_convert.png b/src/sas/sasgui/perspectives/calculator/media/pic_convert.png
new file mode 100644
index 0000000..1a25b95
Binary files /dev/null and b/src/sas/sasgui/perspectives/calculator/media/pic_convert.png differ
diff --git a/src/sas/sasgui/perspectives/calculator/media/pic_plot.bmp b/src/sas/sasgui/perspectives/calculator/media/pic_plot.bmp
deleted file mode 100644
index a65ff86..0000000
Binary files a/src/sas/sasgui/perspectives/calculator/media/pic_plot.bmp and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/calculator/media/pic_plot.png b/src/sas/sasgui/perspectives/calculator/media/pic_plot.png
new file mode 100644
index 0000000..095f88d
Binary files /dev/null and b/src/sas/sasgui/perspectives/calculator/media/pic_plot.png differ
diff --git a/src/sas/sasgui/perspectives/calculator/media/q.gif b/src/sas/sasgui/perspectives/calculator/media/q.gif
deleted file mode 100644
index 9078ae4..0000000
Binary files a/src/sas/sasgui/perspectives/calculator/media/q.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/calculator/media/q.png b/src/sas/sasgui/perspectives/calculator/media/q.png
new file mode 100644
index 0000000..34c03be
Binary files /dev/null and b/src/sas/sasgui/perspectives/calculator/media/q.png differ
diff --git a/src/sas/sasgui/perspectives/calculator/media/resolution_calculator_help.rst b/src/sas/sasgui/perspectives/calculator/media/resolution_calculator_help.rst
index 52e4611..7817eb4 100644
--- a/src/sas/sasgui/perspectives/calculator/media/resolution_calculator_help.rst
+++ b/src/sas/sasgui/perspectives/calculator/media/resolution_calculator_help.rst
@@ -9,8 +9,8 @@ Q Resolution Estimator Tool
Description
-----------
-This tool is approximately estimates the resolution of Q from SAS instrumental
-parameter values assuming that the detector is flat and normal to the
+This tool is approximately estimates the resolution of $Q$ from SAS instrumental
+parameter values assuming that the detector is flat and normal to the
incident beam.
.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
@@ -22,49 +22,49 @@ Using the tool
2) Select the source (Neutron or Photon) and source type (Monochromatic or TOF).
- *NOTE! The computational difference between the sources is only the
+ *NOTE! The computational difference between the sources is only the
gravitational contribution due to the mass of the particles.*
-3) Change the default values of the instrumental parameters as required. Be
+3) Change the default values of the instrumental parameters as required. Be
careful to note that distances are specified in cm!
-4) Enter values for the source wavelength(s), |lambda|\ , and its spread (= FWHM/|lambda|\ ).
-
- For monochromatic sources, the inputs are just one value. For TOF sources,
- the minimum and maximum values should be separated by a '-' to specify a
+4) Enter values for the source wavelength(s), $\lambda$, and its spread (= $\text{FWHM}/\lambda$).
+
+ For monochromatic sources, the inputs are just one value. For TOF sources,
+ the minimum and maximum values should be separated by a '-' to specify a
range.
-
- Optionally, the wavelength (BUT NOT of the wavelength spread) can be extended
- by adding '; nn' where the 'nn' specifies the number of the bins for the
- numerical integration. The default value is nn = 10. The same number of bins
+
+ Optionally, the wavelength (BUT NOT of the wavelength spread) can be extended
+ by adding '; nn' where the 'nn' specifies the number of the bins for the
+ numerical integration. The default value is nn = 10. The same number of bins
will be used for the corresponding wavelength spread.
-5) For TOF, the default wavelength spectrum is flat. A custom spectral
- distribution file (2-column text: wavelength (|Ang|\) vs Intensity) can also
+5) For TOF, the default wavelength spectrum is flat. A custom spectral
+ distribution file (2-column text: wavelength (|Ang|\) vs Intensity) can also
be loaded by selecting *Add new* in the combo box.
-6) When ready, click the *Compute* button. Depending on the computation the
+6) When ready, click the *Compute* button. Depending on the computation the
calculation time will vary.
-7) 1D and 2D dQ values will be displayed at the bottom of the panel, and a 2D
- resolution weight distribution (a 2D elliptical Gaussian function) will also
- be displayed in the plot panel even if the Q inputs are outside of the
+7) 1D and 2D $dQ$ values will be displayed at the bottom of the panel, and a 2D
+ resolution weight distribution (a 2D elliptical Gaussian function) will also
+ be displayed in the plot panel even if the $Q$ inputs are outside of the
detector limit (the red lines indicate the limits of the detector).
-
- TOF only: green lines indicate the limits of the maximum Q range accessible
+
+ TOF only: green lines indicate the limits of the maximum $Q$ range accessible
for the longest wavelength due to the size of the detector.
-
- Note that the effect from the beam block/stop is ignored, so in the small Q
- region near the beam block/stop
- [ie., Q < 2. |pi|\ .(beam block diameter) / (sample-to-detector distance) / |lambda|\_min]
+ Note that the effect from the beam block/stop is ignored, so in the small $Q$
+ region near the beam block/stop
+
+ [i.e., $Q < (2 \pi \cdot \text{beam block diameter}) / (\text{sample-to-detector distance} \cdot \lambda_\text{min})$]
the variance is slightly under estimated.
-8) A summary of the calculation is written to the SasView *Console* at the
+8) A summary of the calculation is written to the SasView *Console* at the
bottom of the main SasView window.
-.. image:: resolution_tutor.gif
+.. image:: resolution_tutor.png
.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
@@ -73,29 +73,29 @@ Theory
The scattering wave transfer vector is by definition
-.. image:: q.gif
+.. image:: q.png
-In the small-angle limit, the variance of Q is to a first-order
+In the small-angle limit, the variance of $Q$ is to a first-order
approximation
-.. image:: sigma_q.gif
+.. image:: sigma_q.png
The geometric and gravitational contributions can then be summarised as
-.. image:: sigma_table.gif
+.. image:: sigma_table.png
-Finally, a Gaussian function is used to describe the 2D weighting distribution
-of the uncertainty in Q.
+Finally, a Gaussian function is used to describe the 2D weighting distribution
+of the uncertainty in $Q$.
.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
References
----------
-D.F.R. Mildner and J.M. Carpenter
+D.F.R. Mildner and J.M. Carpenter
*J. Appl. Cryst.* 17 (1984) 249-256
-D.F.R. Mildner, J.M. Carpenter and D.L. Worcester
+D.F.R. Mildner, J.M. Carpenter and D.L. Worcester
*J. Appl. Cryst.* 19 (1986) 311-319
.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
diff --git a/src/sas/sasgui/perspectives/calculator/media/resolution_tutor.gif b/src/sas/sasgui/perspectives/calculator/media/resolution_tutor.gif
deleted file mode 100644
index caea076..0000000
Binary files a/src/sas/sasgui/perspectives/calculator/media/resolution_tutor.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/calculator/media/resolution_tutor.png b/src/sas/sasgui/perspectives/calculator/media/resolution_tutor.png
new file mode 100644
index 0000000..163c120
Binary files /dev/null and b/src/sas/sasgui/perspectives/calculator/media/resolution_tutor.png differ
diff --git a/src/sas/sasgui/perspectives/calculator/media/sas_calculator_help.rst b/src/sas/sasgui/perspectives/calculator/media/sas_calculator_help.rst
index 8b13304..df2e6be 100644
--- a/src/sas/sasgui/perspectives/calculator/media/sas_calculator_help.rst
+++ b/src/sas/sasgui/perspectives/calculator/media/sas_calculator_help.rst
@@ -18,118 +18,120 @@ handle both nuclear and magnetic contributions to the scattering.
Theory
------
-In general, a particle with a volume *V* can be described by an ensemble
-containing *N* 3-dimensional rectangular pixels where each pixel is much
-smaller than *V*.
+In general, a particle with a volume $V$ can be described by an ensemble
+containing $N$ 3-dimensional rectangular pixels where each pixel is much
+smaller than $V$.
-Assuming that all the pixel sizes are the same, the elastic scattering
+Assuming that all the pixel sizes are the same, the elastic scattering
intensity from the particle is
-.. image:: gen_i.gif
+.. image:: gen_i.png
Equation 1.
-where |beta|\ :sub:`j` and *r*\ :sub:`j` are the scattering length density and
-the position of the j'th pixel respectively.
+where $\beta_j$ and $r_j$ are the scattering length density and
+the position of the $j^\text{th}$ pixel respectively.
-The total volume *V*
+The total volume $V$
-.. image:: v_j.gif
+.. math::
-for |beta|\ :sub:`j` |noteql|\0 where *v*\ :sub:`j` is the volume of the j'th
-pixel (or the j'th natural atomic volume (= atomic mass / (natural molar
+ V = \sum_j^N v_j
+
+for $\beta_j \ne 0$ where $v_j$ is the volume of the $j^\text{th}$
+pixel (or the $j^\text{th}$ natural atomic volume (= atomic mass / (natural molar
density * Avogadro number) for the atomic structures).
-*V* can be corrected by users. This correction is useful especially for an
-atomic structure (such as taken from a PDB file) to get the right normalization.
+$V$ can be corrected by users. This correction is useful especially for an
+atomic structure (such as taken from a PDB file) to get the right normalization.
-*NOTE!* |beta|\ :sub:`j` *displayed in the GUI may be incorrect but this will not
+*NOTE! $\beta_j$ displayed in the GUI may be incorrect but this will not
affect the scattering computation if the correction of the total volume V is made.*
-The scattering length density (SLD) of each pixel, where the SLD is uniform, is
-a combination of the nuclear and magnetic SLDs and depends on the spin states
+The scattering length density (SLD) of each pixel, where the SLD is uniform, is
+a combination of the nuclear and magnetic SLDs and depends on the spin states
of the neutrons as follows.
Magnetic Scattering
^^^^^^^^^^^^^^^^^^^
-For magnetic scattering, only the magnetization component, *M*\ :sub:`perp`\ ,
-perpendicular to the scattering vector *Q* contributes to the magnetic
+For magnetic scattering, only the magnetization component, $M_\perp$,
+perpendicular to the scattering vector $Q$ contributes to the magnetic
scattering length.
-.. image:: mag_vector.bmp
+.. image:: mag_vector.png
The magnetic scattering length density is then
-.. image:: dm_eq.gif
+.. image:: dm_eq.png
-where the gyromagnetic ratio |gamma| = -1.913, |mu|\ :sub:`B` is the Bohr
-magneton, *r*\ :sub:`0` is the classical radius of electron, and |sigma| is the
+where the gyromagnetic ratio is $\gamma = -1.913$, $\mu_B$ is the Bohr
+magneton, $r_0$ is the classical radius of electron, and $\sigma$ is the
Pauli spin.
For a polarized neutron, the magnetic scattering is depending on the spin states.
-Let us consider that the incident neutrons are polarised both parallel (+) and
-anti-parallel (-) to the x' axis (see below). The possible states after
-scattering from the sample are then
+Let us consider that the incident neutrons are polarised both parallel (+) and
+anti-parallel (-) to the x' axis (see below). The possible states after
+scattering from the sample are then
* Non-spin flips: (+ +) and (- -)
* Spin flips: (+ -) and (- +)
-.. image:: gen_mag_pic.bmp
+.. image:: gen_mag_pic.png
-Now let us assume that the angles of the *Q* vector and the spin-axis (x')
-to the x-axis are |phi| and |theta|\ :sub:`up` respectively (see above). Then,
-depending upon the polarization (spin) state of neutrons, the scattering
-length densities, including the nuclear scattering length density (|beta|\ :sub:`N`\ )
+Now let us assume that the angles of the *Q* vector and the spin-axis (x')
+to the x-axis are $\phi$ and $\theta_\text{up}$ respectively (see above). Then,
+depending upon the polarization (spin) state of neutrons, the scattering
+length densities, including the nuclear scattering length density ($\beta_N$)
are given as
* for non-spin-flips
- .. image:: sld1.gif
+ .. image:: sld1.png
* for spin-flips
- .. image:: sld2.gif
+ .. image:: sld2.png
where
-.. image:: mxp.gif
+.. image:: mxp.png
-.. image:: myp.gif
+.. image:: myp.png
-.. image:: mzp.gif
+.. image:: mzp.png
-.. image:: mqx.gif
+.. image:: mqx.png
-.. image:: mqy.gif
+.. image:: mqy.png
-Here the *M0*\ :sub:`x`\ , *M0*\ :sub:`y` and *M0*\ :sub:`z` are the x, y and z
-components of the magnetisation vector in the laboratory xyz frame.
+Here the $M0_x$, $M0_y$ and $M0_z$ are the $x$, $y$ and $z$
+components of the magnetisation vector in the laboratory $xyz$ frame.
.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
Using the tool
--------------
-.. image:: gen_gui_help.bmp
+.. image:: gen_gui_help.png
-After computation the result will appear in the *Theory* box in the SasView
+After computation the result will appear in the *Theory* box in the SasView
*Data Explorer* panel.
-*Up_frac_in* and *Up_frac_out* are the ratio
+*Up_frac_in* and *Up_frac_out* are the ratio
(spin up) / (spin up + spin down)
-
+
of neutrons before the sample and at the analyzer, respectively.
-*NOTE 1. The values of* Up_frac_in *and* Up_frac_out *must be in the range
+*NOTE 1. The values of* Up_frac_in *and* Up_frac_out *must be in the range
0.0 to 1.0. Both values are 0.5 for unpolarized neutrons.*
-*NOTE 2. This computation is totally based on the pixel (or atomic) data fixed
+*NOTE 2. This computation is totally based on the pixel (or atomic) data fixed
in xyz coordinates. No angular orientational averaging is considered.*
-*NOTE 3. For the nuclear scattering length density, only the real component
+*NOTE 3. For the nuclear scattering length density, only the real component
is taken account.*
.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
@@ -138,17 +140,17 @@ Using PDB/OMF or SLD files
--------------------------
The SANS Calculator tool can read some PDB, OMF or SLD files but ignores
-polarized/magnetic scattering when doing so, thus related parameters such as
+polarized/magnetic scattering when doing so, thus related parameters such as
*Up_frac_in*, etc, will be ignored.
-The calculation for fixed orientation uses Equation 1 above resulting in a 2D
-output, whereas the scattering calculation averaged over all the orientations
+The calculation for fixed orientation uses Equation 1 above resulting in a 2D
+output, whereas the scattering calculation averaged over all the orientations
uses the Debye equation below providing a 1D output
-.. image:: gen_debye_eq.gif
+.. image:: gen_debye_eq.png
-where *v*\ :sub:`j` |beta|\ :sub:`j` |equiv| *b*\ :sub:`j` is the scattering
-length of the j'th atom. The calculation output is passed to the *Data Explorer*
+where $v_j \beta_j \equiv b_j$ is the scattering
+length of the $j^\text{th}$ atom. The calculation output is passed to the *Data Explorer*
for further use.
.. image:: pdb_combo.jpg
diff --git a/src/sas/sasgui/perspectives/calculator/media/sigma_q.gif b/src/sas/sasgui/perspectives/calculator/media/sigma_q.gif
deleted file mode 100644
index 1c1b062..0000000
Binary files a/src/sas/sasgui/perspectives/calculator/media/sigma_q.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/calculator/media/sigma_q.png b/src/sas/sasgui/perspectives/calculator/media/sigma_q.png
new file mode 100644
index 0000000..c956774
Binary files /dev/null and b/src/sas/sasgui/perspectives/calculator/media/sigma_q.png differ
diff --git a/src/sas/sasgui/perspectives/calculator/media/sigma_table.gif b/src/sas/sasgui/perspectives/calculator/media/sigma_table.gif
deleted file mode 100644
index 1273bf1..0000000
Binary files a/src/sas/sasgui/perspectives/calculator/media/sigma_table.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/calculator/media/sigma_table.png b/src/sas/sasgui/perspectives/calculator/media/sigma_table.png
new file mode 100644
index 0000000..4f79d75
Binary files /dev/null and b/src/sas/sasgui/perspectives/calculator/media/sigma_table.png differ
diff --git a/src/sas/sasgui/perspectives/calculator/media/sld1.gif b/src/sas/sasgui/perspectives/calculator/media/sld1.gif
deleted file mode 100644
index 591aa0b..0000000
Binary files a/src/sas/sasgui/perspectives/calculator/media/sld1.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/calculator/media/sld1.png b/src/sas/sasgui/perspectives/calculator/media/sld1.png
new file mode 100644
index 0000000..a19e698
Binary files /dev/null and b/src/sas/sasgui/perspectives/calculator/media/sld1.png differ
diff --git a/src/sas/sasgui/perspectives/calculator/media/sld2.gif b/src/sas/sasgui/perspectives/calculator/media/sld2.gif
deleted file mode 100644
index c868742..0000000
Binary files a/src/sas/sasgui/perspectives/calculator/media/sld2.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/calculator/media/sld2.png b/src/sas/sasgui/perspectives/calculator/media/sld2.png
new file mode 100644
index 0000000..cb937eb
Binary files /dev/null and b/src/sas/sasgui/perspectives/calculator/media/sld2.png differ
diff --git a/src/sas/sasgui/perspectives/calculator/media/sld_calculator_help.rst b/src/sas/sasgui/perspectives/calculator/media/sld_calculator_help.rst
index 5a75548..d939de9 100644
--- a/src/sas/sasgui/perspectives/calculator/media/sld_calculator_help.rst
+++ b/src/sas/sasgui/perspectives/calculator/media/sld_calculator_help.rst
@@ -9,22 +9,24 @@ SLD Calculator Tool
Description
-----------
-The neutron scattering length density (SLD) is defined as
+The neutron scattering length density (SLD, $\beta_N$) is defined as
- SLD = (b_c1 + b_c2 + ... + b_cn) / Vm
+.. math::
-where b_ci is the bound coherent scattering length of ith of n atoms in a molecule
-with the molecular volume Vm
+ \beta_N = (b_{c1} + b_{c2} + ... + b_{cn}) / V_m
+
+where $b_{ci}$ is the bound coherent scattering length of ith of n atoms in a molecule
+with the molecular volume $V_m$.
.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
Specifying the Compound Name
----------------------------
-To calculate scattering length densities enter the empirical formula of a
+To calculate scattering length densities enter the empirical formula of a
compound and its mass density and click "Calculate".
-Entering a wavelength value is optional (a default value of 6.0 |Ang| will
+Entering a wavelength value is optional (a default value of 6.0 |Ang| will
be used).
TIPS!
@@ -37,20 +39,20 @@ TIPS!
* Parentheses can be nested, such as "(CaCO3(H2O)6)1".
-* Isotopes are represented by their atomic number in *square brackets*, such
+* Isotopes are represented by their atomic number in *square brackets*, such
as "CaCO[18]3+6H2O", H[1], or H[2].
* Numbers of atoms can be integer or decimal, such as "CaCO3+(3HO0.5)2".
-* The SLD of mixtures can be calculated as well. For example, for a 70-30
+* The SLD of mixtures can be calculated as well. For example, for a 70-30
mixture of H2O/D2O write "H14O7+D6O3" or more simply "H7D3O5" (i.e. this says
7 hydrogens, 3 deuteriums, and 5 oxygens) and enter a mass density calculated
on the percentages of H2O and D2O.
-* Type "C[13]6 H[2]12 O[18]6" for C(13)6H(2)12O(18)6 (6 Carbon-13 atoms, 12
+* Type "C[13]6 H[2]12 O[18]6" for C(13)6H(2)12O(18)6 (6 Carbon-13 atoms, 12
deuterium atoms, and 6 Oxygen-18 atoms).
-
+
.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
-.. note:: This help document was last changed by Steve King, 01May2015
+.. note:: This help document was last changed by Paul Kienzle, 05Apr2017
diff --git a/src/sas/sasgui/perspectives/calculator/media/slit_calculator_help.rst b/src/sas/sasgui/perspectives/calculator/media/slit_calculator_help.rst
index 446e31c..5e95d71 100644
--- a/src/sas/sasgui/perspectives/calculator/media/slit_calculator_help.rst
+++ b/src/sas/sasgui/perspectives/calculator/media/slit_calculator_help.rst
@@ -10,12 +10,11 @@ Slit Size Calculator Tool
Description
-----------
-This tool enables X-ray users to calculate the slit size (FWHM/2) for smearing
+This tool enables X-ray users to calculate the slit size (FWHM/2) for smearing
based on their half beam profile data.
*NOTE! Whilst it may have some more generic applicability, the calculator has
-only been tested with beam profile data from Anton-Paar SAXSess*\ |TM|\
-*software.*
+only been tested with beam profile data from Anton-Paar SAXSess:sup:`TM` software.*
.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
@@ -26,13 +25,13 @@ Using the tool
2) Load a beam profile file in the *Data* field using the *Browse* button.
- *NOTE! To see an example of the beam profile file format, visit the file
+ *NOTE! To see an example of the beam profile file format, visit the file
beam profile.DAT in your {installation_directory}/SasView/test folder.*
-3) Once a data is loaded, the slit size is automatically computed and displayed
+3) Once a data is loaded, the slit size is automatically computed and displayed
in the tool window.
-*NOTE! The beam profile file does not carry any information about the units of
+*NOTE! The beam profile file does not carry any information about the units of
the Q data. This calculator assumes the data has units of 1/\ |Ang|\ . If the
data is not in these units it must be manually converted beforehand.*
diff --git a/src/sas/sasgui/perspectives/calculator/media/v_j.gif b/src/sas/sasgui/perspectives/calculator/media/v_j.gif
deleted file mode 100644
index 0d521ac..0000000
Binary files a/src/sas/sasgui/perspectives/calculator/media/v_j.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/calculator/model_editor.py b/src/sas/sasgui/perspectives/calculator/model_editor.py
index 7a06677..a2f164d 100644
--- a/src/sas/sasgui/perspectives/calculator/model_editor.py
+++ b/src/sas/sasgui/perspectives/calculator/model_editor.py
@@ -1,1600 +1,1167 @@
-'''
-This module provides three model editor classes: the composite model editor,
-the easy editor which provides a simple interface with tooltip help to enter
-the parameters of the model and their default value and a panel to input a
-function of y (usually the intensity). It also provides a drop down of
-standard available math functions. Finally a full python editor panel for
-complete customization is provided.
-
-:TODO the writing of the file and name checking (and maybe some other
-functions?) should be moved to a computational module which could be called
-from a python script. Basically one just needs to pass the name,
-description text and function text (or in the case of the composite editor
-the names of the first and second model and the operator to be used).
-'''
-
-################################################################################
-#This software was developed by the University of Tennessee as part of the
-#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
-#project funded by the US National Science Foundation.
-#
-#See the license text in license.txt
-#
-#copyright 2009, University of Tennessee
-################################################################################
-import wx
-import sys
-import os
-import math
-import re
-import logging
-from wx.py.editwindow import EditWindow
-from sas.sasgui.guiframe.documentation_window import DocumentationWindow
-from .pyconsole import show_model_output, check_model
-
-
-if sys.platform.count("win32") > 0:
- FONT_VARIANT = 0
- PNL_WIDTH = 450
- PNL_HEIGHT = 320
-else:
- FONT_VARIANT = 1
- PNL_WIDTH = 590
- PNL_HEIGHT = 350
-M_NAME = 'Model'
-EDITOR_WIDTH = 800
-EDITOR_HEIGTH = 735
-PANEL_WIDTH = 500
-_BOX_WIDTH = 55
-
-def _delete_file(path):
- """
- Delete file in the path
- """
- try:
- os.remove(path)
- except:
- raise
-
-
-class TextDialog(wx.Dialog):
- """
- Dialog for easy custom composite models. Provides a wx.Dialog panel
- to choose two existing models (including pre-existing Plugin Models which
- may themselves be composite models) as well as an operation on those models
- (add or multiply) the resulting model will add a scale parameter for summed
- models and a background parameter for a multiplied model.
-
- The user also gives a brief help for the model in a description box and
- must provide a unique name which is verified as unique before the new
- model is saved.
-
- This Dialog pops up for the user when they press 'Sum|Multi(p1,p2)' under
- 'Plugin Model Operations' under 'Fitting' menu. This is currently called as
- a Modal Dialog.
-
- :TODO the build in compiler currently balks at when it tries to import
- a model whose name contains spaces or symbols (such as + ... underscore
- should be fine). Have fixed so the editor cannot save such a file name
- but if a file is dropped in the plugin directory from outside this class
- will create a file that cannot be compiled. Should add the check to
- the write method or to the on_modelx method.
-
- - PDB:April 5, 2015
- """
- def __init__(self, parent=None, base=None, id=None, title='',
- model_list=[], plugin_dir=None):
- """
- This class is run when instatiated. The __init__ initializes and
- calls the internal methods necessary. On exiting the wx.Dialog
- window should be destroyed.
- """
- wx.Dialog.__init__(self, parent=parent, id=id,
- title=title, size=(PNL_WIDTH, PNL_HEIGHT))
- self.parent = base
- #Font
- self.SetWindowVariant(variant=FONT_VARIANT)
- # default
- self.overwrite_name = False
- self.plugin_dir = plugin_dir
- self.model_list = model_list
- self.model1_string = "sphere"
- self.model2_string = "cylinder"
- self.name = 'Sum' + M_NAME
- self.factor = 'scale_factor'
- self._notes = ''
- self._operator = '+'
- self._operator_choice = None
- self.explanation = ''
- self.explanationctr = None
- self.type = None
- self.name_sizer = None
- self.name_tcl = None
- self.desc_sizer = None
- self.desc_tcl = None
- self._selection_box = None
- self.model1 = None
- self.model2 = None
- self.static_line_1 = None
- self.ok_button = None
- self.close_button = None
- self._msg_box = None
- self.msg_sizer = None
- self.fname = None
- self.cm_list = None
- self.is_p1_custom = False
- self.is_p2_custom = False
- self._build_sizer()
- self.model1_name = str(self.model1.GetValue())
- self.model2_name = str(self.model2.GetValue())
- self.good_name = True
- self.fill_oprator_combox()
-
- def _layout_name(self):
- """
- Do the layout for file/function name related widgets
- """
- #container for new model name input
- self.name_sizer = wx.BoxSizer(wx.HORIZONTAL)
-
- #set up label and input box with tool tip and event handling
- name_txt = wx.StaticText(self, -1, 'Function Name : ')
- self.name_tcl = wx.TextCtrl(self, -1, value='MySumFunction')
- self.name_tcl.Bind(wx.EVT_TEXT_ENTER, self.on_change_name)
- hint_name = "Unique Sum/Multiply Model Function Name."
- self.name_tcl.SetToolTipString(hint_name)
-
- self.name_sizer.AddMany([(name_txt, 0, wx.LEFT | wx.TOP, 10),
- (self.name_tcl, -1,
- wx.EXPAND | wx.RIGHT | wx.TOP | wx.BOTTOM,
- 10)])
-
-
- def _layout_description(self):
- """
- Do the layout for description related widgets
- """
- #container for new model description input
- self.desc_sizer = wx.BoxSizer(wx.HORIZONTAL)
-
- #set up description label and input box with tool tip and event handling
- desc_txt = wx.StaticText(self, -1, 'Description (optional) : ')
- self.desc_tcl = wx.TextCtrl(self, -1)
- hint_desc = "Write a short description of this model function."
- self.desc_tcl.SetToolTipString(hint_desc)
-
- self.desc_sizer.AddMany([(desc_txt, 0, wx.LEFT | wx.TOP, 10),
- (self.desc_tcl, -1,
- wx.EXPAND | wx.RIGHT | wx.TOP | wx.BOTTOM,
- 10)])
-
-
- def _layout_model_selection(self):
- """
- Do the layout for model selection related widgets
- """
- box_width = 195 # combobox width
-
- #First set up main sizer for the selection
- selection_box_title = wx.StaticBox(self, -1, 'Select',
- size=(PNL_WIDTH - 30, 70))
- self._selection_box = wx.StaticBoxSizer(selection_box_title,
- wx.VERTICAL)
-
- #Next create the help labels for the model selection
- select_help_box = wx.BoxSizer(wx.HORIZONTAL)
- model_string = " Model%s (p%s):"
- select_help_box.Add(wx.StaticText(self, -1, model_string % (1, 1)),
- 0, 0)
- select_help_box.Add((box_width - 25, 10), 0, 0)
- select_help_box.Add(wx.StaticText(self, -1, model_string % (2, 2)),
- 0, 0)
- self._selection_box.Add(select_help_box, 0, 0)
-
- #Next create the actual selection box with 3 combo boxes
- selection_box_choose = wx.BoxSizer(wx.HORIZONTAL)
-
- self.model1 = wx.ComboBox(self, -1, style=wx.CB_READONLY)
- wx.EVT_COMBOBOX(self.model1, -1, self.on_model1)
- self.model1.SetMinSize((box_width * 5 / 6, -1))
- self.model1.SetToolTipString("model1")
-
- self._operator_choice = wx.ComboBox(self, -1, size=(50, -1),
- style=wx.CB_READONLY)
- wx.EVT_COMBOBOX(self._operator_choice, -1, self.on_select_operator)
- operation_tip = "Add: +, Multiply: * "
- self._operator_choice.SetToolTipString(operation_tip)
-
- self.model2 = wx.ComboBox(self, -1, style=wx.CB_READONLY)
- wx.EVT_COMBOBOX(self.model2, -1, self.on_model2)
- self.model2.SetMinSize((box_width * 5 / 6, -1))
- self.model2.SetToolTipString("model2")
- self._set_model_list()
-
- selection_box_choose.Add(self.model1, 0, 0)
- selection_box_choose.Add((15, 10))
- selection_box_choose.Add(self._operator_choice, 0, 0)
- selection_box_choose.Add((15, 10))
- selection_box_choose.Add(self.model2, 0, 0)
- # add some space between labels and selection
- self._selection_box.Add((20, 5), 0, 0)
- self._selection_box.Add(selection_box_choose, 0, 0)
-
- def _build_sizer(self):
- """
- Build GUI with calls to _layout_name, _layout Description
- and _layout_model_selection which each build a their portion of the
- GUI.
- """
- mainsizer = wx.BoxSizer(wx.VERTICAL) # create main sizer for dialog
-
- # build fromm top by calling _layout_name and _layout_description
- # and adding to main sizer
- self._layout_name()
- mainsizer.Add(self.name_sizer, 0, wx.EXPAND)
- self._layout_description()
- mainsizer.Add(self.desc_sizer, 0, wx.EXPAND)
-
- # Add an explanation of dialog (short help)
- self.explanationctr = wx.StaticText(self, -1, self.explanation)
- self.fill_explanation_helpstring(self._operator)
- mainsizer.Add(self.explanationctr, 0, wx.LEFT | wx.EXPAND, 15)
-
- # Add the selection box stuff with border and labels built
- # by _layout_model_selection
- self._layout_model_selection()
- mainsizer.Add(self._selection_box, 0, wx.LEFT, 15)
-
- # Add a space and horizontal line before the notification
- #messages and the buttons at the bottom
- mainsizer.Add((10, 10))
- self.static_line_1 = wx.StaticLine(self, -1)
- mainsizer.Add(self.static_line_1, 0, wx.EXPAND, 10)
-
- # Add action status notification line (null at startup)
- self._msg_box = wx.StaticText(self, -1, self._notes)
- self.msg_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.msg_sizer.Add(self._msg_box, 0, wx.LEFT, 0)
- mainsizer.Add(self.msg_sizer, 0,
- wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE | wx.BOTTOM, 10)
-
- # Finally add the buttons (apply and close) on the bottom
- # Eventually need to add help here
- self.ok_button = wx.Button(self, wx.ID_OK, 'Apply')
- _app_tip = "Save the new Model."
- self.ok_button.SetToolTipString(_app_tip)
- self.ok_button.Bind(wx.EVT_BUTTON, self.check_name)
- self.help_button = wx.Button(self, -1, 'HELP')
- _app_tip = "Help on composite model creation."
- self.help_button.SetToolTipString(_app_tip)
- self.help_button.Bind(wx.EVT_BUTTON, self.on_help)
- self.close_button = wx.Button(self, wx.ID_CANCEL, 'Close')
- sizer_button = wx.BoxSizer(wx.HORIZONTAL)
- sizer_button.AddMany([((20, 20), 1, 0),
- (self.ok_button, 0, 0),
- (self.help_button, 0, 0),
- (self.close_button, 0, wx.LEFT | wx.RIGHT, 10)])
- mainsizer.Add(sizer_button, 0, wx.EXPAND | wx.BOTTOM | wx.TOP, 10)
-
- self.SetSizer(mainsizer)
- self.Centre()
-
- def on_change_name(self, event=None):
- """
- Change name
- """
- if event is not None:
- event.Skip()
- self.name_tcl.SetBackgroundColour('white')
- self.Refresh()
-
- def check_name(self, event=None):
- """
- Check that proposed new model name is a valid Python module name
- and that it does not already exist. If not show error message and
- pink background in text box else call on_apply
-
- :TODO this should be separated out from the GUI code. For that we
- need to pass it the name (or if we want to keep the default name
- option also need to pass the self._operator attribute) We just need
- the function to return an error code that the name is good or if
- not why (not a valid name, name exists already). The rest of the
- error handling should be done in this module. so on_apply would then
- start by checking the name and then either raise errors or do the
- deed.
- """
- #Get the function/file name
- mname = M_NAME
- self.on_change_name(None)
- title = self.name_tcl.GetValue().lstrip().rstrip()
- if title == '':
- text = self._operator
- if text.count('+') > 0:
- mname = 'Sum'
- else:
- mname = 'Multi'
- mname += M_NAME
- title = mname
- self.name = title
- t_fname = title + '.py'
-
- #First check if the name is a valid Python name
- if re.match('^[A-Za-z0-9_]*$', title):
- self.good_name = True
- else:
- self.good_name = False
- msg = ("%s is not a valid Python name. Only alphanumeric \n" \
- "and underscore allowed" % self.name)
-
- #Now check if the name already exists
- if not self.overwrite_name and self.good_name:
- #Create list of existing model names for comparison
- list_fnames = os.listdir(self.plugin_dir)
- # fake existing regular model name list
- m_list = [model + ".py" for model in self.model_list]
- list_fnames.append(m_list)
- if t_fname in list_fnames and title != mname:
- self.good_name = False
- msg = "Name exists already."
-
- if self.good_name == False:
- self.name_tcl.SetBackgroundColour('pink')
- info = 'Error'
- wx.MessageBox(msg, info)
- self._notes = msg
- color = 'red'
- self._msg_box.SetLabel(msg)
- self._msg_box.SetForegroundColour(color)
- return self.good_name
- self.fname = os.path.join(self.plugin_dir, t_fname)
- s_title = title
- if len(title) > 20:
- s_title = title[0:19] + '...'
- self._notes = "Model function (%s) has been set! \n" % str(s_title)
- self.good_name = True
- self.on_apply(self.fname)
- return self.good_name
-
- def on_apply(self, path):
- """
- This method is a misnomer - it is not bound to the apply button
- event. Instead the apply button event goes to check_name which
- then calls this method if the name of the new file is acceptable.
-
- :TODO this should be bound to the apply button. The first line
- should call the check_name method which itself should be in another
- module separated from the the GUI modules.
- """
- self.name_tcl.SetBackgroundColour('white')
- try:
- label = self.get_textnames()
- fname = path
- name1 = label[0]
- name2 = label[1]
- self.write_string(fname, name1, name2)
- success = show_model_output(self, fname)
- if success:
- self.parent.update_custom_combo()
- msg = self._notes
- info = 'Info'
- color = 'blue'
- except:
- msg = "Easy Sum/Multipy Plugin: Error occurred..."
- info = 'Error'
- color = 'red'
- self._msg_box.SetLabel(msg)
- self._msg_box.SetForegroundColour(color)
- if self.parent.parent != None:
- from sas.sasgui.guiframe.events import StatusEvent
- wx.PostEvent(self.parent.parent, StatusEvent(status=msg,
- info=info))
-
- def on_help(self, event):
- """
- Bring up the Composite Model Editor Documentation whenever
- the HELP button is clicked.
-
- Calls DocumentationWindow with the path of the location within the
- documentation tree (after /doc/ ....". Note that when using old
- versions of Wx (before 2.9) and thus not the release version of
- installers, the help comes up at the top level of the file as
- webbrowser does not pass anything past the # to the browser when it is
- running "file:///...."
-
- :param evt: Triggers on clicking the help button
- """
-
- _TreeLocation = "user/sasgui/perspectives/fitting/fitting_help.html"
- _PageAnchor = "#sum-multi-p1-p2"
- _doc_viewer = DocumentationWindow(self, -1, _TreeLocation, _PageAnchor,
- "Composite Model Editor Help")
-
- def _set_model_list(self):
- """
- Set the list of models
- """
- # list of model names
- # get regular models
- main_list = self.model_list
- # get custom models
- self.update_cm_list()
- # add custom models to model list
- for name in self.cm_list:
- if name not in main_list:
- main_list.append(name)
-
- if len(main_list) > 1:
- main_list.sort()
- for idx in range(len(main_list)):
- self.model1.Append(str(main_list[idx]), idx)
- self.model2.Append(str(main_list[idx]), idx)
- self.model1.SetStringSelection(self.model1_string)
- self.model2.SetStringSelection(self.model2_string)
-
- def update_cm_list(self):
- """
- Update custom model list
- """
- cm_list = []
- al_list = os.listdir(self.plugin_dir)
- for c_name in al_list:
- if c_name.split('.')[-1] == 'py' and \
- c_name.split('.')[0] != '__init__':
- name = str(c_name.split('.')[0])
- cm_list.append(name)
- self.cm_list = cm_list
-
- def on_model1(self, event):
- """
- Set model1
- """
- event.Skip()
- self.update_cm_list()
- self.model1_name = str(self.model1.GetValue())
- self.model1_string = self.model1_name
- if self.model1_name in self.cm_list:
- self.is_p1_custom = True
- else:
- self.is_p1_custom = False
-
- def on_model2(self, event):
- """
- Set model2
- """
- event.Skip()
- self.update_cm_list()
- self.model2_name = str(self.model2.GetValue())
- self.model2_string = self.model2_name
- if self.model2_name in self.cm_list:
- self.is_p2_custom = True
- else:
- self.is_p2_custom = False
-
- def on_select_operator(self, event=None):
- """
- On Select an Operator
- """
- # For Mac
- if event != None:
- event.Skip()
- item = event.GetEventObject()
- text = item.GetValue()
- self.fill_explanation_helpstring(text)
-
- def fill_explanation_helpstring(self, operator):
- """
- Choose the equation to use depending on whether we now have
- a sum or multiply model then create the appropriate string
- """
-
- name = ''
-
- if operator == '*':
- name = 'Multi'
- factor = 'BackGround'
- f_oper = '+'
- else:
- name = 'Sum'
- factor = 'scale_factor'
- f_oper = '*'
-
- self.factor = factor
- self._operator = operator
- self.explanation = " Plugin Model = %s %s (model1 %s model2)\n" % \
- (self.factor, f_oper, self._operator)
- self.explanationctr.SetLabel(self.explanation)
- self.name = name + M_NAME
-
-
- def fill_oprator_combox(self):
- """
- fill the current combobox with the operator
- """
- operator_list = ['+', '*']
- for oper in operator_list:
- pos = self._operator_choice.Append(str(oper))
- self._operator_choice.SetClientData(pos, str(oper))
- self._operator_choice.SetSelection(0)
-
- def get_textnames(self):
- """
- Returns model name string as list
- """
- return [self.model1_name, self.model2_name]
-
- def write_string(self, fname, name1, name2):
- """
- Write and Save file
- """
- self.fname = fname
- description = self.desc_tcl.GetValue().lstrip().rstrip()
- if description == '':
- description = name1 + self._operator + name2
- text = self._operator_choice.GetValue()
- if text.count('+') > 0:
- factor = 'scale_factor'
- f_oper = '*'
- default_val = '1.0'
- else:
- factor = 'BackGround'
- f_oper = '+'
- default_val = '0.0'
- path = self.fname
- try:
- out_f = open(path, 'w')
- except:
- raise
- lines = SUM_TEMPLATE.split('\n')
- for line in lines:
- try:
- if line.count("scale_factor"):
- line = line.replace('scale_factor', factor)
- #print "scale_factor", line
- if line.count("= %s"):
- out_f.write(line % (default_val) + "\n")
- elif line.count("import Model as P1"):
- if self.is_p1_custom:
- line = line.replace('#', '')
- out_f.write(line % name1 + "\n")
- else:
- out_f.write(line + "\n")
- elif line.count("import %s as P1"):
- if not self.is_p1_custom:
- line = line.replace('#', '')
- out_f.write(line % (name1) + "\n")
- else:
- out_f.write(line + "\n")
- elif line.count("import Model as P2"):
- if self.is_p2_custom:
- line = line.replace('#', '')
- out_f.write(line % name2 + "\n")
- else:
- out_f.write(line + "\n")
- elif line.count("import %s as P2"):
- if not self.is_p2_custom:
- line = line.replace('#', '')
- out_f.write(line % (name2) + "\n")
- else:
- out_f.write(line + "\n")
- elif line.count("P1 = find_model"):
- out_f.write(line % (name1) + "\n")
- elif line.count("P2 = find_model"):
- out_f.write(line % (name2) + "\n")
-
- elif line.count("self.description = '%s'"):
- out_f.write(line % description + "\n")
- #elif line.count("run") and line.count("%s"):
- # out_f.write(line % self._operator + "\n")
- #elif line.count("evalDistribution") and line.count("%s"):
- # out_f.write(line % self._operator + "\n")
- elif line.count("return") and line.count("%s") == 2:
- #print "line return", line
- out_f.write(line % (f_oper, self._operator) + "\n")
- elif line.count("out2")and line.count("%s"):
- out_f.write(line % self._operator + "\n")
- else:
- out_f.write(line + "\n")
- except:
- raise
- out_f.close()
- #else:
- # msg = "Name exists already."
-
- def compile_file(self, path):
- """
- Compile the file in the path
- """
- path = self.fname
- show_model_output(self, path)
-
- def delete_file(self, path):
- """
- Delete file in the path
- """
- _delete_file(path)
-
-
-class EditorPanel(wx.ScrolledWindow):
- """
- Simple Plugin Model function editor
- """
- def __init__(self, parent, base, path, title, *args, **kwds):
- kwds['name'] = title
-# kwds["size"] = (EDITOR_WIDTH, EDITOR_HEIGTH)
- kwds["style"] = wx.FULL_REPAINT_ON_RESIZE
- wx.ScrolledWindow.__init__(self, parent, *args, **kwds)
- self.SetScrollbars(1,1,1,1)
- self.parent = parent
- self.base = base
- self.path = path
- self.font = wx.SystemSettings_GetFont(wx.SYS_SYSTEM_FONT)
- self.font.SetPointSize(10)
- self.reader = None
- self.name = 'untitled'
- self.overwrite_name = False
- self.is_2d = False
- self.fname = None
- self.main_sizer = None
- self.name_sizer = None
- self.name_hsizer = None
- self.name_tcl = None
- self.desc_sizer = None
- self.desc_tcl = None
- self.param_sizer = None
- self.param_tcl = None
- self.function_sizer = None
- self.func_horizon_sizer = None
- self.button_sizer = None
- self.param_strings = ''
- self.function_strings = ''
- self._notes = ""
- self._msg_box = None
- self.msg_sizer = None
- self.warning = ""
- #This does not seem to be used anywhere so commenting out for now
- # -- PDB 2/26/17
- #self._description = "New Plugin Model"
- self.function_tcl = None
- self.math_combo = None
- self.bt_apply = None
- self.bt_close = None
- #self._default_save_location = os.getcwd()
- self._do_layout()
-
-
-
- def _define_structure(self):
- """
- define initial sizer
- """
- #w, h = self.parent.GetSize()
- self.main_sizer = wx.BoxSizer(wx.VERTICAL)
- self.name_sizer = wx.BoxSizer(wx.VERTICAL)
- self.name_hsizer = wx.BoxSizer(wx.HORIZONTAL)
- self.desc_sizer = wx.BoxSizer(wx.VERTICAL)
- self.param_sizer = wx.BoxSizer(wx.VERTICAL)
- self.function_sizer = wx.BoxSizer(wx.VERTICAL)
- self.func_horizon_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.button_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.msg_sizer = wx.BoxSizer(wx.HORIZONTAL)
-
- def _layout_name(self):
- """
- Do the layout for file/function name related widgets
- """
- #title name [string]
- name_txt = wx.StaticText(self, -1, 'Function Name : ')
- overwrite_cb = wx.CheckBox(self, -1, "Overwrite existing plugin model of this name?", (10, 10))
- overwrite_cb.SetValue(False)
- overwrite_cb.SetToolTipString("Overwrite it if already exists?")
- wx.EVT_CHECKBOX(self, overwrite_cb.GetId(), self.on_over_cb)
- self.name_tcl = wx.TextCtrl(self, -1, size=(PANEL_WIDTH * 3 / 5, -1))
- self.name_tcl.Bind(wx.EVT_TEXT_ENTER, self.on_change_name)
- self.name_tcl.SetValue('')
- self.name_tcl.SetFont(self.font)
- hint_name = "Unique Model Function Name."
- self.name_tcl.SetToolTipString(hint_name)
- self.name_hsizer.AddMany([(self.name_tcl, 0, wx.LEFT | wx.TOP, 0),
- (overwrite_cb, 0, wx.LEFT, 20)])
- self.name_sizer.AddMany([(name_txt, 0, wx.LEFT | wx.TOP, 10),
- (self.name_hsizer, 0,
- wx.LEFT | wx.TOP | wx.BOTTOM, 10)])
-
-
- def _layout_description(self):
- """
- Do the layout for description related widgets
- """
- #title name [string]
- desc_txt = wx.StaticText(self, -1, 'Description (optional) : ')
- self.desc_tcl = wx.TextCtrl(self, -1, size=(PANEL_WIDTH * 3 / 5, -1))
- self.desc_tcl.SetValue('')
- hint_desc = "Write a short description of the model function."
- self.desc_tcl.SetToolTipString(hint_desc)
- self.desc_sizer.AddMany([(desc_txt, 0, wx.LEFT | wx.TOP, 10),
- (self.desc_tcl, 0,
- wx.LEFT | wx.TOP | wx.BOTTOM, 10)])
- def _layout_param(self):
- """
- Do the layout for parameter related widgets
- """
- param_txt = wx.StaticText(self, -1, 'Fit Parameters NOT requiring' + \
- ' polydispersity (if any): ')
-
- param_tip = "#Set the parameters NOT requiring polydispersity " + \
- "and their initial values.\n"
- param_tip += "#Example:\n"
- param_tip += "A = 1\nB = 1"
- #param_txt.SetToolTipString(param_tip)
- newid = wx.NewId()
- self.param_tcl = EditWindow(self, newid, wx.DefaultPosition,
- wx.DefaultSize,
- wx.CLIP_CHILDREN | wx.SUNKEN_BORDER)
- self.param_tcl.setDisplayLineNumbers(True)
- self.param_tcl.SetToolTipString(param_tip)
-
- self.param_sizer.AddMany([(param_txt, 0, wx.LEFT, 10),
- (self.param_tcl, 1, wx.EXPAND | wx.ALL, 10)])
-
- # Parameters with polydispersity
- pd_param_txt = wx.StaticText(self, -1, 'Fit Parameters requiring ' + \
- 'polydispersity (if any): ')
-
- pd_param_tip = "#Set the parameters requiring polydispersity and " + \
- "their initial values.\n"
- pd_param_tip += "#Example:\n"
- pd_param_tip += "C = 2\nD = 2"
- newid = wx.NewId()
- self.pd_param_tcl = EditWindow(self, newid, wx.DefaultPosition,
- wx.DefaultSize,
- wx.CLIP_CHILDREN | wx.SUNKEN_BORDER)
- self.pd_param_tcl.setDisplayLineNumbers(True)
- self.pd_param_tcl.SetToolTipString(pd_param_tip)
-
- self.param_sizer.AddMany([(pd_param_txt, 0, wx.LEFT, 10),
- (self.pd_param_tcl, 1, wx.EXPAND | wx.ALL, 10)])
-
- def _layout_function(self):
- """
- Do the layout for function related widgets
- """
- function_txt = wx.StaticText(self, -1, 'Function(x) : ')
- hint_function = "#Example:\n"
- hint_function += "if x <= 0:\n"
- hint_function += " y = A + B\n"
- hint_function += "else:\n"
- hint_function += " y = A + B * cos(2 * pi * x)\n"
- hint_function += "return y\n"
- math_txt = wx.StaticText(self, -1, '*Useful math functions: ')
- math_combo = self._fill_math_combo()
-
- newid = wx.NewId()
- self.function_tcl = EditWindow(self, newid, wx.DefaultPosition,
- wx.DefaultSize,
- wx.CLIP_CHILDREN | wx.SUNKEN_BORDER)
- self.function_tcl.setDisplayLineNumbers(True)
- self.function_tcl.SetToolTipString(hint_function)
-
- self.func_horizon_sizer.Add(function_txt)
- self.func_horizon_sizer.Add(math_txt, 0, wx.LEFT, 250)
- self.func_horizon_sizer.Add(math_combo, 0, wx.LEFT, 10)
-
- self.function_sizer.Add(self.func_horizon_sizer, 0, wx.LEFT, 10)
- self.function_sizer.Add(self.function_tcl, 1, wx.EXPAND | wx.ALL, 10)
-
- def _layout_msg(self):
- """
- Layout msg
- """
- self._msg_box = wx.StaticText(self, -1, self._notes,
- size=(PANEL_WIDTH, -1))
- self.msg_sizer.Add(self._msg_box, 0, wx.LEFT, 10)
-
- def _layout_button(self):
- """
- Do the layout for the button widgets
- """
- self.bt_apply = wx.Button(self, -1, "Apply", size=(_BOX_WIDTH, -1))
- self.bt_apply.SetToolTipString("Save changes into the imported data.")
- self.bt_apply.Bind(wx.EVT_BUTTON, self.on_click_apply)
-
- self.bt_help = wx.Button(self, -1, "HELP", size=(_BOX_WIDTH, -1))
- self.bt_help.SetToolTipString("Get Help For Model Editor")
- self.bt_help.Bind(wx.EVT_BUTTON, self.on_help)
-
- self.bt_close = wx.Button(self, -1, 'Close', size=(_BOX_WIDTH, -1))
- self.bt_close.Bind(wx.EVT_BUTTON, self.on_close)
- self.bt_close.SetToolTipString("Close this panel.")
-
- self.button_sizer.AddMany([(self.bt_apply, 0,0),
- (self.bt_help, 0, wx.LEFT | wx.BOTTOM,15),
- (self.bt_close, 0, wx.LEFT | wx.RIGHT, 15)])
-
- def _do_layout(self):
- """
- Draw the current panel
- """
- self._define_structure()
- self._layout_name()
- self._layout_description()
- self._layout_param()
- self._layout_function()
- self._layout_msg()
- self._layout_button()
- self.main_sizer.AddMany([(self.name_sizer, 0, wx.EXPAND | wx.ALL, 5),
- (wx.StaticLine(self), 0,
- wx.ALL | wx.EXPAND, 5),
- (self.desc_sizer, 0, wx.EXPAND | wx.ALL, 5),
- (wx.StaticLine(self), 0,
- wx.ALL | wx.EXPAND, 5),
- (self.param_sizer, 1, wx.EXPAND | wx.ALL, 5),
- (wx.StaticLine(self), 0,
- wx.ALL | wx.EXPAND, 5),
- (self.function_sizer, 2,
- wx.EXPAND | wx.ALL, 5),
- (wx.StaticLine(self), 0,
- wx.ALL | wx.EXPAND, 5),
- (self.msg_sizer, 0, wx.EXPAND | wx.ALL, 5),
- (self.button_sizer, 0, wx.ALIGN_RIGHT)])
- self.SetSizer(self.main_sizer)
- self.SetAutoLayout(True)
-
- def _fill_math_combo(self):
- """
- Fill up the math combo box
- """
- self.math_combo = wx.ComboBox(self, -1, size=(100, -1),
- style=wx.CB_READONLY)
- for item in dir(math):
- if item.count("_") < 1:
- try:
- exec "float(math.%s)" % item
- self.math_combo.Append(str(item))
- except:
- self.math_combo.Append(str(item) + "()")
- self.math_combo.Bind(wx.EVT_COMBOBOX, self._on_math_select)
- self.math_combo.SetSelection(0)
- return self.math_combo
-
- def _on_math_select(self, event):
- """
- On math selection on ComboBox
- """
- event.Skip()
- label = self.math_combo.GetValue()
- self.function_tcl.SetFocus()
- # Put the text at the cursor position
- pos = self.function_tcl.GetCurrentPos()
- self.function_tcl.InsertText(pos, label)
- # Put the cursor at appropriate position
- length = len(label)
- print length
- if label[length-1] == ')':
- length -= 1
- f_pos = pos + length
- self.function_tcl.GotoPos(f_pos)
-
- def get_notes(self):
- """
- return notes
- """
- return self._notes
-
- def on_change_name(self, event=None):
- """
- Change name
- """
- if event is not None:
- event.Skip()
- self.name_tcl.SetBackgroundColour('white')
- self.Refresh()
-
- def check_name(self):
- """
- Check name if exist already
- """
- self._notes = ''
- self.on_change_name(None)
- plugin_dir = self.path
- list_fnames = os.listdir(plugin_dir)
- # function/file name
- title = self.name_tcl.GetValue().lstrip().rstrip()
- self.name = title
- t_fname = title + '.py'
- if not self.overwrite_name:
- if t_fname in list_fnames:
- self.name_tcl.SetBackgroundColour('pink')
- return False
- self.fname = os.path.join(plugin_dir, t_fname)
- s_title = title
- if len(title) > 20:
- s_title = title[0:19] + '...'
- self._notes += "Model function name is set "
- self._notes += "to %s. \n" % str(s_title)
- return True
-
- def on_over_cb(self, event):
- """
- Set overwrite name flag on cb event
- """
- if event is not None:
- event.Skip()
- cb_value = event.GetEventObject()
- self.overwrite_name = cb_value.GetValue()
-
- def on_click_apply(self, event):
- """
- Changes are saved in data object imported to edit.
-
- checks firs for valid name, then if it already exists then checks
- that a function was entered and finally that if entered it contains at
- least a return statement. If all passes writes file then tries to
- compile. If compile fails or import module fails or run method fails
- tries to remove any .py and pyc files that may have been created and
- sets error message.
-
- :todo this code still could do with a careful going over to clean
- up and simplify. the non GUI methods such as this one should be removed
- to computational code of SasView. Most of those computational methods
- would be the same for both the simple editors.
- """
- #must post event here
- event.Skip()
- name = self.name_tcl.GetValue().lstrip().rstrip()
- info = 'Info'
- msg = ''
- result, check_err = '', ''
- # Sort out the errors if occur
- # First check for valid python name then if the name already exists
- if not name or not bool(re.match('^[A-Za-z0-9_]*$', name)):
- msg = '"%s" '%name
- msg += "is not a valid model name. Name must not be empty and \n"
- msg += "may include only alpha numeric or underline characters \n"
- msg += "and no spaces"
- elif self.check_name():
- description = self.desc_tcl.GetValue()
- param_str = self.param_tcl.GetText()
- pd_param_str = self.pd_param_tcl.GetText()
- func_str = self.function_tcl.GetText()
- # No input for the model function
- if func_str.lstrip().rstrip():
- if func_str.count('return') > 0:
- self.write_file(self.fname, name, description, param_str,
- pd_param_str, func_str)
- try:
- result, msg = check_model(self.fname), None
- except Exception:
- import traceback
- result, msg = None, "error building model"
- check_err = "\n"+traceback.format_exc(limit=2)
- else:
- msg = "Error: The func(x) must 'return' a value at least.\n"
- msg += "For example: \n\nreturn 2*x"
- else:
- msg = 'Error: Function is not defined.'
- else:
- msg = "Name exists already."
-
- # Prepare the messagebox
- if self.base != None and not msg:
- self.base.update_custom_combo()
- # Passed exception in import test as it will fail for sasmodels.sasview_model class
- # Should add similar test for new style?
- Model = None
- try:
- exec "from %s import Model" % name
- except:
- logging.error(sys.exc_value)
-
- # Prepare the messagebox
- if msg:
- info = 'Error'
- color = 'red'
- else:
- self._notes = result
- msg = "Successful! Please look for %s in Plugin Models."%name
- msg += " " + self._notes
- info = 'Info'
- color = 'blue'
- self._msg_box.SetLabel(msg)
- self._msg_box.SetForegroundColour(color)
- # Send msg to the top window
- if self.base != None:
- from sas.sasgui.guiframe.events import StatusEvent
- wx.PostEvent(self.base.parent,
- StatusEvent(status=msg+check_err, info=info))
- self.warning = msg
-
- def write_file(self, fname, name, desc_str, param_str, pd_param_str, func_str):
- """
- Write content in file
-
- :param fname: full file path
- :param desc_str: content of the description strings
- :param param_str: content of params; Strings
- :param pd_param_str: content of params requiring polydispersity; Strings
- :param func_str: content of func; Strings
- """
- try:
- out_f = open(fname, 'w')
- except:
- raise
- # Prepare the content of the function
- lines = CUSTOM_TEMPLATE.split('\n')
-
- has_scipy = func_str.count("scipy.")
- if has_scipy:
- lines.insert(0, 'import scipy')
-
- # Think about 2D later
- #self.is_2d = func_str.count("#self.ndim = 2")
- #line_2d = ''
- #if self.is_2d:
- # line_2d = CUSTOM_2D_TEMP.split('\n')
-
- # Also think about test later
- #line_test = TEST_TEMPLATE.split('\n')
- #local_params = ''
- #spaces = ' '#8spaces
- spaces4 = ' '*4
- spaces13 = ' '*13
- spaces16 = ' '*16
- param_names = [] # to store parameter names
- has_scipy = func_str.count("scipy.")
- if has_scipy:
- lines.insert(0, 'import scipy')
-
- # write function here
- for line in lines:
- # The location where to put the strings is
- # hard-coded in the template as shown below.
- out_f.write(line + '\n')
- if line.count('#name'):
- out_f.write('name = "%s" \n' % name)
- elif line.count('#title'):
- out_f.write('title = "User model for %s"\n' % name)
- elif line.count('#description'):
- out_f.write('description = "%s"\n' % desc_str)
- elif line.count('#parameters'):
- out_f.write('parameters = [ \n')
- for param_line in param_str.split('\n'):
- p_line = param_line.lstrip().rstrip()
- if p_line:
- pname, pvalue = self.get_param_helper(p_line)
- param_names.append(pname)
- out_f.write("%s['%s', '', %s, [-numpy.inf, numpy.inf], '', ''],\n" % (spaces16, pname, pvalue))
- for param_line in pd_param_str.split('\n'):
- p_line = param_line.lstrip().rstrip()
- if p_line:
- pname, pvalue = self.get_param_helper(p_line)
- param_names.append(pname)
- out_f.write("%s['%s', '', %s, [-numpy.inf, numpy.inf], 'volume', ''],\n" % (spaces16, pname, pvalue))
- out_f.write('%s]\n' % spaces13)
-
- # No form_volume or ER available in simple model editor
- out_f.write('def form_volume(*arg): \n')
- out_f.write(' return 1.0 \n')
- out_f.write('\n')
- out_f.write('def ER(*arg): \n')
- out_f.write(' return 1.0 \n')
-
- # function to compute
- out_f.write('\n')
- out_f.write('def Iq(x ')
- for name in param_names:
- out_f.write(', %s' % name)
- out_f.write('):\n')
- for func_line in func_str.split('\n'):
- out_f.write('%s%s\n' % (spaces4, func_line))
-
- Iqxy_string = 'return Iq(numpy.sqrt(x**2+y**2) '
-
- out_f.write('\n')
- out_f.write('def Iqxy(x, y ')
- for name in param_names:
- out_f.write(', %s' % name)
- Iqxy_string += ', ' + name
- out_f.write('):\n')
- Iqxy_string += ')'
- out_f.write('%s%s\n' % (spaces4, Iqxy_string))
-
- out_f.close()
-
- def get_param_helper(self, line):
- """
- Get string in line to define the params dictionary
-
- :param line: one line of string got from the param_str
- """
- items = line.split(";")
- for item in items:
- name = item.split("=")[0].lstrip().rstrip()
- try:
- value = item.split("=")[1].lstrip().rstrip()
- float(value)
- except:
- value = 1.0 # default
-
- return name, value
-
- def set_function_helper(self, line):
- """
- Get string in line to define the local params
-
- :param line: one line of string got from the param_str
- """
- params_str = ''
- spaces = ' '#8spaces
- items = line.split(";")
- for item in items:
- name = item.split("=")[0].lstrip().rstrip()
- params_str += spaces + "%s = self.params['%s']\n" % (name, name)
- return params_str
-
- def get_warning(self):
- """
- Get the warning msg
- """
- return self.warning
-
- def on_help(self, event):
- """
- Bring up the New Plugin Model Editor Documentation whenever
- the HELP button is clicked.
-
- Calls DocumentationWindow with the path of the location within the
- documentation tree (after /doc/ ....". Note that when using old
- versions of Wx (before 2.9) and thus not the release version of
- installers, the help comes up at the top level of the file as
- webbrowser does not pass anything past the # to the browser when it is
- running "file:///...."
-
- :param evt: Triggers on clicking the help button
- """
-
- _TreeLocation = "user/sasgui/perspectives/fitting/fitting_help.html"
- _PageAnchor = "#new-plugin-model"
- _doc_viewer = DocumentationWindow(self, -1, _TreeLocation, _PageAnchor,
- "Plugin Model Editor Help")
-
- def on_close(self, event):
- """
- leave data as it is and close
- """
- self.parent.Show(False)#Close()
- event.Skip()
-
-class EditorWindow(wx.Frame):
- """
- Editor Window
- """
- def __init__(self, parent, base, path, title,
- size=(EDITOR_WIDTH, EDITOR_HEIGTH), *args, **kwds):
- """
- Init
- """
- kwds["title"] = title
- kwds["size"] = size
- wx.Frame.__init__(self, parent=None, *args, **kwds)
- self.parent = parent
- self.panel = EditorPanel(parent=self, base=parent,
- path=path, title=title)
- self.Show(True)
- wx.EVT_CLOSE(self, self.on_close)
-
- def on_close(self, event):
- """
- On close event
- """
- self.Show(False)
- #if self.parent != None:
- # self.parent.new_model_frame = None
- #self.Destroy()
-
-## Templates for plugin models
-
-CUSTOM_TEMPLATE = """
-from math import *
-import os
-import sys
-import numpy
-
-#name
-
-#title
-
-#description
-
-#parameters
-
-"""
-
-CUSTOM_2D_TEMP = """
- def run(self, x=0.0, y=0.0):
- if x.__class__.__name__ == 'list':
- x_val = x[0]
- y_val = y[0]*0.0
- return self.function(x_val, y_val)
- elif x.__class__.__name__ == 'tuple':
- msg = "Tuples are not allowed as input to BaseComponent models"
- raise ValueError, msg
- else:
- return self.function(x, 0.0)
- def runXY(self, x=0.0, y=0.0):
- if x.__class__.__name__ == 'list':
- return self.function(x, y)
- elif x.__class__.__name__ == 'tuple':
- msg = "Tuples are not allowed as input to BaseComponent models"
- raise ValueError, msg
- else:
- return self.function(x, y)
- def evalDistribution(self, qdist):
- if qdist.__class__.__name__ == 'list':
- msg = "evalDistribution expects a list of 2 ndarrays"
- if len(qdist)!=2:
- raise RuntimeError, msg
- if qdist[0].__class__.__name__ != 'ndarray':
- raise RuntimeError, msg
- if qdist[1].__class__.__name__ != 'ndarray':
- raise RuntimeError, msg
- v_model = numpy.vectorize(self.runXY, otypes=[float])
- iq_array = v_model(qdist[0], qdist[1])
- return iq_array
- elif qdist.__class__.__name__ == 'ndarray':
- v_model = numpy.vectorize(self.runXY, otypes=[float])
- iq_array = v_model(qdist)
- return iq_array
-"""
-TEST_TEMPLATE = """
-######################################################################
-## THIS IS FOR TEST. DO NOT MODIFY THE FOLLOWING LINES!!!!!!!!!!!!!!!!
-if __name__ == "__main__":
- m= Model()
- out1 = m.runXY(0.0)
- out2 = m.runXY(0.01)
- isfine1 = numpy.isfinite(out1)
- isfine2 = numpy.isfinite(out2)
- print "Testing the value at Q = 0.0:"
- print out1, " : finite? ", isfine1
- print "Testing the value at Q = 0.01:"
- print out2, " : finite? ", isfine2
- if isfine1 and isfine2:
- print "===> Simple Test: Passed!"
- else:
- print "===> Simple Test: Failed!"
-"""
-SUM_TEMPLATE = """
-# A sample of an experimental model function for Sum/Multiply(Pmodel1,Pmodel2)
-import os
-import sys
-import copy
-import collections
-
-import numpy
-
-from sas.sascalc.fit.pluginmodel import Model1DPlugin
-from sasmodels.sasview_model import find_model
-
-class Model(Model1DPlugin):
- name = os.path.splitext(os.path.basename(__file__))[0]
- is_multiplicity_model = False
- def __init__(self, multiplicity=1):
- Model1DPlugin.__init__(self, name='')
- P1 = find_model('%s')
- P2 = find_model('%s')
- p_model1 = P1()
- p_model2 = P2()
- ## Setting model name model description
- self.description = '%s'
- if self.name.rstrip().lstrip() == '':
- self.name = self._get_name(p_model1.name, p_model2.name)
- if self.description.rstrip().lstrip() == '':
- self.description = p_model1.name
- self.description += p_model2.name
- self.fill_description(p_model1, p_model2)
-
- ## Define parameters
- self.params = collections.OrderedDict()
-
- ## Parameter details [units, min, max]
- self.details = {}
- ## Magnetic Panrameters
- self.magnetic_params = []
- # non-fittable parameters
- self.non_fittable = p_model1.non_fittable
- self.non_fittable += p_model2.non_fittable
-
- ##models
- self.p_model1= p_model1
- self.p_model2= p_model2
-
-
- ## dispersion
- self._set_dispersion()
- ## Define parameters
- self._set_params()
- ## New parameter:scaling_factor
- self.params['scale_factor'] = %s
-
- ## Parameter details [units, min, max]
- self._set_details()
- self.details['scale_factor'] = ['', 0.0, numpy.inf]
-
-
- #list of parameter that can be fitted
- self._set_fixed_params()
-
- ## parameters with orientation
- self.orientation_params = []
- for item in self.p_model1.orientation_params:
- new_item = "p1_" + item
- if not new_item in self.orientation_params:
- self.orientation_params.append(new_item)
-
- for item in self.p_model2.orientation_params:
- new_item = "p2_" + item
- if not new_item in self.orientation_params:
- self.orientation_params.append(new_item)
- ## magnetic params
- self.magnetic_params = []
- for item in self.p_model1.magnetic_params:
- new_item = "p1_" + item
- if not new_item in self.magnetic_params:
- self.magnetic_params.append(new_item)
-
- for item in self.p_model2.magnetic_params:
- new_item = "p2_" + item
- if not new_item in self.magnetic_params:
- self.magnetic_params.append(new_item)
- # get multiplicity if model provide it, else 1.
- try:
- multiplicity1 = p_model1.multiplicity
- try:
- multiplicity2 = p_model2.multiplicity
- except:
- multiplicity2 = 1
- except:
- multiplicity1 = 1
- multiplicity2 = 1
- ## functional multiplicity of the model
- self.multiplicity1 = multiplicity1
- self.multiplicity2 = multiplicity2
- self.multiplicity_info = []
-
- def _clone(self, obj):
- import copy
- obj.params = copy.deepcopy(self.params)
- obj.description = copy.deepcopy(self.description)
- obj.details = copy.deepcopy(self.details)
- obj.dispersion = copy.deepcopy(self.dispersion)
- obj.p_model1 = self.p_model1.clone()
- obj.p_model2 = self.p_model2.clone()
- #obj = copy.deepcopy(self)
- return obj
-
- def _get_name(self, name1, name2):
- p1_name = self._get_upper_name(name1)
- if not p1_name:
- p1_name = name1
- name = p1_name
- name += "_and_"
- p2_name = self._get_upper_name(name2)
- if not p2_name:
- p2_name = name2
- name += p2_name
- return name
-
- def _get_upper_name(self, name=None):
- if name == None:
- return ""
- upper_name = ""
- str_name = str(name)
- for index in range(len(str_name)):
- if str_name[index].isupper():
- upper_name += str_name[index]
- return upper_name
-
- def _set_dispersion(self):
- self.dispersion = collections.OrderedDict()
- ##set dispersion only from p_model
- for name , value in self.p_model1.dispersion.iteritems():
- #if name.lower() not in self.p_model1.orientation_params:
- new_name = "p1_" + name
- self.dispersion[new_name]= value
- for name , value in self.p_model2.dispersion.iteritems():
- #if name.lower() not in self.p_model2.orientation_params:
- new_name = "p2_" + name
- self.dispersion[new_name]= value
-
- def function(self, x=0.0):
- return 0
-
- def getProfile(self):
- try:
- x,y = self.p_model1.getProfile()
- except:
- x = None
- y = None
-
- return x, y
-
- def _set_params(self):
- for name , value in self.p_model1.params.iteritems():
- # No 2D-supported
- #if name not in self.p_model1.orientation_params:
- new_name = "p1_" + name
- self.params[new_name]= value
-
- for name , value in self.p_model2.params.iteritems():
- # No 2D-supported
- #if name not in self.p_model2.orientation_params:
- new_name = "p2_" + name
- self.params[new_name]= value
-
- # Set "scale" as initializing
- self._set_scale_factor()
-
-
- def _set_details(self):
- for name ,detail in self.p_model1.details.iteritems():
- new_name = "p1_" + name
- #if new_name not in self.orientation_params:
- self.details[new_name]= detail
-
- for name ,detail in self.p_model2.details.iteritems():
- new_name = "p2_" + name
- #if new_name not in self.orientation_params:
- self.details[new_name]= detail
-
- def _set_scale_factor(self):
- pass
-
-
- def setParam(self, name, value):
- # set param to this (p1, p2) model
- self._setParamHelper(name, value)
-
- ## setParam to p model
- model_pre = ''
- new_name = ''
- name_split = name.split('_', 1)
- if len(name_split) == 2:
- model_pre = name.split('_', 1)[0]
- new_name = name.split('_', 1)[1]
- if model_pre == "p1":
- if new_name in self.p_model1.getParamList():
- self.p_model1.setParam(new_name, value)
- elif model_pre == "p2":
- if new_name in self.p_model2.getParamList():
- self.p_model2.setParam(new_name, value)
- elif name == 'scale_factor':
- self.params['scale_factor'] = value
- else:
- raise ValueError, "Model does not contain parameter %s" % name
-
- def getParam(self, name):
- # Look for dispersion parameters
- toks = name.split('.')
- if len(toks)==2:
- for item in self.dispersion.keys():
- # 2D not supported
- if item.lower()==toks[0].lower():
- for par in self.dispersion[item]:
- if par.lower() == toks[1].lower():
- return self.dispersion[item][par]
- else:
- # Look for standard parameter
- for item in self.params.keys():
- if item.lower()==name.lower():
- return self.params[item]
- return
- #raise ValueError, "Model does not contain parameter %s" % name
-
- def _setParamHelper(self, name, value):
- # Look for dispersion parameters
- toks = name.split('.')
- if len(toks)== 2:
- for item in self.dispersion.keys():
- if item.lower()== toks[0].lower():
- for par in self.dispersion[item]:
- if par.lower() == toks[1].lower():
- self.dispersion[item][par] = value
- return
- else:
- # Look for standard parameter
- for item in self.params.keys():
- if item.lower()== name.lower():
- self.params[item] = value
- return
-
- raise ValueError, "Model does not contain parameter %s" % name
-
-
- def _set_fixed_params(self):
- self.fixed = []
- for item in self.p_model1.fixed:
- new_item = "p1" + item
- self.fixed.append(new_item)
- for item in self.p_model2.fixed:
- new_item = "p2" + item
- self.fixed.append(new_item)
-
- self.fixed.sort()
-
-
- def run(self, x = 0.0):
- self._set_scale_factor()
- return self.params['scale_factor'] %s \
-(self.p_model1.run(x) %s self.p_model2.run(x))
-
- def runXY(self, x = 0.0):
- self._set_scale_factor()
- return self.params['scale_factor'] %s \
-(self.p_model1.runXY(x) %s self.p_model2.runXY(x))
-
- ## Now (May27,10) directly uses the model eval function
- ## instead of the for-loop in Base Component.
- def evalDistribution(self, x = []):
- self._set_scale_factor()
- return self.params['scale_factor'] %s \
-(self.p_model1.evalDistribution(x) %s \
-self.p_model2.evalDistribution(x))
-
- def set_dispersion(self, parameter, dispersion):
- value= None
- new_pre = parameter.split("_", 1)[0]
- new_parameter = parameter.split("_", 1)[1]
- try:
- if new_pre == 'p1' and \
-new_parameter in self.p_model1.dispersion.keys():
- value= self.p_model1.set_dispersion(new_parameter, dispersion)
- if new_pre == 'p2' and \
-new_parameter in self.p_model2.dispersion.keys():
- value= self.p_model2.set_dispersion(new_parameter, dispersion)
- self._set_dispersion()
- return value
- except:
- raise
-
- def fill_description(self, p_model1, p_model2):
- description = ""
- description += "This model gives the summation or multiplication of"
- description += "%s and %s. "% ( p_model1.name, p_model2.name )
- self.description += description
-
-if __name__ == "__main__":
- m1= Model()
- #m1.setParam("p1_scale", 25)
- #m1.setParam("p1_length", 1000)
- #m1.setParam("p2_scale", 100)
- #m1.setParam("p2_rg", 100)
- out1 = m1.runXY(0.01)
-
- m2= Model()
- #m2.p_model1.setParam("scale", 25)
- #m2.p_model1.setParam("length", 1000)
- #m2.p_model2.setParam("scale", 100)
- #m2.p_model2.setParam("rg", 100)
- out2 = m2.p_model1.runXY(0.01) %s m2.p_model2.runXY(0.01)\n
- print "My name is %s."% m1.name
- print out1, " = ", out2
- if out1 == out2:
- print "===> Simple Test: Passed!"
- else:
- print "===> Simple Test: Failed!"
-"""
-
-if __name__ == "__main__":
-# app = wx.PySimpleApp()
- main_app = wx.App()
- main_frame = TextDialog(id=1, model_list=["SphereModel", "CylinderModel"],
- plugin_dir='../fitting/plugin_models')
- main_frame.ShowModal()
- main_app.MainLoop()
-
-#if __name__ == "__main__":
-# from sas.sasgui.perspectives.fitting import models
-# dir_path = models.find_plugins_dir()
-# app = wx.App()
-# window = EditorWindow(parent=None, base=None, path=dir_path, title="Editor")
-# app.MainLoop()
+'''
+This module provides three model editor classes: the composite model editor,
+the easy editor which provides a simple interface with tooltip help to enter
+the parameters of the model and their default value and a panel to input a
+function of y (usually the intensity). It also provides a drop down of
+standard available math functions. Finally a full python editor panel for
+complete customization is provided.
+
+:TODO the writing of the file and name checking (and maybe some other
+functions?) should be moved to a computational module which could be called
+from a python script. Basically one just needs to pass the name,
+description text and function text (or in the case of the composite editor
+the names of the first and second model and the operator to be used).
+'''
+
+################################################################################
+#This software was developed by the University of Tennessee as part of the
+#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
+#project funded by the US National Science Foundation.
+#
+#See the license text in license.txt
+#
+#copyright 2009, University of Tennessee
+################################################################################
+from __future__ import print_function
+
+import wx
+import sys
+import os
+import math
+import re
+import logging
+import datetime
+
+from wx.py.editwindow import EditWindow
+
+from sas.sasgui.guiframe.documentation_window import DocumentationWindow
+
+from .pyconsole import show_model_output, check_model
+
+logger = logging.getLogger(__name__)
+
+if sys.platform.count("win32") > 0:
+ FONT_VARIANT = 0
+ PNL_WIDTH = 450
+ PNL_HEIGHT = 320
+else:
+ FONT_VARIANT = 1
+ PNL_WIDTH = 590
+ PNL_HEIGHT = 350
+M_NAME = 'Model'
+EDITOR_WIDTH = 800
+EDITOR_HEIGTH = 735
+PANEL_WIDTH = 500
+_BOX_WIDTH = 55
+
+def _delete_file(path):
+ """
+ Delete file in the path
+ """
+ try:
+ os.remove(path)
+ except:
+ raise
+
+
+class TextDialog(wx.Dialog):
+ """
+ Dialog for easy custom composite models. Provides a wx.Dialog panel
+ to choose two existing models (including pre-existing Plugin Models which
+ may themselves be composite models) as well as an operation on those models
+ (add or multiply) the resulting model will add a scale parameter for summed
+ models and a background parameter for a multiplied model.
+
+ The user also gives a brief help for the model in a description box and
+ must provide a unique name which is verified as unique before the new
+ model is saved.
+
+ This Dialog pops up for the user when they press 'Sum|Multi(p1,p2)' under
+ 'Plugin Model Operations' under 'Fitting' menu. This is currently called as
+ a Modal Dialog.
+
+ :TODO the built in compiler currently balks at when it tries to import
+ a model whose name contains spaces or symbols (such as + ... underscore
+ should be fine). Have fixed so the editor cannot save such a file name
+ but if a file is dropped in the plugin directory from outside this class
+ will create a file that cannot be compiled. Should add the check to
+ the write method or to the on_modelx method.
+
+ - PDB:April 5, 2015
+ """
+ def __init__(self, parent=None, base=None, id=None, title='',
+ model_list=[], plugin_dir=None):
+ """
+ This class is run when instatiated. The __init__ initializes and
+ calls the internal methods necessary. On exiting the wx.Dialog
+ window should be destroyed.
+ """
+ wx.Dialog.__init__(self, parent=parent, id=id,
+ title=title, size=(PNL_WIDTH, PNL_HEIGHT))
+ self.parent = base
+ #Font
+ self.SetWindowVariant(variant=FONT_VARIANT)
+ # default
+ self.overwrite_name = False
+ self.plugin_dir = plugin_dir
+ self.model_list = model_list
+ self.model1_string = "sphere"
+ self.model2_string = "cylinder"
+ self.name = 'Sum' + M_NAME
+ self._notes = ''
+ self._operator = '+'
+ self._operator_choice = None
+ self.explanation = ''
+ self.explanationctr = None
+ self.type = None
+ self.name_sizer = None
+ self.name_tcl = None
+ self.desc_sizer = None
+ self.desc_tcl = None
+ self._selection_box = None
+ self.model1 = None
+ self.model2 = None
+ self.static_line_1 = None
+ self.ok_button = None
+ self.close_button = None
+ self._msg_box = None
+ self.msg_sizer = None
+ self.fname = None
+ self.cm_list = None
+ self.is_p1_custom = False
+ self.is_p2_custom = False
+ self._build_sizer()
+ self.model1_name = str(self.model1.GetValue())
+ self.model2_name = str(self.model2.GetValue())
+ self.good_name = True
+ self.fill_operator_combox()
+
+ def _layout_name(self):
+ """
+ Do the layout for file/function name related widgets
+ """
+ #container for new model name input
+ self.name_sizer = wx.BoxSizer(wx.HORIZONTAL)
+
+ #set up label and input box with tool tip and event handling
+ name_txt = wx.StaticText(self, -1, 'Function Name : ')
+ self.name_tcl = wx.TextCtrl(self, -1, value='MySumFunction')
+ self.name_tcl.Bind(wx.EVT_TEXT_ENTER, self.on_change_name)
+ hint_name = "Unique Sum/Multiply Model Function Name."
+ self.name_tcl.SetToolTipString(hint_name)
+
+ self.name_sizer.AddMany([(name_txt, 0, wx.LEFT | wx.TOP, 10),
+ (self.name_tcl, -1,
+ wx.EXPAND | wx.RIGHT | wx.TOP | wx.BOTTOM,
+ 10)])
+
+
+ def _layout_description(self):
+ """
+ Do the layout for description related widgets
+ """
+ #container for new model description input
+ self.desc_sizer = wx.BoxSizer(wx.HORIZONTAL)
+
+ #set up description label and input box with tool tip and event handling
+ desc_txt = wx.StaticText(self, -1, 'Description (optional) : ')
+ self.desc_tcl = wx.TextCtrl(self, -1)
+ hint_desc = "Write a short description of this model function."
+ self.desc_tcl.SetToolTipString(hint_desc)
+
+ self.desc_sizer.AddMany([(desc_txt, 0, wx.LEFT | wx.TOP, 10),
+ (self.desc_tcl, -1,
+ wx.EXPAND | wx.RIGHT | wx.TOP | wx.BOTTOM,
+ 10)])
+
+
+ def _layout_model_selection(self):
+ """
+ Do the layout for model selection related widgets
+ """
+ box_width = 195 # combobox width
+
+ #First set up main sizer for the selection
+ selection_box_title = wx.StaticBox(self, -1, 'Select',
+ size=(PNL_WIDTH - 30, 70))
+ self._selection_box = wx.StaticBoxSizer(selection_box_title,
+ wx.VERTICAL)
+
+ #Next create the help labels for the model selection
+ select_help_box = wx.BoxSizer(wx.HORIZONTAL)
+ model_string = " Model%s (p%s):"
+ select_help_box.Add(wx.StaticText(self, -1, model_string % (1, 1)),
+ 0, 0)
+ select_help_box.Add((box_width - 25, 10), 0, 0)
+ select_help_box.Add(wx.StaticText(self, -1, model_string % (2, 2)),
+ 0, 0)
+ self._selection_box.Add(select_help_box, 0, 0)
+
+ #Next create the actual selection box with 3 combo boxes
+ selection_box_choose = wx.BoxSizer(wx.HORIZONTAL)
+
+ self.model1 = wx.ComboBox(self, -1, style=wx.CB_READONLY)
+ wx.EVT_COMBOBOX(self.model1, -1, self.on_model1)
+ self.model1.SetMinSize((box_width * 5 / 6, -1))
+ self.model1.SetToolTipString("model1")
+
+ self._operator_choice = wx.ComboBox(self, -1, size=(50, -1),
+ style=wx.CB_READONLY)
+ wx.EVT_COMBOBOX(self._operator_choice, -1, self.on_select_operator)
+ operation_tip = "Add: +, Multiply: * "
+ self._operator_choice.SetToolTipString(operation_tip)
+
+ self.model2 = wx.ComboBox(self, -1, style=wx.CB_READONLY)
+ wx.EVT_COMBOBOX(self.model2, -1, self.on_model2)
+ self.model2.SetMinSize((box_width * 5 / 6, -1))
+ self.model2.SetToolTipString("model2")
+ self._set_model_list()
+
+ selection_box_choose.Add(self.model1, 0, 0)
+ selection_box_choose.Add((15, 10))
+ selection_box_choose.Add(self._operator_choice, 0, 0)
+ selection_box_choose.Add((15, 10))
+ selection_box_choose.Add(self.model2, 0, 0)
+ # add some space between labels and selection
+ self._selection_box.Add((20, 5), 0, 0)
+ self._selection_box.Add(selection_box_choose, 0, 0)
+
+ def _build_sizer(self):
+ """
+ Build GUI with calls to _layout_name, _layout Description
+ and _layout_model_selection which each build a their portion of the
+ GUI.
+ """
+ mainsizer = wx.BoxSizer(wx.VERTICAL) # create main sizer for dialog
+
+ # build fromm top by calling _layout_name and _layout_description
+ # and adding to main sizer
+ self._layout_name()
+ mainsizer.Add(self.name_sizer, 0, wx.EXPAND)
+ self._layout_description()
+ mainsizer.Add(self.desc_sizer, 0, wx.EXPAND)
+
+ # Add an explanation of dialog (short help)
+ self.explanationctr = wx.StaticText(self, -1, self.explanation)
+ self.fill_explanation_helpstring(self._operator)
+ mainsizer.Add(self.explanationctr, 0, wx.LEFT | wx.EXPAND, 15)
+
+ # Add the selection box stuff with border and labels built
+ # by _layout_model_selection
+ self._layout_model_selection()
+ mainsizer.Add(self._selection_box, 0, wx.LEFT, 15)
+
+ # Add a space and horizontal line before the notification
+ #messages and the buttons at the bottom
+ mainsizer.Add((10, 10))
+ self.static_line_1 = wx.StaticLine(self, -1)
+ mainsizer.Add(self.static_line_1, 0, wx.EXPAND, 10)
+
+ # Add action status notification line (null at startup)
+ self._msg_box = wx.StaticText(self, -1, self._notes)
+ self.msg_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.msg_sizer.Add(self._msg_box, 0, wx.LEFT, 0)
+ mainsizer.Add(self.msg_sizer, 0,
+ wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE | wx.BOTTOM, 10)
+
+ # Finally add the buttons (apply and close) on the bottom
+ # Eventually need to add help here
+ self.ok_button = wx.Button(self, wx.ID_OK, 'Apply')
+ _app_tip = "Save the new Model."
+ self.ok_button.SetToolTipString(_app_tip)
+ self.ok_button.Bind(wx.EVT_BUTTON, self.check_name)
+ self.help_button = wx.Button(self, -1, 'HELP')
+ _app_tip = "Help on composite model creation."
+ self.help_button.SetToolTipString(_app_tip)
+ self.help_button.Bind(wx.EVT_BUTTON, self.on_help)
+ self.close_button = wx.Button(self, wx.ID_CANCEL, 'Close')
+ sizer_button = wx.BoxSizer(wx.HORIZONTAL)
+ sizer_button.AddMany([((20, 20), 1, 0),
+ (self.ok_button, 0, 0),
+ (self.help_button, 0, 0),
+ (self.close_button, 0, wx.LEFT | wx.RIGHT, 10)])
+ mainsizer.Add(sizer_button, 0, wx.EXPAND | wx.BOTTOM | wx.TOP, 10)
+
+ self.SetSizer(mainsizer)
+ self.Centre()
+
+ def on_change_name(self, event=None):
+ """
+ Change name
+ """
+ if event is not None:
+ event.Skip()
+ self.name_tcl.SetBackgroundColour('white')
+ self.Refresh()
+
+ def check_name(self, event=None):
+ """
+ Check that proposed new model name is a valid Python module name
+ and that it does not already exist. If not show error message and
+ pink background in text box else call on_apply
+
+ :TODO this should be separated out from the GUI code. For that we
+ need to pass it the name (or if we want to keep the default name
+ option also need to pass the self._operator attribute) We just need
+ the function to return an error code that the name is good or if
+ not why (not a valid name, name exists already). The rest of the
+ error handling should be done in this module. so on_apply would then
+ start by checking the name and then either raise errors or do the
+ deed.
+ """
+ #Get the function/file name
+ mname = M_NAME
+ self.on_change_name(None)
+ title = self.name_tcl.GetValue().lstrip().rstrip()
+ if title == '':
+ text = self._operator
+ if text.count('+') > 0:
+ mname = 'Sum'
+ else:
+ mname = 'Multi'
+ mname += M_NAME
+ title = mname
+ self.name = title
+ t_fname = title + '.py'
+
+ #First check if the name is a valid Python name
+ if re.match('^[A-Za-z0-9_]*$', title):
+ self.good_name = True
+ else:
+ self.good_name = False
+ msg = ("%s is not a valid Python name. Only alphanumeric \n" \
+ "and underscore allowed" % self.name)
+
+ #Now check if the name already exists
+ if not self.overwrite_name and self.good_name:
+ #Create list of existing model names for comparison
+ list_fnames = os.listdir(self.plugin_dir)
+ # fake existing regular model name list
+ m_list = [model.name + ".py" for model in self.model_list]
+ list_fnames.append(m_list)
+ if t_fname in list_fnames and title != mname:
+ self.good_name = False
+ msg = "Name exists already."
+
+ if self.good_name == False:
+ self.name_tcl.SetBackgroundColour('pink')
+ info = 'Error'
+ wx.MessageBox(msg, info)
+ self._notes = msg
+ color = 'red'
+ self._msg_box.SetLabel(msg)
+ self._msg_box.SetForegroundColour(color)
+ return self.good_name
+ self.fname = os.path.join(self.plugin_dir, t_fname)
+ s_title = title
+ if len(title) > 20:
+ s_title = title[0:19] + '...'
+ self._notes = "Model function (%s) has been set! \n" % str(s_title)
+ self.good_name = True
+ self.on_apply(self.fname)
+ return self.good_name
+
+ def on_apply(self, path):
+ """
+ This method is a misnomer - it is not bound to the apply button
+ event. Instead the apply button event goes to check_name which
+ then calls this method if the name of the new file is acceptable.
+
+ :TODO this should be bound to the apply button. The first line
+ should call the check_name method which itself should be in another
+ module separated from the the GUI modules.
+ """
+ self.name_tcl.SetBackgroundColour('white')
+ try:
+ label = self.get_textnames()
+ fname = path
+ name1 = label[0]
+ name2 = label[1]
+ self.write_string(fname, name1, name2)
+ success = show_model_output(self, fname)
+ if success:
+ self.parent.update_custom_combo()
+ msg = self._notes
+ info = 'Info'
+ color = 'blue'
+ except:
+ msg = "Easy Sum/Multipy Plugin: Error occurred..."
+ info = 'Error'
+ color = 'red'
+ self._msg_box.SetLabel(msg)
+ self._msg_box.SetForegroundColour(color)
+ if self.parent.parent is not None:
+ from sas.sasgui.guiframe.events import StatusEvent
+ wx.PostEvent(self.parent.parent, StatusEvent(status=msg,
+ info=info))
+
+ def on_help(self, event):
+ """
+ Bring up the Composite Model Editor Documentation whenever
+ the HELP button is clicked.
+
+ Calls DocumentationWindow with the path of the location within the
+ documentation tree (after /doc/ ....". Note that when using old
+ versions of Wx (before 2.9) and thus not the release version of
+ installers, the help comes up at the top level of the file as
+ webbrowser does not pass anything past the # to the browser when it is
+ running "file:///...."
+
+ :param evt: Triggers on clicking the help button
+ """
+
+ _TreeLocation = "user/sasgui/perspectives/fitting/fitting_help.html"
+ _PageAnchor = "#sum-multi-p1-p2"
+ _doc_viewer = DocumentationWindow(self, -1, _TreeLocation, _PageAnchor,
+ "Composite Model Editor Help")
+
+ def _set_model_list(self):
+ """
+ Set the list of models
+ """
+ # list of model names
+ # get regular models
+ main_list = self.model_list
+ # get custom models
+ self.update_cm_list()
+ # add custom models to model list
+ for name in self.cm_list:
+ if name not in main_list:
+ main_list.append(name)
+
+ if len(main_list) > 1:
+ main_list.sort()
+ for idx in range(len(main_list)):
+ self.model1.Append(str(main_list[idx]), idx)
+ self.model2.Append(str(main_list[idx]), idx)
+ self.model1.SetStringSelection(self.model1_string)
+ self.model2.SetStringSelection(self.model2_string)
+
+ def update_cm_list(self):
+ """
+ Update custom model list
+ """
+ cm_list = []
+ al_list = os.listdir(self.plugin_dir)
+ for c_name in al_list:
+ if c_name.split('.')[-1] == 'py' and \
+ c_name.split('.')[0] != '__init__':
+ name = str(c_name.split('.')[0])
+ cm_list.append(name)
+ self.cm_list = cm_list
+
+ def on_model1(self, event):
+ """
+ Set model1
+ """
+ event.Skip()
+ self.update_cm_list()
+ self.model1_name = str(self.model1.GetValue())
+ self.model1_string = self.model1_name
+ if self.model1_name in self.cm_list:
+ self.is_p1_custom = True
+ else:
+ self.is_p1_custom = False
+
+ def on_model2(self, event):
+ """
+ Set model2
+ """
+ event.Skip()
+ self.update_cm_list()
+ self.model2_name = str(self.model2.GetValue())
+ self.model2_string = self.model2_name
+ if self.model2_name in self.cm_list:
+ self.is_p2_custom = True
+ else:
+ self.is_p2_custom = False
+
+ def on_select_operator(self, event=None):
+ """
+ On Select an Operator
+ """
+ # For Mac
+ if event is not None:
+ event.Skip()
+ item = event.GetEventObject()
+ text = item.GetValue()
+ self.fill_explanation_helpstring(text)
+
+ def fill_explanation_helpstring(self, operator):
+ """
+ Choose the equation to use depending on whether we now have
+ a sum or multiply model then create the appropriate string
+ """
+ name = ''
+ if operator == '*':
+ name = 'Multi'
+ factor = 'background'
+ else:
+ name = 'Sum'
+ factor = 'scale_factor'
+
+ self._operator = operator
+ self.explanation = (" Plugin_model = scale_factor * (model_1 {} "
+ "model_2) + background").format(operator)
+ self.explanationctr.SetLabel(self.explanation)
+ self.name = name + M_NAME
+
+
+ def fill_operator_combox(self):
+ """
+ fill the current combobox with the operator
+ """
+ operator_list = ['+', '*']
+ for oper in operator_list:
+ pos = self._operator_choice.Append(str(oper))
+ self._operator_choice.SetClientData(pos, str(oper))
+ self._operator_choice.SetSelection(0)
+
+ def get_textnames(self):
+ """
+ Returns model name string as list
+ """
+ return [self.model1_name, self.model2_name]
+
+ def write_string(self, fname, model1_name, model2_name):
+ """
+ Write and Save file
+ """
+ self.fname = fname
+ description = self.desc_tcl.GetValue().lstrip().rstrip()
+ desc_line = ''
+ if description.strip() != '':
+ # Sasmodels generates a description for us. If the user provides
+ # their own description, add a line to overwrite the sasmodels one
+ desc_line = "\nmodel_info.description = '{}'".format(description)
+ name = os.path.splitext(os.path.basename(self.fname))[0]
+ output = SUM_TEMPLATE.format(name=name, model1=model1_name,
+ model2=model2_name, operator=self._operator, desc_line=desc_line)
+ with open(self.fname, 'w') as out_f:
+ out_f.write(output)
+
+ def compile_file(self, path):
+ """
+ Compile the file in the path
+ """
+ path = self.fname
+ show_model_output(self, path)
+
+ def delete_file(self, path):
+ """
+ Delete file in the path
+ """
+ _delete_file(path)
+
+
+class EditorPanel(wx.ScrolledWindow):
+ """
+ Simple Plugin Model function editor
+ """
+ def __init__(self, parent, base, path, title, *args, **kwds):
+ kwds['name'] = title
+# kwds["size"] = (EDITOR_WIDTH, EDITOR_HEIGTH)
+ kwds["style"] = wx.FULL_REPAINT_ON_RESIZE
+ wx.ScrolledWindow.__init__(self, parent, *args, **kwds)
+ self.SetScrollbars(1,1,1,1)
+ self.parent = parent
+ self.base = base
+ self.path = path
+ self.font = wx.SystemSettings_GetFont(wx.SYS_SYSTEM_FONT)
+ self.font.SetPointSize(10)
+ self.reader = None
+ self.name = 'untitled'
+ self.overwrite_name = False
+ self.is_2d = False
+ self.fname = None
+ self.main_sizer = None
+ self.name_sizer = None
+ self.name_hsizer = None
+ self.name_tcl = None
+ self.overwrite_cb = None
+ self.desc_sizer = None
+ self.desc_tcl = None
+ self.param_sizer = None
+ self.param_tcl = None
+ self.function_sizer = None
+ self.func_horizon_sizer = None
+ self.button_sizer = None
+ self.param_strings = ''
+ self.function_strings = ''
+ self._notes = ""
+ self._msg_box = None
+ self.msg_sizer = None
+ self.warning = ""
+ #This does not seem to be used anywhere so commenting out for now
+ # -- PDB 2/26/17
+ #self._description = "New Plugin Model"
+ self.function_tcl = None
+ self.math_combo = None
+ self.bt_apply = None
+ self.bt_close = None
+ #self._default_save_location = os.getcwd()
+ self._do_layout()
+
+
+
+ def _define_structure(self):
+ """
+ define initial sizer
+ """
+ #w, h = self.parent.GetSize()
+ self.main_sizer = wx.BoxSizer(wx.VERTICAL)
+ self.name_sizer = wx.BoxSizer(wx.VERTICAL)
+ self.name_hsizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.desc_sizer = wx.BoxSizer(wx.VERTICAL)
+ self.param_sizer = wx.BoxSizer(wx.VERTICAL)
+ self.function_sizer = wx.BoxSizer(wx.VERTICAL)
+ self.func_horizon_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.button_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.msg_sizer = wx.BoxSizer(wx.HORIZONTAL)
+
+ def _layout_name(self):
+ """
+ Do the layout for file/function name related widgets
+ """
+ #title name [string]
+ name_txt = wx.StaticText(self, -1, 'Function Name : ')
+ self.overwrite_cb = wx.CheckBox(self, -1, "Overwrite existing plugin model of this name?", (10, 10))
+ self.overwrite_cb.SetValue(False)
+ self.overwrite_cb.SetToolTipString("Overwrite it if already exists?")
+ wx.EVT_CHECKBOX(self, self.overwrite_cb.GetId(), self.on_over_cb)
+ self.name_tcl = wx.TextCtrl(self, -1, size=(PANEL_WIDTH * 3 / 5, -1))
+ self.name_tcl.Bind(wx.EVT_TEXT_ENTER, self.on_change_name)
+ self.name_tcl.SetValue('')
+ self.name_tcl.SetFont(self.font)
+ hint_name = "Unique Model Function Name."
+ self.name_tcl.SetToolTipString(hint_name)
+ self.name_hsizer.AddMany([(self.name_tcl, 0, wx.LEFT | wx.TOP, 0),
+ (self.overwrite_cb, 0, wx.LEFT, 20)])
+ self.name_sizer.AddMany([(name_txt, 0, wx.LEFT | wx.TOP, 10),
+ (self.name_hsizer, 0,
+ wx.LEFT | wx.TOP | wx.BOTTOM, 10)])
+
+
+ def _layout_description(self):
+ """
+ Do the layout for description related widgets
+ """
+ #title name [string]
+ desc_txt = wx.StaticText(self, -1, 'Description (optional) : ')
+ self.desc_tcl = wx.TextCtrl(self, -1, size=(PANEL_WIDTH * 3 / 5, -1))
+ self.desc_tcl.SetValue('')
+ hint_desc = "Write a short description of the model function."
+ self.desc_tcl.SetToolTipString(hint_desc)
+ self.desc_sizer.AddMany([(desc_txt, 0, wx.LEFT | wx.TOP, 10),
+ (self.desc_tcl, 0,
+ wx.LEFT | wx.TOP | wx.BOTTOM, 10)])
+ def _layout_param(self):
+ """
+ Do the layout for parameter related widgets
+ """
+ param_txt = wx.StaticText(self, -1, 'Fit Parameters NOT requiring' + \
+ ' polydispersity (if any): ')
+
+ param_tip = "#Set the parameters NOT requiring polydispersity " + \
+ "and their initial values.\n"
+ param_tip += "#Example:\n"
+ param_tip += "A = 1\nB = 1"
+ #param_txt.SetToolTipString(param_tip)
+ newid = wx.NewId()
+ self.param_tcl = EditWindow(self, newid, wx.DefaultPosition,
+ wx.DefaultSize,
+ wx.CLIP_CHILDREN | wx.SUNKEN_BORDER)
+ self.param_tcl.setDisplayLineNumbers(True)
+ self.param_tcl.SetToolTipString(param_tip)
+
+ self.param_sizer.AddMany([(param_txt, 0, wx.LEFT, 10),
+ (self.param_tcl, 1, wx.EXPAND | wx.ALL, 10)])
+
+ # Parameters with polydispersity
+ pd_param_txt = wx.StaticText(self, -1, 'Fit Parameters requiring ' + \
+ 'polydispersity (if any): ')
+
+ pd_param_tip = "#Set the parameters requiring polydispersity and " + \
+ "their initial values.\n"
+ pd_param_tip += "#Example:\n"
+ pd_param_tip += "C = 2\nD = 2"
+ newid = wx.NewId()
+ self.pd_param_tcl = EditWindow(self, newid, wx.DefaultPosition,
+ wx.DefaultSize,
+ wx.CLIP_CHILDREN | wx.SUNKEN_BORDER)
+ self.pd_param_tcl.setDisplayLineNumbers(True)
+ self.pd_param_tcl.SetToolTipString(pd_param_tip)
+
+ self.param_sizer.AddMany([(pd_param_txt, 0, wx.LEFT, 10),
+ (self.pd_param_tcl, 1, wx.EXPAND | wx.ALL, 10)])
+
+ def _layout_function(self):
+ """
+ Do the layout for function related widgets
+ """
+ function_txt = wx.StaticText(self, -1, 'Function(x) : ')
+ hint_function = "#Example:\n"
+ hint_function += "if x <= 0:\n"
+ hint_function += " y = A + B\n"
+ hint_function += "else:\n"
+ hint_function += " y = A + B * cos(2 * pi * x)\n"
+ hint_function += "return y\n"
+ math_txt = wx.StaticText(self, -1, '*Useful math functions: ')
+ math_combo = self._fill_math_combo()
+
+ newid = wx.NewId()
+ self.function_tcl = EditWindow(self, newid, wx.DefaultPosition,
+ wx.DefaultSize,
+ wx.CLIP_CHILDREN | wx.SUNKEN_BORDER)
+ self.function_tcl.setDisplayLineNumbers(True)
+ self.function_tcl.SetToolTipString(hint_function)
+
+ self.func_horizon_sizer.Add(function_txt)
+ self.func_horizon_sizer.Add(math_txt, 0, wx.LEFT, 250)
+ self.func_horizon_sizer.Add(math_combo, 0, wx.LEFT, 10)
+
+ self.function_sizer.Add(self.func_horizon_sizer, 0, wx.LEFT, 10)
+ self.function_sizer.Add(self.function_tcl, 1, wx.EXPAND | wx.ALL, 10)
+
+ def _layout_msg(self):
+ """
+ Layout msg
+ """
+ self._msg_box = wx.StaticText(self, -1, self._notes,
+ size=(PANEL_WIDTH, -1))
+ self.msg_sizer.Add(self._msg_box, 0, wx.LEFT, 10)
+
+ def _layout_button(self):
+ """
+ Do the layout for the button widgets
+ """
+ self.bt_apply = wx.Button(self, -1, "Apply", size=(_BOX_WIDTH, -1))
+ self.bt_apply.SetToolTipString("Save changes into the imported data.")
+ self.bt_apply.Bind(wx.EVT_BUTTON, self.on_click_apply)
+
+ self.bt_help = wx.Button(self, -1, "HELP", size=(_BOX_WIDTH, -1))
+ self.bt_help.SetToolTipString("Get Help For Model Editor")
+ self.bt_help.Bind(wx.EVT_BUTTON, self.on_help)
+
+ self.bt_close = wx.Button(self, -1, 'Close', size=(_BOX_WIDTH, -1))
+ self.bt_close.Bind(wx.EVT_BUTTON, self.on_close)
+ self.bt_close.SetToolTipString("Close this panel.")
+
+ self.button_sizer.AddMany([(self.bt_apply, 0,0),
+ (self.bt_help, 0, wx.LEFT | wx.BOTTOM,15),
+ (self.bt_close, 0, wx.LEFT | wx.RIGHT, 15)])
+
+ def _do_layout(self):
+ """
+ Draw the current panel
+ """
+ self._define_structure()
+ self._layout_name()
+ self._layout_description()
+ self._layout_param()
+ self._layout_function()
+ self._layout_msg()
+ self._layout_button()
+ self.main_sizer.AddMany([(self.name_sizer, 0, wx.EXPAND | wx.ALL, 5),
+ (wx.StaticLine(self), 0,
+ wx.ALL | wx.EXPAND, 5),
+ (self.desc_sizer, 0, wx.EXPAND | wx.ALL, 5),
+ (wx.StaticLine(self), 0,
+ wx.ALL | wx.EXPAND, 5),
+ (self.param_sizer, 1, wx.EXPAND | wx.ALL, 5),
+ (wx.StaticLine(self), 0,
+ wx.ALL | wx.EXPAND, 5),
+ (self.function_sizer, 2,
+ wx.EXPAND | wx.ALL, 5),
+ (wx.StaticLine(self), 0,
+ wx.ALL | wx.EXPAND, 5),
+ (self.msg_sizer, 0, wx.EXPAND | wx.ALL, 5),
+ (self.button_sizer, 0, wx.ALIGN_RIGHT)])
+ self.SetSizer(self.main_sizer)
+ self.SetAutoLayout(True)
+
+ def _fill_math_combo(self):
+ """
+ Fill up the math combo box
+ """
+ self.math_combo = wx.ComboBox(self, -1, size=(100, -1),
+ style=wx.CB_READONLY)
+ for item in dir(math):
+ if item.count("_") < 1:
+ try:
+ exec "float(math.%s)" % item
+ self.math_combo.Append(str(item))
+ except Exception:
+ self.math_combo.Append(str(item) + "()")
+ self.math_combo.Bind(wx.EVT_COMBOBOX, self._on_math_select)
+ self.math_combo.SetSelection(0)
+ return self.math_combo
+
+ def _on_math_select(self, event):
+ """
+ On math selection on ComboBox
+ """
+ event.Skip()
+ label = self.math_combo.GetValue()
+ self.function_tcl.SetFocus()
+ # Put the text at the cursor position
+ pos = self.function_tcl.GetCurrentPos()
+ self.function_tcl.InsertText(pos, label)
+ # Put the cursor at appropriate position
+ length = len(label)
+ print(length)
+ if label[length-1] == ')':
+ length -= 1
+ f_pos = pos + length
+ self.function_tcl.GotoPos(f_pos)
+
+ def get_notes(self):
+ """
+ return notes
+ """
+ return self._notes
+
+ def on_change_name(self, event=None):
+ """
+ Change name
+ """
+ if event is not None:
+ event.Skip()
+ self.name_tcl.SetBackgroundColour('white')
+ self.Refresh()
+
+ def check_name(self):
+ """
+ Check name if exist already
+ """
+ self._notes = ''
+ self.on_change_name(None)
+ plugin_dir = self.path
+ list_fnames = os.listdir(plugin_dir)
+ # function/file name
+ title = self.name_tcl.GetValue().lstrip().rstrip()
+ self.name = title
+ t_fname = title + '.py'
+ if not self.overwrite_name:
+ if t_fname in list_fnames:
+ self.name_tcl.SetBackgroundColour('pink')
+ return False
+ self.fname = os.path.join(plugin_dir, t_fname)
+ s_title = title
+ if len(title) > 20:
+ s_title = title[0:19] + '...'
+ self._notes += "Model function name is set "
+ self._notes += "to %s. \n" % str(s_title)
+ return True
+
+ def on_over_cb(self, event):
+ """
+ Set overwrite name flag on cb event
+ """
+ if event is not None:
+ event.Skip()
+ cb_value = event.GetEventObject()
+ self.overwrite_name = cb_value.GetValue()
+
+ def on_click_apply(self, event):
+ """
+ Changes are saved in data object imported to edit.
+
+ checks firs for valid name, then if it already exists then checks
+ that a function was entered and finally that if entered it contains at
+ least a return statement. If all passes writes file then tries to
+ compile. If compile fails or import module fails or run method fails
+ tries to remove any .py and pyc files that may have been created and
+ sets error message.
+
+ :todo this code still could do with a careful going over to clean
+ up and simplify. the non GUI methods such as this one should be removed
+ to computational code of SasView. Most of those computational methods
+ would be the same for both the simple editors.
+ """
+ #must post event here
+ event.Skip()
+ name = self.name_tcl.GetValue().lstrip().rstrip()
+ info = 'Info'
+ msg = ''
+ result, check_err = '', ''
+ # Sort out the errors if occur
+ # First check for valid python name then if the name already exists
+ if not name or not bool(re.match('^[A-Za-z0-9_]*$', name)):
+ msg = '"%s" '%name
+ msg += "is not a valid model name. Name must not be empty and \n"
+ msg += "may include only alpha numeric or underline characters \n"
+ msg += "and no spaces"
+ elif self.check_name():
+ description = self.desc_tcl.GetValue()
+ param_str = self.param_tcl.GetText()
+ pd_param_str = self.pd_param_tcl.GetText()
+ func_str = self.function_tcl.GetText()
+ # No input for the model function
+ if func_str.lstrip().rstrip():
+ if func_str.count('return') > 0:
+ self.write_file(self.fname, name, description, param_str,
+ pd_param_str, func_str)
+ try:
+ result, msg = check_model(self.fname), None
+ except Exception:
+ import traceback
+ result, msg = None, "error building model"
+ check_err = "\n"+traceback.format_exc(limit=2)
+ else:
+ msg = "Error: The func(x) must 'return' a value at least.\n"
+ msg += "For example: \n\nreturn 2*x"
+ else:
+ msg = 'Error: Function is not defined.'
+ else:
+ msg = "Name exists already."
+
+ #
+ if self.base is not None and not msg:
+ self.base.update_custom_combo()
+
+ # Prepare the messagebox
+ if msg:
+ info = 'Error'
+ color = 'red'
+ self.overwrite_cb.SetValue(True)
+ self.overwrite_name = True
+ else:
+ self._notes = result
+ msg = "Successful! Please look for %s in Plugin Models."%name
+ msg += " " + self._notes
+ info = 'Info'
+ color = 'blue'
+ self._msg_box.SetLabel(msg)
+ self._msg_box.SetForegroundColour(color)
+ # Send msg to the top window
+ if self.base is not None:
+ from sas.sasgui.guiframe.events import StatusEvent
+ wx.PostEvent(self.base.parent,
+ StatusEvent(status=msg+check_err, info=info))
+ self.warning = msg
+
+ def write_file(self, fname, name, desc_str, param_str, pd_param_str, func_str):
+ """
+ Write content in file
+
+ :param fname: full file path
+ :param desc_str: content of the description strings
+ :param param_str: content of params; Strings
+ :param pd_param_str: content of params requiring polydispersity; Strings
+ :param func_str: content of func; Strings
+ """
+ out_f = open(fname, 'w')
+
+ out_f.write(CUSTOM_TEMPLATE % {
+ 'name': name,
+ 'title': 'User model for ' + name,
+ 'description': desc_str,
+ 'date': datetime.datetime.now().strftime('%YYYY-%mm-%dd'),
+ })
+
+ # Write out parameters
+ param_names = [] # to store parameter names
+ pd_params = []
+ out_f.write('parameters = [ \n')
+ out_f.write('# ["name", "units", default, [lower, upper], "type", "description"],\n')
+ for pname, pvalue, desc in self.get_param_helper(param_str):
+ param_names.append(pname)
+ out_f.write(" ['%s', '', %s, [-inf, inf], '', '%s'],\n"
+ % (pname, pvalue, desc))
+ for pname, pvalue, desc in self.get_param_helper(pd_param_str):
+ param_names.append(pname)
+ pd_params.append(pname)
+ out_f.write(" ['%s', '', %s, [-inf, inf], 'volume', '%s'],\n"
+ % (pname, pvalue, desc))
+ out_f.write(' ]\n')
+
+ # Write out function definition
+ out_f.write('def Iq(%s):\n' % ', '.join(['x'] + param_names))
+ out_f.write(' """Absolute scattering"""\n')
+ if "scipy." in func_str:
+ out_f.write(' import scipy')
+ if "numpy." in func_str:
+ out_f.write(' import numpy')
+ if "np." in func_str:
+ out_f.write(' import numpy as np')
+ for func_line in func_str.split('\n'):
+ out_f.write('%s%s\n' % (spaces4, func_line))
+ out_f.write('## uncomment the following if Iq works for vector x\n')
+ out_f.write('#Iq.vectorized = True\n')
+
+ # If polydisperse, create place holders for form_volume, ER and VR
+ if pd_params:
+ out_f.write('\n')
+ out_f.write(CUSTOM_TEMPLATE_PD % {'args': ', '.join(pd_params)})
+
+ # Create place holder for Iqxy
+ out_f.write('\n')
+ out_f.write('#def Iqxy(%s):\n' % ', '.join(["x", "y"] + param_names))
+ out_f.write('# """Absolute scattering of oriented particles."""\n')
+ out_f.write('# ...\n')
+ out_f.write('# return oriented_form(x, y, args)\n')
+ out_f.write('## uncomment the following if Iqxy works for vector x, y\n')
+ out_f.write('#Iqxy.vectorized = True\n')
+
+ out_f.close()
+
+ def get_param_helper(self, param_str):
+ """
+ yield a sequence of name, value pairs for the parameters in param_str
+
+ Parameters can be defined by one per line by name=value, or multiple
+ on the same line by separating the pairs by semicolon or comma. The
+ value is optional and defaults to "1.0".
+ """
+ for line in param_str.replace(';', ',').split('\n'):
+ for item in line.split(','):
+ defn, desc = item.split('#', 1) if '#' in item else (item, '')
+ name, value = defn.split('=', 1) if '=' in defn else (defn, '1.0')
+ if name:
+ yield [v.strip() for v in (name, value, desc)]
+
+ def set_function_helper(self, line):
+ """
+ Get string in line to define the local params
+
+ :param line: one line of string got from the param_str
+ """
+ params_str = ''
+ spaces = ' '#8spaces
+ items = line.split(";")
+ for item in items:
+ name = item.split("=")[0].lstrip().rstrip()
+ params_str += spaces + "%s = self.params['%s']\n" % (name, name)
+ return params_str
+
+ def get_warning(self):
+ """
+ Get the warning msg
+ """
+ return self.warning
+
+ def on_help(self, event):
+ """
+ Bring up the New Plugin Model Editor Documentation whenever
+ the HELP button is clicked.
+
+ Calls DocumentationWindow with the path of the location within the
+ documentation tree (after /doc/ ....". Note that when using old
+ versions of Wx (before 2.9) and thus not the release version of
+ installers, the help comes up at the top level of the file as
+ webbrowser does not pass anything past the # to the browser when it is
+ running "file:///...."
+
+ :param evt: Triggers on clicking the help button
+ """
+
+ _TreeLocation = "user/sasgui/perspectives/fitting/fitting_help.html"
+ _PageAnchor = "#new-plugin-model"
+ _doc_viewer = DocumentationWindow(self, -1, _TreeLocation, _PageAnchor,
+ "Plugin Model Editor Help")
+
+ def on_close(self, event):
+ """
+ leave data as it is and close
+ """
+ self.parent.Show(False)#Close()
+ event.Skip()
+
+class EditorWindow(wx.Frame):
+ """
+ Editor Window
+ """
+ def __init__(self, parent, base, path, title,
+ size=(EDITOR_WIDTH, EDITOR_HEIGTH), *args, **kwds):
+ """
+ Init
+ """
+ kwds["title"] = title
+ kwds["size"] = size
+ wx.Frame.__init__(self, parent=None, *args, **kwds)
+ self.parent = parent
+ self.panel = EditorPanel(parent=self, base=parent,
+ path=path, title=title)
+ self.Show(True)
+ wx.EVT_CLOSE(self, self.on_close)
+
+ def on_close(self, event):
+ """
+ On close event
+ """
+ self.Show(False)
+ #if self.parent is not None:
+ # self.parent.new_model_frame = None
+ #self.Destroy()
+
+## Templates for plugin models
+
+CUSTOM_TEMPLATE = '''\
+r"""
+Definition
+----------
+
+Calculates %(name)s.
+
+%(description)s
+
+References
+----------
+
+Authorship and Verification
+---------------------------
+
+* **Author:** --- **Date:** %(date)s
+* **Last Modified by:** --- **Date:** %(date)s
+* **Last Reviewed by:** --- **Date:** %(date)s
+"""
+
+from math import *
+from numpy import inf
+
+name = "%(name)s"
+title = "%(title)s"
+description = """%(description)s"""
+
+'''
+
+CUSTOM_TEMPLATE_PD = '''\
+def form_volume(%(args)s):
+ """
+ Volume of the particles used to compute absolute scattering intensity
+ and to weight polydisperse parameter contributions.
+ """
+ return 0.0
+
+def ER(%(args)s):
+ """
+ Effective radius of particles to be used when computing structure factors.
+
+ Input parameters are vectors ranging over the mesh of polydispersity values.
+ """
+ return 0.0
+
+def VR(%(args)s):
+ """
+ Volume ratio of particles to be used when computing structure factors.
+
+ Input parameters are vectors ranging over the mesh of polydispersity values.
+ """
+ return 1.0
+'''
+
+SUM_TEMPLATE = """
+from sasmodels.core import load_model_info
+from sasmodels.sasview_model import make_model_from_info
+
+model_info = load_model_info('{model1}{operator}{model2}')
+model_info.name = '{name}'{desc_line}
+Model = make_model_from_info(model_info)
+"""
+if __name__ == "__main__":
+ main_app = wx.App()
+ main_frame = TextDialog(id=1, model_list=["SphereModel", "CylinderModel"],
+ plugin_dir='../fitting/plugin_models')
+ main_frame.ShowModal()
+ main_app.MainLoop()
diff --git a/src/sas/sasgui/perspectives/calculator/pyconsole.py b/src/sas/sasgui/perspectives/calculator/pyconsole.py
index fad994c..47e0efe 100644
--- a/src/sas/sasgui/perspectives/calculator/pyconsole.py
+++ b/src/sas/sasgui/perspectives/calculator/pyconsole.py
@@ -36,10 +36,9 @@ def check_model(path):
qx, qy = np.array([0.01, 0.01]), np.array([0.1, 0.1])
Iqxy = model.evalDistribution([qx, qy])
- result = """
- Iq(%s) = %s
- Iqxy(%s, %s) = %s
- """%(q, Iq, qx, qy, Iqxy)
+ # check the model's unit tests run
+ from sasmodels.model_test import run_one
+ result = run_one(path)
return result
@@ -88,7 +87,7 @@ class ResizableScrolledMessageDialog(wx.Dialog):
text = wx.TextCtrl(self, -1, msg, style=wx.TE_MULTILINE | wx.TE_READONLY)
ok = wx.Button(self, wx.ID_OK, "OK")
- # Mysterious constraint layouts from
+ # Mysterious constraint layouts from
# https://www.wxpython.org/docs/api/wx.lib.layoutf.Layoutf-class.html
lc = layoutf.Layoutf('t=t5#1;b=t5#2;l=l5#1;r=r5#1', (self,ok))
text.SetConstraints(lc)
@@ -117,9 +116,9 @@ class PyConsole(editor.EditorNotebookFrame):
self.base = base
self.panel = panel
self._add_menu()
- if filename != None:
+ if filename is not None:
dataDir = os.path.dirname(filename)
- elif self.parent != None:
+ elif self.parent is not None:
dataDir = self.parent._default_save_location
else:
dataDir = None
@@ -127,7 +126,7 @@ class PyConsole(editor.EditorNotebookFrame):
self.Centre()
# See if there is a corresponding C file
- if filename != None:
+ if filename is not None:
c_filename = os.path.splitext(filename)[0] + ".c"
if os.path.isfile(c_filename):
self.bufferCreate(c_filename)
@@ -243,7 +242,7 @@ class PyConsole(editor.EditorNotebookFrame):
self.bufferCreate(result.path)
# See if there is a corresponding C file
- if result.path != None:
+ if result.path is not None:
c_filename = os.path.splitext(result.path)[0] + ".c"
if os.path.isfile(c_filename):
self.bufferCreate(c_filename)
@@ -302,7 +301,7 @@ class PyConsole(editor.EditorNotebookFrame):
success = show_model_output(self, fname)
# Update plugin model list in fitpage combobox
- if success and self._manager != None and self.panel != None:
+ if success and self._manager is not None and self.panel is not None:
self._manager.set_edit_menu_helper(self.parent)
wx.CallAfter(self._manager.update_custom_combo)
@@ -336,7 +335,7 @@ class PyConsole(editor.EditorNotebookFrame):
"""
Close event
"""
- if self.base != None:
+ if self.base is not None:
self.base.py_frame = None
self.Destroy()
diff --git a/src/sas/sasgui/perspectives/calculator/resolcal_thread.py b/src/sas/sasgui/perspectives/calculator/resolcal_thread.py
index 49bea72..ef1f58e 100644
--- a/src/sas/sasgui/perspectives/calculator/resolcal_thread.py
+++ b/src/sas/sasgui/perspectives/calculator/resolcal_thread.py
@@ -1,54 +1,54 @@
-"""
-Thread for Resolution computation
-"""
-import time
-from sas.sascalc.data_util.calcthread import CalcThread
-
-class CalcRes(CalcThread):
- """
- Compute Resolution
- """
- def __init__(self,
- id= -1,
- func=None,
- qx=None,
- qy=None,
- qx_min=None,
- qx_max=None,
- qy_min=None,
- qy_max=None,
- image=None,
- completefn=None,
- updatefn=None,
- elapsed=0,
- yieldtime=0.01,
- worktime=0.01
- ):
- """
- """
- CalcThread.__init__(self, completefn,
- updatefn,
- yieldtime,
- worktime)
- self.starttime = 0
- self.id = id
- self.func = func
- self.qx = qx
- self.qy = qy
- self.qx_min = qx_min
- self.qx_max = qx_max
- self.qy_min = qy_min
- self.qy_max = qy_max
- self.image = image
-
- def compute(self):
- """
- excuting computation
- """
- self.image = map(self.func, self.qx, self.qy,
- self.qx_min, self.qx_max,
- self.qy_min, self.qy_max)[0]
- elapsed = time.time() - self.starttime
-
- self.complete(image=self.image,
+"""
+Thread for Resolution computation
+"""
+import time
+from sas.sascalc.data_util.calcthread import CalcThread
+
+class CalcRes(CalcThread):
+ """
+ Compute Resolution
+ """
+ def __init__(self,
+ id= -1,
+ func=None,
+ qx=None,
+ qy=None,
+ qx_min=None,
+ qx_max=None,
+ qy_min=None,
+ qy_max=None,
+ image=None,
+ completefn=None,
+ updatefn=None,
+ elapsed=0,
+ yieldtime=0.01,
+ worktime=0.01
+ ):
+ """
+ """
+ CalcThread.__init__(self, completefn,
+ updatefn,
+ yieldtime,
+ worktime)
+ self.starttime = 0
+ self.id = id
+ self.func = func
+ self.qx = qx
+ self.qy = qy
+ self.qx_min = qx_min
+ self.qx_max = qx_max
+ self.qy_min = qy_min
+ self.qy_max = qy_max
+ self.image = image
+
+ def compute(self):
+ """
+ excuting computation
+ """
+ self.image = map(self.func, self.qx, self.qy,
+ self.qx_min, self.qx_max,
+ self.qy_min, self.qy_max)[0]
+ elapsed = time.time() - self.starttime
+
+ self.complete(image=self.image,
elapsed=elapsed)
\ No newline at end of file
diff --git a/src/sas/sasgui/perspectives/calculator/resolution_calculator_panel.py b/src/sas/sasgui/perspectives/calculator/resolution_calculator_panel.py
index c149c4c..590a316 100644
--- a/src/sas/sasgui/perspectives/calculator/resolution_calculator_panel.py
+++ b/src/sas/sasgui/perspectives/calculator/resolution_calculator_panel.py
@@ -1,1358 +1,1360 @@
-# pylint: disable=attribute-defined-outside-init
-"""
-This software was developed by the University of Tennessee as part of the
-Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
-project funded by the US National Science Foundation.
-
-See the license text in license.txt
-
-copyright 2008, 2009, 2010 University of Tennessee
-"""
-import wx
-import sys
-import os
-import matplotlib
-import math
-import logging
-#Use the WxAgg back end. The Wx one takes too long to render
-matplotlib.use('WXAgg')
-from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
-from matplotlib.backends.backend_wxagg import NavigationToolbar2Wx as Toolbar
-from matplotlib.backend_bases import FigureManagerBase
-# Wx-Pylab magic for displaying plots within an application's window.
-from matplotlib import _pylab_helpers
-# The Figure object is used to create backend-independent plot representations.
-from matplotlib.figure import Figure
-
-#from sas.guicomm.events import StatusEvent
-from sas.sascalc.calculator.resolution_calculator import ResolutionCalculator
-from sas.sasgui.guiframe.events import StatusEvent
-from sas.sasgui.perspectives.calculator.calculator_widgets import OutputTextCtrl
-from sas.sasgui.perspectives.calculator.calculator_widgets import InputTextCtrl
-from wx.lib.scrolledpanel import ScrolledPanel
-from math import fabs
-from sas.sasgui.perspectives.calculator import calculator_widgets as widget
-from sas.sasgui.guiframe.documentation_window import DocumentationWindow
-
-_BOX_WIDTH = 100
-_Q_DEFAULT = 0.0
-#Slit length panel size
-if sys.platform.count("win32") > 0:
- PANEL_TOP = 0
- PANEL_WIDTH = 525
- PANEL_HEIGHT = 653
- FONT_VARIANT = 0
- IS_WIN = True
-else:
- PANEL_TOP = 60
- PANEL_WIDTH = 540
- PANEL_HEIGHT = 662
- FONT_VARIANT = 1
- IS_WIN = False
-
-_SOURCE_MASS = {'Alpha':6.64465620E-24,
- 'Deuteron':3.34358320E-24,
- 'Neutron':1.67492729E-24,
- 'Photon': 0.0,
- 'Proton':1.67262137E-24,
- 'Triton':5.00826667E-24}
-
-class ResolutionCalculatorPanel(ScrolledPanel):
- """
- Provides the Resolution calculator GUI.
- """
- ## Internal nickname for the window, used by the AUI manager
- window_name = "Q Resolution Estimator"
- ## Name to appear on the window title bar
- window_caption = ""
- ## Flag to tell the AUI manager to put this panel in the center pane
- CENTER_PANE = True
-
- def __init__(self, parent, *args, **kwds):
- kwds["size"] = (PANEL_WIDTH * 2, PANEL_HEIGHT)
- kwds["style"] = wx.FULL_REPAINT_ON_RESIZE
- ScrolledPanel.__init__(self, parent, *args, **kwds)
- self.SetupScrolling()
- self.parent = parent
-
- # input defaults
- self.qx = []
- self.qy = []
- # dQ defaults
- self.sigma_r = None
- self.sigma_phi = None
- self.sigma_1d = None
- # monchromatic or polychromatic
- self.wave_color = 'mono'
- self.num_wave = 10
- self.spectrum_dic = {}
- # dQ 2d image
- self.image = None
- # results of sigmas
- self.sigma_strings = ' '
- #Font size
- self.SetWindowVariant(variant=FONT_VARIANT)
- # Object that receive status event
- self.resolution = ResolutionCalculator()
- # Source selection dic
- self.source_mass = _SOURCE_MASS
- #layout attribute
- self.hint_sizer = None
- # detector coordinate of estimation of sigmas
- self.det_coordinate = 'cartesian'
- self.source_cb = None
- self._do_layout()
-
- def _define_structure(self):
- """
- Define the main sizers building to build this application.
- """
- self.main_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.vertical_l_sizer = wx.BoxSizer(wx.VERTICAL)
- self.vertical_r_spacer = wx.BoxSizer(wx.VERTICAL)
- self.vertical_r_frame = wx.StaticBox(self, -1, '')
- self.vertical_r_sizer = wx.StaticBoxSizer(self.vertical_r_frame,
- wx.VERTICAL)
- self.box_source = wx.StaticBox(self, -1, str(self.window_caption))
- self.boxsizer_source = wx.StaticBoxSizer(self.box_source, wx.VERTICAL)
- self.mass_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.intensity_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.wavelength_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.wavelength_spread_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.source_aperture_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.sample_aperture_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.source2sample_distance_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.sample2sample_distance_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.sample2detector_distance_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.detector_size_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.detector_pix_size_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.input_sizer = wx.BoxSizer(wx.VERTICAL)
- self.output_sizer = wx.BoxSizer(wx.VERTICAL)
- self.hint_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.button_sizer = wx.BoxSizer(wx.HORIZONTAL)
-
- def _layout_mass(self):
- """
- Fill the sizer containing mass
- """
- # get the mass
- mass_value = str(self.resolution.mass)
- self.mass_txt = wx.StaticText(self, -1, 'Source: ')
- self.mass_hint = "Mass of Neutrons m = %s [g]" % str(self.resolution.mass)
- self.source_cb = wx.ComboBox(self, -1,
- style=wx.CB_READONLY,
- name='%s' % mass_value)
- # Sort source name because wx2.9 on Mac does not support CB_SORT
- # Custom sorting
- source_list = []
- for key, _ in self.source_mass.iteritems():
- name_source = str(key)
- source_list.append(name_source)
- source_list.sort()
- for idx in range(len(source_list)):
- self.source_cb.Append(source_list[idx], idx)
- self.source_cb.SetStringSelection("Neutron")
- wx.EVT_COMBOBOX(self.source_cb, -1, self._on_source_selection)
-
- # combo box for color
- self.wave_color_cb = wx.ComboBox(self, -1,
- style=wx.CB_READONLY,
- name='color')
- # two choices
- self.wave_color_cb.Append('Monochromatic')
- self.wave_color_cb.Append('TOF')
- self.wave_color_cb.SetStringSelection("Monochromatic")
- wx.EVT_COMBOBOX(self.wave_color_cb, -1, self._on_source_color)
-
- source_hint = "Source Selection: Affect on"
- source_hint += " the gravitational contribution.\n"
- source_hint += "Mass of %s: m = %s [g]" % \
- ('Neutron', str(self.resolution.mass))
- self.mass_txt.SetToolTipString(source_hint)
- self.mass_sizer.AddMany([(self.mass_txt, 0, wx.LEFT, 15),
- (self.source_cb, 0, wx.LEFT, 15),
- (self.wave_color_cb, 0, wx.LEFT, 15)])
-
- def _layout_intensity(self):
- """
- Fill the sizer containing intensity
- """
- # get the intensity
- intensity_value = str(self.resolution.intensity)
- intensity_unit_txt = wx.StaticText(self, -1, '[counts/s]')
- intensity_txt = wx.StaticText(self, -1, 'Intensity: ')
- self.intensity_tcl = InputTextCtrl(self, -1,
- size=(_BOX_WIDTH, -1))
- intensity_hint = "Intensity of Neutrons"
- self.intensity_tcl.SetValue(intensity_value)
- self.intensity_tcl.SetToolTipString(intensity_hint)
- self.intensity_sizer.AddMany([(intensity_txt, 0, wx.LEFT, 15),
- (self.intensity_tcl, 0, wx.LEFT, 15),
- (intensity_unit_txt, 0, wx.LEFT, 10)])
-
-
- def _layout_wavelength(self):
- """
- Fill the sizer containing wavelength
- """
- # get the wavelength
- wavelength_value = str(self.resolution.get_wavelength())
- wavelength_unit_txt = wx.StaticText(self, -1, '[A]')
- wavelength_txt = wx.StaticText(self, -1, 'Wavelength: ')
- self.wavelength_tcl = InputTextCtrl(self, -1,
- size=(_BOX_WIDTH, -1))
- wavelength_hint = "Wavelength of Neutrons"
- self.wavelength_tcl.SetValue(wavelength_value)
- self.wavelength_tcl.SetToolTipString(wavelength_hint)
-
- # get the spectrum
- spectrum_value = self.resolution.get_default_spectrum()
- self.spectrum_dic['Add new'] = ''
- self.spectrum_dic['Flat'] = spectrum_value
-
- self.spectrum_txt = wx.StaticText(self, -1, 'Spectrum: ')
- self.spectrum_cb = wx.ComboBox(self, -1,
- style=wx.CB_READONLY,
- size=(_BOX_WIDTH, -1),
- name='spectrum')
- self.spectrum_cb.Append('Add new')
- self.spectrum_cb.Append('Flat')
- wx.EVT_COMBOBOX(self.spectrum_cb, -1, self._on_spectrum_cb)
- spectrum_hint = "Wavelength Spectrum: Intensity vs. wavelength"
- self.spectrum_cb.SetStringSelection('Flat')
- self.spectrum_cb.SetToolTipString(spectrum_hint)
- self.wavelength_sizer.AddMany([(wavelength_txt, 0, wx.LEFT, 15),
- (self.wavelength_tcl, 0, wx.LEFT, 5),
- (wavelength_unit_txt, 0, wx.LEFT, 5),
- (self.spectrum_txt, 0, wx.LEFT, 20),
- (self.spectrum_cb, 0, wx.LEFT, 5)])
- self.spectrum_txt.Show(False)
- self.spectrum_cb.Show(False)
-
- def _layout_wavelength_spread(self):
- """
- Fill the sizer containing wavelength
- """
- # get the wavelength
- wavelength_spread_value = str(self.resolution.get_wavelength_spread())
- wavelength_spread_unit_txt = wx.StaticText(self, -1, '')
- wavelength_spread_txt = wx.StaticText(self, -1, 'Wavelength Spread: ')
- self.wavelength_spread_tcl = InputTextCtrl(self, -1, size=(_BOX_WIDTH, -1))
- wavelength_spread_hint = "Wavelength Spread of Neutrons"
- self.wavelength_spread_tcl.SetValue(wavelength_spread_value)
- self.wavelength_spread_tcl.SetToolTipString(wavelength_spread_hint)
- self.wavelength_spread_sizer.AddMany([(wavelength_spread_txt, 0,
- wx.LEFT, 15),
- (self.wavelength_spread_tcl, 0, wx.LEFT, 15),
- (wavelength_spread_unit_txt, 0, wx.LEFT, 10)])
-
-
- def _layout_source_aperture(self):
- """
- Fill the sizer containing source aperture size
- """
- # get the wavelength
- source_aperture_value = str(self.resolution.source_aperture_size[0])
- if len(self.resolution.source_aperture_size) > 1:
- source_aperture_value += ", "
- source_aperture_value += str(self.resolution.source_aperture_size[1])
- source_aperture_unit_txt = wx.StaticText(self, -1, '[cm]')
- source_aperture_txt = wx.StaticText(self, -1, 'Source Aperture Size: ')
- self.source_aperture_tcl = InputTextCtrl(self, -1, size=(_BOX_WIDTH, -1))
- source_aperture_hint = "Source Aperture Size"
- self.source_aperture_tcl.SetValue(source_aperture_value)
- self.source_aperture_tcl.SetToolTipString(source_aperture_hint)
- self.source_aperture_sizer.AddMany([(source_aperture_txt, 0, wx.LEFT, 15),
- (self.source_aperture_tcl, 0, wx.LEFT, 15),
- (source_aperture_unit_txt, 0, wx.LEFT, 10)])
-
- def _layout_sample_aperture(self):
- """
- Fill the sizer containing sample aperture size
- """
- # get the wavelength
- sample_aperture_value = str(self.resolution.sample_aperture_size[0])
- if len(self.resolution.sample_aperture_size) > 1:
- sample_aperture_value += ", "
- sample_aperture_value += str(self.resolution.sample_aperture_size[1])
- sample_aperture_unit_txt = wx.StaticText(self, -1, '[cm]')
- sample_aperture_txt = wx.StaticText(self, -1, 'Sample Aperture Size: ')
- self.sample_aperture_tcl = InputTextCtrl(self, -1, size=(_BOX_WIDTH, -1))
- sample_aperture_hint = "Sample Aperture Size"
- self.sample_aperture_tcl.SetValue(sample_aperture_value)
- self.sample_aperture_tcl.SetToolTipString(sample_aperture_hint)
- self.sample_aperture_sizer.AddMany([(sample_aperture_txt, 0, wx.LEFT, 15),
- (self.sample_aperture_tcl, 0, wx.LEFT, 15),
- (sample_aperture_unit_txt, 0, wx.LEFT, 10)])
-
- def _layout_source2sample_distance(self):
- """
- Fill the sizer containing souce2sample_distance
- """
- # get the wavelength
- source2sample_distance_value = str(self.resolution.source2sample_distance[0])
-
- source2sample_distance_unit_txt = wx.StaticText(self, -1, '[cm]')
- source2sample_distance_txt = wx.StaticText(self, -1,
- 'Source to Sample Aperture Distance: ')
- self.source2sample_distance_tcl = InputTextCtrl(self, -1, size=(_BOX_WIDTH, -1))
- source2sample_distance_hint = "Source to Sample Aperture Distance"
- self.source2sample_distance_tcl.SetValue(source2sample_distance_value)
- self.source2sample_distance_tcl.SetToolTipString(source2sample_distance_hint)
- self.source2sample_distance_sizer.AddMany([(source2sample_distance_txt, 0, wx.LEFT, 15),
- (self.source2sample_distance_tcl, 0, wx.LEFT, 15),
- (source2sample_distance_unit_txt, 0, wx.LEFT, 10)])
-
- def _layout_sample2sample_distance(self):
- """
- Fill the sizer containing sampleslit2sample_distance
- """
- # get the distance
- sample2sample_distance_value = str(self.resolution.sample2sample_distance[0])
-
- sample2sample_distance_unit_txt = wx.StaticText(self, -1, '[cm]')
- sample2sample_distance_txt = wx.StaticText(self, -1, 'Sample Offset: ')
- self.sample2sample_distance_tcl = InputTextCtrl(self, -1, size=(_BOX_WIDTH, -1))
- sample2sample_distance_hint = "Sample Aperture to Sample Distance"
- self.sample2sample_distance_tcl.SetValue(sample2sample_distance_value)
- self.sample2sample_distance_tcl.SetToolTipString(sample2sample_distance_hint)
- self.sample2sample_distance_sizer.AddMany([(sample2sample_distance_txt, 0, wx.LEFT, 15),
- (self.sample2sample_distance_tcl, 0, wx.LEFT, 15),
- (sample2sample_distance_unit_txt, 0, wx.LEFT, 10)])
-
- def _layout_sample2detector_distance(self):
- """
- Fill the sizer containing sample2detector_distance
- """
- # get the wavelength
- sample2detector_distance_value = str(self.resolution.sample2detector_distance[0])
-
- sample2detector_distance_unit_txt = wx.StaticText(self, -1, '[cm]')
- sample2detector_distance_txt = wx.StaticText(self, -1,
- 'Sample Aperture to Detector Distance: ')
- self.sample2detector_distance_tcl = InputTextCtrl(self, -1, size=(_BOX_WIDTH, -1))
- sample2detector_distance_hint = "Sample Aperture to Detector Distance"
- self.sample2detector_distance_tcl.SetValue(sample2detector_distance_value)
- self.sample2detector_distance_tcl.SetToolTipString(sample2detector_distance_hint)
- self.sample2detector_distance_sizer.AddMany([\
- (sample2detector_distance_txt, 0, wx.LEFT, 15),
- (self.sample2detector_distance_tcl, 0, wx.LEFT, 15),
- (sample2detector_distance_unit_txt, 0, wx.LEFT, 10)])
-
- def _layout_detector_size(self):
- """
- Fill the sizer containing detector size
- """
- # get the wavelength
- detector_size_value = str(self.resolution.detector_size[0])
- if len(self.resolution.detector_size) > 1:
- detector_size_value += ", "
- detector_size_value += str(self.resolution.detector_size[1])
- detector_size_unit_txt = wx.StaticText(self, -1, '')
- detector_size_txt = wx.StaticText(self, -1, 'Number of Pixels on Detector: ')
- self.detector_size_tcl = InputTextCtrl(self, -1, size=(_BOX_WIDTH, -1))
- detector_size_hint = "Number of Pixels on Detector"
- self.detector_size_tcl.SetValue(detector_size_value)
- self.detector_size_tcl.SetToolTipString(detector_size_hint)
- self.detector_size_sizer.AddMany([(detector_size_txt, 0, wx.LEFT, 15),
- (self.detector_size_tcl, 0, wx.LEFT, 15),
- (detector_size_unit_txt, 0, wx.LEFT, 10)])
-
- def _layout_detector_pix_size(self):
- """
- Fill the sizer containing detector pixel size
- """
- # get the detector_pix_size
- detector_pix_size_value = str(self.resolution.detector_pix_size[0])
- if len(self.resolution.detector_pix_size) > 1:
- detector_pix_size_value += ", "
- detector_pix_size_value += str(self.resolution.detector_pix_size[1])
- detector_pix_size_unit_txt = wx.StaticText(self, -1, '[cm]')
- detector_pix_size_txt = wx.StaticText(self, -1, 'Detector Pixel Size: ')
- self.detector_pix_size_tcl = InputTextCtrl(self, -1, size=(_BOX_WIDTH, -1))
- detector_pix_size_hint = "Detector Pixel Size"
- self.detector_pix_size_tcl.SetValue(detector_pix_size_value)
- self.detector_pix_size_tcl.SetToolTipString(detector_pix_size_hint)
- self.detector_pix_size_sizer.AddMany([(detector_pix_size_txt, 0, wx.LEFT, 15),
- (self.detector_pix_size_tcl, 0, wx.LEFT, 15),
- (detector_pix_size_unit_txt, 0, wx.LEFT, 10)])
-
- def _layout_input(self):
- """
- Fill the sizer containing inputs; qx, qy
- """
-
- q_title = wx.StaticText(self, -1, "[Q Location of the Estimation]:")
- # sizers for inputs
- inputQx_sizer = wx.BoxSizer(wx.HORIZONTAL)
- inputQy_sizer = wx.BoxSizer(wx.HORIZONTAL)
- # get the default dq
- qx_value = str(_Q_DEFAULT)
- qy_value = str(_Q_DEFAULT)
- qx_unit_txt = wx.StaticText(self, -1, '[1/A] ')
- qy_unit_txt = wx.StaticText(self, -1, '[1/A] ')
- qx_name_txt = wx.StaticText(self, -1, 'Qx: ')
- qy_name_txt = wx.StaticText(self, -1, 'Qy: ')
- self.qx_tcl = InputTextCtrl(self, -1, size=(_BOX_WIDTH * 3, -1))
- self.qy_tcl = InputTextCtrl(self, -1, size=(_BOX_WIDTH * 3, -1))
- qx_hint = "Type the Qx value."
- qy_hint = "Type the Qy value."
- self.qx_tcl.SetValue(qx_value)
- self.qy_tcl.SetValue(qy_value)
- self.qx_tcl.SetToolTipString(qx_hint)
- self.qy_tcl.SetToolTipString(qy_hint)
- inputQx_sizer.AddMany([(qx_name_txt, 0, wx.LEFT, 15),
- (self.qx_tcl, 0, wx.LEFT, 15),
- (qx_unit_txt, 0, wx.LEFT, 15)])
- inputQy_sizer.AddMany([(qy_name_txt, 0, wx.LEFT, 15),
- (self.qy_tcl, 0, wx.LEFT, 15),
- (qy_unit_txt, 0, wx.LEFT, 15)])
- self.input_sizer.AddMany([(q_title, 0, wx.LEFT, 15),
- (inputQx_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
- (inputQy_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
-
- def _layout_output(self):
- """
- Fill the sizer containing dQ|| and dQ+
- """
- sigma_title = wx.StaticText(self, -1,
- "[Standard Deviation of the Resolution Distribution]:")
- # sizers for inputs
- outputQxy_sizer = wx.BoxSizer(wx.HORIZONTAL)
- outputQ_sizer = wx.BoxSizer(wx.HORIZONTAL)
- sigma_unit = '[' + '1/A' + ']'
- self.sigma_r_txt = wx.StaticText(self, -1, 'Sigma_x: ')
- self.sigma_r_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH * 0.8, -1))
- self.sigma_phi_txt = wx.StaticText(self, -1, 'Sigma_y:')
- self.sigma_phi_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH * 0.8, -1))
- self.sigma_lamd_txt = wx.StaticText(self, -1, 'Sigma_lamd:')
- self.sigma_lamd_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH * 0.7, -1))
- sigma_1d_txt = wx.StaticText(self, -1, '( 1D: Sigma:')
- self.sigma_1d_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH * 0.7, -1))
- sigmax_hint = " The x component of the geometric resolution,"
- sigmax_hint += " excluding sigma_lamda."
- sigmay_hint = " The y component of the geometric resolution,"
- sigmay_hint += " excluding sigma_lamda."
- sigma_hint_lamd = " The wavelength contribution in the radial direction"
- sigma_hint_lamd += ".\n Note: The phi component is always zero."
- sigma_hint_1d = " Resolution in 1-dimension (for 1D data)."
- self.sigma_r_tcl.SetToolTipString(sigmax_hint)
- self.sigma_phi_tcl.SetToolTipString(sigmay_hint)
- self.sigma_lamd_tcl.SetToolTipString(sigma_hint_lamd)
- self.sigma_1d_tcl.SetToolTipString(sigma_hint_1d)
- sigma_r_unit_txt = wx.StaticText(self, -1, sigma_unit)
- sigma_phi_unit_txt = wx.StaticText(self, -1, sigma_unit)
- sigma_lamd_unit_txt = wx.StaticText(self, -1, sigma_unit)
- sigma_1d_unit_txt = wx.StaticText(self, -1, sigma_unit + ' )')
- outputQxy_sizer.AddMany([(self.sigma_r_txt, 0, wx.LEFT, 15),
- (self.sigma_r_tcl, 0, wx.LEFT, 15),
- (sigma_r_unit_txt, 0, wx.LEFT, 15),
- (self.sigma_phi_txt, 0, wx.LEFT, 15),
- (self.sigma_phi_tcl, 0, wx.LEFT, 15),
- (sigma_phi_unit_txt, 0, wx.LEFT, 15)])
- outputQ_sizer.AddMany([(self.sigma_lamd_txt, 0, wx.LEFT, 15),
- (self.sigma_lamd_tcl, 0, wx.LEFT, 15),
- (sigma_lamd_unit_txt, 0, wx.LEFT, 15),
- (sigma_1d_txt, 0, wx.LEFT, 15),
- (self.sigma_1d_tcl, 0, wx.LEFT, 15),
- (sigma_1d_unit_txt, 0, wx.LEFT, 15)])
- self.output_sizer.AddMany([(sigma_title, 0, wx.LEFT, 15),
- (outputQxy_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
- (outputQ_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
-
- def _layout_hint(self):
- """
- Fill the sizer containing hint
- """
- hint_msg = ""
- #hint_msg += "This tool is to approximately compute "
- #hint_msg += "the instrumental resolution (dQ)."
-
- self.hint_txt = wx.StaticText(self, -1, hint_msg)
- self.hint_sizer.AddMany([(self.hint_txt, 0, wx.LEFT, 15)])
-
- def _layout_button(self):
- """
- Do the layout for the button widgets
- """
-
- wx_id = wx.NewId()
- self.reset_button = wx.Button(self, wx_id, "Reset")
- hint_on_reset = "..."
- self.reset_button.SetToolTipString(hint_on_reset)
- self.Bind(wx.EVT_BUTTON, self.on_reset, id=wx_id)
- #compute button
- wx_id = wx.NewId()
- self.compute_button = wx.Button(self, wx_id, "Compute")
- hint_on_compute = "Compute... Please wait until finished."
- self.compute_button.SetToolTipString(hint_on_compute)
- self.Bind(wx.EVT_BUTTON, self.on_compute, id=wx_id)
- #help button
- wx_id = wx.NewId()
- self.help_button = wx.Button(self, wx_id, "HELP")
- hint_on_help = "Help on using the Resolution Calculator"
- self.help_button.SetToolTipString(hint_on_help)
- self.Bind(wx.EVT_BUTTON, self.on_help, id=wx_id)
- # close button
- self.bt_close = wx.Button(self, wx.ID_CANCEL, 'Close')
- self.bt_close.Bind(wx.EVT_BUTTON, self.on_close)
- self.bt_close.SetToolTipString("Close this window.")
-
- self.button_sizer.Add((110, -1))
- self.button_sizer.AddMany([(self.reset_button, 0, wx.LEFT, 50),
- (self.compute_button, 0, wx.LEFT, 15),
- (self.help_button, 0, wx.LEFT, 15),
- (self.bt_close, 0, wx.LEFT, 15)])
- self.compute_button.SetFocus()
-
- def _layout_image(self):
- """
- Layout for image plot
- """
- # Contribution by James C.
- # Instantiate a figure object that will contain our plots.
- # Make the fig a little smaller than the default
- self.figure = Figure(figsize=(6.5, 6), facecolor='white')
-
- # Initialize the figure canvas, mapping the figure object to the plot
- # engine backend.
- self.canvas = FigureCanvas(self, wx.ID_ANY, self.figure)
-
- # Wx-Pylab magic ...
- # Make our canvas the active figure manager for pylab so that when
- # pylab plotting statements are executed they will operate on our
- # canvas and not create a new frame and canvas for display purposes.
- # This technique allows this application to execute code that uses
- # pylab stataments to generate plots and embed these plots in our
- # application window(s).
- self.fm = FigureManagerBase(self.canvas, 1)
- _pylab_helpers.Gcf.set_active(self.fm)
-
- # Instantiate the matplotlib navigation toolbar and explicitly show it.
- mpl_toolbar = Toolbar(self.canvas)
- # Diable pan
- mpl_toolbar.DeleteToolByPos(3)
-
- # Add a toolbar into the frame
- mpl_toolbar.Realize()
-
- # Compute before adding the canvas to the sizer
- self.on_compute()
-
- # Fill up the sizer
- if IS_WIN:
- gap = 27
- else:
- gap = 13
- self.vertical_r_sizer.Add(self.canvas, 0, wx.ALL | wx.EXPAND, 2)
- self.vertical_r_spacer.Add((0, gap))
- self.vertical_r_spacer.Add(self.vertical_r_sizer, 0, wx.ALL | wx.EXPAND, 2)
- self.vertical_r_spacer.Add((0, gap))
- self.vertical_r_spacer.Add(wx.StaticLine(self), 0, wx.ALL | wx.EXPAND, 2)
- self.vertical_r_spacer.Add(mpl_toolbar, 0, wx.ALL | wx.EXPAND, 2)
-
- def _do_layout(self):
- """
- Draw window layout
- """
- # Title of parameters
- instrument_txt = wx.StaticText(self, -1, '[Instrumental Parameters]:')
- # Build individual layouts
- self._define_structure()
- self._layout_mass()
- self._layout_wavelength()
- self._layout_wavelength_spread()
- self._layout_source_aperture()
- self._layout_sample_aperture()
- self._layout_source2sample_distance()
- self._layout_sample2detector_distance()
- self._layout_sample2sample_distance()
- self._layout_detector_size()
- self._layout_detector_pix_size()
- self._layout_input()
- self._layout_output()
- self._layout_hint()
- self._layout_button()
- # Fill the sizers
- self.boxsizer_source.AddMany([(instrument_txt, 0,
- wx.EXPAND | wx.LEFT, 15),
- (self.mass_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
- (self.wavelength_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
- (self.wavelength_spread_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
- (self.source_aperture_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
- (self.sample_aperture_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
- (self.source2sample_distance_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
- (self.sample2detector_distance_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
- (self.sample2sample_distance_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
- (self.detector_size_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
- (self.detector_pix_size_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
- (wx.StaticLine(self), 0,
- wx.ALL | wx.EXPAND, 5),
- (self.input_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
- (wx.StaticLine(self), 0,
- wx.ALL | wx.EXPAND, 5),
- (self.output_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
- self.vertical_l_sizer.AddMany([(self.boxsizer_source, 0, wx.ALL, 10),
- (wx.StaticLine(self), 0,
- wx.ALL | wx.EXPAND, 5),
- (self.button_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
- self.main_sizer.Add(self.vertical_l_sizer, 0, wx.ALL, 10)
-
- # Build image plot layout
- self._layout_image()
- # Add a vertical static line
- self.main_sizer.Add(wx.StaticLine(self, -1, (2, 2),
- (2, PANEL_HEIGHT * 0.94), style=wx.LI_VERTICAL))
- # Add the plot to main sizer
- self.main_sizer.Add(self.vertical_r_spacer, 0, wx.ALL, 10)
- self.SetSizer(self.main_sizer)
- self.SetAutoLayout(True)
-
- def on_help(self, event):
- """
- Bring up the Resolution calculator Documentation whenever
- the HELP button is clicked.
-
- Calls DocumentationWindow with the path of the location within the
- documentation tree (after /doc/ ....". Note that when using old
- versions of Wx (before 2.9) and thus not the release version of
- installers, the help comes up at the top level of the file as
- webbrowser does not pass anything past the # to the browser when it is
- running "file:///...."
-
- :param evt: Triggers on clicking the help button
- """
-
- _TreeLocation = "user/sasgui/perspectives/calculator/"
- _TreeLocation += "resolution_calculator_help.html"
- _doc_viewer = DocumentationWindow(self, -1, _TreeLocation, "",
- "Resolution Calculator Help")
-
- def on_close(self, event):
- """
- close the window containing this panel
- """
- # get ready for other events
- if event is not None:
- event.Skip()
- # Clear the plot
- if self.image != None:
- self.image.clf()
- # reset image
- self.image = None
- # Close panel
- self.parent.OnClose(None)
-
- def on_compute(self, event=None):
- """
- Execute the computation of resolution
- """
- wx.CallAfter(self.on_compute_call, event)
-
- def on_compute_call(self, event=None):
- """
- Execute the computation of resolution
- """
- # Skip event for next event
- if event != None:
- event.Skip()
- msg = "Please Check your input values "
- msg += "before starting the computation..."
-
- # message
- status_type = 'progress'
- msg = 'Calculating...'
- self._status_info(msg, status_type)
-
- status_type = 'stop'
- # Q min max list default
- qx_min = []
- qx_max = []
- qy_min = []
- qy_max = []
- # possible max qrange
- self.resolution.qxmin_limit = 0
- self.resolution.qxmax_limit = 0
- self.resolution.qymin_limit = 0
- self.resolution.qymax_limit = 0
- # q min and max of the detector
- try:
- # Get all the values at set to compute
- # default num bin of wave list
- self.num_wave = 10
- wavelength = self._str2longlist(self.wavelength_tcl.GetValue())
- source = self.source_cb.GetValue()
- mass = self.source_mass[str(source)]
- self.resolution.set_neutron_mass(float(mass))
- wavelength_spread = self._str2longlist(\
- self.wavelength_spread_tcl.GetValue().split(';')[0])
- # Validate the wave inputs
- wave_input = self._validate_q_input(wavelength, wavelength_spread)
- if wave_input != None:
- wavelength, wavelength_spread = wave_input
-
- self.resolution.set_wave(wavelength)
- self.resolution.set_wave_spread(wavelength_spread)
- source_aperture_size = self.source_aperture_tcl.GetValue()
- source_aperture_size = self._string2list(source_aperture_size)
- self.resolution.set_source_aperture_size(source_aperture_size)
- sample_aperture_size = self.sample_aperture_tcl.GetValue()
- sample_aperture_size = self._string2list(sample_aperture_size)
- self.resolution.set_sample_aperture_size(sample_aperture_size)
- source2sample_distance = self.source2sample_distance_tcl.GetValue()
- source2sample_distance = self._string2list(source2sample_distance)
- self.resolution.set_source2sample_distance(source2sample_distance)
- sample2sample_distance = self.sample2sample_distance_tcl.GetValue()
- sample2sample_distance = self._string2list(sample2sample_distance)
- self.resolution.set_sample2sample_distance(sample2sample_distance)
- sample2detector_distance = \
- self.sample2detector_distance_tcl.GetValue()
- sample2detector_distance = \
- self._string2list(sample2detector_distance)
- self.resolution.set_sample2detector_distance(\
- sample2detector_distance)
- detector_size = self.detector_size_tcl.GetValue()
- detector_size = self._string2list(detector_size)
- self.resolution.set_detector_size(detector_size)
- detector_pix_size = self.detector_pix_size_tcl.GetValue()
- detector_pix_size = self._string2list(detector_pix_size)
- self.resolution.set_detector_pix_size(detector_pix_size)
- self.qx = self._string2inputlist(self.qx_tcl.GetValue())
- self.qy = self._string2inputlist(self.qy_tcl.GetValue())
-
- # Find min max of qs
- xmin = min(self.qx)
- xmax = max(self.qx)
- ymin = min(self.qy)
- ymax = max(self.qy)
- if not self._validate_q_input(self.qx, self.qy):
- raise
- except:
- msg = "An error occured during the resolution computation."
- msg += "Please check your inputs..."
- self._status_info(msg, status_type)
- wx.MessageBox(msg, 'Warning')
- return
- #raise ValueError, "Invalid Q Input..."
-
- # Validate the q inputs
- q_input = self._validate_q_input(self.qx, self.qy)
- if q_input != None:
- self.qx, self.qy = q_input
-
- # Make list of q min max for mapping
- for i in range(len(self.qx)):
- qx_min.append(xmin)
- qx_max.append(xmax)
- for i in range(len(self.qy)):
- qy_min.append(ymin)
- qy_max.append(ymax)
-
- # Compute the resolution
- if self.image != None:
- #_pylab_helpers.Gcf.set_active(self.fm)
- _pylab_helpers.Gcf.figs = {}
- # Clear the image before redraw
- self.image.clf()
- # reset the image
- self.resolution.reset_image()
-
- # Compute and get the image plot
- try:
- from sas.sasgui.perspectives.calculator.resolcal_thread import CalcRes as thread
- self.sigma_strings = '\nResolution: Computation is finished. \n'
- cal_res = thread(func=self._map_func,
- qx=self.qx,
- qy=self.qy,
- qx_min=qx_min,
- qx_max=qx_max,
- qy_min=qy_min,
- qy_max=qy_max,
- image=self.image,
- completefn=self.complete)
- cal_res.queue()
- msg = "Computation is in progress..."
- status_type = 'progress'
- self._status_info(msg, status_type)
- except:
- raise
-
- def complete(self, image, elapsed=None):
- """
- Callafter complete: wx call after needed for stable output
- """
- wx.CallAfter(self.complete_cal, image, elapsed)
-
- def complete_cal(self, image, elapsed=None):
- """
- Complete computation
- """
- self.image = image
- # Draw lines in image before drawing
- wave_list, _ = self.resolution.get_wave_list()
- if len(wave_list) > 1 and wave_list[-1] == max(wave_list):
- # draw a green rectangle(limit for the longest wavelength
- # to be involved) for tof inputs
- self._draw_lines(self.image, color='g')
- self._draw_lines(self.image, color='r')
- # Draw image
- self.image.draw()
-
- # Get and format the sigmas
- sigma_r = self.format_number(self.resolution.sigma_1)
- sigma_phi = self.format_number(self.resolution.sigma_2)
- sigma_lamd = self.format_number(self.resolution.sigma_lamd)
- sigma_1d = self.format_number(self.resolution.sigma_1d)
-
- # Set output values
- self.sigma_r_tcl.SetValue(str(sigma_r))
- self.sigma_phi_tcl.SetValue(str(sigma_phi))
- self.sigma_lamd_tcl.SetValue(str(sigma_lamd))
- self.sigma_1d_tcl.SetValue(str(sigma_1d))
- msg = self.sigma_strings
- msg += "\n"
- status_type = 'stop'
- self._status_info(msg, status_type)
-
- def _draw_lines(self, image=None, color='r'):
- """
- Draw lines in image if applicable
- : Param image: pylab object
- """
- if image == None:
- return
- if color == 'g':
- # Get the params from resolution
- # ploting range for largest wavelength
- qx_min = self.resolution.qx_min
- qx_max = self.resolution.qx_max
- qy_min = self.resolution.qy_min
- qy_max = self.resolution.qy_max
- # detector range
- detector_qx_min = self.resolution.detector_qx_min
- detector_qx_max = self.resolution.detector_qx_max
- detector_qy_min = self.resolution.detector_qy_min
- detector_qy_max = self.resolution.detector_qy_max
- else:
- qx_min, qx_max, qy_min, qy_max = \
- self.resolution.get_detector_qrange()
- # detector range
- detector_qx_min = self.resolution.qxmin_limit
- detector_qx_max = self.resolution.qxmax_limit
- detector_qy_min = self.resolution.qymin_limit
- detector_qy_max = self.resolution.qymax_limit
-
- # Draw zero axis lines
- if qy_min < 0 and qy_max >= 0:
- image.axhline(linewidth=1)
- if qx_min < 0 and qx_max >= 0:
- image.axvline(linewidth=1)
-
- # Find x and y ratio values to draw the detector outline
- x_min = fabs(detector_qx_min - qx_min) / (qx_max - qx_min)
- x_max = fabs(detector_qx_max - qx_min) / (qx_max - qx_min)
- y_min = fabs(detector_qy_min - qy_min) / (qy_max - qy_min)
- y_max = fabs(detector_qy_max - qy_min) / (qy_max - qy_min)
-
- # Draw Detector outline
- if detector_qy_min >= qy_min:
- image.axhline(y=detector_qy_min + 0.0002,
- xmin=x_min, xmax=x_max,
- linewidth=2, color=color)
- if detector_qy_max <= qy_max:
- image.axhline(y=detector_qy_max - 0.0002,
- xmin=x_min, xmax=x_max,
- linewidth=2, color=color)
- if detector_qx_min >= qx_min:
- image.axvline(x=detector_qx_min + 0.0002,
- ymin=y_min, ymax=y_max,
- linewidth=2, color=color)
- if detector_qx_max <= qx_max:
- image.axvline(x=detector_qx_max - 0.0002,
- ymin=y_min, ymax=y_max,
- linewidth=2, color=color)
- xmin = min(self.qx)
- xmax = max(self.qx)
- ymin = min(self.qy)
- ymax = max(self.qy)
- if color != 'g':
- if xmin < detector_qx_min or xmax > detector_qx_max or \
- ymin < detector_qy_min or ymax > detector_qy_max:
- # message
- status_type = 'stop'
- msg = 'At least one q value located out side of\n'
- msg += " the detector range (%s < qx < %s, %s < qy < %s),\n" % \
- (self.format_number(detector_qx_min),
- self.format_number(detector_qx_max),
- self.format_number(detector_qy_min),
- self.format_number(detector_qy_max))
- msg += " is ignored in computation.\n"
-
- self._status_info(msg, status_type)
- wx.MessageBox(msg, 'Warning')
-
- def _map_func(self, qx, qy, qx_min, qx_max, qy_min, qy_max):
- """
- Prepare the Mapping for the computation
- : params qx, qy, qx_min, qx_max, qy_min, qy_max:
-
- : return: image (pylab)
- """
- try:
- qx_value = float(qx)
- qy_value = float(qy)
- except:
- raise
- # calculate 2D resolution distribution image
- image = self.resolution.compute_and_plot(qx_value, qy_value,
- qx_min, qx_max, qy_min, qy_max,
- self.det_coordinate)
- # record sigmas
- self.sigma_strings += " At Qx = %s, Qy = %s; \n" % (qx_value, qy_value)
- self._sigma_strings()
- return image
-
- def _sigma_strings(self):
- """
- Recode sigmas as strins
- """
- sigma_r = self.format_number(self.resolution.sigma_1)
- sigma_phi = self.format_number(self.resolution.sigma_2)
- sigma_lamd = self.format_number(self.resolution.sigma_lamd)
- sigma_1d = self.format_number(self.resolution.sigma_1d)
- # Set output values
- self.sigma_strings += " sigma_x = %s\n" % sigma_r
- self.sigma_strings += " sigma_y = %s\n" % sigma_phi
- self.sigma_strings += " sigma_lamd = %s\n" % sigma_lamd
- self.sigma_strings += " sigma_1D = %s\n" % sigma_1d
-
- def _validate_q_input(self, qx, qy):
- """
- Check if q inputs are valid
- : params qx: qx as a list
- : params qy: qy as a list
-
- : return: True/False
- """
- # check qualifications
- if qx.__class__.__name__ != 'list':
- return None
- if qy.__class__.__name__ != 'list':
- return None
- if len(qx) < 1:
- return None
- if len(qy) < 1:
- return None
- # allow one input
- if len(qx) == 1 and len(qy) > 1:
- qx = [qx[0] for ind in range(len(qy))]
- #self.qx = qx
- if len(qy) == 1 and len(qx) > 1:
- qy = [qy[0] for ind in range(len(qx))]
- #self.qy = qy
- # check length
- if len(qx) != len(qy):
- return None
- if qx == None or qy == None:
- return None
- return qx, qy
-
- def on_reset(self, event):
- """
- Execute the reset
- """
- # skip for another event
- if event != None:
- event.Skip()
- # init resolution_calculator
- self.resolution = ResolutionCalculator()
- self.resolution.get_all_instrument_params()
- # reset all param values
- self.source_cb.SetValue('Neutron')
- self._on_source_selection(None)
- self.wave_color_cb.SetValue('Monochromatic')
- self._on_source_color(None)
- #self.intensity_tcl.SetValue(str(self.resolution.intensity))
- self.wavelength_tcl.SetValue(str(6.0))
- self.wavelength_spread_tcl.SetValue(str(0.125))
- self.resolution.set_spectrum(self.spectrum_dic['Flat'])
- self.spectrum_txt.Show(False)
- self.spectrum_cb.Show(False)
- source_aperture_value = str(self.resolution.source_aperture_size[0])
- if len(self.resolution.source_aperture_size) > 1:
- source_aperture_value += ", "
- source_aperture_value += \
- str(self.resolution.source_aperture_size[1])
- self.source_aperture_tcl.SetValue(str(source_aperture_value))
- sample_aperture_value = str(self.resolution.sample_aperture_size[0])
- if len(self.resolution.sample_aperture_size) > 1:
- sample_aperture_value += ", "
- sample_aperture_value += \
- str(self.resolution.sample_aperture_size[1])
- self.sample_aperture_tcl.SetValue(sample_aperture_value)
- source2sample_distance_value = \
- str(self.resolution.source2sample_distance[0])
- self.source2sample_distance_tcl.SetValue(source2sample_distance_value)
- sample2sample_distance_value = \
- str(self.resolution.sample2sample_distance[0])
- self.sample2sample_distance_tcl.SetValue(sample2sample_distance_value)
- sample2detector_distance_value = \
- str(self.resolution.sample2detector_distance[0])
- self.sample2detector_distance_tcl.SetValue(\
- sample2detector_distance_value)
- detector_size_value = str(self.resolution.detector_size[0])
- if len(self.resolution.detector_size) > 1:
- detector_size_value += ", "
- detector_size_value += str(self.resolution.detector_size[1])
- self.detector_size_tcl.SetValue(detector_size_value)
- detector_pix_size_value = str(self.resolution.detector_pix_size[0])
- if len(self.resolution.detector_pix_size) > 1:
- detector_pix_size_value += ", "
- detector_pix_size_value += str(self.resolution.detector_pix_size[1])
- self.detector_pix_size_tcl.SetValue(detector_pix_size_value)
- #layout attribute
- self.hint_sizer = None
- # reset q inputs
- self.qx_tcl.SetValue(str(_Q_DEFAULT))
- self.qy_tcl.SetValue(str(_Q_DEFAULT))
- # reset sigma outputs
- self.sigma_r_tcl.SetValue('')
- self.sigma_phi_tcl.SetValue('')
- self.sigma_1d_tcl.SetValue('')
- # reset radio button
- #self.r_phi_rb.SetValue(True)
- # Finally re-compute
- self.on_compute()
- # msg on info
- msg = " Finished the resetting..."
- self._status_info(msg, 'stop')
-
- def format_number(self, value=None):
- """
- Return a float in a standardized, human-readable formatted string
- """
- try:
- value = float(value)
- except:
- output = None
- return output
-
- output = "%-7.4g" % value
- return output.lstrip().rstrip()
-
- def _string2list(self, string):
- """
- Change NNN, NNN to list,ie. [NNN, NNN] where NNN is a number
- """
- new_string = []
- # check the number of floats
- try:
- strg = float(string)
- new_string.append(strg)
- except:
- string_split = string.split(',')
- if len(string_split) == 2:
- str_1 = string_split[0]
- str_2 = string_split[1]
- new_string.append(float(str_1))
- new_string.append(float(str_2))
- elif len(string_split) == 1:
- str_1 = string_split[0]
- new_string.append(float(str_1))
- else:
- msg = "The numbers must be one or two (separated by ',')..."
- self._status_info(msg, 'stop')
- raise RuntimeError, msg
-
- return new_string
-
- def _string2inputlist(self, string):
- """
- Change NNN, NNN,... to list,ie. [NNN, NNN,...] where NNN is a number
-
- : return new_string: string like list
- """
- new_string = []
- string_split = string.split(',')
- length = len(string_split)
- for ind in range(length):
- try:
- value = float(string_split[ind])
- new_string.append(value)
- except:
- logging.error(sys.exc_value)
-
- return new_string
-
- def _str2longlist(self, string):
- """
- Change NNN, NNN,... to list, NNN - NNN ; NNN to list, or float to list
-
- : return new_string: string like list
- """
- msg = "Wrong format of intputs."
- try:
- # is float
- out = [float(string)]
- return out
- except:
- if self.wave_color.lower().count('mono') > 0:
- wx.MessageBox(msg, 'Warning')
- else:
- try:
- # has a '-'
- if string.count('-') > 0:
- value = string.split('-')
- if value[1].count(';') > 0:
- # has a ';'
- last_list = value[1].split(';')
- num = math.ceil(float(last_list[1]))
- max_value = float(last_list[0])
- self.num_wave = num
- else:
- # default num
- num = self.num_wave
- max_value = float(value[1])
- min_value = float(value[0])
- # make a list
- bin_size = math.fabs(max_value - min_value) / (num - 1)
- out = [min_value + bin_size * bnum for bnum in range(num)]
- return out
- if string.count(',') > 0:
- out = self._string2inputlist(string)
- return out
- except:
- logging.error(sys.exc_value)
-
- def _on_xy_coordinate(self, event=None):
- """
- Set the detector coordinate for sigmas to x-y coordinate
- """
- if event != None:
- event.Skip()
- # Set the coordinate in Cartesian
- self.det_coordinate = 'cartesian'
- self.sigma_r_txt.SetLabel('Sigma_x:')
- self.sigma_phi_txt.SetLabel('Sigma_y:')
- self._onparamEnter()
-
- def _on_rp_coordinate(self, event=None):
- """
- Set the detector coordinate for sigmas to polar coordinate
- """
- if event != None:
- event.Skip()
- # Set the coordinate in polar
- self.det_coordinate = 'polar'
- self.sigma_r_txt.SetLabel('Sigma_r: ')
- self.sigma_phi_txt.SetLabel('Sigma_phi:')
- self._onparamEnter()
-
- def _status_info(self, msg='', type="update"):
- """
- Status msg
- """
- if type == "stop":
- label = "Compute"
- able = True
- else:
- label = "Wait..."
- able = False
- self.compute_button.Enable(able)
- self.compute_button.SetLabel(label)
- self.compute_button.SetToolTipString(label)
- if self.parent.parent != None:
- wx.PostEvent(self.parent.parent,
- StatusEvent(status=msg, type=type))
-
-
- def _onparamEnter(self, event=None):
- """
- On Text_enter_callback, perform compute
- """
- self.on_compute()
-
- def _on_source_selection(self, event=None):
- """
- On source combobox selection
- """
- if event != None:
- combo = event.GetEventObject()
- event.Skip()
- else:
- combo = self.source_cb
- selection = combo.GetValue()
- mass = self.source_mass[selection]
- self.resolution.set_neutron_mass(mass)
- source_hint = "Source Selection: Affect on"
- source_hint += " the gravitational contribution.\n"
- source_hint += "Mass of %s: m = %s [g]" % \
- (selection, str(self.resolution.get_neutron_mass()))
- #source_tip.SetTip(source_hint)
- self.mass_txt.ToolTip.SetTip(source_hint)
-
- def _on_source_color(self, event=None):
- """
- On source color combobox selection
- """
- if event != None:
- #combo = event.GetEventObject()
- event.Skip()
- #else:
- combo = self.wave_color_cb
- selection = combo.GetValue()
- self.wave_color = selection
- if self.wave_color.lower() == 'tof':
- list = self.resolution.get_wave_list()
- minw = min(list[0])
- if len(list[0]) < 2:
- maxw = 2 * minw
- else:
- maxw = max(list[0])
- self.wavelength_tcl.SetValue('%s - %s' % (minw, maxw))
- minw = min(list[1])
- maxw = max(list[1])
- self.wavelength_spread_tcl.SetValue('%s - %s' % (minw, maxw))
- spectrum_val = self.spectrum_cb.GetValue()
- self.resolution.set_spectrum(self.spectrum_dic[spectrum_val])
- self.spectrum_txt.Show(True)
- self.spectrum_cb.Show(True)
-
- else:
- wavelength = self.resolution.get_wavelength()
- wavelength_spread = self.resolution.get_wavelength_spread()
- self.wavelength_tcl.SetValue(str(wavelength))
- self.wavelength_spread_tcl.SetValue(str(wavelength_spread))
- self.resolution.set_spectrum(self.spectrum_dic['Flat'])
- self.spectrum_txt.Show(False)
- self.spectrum_cb.Show(False)
- self.wavelength_sizer.Layout()
- self.Layout()
-
- def _on_spectrum_cb(self, event=None):
- """
- On spectrum ComboBox event
- """
- if event != None:
- #combo = event.GetEventObject()
- event.Skip()
- else:
- raise
- selection = self.spectrum_cb.GetValue()
- if selection == 'Add new':
- path = self._selectDlg()
- if path == None:
- self.spectrum_cb.SetValue('Flat')
- self.resolution.set_spectrum(self.spectrum_dic['Flat'])
- msg = "No file has been chosen."
- wx.MessageBox(msg, 'Info')
- return
- try:
- basename = os.path.basename(path)
- if basename not in self.spectrum_dic.keys():
- self.spectrum_cb.Append(basename)
- self.spectrum_dic[basename] = self._read_file(path)
- self.spectrum_cb.SetValue(basename)
- self.resolution.set_spectrum(self.spectrum_dic[basename])
- return
- except:
- raise
-
- self.resolution.set_spectrum(self.spectrum_dic[selection])
-
- def _selectDlg(self):
- """
- open a dialog file to select a customized spectrum
- """
- dlg = wx.FileDialog(self,
- "Choose a wavelength spectrum file: Intensity vs. wavelength",
- self.parent.parent.get_save_location() , "", "*.*", wx.OPEN)
- path = None
- if dlg.ShowModal() == wx.ID_OK:
- path = dlg.GetPath()
- dlg.Destroy()
- return path
-
- def _read_file(self, path):
- """
- Read two columns file as tuples of numpy array
-
- :param path: the path to the file to read
-
- """
- try:
- if path == None:
- wx.PostEvent(self.parent.parent, StatusEvent(status=\
- " Selected Distribution was not loaded: %s" % path))
- return None, None
- input_f = open(path, 'r')
- buff = input_f.read()
- lines = buff.split('\n')
-
- wavelength = []
- intensity = []
- for line in lines:
- toks = line.split()
- try:
- wave = float(toks[0])
- intens = float(toks[1])
- wavelength.append(wave)
- intensity.append(intens)
- except:
- # Skip non-data lines
- logging.error(sys.exc_value)
-
- return [wavelength, intensity]
- except:
- raise
-
-class ResolutionWindow(widget.CHILD_FRAME):
- """
- Resolution Window
- """
- def __init__(self, parent=None, manager=None,
- title="Q Resolution Estimator",
- size=(PANEL_WIDTH * 2, PANEL_HEIGHT), *args, **kwds):
- kwds['title'] = title
- kwds['size'] = size
- widget.CHILD_FRAME.__init__(self, parent=parent, *args, **kwds)
- self.parent = parent
- self.manager = manager
- self.panel = ResolutionCalculatorPanel(parent=self)
- self.Bind(wx.EVT_CLOSE, self.OnClose)
- self.SetPosition((wx.LEFT, PANEL_TOP))
- self.Show(True)
-
- def OnClose(self, event):
- """
- On close event
- """
- _pylab_helpers.Gcf.figs = {}
- if self.manager != None:
- self.manager.cal_res_frame = None
- self.Destroy()
-
-
-if __name__ == "__main__":
- app = wx.PySimpleApp()
- widget.CHILD_FRAME = wx.Frame
- frame = ResolutionWindow()
- frame.Show(True)
- app.MainLoop()
+# pylint: disable=attribute-defined-outside-init
+"""
+This software was developed by the University of Tennessee as part of the
+Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
+project funded by the US National Science Foundation.
+
+See the license text in license.txt
+
+copyright 2008, 2009, 2010 University of Tennessee
+"""
+import wx
+import sys
+import os
+import matplotlib
+import math
+import logging
+#Use the WxAgg back end. The Wx one takes too long to render
+matplotlib.use('WXAgg')
+from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
+from matplotlib.backends.backend_wxagg import NavigationToolbar2Wx as Toolbar
+from matplotlib.backend_bases import FigureManagerBase
+# Wx-Pylab magic for displaying plots within an application's window.
+from matplotlib import _pylab_helpers
+# The Figure object is used to create backend-independent plot representations.
+from matplotlib.figure import Figure
+
+#from sas.guicomm.events import StatusEvent
+from sas.sascalc.calculator.resolution_calculator import ResolutionCalculator
+from sas.sasgui.guiframe.events import StatusEvent
+from sas.sasgui.perspectives.calculator.calculator_widgets import OutputTextCtrl
+from sas.sasgui.perspectives.calculator.calculator_widgets import InputTextCtrl
+from wx.lib.scrolledpanel import ScrolledPanel
+from math import fabs
+from sas.sasgui.perspectives.calculator import calculator_widgets as widget
+from sas.sasgui.guiframe.documentation_window import DocumentationWindow
+
+logger = logging.getLogger(__name__)
+
+_BOX_WIDTH = 100
+_Q_DEFAULT = 0.0
+#Slit length panel size
+if sys.platform.count("win32") > 0:
+ PANEL_TOP = 0
+ PANEL_WIDTH = 525
+ PANEL_HEIGHT = 653
+ FONT_VARIANT = 0
+ IS_WIN = True
+else:
+ PANEL_TOP = 60
+ PANEL_WIDTH = 540
+ PANEL_HEIGHT = 662
+ FONT_VARIANT = 1
+ IS_WIN = False
+
+_SOURCE_MASS = {'Alpha':6.64465620E-24,
+ 'Deuteron':3.34358320E-24,
+ 'Neutron':1.67492729E-24,
+ 'Photon': 0.0,
+ 'Proton':1.67262137E-24,
+ 'Triton':5.00826667E-24}
+
+class ResolutionCalculatorPanel(ScrolledPanel):
+ """
+ Provides the Resolution calculator GUI.
+ """
+ ## Internal nickname for the window, used by the AUI manager
+ window_name = "Q Resolution Estimator"
+ ## Name to appear on the window title bar
+ window_caption = ""
+ ## Flag to tell the AUI manager to put this panel in the center pane
+ CENTER_PANE = True
+
+ def __init__(self, parent, *args, **kwds):
+ kwds["size"] = (PANEL_WIDTH * 2, PANEL_HEIGHT)
+ kwds["style"] = wx.FULL_REPAINT_ON_RESIZE
+ ScrolledPanel.__init__(self, parent, *args, **kwds)
+ self.SetupScrolling()
+ self.parent = parent
+
+ # input defaults
+ self.qx = []
+ self.qy = []
+ # dQ defaults
+ self.sigma_r = None
+ self.sigma_phi = None
+ self.sigma_1d = None
+ # monchromatic or polychromatic
+ self.wave_color = 'mono'
+ self.num_wave = 10
+ self.spectrum_dic = {}
+ # dQ 2d image
+ self.image = None
+ # results of sigmas
+ self.sigma_strings = ' '
+ #Font size
+ self.SetWindowVariant(variant=FONT_VARIANT)
+ # Object that receive status event
+ self.resolution = ResolutionCalculator()
+ # Source selection dic
+ self.source_mass = _SOURCE_MASS
+ #layout attribute
+ self.hint_sizer = None
+ # detector coordinate of estimation of sigmas
+ self.det_coordinate = 'cartesian'
+ self.source_cb = None
+ self._do_layout()
+
+ def _define_structure(self):
+ """
+ Define the main sizers building to build this application.
+ """
+ self.main_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.vertical_l_sizer = wx.BoxSizer(wx.VERTICAL)
+ self.vertical_r_spacer = wx.BoxSizer(wx.VERTICAL)
+ self.vertical_r_frame = wx.StaticBox(self, -1, '')
+ self.vertical_r_sizer = wx.StaticBoxSizer(self.vertical_r_frame,
+ wx.VERTICAL)
+ self.box_source = wx.StaticBox(self, -1, str(self.window_caption))
+ self.boxsizer_source = wx.StaticBoxSizer(self.box_source, wx.VERTICAL)
+ self.mass_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.intensity_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.wavelength_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.wavelength_spread_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.source_aperture_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.sample_aperture_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.source2sample_distance_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.sample2sample_distance_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.sample2detector_distance_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.detector_size_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.detector_pix_size_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.input_sizer = wx.BoxSizer(wx.VERTICAL)
+ self.output_sizer = wx.BoxSizer(wx.VERTICAL)
+ self.hint_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.button_sizer = wx.BoxSizer(wx.HORIZONTAL)
+
+ def _layout_mass(self):
+ """
+ Fill the sizer containing mass
+ """
+ # get the mass
+ mass_value = str(self.resolution.mass)
+ self.mass_txt = wx.StaticText(self, -1, 'Source: ')
+ self.mass_hint = "Mass of Neutrons m = %s [g]" % str(self.resolution.mass)
+ self.source_cb = wx.ComboBox(self, -1,
+ style=wx.CB_READONLY,
+ name='%s' % mass_value)
+ # Sort source name because wx2.9 on Mac does not support CB_SORT
+ # Custom sorting
+ source_list = []
+ for key, _ in self.source_mass.iteritems():
+ name_source = str(key)
+ source_list.append(name_source)
+ source_list.sort()
+ for idx in range(len(source_list)):
+ self.source_cb.Append(source_list[idx], idx)
+ self.source_cb.SetStringSelection("Neutron")
+ wx.EVT_COMBOBOX(self.source_cb, -1, self._on_source_selection)
+
+ # combo box for color
+ self.wave_color_cb = wx.ComboBox(self, -1,
+ style=wx.CB_READONLY,
+ name='color')
+ # two choices
+ self.wave_color_cb.Append('Monochromatic')
+ self.wave_color_cb.Append('TOF')
+ self.wave_color_cb.SetStringSelection("Monochromatic")
+ wx.EVT_COMBOBOX(self.wave_color_cb, -1, self._on_source_color)
+
+ source_hint = "Source Selection: Affect on"
+ source_hint += " the gravitational contribution.\n"
+ source_hint += "Mass of %s: m = %s [g]" % \
+ ('Neutron', str(self.resolution.mass))
+ self.mass_txt.SetToolTipString(source_hint)
+ self.mass_sizer.AddMany([(self.mass_txt, 0, wx.LEFT, 15),
+ (self.source_cb, 0, wx.LEFT, 15),
+ (self.wave_color_cb, 0, wx.LEFT, 15)])
+
+ def _layout_intensity(self):
+ """
+ Fill the sizer containing intensity
+ """
+ # get the intensity
+ intensity_value = str(self.resolution.intensity)
+ intensity_unit_txt = wx.StaticText(self, -1, '[counts/s]')
+ intensity_txt = wx.StaticText(self, -1, 'Intensity: ')
+ self.intensity_tcl = InputTextCtrl(self, -1,
+ size=(_BOX_WIDTH, -1))
+ intensity_hint = "Intensity of Neutrons"
+ self.intensity_tcl.SetValue(intensity_value)
+ self.intensity_tcl.SetToolTipString(intensity_hint)
+ self.intensity_sizer.AddMany([(intensity_txt, 0, wx.LEFT, 15),
+ (self.intensity_tcl, 0, wx.LEFT, 15),
+ (intensity_unit_txt, 0, wx.LEFT, 10)])
+
+
+ def _layout_wavelength(self):
+ """
+ Fill the sizer containing wavelength
+ """
+ # get the wavelength
+ wavelength_value = str(self.resolution.get_wavelength())
+ wavelength_unit_txt = wx.StaticText(self, -1, '[A]')
+ wavelength_txt = wx.StaticText(self, -1, 'Wavelength: ')
+ self.wavelength_tcl = InputTextCtrl(self, -1,
+ size=(_BOX_WIDTH, -1))
+ wavelength_hint = "Wavelength of Neutrons"
+ self.wavelength_tcl.SetValue(wavelength_value)
+ self.wavelength_tcl.SetToolTipString(wavelength_hint)
+
+ # get the spectrum
+ spectrum_value = self.resolution.get_default_spectrum()
+ self.spectrum_dic['Add new'] = ''
+ self.spectrum_dic['Flat'] = spectrum_value
+
+ self.spectrum_txt = wx.StaticText(self, -1, 'Spectrum: ')
+ self.spectrum_cb = wx.ComboBox(self, -1,
+ style=wx.CB_READONLY,
+ size=(_BOX_WIDTH, -1),
+ name='spectrum')
+ self.spectrum_cb.Append('Add new')
+ self.spectrum_cb.Append('Flat')
+ wx.EVT_COMBOBOX(self.spectrum_cb, -1, self._on_spectrum_cb)
+ spectrum_hint = "Wavelength Spectrum: Intensity vs. wavelength"
+ self.spectrum_cb.SetStringSelection('Flat')
+ self.spectrum_cb.SetToolTipString(spectrum_hint)
+ self.wavelength_sizer.AddMany([(wavelength_txt, 0, wx.LEFT, 15),
+ (self.wavelength_tcl, 0, wx.LEFT, 5),
+ (wavelength_unit_txt, 0, wx.LEFT, 5),
+ (self.spectrum_txt, 0, wx.LEFT, 20),
+ (self.spectrum_cb, 0, wx.LEFT, 5)])
+ self.spectrum_txt.Show(False)
+ self.spectrum_cb.Show(False)
+
+ def _layout_wavelength_spread(self):
+ """
+ Fill the sizer containing wavelength
+ """
+ # get the wavelength
+ wavelength_spread_value = str(self.resolution.get_wavelength_spread())
+ wavelength_spread_unit_txt = wx.StaticText(self, -1, '')
+ wavelength_spread_txt = wx.StaticText(self, -1, 'Wavelength Spread: ')
+ self.wavelength_spread_tcl = InputTextCtrl(self, -1, size=(_BOX_WIDTH, -1))
+ wavelength_spread_hint = "Wavelength Spread of Neutrons"
+ self.wavelength_spread_tcl.SetValue(wavelength_spread_value)
+ self.wavelength_spread_tcl.SetToolTipString(wavelength_spread_hint)
+ self.wavelength_spread_sizer.AddMany([(wavelength_spread_txt, 0,
+ wx.LEFT, 15),
+ (self.wavelength_spread_tcl, 0, wx.LEFT, 15),
+ (wavelength_spread_unit_txt, 0, wx.LEFT, 10)])
+
+
+ def _layout_source_aperture(self):
+ """
+ Fill the sizer containing source aperture size
+ """
+ # get the wavelength
+ source_aperture_value = str(self.resolution.source_aperture_size[0])
+ if len(self.resolution.source_aperture_size) > 1:
+ source_aperture_value += ", "
+ source_aperture_value += str(self.resolution.source_aperture_size[1])
+ source_aperture_unit_txt = wx.StaticText(self, -1, '[cm]')
+ source_aperture_txt = wx.StaticText(self, -1, 'Source Aperture Size: ')
+ self.source_aperture_tcl = InputTextCtrl(self, -1, size=(_BOX_WIDTH, -1))
+ source_aperture_hint = "Source Aperture Size"
+ self.source_aperture_tcl.SetValue(source_aperture_value)
+ self.source_aperture_tcl.SetToolTipString(source_aperture_hint)
+ self.source_aperture_sizer.AddMany([(source_aperture_txt, 0, wx.LEFT, 15),
+ (self.source_aperture_tcl, 0, wx.LEFT, 15),
+ (source_aperture_unit_txt, 0, wx.LEFT, 10)])
+
+ def _layout_sample_aperture(self):
+ """
+ Fill the sizer containing sample aperture size
+ """
+ # get the wavelength
+ sample_aperture_value = str(self.resolution.sample_aperture_size[0])
+ if len(self.resolution.sample_aperture_size) > 1:
+ sample_aperture_value += ", "
+ sample_aperture_value += str(self.resolution.sample_aperture_size[1])
+ sample_aperture_unit_txt = wx.StaticText(self, -1, '[cm]')
+ sample_aperture_txt = wx.StaticText(self, -1, 'Sample Aperture Size: ')
+ self.sample_aperture_tcl = InputTextCtrl(self, -1, size=(_BOX_WIDTH, -1))
+ sample_aperture_hint = "Sample Aperture Size"
+ self.sample_aperture_tcl.SetValue(sample_aperture_value)
+ self.sample_aperture_tcl.SetToolTipString(sample_aperture_hint)
+ self.sample_aperture_sizer.AddMany([(sample_aperture_txt, 0, wx.LEFT, 15),
+ (self.sample_aperture_tcl, 0, wx.LEFT, 15),
+ (sample_aperture_unit_txt, 0, wx.LEFT, 10)])
+
+ def _layout_source2sample_distance(self):
+ """
+ Fill the sizer containing souce2sample_distance
+ """
+ # get the wavelength
+ source2sample_distance_value = str(self.resolution.source2sample_distance[0])
+
+ source2sample_distance_unit_txt = wx.StaticText(self, -1, '[cm]')
+ source2sample_distance_txt = wx.StaticText(self, -1,
+ 'Source to Sample Aperture Distance: ')
+ self.source2sample_distance_tcl = InputTextCtrl(self, -1, size=(_BOX_WIDTH, -1))
+ source2sample_distance_hint = "Source to Sample Aperture Distance"
+ self.source2sample_distance_tcl.SetValue(source2sample_distance_value)
+ self.source2sample_distance_tcl.SetToolTipString(source2sample_distance_hint)
+ self.source2sample_distance_sizer.AddMany([(source2sample_distance_txt, 0, wx.LEFT, 15),
+ (self.source2sample_distance_tcl, 0, wx.LEFT, 15),
+ (source2sample_distance_unit_txt, 0, wx.LEFT, 10)])
+
+ def _layout_sample2sample_distance(self):
+ """
+ Fill the sizer containing sampleslit2sample_distance
+ """
+ # get the distance
+ sample2sample_distance_value = str(self.resolution.sample2sample_distance[0])
+
+ sample2sample_distance_unit_txt = wx.StaticText(self, -1, '[cm]')
+ sample2sample_distance_txt = wx.StaticText(self, -1, 'Sample Offset: ')
+ self.sample2sample_distance_tcl = InputTextCtrl(self, -1, size=(_BOX_WIDTH, -1))
+ sample2sample_distance_hint = "Sample Aperture to Sample Distance"
+ self.sample2sample_distance_tcl.SetValue(sample2sample_distance_value)
+ self.sample2sample_distance_tcl.SetToolTipString(sample2sample_distance_hint)
+ self.sample2sample_distance_sizer.AddMany([(sample2sample_distance_txt, 0, wx.LEFT, 15),
+ (self.sample2sample_distance_tcl, 0, wx.LEFT, 15),
+ (sample2sample_distance_unit_txt, 0, wx.LEFT, 10)])
+
+ def _layout_sample2detector_distance(self):
+ """
+ Fill the sizer containing sample2detector_distance
+ """
+ # get the wavelength
+ sample2detector_distance_value = str(self.resolution.sample2detector_distance[0])
+
+ sample2detector_distance_unit_txt = wx.StaticText(self, -1, '[cm]')
+ sample2detector_distance_txt = wx.StaticText(self, -1,
+ 'Sample Aperture to Detector Distance: ')
+ self.sample2detector_distance_tcl = InputTextCtrl(self, -1, size=(_BOX_WIDTH, -1))
+ sample2detector_distance_hint = "Sample Aperture to Detector Distance"
+ self.sample2detector_distance_tcl.SetValue(sample2detector_distance_value)
+ self.sample2detector_distance_tcl.SetToolTipString(sample2detector_distance_hint)
+ self.sample2detector_distance_sizer.AddMany([\
+ (sample2detector_distance_txt, 0, wx.LEFT, 15),
+ (self.sample2detector_distance_tcl, 0, wx.LEFT, 15),
+ (sample2detector_distance_unit_txt, 0, wx.LEFT, 10)])
+
+ def _layout_detector_size(self):
+ """
+ Fill the sizer containing detector size
+ """
+ # get the wavelength
+ detector_size_value = str(self.resolution.detector_size[0])
+ if len(self.resolution.detector_size) > 1:
+ detector_size_value += ", "
+ detector_size_value += str(self.resolution.detector_size[1])
+ detector_size_unit_txt = wx.StaticText(self, -1, '')
+ detector_size_txt = wx.StaticText(self, -1, 'Number of Pixels on Detector: ')
+ self.detector_size_tcl = InputTextCtrl(self, -1, size=(_BOX_WIDTH, -1))
+ detector_size_hint = "Number of Pixels on Detector"
+ self.detector_size_tcl.SetValue(detector_size_value)
+ self.detector_size_tcl.SetToolTipString(detector_size_hint)
+ self.detector_size_sizer.AddMany([(detector_size_txt, 0, wx.LEFT, 15),
+ (self.detector_size_tcl, 0, wx.LEFT, 15),
+ (detector_size_unit_txt, 0, wx.LEFT, 10)])
+
+ def _layout_detector_pix_size(self):
+ """
+ Fill the sizer containing detector pixel size
+ """
+ # get the detector_pix_size
+ detector_pix_size_value = str(self.resolution.detector_pix_size[0])
+ if len(self.resolution.detector_pix_size) > 1:
+ detector_pix_size_value += ", "
+ detector_pix_size_value += str(self.resolution.detector_pix_size[1])
+ detector_pix_size_unit_txt = wx.StaticText(self, -1, '[cm]')
+ detector_pix_size_txt = wx.StaticText(self, -1, 'Detector Pixel Size: ')
+ self.detector_pix_size_tcl = InputTextCtrl(self, -1, size=(_BOX_WIDTH, -1))
+ detector_pix_size_hint = "Detector Pixel Size"
+ self.detector_pix_size_tcl.SetValue(detector_pix_size_value)
+ self.detector_pix_size_tcl.SetToolTipString(detector_pix_size_hint)
+ self.detector_pix_size_sizer.AddMany([(detector_pix_size_txt, 0, wx.LEFT, 15),
+ (self.detector_pix_size_tcl, 0, wx.LEFT, 15),
+ (detector_pix_size_unit_txt, 0, wx.LEFT, 10)])
+
+ def _layout_input(self):
+ """
+ Fill the sizer containing inputs; qx, qy
+ """
+
+ q_title = wx.StaticText(self, -1, "[Q Location of the Estimation]:")
+ # sizers for inputs
+ inputQx_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ inputQy_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ # get the default dq
+ qx_value = str(_Q_DEFAULT)
+ qy_value = str(_Q_DEFAULT)
+ qx_unit_txt = wx.StaticText(self, -1, '[1/A] ')
+ qy_unit_txt = wx.StaticText(self, -1, '[1/A] ')
+ qx_name_txt = wx.StaticText(self, -1, 'Qx: ')
+ qy_name_txt = wx.StaticText(self, -1, 'Qy: ')
+ self.qx_tcl = InputTextCtrl(self, -1, size=(_BOX_WIDTH * 3, -1))
+ self.qy_tcl = InputTextCtrl(self, -1, size=(_BOX_WIDTH * 3, -1))
+ qx_hint = "Type the Qx value."
+ qy_hint = "Type the Qy value."
+ self.qx_tcl.SetValue(qx_value)
+ self.qy_tcl.SetValue(qy_value)
+ self.qx_tcl.SetToolTipString(qx_hint)
+ self.qy_tcl.SetToolTipString(qy_hint)
+ inputQx_sizer.AddMany([(qx_name_txt, 0, wx.LEFT, 15),
+ (self.qx_tcl, 0, wx.LEFT, 15),
+ (qx_unit_txt, 0, wx.LEFT, 15)])
+ inputQy_sizer.AddMany([(qy_name_txt, 0, wx.LEFT, 15),
+ (self.qy_tcl, 0, wx.LEFT, 15),
+ (qy_unit_txt, 0, wx.LEFT, 15)])
+ self.input_sizer.AddMany([(q_title, 0, wx.LEFT, 15),
+ (inputQx_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
+ (inputQy_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
+
+ def _layout_output(self):
+ """
+ Fill the sizer containing dQ|| and dQ+
+ """
+ sigma_title = wx.StaticText(self, -1,
+ "[Standard Deviation of the Resolution Distribution]:")
+ # sizers for inputs
+ outputQxy_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ outputQ_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ sigma_unit = '[' + '1/A' + ']'
+ self.sigma_r_txt = wx.StaticText(self, -1, 'Sigma_x: ')
+ self.sigma_r_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH * 0.8, -1))
+ self.sigma_phi_txt = wx.StaticText(self, -1, 'Sigma_y:')
+ self.sigma_phi_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH * 0.8, -1))
+ self.sigma_lamd_txt = wx.StaticText(self, -1, 'Sigma_lamd:')
+ self.sigma_lamd_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH * 0.7, -1))
+ sigma_1d_txt = wx.StaticText(self, -1, '( 1D: Sigma:')
+ self.sigma_1d_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH * 0.7, -1))
+ sigmax_hint = " The x component of the geometric resolution,"
+ sigmax_hint += " excluding sigma_lamda."
+ sigmay_hint = " The y component of the geometric resolution,"
+ sigmay_hint += " excluding sigma_lamda."
+ sigma_hint_lamd = " The wavelength contribution in the radial direction"
+ sigma_hint_lamd += ".\n Note: The phi component is always zero."
+ sigma_hint_1d = " Resolution in 1-dimension (for 1D data)."
+ self.sigma_r_tcl.SetToolTipString(sigmax_hint)
+ self.sigma_phi_tcl.SetToolTipString(sigmay_hint)
+ self.sigma_lamd_tcl.SetToolTipString(sigma_hint_lamd)
+ self.sigma_1d_tcl.SetToolTipString(sigma_hint_1d)
+ sigma_r_unit_txt = wx.StaticText(self, -1, sigma_unit)
+ sigma_phi_unit_txt = wx.StaticText(self, -1, sigma_unit)
+ sigma_lamd_unit_txt = wx.StaticText(self, -1, sigma_unit)
+ sigma_1d_unit_txt = wx.StaticText(self, -1, sigma_unit + ' )')
+ outputQxy_sizer.AddMany([(self.sigma_r_txt, 0, wx.LEFT, 15),
+ (self.sigma_r_tcl, 0, wx.LEFT, 15),
+ (sigma_r_unit_txt, 0, wx.LEFT, 15),
+ (self.sigma_phi_txt, 0, wx.LEFT, 15),
+ (self.sigma_phi_tcl, 0, wx.LEFT, 15),
+ (sigma_phi_unit_txt, 0, wx.LEFT, 15)])
+ outputQ_sizer.AddMany([(self.sigma_lamd_txt, 0, wx.LEFT, 15),
+ (self.sigma_lamd_tcl, 0, wx.LEFT, 15),
+ (sigma_lamd_unit_txt, 0, wx.LEFT, 15),
+ (sigma_1d_txt, 0, wx.LEFT, 15),
+ (self.sigma_1d_tcl, 0, wx.LEFT, 15),
+ (sigma_1d_unit_txt, 0, wx.LEFT, 15)])
+ self.output_sizer.AddMany([(sigma_title, 0, wx.LEFT, 15),
+ (outputQxy_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
+ (outputQ_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
+
+ def _layout_hint(self):
+ """
+ Fill the sizer containing hint
+ """
+ hint_msg = ""
+ #hint_msg += "This tool is to approximately compute "
+ #hint_msg += "the instrumental resolution (dQ)."
+
+ self.hint_txt = wx.StaticText(self, -1, hint_msg)
+ self.hint_sizer.AddMany([(self.hint_txt, 0, wx.LEFT, 15)])
+
+ def _layout_button(self):
+ """
+ Do the layout for the button widgets
+ """
+
+ wx_id = wx.NewId()
+ self.reset_button = wx.Button(self, wx_id, "Reset")
+ hint_on_reset = "..."
+ self.reset_button.SetToolTipString(hint_on_reset)
+ self.Bind(wx.EVT_BUTTON, self.on_reset, id=wx_id)
+ #compute button
+ wx_id = wx.NewId()
+ self.compute_button = wx.Button(self, wx_id, "Compute")
+ hint_on_compute = "Compute... Please wait until finished."
+ self.compute_button.SetToolTipString(hint_on_compute)
+ self.Bind(wx.EVT_BUTTON, self.on_compute, id=wx_id)
+ #help button
+ wx_id = wx.NewId()
+ self.help_button = wx.Button(self, wx_id, "HELP")
+ hint_on_help = "Help on using the Resolution Calculator"
+ self.help_button.SetToolTipString(hint_on_help)
+ self.Bind(wx.EVT_BUTTON, self.on_help, id=wx_id)
+ # close button
+ self.bt_close = wx.Button(self, wx.ID_CANCEL, 'Close')
+ self.bt_close.Bind(wx.EVT_BUTTON, self.on_close)
+ self.bt_close.SetToolTipString("Close this window.")
+
+ self.button_sizer.Add((110, -1))
+ self.button_sizer.AddMany([(self.reset_button, 0, wx.LEFT, 50),
+ (self.compute_button, 0, wx.LEFT, 15),
+ (self.help_button, 0, wx.LEFT, 15),
+ (self.bt_close, 0, wx.LEFT, 15)])
+ self.compute_button.SetFocus()
+
+ def _layout_image(self):
+ """
+ Layout for image plot
+ """
+ # Contribution by James C.
+ # Instantiate a figure object that will contain our plots.
+ # Make the fig a little smaller than the default
+ self.figure = Figure(figsize=(6.5, 6), facecolor='white')
+
+ # Initialize the figure canvas, mapping the figure object to the plot
+ # engine backend.
+ self.canvas = FigureCanvas(self, wx.ID_ANY, self.figure)
+
+ # Wx-Pylab magic ...
+ # Make our canvas the active figure manager for pylab so that when
+ # pylab plotting statements are executed they will operate on our
+ # canvas and not create a new frame and canvas for display purposes.
+ # This technique allows this application to execute code that uses
+ # pylab stataments to generate plots and embed these plots in our
+ # application window(s).
+ self.fm = FigureManagerBase(self.canvas, 1)
+ _pylab_helpers.Gcf.set_active(self.fm)
+
+ # Instantiate the matplotlib navigation toolbar and explicitly show it.
+ mpl_toolbar = Toolbar(self.canvas)
+ # Diable pan
+ mpl_toolbar.DeleteToolByPos(3)
+
+ # Add a toolbar into the frame
+ mpl_toolbar.Realize()
+
+ # Compute before adding the canvas to the sizer
+ self.on_compute()
+
+ # Fill up the sizer
+ if IS_WIN:
+ gap = 27
+ else:
+ gap = 13
+ self.vertical_r_sizer.Add(self.canvas, 0, wx.ALL | wx.EXPAND, 2)
+ self.vertical_r_spacer.Add((0, gap))
+ self.vertical_r_spacer.Add(self.vertical_r_sizer, 0, wx.ALL | wx.EXPAND, 2)
+ self.vertical_r_spacer.Add((0, gap))
+ self.vertical_r_spacer.Add(wx.StaticLine(self), 0, wx.ALL | wx.EXPAND, 2)
+ self.vertical_r_spacer.Add(mpl_toolbar, 0, wx.ALL | wx.EXPAND, 2)
+
+ def _do_layout(self):
+ """
+ Draw window layout
+ """
+ # Title of parameters
+ instrument_txt = wx.StaticText(self, -1, '[Instrumental Parameters]:')
+ # Build individual layouts
+ self._define_structure()
+ self._layout_mass()
+ self._layout_wavelength()
+ self._layout_wavelength_spread()
+ self._layout_source_aperture()
+ self._layout_sample_aperture()
+ self._layout_source2sample_distance()
+ self._layout_sample2detector_distance()
+ self._layout_sample2sample_distance()
+ self._layout_detector_size()
+ self._layout_detector_pix_size()
+ self._layout_input()
+ self._layout_output()
+ self._layout_hint()
+ self._layout_button()
+ # Fill the sizers
+ self.boxsizer_source.AddMany([(instrument_txt, 0,
+ wx.EXPAND | wx.LEFT, 15),
+ (self.mass_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
+ (self.wavelength_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
+ (self.wavelength_spread_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
+ (self.source_aperture_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
+ (self.sample_aperture_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
+ (self.source2sample_distance_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
+ (self.sample2detector_distance_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
+ (self.sample2sample_distance_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
+ (self.detector_size_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
+ (self.detector_pix_size_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
+ (wx.StaticLine(self), 0,
+ wx.ALL | wx.EXPAND, 5),
+ (self.input_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
+ (wx.StaticLine(self), 0,
+ wx.ALL | wx.EXPAND, 5),
+ (self.output_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
+ self.vertical_l_sizer.AddMany([(self.boxsizer_source, 0, wx.ALL, 10),
+ (wx.StaticLine(self), 0,
+ wx.ALL | wx.EXPAND, 5),
+ (self.button_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
+ self.main_sizer.Add(self.vertical_l_sizer, 0, wx.ALL, 10)
+
+ # Build image plot layout
+ self._layout_image()
+ # Add a vertical static line
+ self.main_sizer.Add(wx.StaticLine(self, -1, (2, 2),
+ (2, PANEL_HEIGHT * 0.94), style=wx.LI_VERTICAL))
+ # Add the plot to main sizer
+ self.main_sizer.Add(self.vertical_r_spacer, 0, wx.ALL, 10)
+ self.SetSizer(self.main_sizer)
+ self.SetAutoLayout(True)
+
+ def on_help(self, event):
+ """
+ Bring up the Resolution calculator Documentation whenever
+ the HELP button is clicked.
+
+ Calls DocumentationWindow with the path of the location within the
+ documentation tree (after /doc/ ....". Note that when using old
+ versions of Wx (before 2.9) and thus not the release version of
+ installers, the help comes up at the top level of the file as
+ webbrowser does not pass anything past the # to the browser when it is
+ running "file:///...."
+
+ :param evt: Triggers on clicking the help button
+ """
+
+ _TreeLocation = "user/sasgui/perspectives/calculator/"
+ _TreeLocation += "resolution_calculator_help.html"
+ _doc_viewer = DocumentationWindow(self, -1, _TreeLocation, "",
+ "Resolution Calculator Help")
+
+ def on_close(self, event):
+ """
+ close the window containing this panel
+ """
+ # get ready for other events
+ if event is not None:
+ event.Skip()
+ # Clear the plot
+ if self.image is not None:
+ self.image.clf()
+ # reset image
+ self.image = None
+ # Close panel
+ self.parent.OnClose(None)
+
+ def on_compute(self, event=None):
+ """
+ Execute the computation of resolution
+ """
+ wx.CallAfter(self.on_compute_call, event)
+
+ def on_compute_call(self, event=None):
+ """
+ Execute the computation of resolution
+ """
+ # Skip event for next event
+ if event is not None:
+ event.Skip()
+ msg = "Please Check your input values "
+ msg += "before starting the computation..."
+
+ # message
+ status_type = 'progress'
+ msg = 'Calculating...'
+ self._status_info(msg, status_type)
+
+ status_type = 'stop'
+ # Q min max list default
+ qx_min = []
+ qx_max = []
+ qy_min = []
+ qy_max = []
+ # possible max qrange
+ self.resolution.qxmin_limit = 0
+ self.resolution.qxmax_limit = 0
+ self.resolution.qymin_limit = 0
+ self.resolution.qymax_limit = 0
+ # q min and max of the detector
+ try:
+ # Get all the values at set to compute
+ # default num bin of wave list
+ self.num_wave = 10
+ wavelength = self._str2longlist(self.wavelength_tcl.GetValue())
+ source = self.source_cb.GetValue()
+ mass = self.source_mass[str(source)]
+ self.resolution.set_neutron_mass(float(mass))
+ wavelength_spread = self._str2longlist(\
+ self.wavelength_spread_tcl.GetValue().split(';')[0])
+ # Validate the wave inputs
+ wave_input = self._validate_q_input(wavelength, wavelength_spread)
+ if wave_input is not None:
+ wavelength, wavelength_spread = wave_input
+
+ self.resolution.set_wave(wavelength)
+ self.resolution.set_wave_spread(wavelength_spread)
+ source_aperture_size = self.source_aperture_tcl.GetValue()
+ source_aperture_size = self._string2list(source_aperture_size)
+ self.resolution.set_source_aperture_size(source_aperture_size)
+ sample_aperture_size = self.sample_aperture_tcl.GetValue()
+ sample_aperture_size = self._string2list(sample_aperture_size)
+ self.resolution.set_sample_aperture_size(sample_aperture_size)
+ source2sample_distance = self.source2sample_distance_tcl.GetValue()
+ source2sample_distance = self._string2list(source2sample_distance)
+ self.resolution.set_source2sample_distance(source2sample_distance)
+ sample2sample_distance = self.sample2sample_distance_tcl.GetValue()
+ sample2sample_distance = self._string2list(sample2sample_distance)
+ self.resolution.set_sample2sample_distance(sample2sample_distance)
+ sample2detector_distance = \
+ self.sample2detector_distance_tcl.GetValue()
+ sample2detector_distance = \
+ self._string2list(sample2detector_distance)
+ self.resolution.set_sample2detector_distance(\
+ sample2detector_distance)
+ detector_size = self.detector_size_tcl.GetValue()
+ detector_size = self._string2list(detector_size)
+ self.resolution.set_detector_size(detector_size)
+ detector_pix_size = self.detector_pix_size_tcl.GetValue()
+ detector_pix_size = self._string2list(detector_pix_size)
+ self.resolution.set_detector_pix_size(detector_pix_size)
+ self.qx = self._string2inputlist(self.qx_tcl.GetValue())
+ self.qy = self._string2inputlist(self.qy_tcl.GetValue())
+
+ # Find min max of qs
+ xmin = min(self.qx)
+ xmax = max(self.qx)
+ ymin = min(self.qy)
+ ymax = max(self.qy)
+ if not self._validate_q_input(self.qx, self.qy):
+ raise
+ except:
+ msg = "An error occured during the resolution computation."
+ msg += "Please check your inputs..."
+ self._status_info(msg, status_type)
+ wx.MessageBox(msg, 'Warning')
+ return
+ #raise ValueError, "Invalid Q Input..."
+
+ # Validate the q inputs
+ q_input = self._validate_q_input(self.qx, self.qy)
+ if q_input is not None:
+ self.qx, self.qy = q_input
+
+ # Make list of q min max for mapping
+ for i in range(len(self.qx)):
+ qx_min.append(xmin)
+ qx_max.append(xmax)
+ for i in range(len(self.qy)):
+ qy_min.append(ymin)
+ qy_max.append(ymax)
+
+ # Compute the resolution
+ if self.image is not None:
+ #_pylab_helpers.Gcf.set_active(self.fm)
+ _pylab_helpers.Gcf.figs = {}
+ # Clear the image before redraw
+ self.image.clf()
+ # reset the image
+ self.resolution.reset_image()
+
+ # Compute and get the image plot
+ try:
+ from sas.sasgui.perspectives.calculator.resolcal_thread import CalcRes as thread
+ self.sigma_strings = '\nResolution: Computation is finished. \n'
+ cal_res = thread(func=self._map_func,
+ qx=self.qx,
+ qy=self.qy,
+ qx_min=qx_min,
+ qx_max=qx_max,
+ qy_min=qy_min,
+ qy_max=qy_max,
+ image=self.image,
+ completefn=self.complete)
+ cal_res.queue()
+ msg = "Computation is in progress..."
+ status_type = 'progress'
+ self._status_info(msg, status_type)
+ except:
+ raise
+
+ def complete(self, image, elapsed=None):
+ """
+ Callafter complete: wx call after needed for stable output
+ """
+ wx.CallAfter(self.complete_cal, image, elapsed)
+
+ def complete_cal(self, image, elapsed=None):
+ """
+ Complete computation
+ """
+ self.image = image
+ # Draw lines in image before drawing
+ wave_list, _ = self.resolution.get_wave_list()
+ if len(wave_list) > 1 and wave_list[-1] == max(wave_list):
+ # draw a green rectangle(limit for the longest wavelength
+ # to be involved) for tof inputs
+ self._draw_lines(self.image, color='g')
+ self._draw_lines(self.image, color='r')
+ # Draw image
+ self.image.draw()
+
+ # Get and format the sigmas
+ sigma_r = self.format_number(self.resolution.sigma_1)
+ sigma_phi = self.format_number(self.resolution.sigma_2)
+ sigma_lamd = self.format_number(self.resolution.sigma_lamd)
+ sigma_1d = self.format_number(self.resolution.sigma_1d)
+
+ # Set output values
+ self.sigma_r_tcl.SetValue(str(sigma_r))
+ self.sigma_phi_tcl.SetValue(str(sigma_phi))
+ self.sigma_lamd_tcl.SetValue(str(sigma_lamd))
+ self.sigma_1d_tcl.SetValue(str(sigma_1d))
+ msg = self.sigma_strings
+ msg += "\n"
+ status_type = 'stop'
+ self._status_info(msg, status_type)
+
+ def _draw_lines(self, image=None, color='r'):
+ """
+ Draw lines in image if applicable
+ : Param image: pylab object
+ """
+ if image is None:
+ return
+ if color == 'g':
+ # Get the params from resolution
+ # ploting range for largest wavelength
+ qx_min = self.resolution.qx_min
+ qx_max = self.resolution.qx_max
+ qy_min = self.resolution.qy_min
+ qy_max = self.resolution.qy_max
+ # detector range
+ detector_qx_min = self.resolution.detector_qx_min
+ detector_qx_max = self.resolution.detector_qx_max
+ detector_qy_min = self.resolution.detector_qy_min
+ detector_qy_max = self.resolution.detector_qy_max
+ else:
+ qx_min, qx_max, qy_min, qy_max = \
+ self.resolution.get_detector_qrange()
+ # detector range
+ detector_qx_min = self.resolution.qxmin_limit
+ detector_qx_max = self.resolution.qxmax_limit
+ detector_qy_min = self.resolution.qymin_limit
+ detector_qy_max = self.resolution.qymax_limit
+
+ # Draw zero axis lines
+ if qy_min < 0 and qy_max >= 0:
+ image.axhline(linewidth=1)
+ if qx_min < 0 and qx_max >= 0:
+ image.axvline(linewidth=1)
+
+ # Find x and y ratio values to draw the detector outline
+ x_min = fabs(detector_qx_min - qx_min) / (qx_max - qx_min)
+ x_max = fabs(detector_qx_max - qx_min) / (qx_max - qx_min)
+ y_min = fabs(detector_qy_min - qy_min) / (qy_max - qy_min)
+ y_max = fabs(detector_qy_max - qy_min) / (qy_max - qy_min)
+
+ # Draw Detector outline
+ if detector_qy_min >= qy_min:
+ image.axhline(y=detector_qy_min + 0.0002,
+ xmin=x_min, xmax=x_max,
+ linewidth=2, color=color)
+ if detector_qy_max <= qy_max:
+ image.axhline(y=detector_qy_max - 0.0002,
+ xmin=x_min, xmax=x_max,
+ linewidth=2, color=color)
+ if detector_qx_min >= qx_min:
+ image.axvline(x=detector_qx_min + 0.0002,
+ ymin=y_min, ymax=y_max,
+ linewidth=2, color=color)
+ if detector_qx_max <= qx_max:
+ image.axvline(x=detector_qx_max - 0.0002,
+ ymin=y_min, ymax=y_max,
+ linewidth=2, color=color)
+ xmin = min(self.qx)
+ xmax = max(self.qx)
+ ymin = min(self.qy)
+ ymax = max(self.qy)
+ if color != 'g':
+ if xmin < detector_qx_min or xmax > detector_qx_max or \
+ ymin < detector_qy_min or ymax > detector_qy_max:
+ # message
+ status_type = 'stop'
+ msg = 'At least one q value located out side of\n'
+ msg += " the detector range (%s < qx < %s, %s < qy < %s),\n" % \
+ (self.format_number(detector_qx_min),
+ self.format_number(detector_qx_max),
+ self.format_number(detector_qy_min),
+ self.format_number(detector_qy_max))
+ msg += " is ignored in computation.\n"
+
+ self._status_info(msg, status_type)
+ wx.MessageBox(msg, 'Warning')
+
+ def _map_func(self, qx, qy, qx_min, qx_max, qy_min, qy_max):
+ """
+ Prepare the Mapping for the computation
+ : params qx, qy, qx_min, qx_max, qy_min, qy_max:
+
+ : return: image (pylab)
+ """
+ try:
+ qx_value = float(qx)
+ qy_value = float(qy)
+ except:
+ raise
+ # calculate 2D resolution distribution image
+ image = self.resolution.compute_and_plot(qx_value, qy_value,
+ qx_min, qx_max, qy_min, qy_max,
+ self.det_coordinate)
+ # record sigmas
+ self.sigma_strings += " At Qx = %s, Qy = %s; \n" % (qx_value, qy_value)
+ self._sigma_strings()
+ return image
+
+ def _sigma_strings(self):
+ """
+ Recode sigmas as strins
+ """
+ sigma_r = self.format_number(self.resolution.sigma_1)
+ sigma_phi = self.format_number(self.resolution.sigma_2)
+ sigma_lamd = self.format_number(self.resolution.sigma_lamd)
+ sigma_1d = self.format_number(self.resolution.sigma_1d)
+ # Set output values
+ self.sigma_strings += " sigma_x = %s\n" % sigma_r
+ self.sigma_strings += " sigma_y = %s\n" % sigma_phi
+ self.sigma_strings += " sigma_lamd = %s\n" % sigma_lamd
+ self.sigma_strings += " sigma_1D = %s\n" % sigma_1d
+
+ def _validate_q_input(self, qx, qy):
+ """
+ Check if q inputs are valid
+ : params qx: qx as a list
+ : params qy: qy as a list
+
+ : return: True/False
+ """
+ # check qualifications
+ if qx.__class__.__name__ != 'list':
+ return None
+ if qy.__class__.__name__ != 'list':
+ return None
+ if len(qx) < 1:
+ return None
+ if len(qy) < 1:
+ return None
+ # allow one input
+ if len(qx) == 1 and len(qy) > 1:
+ qx = [qx[0] for ind in range(len(qy))]
+ #self.qx = qx
+ if len(qy) == 1 and len(qx) > 1:
+ qy = [qy[0] for ind in range(len(qx))]
+ #self.qy = qy
+ # check length
+ if len(qx) != len(qy):
+ return None
+ if qx is None or qy is None:
+ return None
+ return qx, qy
+
+ def on_reset(self, event):
+ """
+ Execute the reset
+ """
+ # skip for another event
+ if event is not None:
+ event.Skip()
+ # init resolution_calculator
+ self.resolution = ResolutionCalculator()
+ self.resolution.get_all_instrument_params()
+ # reset all param values
+ self.source_cb.SetValue('Neutron')
+ self._on_source_selection(None)
+ self.wave_color_cb.SetValue('Monochromatic')
+ self._on_source_color(None)
+ #self.intensity_tcl.SetValue(str(self.resolution.intensity))
+ self.wavelength_tcl.SetValue(str(6.0))
+ self.wavelength_spread_tcl.SetValue(str(0.125))
+ self.resolution.set_spectrum(self.spectrum_dic['Flat'])
+ self.spectrum_txt.Show(False)
+ self.spectrum_cb.Show(False)
+ source_aperture_value = str(self.resolution.source_aperture_size[0])
+ if len(self.resolution.source_aperture_size) > 1:
+ source_aperture_value += ", "
+ source_aperture_value += \
+ str(self.resolution.source_aperture_size[1])
+ self.source_aperture_tcl.SetValue(str(source_aperture_value))
+ sample_aperture_value = str(self.resolution.sample_aperture_size[0])
+ if len(self.resolution.sample_aperture_size) > 1:
+ sample_aperture_value += ", "
+ sample_aperture_value += \
+ str(self.resolution.sample_aperture_size[1])
+ self.sample_aperture_tcl.SetValue(sample_aperture_value)
+ source2sample_distance_value = \
+ str(self.resolution.source2sample_distance[0])
+ self.source2sample_distance_tcl.SetValue(source2sample_distance_value)
+ sample2sample_distance_value = \
+ str(self.resolution.sample2sample_distance[0])
+ self.sample2sample_distance_tcl.SetValue(sample2sample_distance_value)
+ sample2detector_distance_value = \
+ str(self.resolution.sample2detector_distance[0])
+ self.sample2detector_distance_tcl.SetValue(\
+ sample2detector_distance_value)
+ detector_size_value = str(self.resolution.detector_size[0])
+ if len(self.resolution.detector_size) > 1:
+ detector_size_value += ", "
+ detector_size_value += str(self.resolution.detector_size[1])
+ self.detector_size_tcl.SetValue(detector_size_value)
+ detector_pix_size_value = str(self.resolution.detector_pix_size[0])
+ if len(self.resolution.detector_pix_size) > 1:
+ detector_pix_size_value += ", "
+ detector_pix_size_value += str(self.resolution.detector_pix_size[1])
+ self.detector_pix_size_tcl.SetValue(detector_pix_size_value)
+ #layout attribute
+ self.hint_sizer = None
+ # reset q inputs
+ self.qx_tcl.SetValue(str(_Q_DEFAULT))
+ self.qy_tcl.SetValue(str(_Q_DEFAULT))
+ # reset sigma outputs
+ self.sigma_r_tcl.SetValue('')
+ self.sigma_phi_tcl.SetValue('')
+ self.sigma_1d_tcl.SetValue('')
+ # reset radio button
+ #self.r_phi_rb.SetValue(True)
+ # Finally re-compute
+ self.on_compute()
+ # msg on info
+ msg = " Finished the resetting..."
+ self._status_info(msg, 'stop')
+
+ def format_number(self, value=None):
+ """
+ Return a float in a standardized, human-readable formatted string
+ """
+ try:
+ value = float(value)
+ except:
+ output = None
+ return output
+
+ output = "%-7.4g" % value
+ return output.lstrip().rstrip()
+
+ def _string2list(self, string):
+ """
+ Change NNN, NNN to list,ie. [NNN, NNN] where NNN is a number
+ """
+ new_string = []
+ # check the number of floats
+ try:
+ strg = float(string)
+ new_string.append(strg)
+ except:
+ string_split = string.split(',')
+ if len(string_split) == 2:
+ str_1 = string_split[0]
+ str_2 = string_split[1]
+ new_string.append(float(str_1))
+ new_string.append(float(str_2))
+ elif len(string_split) == 1:
+ str_1 = string_split[0]
+ new_string.append(float(str_1))
+ else:
+ msg = "The numbers must be one or two (separated by ',')..."
+ self._status_info(msg, 'stop')
+ raise RuntimeError, msg
+
+ return new_string
+
+ def _string2inputlist(self, string):
+ """
+ Change NNN, NNN,... to list,ie. [NNN, NNN,...] where NNN is a number
+
+ : return new_string: string like list
+ """
+ new_string = []
+ string_split = string.split(',')
+ length = len(string_split)
+ for ind in range(length):
+ try:
+ value = float(string_split[ind])
+ new_string.append(value)
+ except:
+ logger.error(sys.exc_value)
+
+ return new_string
+
+ def _str2longlist(self, string):
+ """
+ Change NNN, NNN,... to list, NNN - NNN ; NNN to list, or float to list
+
+ : return new_string: string like list
+ """
+ msg = "Wrong format of intputs."
+ try:
+ # is float
+ out = [float(string)]
+ return out
+ except:
+ if self.wave_color.lower().count('mono') > 0:
+ wx.MessageBox(msg, 'Warning')
+ else:
+ try:
+ # has a '-'
+ if string.count('-') > 0:
+ value = string.split('-')
+ if value[1].count(';') > 0:
+ # has a ';'
+ last_list = value[1].split(';')
+ num = math.ceil(float(last_list[1]))
+ max_value = float(last_list[0])
+ self.num_wave = num
+ else:
+ # default num
+ num = self.num_wave
+ max_value = float(value[1])
+ min_value = float(value[0])
+ # make a list
+ bin_size = math.fabs(max_value - min_value) / (num - 1)
+ out = [min_value + bin_size * bnum for bnum in range(num)]
+ return out
+ if string.count(',') > 0:
+ out = self._string2inputlist(string)
+ return out
+ except:
+ logger.error(sys.exc_value)
+
+ def _on_xy_coordinate(self, event=None):
+ """
+ Set the detector coordinate for sigmas to x-y coordinate
+ """
+ if event is not None:
+ event.Skip()
+ # Set the coordinate in Cartesian
+ self.det_coordinate = 'cartesian'
+ self.sigma_r_txt.SetLabel('Sigma_x:')
+ self.sigma_phi_txt.SetLabel('Sigma_y:')
+ self._onparamEnter()
+
+ def _on_rp_coordinate(self, event=None):
+ """
+ Set the detector coordinate for sigmas to polar coordinate
+ """
+ if event is not None:
+ event.Skip()
+ # Set the coordinate in polar
+ self.det_coordinate = 'polar'
+ self.sigma_r_txt.SetLabel('Sigma_r: ')
+ self.sigma_phi_txt.SetLabel('Sigma_phi:')
+ self._onparamEnter()
+
+ def _status_info(self, msg='', type="update"):
+ """
+ Status msg
+ """
+ if type == "stop":
+ label = "Compute"
+ able = True
+ else:
+ label = "Wait..."
+ able = False
+ self.compute_button.Enable(able)
+ self.compute_button.SetLabel(label)
+ self.compute_button.SetToolTipString(label)
+ if self.parent.parent is not None:
+ wx.PostEvent(self.parent.parent,
+ StatusEvent(status=msg, type=type))
+
+
+ def _onparamEnter(self, event=None):
+ """
+ On Text_enter_callback, perform compute
+ """
+ self.on_compute()
+
+ def _on_source_selection(self, event=None):
+ """
+ On source combobox selection
+ """
+ if event is not None:
+ combo = event.GetEventObject()
+ event.Skip()
+ else:
+ combo = self.source_cb
+ selection = combo.GetValue()
+ mass = self.source_mass[selection]
+ self.resolution.set_neutron_mass(mass)
+ source_hint = "Source Selection: Affect on"
+ source_hint += " the gravitational contribution.\n"
+ source_hint += "Mass of %s: m = %s [g]" % \
+ (selection, str(self.resolution.get_neutron_mass()))
+ #source_tip.SetTip(source_hint)
+ self.mass_txt.ToolTip.SetTip(source_hint)
+
+ def _on_source_color(self, event=None):
+ """
+ On source color combobox selection
+ """
+ if event is not None:
+ #combo = event.GetEventObject()
+ event.Skip()
+ #else:
+ combo = self.wave_color_cb
+ selection = combo.GetValue()
+ self.wave_color = selection
+ if self.wave_color.lower() == 'tof':
+ list = self.resolution.get_wave_list()
+ minw = min(list[0])
+ if len(list[0]) < 2:
+ maxw = 2 * minw
+ else:
+ maxw = max(list[0])
+ self.wavelength_tcl.SetValue('%s - %s' % (minw, maxw))
+ minw = min(list[1])
+ maxw = max(list[1])
+ self.wavelength_spread_tcl.SetValue('%s - %s' % (minw, maxw))
+ spectrum_val = self.spectrum_cb.GetValue()
+ self.resolution.set_spectrum(self.spectrum_dic[spectrum_val])
+ self.spectrum_txt.Show(True)
+ self.spectrum_cb.Show(True)
+
+ else:
+ wavelength = self.resolution.get_wavelength()
+ wavelength_spread = self.resolution.get_wavelength_spread()
+ self.wavelength_tcl.SetValue(str(wavelength))
+ self.wavelength_spread_tcl.SetValue(str(wavelength_spread))
+ self.resolution.set_spectrum(self.spectrum_dic['Flat'])
+ self.spectrum_txt.Show(False)
+ self.spectrum_cb.Show(False)
+ self.wavelength_sizer.Layout()
+ self.Layout()
+
+ def _on_spectrum_cb(self, event=None):
+ """
+ On spectrum ComboBox event
+ """
+ if event is not None:
+ #combo = event.GetEventObject()
+ event.Skip()
+ else:
+ raise
+ selection = self.spectrum_cb.GetValue()
+ if selection == 'Add new':
+ path = self._selectDlg()
+ if path is None:
+ self.spectrum_cb.SetValue('Flat')
+ self.resolution.set_spectrum(self.spectrum_dic['Flat'])
+ msg = "No file has been chosen."
+ wx.MessageBox(msg, 'Info')
+ return
+ try:
+ basename = os.path.basename(path)
+ if basename not in self.spectrum_dic.keys():
+ self.spectrum_cb.Append(basename)
+ self.spectrum_dic[basename] = self._read_file(path)
+ self.spectrum_cb.SetValue(basename)
+ self.resolution.set_spectrum(self.spectrum_dic[basename])
+ return
+ except:
+ raise
+
+ self.resolution.set_spectrum(self.spectrum_dic[selection])
+
+ def _selectDlg(self):
+ """
+ open a dialog file to select a customized spectrum
+ """
+ dlg = wx.FileDialog(self,
+ "Choose a wavelength spectrum file: Intensity vs. wavelength",
+ self.parent.parent.get_save_location() , "", "*.*", wx.OPEN)
+ path = None
+ if dlg.ShowModal() == wx.ID_OK:
+ path = dlg.GetPath()
+ dlg.Destroy()
+ return path
+
+ def _read_file(self, path):
+ """
+ Read two columns file as tuples of numpy array
+
+ :param path: the path to the file to read
+
+ """
+ try:
+ if path is None:
+ wx.PostEvent(self.parent.parent, StatusEvent(status=\
+ " Selected Distribution was not loaded: %s" % path))
+ return None, None
+ input_f = open(path, 'r')
+ buff = input_f.read()
+ lines = buff.split('\n')
+
+ wavelength = []
+ intensity = []
+ for line in lines:
+ toks = line.split()
+ try:
+ wave = float(toks[0])
+ intens = float(toks[1])
+ wavelength.append(wave)
+ intensity.append(intens)
+ except:
+ # Skip non-data lines
+ logger.error(sys.exc_value)
+
+ return [wavelength, intensity]
+ except:
+ raise
+
+class ResolutionWindow(widget.CHILD_FRAME):
+ """
+ Resolution Window
+ """
+ def __init__(self, parent=None, manager=None,
+ title="Q Resolution Estimator",
+ size=(PANEL_WIDTH * 2, PANEL_HEIGHT), *args, **kwds):
+ kwds['title'] = title
+ kwds['size'] = size
+ widget.CHILD_FRAME.__init__(self, parent=parent, *args, **kwds)
+ self.parent = parent
+ self.manager = manager
+ self.panel = ResolutionCalculatorPanel(parent=self)
+ self.Bind(wx.EVT_CLOSE, self.OnClose)
+ self.SetPosition((wx.LEFT, PANEL_TOP))
+ self.Show(True)
+
+ def OnClose(self, event):
+ """
+ On close event
+ """
+ _pylab_helpers.Gcf.figs = {}
+ if self.manager is not None:
+ self.manager.cal_res_frame = None
+ self.Destroy()
+
+
+if __name__ == "__main__":
+ app = wx.PySimpleApp()
+ widget.CHILD_FRAME = wx.Frame
+ frame = ResolutionWindow()
+ frame.Show(True)
+ app.MainLoop()
diff --git a/src/sas/sasgui/perspectives/calculator/sample_editor.py b/src/sas/sasgui/perspectives/calculator/sample_editor.py
index a52ed20..5127a6d 100644
--- a/src/sas/sasgui/perspectives/calculator/sample_editor.py
+++ b/src/sas/sasgui/perspectives/calculator/sample_editor.py
@@ -1,552 +1,552 @@
-
-import wx
-import sys
-from copy import deepcopy
-from sas.sasgui.guiframe.utils import check_float
-
-_BOX_WIDTH = 60
-if sys.platform.count("win32") > 0:
- _STATICBOX_WIDTH = 450
- PANEL_WIDTH = 500
- PANEL_HEIGHT = 430
- FONT_VARIANT = 0
-else:
- _STATICBOX_WIDTH = 480
- PANEL_WIDTH = 550
- PANEL_HEIGHT = 430
- FONT_VARIANT = 1
-
-class SampleDialog(wx.Dialog):
- def __init__(self, parent=None, manager=None, sample=None,
- size=(PANEL_WIDTH, PANEL_HEIGHT), title='Sample Editor'):
-
- wx.Dialog.__init__(self, parent=parent, size=size, title=title)
- self.parent = parent
- self.manager = manager
- self._sample = sample
- self._reset_sample = deepcopy(sample)
- self._notes = ""
- self._description = "Edit Sample"
- self._do_layout()
- self.set_values()
-
- def _define_structure(self):
- """
- define initial sizer
- """
- self.main_sizer = wx.BoxSizer(wx.VERTICAL)
- self.box_sample = wx.StaticBox(self, -1, str("Sample"))
- self.boxsizer_sample = wx.StaticBoxSizer(self.box_sample,
- wx.VERTICAL)
- self.name_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.id_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.thickness_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.transmission_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.temperature_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.position_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.orientation_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.details_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.button_sizer = wx.BoxSizer(wx.HORIZONTAL)
-
- def _layout_name(self):
- """
- Do the layout for sample name related widgets
- """
- ## Short name for sample [string]
- sample_name_txt = wx.StaticText(self, -1, 'Sample Name : ')
- self.sample_name_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH * 5, 20), style=0)
- self.name_sizer.AddMany([(sample_name_txt, 0, wx.LEFT | wx.RIGHT, 10),
- (self.sample_name_tcl, 0, wx.EXPAND)])
- def _layout_id(self):
- """
- Do the layout for id related widgets
- """
- ## ID [String]
- id_txt = wx.StaticText(self, -1, 'ID: ')
- self.id_tcl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, 20), style=0)
- self.id_sizer.AddMany([(id_txt, 0, wx.LEFT | wx.RIGHT, 10),
- (self.id_tcl, 0, wx.LEFT, 55)])
-
- def _layout_thickness(self):
- """
- Do the layout for thickness related widgets
- """
- ## Thickness [float] [mm]
- thickness_txt = wx.StaticText(self, -1, 'Thickness:')
- self.thickness_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, 20), style=0)
- thickness_unit_txt = wx.StaticText(self, -1, 'Unit: ')
- self.thickness_unit_tcl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, 20),
- style=0)
- self.thickness_sizer.AddMany([(thickness_txt, 0, wx.LEFT | wx.RIGHT, 10),
- (self.thickness_tcl, 0, wx.LEFT, 25),
- (thickness_unit_txt, 0, wx.LEFT | wx.RIGHT, 10),
- (self.thickness_unit_tcl, 0, wx.EXPAND)])
- def _layout_transmission(self):
- """
- Do the layout for transmission related widgets
- """
- ## Transmission [float] [fraction]
- transmission = None
- transmission_txt = wx.StaticText(self, -1, 'Transmission:')
- self.transmission_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, 20), style=0)
- self.transmission_sizer.AddMany([(transmission_txt,
- 0, wx.LEFT | wx.RIGHT, 10),
- (self.transmission_tcl, 0, wx.LEFT, 12)])
-
- def _layout_temperature(self):
- """
- Do the layout for temperature related widgets
- """
- ## Temperature [float] [C]
- temperature_txt = wx.StaticText(self, -1, 'Temperature:')
- self.temperature_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, 20), style=0)
- temperature_unit_txt = wx.StaticText(self, -1, 'Unit: ')
- self.temperature_unit_tcl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, 20),
- style=0)
- self.temperature_sizer.AddMany([(temperature_txt, 0,
- wx.LEFT | wx.RIGHT, 10),
- (self.temperature_tcl, 0, wx.LEFT, 10),
- (temperature_unit_txt, 0, wx.LEFT | wx.RIGHT, 10),
- (self.temperature_unit_tcl, 0, wx.EXPAND)])
-
- def _layout_position(self):
- """
- Do the layout for position related widgets
- """
- ## Position [Vector] [mm]
- position_txt = wx.StaticText(self, -1, 'Position:')
- x_position_txt = wx.StaticText(self, -1, 'x = ')
- self.x_position_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, 20), style=0)
- y_position_txt = wx.StaticText(self, -1, 'y = ')
- self.y_position_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, 20), style=0)
- z_position_txt = wx.StaticText(self, -1, 'z = ')
- self.z_position_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, 20), style=0)
- position_unit_txt = wx.StaticText(self, -1, 'Unit: ')
- self.position_unit_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, 20), style=0)
- self.position_sizer.AddMany([(position_txt, 0, wx.LEFT | wx.RIGHT, 10),
- (x_position_txt, 0, wx.LEFT, 14),
- (self.x_position_tcl, 0, wx.RIGHT, 10),
- (y_position_txt, 0, wx.EXPAND),
- (self.y_position_tcl, 0, wx.RIGHT, 10),
- (z_position_txt, 0, wx.EXPAND),
- (self.z_position_tcl, 0, wx.RIGHT, 10),
- (position_unit_txt, 0, wx.EXPAND),
- (self.position_unit_tcl, 0, wx.RIGHT, 10)])
- def _layout_orientation(self):
- """
- Do the layout for orientation related widgets
- """
- ## Orientation [Vector] [degrees]
- orientation_txt = wx.StaticText(self, -1, 'Orientation:')
- x_orientation_txt = wx.StaticText(self, -1, 'x = ')
- self.x_orientation_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, 20), style=0)
- y_orientation_txt = wx.StaticText(self, -1, 'y = ')
- self.y_orientation_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, 20), style=0)
- z_orientation_txt = wx.StaticText(self, -1, 'z = ')
- self.z_orientation_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, 20), style=0)
- orientation_unit_txt = wx.StaticText(self, -1, 'Unit: ')
- self.orientation_unit_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, 20), style=0)
- self.orientation_sizer.AddMany([(orientation_txt, 0,
- wx.LEFT | wx.RIGHT, 10),
- (x_orientation_txt, 0, wx.LEFT, 0),
- (self.x_orientation_tcl, 0, wx.RIGHT, 10),
- (y_orientation_txt, 0, wx.EXPAND),
- (self.y_orientation_tcl, 0, wx.RIGHT, 10),
- (z_orientation_txt, 0, wx.EXPAND),
- (self.z_orientation_tcl, 0, wx.RIGHT, 10),
- (orientation_unit_txt, 0, wx.EXPAND),
- (self.orientation_unit_tcl, 0, wx.RIGHT, 10)])
-
- def _layout_details(self):
- """
- Do the layout for beam size name related widgets
- """
- ## Details
- details = None
- details_txt = wx.StaticText(self, -1, 'Details: ')
- self.details_tcl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH * 5, _BOX_WIDTH),
- style=wx.TE_MULTILINE | wx.HSCROLL)
- self.details_sizer.AddMany([(details_txt, 0, wx.LEFT | wx.RIGHT, 10),
- (self.details_tcl, 0, wx.EXPAND)])
-
- def _layout_button(self):
- """
- Do the layout for the button widgets
- """
- self.bt_apply = wx.Button(self, -1, 'Apply')
- self.bt_apply.Bind(wx.EVT_BUTTON, self.on_click_apply)
- self.bt_apply.SetToolTipString("Apply current changes to the sample.")
- self.bt_cancel = wx.Button(self, -1, 'Cancel')
- self.bt_cancel.SetToolTipString("Cancel current changes.")
- self.bt_cancel.Bind(wx.EVT_BUTTON, self.on_click_cancel)
- self.bt_close = wx.Button(self, wx.ID_CANCEL, 'Close')
- self.bt_close.SetToolTipString("Close window.")
- self.button_sizer.AddMany([(self.bt_apply, 0, wx.LEFT, 200),
- (self.bt_cancel, 0, wx.LEFT, 10),
- (self.bt_close, 0, wx.LEFT, 10)])
-
- def _do_layout(self, data=None):
- """
- Draw the current panel
- """
- self._define_structure()
- self._layout_name()
- self._layout_id()
- self._layout_thickness()
- self._layout_transmission()
- self._layout_temperature()
- self._layout_position()
- self._layout_orientation()
- self._layout_details()
- self._layout_button()
- self.boxsizer_sample.AddMany([(self.name_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
- (self.id_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
- (self.thickness_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
- (self.transmission_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
- (self.temperature_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
- (self.position_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
- (self.orientation_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
- (self.details_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
- self.main_sizer.AddMany([(self.boxsizer_sample, 0, wx.ALL, 10),
- (self.button_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
-
- self.SetSizer(self.main_sizer)
- self.SetAutoLayout(True)
-
- def reset_sample(self):
- """
- Put initial values of the sample back to the current sample
- """
- self._sample.name = self._reset_sample.name
- self._sample.ID = self._reset_sample.ID
- self._sample.thickness = self._reset_sample.thickness
- self._sample.thickness_unit = self._reset_sample.thickness_unit
- self._sample.transmission = self._reset_sample.transmission
- self._sample.temperature = self._reset_sample.temperature
- self._sample.temperature_unit = self._reset_sample.temperature_unit
-
- self._sample.position.x = self._reset_sample.position.x
- self._sample.position.y = self._reset_sample.position.y
- self._sample.position.z = self._reset_sample.position.x
- self._sample.position_unit = self._reset_sample.position_unit
-
- self._sample.orientation.x = self._reset_sample.orientation.x
- self._sample.orientation.y = self._reset_sample.orientation.y
- self._sample.orientation.z = self._reset_sample.orientation.x
- self._sample.orientation_unit = self._reset_sample.orientation_unit
-
- self._sample.details = self._reset_sample.details
-
- def set_manager(self, manager):
- """
- Set manager of this window
- """
- self.manager = manager
-
- def set_values(self):
- """
- take the sample values of the current data and display them
- through the panel
- """
- sample = self._sample
- #Name
- self.sample_name_tcl.SetValue(str(sample.name))
- #id
- self.id_tcl.SetValue(str(sample.ID))
- #thickness
- self.thickness_tcl.SetValue(str(sample.thickness))
- self.thickness_unit_tcl.SetValue(str(sample.thickness_unit))
- #transmission
- self.transmission_tcl.SetValue(str(sample.transmission))
- #temperature
- self.temperature_tcl.SetValue(str(sample.temperature))
- self.temperature_unit_tcl.SetValue(str(sample.temperature_unit))
- #position
- x, y, z = sample.position.x, sample.position.y , sample.position.z
- self.x_position_tcl.SetValue(str(x))
- self.y_position_tcl.SetValue(str(y))
- self.z_position_tcl.SetValue(str(z))
- self.position_unit_tcl.SetValue(str(sample.position_unit))
- #orientation
- x, y = sample.orientation.x, sample.orientation.y
- z = sample.orientation.z
- self.x_orientation_tcl.SetValue(str(x))
- self.y_orientation_tcl.SetValue(str(y))
- self.z_orientation_tcl.SetValue(str(z))
- self.orientation_unit_tcl.SetValue(str(sample.orientation_unit))
-
- self.set_details(sample)
-
- def set_details(self, sample):
- """
- print details on the current sample
- """
- #detail
- msg = ''
- if sample.details is not None or sample.details:
- for item in sample.details:
- msg += " %s\n" % item
- self.details_tcl.SetValue(str(msg))
-
- def get_sample(self):
- """
- return the current sample
- """
- return self._sample
-
- def get_notes(self):
- """
- return notes
- """
- return self._notes
-
- def on_change_name(self):
- """
- Change name
- """
- #Change the name of the sample
- name = self.sample_name_tcl.GetValue().lstrip().rstrip()
- if name == "" or name == str(None):
- name = None
- if self._sample.name != name:
- self._notes += "Change sample 's "
- self._notes += "name from %s to %s \n" % (self._sample.name, name)
- self._sample.name = name
-
- def on_change_id(self):
- """
- Change id of the sample
- """
- #Change id
- id = self.id_tcl.GetValue().lstrip().rstrip()
- self._sample.ID = id
- self._notes += " Change ID from"
- self._notes += " %s to %s \n" % (self._sample.ID, id)
-
- def on_change_thickness(self):
- """
- Change thickness
- """
- #Change thickness
- thickness = self.thickness_tcl.GetValue().lstrip().rstrip()
- self._sample.thickness = thickness
- self._notes += " Change thickness from"
- self._notes += " %s to %s \n" % (self._sample.thickness, thickness)
-
- def on_change_transmission(self):
- """
- Change transmission
- """
- #Change transmission
- transmission = self.transmission_tcl.GetValue().lstrip().rstrip()
- if self._sample.transmission != transmission:
- self._notes += " Change transmission from"
- self._notes += " %s to %s \n" % (self._sample.transmission,
- transmission)
- self._sample.transmission = transmission
-
- def on_change_temperature(self):
- """
- Change temperature
- """
- #Change temperature
- temperature = self.temperature_tcl.GetValue().lstrip().rstrip()
- self._sample.temperature = temperature
- self._notes += " Change temperature from"
- self._notes += " %s to %s \n" % (self._sample.temperature, temperature)
- #change temperature unit
- unit = self.temperature_unit_tcl.GetValue().lstrip().rstrip()
- if self._sample.temperature_unit != unit:
- self._notes += " Change temperature's unit from "
- self._notes += "%s to %s" % (self._sample.temperature_unit, unit)
- self._sample.temperature_unit = unit
-
- def on_change_position(self):
- """
- Change position
- """
- #Change x coordinate
- x_position = self.x_position_tcl.GetValue().lstrip().rstrip()
- if x_position == "" or x_position == str(None):
- x_position = None
- else:
- if check_float(self.x_position_tcl):
- if self._sample.position.x != float(x_position) :
- self._notes += "Change x of position from "
- self._notes += "%s to %s \n" % (self._sample.position.x,
- x_position)
- self._sample.position.x = float(x_position)
- else:
- self._notes += "Error: Expected a float for the position 's x "
- self._notes += "won't changes x position from "
- self._notes += "%s to %s" % (self._sample.position.x, x_position)
- #Change y coordinate
- y_position = self.y_position_tcl.GetValue().lstrip().rstrip()
- if y_position == "" or y_position == str(None):
- y_position = None
- self._sample.position.y = y_position
- else:
- if check_float(self.y_position_tcl):
- if self._sample.position.y != float(y_position):
- self._notes += "Change y of position from "
- self._notes += "%s to %s \n" % (self._sample.position.y,
- y_position)
- self._sample.position.y = float(y_position)
- else:
- self._notes += "Error: Expected a float for the beam size's y "
- self._notes += "won't changes y position from "
- self._notes += "%s to %s" % (self._sample.position.y, y_position)
- #Change z coordinate
- z_position = self.z_position_tcl.GetValue().lstrip().rstrip()
- if z_position == "" or z_position == str(None):
- z_position = None
- self._sample.position.z = z_position
- else:
- if check_float(self.z_position_tcl):
- if self._sample.position.z != float(z_position):
- self._notes += "Change z of position from "
- self._notes += "%s to %s \n" % (self._sample.position.z,
- z_position)
- self._sample.position.z = float(z_position)
- else:
- self._notes += "Error: Expected a float for position's x "
- self._notes += "won't changes z position from "
- self._notes += "%s to %s" % (self._sample.position.z, z_position)
- #change the beam center unit
- unit = self.position_unit_tcl.GetValue().lstrip().rstrip()
- if self._sample.position_unit != unit:
- self._notes += " Change position's unit from "
- self._notes += "%s to %s" % (self._sample.position_unit, unit)
-
- def on_change_orientation(self):
- """
- Change orientation
- """
- #Change x coordinate
- x_orientation = self.x_orientation_tcl.GetValue().lstrip().rstrip()
- if x_orientation == "" or x_orientation == str(None):
- x_orientation = None
- else:
- if check_float(self.x_orientation_tcl):
- if self._sample.orientation.x != float(x_orientation) :
- self._notes += "Change x of orientation from "
- self._notes += "%s to %s \n" % (self._sample.orientation.x,
- x_orientation)
- self._sample.orientation.x = float(x_orientation)
- else:
- self._notes += "Error: Expected a float for orientation 's x "
- self._notes += "won't changes x orientation from "
- self._notes += "%s to %s" % (self._sample.orientation.x,
- x_orientation)
- #Change y coordinate
- y_orientation = self.y_orientation_tcl.GetValue().lstrip().rstrip()
- if y_orientation == "" or y_orientation == str(None):
- y_orientation = None
- self._sample.orientation.y = y_orientation
- else:
- if check_float(self.y_orientation_tcl):
- if self._sample.orientation.y != float(y_orientation):
- self._notes += "Change y of orientation from "
- self._notes += "%s to %s \n" % (self._sample.orientation.y,
- y_orientation)
- self._sample.orientation.y = float(y_orientation)
- else:
- self._notes += "Error: Expected a float for orientation's y "
- self._notes += "won't changes y orientation from "
- self._notes += "%s to %s" % (self._sample.orientation.y,
- y_orientation)
- #Change z coordinate
- z_orientation = self.z_orientation_tcl.GetValue().lstrip().rstrip()
- if z_orientation == "" or z_orientation == str(None):
- z_orientation = None
- self._sample.orientation.z = z_orientation
- else:
- if check_float(self.z_orientation_tcl):
- if self._sample.orientation.z != float(z_orientation):
- self._notes += "Change z of orientation from "
- self._notes += "%s to %s \n" % (self._sample.orientation.z,
- z_orientation)
- self._sample.orientation.z = float(z_orientation)
- else:
- self._notes += "Error: Expected a float for orientation 's x "
- self._notes += "won't changes z orientation from "
- self._notes += "%s to %s" % (self._sample.orientation.z,
- z_orientation)
- #change the beam center unit
- unit = self.orientation_unit_tcl.GetValue().lstrip().rstrip()
- if self._sample.orientation_unit != unit:
- self._notes += " Change orientation's unit from "
- self._notes += "%s to %s" % (self._sample.orientation_unit, unit)
-
- def on_change_details(self):
- """
- Change details
- """
- #Change details
- details = self.details_tcl.GetValue().lstrip().rstrip()
- msg = ""
- if self._sample.details is not None or self._sample.details:
- for item in self._sample.details:
- if item != details:
- msg += " %s\n" % item
- self._notes += " Change details from"
- self._notes += " %s to %s \n" % (msg, details)
- self._sample.details.append(details)
-
- def on_click_apply(self, event):
- """
- Apply user values to the sample
- """
- self.on_change_name()
- self.on_change_id()
- self.on_change_thickness()
- self.on_change_transmission()
- self.on_change_temperature()
- self.on_change_position()
- self.on_change_orientation()
- self.on_change_details()
- self.set_details(self._sample)
- if self.manager is not None:
- self.manager.set_sample(self._sample)
- if event is not None:
- event.Skip()
-
- def on_click_cancel(self, event):
- """
- leave the sample as it is and close
- """
- self.reset_sample()
- self.set_values()
- if self.manager is not None:
- self.manager.set_sample(self._sample, self._notes)
- if event is not None:
- event.Skip()
-
-if __name__ == "__main__":
- app = wx.App()
- from sas.sascalc.dataloader.data_info import Sample
- sample = Sample()
- dlg = SampleDialog(sample=sample)
- dlg.ShowModal()
- app.MainLoop()
+
+import wx
+import sys
+from copy import deepcopy
+from sas.sasgui.guiframe.utils import check_float
+
+_BOX_WIDTH = 60
+if sys.platform.count("win32") > 0:
+ _STATICBOX_WIDTH = 450
+ PANEL_WIDTH = 500
+ PANEL_HEIGHT = 430
+ FONT_VARIANT = 0
+else:
+ _STATICBOX_WIDTH = 480
+ PANEL_WIDTH = 550
+ PANEL_HEIGHT = 430
+ FONT_VARIANT = 1
+
+class SampleDialog(wx.Dialog):
+ def __init__(self, parent=None, manager=None, sample=None,
+ size=(PANEL_WIDTH, PANEL_HEIGHT), title='Sample Editor'):
+
+ wx.Dialog.__init__(self, parent=parent, size=size, title=title)
+ self.parent = parent
+ self.manager = manager
+ self._sample = sample
+ self._reset_sample = deepcopy(sample)
+ self._notes = ""
+ self._description = "Edit Sample"
+ self._do_layout()
+ self.set_values()
+
+ def _define_structure(self):
+ """
+ define initial sizer
+ """
+ self.main_sizer = wx.BoxSizer(wx.VERTICAL)
+ self.box_sample = wx.StaticBox(self, -1, str("Sample"))
+ self.boxsizer_sample = wx.StaticBoxSizer(self.box_sample,
+ wx.VERTICAL)
+ self.name_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.id_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.thickness_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.transmission_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.temperature_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.position_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.orientation_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.details_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.button_sizer = wx.BoxSizer(wx.HORIZONTAL)
+
+ def _layout_name(self):
+ """
+ Do the layout for sample name related widgets
+ """
+ ## Short name for sample [string]
+ sample_name_txt = wx.StaticText(self, -1, 'Sample Name : ')
+ self.sample_name_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH * 5, 20), style=0)
+ self.name_sizer.AddMany([(sample_name_txt, 0, wx.LEFT | wx.RIGHT, 10),
+ (self.sample_name_tcl, 0, wx.EXPAND)])
+ def _layout_id(self):
+ """
+ Do the layout for id related widgets
+ """
+ ## ID [String]
+ id_txt = wx.StaticText(self, -1, 'ID: ')
+ self.id_tcl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, 20), style=0)
+ self.id_sizer.AddMany([(id_txt, 0, wx.LEFT | wx.RIGHT, 10),
+ (self.id_tcl, 0, wx.LEFT, 55)])
+
+ def _layout_thickness(self):
+ """
+ Do the layout for thickness related widgets
+ """
+ ## Thickness [float] [mm]
+ thickness_txt = wx.StaticText(self, -1, 'Thickness:')
+ self.thickness_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, 20), style=0)
+ thickness_unit_txt = wx.StaticText(self, -1, 'Unit: ')
+ self.thickness_unit_tcl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, 20),
+ style=0)
+ self.thickness_sizer.AddMany([(thickness_txt, 0, wx.LEFT | wx.RIGHT, 10),
+ (self.thickness_tcl, 0, wx.LEFT, 25),
+ (thickness_unit_txt, 0, wx.LEFT | wx.RIGHT, 10),
+ (self.thickness_unit_tcl, 0, wx.EXPAND)])
+ def _layout_transmission(self):
+ """
+ Do the layout for transmission related widgets
+ """
+ ## Transmission [float] [fraction]
+ transmission = None
+ transmission_txt = wx.StaticText(self, -1, 'Transmission:')
+ self.transmission_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, 20), style=0)
+ self.transmission_sizer.AddMany([(transmission_txt,
+ 0, wx.LEFT | wx.RIGHT, 10),
+ (self.transmission_tcl, 0, wx.LEFT, 12)])
+
+ def _layout_temperature(self):
+ """
+ Do the layout for temperature related widgets
+ """
+ ## Temperature [float] [C]
+ temperature_txt = wx.StaticText(self, -1, 'Temperature:')
+ self.temperature_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, 20), style=0)
+ temperature_unit_txt = wx.StaticText(self, -1, 'Unit: ')
+ self.temperature_unit_tcl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, 20),
+ style=0)
+ self.temperature_sizer.AddMany([(temperature_txt, 0,
+ wx.LEFT | wx.RIGHT, 10),
+ (self.temperature_tcl, 0, wx.LEFT, 10),
+ (temperature_unit_txt, 0, wx.LEFT | wx.RIGHT, 10),
+ (self.temperature_unit_tcl, 0, wx.EXPAND)])
+
+ def _layout_position(self):
+ """
+ Do the layout for position related widgets
+ """
+ ## Position [Vector] [mm]
+ position_txt = wx.StaticText(self, -1, 'Position:')
+ x_position_txt = wx.StaticText(self, -1, 'x = ')
+ self.x_position_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, 20), style=0)
+ y_position_txt = wx.StaticText(self, -1, 'y = ')
+ self.y_position_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, 20), style=0)
+ z_position_txt = wx.StaticText(self, -1, 'z = ')
+ self.z_position_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, 20), style=0)
+ position_unit_txt = wx.StaticText(self, -1, 'Unit: ')
+ self.position_unit_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, 20), style=0)
+ self.position_sizer.AddMany([(position_txt, 0, wx.LEFT | wx.RIGHT, 10),
+ (x_position_txt, 0, wx.LEFT, 14),
+ (self.x_position_tcl, 0, wx.RIGHT, 10),
+ (y_position_txt, 0, wx.EXPAND),
+ (self.y_position_tcl, 0, wx.RIGHT, 10),
+ (z_position_txt, 0, wx.EXPAND),
+ (self.z_position_tcl, 0, wx.RIGHT, 10),
+ (position_unit_txt, 0, wx.EXPAND),
+ (self.position_unit_tcl, 0, wx.RIGHT, 10)])
+ def _layout_orientation(self):
+ """
+ Do the layout for orientation related widgets
+ """
+ ## Orientation [Vector] [degrees]
+ orientation_txt = wx.StaticText(self, -1, 'Orientation:')
+ x_orientation_txt = wx.StaticText(self, -1, 'x = ')
+ self.x_orientation_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, 20), style=0)
+ y_orientation_txt = wx.StaticText(self, -1, 'y = ')
+ self.y_orientation_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, 20), style=0)
+ z_orientation_txt = wx.StaticText(self, -1, 'z = ')
+ self.z_orientation_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, 20), style=0)
+ orientation_unit_txt = wx.StaticText(self, -1, 'Unit: ')
+ self.orientation_unit_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, 20), style=0)
+ self.orientation_sizer.AddMany([(orientation_txt, 0,
+ wx.LEFT | wx.RIGHT, 10),
+ (x_orientation_txt, 0, wx.LEFT, 0),
+ (self.x_orientation_tcl, 0, wx.RIGHT, 10),
+ (y_orientation_txt, 0, wx.EXPAND),
+ (self.y_orientation_tcl, 0, wx.RIGHT, 10),
+ (z_orientation_txt, 0, wx.EXPAND),
+ (self.z_orientation_tcl, 0, wx.RIGHT, 10),
+ (orientation_unit_txt, 0, wx.EXPAND),
+ (self.orientation_unit_tcl, 0, wx.RIGHT, 10)])
+
+ def _layout_details(self):
+ """
+ Do the layout for beam size name related widgets
+ """
+ ## Details
+ details = None
+ details_txt = wx.StaticText(self, -1, 'Details: ')
+ self.details_tcl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH * 5, _BOX_WIDTH),
+ style=wx.TE_MULTILINE | wx.HSCROLL)
+ self.details_sizer.AddMany([(details_txt, 0, wx.LEFT | wx.RIGHT, 10),
+ (self.details_tcl, 0, wx.EXPAND)])
+
+ def _layout_button(self):
+ """
+ Do the layout for the button widgets
+ """
+ self.bt_apply = wx.Button(self, -1, 'Apply')
+ self.bt_apply.Bind(wx.EVT_BUTTON, self.on_click_apply)
+ self.bt_apply.SetToolTipString("Apply current changes to the sample.")
+ self.bt_cancel = wx.Button(self, -1, 'Cancel')
+ self.bt_cancel.SetToolTipString("Cancel current changes.")
+ self.bt_cancel.Bind(wx.EVT_BUTTON, self.on_click_cancel)
+ self.bt_close = wx.Button(self, wx.ID_CANCEL, 'Close')
+ self.bt_close.SetToolTipString("Close window.")
+ self.button_sizer.AddMany([(self.bt_apply, 0, wx.LEFT, 200),
+ (self.bt_cancel, 0, wx.LEFT, 10),
+ (self.bt_close, 0, wx.LEFT, 10)])
+
+ def _do_layout(self, data=None):
+ """
+ Draw the current panel
+ """
+ self._define_structure()
+ self._layout_name()
+ self._layout_id()
+ self._layout_thickness()
+ self._layout_transmission()
+ self._layout_temperature()
+ self._layout_position()
+ self._layout_orientation()
+ self._layout_details()
+ self._layout_button()
+ self.boxsizer_sample.AddMany([(self.name_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
+ (self.id_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
+ (self.thickness_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
+ (self.transmission_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
+ (self.temperature_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
+ (self.position_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
+ (self.orientation_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
+ (self.details_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
+ self.main_sizer.AddMany([(self.boxsizer_sample, 0, wx.ALL, 10),
+ (self.button_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
+
+ self.SetSizer(self.main_sizer)
+ self.SetAutoLayout(True)
+
+ def reset_sample(self):
+ """
+ Put initial values of the sample back to the current sample
+ """
+ self._sample.name = self._reset_sample.name
+ self._sample.ID = self._reset_sample.ID
+ self._sample.thickness = self._reset_sample.thickness
+ self._sample.thickness_unit = self._reset_sample.thickness_unit
+ self._sample.transmission = self._reset_sample.transmission
+ self._sample.temperature = self._reset_sample.temperature
+ self._sample.temperature_unit = self._reset_sample.temperature_unit
+
+ self._sample.position.x = self._reset_sample.position.x
+ self._sample.position.y = self._reset_sample.position.y
+ self._sample.position.z = self._reset_sample.position.x
+ self._sample.position_unit = self._reset_sample.position_unit
+
+ self._sample.orientation.x = self._reset_sample.orientation.x
+ self._sample.orientation.y = self._reset_sample.orientation.y
+ self._sample.orientation.z = self._reset_sample.orientation.x
+ self._sample.orientation_unit = self._reset_sample.orientation_unit
+
+ self._sample.details = self._reset_sample.details
+
+ def set_manager(self, manager):
+ """
+ Set manager of this window
+ """
+ self.manager = manager
+
+ def set_values(self):
+ """
+ take the sample values of the current data and display them
+ through the panel
+ """
+ sample = self._sample
+ #Name
+ self.sample_name_tcl.SetValue(str(sample.name))
+ #id
+ self.id_tcl.SetValue(str(sample.ID))
+ #thickness
+ self.thickness_tcl.SetValue(str(sample.thickness))
+ self.thickness_unit_tcl.SetValue(str(sample.thickness_unit))
+ #transmission
+ self.transmission_tcl.SetValue(str(sample.transmission))
+ #temperature
+ self.temperature_tcl.SetValue(str(sample.temperature))
+ self.temperature_unit_tcl.SetValue(str(sample.temperature_unit))
+ #position
+ x, y, z = sample.position.x, sample.position.y , sample.position.z
+ self.x_position_tcl.SetValue(str(x))
+ self.y_position_tcl.SetValue(str(y))
+ self.z_position_tcl.SetValue(str(z))
+ self.position_unit_tcl.SetValue(str(sample.position_unit))
+ #orientation
+ x, y = sample.orientation.x, sample.orientation.y
+ z = sample.orientation.z
+ self.x_orientation_tcl.SetValue(str(x))
+ self.y_orientation_tcl.SetValue(str(y))
+ self.z_orientation_tcl.SetValue(str(z))
+ self.orientation_unit_tcl.SetValue(str(sample.orientation_unit))
+
+ self.set_details(sample)
+
+ def set_details(self, sample):
+ """
+ print details on the current sample
+ """
+ #detail
+ msg = ''
+ if sample.details is not None or sample.details:
+ for item in sample.details:
+ msg += " %s\n" % item
+ self.details_tcl.SetValue(str(msg))
+
+ def get_sample(self):
+ """
+ return the current sample
+ """
+ return self._sample
+
+ def get_notes(self):
+ """
+ return notes
+ """
+ return self._notes
+
+ def on_change_name(self):
+ """
+ Change name
+ """
+ #Change the name of the sample
+ name = self.sample_name_tcl.GetValue().lstrip().rstrip()
+ if name == "" or name == str(None):
+ name = None
+ if self._sample.name != name:
+ self._notes += "Change sample 's "
+ self._notes += "name from %s to %s \n" % (self._sample.name, name)
+ self._sample.name = name
+
+ def on_change_id(self):
+ """
+ Change id of the sample
+ """
+ #Change id
+ id = self.id_tcl.GetValue().lstrip().rstrip()
+ self._sample.ID = id
+ self._notes += " Change ID from"
+ self._notes += " %s to %s \n" % (self._sample.ID, id)
+
+ def on_change_thickness(self):
+ """
+ Change thickness
+ """
+ #Change thickness
+ thickness = self.thickness_tcl.GetValue().lstrip().rstrip()
+ self._sample.thickness = thickness
+ self._notes += " Change thickness from"
+ self._notes += " %s to %s \n" % (self._sample.thickness, thickness)
+
+ def on_change_transmission(self):
+ """
+ Change transmission
+ """
+ #Change transmission
+ transmission = self.transmission_tcl.GetValue().lstrip().rstrip()
+ if self._sample.transmission != transmission:
+ self._notes += " Change transmission from"
+ self._notes += " %s to %s \n" % (self._sample.transmission,
+ transmission)
+ self._sample.transmission = transmission
+
+ def on_change_temperature(self):
+ """
+ Change temperature
+ """
+ #Change temperature
+ temperature = self.temperature_tcl.GetValue().lstrip().rstrip()
+ self._sample.temperature = temperature
+ self._notes += " Change temperature from"
+ self._notes += " %s to %s \n" % (self._sample.temperature, temperature)
+ #change temperature unit
+ unit = self.temperature_unit_tcl.GetValue().lstrip().rstrip()
+ if self._sample.temperature_unit != unit:
+ self._notes += " Change temperature's unit from "
+ self._notes += "%s to %s" % (self._sample.temperature_unit, unit)
+ self._sample.temperature_unit = unit
+
+ def on_change_position(self):
+ """
+ Change position
+ """
+ #Change x coordinate
+ x_position = self.x_position_tcl.GetValue().lstrip().rstrip()
+ if x_position == "" or x_position == str(None):
+ x_position = None
+ else:
+ if check_float(self.x_position_tcl):
+ if self._sample.position.x != float(x_position) :
+ self._notes += "Change x of position from "
+ self._notes += "%s to %s \n" % (self._sample.position.x,
+ x_position)
+ self._sample.position.x = float(x_position)
+ else:
+ self._notes += "Error: Expected a float for the position 's x "
+ self._notes += "won't changes x position from "
+ self._notes += "%s to %s" % (self._sample.position.x, x_position)
+ #Change y coordinate
+ y_position = self.y_position_tcl.GetValue().lstrip().rstrip()
+ if y_position == "" or y_position == str(None):
+ y_position = None
+ self._sample.position.y = y_position
+ else:
+ if check_float(self.y_position_tcl):
+ if self._sample.position.y != float(y_position):
+ self._notes += "Change y of position from "
+ self._notes += "%s to %s \n" % (self._sample.position.y,
+ y_position)
+ self._sample.position.y = float(y_position)
+ else:
+ self._notes += "Error: Expected a float for the beam size's y "
+ self._notes += "won't changes y position from "
+ self._notes += "%s to %s" % (self._sample.position.y, y_position)
+ #Change z coordinate
+ z_position = self.z_position_tcl.GetValue().lstrip().rstrip()
+ if z_position == "" or z_position == str(None):
+ z_position = None
+ self._sample.position.z = z_position
+ else:
+ if check_float(self.z_position_tcl):
+ if self._sample.position.z != float(z_position):
+ self._notes += "Change z of position from "
+ self._notes += "%s to %s \n" % (self._sample.position.z,
+ z_position)
+ self._sample.position.z = float(z_position)
+ else:
+ self._notes += "Error: Expected a float for position's x "
+ self._notes += "won't changes z position from "
+ self._notes += "%s to %s" % (self._sample.position.z, z_position)
+ #change the beam center unit
+ unit = self.position_unit_tcl.GetValue().lstrip().rstrip()
+ if self._sample.position_unit != unit:
+ self._notes += " Change position's unit from "
+ self._notes += "%s to %s" % (self._sample.position_unit, unit)
+
+ def on_change_orientation(self):
+ """
+ Change orientation
+ """
+ #Change x coordinate
+ x_orientation = self.x_orientation_tcl.GetValue().lstrip().rstrip()
+ if x_orientation == "" or x_orientation == str(None):
+ x_orientation = None
+ else:
+ if check_float(self.x_orientation_tcl):
+ if self._sample.orientation.x != float(x_orientation) :
+ self._notes += "Change x of orientation from "
+ self._notes += "%s to %s \n" % (self._sample.orientation.x,
+ x_orientation)
+ self._sample.orientation.x = float(x_orientation)
+ else:
+ self._notes += "Error: Expected a float for orientation 's x "
+ self._notes += "won't changes x orientation from "
+ self._notes += "%s to %s" % (self._sample.orientation.x,
+ x_orientation)
+ #Change y coordinate
+ y_orientation = self.y_orientation_tcl.GetValue().lstrip().rstrip()
+ if y_orientation == "" or y_orientation == str(None):
+ y_orientation = None
+ self._sample.orientation.y = y_orientation
+ else:
+ if check_float(self.y_orientation_tcl):
+ if self._sample.orientation.y != float(y_orientation):
+ self._notes += "Change y of orientation from "
+ self._notes += "%s to %s \n" % (self._sample.orientation.y,
+ y_orientation)
+ self._sample.orientation.y = float(y_orientation)
+ else:
+ self._notes += "Error: Expected a float for orientation's y "
+ self._notes += "won't changes y orientation from "
+ self._notes += "%s to %s" % (self._sample.orientation.y,
+ y_orientation)
+ #Change z coordinate
+ z_orientation = self.z_orientation_tcl.GetValue().lstrip().rstrip()
+ if z_orientation == "" or z_orientation == str(None):
+ z_orientation = None
+ self._sample.orientation.z = z_orientation
+ else:
+ if check_float(self.z_orientation_tcl):
+ if self._sample.orientation.z != float(z_orientation):
+ self._notes += "Change z of orientation from "
+ self._notes += "%s to %s \n" % (self._sample.orientation.z,
+ z_orientation)
+ self._sample.orientation.z = float(z_orientation)
+ else:
+ self._notes += "Error: Expected a float for orientation 's x "
+ self._notes += "won't changes z orientation from "
+ self._notes += "%s to %s" % (self._sample.orientation.z,
+ z_orientation)
+ #change the beam center unit
+ unit = self.orientation_unit_tcl.GetValue().lstrip().rstrip()
+ if self._sample.orientation_unit != unit:
+ self._notes += " Change orientation's unit from "
+ self._notes += "%s to %s" % (self._sample.orientation_unit, unit)
+
+ def on_change_details(self):
+ """
+ Change details
+ """
+ #Change details
+ details = self.details_tcl.GetValue().lstrip().rstrip()
+ msg = ""
+ if self._sample.details is not None or self._sample.details:
+ for item in self._sample.details:
+ if item != details:
+ msg += " %s\n" % item
+ self._notes += " Change details from"
+ self._notes += " %s to %s \n" % (msg, details)
+ self._sample.details.append(details)
+
+ def on_click_apply(self, event):
+ """
+ Apply user values to the sample
+ """
+ self.on_change_name()
+ self.on_change_id()
+ self.on_change_thickness()
+ self.on_change_transmission()
+ self.on_change_temperature()
+ self.on_change_position()
+ self.on_change_orientation()
+ self.on_change_details()
+ self.set_details(self._sample)
+ if self.manager is not None:
+ self.manager.set_sample(self._sample)
+ if event is not None:
+ event.Skip()
+
+ def on_click_cancel(self, event):
+ """
+ leave the sample as it is and close
+ """
+ self.reset_sample()
+ self.set_values()
+ if self.manager is not None:
+ self.manager.set_sample(self._sample, self._notes)
+ if event is not None:
+ event.Skip()
+
+if __name__ == "__main__":
+ app = wx.App()
+ from sas.sascalc.dataloader.data_info import Sample
+ sample = Sample()
+ dlg = SampleDialog(sample=sample)
+ dlg.ShowModal()
+ app.MainLoop()
diff --git a/src/sas/sasgui/perspectives/calculator/sld_panel.py b/src/sas/sasgui/perspectives/calculator/sld_panel.py
index a82811e..4a901eb 100644
--- a/src/sas/sasgui/perspectives/calculator/sld_panel.py
+++ b/src/sas/sasgui/perspectives/calculator/sld_panel.py
@@ -1,526 +1,572 @@
-"""
-This module provide GUI for the neutron scattering length density calculator
-
-"""
-
-import wx
-import math
-import sys
-
-from sas.sasgui.guiframe.panel_base import PanelBase
-
-from sas.sasgui.guiframe.utils import format_number
-from sas.sasgui.guiframe.utils import check_float
-from sas.sasgui.guiframe.events import StatusEvent
-
-# the calculator default value for wavelength is 6
-#import periodictable
-from periodictable import formula
-from periodictable.xsf import xray_energy
-from periodictable.xsf import xray_sld_from_atoms
-from periodictable.nsf import neutron_scattering
-from sas.sasgui.perspectives.calculator import calculator_widgets as widget
-from sas.sasgui.guiframe.documentation_window import DocumentationWindow
-
-WAVELENGTH = 6.0
-_BOX_WIDTH = 76
-_STATICBOX_WIDTH = 350
-_SCALE = 1e-6
-
-#SLD panel size
-if sys.platform.count("win32") > 0:
- PANEL_TOP = 0
- _STATICBOX_WIDTH = 350
- PANEL_SIZE = 400
- FONT_VARIANT = 0
-else:
- PANEL_TOP = 60
- _STATICBOX_WIDTH = 380
- PANEL_SIZE = 410
- FONT_VARIANT = 1
-
-class SldPanel(wx.Panel, PanelBase):
- """
- Provides the SLD calculator GUI.
- """
- ## Internal nickname for the window, used by the AUI manager
- window_name = "SLD Calculator"
- ## Name to appear on the window title bar
- window_caption = "SLD Calculator"
- ## Flag to tell the AUI manager to put this panel in the center pane
- CENTER_PANE = True
-
- def __init__(self, parent, base=None, *args, **kwds):
- """
- """
- wx.Panel.__init__(self, parent, *args, **kwds)
- PanelBase.__init__(self)
- #Font size
- self.SetWindowVariant(variant=FONT_VARIANT)
- # Object that receive status event
- self.base = base
- self.wavelength = WAVELENGTH
- self.parent = parent
- #layout attribute
- self.compound_ctl = None
- self.density_ctl = None
- self.compound = ""
- self.density = ""
- self.wavelength_ctl = None
- self.neutron_sld_real_ctl = None
- self.neutron_sld_im_ctl = None
- self.mo_ka_sld_real_ctl = None
- self.mo_ka_sld_im_ctl = None
- self.cu_ka_sld_real_ctl = None
- self.cu_ka_sld_im_ctl = None
- self.neutron_abs_ctl = None
- self.neutron_inc_ctl = None
- self.neutron_length_ctl = None
- self.button_calculate = None
- #Draw the panel
- self._do_layout()
- self.SetAutoLayout(True)
- self.Layout()
-
- def _do_layout(self):
- """
- Draw window content
- """
- unit_a = '[A]'
- unit_density = '[g/cm^(3)]'
- unit_sld = '[1/A^(2)]'
- unit_cm1 = '[1/cm]'
- unit_cm = '[cm]'
- sizer_input = wx.GridBagSizer(5, 5)
- sizer_output = wx.GridBagSizer(5, 5)
- sizer_button = wx.BoxSizer(wx.HORIZONTAL)
- sizer1 = wx.BoxSizer(wx.HORIZONTAL)
- sizer2 = wx.BoxSizer(wx.HORIZONTAL)
- sizer3 = wx.BoxSizer(wx.HORIZONTAL)
- #---------inputs----------------
- inputbox = wx.StaticBox(self, -1, "Input")
- boxsizer1 = wx.StaticBoxSizer(inputbox, wx.VERTICAL)
- boxsizer1.SetMinSize((_STATICBOX_WIDTH, -1))
-
- compound_txt = wx.StaticText(self, -1, 'Compound ')
- self.compound_ctl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH * 2, -1))
- density_txt = wx.StaticText(self, -1, 'Density ')
- self.density_ctl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, -1))
- unit_density_txt = wx.StaticText(self, -1, unit_density)
- wavelength_txt = wx.StaticText(self, -1, 'Wavelength ')
- self.wavelength_ctl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, -1))
- self.wavelength_ctl.SetValue(str(self.wavelength))
- unit_a_txt = wx.StaticText(self, -1, unit_a)
- iy = 0
- ix = 0
- sizer_input.Add(compound_txt, (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- ix += 1
- sizer_input.Add(self.compound_ctl, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- iy += 1
- ix = 0
- sizer_input.Add(density_txt, (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- ix += 1
- sizer_input.Add(self.density_ctl, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 1
- sizer_input.Add(unit_density_txt, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- iy += 1
- ix = 0
- sizer_input.Add(wavelength_txt, (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- ix += 1
- sizer_input.Add(self.wavelength_ctl, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 1
- sizer_input.Add(unit_a_txt, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- boxsizer1.Add(sizer_input)
- sizer1.Add(boxsizer1, 0, wx.EXPAND | wx.ALL, 10)
- #---------Outputs sizer--------
- outputbox = wx.StaticBox(self, -1, "Output")
- boxsizer2 = wx.StaticBoxSizer(outputbox, wx.VERTICAL)
- boxsizer2.SetMinSize((_STATICBOX_WIDTH, -1))
-
- i_complex = '- i'
- neutron_sld_txt = wx.StaticText(self, -1, 'Neutron SLD')
- self.neutron_sld_real_ctl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, -1))
- self.neutron_sld_real_ctl.SetEditable(False)
- self.neutron_sld_real_ctl.SetToolTipString("Neutron SLD real.")
- self.neutron_sld_im_ctl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, -1))
- self.neutron_sld_im_ctl.SetEditable(False)
- self.neutron_sld_im_ctl.SetToolTipString("Neutron SLD imaginary.")
- neutron_sld_units_txt = wx.StaticText(self, -1, unit_sld)
-
- cu_ka_sld_txt = wx.StaticText(self, -1, 'Cu Ka SLD')
- self.cu_ka_sld_real_ctl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, -1))
- self.cu_ka_sld_real_ctl.SetEditable(False)
- self.cu_ka_sld_real_ctl.SetToolTipString("Cu Ka SLD real.")
- self.cu_ka_sld_im_ctl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, -1))
- self.cu_ka_sld_im_ctl.SetEditable(False)
- self.cu_ka_sld_im_ctl.SetToolTipString("Cu Ka SLD imaginary.")
- cu_ka_sld_units_txt = wx.StaticText(self, -1, unit_sld)
-
- mo_ka_sld_txt = wx.StaticText(self, -1, 'Mo Ka SLD')
- self.mo_ka_sld_real_ctl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, -1))
- self.mo_ka_sld_real_ctl.SetEditable(False)
- self.mo_ka_sld_real_ctl.SetToolTipString("Mo Ka SLD real.")
- self.mo_ka_sld_im_ctl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, -1))
- self.mo_ka_sld_im_ctl.SetEditable(False)
- self.mo_ka_sld_im_ctl.SetToolTipString("Mo Ka SLD imaginary.")
- mo_ka_sld_units_txt = wx.StaticText(self, -1, unit_sld)
-
- neutron_inc_txt = wx.StaticText(self, -1, 'Neutron Inc. Xs')
- self.neutron_inc_ctl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, -1))
- self.neutron_inc_ctl.SetEditable(False)
- self.neutron_inc_ctl.SetToolTipString("Neutron Inc. Xs")
- neutron_inc_units_txt = wx.StaticText(self, -1, unit_cm1)
-
- neutron_abs_txt = wx.StaticText(self, -1, 'Neutron Abs. Xs')
- self.neutron_abs_ctl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, -1))
- self.neutron_abs_ctl.SetEditable(False)
- self.neutron_abs_ctl.SetToolTipString("Neutron Abs. Xs")
- neutron_abs_units_txt = wx.StaticText(self, -1, unit_cm1)
-
- neutron_length_txt = wx.StaticText(self, -1, 'Neutron 1/e length')
- self.neutron_length_ctl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, -1))
- self.neutron_length_ctl.SetEditable(False)
- self.neutron_length_ctl.SetToolTipString("Neutron 1/e length")
- neutron_length_units_txt = wx.StaticText(self, -1, unit_cm)
-
- iy = 0
- ix = 0
- sizer_output.Add(neutron_sld_txt, (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- ix += 1
- sizer_output.Add(self.neutron_sld_real_ctl, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 1
- sizer_output.Add(wx.StaticText(self, -1, i_complex),
- (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 1
- sizer_output.Add(self.neutron_sld_im_ctl,
- (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 1
- sizer_output.Add(neutron_sld_units_txt,
- (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- iy += 1
- ix = 0
- sizer_output.Add(cu_ka_sld_txt, (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- ix += 1
- sizer_output.Add(self.cu_ka_sld_real_ctl, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 1
- sizer_output.Add(wx.StaticText(self, -1, i_complex),
- (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 1
- sizer_output.Add(self.cu_ka_sld_im_ctl,
- (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 1
- sizer_output.Add(cu_ka_sld_units_txt,
- (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- iy += 1
- ix = 0
- sizer_output.Add(mo_ka_sld_txt, (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- ix += 1
- sizer_output.Add(self.mo_ka_sld_real_ctl, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 1
- sizer_output.Add(wx.StaticText(self, -1, i_complex),
- (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 1
- sizer_output.Add(self.mo_ka_sld_im_ctl,
- (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 1
- sizer_output.Add(mo_ka_sld_units_txt,
- (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- iy += 1
- ix = 0
- sizer_output.Add(neutron_inc_txt, (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- ix += 1
- sizer_output.Add(self.neutron_inc_ctl, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 2
- sizer_output.Add(neutron_inc_units_txt, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- iy += 1
- ix = 0
- sizer_output.Add(neutron_abs_txt, (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- ix += 1
- sizer_output.Add(self.neutron_abs_ctl, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 2
- sizer_output.Add(neutron_abs_units_txt, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- iy += 1
- ix = 0
- sizer_output.Add(neutron_length_txt, (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- ix += 1
- sizer_output.Add(self.neutron_length_ctl, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 2
- sizer_output.Add(neutron_length_units_txt, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- boxsizer2.Add(sizer_output)
- sizer2.Add(boxsizer2, 0, wx.EXPAND | wx.ALL, 10)
- #-----Button sizer------------
-
- id = wx.NewId()
- self.button_calculate = wx.Button(self, id, "Calculate")
- self.button_calculate.SetToolTipString("Calculate SLD.")
- self.Bind(wx.EVT_BUTTON, self.calculateSld, id=id)
-
- id = wx.NewId()
- self.button_help = wx.Button(self, id, "HELP")
- self.button_help.SetToolTipString("help on SLD calculator.")
- self.Bind(wx.EVT_BUTTON, self.on_help, id=id)
-
- self.button_close = wx.Button(self, wx.ID_CANCEL, 'Close')
- self.button_close.Bind(wx.EVT_BUTTON, self.on_close)
- self.button_close.SetToolTipString("Close this window.")
-
- sizer_button.Add((150, 20), 1, wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- sizer_button.Add(self.button_calculate, 0, wx.RIGHT | wx.ADJUST_MINSIZE, 20)
- sizer_button.Add(self.button_help, 0, wx.RIGHT | wx.ADJUST_MINSIZE, 20)
- sizer_button.Add(self.button_close, 0, wx.RIGHT | wx.ADJUST_MINSIZE, 20)
- sizer3.Add(sizer_button)
- #---------layout----------------
- vbox = wx.BoxSizer(wx.VERTICAL)
- vbox.Add(sizer1)
- vbox.Add(sizer2)
- vbox.Add(sizer3)
- vbox.Fit(self)
- self.SetSizer(vbox)
-
- def on_help(self, event):
- """
- Bring up the SLD Documentation whenever
- the HELP button is clicked.
-
- Calls DocumentationWindow with the path of the location within the
- documentation tree (after /doc/ ....". Note that when using old
- versions of Wx (before 2.9) and thus not the release version of
- installers, the help comes up at the top level of the file as
- webbrowser does not pass anything past the # to the browser when it is
- running "file:///...."
-
- :param evt: Triggers on clicking the help button
- """
-
- _TreeLocation = "user/sasgui/perspectives/calculator/"
- _TreeLocation += "sld_calculator_help.html"
- _doc_viewer = DocumentationWindow(self, -1, _TreeLocation, "",
- "General Scattering Calculator Help")
-
- def on_close(self, event):
- """
- close the window containing this panel
- """
- self.parent.Close()
-
- def calculate_xray_sld(self, element):
- """
- Get an element and compute the corresponding SLD for a given formula
-
- :param element: elements a string of existing atom
-
- """
- myformula = formula(str(element))
- if len(myformula.atoms) != 1:
- return
- element = myformula.atoms.keys()[0]
- energy = xray_energy(element.K_alpha)
-
- self.sld_formula = formula(str(self.compound), density=self.density)
- atom = self.sld_formula.atoms
- return xray_sld_from_atoms(atom, density=self.density, energy=energy)
-
- def check_inputs(self):
- """Check validity user inputs"""
- flag = True
- msg = ""
- if check_float(self.density_ctl):
- self.density = float(self.density_ctl.GetValue())
- else:
- flag = False
- msg += "Error for Density value :expect float"
-
- self.wavelength = self.wavelength_ctl.GetValue()
- if str(self.wavelength).lstrip().rstrip() == "":
- self.wavelength = WAVELENGTH
- self.wavelength_ctl.SetValue(str(WAVELENGTH))
- self.wavelength_ctl.SetBackgroundColour(wx.WHITE)
- self.wavelength_ctl.Refresh()
- msg += "Default value for wavelength is 6.0"
- else:
- if check_float(self.wavelength_ctl):
- self.wavelength = float(self.wavelength)
- else:
- flag = False
- msg += "Error for wavelength value :expect float"
-
- self.compound = self.compound_ctl.GetValue().lstrip().rstrip()
- if self.compound != "":
- try :
- formula(self.compound)
- self.compound_ctl.SetBackgroundColour(wx.WHITE)
- self.compound_ctl.Refresh()
- except:
- self.compound_ctl.SetBackgroundColour("pink")
- self.compound_ctl.Refresh()
- flag = False
- msg += "Enter correct formula"
- else:
- self.compound_ctl.SetBackgroundColour("pink")
- self.compound_ctl.Refresh()
- flag = False
- msg += "Enter a formula"
- return flag, msg
-
- def calculate_sld_helper(self, element, density, molecule_formula):
- """
- Get an element and compute the corresponding SLD for a given formula
-
- :param element: elements a string of existing atom
-
- """
- element_formula = formula(str(element))
- if len(element_formula.atoms) != 1:
- return
- element = element_formula.atoms.keys()[0]
- energy = xray_energy(element.K_alpha)
- atom = molecule_formula.atoms
- return xray_sld_from_atoms(atom, density=density, energy=energy)
-
-
- def calculateSld(self, event):
- """
- Calculate the neutron scattering density length of a molecule
- """
- self.clear_outputs()
- try:
- #Check validity user inputs
- flag, msg = self.check_inputs()
- if self.base is not None and msg.lstrip().rstrip() != "":
- msg = "SLD Calculator: %s" % str(msg)
- wx.PostEvent(self.base, StatusEvent(status=msg))
- if not flag:
- return
- #get ready to compute
- self.sld_formula = formula(self.compound,
- density=self.density)
- (sld_real, sld_im, _), (_, absorp, incoh), \
- length = neutron_scattering(compound=self.compound,
- density=self.density,
- wavelength=self.wavelength)
- cu_real, cu_im = self.calculate_sld_helper(element="Cu",
- density=self.density,
- molecule_formula=self.sld_formula)
- mo_real, mo_im = self.calculate_sld_helper(element="Mo",
- density=self.density,
- molecule_formula=self.sld_formula)
- # set neutron sld values
- val = format_number(sld_real * _SCALE)
- self.neutron_sld_real_ctl.SetValue(val)
- val = format_number(math.fabs(sld_im) * _SCALE)
- self.neutron_sld_im_ctl.SetValue(val)
- # Compute the Cu SLD
- self.cu_ka_sld_real_ctl.SetValue(format_number(cu_real * _SCALE))
- val = format_number(math.fabs(cu_im) * _SCALE)
- self.cu_ka_sld_im_ctl.SetValue(val)
- # Compute the Mo SLD
- self.mo_ka_sld_real_ctl.SetValue(format_number(mo_real * _SCALE))
- val = format_number(math.fabs(mo_im) * _SCALE)
- self.mo_ka_sld_im_ctl.SetValue(val)
- # set incoherence and absorption
- self.neutron_inc_ctl.SetValue(format_number(incoh))
- self.neutron_abs_ctl.SetValue(format_number(absorp))
- # Neutron length
- self.neutron_length_ctl.SetValue(format_number(length))
- # display wavelength
- self.wavelength_ctl.SetValue(str(self.wavelength))
- except:
- if self.base is not None:
- msg = "SLD Calculator: %s" % (sys.exc_value)
- wx.PostEvent(self.base, StatusEvent(status=msg))
- if event is not None:
- event.Skip()
-
- def clear_outputs(self):
- """
- Clear the outputs textctrl
- """
- self.neutron_sld_real_ctl.SetValue("")
- self.neutron_sld_im_ctl.SetValue("")
- self.mo_ka_sld_real_ctl.SetValue("")
- self.mo_ka_sld_im_ctl.SetValue("")
- self.cu_ka_sld_real_ctl.SetValue("")
- self.cu_ka_sld_im_ctl.SetValue("")
- self.neutron_abs_ctl.SetValue("")
- self.neutron_inc_ctl.SetValue("")
- self.neutron_length_ctl.SetValue("")
-
-
-class SldWindow(widget.CHILD_FRAME):
- """
- """
- def __init__(self, parent=None, title="SLD Calculator",
- base=None, manager=None,
- size=(PANEL_SIZE, PANEL_SIZE), *args, **kwds):
- """
- """
- kwds['title'] = title
- kwds['size'] = size
- widget.CHILD_FRAME.__init__(self, parent, *args, **kwds)
- """
- """
- self.parent = parent
- self.base = base
- self.manager = manager
- self.panel = SldPanel(self, base=base)
- self.Bind(wx.EVT_CLOSE, self.on_close)
- self.SetPosition((wx.LEFT, PANEL_TOP))
- self.Show(True)
-
- def on_close(self, event):
- """
- On close event
- """
- if self.manager != None:
- self.manager.sld_frame = None
- self.Destroy()
-
-
-class ViewApp(wx.App):
- """
- """
- def OnInit(self):
- """
- """
- widget.CHILD_FRAME = wx.Frame
- frame = SldWindow(None, title='SLD Calculator')
- frame.Show(True)
- self.SetTopWindow(frame)
- return True
-
-
-if __name__ == "__main__":
- app = ViewApp(0)
- app.MainLoop()
+"""
+This module provide GUI for the neutron scattering length density calculator
+
+"""
+
+import wx
+import math
+import sys
+
+from sas.sasgui.guiframe.panel_base import PanelBase
+
+from sas.sasgui.guiframe.utils import format_number
+from sas.sasgui.guiframe.utils import check_float
+from sas.sasgui.guiframe.events import StatusEvent
+
+# the calculator default value for wavelength is 6
+#import periodictable
+from periodictable import formula
+from periodictable.xsf import xray_energy
+from periodictable.xsf import xray_sld_from_atoms
+from periodictable.nsf import neutron_scattering
+from sas.sasgui.perspectives.calculator import calculator_widgets as widget
+from sas.sasgui.guiframe.documentation_window import DocumentationWindow
+
+WAVELENGTH = 6.0
+_BOX_WIDTH = 76
+_STATICBOX_WIDTH = 350
+_SCALE = 1e-6
+
+#SLD panel size
+if sys.platform.count("win32") > 0:
+ PANEL_TOP = 0
+ _STATICBOX_WIDTH = 350
+ PANEL_SIZE = 400
+ FONT_VARIANT = 0
+else:
+ PANEL_TOP = 60
+ _STATICBOX_WIDTH = 380
+ PANEL_SIZE = 410
+ FONT_VARIANT = 1
+
+class SldPanel(wx.Panel, PanelBase):
+ """
+ Provides the SLD calculator GUI.
+ """
+ ## Internal nickname for the window, used by the AUI manager
+ window_name = "SLD Calculator"
+ ## Name to appear on the window title bar
+ window_caption = "SLD Calculator"
+ ## Flag to tell the AUI manager to put this panel in the center pane
+ CENTER_PANE = True
+
+ def __init__(self, parent, base=None, *args, **kwds):
+ """
+ """
+ wx.Panel.__init__(self, parent, *args, **kwds)
+ PanelBase.__init__(self)
+ #Font size
+ self.SetWindowVariant(variant=FONT_VARIANT)
+ # Object that receive status event
+ self.base = base
+ self.neutron_wavelength = WAVELENGTH
+ self.xray_source_input = WAVELENGTH
+ self.parent = parent
+ #layout attribute
+ self.compound_ctl = None
+ self.density_ctl = None
+ self.compound = ""
+ self.density = ""
+ self.neutron_wavelength_ctl = None
+ self.xray_source_input_ctl = None
+ self.xray_cbox = None
+ self.neutron_sld_real_ctl = None
+ self.neutron_sld_im_ctl = None
+ self.xray_sld_real_ctl = None
+ self.xray_sld_im_ctl = None
+ self.neutron_abs_ctl = None
+ self.neutron_inc_ctl = None
+ self.neutron_length_ctl = None
+ self.button_calculate = None
+ self.xray_source = None
+ #Draw the panel
+ self._do_layout()
+ self.SetAutoLayout(True)
+ self.Layout()
+ self.fill_xray_cbox()
+
+ def _do_layout(self):
+ """
+ Draw window content
+ """
+ unit_a = '[A]'
+ unit_density = '[g/cm^(3)]'
+ unit_sld = '[1/A^(2)]'
+ unit_cm1 = '[1/cm]'
+ unit_cm = '[cm]'
+ sizer_input = wx.GridBagSizer(5, 5)
+ sizer_output = wx.GridBagSizer(5, 5)
+ sizer_button = wx.BoxSizer(wx.HORIZONTAL)
+ sizer1 = wx.BoxSizer(wx.HORIZONTAL)
+ sizer2 = wx.BoxSizer(wx.HORIZONTAL)
+ sizer3 = wx.BoxSizer(wx.HORIZONTAL)
+ #---------inputs----------------
+ inputbox = wx.StaticBox(self, -1, "Input")
+ boxsizer1 = wx.StaticBoxSizer(inputbox, wx.VERTICAL)
+ boxsizer1.SetMinSize((_STATICBOX_WIDTH, -1))
+
+ compound_txt = wx.StaticText(self, -1, 'Compound ')
+ self.compound_ctl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH * 2, -1))
+ density_txt = wx.StaticText(self, -1, 'Density ')
+ self.density_ctl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, -1))
+ unit_density_txt = wx.StaticText(self, -1, unit_density)
+ neutron_wavelength_txt = wx.StaticText(self, -1, 'Neutron wavelength')
+ self.neutron_wavelength_ctl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, -1))
+ self.neutron_wavelength_ctl.SetValue(str(self.neutron_wavelength))
+ self.xray_source_input_txt = wx.StaticText(self, -1, 'X-ray wavelength')
+ self.xray_source_input_ctl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, -1))
+ self.xray_source_input_ctl.SetValue(str(self.xray_source_input))
+ neutron_unit_a_txt = wx.StaticText(self, -1, unit_a)
+
+ self.xray_cbox = wx.ComboBox(self, -1, size=(70, 20), style=wx.CB_READONLY)
+ xray_cbox_tip = "Select an element, wavelength or energy"
+ self.xray_cbox.SetToolTipString(xray_cbox_tip)
+ wx.EVT_COMBOBOX(self.xray_cbox, -1, self.on_select_xray)
+
+ iy = 0
+ ix = 0
+ sizer_input.Add(compound_txt, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ ix += 1
+ sizer_input.Add(self.compound_ctl, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ iy += 1
+ ix = 0
+ sizer_input.Add(density_txt, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ ix += 1
+ sizer_input.Add(self.density_ctl, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix += 1
+ sizer_input.Add(unit_density_txt, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ iy += 1
+ ix = 0
+ sizer_input.Add(neutron_wavelength_txt, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ ix += 1
+ sizer_input.Add(self.neutron_wavelength_ctl, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix += 1
+ sizer_input.Add(neutron_unit_a_txt, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ iy += 1
+ ix = 0
+ sizer_input.Add(self.xray_source_input_txt, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ ix += 1
+ sizer_input.Add(self.xray_source_input_ctl, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix += 1
+ sizer_input.Add(self.xray_cbox, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ boxsizer1.Add(sizer_input)
+ sizer1.Add(boxsizer1, 0, wx.EXPAND | wx.ALL, 10)
+ #---------Outputs sizer--------
+ outputbox = wx.StaticBox(self, -1, "Output")
+ boxsizer2 = wx.StaticBoxSizer(outputbox, wx.VERTICAL)
+ boxsizer2.SetMinSize((_STATICBOX_WIDTH, -1))
+
+ i_complex = '- i'
+ neutron_sld_txt = wx.StaticText(self, -1, 'Neutron SLD')
+ self.neutron_sld_real_ctl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, -1))
+ self.neutron_sld_real_ctl.SetEditable(False)
+ self.neutron_sld_real_ctl.SetToolTipString("Neutron SLD real")
+ self.neutron_sld_im_ctl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, -1))
+ self.neutron_sld_im_ctl.SetEditable(False)
+ self.neutron_sld_im_ctl.SetToolTipString("Neutron SLD imaginary")
+ neutron_sld_units_txt = wx.StaticText(self, -1, unit_sld)
+
+ xray_sld_txt = wx.StaticText(self, -1, 'X-ray SLD')
+ self.xray_sld_real_ctl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, -1))
+ self.xray_sld_real_ctl.SetEditable(False)
+ self.xray_sld_real_ctl.SetToolTipString("X-ray SLD real")
+ self.xray_sld_im_ctl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, -1))
+ self.xray_sld_im_ctl.SetEditable(False)
+ self.xray_sld_im_ctl.SetToolTipString("X-ray SLD imaginary")
+ xray_sld_units_txt = wx.StaticText(self, -1, unit_sld)
+
+ neutron_inc_txt = wx.StaticText(self, -1, 'Neutron Inc. Xs')
+ self.neutron_inc_ctl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, -1))
+ self.neutron_inc_ctl.SetEditable(False)
+ self.neutron_inc_ctl.SetToolTipString("Neutron Inc. Xs")
+ neutron_inc_units_txt = wx.StaticText(self, -1, unit_cm1)
+
+ neutron_abs_txt = wx.StaticText(self, -1, 'Neutron Abs. Xs')
+ self.neutron_abs_ctl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, -1))
+ self.neutron_abs_ctl.SetEditable(False)
+ self.neutron_abs_ctl.SetToolTipString("Neutron Abs. Xs")
+ neutron_abs_units_txt = wx.StaticText(self, -1, unit_cm1)
+
+ neutron_length_txt = wx.StaticText(self, -1, 'Neutron 1/e length')
+ self.neutron_length_ctl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, -1))
+ self.neutron_length_ctl.SetEditable(False)
+ self.neutron_length_ctl.SetToolTipString("Neutron 1/e length")
+ neutron_length_units_txt = wx.StaticText(self, -1, unit_cm)
+
+ iy = 0
+ ix = 0
+ sizer_output.Add(neutron_sld_txt, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ ix += 1
+ sizer_output.Add(self.neutron_sld_real_ctl, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix += 1
+ sizer_output.Add(wx.StaticText(self, -1, i_complex),
+ (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix += 1
+ sizer_output.Add(self.neutron_sld_im_ctl,
+ (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix += 1
+ sizer_output.Add(neutron_sld_units_txt,
+ (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ iy += 1
+ ix = 0
+ sizer_output.Add(xray_sld_txt, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ ix += 1
+ sizer_output.Add(self.xray_sld_real_ctl, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix += 1
+ sizer_output.Add(wx.StaticText(self, -1, i_complex),
+ (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix += 1
+ sizer_output.Add(self.xray_sld_im_ctl,
+ (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix += 1
+ sizer_output.Add(xray_sld_units_txt,
+ (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ iy += 1
+ ix = 0
+ sizer_output.Add(neutron_inc_txt, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ ix += 1
+ sizer_output.Add(self.neutron_inc_ctl, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix += 2
+ sizer_output.Add(neutron_inc_units_txt, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ iy += 1
+ ix = 0
+ sizer_output.Add(neutron_abs_txt, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ ix += 1
+ sizer_output.Add(self.neutron_abs_ctl, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix += 2
+ sizer_output.Add(neutron_abs_units_txt, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ iy += 1
+ ix = 0
+ sizer_output.Add(neutron_length_txt, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ ix += 1
+ sizer_output.Add(self.neutron_length_ctl, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix += 2
+ sizer_output.Add(neutron_length_units_txt, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ boxsizer2.Add(sizer_output)
+ sizer2.Add(boxsizer2, 0, wx.EXPAND | wx.ALL, 10)
+ #-----Button sizer------------
+
+ id = wx.NewId()
+ self.button_calculate = wx.Button(self, id, "Calculate")
+ self.button_calculate.SetToolTipString("Calculate SLD.")
+ self.Bind(wx.EVT_BUTTON, self.calculateSld, id=id)
+
+ id = wx.NewId()
+ self.button_help = wx.Button(self, id, "HELP")
+ self.button_help.SetToolTipString("help on SLD calculator.")
+ self.Bind(wx.EVT_BUTTON, self.on_help, id=id)
+
+ self.button_close = wx.Button(self, wx.ID_CANCEL, 'Close')
+ self.button_close.Bind(wx.EVT_BUTTON, self.on_close)
+ self.button_close.SetToolTipString("Close this window.")
+
+ sizer_button.Add((150, 20), 1, wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ sizer_button.Add(self.button_calculate, 0, wx.RIGHT | wx.ADJUST_MINSIZE, 20)
+ sizer_button.Add(self.button_help, 0, wx.RIGHT | wx.ADJUST_MINSIZE, 20)
+ sizer_button.Add(self.button_close, 0, wx.RIGHT | wx.ADJUST_MINSIZE, 20)
+ sizer3.Add(sizer_button)
+ #---------layout----------------
+ vbox = wx.BoxSizer(wx.VERTICAL)
+ vbox.Add(sizer1)
+ vbox.Add(sizer2)
+ vbox.Add(sizer3)
+ vbox.Fit(self)
+ self.SetSizer(vbox)
+
+ def fill_xray_cbox(self):
+ """
+ fill the x-ray combobox with the sources
+ """
+ source_list = ['[A]', '[keV]', 'Element']
+ for source in source_list:
+ pos = self.xray_cbox.Append(str(source))
+ self.xray_cbox.SetClientData(pos, str(source.strip()))
+ self.xray_cbox.SetSelection(0)
+ self.xray_source = source_list[0]
+
+ def on_select_xray(self, event=None):
+ """
+ On Selecting a source
+ """
+ item = event.GetEventObject()
+ self.xray_source = item.GetValue().strip()
+
+ if self.xray_source == "[A]":
+ self.xray_source_input_txt.SetLabel("X-ray wavelength")
+ elif self.xray_source == "[keV]":
+ self.xray_source_input_txt.SetLabel("X-ray energy")
+ elif self.xray_source == "Element":
+ self.xray_source_input_txt.SetLabel("X-ray source")
+
+ def on_help(self, event):
+ """
+ Bring up the SLD Documentation whenever
+ the HELP button is clicked.
+
+ Calls DocumentationWindow with the path of the location within the
+ documentation tree (after /doc/ ....". Note that when using old
+ versions of Wx (before 2.9) and thus not the release version of
+ installers, the help comes up at the top level of the file as
+ webbrowser does not pass anything past the # to the browser when it is
+ running "file:///...."
+
+ :param evt: Triggers on clicking the help button
+ """
+
+ _TreeLocation = "user/sasgui/perspectives/calculator/"
+ _TreeLocation += "sld_calculator_help.html"
+ _doc_viewer = DocumentationWindow(self, -1, _TreeLocation, "",
+ "General Scattering Calculator Help")
+
+ def on_close(self, event):
+ """
+ close the window containing this panel
+ """
+ self.parent.Close()
+
+ def calculate_xray_sld(self, element):
+ """
+ Get an element and compute the corresponding SLD for a given formula
+
+ :param element: elements a string of existing atom
+
+ """
+ myformula = formula(str(element))
+ if len(myformula.atoms) != 1:
+ return
+ element = myformula.atoms.keys()[0]
+ energy = xray_energy(element.K_alpha)
+
+ self.sld_formula = formula(str(self.compound), density=self.density)
+ atom = self.sld_formula.atoms
+ return xray_sld_from_atoms(atom, density=self.density, energy=energy)
+
+ def check_inputs(self):
+ """Check validity user inputs"""
+ flag = True
+ msg = ""
+ if check_float(self.density_ctl):
+ self.density = float(self.density_ctl.GetValue())
+ else:
+ flag = False
+ msg += "Error for Density value :expect float"
+
+ self.neutron_wavelength = self.neutron_wavelength_ctl.GetValue()
+ self.xray_source_input = self.xray_source_input_ctl.GetValue()
+
+ if str(self.neutron_wavelength).lstrip().rstrip() == "":
+ self.neutron_wavelength = WAVELENGTH
+ self.neutron_wavelength_ctl.SetValue(str(WAVELENGTH))
+ self.neutron_wavelength_ctl.SetBackgroundColour(wx.WHITE)
+ self.neutron_wavelength_ctl.Refresh()
+ msg += "Default value for wavelength is 6.0"
+ else:
+ if check_float(self.neutron_wavelength_ctl):
+ self.neutron_wavelength = float(self.neutron_wavelength)
+ else:
+ flag = False
+ msg += "Error for wavelength value :expect float"
+
+ if str(self.xray_source_input).lstrip().rstrip() == "":
+ self.xray_source_input = WAVELENGTH
+ self.xray_source_input_ctl.SetValue(str(WAVELENGTH))
+ self.xray_source_input_ctl.SetBackgroundColour(wx.WHITE)
+ self.xray_source_input_ctl.Refresh()
+ msg += "Default value for wavelength is 6.0"
+ else:
+ if (self.xray_source == '[A]') or (self.xray_source == '[keV]'):
+ if check_float(self.xray_source_input_ctl):
+ self.xray_source_input = float(self.xray_source_input)
+ else:
+ flag = False
+ msg += "Error for wavelength value :expect float"
+ elif (self.xray_source == 'Element'):
+ try:
+ import periodictable
+ exec("periodictable." + self.xray_source_input)
+ except AttributeError:
+ flag = False
+ msg += "X-ray element supplied isn't in the database"
+
+
+
+ self.compound = self.compound_ctl.GetValue().lstrip().rstrip()
+ if self.compound != "":
+ try :
+ formula(self.compound)
+ self.compound_ctl.SetBackgroundColour(wx.WHITE)
+ self.compound_ctl.Refresh()
+ except:
+ self.compound_ctl.SetBackgroundColour("pink")
+ self.compound_ctl.Refresh()
+ flag = False
+ msg += "Enter correct formula"
+ else:
+ self.compound_ctl.SetBackgroundColour("pink")
+ self.compound_ctl.Refresh()
+ flag = False
+ msg += "Enter a formula"
+ return flag, msg
+
+ def calculate_sld_helper(self, element, density, molecule_formula):
+ """
+ Get an element and compute the corresponding SLD for a given formula
+
+ :param element: elements a string of existing atom
+
+ """
+ element_formula = formula(str(element))
+ if len(element_formula.atoms) != 1:
+ return
+ element = element_formula.atoms.keys()[0]
+ energy = xray_energy(element.K_alpha)
+ atom = molecule_formula.atoms
+ return xray_sld_from_atoms(atom, density=density, energy=energy)
+
+ def calculateSld(self, event):
+ """
+ Calculate the neutron scattering density length of a molecule
+ """
+ self.clear_outputs()
+ try:
+ #Check validity user inputs
+ flag, msg = self.check_inputs()
+ if self.base is not None and msg.lstrip().rstrip() != "":
+ msg = "SLD Calculator: %s" % str(msg)
+ wx.PostEvent(self.base, StatusEvent(status=msg))
+ if not flag:
+ return
+ #get ready to compute
+ self.sld_formula = formula(self.compound,
+ density=self.density)
+ (sld_real, sld_im, _), (_, absorp, incoh), \
+ length = neutron_scattering(compound=self.compound,
+ density=self.density,
+ wavelength=self.neutron_wavelength)
+ if self.xray_source == "[A]":
+ energy = xray_energy(self.xray_source_input)
+ xray_real, xray_im = xray_sld_from_atoms(self.sld_formula.atoms,
+ density=self.density,
+ energy=energy)
+ elif self.xray_source == "[keV]":
+ xray_real, xray_im = xray_sld_from_atoms(self.sld_formula.atoms,
+ density=self.density,
+ energy=self.xray_source_input)
+ elif self.xray_source == "Element":
+ xray_real, xray_im = self.calculate_sld_helper(element=self.xray_source_input,
+ density=self.density,
+ molecule_formula=self.sld_formula)
+ # set neutron sld values
+ val = format_number(sld_real * _SCALE)
+ self.neutron_sld_real_ctl.SetValue(val)
+ val = format_number(math.fabs(sld_im) * _SCALE)
+ self.neutron_sld_im_ctl.SetValue(val)
+ # Compute the Cu SLD
+ self.xray_sld_real_ctl.SetValue(format_number(xray_real * _SCALE))
+ val = format_number(math.fabs(xray_im) * _SCALE)
+ self.xray_sld_im_ctl.SetValue(val)
+ # set incoherence and absorption
+ self.neutron_inc_ctl.SetValue(format_number(incoh))
+ self.neutron_abs_ctl.SetValue(format_number(absorp))
+ # Neutron length
+ self.neutron_length_ctl.SetValue(format_number(length))
+ # display wavelength
+ #self.wavelength_ctl.SetValue(str(self.wavelength))
+ #self.wavelength_ctl.SetValue(str(self.wavelength))
+ except:
+ if self.base is not None:
+ msg = "SLD Calculator: %s" % (sys.exc_value)
+ wx.PostEvent(self.base, StatusEvent(status=msg))
+ if event is not None:
+ event.Skip()
+
+ def clear_outputs(self):
+ """
+ Clear the outputs textctrl
+ """
+ self.neutron_sld_real_ctl.SetValue("")
+ self.neutron_sld_im_ctl.SetValue("")
+ self.xray_sld_real_ctl.SetValue("")
+ self.xray_sld_im_ctl.SetValue("")
+ self.neutron_abs_ctl.SetValue("")
+ self.neutron_inc_ctl.SetValue("")
+ self.neutron_length_ctl.SetValue("")
+
+
+class SldWindow(widget.CHILD_FRAME):
+ """
+ """
+ def __init__(self, parent=None, title="SLD Calculator",
+ base=None, manager=None,
+ size=(PANEL_SIZE, PANEL_SIZE), *args, **kwds):
+ """
+ """
+ kwds['title'] = title
+ kwds['size'] = size
+ widget.CHILD_FRAME.__init__(self, parent, *args, **kwds)
+ """
+ """
+ self.parent = parent
+ self.base = base
+ self.manager = manager
+ self.panel = SldPanel(self, base=base)
+ self.Bind(wx.EVT_CLOSE, self.on_close)
+ self.SetPosition((wx.LEFT, PANEL_TOP))
+ self.Show(True)
+
+ def on_close(self, event):
+ """
+ On close event
+ """
+ if self.manager is not None:
+ self.manager.sld_frame = None
+ self.Destroy()
+
+
+class ViewApp(wx.App):
+ """
+ """
+ def OnInit(self):
+ """
+ """
+ widget.CHILD_FRAME = wx.Frame
+ frame = SldWindow(None, title='SLD Calculator')
+ frame.Show(True)
+ self.SetTopWindow(frame)
+ return True
+
+
+if __name__ == "__main__":
+ app = ViewApp(0)
+ app.MainLoop()
diff --git a/src/sas/sasgui/perspectives/calculator/slit_length_calculator_panel.py b/src/sas/sasgui/perspectives/calculator/slit_length_calculator_panel.py
index 5e5ad82..36e50a1 100644
--- a/src/sas/sasgui/perspectives/calculator/slit_length_calculator_panel.py
+++ b/src/sas/sasgui/perspectives/calculator/slit_length_calculator_panel.py
@@ -156,7 +156,7 @@ class SlitLengthCalculatorPanel(wx.Panel, PanelBase):
def choose_data_file(self, location=None):
path = None
filename = ''
- if location == None:
+ if location is None:
location = os.getcwd()
wildcard = "SAXSess Data 1D (*.DAT, *.dat)|*.DAT"
@@ -302,7 +302,7 @@ class SlitLengthCalculatorWindow(widget.CHILD_FRAME):
"""
Close event
"""
- if self.manager != None:
+ if self.manager is not None:
self.manager.cal_slit_frame = None
self.Destroy()
diff --git a/src/sas/sasgui/perspectives/calculator/source_editor.py b/src/sas/sasgui/perspectives/calculator/source_editor.py
index 876aec7..2afdd39 100644
--- a/src/sas/sasgui/perspectives/calculator/source_editor.py
+++ b/src/sas/sasgui/perspectives/calculator/source_editor.py
@@ -1,540 +1,540 @@
-"""
-"""
-import wx
-import sys
-from copy import deepcopy
-from sas.sasgui.guiframe.utils import check_float
-
-_BOX_WIDTH = 60
-if sys.platform.count("win32") > 0:
- _STATICBOX_WIDTH = 450
- PANEL_WIDTH = 500
- PANEL_HEIGHT = 430
- FONT_VARIANT = 0
-else:
- _STATICBOX_WIDTH = 480
- PANEL_WIDTH = 550
- PANEL_HEIGHT = 430
- FONT_VARIANT = 1
-
-class SourceDialog(wx.Dialog):
- def __init__(self, parent=None, manager=None, source=None, *args, **kwds):
- kwds['title'] = "Source Editor"
- kwds['size'] = (PANEL_WIDTH, PANEL_HEIGHT)
- wx.Dialog.__init__(self, parent=parent, *args, **kwds)
-
- self.parent = parent
- self.manager = manager
- self._source = source
- self._reset_source = deepcopy(source)
- self._notes = ""
- self._description = "Edit source"
- self._do_layout()
- self.set_values()
-
- def _define_structure(self):
- """
- define initial sizer
- """
- self.main_sizer = wx.BoxSizer(wx.VERTICAL)
- self.box_source = wx.StaticBox(self, -1, str("source"))
- self.boxsizer_source = wx.StaticBoxSizer(self.box_source,
- wx.VERTICAL)
- self.name_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.radiation_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.beam_shape_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.wavelength_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.wavelength_min_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.wavelength_max_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.wavelength_spread_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.beam_size_name_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.beam_size_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.button_sizer = wx.BoxSizer(wx.HORIZONTAL)
-
- def _layout_name(self):
- """
- Do the layout for sample name related widgets
- """
- # Sample name [string]
- sample_name_txt = wx.StaticText(self, -1, 'Sample Name : ')
- self.sample_name_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH * 5, 20), style=0)
- self.name_sizer.AddMany([(sample_name_txt, 0, wx.LEFT | wx.RIGHT, 10),
- (self.sample_name_tcl, 0, wx.EXPAND)])
- def _layout_radiation(self):
- """
- Do the layout for radiation related widgets
- """
- #Radiation type [string]
- radiation_txt = wx.StaticText(self, -1, 'Radiation: ')
- self.radiation_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, 20), style=0)
- self.radiation_sizer.AddMany([(radiation_txt, 0, wx.LEFT | wx.RIGHT, 10),
- (self.radiation_tcl, 0, wx.LEFT, 20)])
-
- def _layout_beam_shape(self):
- """
- Do the layout for beam shape related widgets
- """
- #Beam shape [string]
- beam_shape_txt = wx.StaticText(self, -1, 'Beam shape:')
- self.beam_shape_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, 20), style=0)
- self.beam_shape_sizer.AddMany([(beam_shape_txt, 0,
- wx.LEFT | wx.RIGHT, 10),
- (self.beam_shape_tcl, 0, wx.LEFT, 10)])
-
- def _layout_wavelength(self):
- """
- Do the layout for wavelength related widgets
- """
- #Wavelength [float] [Angstrom]
- wavelength_txt = wx.StaticText(self, -1, 'wavelength:')
- self.wavelength_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, 20), style=0)
- wavelength_unit_txt = wx.StaticText(self, -1, 'Unit: ')
- self.wavelength_unit_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, 20), style=0)
- self.wavelength_sizer.AddMany([(wavelength_txt,
- 0, wx.LEFT | wx.RIGHT, 10),
- (self.wavelength_tcl, 0, wx.LEFT, 12),
- (wavelength_unit_txt, 0, wx.LEFT | wx.RIGHT, 10),
- (self.wavelength_unit_tcl, 0, wx.EXPAND)])
-
- def _layout_wavelength_min(self):
- """
- Do the layout for wavelength min related widgets
- """
- #Minimum wavelength [float] [Angstrom]
- wavelength_min_txt = wx.StaticText(self, -1, 'Wavelength min:')
- self.wavelength_min_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, 20), style=0)
- wavelength_min_unit_txt = wx.StaticText(self, -1, 'Unit: ')
- self.wavelength_min_unit_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, 20), style=0)
- self.wavelength_min_sizer.AddMany([(wavelength_min_txt,
- 0, wx.LEFT | wx.RIGHT, 10),
- (self.wavelength_min_tcl, 0, wx.LEFT, 10),
- (wavelength_min_unit_txt, 0, wx.LEFT | wx.RIGHT, 10),
- (self.wavelength_min_unit_tcl, 0, wx.EXPAND)])
-
- def _layout_wavelength_max(self):
- """
- Do the layout for wavelength max related widgets
- """
- #Maximum wavelength [float] [Angstrom]
- wavelength_max_txt = wx.StaticText(self, -1, 'Wavelength max:')
- self.wavelength_max_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, 20), style=0)
- wavelength_max_unit_txt = wx.StaticText(self, -1, 'Unit: ')
- self.wavelength_max_unit_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, 20), style=0)
- self.wavelength_max_sizer.AddMany([(wavelength_max_txt, 0,
- wx.LEFT | wx.RIGHT, 10),
- (self.wavelength_max_tcl, 0, wx.LEFT, 7),
- (wavelength_max_unit_txt, 0, wx.LEFT | wx.RIGHT, 10),
- (self.wavelength_max_unit_tcl, 0, wx.EXPAND)])
-
- def _layout_wavelength_spread(self):
- """
- Do the layout for wavelength spread related widgets
- """
- ## Wavelength spread [float] [Angstrom]
- wavelength_spread = None
- wavelength_spread_unit = 'percent'
- wavelength_spread_txt = wx.StaticText(self, -1, 'Wavelength spread:')
- self.wavelength_spread_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, 20), style=0)
- wavelength_spread_unit_txt = wx.StaticText(self, -1, 'Unit: ')
- self.wavelength_spread_unit_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, 20), style=0)
- self.wavelength_spread_sizer.AddMany([(wavelength_spread_txt,
- 0, wx.LEFT, 10),
- (self.wavelength_spread_tcl, 0, wx.LEFT, 5),
- (wavelength_spread_unit_txt, 0, wx.LEFT | wx.RIGHT, 10),
- (self.wavelength_spread_unit_tcl, 0, wx.EXPAND)])
- def _layout_beam_size_name(self):
- """
- Do the layout for beam size name related widgets
- """
- # Beam size name [string]
- beam_size_name_txt = wx.StaticText(self, -1, 'Beam size name : ')
- self.beam_size_name_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH * 5, 20), style=0)
- self.beam_size_name_sizer.AddMany([(beam_size_name_txt,
- 0, wx.LEFT | wx.RIGHT, 10),
- (self.beam_size_name_tcl, 0, wx.EXPAND)])
-
- def _layout_beam_size(self):
- """
- Do the layout for beam size related widgets
- """
- ## Beam size [Vector] [mm]
- beam_size = None
- beam_size_unit = 'mm'
-
- beam_size_txt = wx.StaticText(self, -1, 'Beam size:')
- x_beam_size_txt = wx.StaticText(self, -1, 'x = ')
- self.x_beam_size_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, 20), style=0)
- y_beam_size_txt = wx.StaticText(self, -1, 'y = ')
- self.y_beam_size_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, 20), style=0)
- z_beam_size_txt = wx.StaticText(self, -1, 'z = ')
- self.z_beam_size_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, 20), style=0)
- beam_size_unit_txt = wx.StaticText(self, -1, 'Unit: ')
- self.beam_size_unit_tcl = wx.TextCtrl(self, -1,
- size=(_BOX_WIDTH, 20), style=0)
- self.beam_size_sizer.AddMany([(beam_size_txt, 0, wx.LEFT | wx.RIGHT, 10),
- (x_beam_size_txt, 0, wx.LEFT, 17),
- (self.x_beam_size_tcl, 0, wx.RIGHT, 10),
- (y_beam_size_txt, 0, wx.EXPAND),
- (self.y_beam_size_tcl, 0, wx.RIGHT, 10),
- (z_beam_size_txt, 0, wx.EXPAND),
- (self.z_beam_size_tcl, 0, wx.RIGHT, 10),
- (beam_size_unit_txt, 0, wx.EXPAND),
- (self.beam_size_unit_tcl, 0, wx.RIGHT, 10)])
-
- def _layout_button(self):
- """
- Do the layout for the button widgets
- """
- self.bt_apply = wx.Button(self, -1, 'Apply')
- self.bt_apply.Bind(wx.EVT_BUTTON, self.on_click_apply)
- self.bt_apply.SetToolTipString("Apply current changes to the source.")
- self.bt_cancel = wx.Button(self, -1, 'Cancel')
- self.bt_cancel.SetToolTipString("Cancel current changes.")
- self.bt_cancel.Bind(wx.EVT_BUTTON, self.on_click_cancel)
- self.bt_close = wx.Button(self, wx.ID_CANCEL, 'Close')
- self.bt_close.SetToolTipString("Close window.")
- self.button_sizer.AddMany([(self.bt_apply, 0, wx.LEFT, 200),
- (self.bt_cancel, 0, wx.LEFT, 10),
- (self.bt_close, 0, wx.LEFT, 10)])
-
- def _do_layout(self, data=None):
- """
- Draw the current panel
- """
- self._define_structure()
- self._layout_name()
- self._layout_radiation()
- self._layout_beam_shape()
- self._layout_wavelength()
- self._layout_wavelength_min()
- self._layout_wavelength_max()
- self._layout_wavelength_spread()
- self._layout_beam_size_name()
- self._layout_beam_size()
- self._layout_button()
-
- self.boxsizer_source.AddMany([(self.name_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
- (self.radiation_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
- (self.beam_shape_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
- (self.wavelength_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
- (self.wavelength_min_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
- (self.wavelength_max_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
- (self.wavelength_spread_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
- (self.beam_size_name_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
- (self.beam_size_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
- self.main_sizer.AddMany([(self.boxsizer_source, 0, wx.ALL, 10),
- (self.button_sizer, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
-
- self.SetSizer(self.main_sizer)
- self.SetAutoLayout(True)
-
- def set_manager(self, manager):
- """
- Set manager of this window
- """
- self.manager = manager
-
- def reset_source(self):
- """
- put back initial values of the source
- """
- self._source.name = self._reset_source.name
- self._source.radiation = self._reset_source.radiation
- self._source.beam_size_name = self._reset_source.beam_size_name
-
- self._source.beam_size.x = self._reset_source.beam_size.x
- self._source.beam_size.y = self._reset_source.beam_size.y
- self._source.beam_size.z = self._reset_source.beam_size.z
- self._source.beam_size_unit = self._reset_source.beam_size_unit
-
- self._source.beam_shape = self._reset_source.beam_shape
- self._source.wavelength = self._reset_source.wavelength
- self._source.wavelength_unit = self._reset_source.wavelength_unit
- ## Minimum wavelength [float] [Angstrom]
- self._source.wavelength_min = self._reset_source.wavelength_min
- self._source.wavelength_min_unit = self._reset_source.wavelength_min_unit
-
- self._source.wavelength_max = self._reset_source.wavelength_max
- self._source.wavelength_max_unit = self._reset_source.wavelength_max_unit
-
- self._source.wavelength_spread = self._reset_source.wavelength_spread
- self._source.wavelength_spread_unit = self._reset_source.wavelength_spread_unit
-
- def set_values(self):
- """
- take the source values of the current data and display them
- through the panel
- """
- source = self._source
- #Name
- self.sample_name_tcl.SetValue(str(source.name))
- #Radiation
- self.radiation_tcl.SetValue(str(source.radiation))
- #Beam shape
- self.beam_shape_tcl.SetValue(str(source.beam_shape))
- #Wavelength
- self.wavelength_tcl.SetValue(str(source.wavelength))
- self.wavelength_unit_tcl.SetValue(str(source.wavelength_unit))
- #Wavelength min
- self.wavelength_min_tcl.SetValue(str(source.wavelength_min))
- self.wavelength_min_unit_tcl.SetValue(str(source.wavelength_min_unit))
- #Wavelength max
- self.wavelength_max_tcl.SetValue(str(source.wavelength_max))
- self.wavelength_max_unit_tcl.SetValue(str(source.wavelength_max_unit))
- #Wavelength spread
- self.wavelength_spread_tcl.SetValue(str(source.wavelength_spread))
- self.wavelength_spread_unit_tcl.SetValue(str(source.wavelength_spread_unit))
- #Beam size
- self.beam_size_name_tcl.SetValue(str(source.beam_size_name))
- x, y, z = source.beam_size.x, source.beam_size.y , source.beam_size.z
- self.x_beam_size_tcl.SetValue(str(x))
- self.y_beam_size_tcl.SetValue(str(y))
- self.z_beam_size_tcl.SetValue(str(z))
- self.beam_size_unit_tcl.SetValue(str(source.beam_size_unit))
-
- def get_source(self):
- """
- return the current source
- """
- return self._source
-
- def get_notes(self):
- """
- return notes
- """
- return self._notes
-
- def on_change_name(self):
- """
- Change name
- """
- #Change the name of the source
- name = self.sample_name_tcl.GetValue().lstrip().rstrip()
- if name == "" or name == str(None):
- name = None
- if self._source.name != name:
- self._notes += "Change sample 's "
- self._notes += "name from %s to %s \n" % (self._source.name, name)
- self._source.name = name
-
- def on_change_radiation(self):
- """
- Change radiation of the sample
- """
- #Change radiation
- radiation = self.radiation_tcl.GetValue().lstrip().rstrip()
- self._source.radiation = radiation
- self._notes += " Change radiation from"
- self._notes += " %s to %s \n" % (self._source.radiation, radiation)
-
- def on_change_beam_shape(self):
- """
- Change beams shape
- """
- #Change beam shape
- beam_shape = self.beam_shape_tcl.GetValue().lstrip().rstrip()
- self._source.beam_shape = beam_shape
- self._notes += " Change beam shape from"
- self._notes += " %s to %s \n" % (self._source.beam_shape, beam_shape)
-
- def on_change_wavelength(self):
- """
- Change the wavelength
- """
- #Change wavelength
- wavelength = self.wavelength_tcl.GetValue().lstrip().rstrip()
- self._source.wavelength = wavelength
- self._notes += " Change wavelength from"
- self._notes += " %s to %s \n" % (self._source.wavelength, wavelength)
- #change the wavelength unit
- unit = self.wavelength_unit_tcl.GetValue().lstrip().rstrip()
- if self._source.wavelength_unit != unit:
- self._notes += " Change wavelength's unit from "
- self._notes += "%s to %s" % (self._source.wavelength_unit, unit)
-
- def on_change_wavelength_min(self):
- """
- Change the wavelength minimum
- """
- #Change wavelength min
- wavelength_min = self.wavelength_min_tcl.GetValue().lstrip().rstrip()
- self._source.wavelength_min = wavelength_min
- self._notes += " Change wavelength min from"
- self._notes += " %s to %s \n" % (self._source.wavelength_min,
- wavelength_min)
- #change the wavelength min unit
- unit = self.wavelength_min_unit_tcl.GetValue().lstrip().rstrip()
- if self._source.wavelength_min_unit != unit:
- self._notes += " Change wavelength min's unit from "
- self._notes += "%s to %s" % (self._source.wavelength_min_unit, unit)
-
- def on_change_wavelength_max(self):
- """
- Change the wavelength maximum
- """
- #Change wavelength max
- wavelength_max = self.wavelength_max_tcl.GetValue().lstrip().rstrip()
- self._source.wavelength_max = wavelength_max
- self._notes += " Change wavelength max from"
- self._notes += " %s to %s \n" % (self._source.wavelength_max,
- wavelength_max)
- #change the wavelength max unit
- unit = self.wavelength_max_unit_tcl.GetValue().lstrip().rstrip()
- if self._source.wavelength_max_unit != unit:
- self._notes += " Change wavelength max's unit from "
- self._notes += "%s to %s" % (self._source.wavelength_max_unit, unit)
-
- def on_change_wavelength_spread(self):
- """
- Change the wavelength spread
- """
- #Change wavelength spread
- wavelength_spread = self.wavelength_spread_tcl.GetValue().lstrip().rstrip()
- self._notes += " Change wavelength spread from"
- self._notes += " %s to %s \n" % (self._source.wavelength_spread,
- wavelength_spread)
- self._source.wavelength_spread = wavelength_spread
- #change the wavelength spread unit
- unit = self.wavelength_spread_unit_tcl.GetValue().lstrip().rstrip()
- if self._source.wavelength_spread_unit != unit:
- self._notes += " Change wavelength spread's unit from "
- self._notes += "%s to %s" % (self._source.wavelength_spread_unit,
- unit)
- self._source.wavelength_spread_unit = unit
-
- def on_change_beam_size_name(self):
- """
- Change beam size name
- """
- #Change beam size name
- name = self.beam_size_name_tcl.GetValue().lstrip().rstrip()
- if name == "" or name == str(None):
- name = None
- if self._source.beam_size_name != name:
- self._notes += "Change beam size 's "
- self._notes += "name from %s to %s \n" % (self._source.beam_size_name,
- name)
- self._source.name = name
-
- def on_change_beam_size(self):
- """
- Change beam size
- """
- #Change x coordinate
- x_beam_size = self.x_beam_size_tcl.GetValue().lstrip().rstrip()
- if x_beam_size == "" or x_beam_size == str(None):
- x_beam_size = None
- else:
- if check_float(self.x_beam_size_tcl):
- if self._source.beam_size.x != float(x_beam_size) :
- self._notes += "Change x of beam size from "
- self._notes += "%s to %s \n" % (self._source.beam_size.x,
- x_beam_size)
- self._source.beam_size.x = float(x_beam_size)
- else:
- self._notes += "Error: Expected a float for the beam size 's x "
- self._notes += "won't changes x beam size from "
- self._notes += "%s to %s" % (self._source.beam_size.x,
- x_beam_size)
- #Change y coordinate
- y_beam_size = self.y_beam_size_tcl.GetValue().lstrip().rstrip()
- if y_beam_size == "" or y_beam_size == str(None):
- y_beam_size = None
- self._source.beam_size.y = y_beam_size
- else:
- if check_float(self.y_beam_size_tcl):
- if self._source.beam_size.y != float(y_beam_size):
- self._notes += "Change y of beam size from "
- self._notes += "%s to %s \n" % (self._source.beam_size.y,
- y_beam_size)
- self._source.beam_size.y = float(y_beam_size)
- else:
- self._notes += "Error: Expected a float for the beam size's y "
- self._notes += "won't changes y beam size from "
- self._notes += "%s to %s" % (self._source.beam_size.y,
- y_beam_size)
- #Change z coordinate
- z_beam_size = self.z_beam_size_tcl.GetValue().lstrip().rstrip()
- if z_beam_size == "" or z_beam_size == str(None):
- z_beam_size = None
- self._source.beam_size.z = z_beam_size
- else:
- if check_float(self.z_beam_size_tcl):
- if self._source.beam_size.z != float(z_beam_size):
- self._notes += "Change z of beam size from "
- self._notes += "%s to %s \n" % (self._source.beam_size.z,
- z_beam_size)
- self._source.beam_size.z = float(z_beam_size)
- else:
- self._notes += "Error: Expected a float for the beam size 's z "
- self._notes += "won't changes z beam size from "
- self._notes += "%s to %s" % (self._source.beam_size.z,
- z_beam_size)
- #change the beam center unit
- unit = self.beam_size_unit_tcl.GetValue().lstrip().rstrip()
- if self._source.beam_size_unit != unit:
- self._notes += " Change beam size's unit from "
- self._notes += "%s to %s" % (self._source.beam_size_unit, unit)
- self._source.beam_size_unit = unit
-
- def on_click_apply(self, event):
- """
- Apply user values to the source
- """
- self.on_change_name()
- self.on_change_radiation()
- self.on_change_beam_shape()
- self.on_change_wavelength()
- self.on_change_wavelength_min()
- self.on_change_wavelength_max()
- self.on_change_wavelength_spread()
- self.on_change_beam_size_name()
- self.on_change_beam_size()
- if self.manager is not None:
- self.manager.set_source(self._source, self._notes)
- if event is not None:
- event.Skip()
-
- def on_click_cancel(self, event):
- """
- reset the current source
- """
- self.reset_source()
- self.set_values()
- if self.manager is not None:
- self.manager.set_source(self._source)
- if event is not None:
- event.Skip()
-
-if __name__ == "__main__":
- app = wx.App()
- from sas.sascalc.dataloader.data_info import Source
- source = Source()
- dlg = SourceDialog(source=source)
- dlg.ShowModal()
- app.MainLoop()
+"""
+"""
+import wx
+import sys
+from copy import deepcopy
+from sas.sasgui.guiframe.utils import check_float
+
+_BOX_WIDTH = 60
+if sys.platform.count("win32") > 0:
+ _STATICBOX_WIDTH = 450
+ PANEL_WIDTH = 500
+ PANEL_HEIGHT = 430
+ FONT_VARIANT = 0
+else:
+ _STATICBOX_WIDTH = 480
+ PANEL_WIDTH = 550
+ PANEL_HEIGHT = 430
+ FONT_VARIANT = 1
+
+class SourceDialog(wx.Dialog):
+ def __init__(self, parent=None, manager=None, source=None, *args, **kwds):
+ kwds['title'] = "Source Editor"
+ kwds['size'] = (PANEL_WIDTH, PANEL_HEIGHT)
+ wx.Dialog.__init__(self, parent=parent, *args, **kwds)
+
+ self.parent = parent
+ self.manager = manager
+ self._source = source
+ self._reset_source = deepcopy(source)
+ self._notes = ""
+ self._description = "Edit source"
+ self._do_layout()
+ self.set_values()
+
+ def _define_structure(self):
+ """
+ define initial sizer
+ """
+ self.main_sizer = wx.BoxSizer(wx.VERTICAL)
+ self.box_source = wx.StaticBox(self, -1, str("source"))
+ self.boxsizer_source = wx.StaticBoxSizer(self.box_source,
+ wx.VERTICAL)
+ self.name_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.radiation_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.beam_shape_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.wavelength_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.wavelength_min_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.wavelength_max_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.wavelength_spread_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.beam_size_name_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.beam_size_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.button_sizer = wx.BoxSizer(wx.HORIZONTAL)
+
+ def _layout_name(self):
+ """
+ Do the layout for sample name related widgets
+ """
+ # Sample name [string]
+ sample_name_txt = wx.StaticText(self, -1, 'Sample Name : ')
+ self.sample_name_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH * 5, 20), style=0)
+ self.name_sizer.AddMany([(sample_name_txt, 0, wx.LEFT | wx.RIGHT, 10),
+ (self.sample_name_tcl, 0, wx.EXPAND)])
+ def _layout_radiation(self):
+ """
+ Do the layout for radiation related widgets
+ """
+ #Radiation type [string]
+ radiation_txt = wx.StaticText(self, -1, 'Radiation: ')
+ self.radiation_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, 20), style=0)
+ self.radiation_sizer.AddMany([(radiation_txt, 0, wx.LEFT | wx.RIGHT, 10),
+ (self.radiation_tcl, 0, wx.LEFT, 20)])
+
+ def _layout_beam_shape(self):
+ """
+ Do the layout for beam shape related widgets
+ """
+ #Beam shape [string]
+ beam_shape_txt = wx.StaticText(self, -1, 'Beam shape:')
+ self.beam_shape_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, 20), style=0)
+ self.beam_shape_sizer.AddMany([(beam_shape_txt, 0,
+ wx.LEFT | wx.RIGHT, 10),
+ (self.beam_shape_tcl, 0, wx.LEFT, 10)])
+
+ def _layout_wavelength(self):
+ """
+ Do the layout for wavelength related widgets
+ """
+ #Wavelength [float] [Angstrom]
+ wavelength_txt = wx.StaticText(self, -1, 'wavelength:')
+ self.wavelength_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, 20), style=0)
+ wavelength_unit_txt = wx.StaticText(self, -1, 'Unit: ')
+ self.wavelength_unit_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, 20), style=0)
+ self.wavelength_sizer.AddMany([(wavelength_txt,
+ 0, wx.LEFT | wx.RIGHT, 10),
+ (self.wavelength_tcl, 0, wx.LEFT, 12),
+ (wavelength_unit_txt, 0, wx.LEFT | wx.RIGHT, 10),
+ (self.wavelength_unit_tcl, 0, wx.EXPAND)])
+
+ def _layout_wavelength_min(self):
+ """
+ Do the layout for wavelength min related widgets
+ """
+ #Minimum wavelength [float] [Angstrom]
+ wavelength_min_txt = wx.StaticText(self, -1, 'Wavelength min:')
+ self.wavelength_min_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, 20), style=0)
+ wavelength_min_unit_txt = wx.StaticText(self, -1, 'Unit: ')
+ self.wavelength_min_unit_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, 20), style=0)
+ self.wavelength_min_sizer.AddMany([(wavelength_min_txt,
+ 0, wx.LEFT | wx.RIGHT, 10),
+ (self.wavelength_min_tcl, 0, wx.LEFT, 10),
+ (wavelength_min_unit_txt, 0, wx.LEFT | wx.RIGHT, 10),
+ (self.wavelength_min_unit_tcl, 0, wx.EXPAND)])
+
+ def _layout_wavelength_max(self):
+ """
+ Do the layout for wavelength max related widgets
+ """
+ #Maximum wavelength [float] [Angstrom]
+ wavelength_max_txt = wx.StaticText(self, -1, 'Wavelength max:')
+ self.wavelength_max_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, 20), style=0)
+ wavelength_max_unit_txt = wx.StaticText(self, -1, 'Unit: ')
+ self.wavelength_max_unit_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, 20), style=0)
+ self.wavelength_max_sizer.AddMany([(wavelength_max_txt, 0,
+ wx.LEFT | wx.RIGHT, 10),
+ (self.wavelength_max_tcl, 0, wx.LEFT, 7),
+ (wavelength_max_unit_txt, 0, wx.LEFT | wx.RIGHT, 10),
+ (self.wavelength_max_unit_tcl, 0, wx.EXPAND)])
+
+ def _layout_wavelength_spread(self):
+ """
+ Do the layout for wavelength spread related widgets
+ """
+ ## Wavelength spread [float] [Angstrom]
+ wavelength_spread = None
+ wavelength_spread_unit = 'percent'
+ wavelength_spread_txt = wx.StaticText(self, -1, 'Wavelength spread:')
+ self.wavelength_spread_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, 20), style=0)
+ wavelength_spread_unit_txt = wx.StaticText(self, -1, 'Unit: ')
+ self.wavelength_spread_unit_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, 20), style=0)
+ self.wavelength_spread_sizer.AddMany([(wavelength_spread_txt,
+ 0, wx.LEFT, 10),
+ (self.wavelength_spread_tcl, 0, wx.LEFT, 5),
+ (wavelength_spread_unit_txt, 0, wx.LEFT | wx.RIGHT, 10),
+ (self.wavelength_spread_unit_tcl, 0, wx.EXPAND)])
+ def _layout_beam_size_name(self):
+ """
+ Do the layout for beam size name related widgets
+ """
+ # Beam size name [string]
+ beam_size_name_txt = wx.StaticText(self, -1, 'Beam size name : ')
+ self.beam_size_name_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH * 5, 20), style=0)
+ self.beam_size_name_sizer.AddMany([(beam_size_name_txt,
+ 0, wx.LEFT | wx.RIGHT, 10),
+ (self.beam_size_name_tcl, 0, wx.EXPAND)])
+
+ def _layout_beam_size(self):
+ """
+ Do the layout for beam size related widgets
+ """
+ ## Beam size [Vector] [mm]
+ beam_size = None
+ beam_size_unit = 'mm'
+
+ beam_size_txt = wx.StaticText(self, -1, 'Beam size:')
+ x_beam_size_txt = wx.StaticText(self, -1, 'x = ')
+ self.x_beam_size_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, 20), style=0)
+ y_beam_size_txt = wx.StaticText(self, -1, 'y = ')
+ self.y_beam_size_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, 20), style=0)
+ z_beam_size_txt = wx.StaticText(self, -1, 'z = ')
+ self.z_beam_size_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, 20), style=0)
+ beam_size_unit_txt = wx.StaticText(self, -1, 'Unit: ')
+ self.beam_size_unit_tcl = wx.TextCtrl(self, -1,
+ size=(_BOX_WIDTH, 20), style=0)
+ self.beam_size_sizer.AddMany([(beam_size_txt, 0, wx.LEFT | wx.RIGHT, 10),
+ (x_beam_size_txt, 0, wx.LEFT, 17),
+ (self.x_beam_size_tcl, 0, wx.RIGHT, 10),
+ (y_beam_size_txt, 0, wx.EXPAND),
+ (self.y_beam_size_tcl, 0, wx.RIGHT, 10),
+ (z_beam_size_txt, 0, wx.EXPAND),
+ (self.z_beam_size_tcl, 0, wx.RIGHT, 10),
+ (beam_size_unit_txt, 0, wx.EXPAND),
+ (self.beam_size_unit_tcl, 0, wx.RIGHT, 10)])
+
+ def _layout_button(self):
+ """
+ Do the layout for the button widgets
+ """
+ self.bt_apply = wx.Button(self, -1, 'Apply')
+ self.bt_apply.Bind(wx.EVT_BUTTON, self.on_click_apply)
+ self.bt_apply.SetToolTipString("Apply current changes to the source.")
+ self.bt_cancel = wx.Button(self, -1, 'Cancel')
+ self.bt_cancel.SetToolTipString("Cancel current changes.")
+ self.bt_cancel.Bind(wx.EVT_BUTTON, self.on_click_cancel)
+ self.bt_close = wx.Button(self, wx.ID_CANCEL, 'Close')
+ self.bt_close.SetToolTipString("Close window.")
+ self.button_sizer.AddMany([(self.bt_apply, 0, wx.LEFT, 200),
+ (self.bt_cancel, 0, wx.LEFT, 10),
+ (self.bt_close, 0, wx.LEFT, 10)])
+
+ def _do_layout(self, data=None):
+ """
+ Draw the current panel
+ """
+ self._define_structure()
+ self._layout_name()
+ self._layout_radiation()
+ self._layout_beam_shape()
+ self._layout_wavelength()
+ self._layout_wavelength_min()
+ self._layout_wavelength_max()
+ self._layout_wavelength_spread()
+ self._layout_beam_size_name()
+ self._layout_beam_size()
+ self._layout_button()
+
+ self.boxsizer_source.AddMany([(self.name_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
+ (self.radiation_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
+ (self.beam_shape_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
+ (self.wavelength_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
+ (self.wavelength_min_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
+ (self.wavelength_max_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
+ (self.wavelength_spread_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
+ (self.beam_size_name_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
+ (self.beam_size_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
+ self.main_sizer.AddMany([(self.boxsizer_source, 0, wx.ALL, 10),
+ (self.button_sizer, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
+
+ self.SetSizer(self.main_sizer)
+ self.SetAutoLayout(True)
+
+ def set_manager(self, manager):
+ """
+ Set manager of this window
+ """
+ self.manager = manager
+
+ def reset_source(self):
+ """
+ put back initial values of the source
+ """
+ self._source.name = self._reset_source.name
+ self._source.radiation = self._reset_source.radiation
+ self._source.beam_size_name = self._reset_source.beam_size_name
+
+ self._source.beam_size.x = self._reset_source.beam_size.x
+ self._source.beam_size.y = self._reset_source.beam_size.y
+ self._source.beam_size.z = self._reset_source.beam_size.z
+ self._source.beam_size_unit = self._reset_source.beam_size_unit
+
+ self._source.beam_shape = self._reset_source.beam_shape
+ self._source.wavelength = self._reset_source.wavelength
+ self._source.wavelength_unit = self._reset_source.wavelength_unit
+ ## Minimum wavelength [float] [Angstrom]
+ self._source.wavelength_min = self._reset_source.wavelength_min
+ self._source.wavelength_min_unit = self._reset_source.wavelength_min_unit
+
+ self._source.wavelength_max = self._reset_source.wavelength_max
+ self._source.wavelength_max_unit = self._reset_source.wavelength_max_unit
+
+ self._source.wavelength_spread = self._reset_source.wavelength_spread
+ self._source.wavelength_spread_unit = self._reset_source.wavelength_spread_unit
+
+ def set_values(self):
+ """
+ take the source values of the current data and display them
+ through the panel
+ """
+ source = self._source
+ #Name
+ self.sample_name_tcl.SetValue(str(source.name))
+ #Radiation
+ self.radiation_tcl.SetValue(str(source.radiation))
+ #Beam shape
+ self.beam_shape_tcl.SetValue(str(source.beam_shape))
+ #Wavelength
+ self.wavelength_tcl.SetValue(str(source.wavelength))
+ self.wavelength_unit_tcl.SetValue(str(source.wavelength_unit))
+ #Wavelength min
+ self.wavelength_min_tcl.SetValue(str(source.wavelength_min))
+ self.wavelength_min_unit_tcl.SetValue(str(source.wavelength_min_unit))
+ #Wavelength max
+ self.wavelength_max_tcl.SetValue(str(source.wavelength_max))
+ self.wavelength_max_unit_tcl.SetValue(str(source.wavelength_max_unit))
+ #Wavelength spread
+ self.wavelength_spread_tcl.SetValue(str(source.wavelength_spread))
+ self.wavelength_spread_unit_tcl.SetValue(str(source.wavelength_spread_unit))
+ #Beam size
+ self.beam_size_name_tcl.SetValue(str(source.beam_size_name))
+ x, y, z = source.beam_size.x, source.beam_size.y , source.beam_size.z
+ self.x_beam_size_tcl.SetValue(str(x))
+ self.y_beam_size_tcl.SetValue(str(y))
+ self.z_beam_size_tcl.SetValue(str(z))
+ self.beam_size_unit_tcl.SetValue(str(source.beam_size_unit))
+
+ def get_source(self):
+ """
+ return the current source
+ """
+ return self._source
+
+ def get_notes(self):
+ """
+ return notes
+ """
+ return self._notes
+
+ def on_change_name(self):
+ """
+ Change name
+ """
+ #Change the name of the source
+ name = self.sample_name_tcl.GetValue().lstrip().rstrip()
+ if name == "" or name == str(None):
+ name = None
+ if self._source.name != name:
+ self._notes += "Change sample 's "
+ self._notes += "name from %s to %s \n" % (self._source.name, name)
+ self._source.name = name
+
+ def on_change_radiation(self):
+ """
+ Change radiation of the sample
+ """
+ #Change radiation
+ radiation = self.radiation_tcl.GetValue().lstrip().rstrip()
+ self._source.radiation = radiation
+ self._notes += " Change radiation from"
+ self._notes += " %s to %s \n" % (self._source.radiation, radiation)
+
+ def on_change_beam_shape(self):
+ """
+ Change beams shape
+ """
+ #Change beam shape
+ beam_shape = self.beam_shape_tcl.GetValue().lstrip().rstrip()
+ self._source.beam_shape = beam_shape
+ self._notes += " Change beam shape from"
+ self._notes += " %s to %s \n" % (self._source.beam_shape, beam_shape)
+
+ def on_change_wavelength(self):
+ """
+ Change the wavelength
+ """
+ #Change wavelength
+ wavelength = self.wavelength_tcl.GetValue().lstrip().rstrip()
+ self._source.wavelength = wavelength
+ self._notes += " Change wavelength from"
+ self._notes += " %s to %s \n" % (self._source.wavelength, wavelength)
+ #change the wavelength unit
+ unit = self.wavelength_unit_tcl.GetValue().lstrip().rstrip()
+ if self._source.wavelength_unit != unit:
+ self._notes += " Change wavelength's unit from "
+ self._notes += "%s to %s" % (self._source.wavelength_unit, unit)
+
+ def on_change_wavelength_min(self):
+ """
+ Change the wavelength minimum
+ """
+ #Change wavelength min
+ wavelength_min = self.wavelength_min_tcl.GetValue().lstrip().rstrip()
+ self._source.wavelength_min = wavelength_min
+ self._notes += " Change wavelength min from"
+ self._notes += " %s to %s \n" % (self._source.wavelength_min,
+ wavelength_min)
+ #change the wavelength min unit
+ unit = self.wavelength_min_unit_tcl.GetValue().lstrip().rstrip()
+ if self._source.wavelength_min_unit != unit:
+ self._notes += " Change wavelength min's unit from "
+ self._notes += "%s to %s" % (self._source.wavelength_min_unit, unit)
+
+ def on_change_wavelength_max(self):
+ """
+ Change the wavelength maximum
+ """
+ #Change wavelength max
+ wavelength_max = self.wavelength_max_tcl.GetValue().lstrip().rstrip()
+ self._source.wavelength_max = wavelength_max
+ self._notes += " Change wavelength max from"
+ self._notes += " %s to %s \n" % (self._source.wavelength_max,
+ wavelength_max)
+ #change the wavelength max unit
+ unit = self.wavelength_max_unit_tcl.GetValue().lstrip().rstrip()
+ if self._source.wavelength_max_unit != unit:
+ self._notes += " Change wavelength max's unit from "
+ self._notes += "%s to %s" % (self._source.wavelength_max_unit, unit)
+
+ def on_change_wavelength_spread(self):
+ """
+ Change the wavelength spread
+ """
+ #Change wavelength spread
+ wavelength_spread = self.wavelength_spread_tcl.GetValue().lstrip().rstrip()
+ self._notes += " Change wavelength spread from"
+ self._notes += " %s to %s \n" % (self._source.wavelength_spread,
+ wavelength_spread)
+ self._source.wavelength_spread = wavelength_spread
+ #change the wavelength spread unit
+ unit = self.wavelength_spread_unit_tcl.GetValue().lstrip().rstrip()
+ if self._source.wavelength_spread_unit != unit:
+ self._notes += " Change wavelength spread's unit from "
+ self._notes += "%s to %s" % (self._source.wavelength_spread_unit,
+ unit)
+ self._source.wavelength_spread_unit = unit
+
+ def on_change_beam_size_name(self):
+ """
+ Change beam size name
+ """
+ #Change beam size name
+ name = self.beam_size_name_tcl.GetValue().lstrip().rstrip()
+ if name == "" or name == str(None):
+ name = None
+ if self._source.beam_size_name != name:
+ self._notes += "Change beam size 's "
+ self._notes += "name from %s to %s \n" % (self._source.beam_size_name,
+ name)
+ self._source.name = name
+
+ def on_change_beam_size(self):
+ """
+ Change beam size
+ """
+ #Change x coordinate
+ x_beam_size = self.x_beam_size_tcl.GetValue().lstrip().rstrip()
+ if x_beam_size == "" or x_beam_size == str(None):
+ x_beam_size = None
+ else:
+ if check_float(self.x_beam_size_tcl):
+ if self._source.beam_size.x != float(x_beam_size) :
+ self._notes += "Change x of beam size from "
+ self._notes += "%s to %s \n" % (self._source.beam_size.x,
+ x_beam_size)
+ self._source.beam_size.x = float(x_beam_size)
+ else:
+ self._notes += "Error: Expected a float for the beam size 's x "
+ self._notes += "won't changes x beam size from "
+ self._notes += "%s to %s" % (self._source.beam_size.x,
+ x_beam_size)
+ #Change y coordinate
+ y_beam_size = self.y_beam_size_tcl.GetValue().lstrip().rstrip()
+ if y_beam_size == "" or y_beam_size == str(None):
+ y_beam_size = None
+ self._source.beam_size.y = y_beam_size
+ else:
+ if check_float(self.y_beam_size_tcl):
+ if self._source.beam_size.y != float(y_beam_size):
+ self._notes += "Change y of beam size from "
+ self._notes += "%s to %s \n" % (self._source.beam_size.y,
+ y_beam_size)
+ self._source.beam_size.y = float(y_beam_size)
+ else:
+ self._notes += "Error: Expected a float for the beam size's y "
+ self._notes += "won't changes y beam size from "
+ self._notes += "%s to %s" % (self._source.beam_size.y,
+ y_beam_size)
+ #Change z coordinate
+ z_beam_size = self.z_beam_size_tcl.GetValue().lstrip().rstrip()
+ if z_beam_size == "" or z_beam_size == str(None):
+ z_beam_size = None
+ self._source.beam_size.z = z_beam_size
+ else:
+ if check_float(self.z_beam_size_tcl):
+ if self._source.beam_size.z != float(z_beam_size):
+ self._notes += "Change z of beam size from "
+ self._notes += "%s to %s \n" % (self._source.beam_size.z,
+ z_beam_size)
+ self._source.beam_size.z = float(z_beam_size)
+ else:
+ self._notes += "Error: Expected a float for the beam size 's z "
+ self._notes += "won't changes z beam size from "
+ self._notes += "%s to %s" % (self._source.beam_size.z,
+ z_beam_size)
+ #change the beam center unit
+ unit = self.beam_size_unit_tcl.GetValue().lstrip().rstrip()
+ if self._source.beam_size_unit != unit:
+ self._notes += " Change beam size's unit from "
+ self._notes += "%s to %s" % (self._source.beam_size_unit, unit)
+ self._source.beam_size_unit = unit
+
+ def on_click_apply(self, event):
+ """
+ Apply user values to the source
+ """
+ self.on_change_name()
+ self.on_change_radiation()
+ self.on_change_beam_shape()
+ self.on_change_wavelength()
+ self.on_change_wavelength_min()
+ self.on_change_wavelength_max()
+ self.on_change_wavelength_spread()
+ self.on_change_beam_size_name()
+ self.on_change_beam_size()
+ if self.manager is not None:
+ self.manager.set_source(self._source, self._notes)
+ if event is not None:
+ event.Skip()
+
+ def on_click_cancel(self, event):
+ """
+ reset the current source
+ """
+ self.reset_source()
+ self.set_values()
+ if self.manager is not None:
+ self.manager.set_source(self._source)
+ if event is not None:
+ event.Skip()
+
+if __name__ == "__main__":
+ app = wx.App()
+ from sas.sascalc.dataloader.data_info import Source
+ source = Source()
+ dlg = SourceDialog(source=source)
+ dlg.ShowModal()
+ app.MainLoop()
diff --git a/src/sas/sasgui/perspectives/corfunc/corfunc.py b/src/sas/sasgui/perspectives/corfunc/corfunc.py
index a03655d..667da38 100644
--- a/src/sas/sasgui/perspectives/corfunc/corfunc.py
+++ b/src/sas/sasgui/perspectives/corfunc/corfunc.py
@@ -19,6 +19,7 @@ from sas.sascalc.dataloader.loader import Loader
import sas.sascalc.dataloader
from plot_labels import *
+logger = logging.getLogger(__name__)
class Plugin(PluginBase):
"""
@@ -28,7 +29,7 @@ class Plugin(PluginBase):
def __init__(self):
PluginBase.__init__(self, name="Correlation Function")
- logging.info("Correlation function plug-in started")
+ logger.info("Correlation function plug-in started")
self._always_active = True
self.state_reader = Reader(self.set_state)
self._extensions = '.crf'
@@ -187,6 +188,15 @@ class Plugin(PluginBase):
group_id = GROUP_ID_TRANSFORM
# Show the transformation as a curve instead of points
new_plot.symbol = GUIFRAME_ID.CURVE_SYMBOL_NUM
+ elif label == IDF_LABEL:
+ new_plot.xaxis("{x}", 'A')
+ new_plot.yaxis("{g_1}", '')
+ # Linear scale
+ new_plot.xtransform = 'x'
+ new_plot.ytransform = 'y'
+ group_id = GROUP_ID_IDF
+ # Show IDF as a curve instead of points
+ new_plot.symbol = GUIFRAME_ID.CURVE_SYMBOL_NUM
new_plot.id = label
new_plot.name = label
new_plot.group_id = group_id
diff --git a/src/sas/sasgui/perspectives/corfunc/corfunc_panel.py b/src/sas/sasgui/perspectives/corfunc/corfunc_panel.py
index 789b1d4..52441cc 100644
--- a/src/sas/sasgui/perspectives/corfunc/corfunc_panel.py
+++ b/src/sas/sasgui/perspectives/corfunc/corfunc_panel.py
@@ -19,7 +19,7 @@ from sas.sasgui.guiframe.documentation_window import DocumentationWindow
from plot_labels import *
OUTPUT_STRINGS = {
- 'max': "Long Period (A): ",
+ 'max': "Long Period / 2 (A): ",
'Lc': "Average Hard Block Thickness (A): ",
'dtr': "Average Interface Thickness (A): ",
'd0': "Average Core Thickness: ",
@@ -54,6 +54,9 @@ class CorfuncPanel(ScrolledPanel,PanelBase):
# The data with no correction for background values
self._data = data # The data to be analysed (corrected fr background)
self._extrapolated_data = None # The extrapolated data set
+ # Callable object of class CorfuncCalculator._Interpolator representing
+ # the extrapolated and interpolated data
+ self._extrapolated_fn = None
self._transformed_data = None # Fourier trans. of the extrapolated data
self._calculator = CorfuncCalculator()
self._data_name_box = None # Text box to show name of file
@@ -217,7 +220,8 @@ class CorfuncPanel(ScrolledPanel,PanelBase):
self._calculator.background = self.background
try:
- params, self._extrapolated_data = self._calculator.compute_extrapolation()
+ params, self._extrapolated_data, self._extrapolated_fn = \
+ self._calculator.compute_extrapolation()
except Exception as e:
msg = "Error extrapolating data:\n"
msg += str(e)
@@ -256,12 +260,12 @@ class CorfuncPanel(ScrolledPanel,PanelBase):
wx.PostEvent(self._manager.parent,
StatusEvent(status=msg))
- def transform_complete(self, transform=None):
+ def transform_complete(self, transforms=None):
"""
Called from FourierThread when calculation has completed
"""
self._transform_btn.SetLabel("Transform")
- if transform is None:
+ if transforms is None:
msg = "Error calculating Transform."
if self.transform_type == 'hilbert':
msg = "Not yet implemented"
@@ -269,11 +273,19 @@ class CorfuncPanel(ScrolledPanel,PanelBase):
StatusEvent(status=msg, info="Error"))
self._extract_btn.Disable()
return
- self._transformed_data = transform
- import numpy as np
- plot_x = transform.x[np.where(transform.x <= 200)]
- plot_y = transform.y[np.where(transform.x <= 200)]
+
+ self._transformed_data = transforms
+ (transform1, transform3, idf) = transforms
+ plot_x = transform1.x[transform1.x <= 200]
+ plot_y = transform1.y[transform1.x <= 200]
self._manager.show_data(Data1D(plot_x, plot_y), TRANSFORM_LABEL1)
+ # No need to shorten gamma3 as it's only calculated up to x=200
+ self._manager.show_data(transform3, TRANSFORM_LABEL3)
+
+ plot_x = idf.x[idf.x <= 200]
+ plot_y = idf.y[idf.x <= 200]
+ self._manager.show_data(Data1D(plot_x, plot_y), IDF_LABEL)
+
# Only enable extract params button if a fourier trans. has been done
if self.transform_type == 'fourier':
self._extract_btn.Enable()
@@ -285,7 +297,7 @@ class CorfuncPanel(ScrolledPanel,PanelBase):
Called when "Extract Parameters" is clicked
"""
try:
- params = self._calculator.extract_parameters(self._transformed_data)
+ params = self._calculator.extract_parameters(self._transformed_data[0])
except:
params = None
if params is None:
@@ -319,7 +331,7 @@ class CorfuncPanel(ScrolledPanel,PanelBase):
# Ask the user the location of the file to write to.
path = None
default_save_location = os.getcwd()
- if self._manager.parent != None:
+ if self._manager.parent is not None:
default_save_location = self._manager.parent.get_save_location()
dlg = wx.FileDialog(self, "Choose a file",
@@ -328,7 +340,7 @@ class CorfuncPanel(ScrolledPanel,PanelBase):
if dlg.ShowModal() == wx.ID_OK:
path = dlg.GetPath()
default_save_location = os.path.dirname(path)
- if self._manager.parent != None:
+ if self._manager.parent is not None:
self._manager.parent._default_save_location = default_save_location
else:
return None
diff --git a/src/sas/sasgui/perspectives/corfunc/corfunc_state.py b/src/sas/sasgui/perspectives/corfunc/corfunc_state.py
index af101cd..3b5d600 100644
--- a/src/sas/sasgui/perspectives/corfunc/corfunc_state.py
+++ b/src/sas/sasgui/perspectives/corfunc/corfunc_state.py
@@ -12,6 +12,8 @@ from sas.sasgui.guiframe.dataFitting import Data1D
from sas.sascalc.dataloader.data_info import Data1D as LoaderData1D
from sas.sascalc.dataloader.loader import Loader
+logger = logging.getLogger(__name__)
+
CORNODE_NAME = 'corfunc'
CANSAS_NS = 'cansas1d/1.0'
@@ -25,7 +27,7 @@ DEFAULT_STATE = {
# List of output parameters, used by __str__
output_list = [
- ['max', "Long Period (A): "],
+ ['max', "Long Period / 2 (A): "],
['Lc', "Average Hard Block Thickness (A): "],
['dtr', "Average Interface Thickness (A): "],
['d0', "Average Core Thickness: "],
@@ -56,7 +58,6 @@ class CorfuncState(object):
# Raw Data
self.q = None
self.iq = None
- # TODO: Add extrapolated data and transformed data (when implemented)
def __str__(self):
"""
@@ -215,7 +216,7 @@ class CorfuncState(object):
except:
msg = ("CorfuncState.fromXML: Could not read timestamp",
"\n{}").format(sys.exc_value)
- logging.error(msg)
+ logger.error(msg)
# Parse current state
entry = get_content('ns:state', node)
@@ -287,10 +288,10 @@ class Reader(CansasReader):
entry_list = root.xpath('/ns:SASroot/ns:SASentry',
namespaces={'ns': CANSAS_NS})
for entry in entry_list:
- sas_entry, _ = self._parse_entry(entry)
corstate = self._parse_state(entry)
- if corstate != None:
+ if corstate is not None:
+ sas_entry, _ = self._parse_entry(entry)
sas_entry.meta_data['corstate'] = corstate
sas_entry.filename = corstate.file
output.append(sas_entry)
@@ -324,7 +325,7 @@ class Reader(CansasReader):
raise RuntimeError, msg
if datainfo.title is None or datainfo.title == '':
datainfo.title = datainfo.name
- if datainfo.run_name == None or datainfo.run_name == '':
+ if datainfo.run_name is None or datainfo.run_name == '':
datainfo.run = [str(datainfo.name)]
datainfo.run_name[0] = datainfo.name
@@ -359,5 +360,5 @@ class Reader(CansasReader):
except:
msg = "XML document does not contain CorfuncState information\n{}"
msg.format(sys.exc_value)
- logging.info(msg)
+ logger.info(msg)
return state
diff --git a/src/sas/sasgui/perspectives/corfunc/media/corfunc_help.rst b/src/sas/sasgui/perspectives/corfunc/media/corfunc_help.rst
index e5baa6d..6a687dc 100644
--- a/src/sas/sasgui/perspectives/corfunc/media/corfunc_help.rst
+++ b/src/sas/sasgui/perspectives/corfunc/media/corfunc_help.rst
@@ -8,77 +8,94 @@ Correlation Function Analysis
Description
-----------
-This performs a correlation function analysis of one-dimensional
-SAXS/SANS data, or generates a model-independent volume fraction
-profile from the SANS from an adsorbed polymer/surfactant layer.
-
-A correlation function may be interpreted in terms of an imaginary rod moving
-through the structure of the material. Γ\ :sub:`1D`\ (R) is the probability that
-a rod of length R moving through the material has equal electron/neutron scattering
-length density at either end. Hence a frequently occurring spacing within a structure
-manifests itself as a peak.
-
-A volume fraction profile :math:`\Phi`\ (z) describes how the density of polymer segments/surfactant molecules varies with distance from an (assumed locally flat) interface.
-
-Both functions are returned in *real space*.
-
-The analysis is performed in 3 stages:
-
-* Extrapolation of the scattering curve to :math:`Q = 0` and
+This currently performs correlation function analysis on SAXS/SANS data,
+but in the the future is also planned to generate model-independent volume
+fraction profiles from the SANS from adsorbed polymer/surfactant layers.
+The two types of analyses differ in the mathematical transform that is
+applied to the data (Fourier vs Hilbert). However, both functions are
+returned in *real space*.
+
+A correlation function may be interpreted in terms of an imaginary rod moving
+through the structure of the material. Γ(x) is the probability that a rod of
+length x has equal electron/neutron scattering length density at either end.
+Hence a frequently occurring spacing within a structure will manifest itself
+as a peak in Γ(x). *SasView* will return both the one-dimensional ( Γ\ :sub:`1`\ (x) )
+and three-dimensional ( Γ\ :sub:`3`\ (x) ) correlation functions, the difference
+being that the former is only averaged in the plane of the scattering vector.
+
+A volume fraction profile :math:`\Phi`\ (z) describes how the density of polymer
+segments/surfactant molecules varies with distance, z, normal to an (assumed
+locally flat) interface. The form of :math:`\Phi`\ (z) can provide information
+about the arrangement of polymer/surfactant molecules at the interface. The width
+of the profile provides measures of the layer thickness, and the area under
+the profile is related to the amount of material that is adsorbed.
+
+Both analyses are performed in 3 stages:
+
+* Extrapolation of the scattering curve to :math:`Q = 0` and toward
:math:`Q = \infty`
* Smoothed merging of the two extrapolations into the original data
* Fourier / Hilbert Transform of the smoothed data to give the correlation
- function / volume fraction profile, respectively
-* (Optional) Interpretation of the 1D correlation function based on an ideal
- lamellar morphology
+ function or volume fraction profile, respectively
+* (Optional) Interpretation of Γ\ :sub:`1`\ (x) assuming the sample conforms
+ to an ideal lamellar morphology
.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
+
Extrapolation
-------------
To :math:`Q = 0`
................
-The data are extrapolated to Q = 0 by fitting a Guinier model to the data
-points in the low-Q range.
+The data are extrapolated to q = 0 by fitting a Guinier function to the data
+points in the low-q range.
The equation used is:
.. math::
- I(Q) = Ae^{Bq^2}
+ I(q) = A e^{Bq^2}
-The Guinier model assumes that the small angle scattering arises from particles
-and that parameter :math:`B` is related to the radius of gyration of those
-particles. This has dubious applicability to polymer systems. However, the
-correlation function is affected by the Guinier back-extrapolation to the
-greatest extent at large values of R and so only has a
-small effect on the final analysis.
+Where the parameter :math:`B` is related to the effective radius-of-gyration of
+a spherical object having the same small-angle scattering in this region.
+
+Note that as q tends to zero this function tends to a limiting value and is
+therefore less appropriate for use in systems where the form factor does not
+do likewise. However, because of the transform, the correlation functions are
+most affected by the Guinier back-extrapolation at *large* values of x where
+the impact on any extrapolated parameters will be least significant.
To :math:`Q = \infty`
.....................
-The data are extrapolated to Q = :math:`\infty` by fitting a Porod model to
-the data points in the high-Q range.
+The data are extrapolated towards q = :math:`\infty` by fitting a Porod model to
+the data points in the high-q range and then computing the extrapolation to 100
+times the maximum q value in the experimental dataset. This should be more than
+sufficient to ensure that on transformation any truncation artefacts introduced
+are at such small values of x that they can be safely ignored.
The equation used is:
.. math::
- I(Q) = K Q^{-4}e^{-Q^2\sigma^2} + Bg
+ I(q) = K q^{-4}e^{-q^2\sigma^2} + Bg
-Where :math:`Bg` is the background, :math:`K` is the Porod
-constant, and :math:`\sigma` (which must be > 0) describes the width of the electron or neutron scattering length density profile at the interface between the crystalline and amorphous
-regions as shown below.
+Where :math:`Bg` is the background, :math:`K` is the Porod constant, and :math:`\sigma` (which
+must be > 0) describes the width of the electron/neutron scattering length density
+profile at the interface between the crystalline and amorphous regions as shown below.
-.. figure:: fig1.gif
+.. figure:: fig1.png
:align: center
-
+
Smoothing
---------
-The extrapolated data set consists of the Guinier back-extrapolation from Q~0
-up to the lowest Q value in the original data, then the original scattering data, and the Porod tail-fit beyond this. The joins between the original data and the Guinier/Porod fits are smoothed using the algorithm below to avoid the formation of ripples in the transformed data.
+The extrapolated data set consists of the Guinier back-extrapolation from q ~ 0
+up to the lowest q value in the original data, then the original scattering data,
+and then the Porod tail-fit beyond this. The joins between the original data and
+the Guinier/Porod extrapolations are smoothed using the algorithm below to try
+and avoid the formation of truncation ripples in the transformed data:
Functions :math:`f(x_i)` and :math:`g(x_i)` where :math:`x_i \in \left\{
{x_1, x_2, ..., x_n} \right\}`, are smoothed over the range :math:`[a, b]`
@@ -92,21 +109,21 @@ where:
.. math::
h_i = \frac{1}{1 + \frac{(x_i-b)^2}{(x_i-a)^2}}
-
-Transform
----------
+
+Transformation
+--------------
Fourier
.......
-If "Fourier" is selected for the transform type, the analysis will perform a
+If "Fourier" is selected for the transform type, *SasView* will perform a
discrete cosine transform on the extrapolated data in order to calculate the
-correlation function
+1D correlation function as:
.. math::
- \Gamma _{1D}(R) = \frac{1}{Q^{*}} \int_{0}^{\infty }I(q) q^{2} cos(qR) dq
+ \Gamma _{1}(x) = \frac{1}{Q^{*}} \int_{0}^{\infty }I(q) q^{2} cos(qx) dq
-where Q\ :sup:`*` is the Scattering Invariant.
+where Q\ :sup:`*` is the Scattering (also called Porod) Invariant.
The following algorithm is applied:
@@ -115,14 +132,41 @@ The following algorithm is applied:
\left(n + \frac{1}{2} \right) k \right] } \text{ for } k = 0, 1, \ldots,
N-1, N
+The 3D correlation function is calculated as:
+
+.. math::
+ \Gamma _{3}(x) = \frac{1}{Q^{*}} \int_{0}^{\infty}I(q) q^{2}
+ \frac{sin(qx)}{qx} dq
+
+.. note:: It is always advisable to inspect Γ\ :sub:`1`\ (x) and Γ\ :sub:`3`\ (x)
+ for artefacts arising from the extrapolation and transformation processes:
+
+ - do they tend to zero as x tends to :math:`\infty`?
+ - do they smoothly curve onto the ordinate at x = 0? (if not check the value
+ of :math:`\sigma` is sensible)
+ - are there ripples at x values corresponding to (2 :math:`pi` over) the two
+ q values at which the extrapolated and experimental data are merged?
+ - are there any artefacts at x values corresponding to 2 :math:`pi` / q\ :sub:`max` in
+ the experimental data?
+ - and lastly, do the significant features/peaks in the correlation functions
+ actually correspond to anticpated spacings in the sample?!!!
+
+Finally, the program calculates the interface distribution function (IDF) g\ :sub:`1`\ (x) as
+the discrete cosine transform of:
+
+.. math::
+ -q^{4} I(q)
+
+The IDF is proportional to the second derivative of Γ\ :sub:`1`\ (x).
+
Hilbert
.......
-
+
If "Hilbert" is selected for the transform type, the analysis will perform a
Hilbert transform on the extrapolated data in order to calculate the Volume
Fraction Profile.
-.. note:: This functionality is not yet implemented in SasView.
+.. note:: The Hilbert transform functionality is not yet implemented in SasView.
Interpretation
@@ -131,17 +175,14 @@ Interpretation
Correlation Function
....................
-Once the correlation function has been calculated it may be interpreted by clicking the "Compute Parameters" button.
+Once the correlation functions have been calculated *SasView* can be asked to
+try and interpret Γ\ :sub:`1`\ (x) in terms of an ideal lamellar morphology
+as shown below.
-The correlation function is interpreted in terms of an ideal lamellar
-morphology, and structural parameters are obtained from it as shown below.
-It should be noted that a small beam size is assumed; ie, no de-smearing is
-performed.
-
-.. figure:: fig2.gif
+.. figure:: fig2.png
:align: center
-The structural parameters obtained are:
+The structural parameters extracted are:
* Long Period :math:`= L_p`
* Average Hard Block Thickness :math:`= L_c`
@@ -153,7 +194,9 @@ The structural parameters obtained are:
Volume Fraction Profile
.......................
-SasView does not provide any automatic interpretation of volume fraction profiles in the same way that it does for correlation functions. However, a number of structural parameters are obtainable by other means:
+SasView does not provide any automatic interpretation of volume fraction profiles
+in the same way that it does for correlation functions. However, a number of
+structural parameters are obtainable by other means:
* Surface Coverage :math:`=\theta`
* Anchor Separation :math:`= D`
@@ -164,14 +207,18 @@ SasView does not provide any automatic interpretation of volume fraction profile
.. figure:: profile1.png
:align: center
-
+
.. figure:: profile2.png
:align: center
-
+
+The reader is directed to the references for information on these parameters.
References
----------
+Correlation Function
+....................
+
Strobl, G. R.; Schneider, M. *J. Polym. Sci.* (1980), 18, 1343-1359
Koberstein, J.; Stein R. *J. Polym. Sci. Phys. Ed.* (1983), 21, 2181-2200
@@ -182,24 +229,45 @@ Baltá Calleja, F. J.; Vonk, C. G. *X-ray Scattering of Synthetic Poylmers*, Els
Baltá Calleja, F. J.; Vonk, C. G. *X-ray Scattering of Synthetic Poylmers*, Elsevier. Amsterdam (1989), 260-270
+Göschel, U.; Urban, G. *Polymer* (1995), 36, 3633-3639
+
+Stribeck, N. *X-Ray Scattering of Soft Matter*, Springer. Berlin (2007), 138-161
+
:ref:`FDR` (PDF format)
+Volume Fraction Profile
+.......................
+
+Washington, C.; King, S. M. *J. Phys. Chem.*, (1996), 100, 7603-7609
+
+Cosgrove, T.; King, S. M.; Griffiths, P. C. *Colloid-Polymer Interactions: From Fundamentals to Practice*, Wiley. New York (1999), 193-204
+
+King, S. M.; Griffiths, P. C.; Cosgrove, T. *Applications of Neutron Scattering to Soft Condensed Matter*, Gordon & Breach. Amsterdam (2000), 77-105
+
+King, S.; Griffiths, P.; Hone, J.; Cosgrove, T. *Macromol. Symp.* (2002), 190, 33-42
+
.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
Usage
-----
Upon sending data for correlation function analysis, it will be plotted (minus
-the background value), along with a *red* bar indicating the *upper end of the
-low-Q range* (used for back-extrapolation), and 2 *purple* bars indicating the range to be used for forward-extrapolation. These bars may be moved my clicking and
-dragging, or by entering appropriate values in the Q range input boxes.
+the background value), along with a *red* bar indicating the *upper end of the
+low-Q range* (used for Guinier back-extrapolation), and 2 *purple* bars indicating
+the range to be used for Porod forward-extrapolation. These bars may be moved by
+grabbing and dragging, or by entering appropriate values in the Q range input boxes.
.. figure:: tutorial1.png
:align: center
-Once the Q ranges have been set, click the "Calculate" button to determine the background level. Alternatively, enter your own value into the field. If the box turns yellow this indicates that background subtraction has resulted in some negative intensities.
+Once the Q ranges have been set, click the "Calculate Bg" button to determine the
+background level. Alternatively, enter your own value into the box. If the box turns
+yellow this indicates that background subtraction has created some negative intensities.
-Click the "Extrapolate" button to extrapolate the data and plot the extrapolation in the same figure. The values of the parameters used for the Guinier and Porod models will also be shown in the "Extrapolation Parameters" section of the window.
+Now click the "Extrapolate" button to extrapolate the data. The graph window will update
+to show the extrapolated data, and the values of the parameters used for the Guinier and
+Porod extrapolations will appear in the "Extrapolation Parameters" section of the SasView
+GUI.
.. figure:: tutorial2.png
:align: center
@@ -207,19 +275,24 @@ Click the "Extrapolate" button to extrapolate the data and plot the extrapolatio
Now select which type of transform you would like to perform, using the radio
buttons:
-* **Fourier** Perform a Fourier Transform to calculate the correlation
- function
-* **Hilbert** Perform a Hilbert Transform to calculate the volume fraction
+* **Fourier**: to perform a Fourier Transform to calculate the correlation
+ functions
+* **Hilbert**: to perform a Hilbert Transform to calculate the volume fraction
profile
-Click the "Transform" button to perform the selected transform and plot
-the result in a new graph window.
-
-If a Fourier Transform was performed, the "Compute Parameters" button can now be clicked to interpret the correlation function as described earlier.
+and click the "Transform" button to perform the selected transform and plot
+the results.
.. figure:: tutorial3.png
:align: center
-
+If a Fourier Transform was performed, the "Compute Parameters" button can now be
+clicked to interpret the correlation function as described earlier. The parameters
+will appear in the "Output Parameters" section of the SasView GUI.
+
+ .. figure:: tutorial4.png
+ :align: center
+
+
.. note::
- This help document was last changed by Steve King, 08Oct2016
+ This help document was last changed by Steve King, 26Sep2017
diff --git a/src/sas/sasgui/perspectives/corfunc/media/fdr-pdfs.rst b/src/sas/sasgui/perspectives/corfunc/media/fdr-pdfs.rst
index 85396d0..5dd9011 100644
--- a/src/sas/sasgui/perspectives/corfunc/media/fdr-pdfs.rst
+++ b/src/sas/sasgui/perspectives/corfunc/media/fdr-pdfs.rst
@@ -1,10 +1,10 @@
-.. fdr-pdfs.rst
-
-.. _FDR:
-
-Fibre Diffraction Review References
-===================================
-
-:download:`Fibre_Diffraction_Review_1994_3_25-29.pdf <Fibre_Diffraction_Review_1994_3_25-29.pdf>`
-:download:`Fibre_Diffraction_Review_2004_12_24.pdf <Fibre_Diffraction_Review_2004_12_24.pdf>`
-:download:`Fibre_Diffraction_Review_2005_13_19-22.pdf <Fibre_Diffraction_Review_2005_13_19-22.pdf>`
+.. fdr-pdfs.rst
+
+.. _FDR:
+
+Fibre Diffraction Review References
+===================================
+
+:download:`Fibre_Diffraction_Review_1994_3_25-29.pdf <Fibre_Diffraction_Review_1994_3_25-29.pdf>`
+:download:`Fibre_Diffraction_Review_2004_12_24.pdf <Fibre_Diffraction_Review_2004_12_24.pdf>`
+:download:`Fibre_Diffraction_Review_2005_13_19-22.pdf <Fibre_Diffraction_Review_2005_13_19-22.pdf>`
diff --git a/src/sas/sasgui/perspectives/corfunc/media/fig1.gif b/src/sas/sasgui/perspectives/corfunc/media/fig1.gif
deleted file mode 100644
index 029461a..0000000
Binary files a/src/sas/sasgui/perspectives/corfunc/media/fig1.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/corfunc/media/fig1.png b/src/sas/sasgui/perspectives/corfunc/media/fig1.png
new file mode 100644
index 0000000..aadd63f
Binary files /dev/null and b/src/sas/sasgui/perspectives/corfunc/media/fig1.png differ
diff --git a/src/sas/sasgui/perspectives/corfunc/media/fig2.gif b/src/sas/sasgui/perspectives/corfunc/media/fig2.gif
deleted file mode 100644
index 6fc1a33..0000000
Binary files a/src/sas/sasgui/perspectives/corfunc/media/fig2.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/corfunc/media/fig2.png b/src/sas/sasgui/perspectives/corfunc/media/fig2.png
new file mode 100644
index 0000000..7832bf9
Binary files /dev/null and b/src/sas/sasgui/perspectives/corfunc/media/fig2.png differ
diff --git a/src/sas/sasgui/perspectives/corfunc/media/tutorial1.png b/src/sas/sasgui/perspectives/corfunc/media/tutorial1.png
index 78a2229..cef1876 100644
Binary files a/src/sas/sasgui/perspectives/corfunc/media/tutorial1.png and b/src/sas/sasgui/perspectives/corfunc/media/tutorial1.png differ
diff --git a/src/sas/sasgui/perspectives/corfunc/media/tutorial2.png b/src/sas/sasgui/perspectives/corfunc/media/tutorial2.png
index 495176f..d232998 100644
Binary files a/src/sas/sasgui/perspectives/corfunc/media/tutorial2.png and b/src/sas/sasgui/perspectives/corfunc/media/tutorial2.png differ
diff --git a/src/sas/sasgui/perspectives/corfunc/media/tutorial3.png b/src/sas/sasgui/perspectives/corfunc/media/tutorial3.png
index 4d8ab87..72bf8e5 100644
Binary files a/src/sas/sasgui/perspectives/corfunc/media/tutorial3.png and b/src/sas/sasgui/perspectives/corfunc/media/tutorial3.png differ
diff --git a/src/sas/sasgui/perspectives/corfunc/media/tutorial4.png b/src/sas/sasgui/perspectives/corfunc/media/tutorial4.png
new file mode 100644
index 0000000..f35fb18
Binary files /dev/null and b/src/sas/sasgui/perspectives/corfunc/media/tutorial4.png differ
diff --git a/src/sas/sasgui/perspectives/corfunc/plot_labels.py b/src/sas/sasgui/perspectives/corfunc/plot_labels.py
index 88b763c..2849711 100644
--- a/src/sas/sasgui/perspectives/corfunc/plot_labels.py
+++ b/src/sas/sasgui/perspectives/corfunc/plot_labels.py
@@ -3,5 +3,8 @@ IQ_DATA_LABEL = r"$I_{obs}(q) - Bg$"
IQ_EXTRAPOLATED_DATA_LABEL = r"$I_{extrap}(q)$"
GROUP_ID_TRANSFORM = r"$\Gamma(x)$"
-TRANSFORM_LABEL1 = r"$\Gamma1(x)$"
-TRANSFORM_LABEL3 = r"$\Gamma3(x)$"
+TRANSFORM_LABEL1 = r"$\Gamma_1(x)$"
+TRANSFORM_LABEL3 = r"$\Gamma_3(x)$"
+
+GROUP_ID_IDF = r"$g_1(x)$"
+IDF_LABEL = r"$g_1(x)$"
diff --git a/src/sas/sasgui/perspectives/file_converter/converter_panel.py b/src/sas/sasgui/perspectives/file_converter/converter_panel.py
index a33ec10..9ad5ee4 100644
--- a/src/sas/sasgui/perspectives/file_converter/converter_panel.py
+++ b/src/sas/sasgui/perspectives/file_converter/converter_panel.py
@@ -23,6 +23,7 @@ from sas.sasgui.guiframe.utils import check_float
from sas.sascalc.file_converter.cansas_writer import CansasWriter
from sas.sascalc.file_converter.otoko_loader import OTOKOLoader
from sas.sascalc.file_converter.bsl_loader import BSLLoader
+from sas.sascalc.file_converter.ascii2d_loader import ASCII2DLoader
from sas.sascalc.file_converter.nxcansas_writer import NXcanSASWriter
from sas.sascalc.dataloader.data_info import Detector
from sas.sascalc.dataloader.data_info import Sample
@@ -34,13 +35,13 @@ if sys.platform.count("win32") > 0:
PANEL_TOP = 0
_STATICBOX_WIDTH = 410
_BOX_WIDTH = 200
- PANEL_SIZE = 480
+ PANEL_SIZE = 520
FONT_VARIANT = 0
else:
PANEL_TOP = 60
_STATICBOX_WIDTH = 430
_BOX_WIDTH = 200
- PANEL_SIZE = 500
+ PANEL_SIZE = 540
FONT_VARIANT = 1
class ConverterPanel(ScrolledPanel, PanelBase):
@@ -91,11 +92,12 @@ class ConverterPanel(ScrolledPanel, PanelBase):
<SasData> elements, or to multiple CanSAS files, each with one
<SasData> element.
- :param frame_data: If single_file is true, an array of Data1D objects.
- If single_file is false, a dictionary of the form frame_number: Data1D.
+ :param frame_data: If single_file is true, an array of Data1D
+ objects. If single_file is false, a dictionary of the
+ form *{frame_number: Data1D}*.
:param filepath: Where to save the CanSAS file
- :param single_file: If true, array is saved as a single file, if false,
- each item in the array is saved to it's own file
+ :param single_file: If true, array is saved as a single file,
+ if false, each item in the array is saved to it's own file
"""
writer = CansasWriter()
entry_attrs = None
@@ -190,8 +192,7 @@ class ConverterPanel(ScrolledPanel, PanelBase):
:param filename: The header file to extract the data from
:return x_data: A 1D array containing all the x coordinates of the data
:return y_data: A 1D array containing all the y coordinates of the data
- :return frame_data: A dictionary of the form frame_number: data, where
- data is a 2D numpy array containing the intensity data
+ :return frame_data: A dictionary of the form *{frame_number: data}*, where data is a 2D numpy array containing the intensity data
"""
loader = BSLLoader(filename)
frames = [0]
@@ -351,6 +352,14 @@ class ConverterPanel(ScrolledPanel, PanelBase):
w = NXcanSASWriter()
w.write(frame_data, output_path)
+ def convert_2d_data(self, dataset):
+ metadata = self.get_metadata()
+ for key, value in metadata.iteritems():
+ setattr(dataset[0], key, value)
+
+ w = NXcanSASWriter()
+ w.write(dataset, self.output.GetPath())
+
def on_convert(self, event):
"""Called when the Convert button is clicked"""
if not self.validate_inputs():
@@ -366,18 +375,18 @@ class ConverterPanel(ScrolledPanel, PanelBase):
elif self.data_type == 'otoko':
qdata, iqdata = self.extract_otoko_data(self.q_input.GetPath())
self.convert_1d_data(qdata, iqdata)
+ elif self.data_type == 'ascii2d':
+ loader = ASCII2DLoader(self.iq_input.GetPath())
+ data = loader.load()
+ dataset = [data] # ASCII 2D only ever contains 1 frame
+ self.convert_2d_data(dataset)
else: # self.data_type == 'bsl'
dataset = self.extract_bsl_data(self.iq_input.GetPath())
if dataset is None:
# Cancelled by user
return
+ self.convert_2d_data(dataset)
- metadata = self.get_metadata()
- for key, value in metadata.iteritems():
- setattr(dataset[0], key, value)
-
- w = NXcanSASWriter()
- w.write(dataset, self.output.GetPath())
except Exception as ex:
msg = str(ex)
wx.PostEvent(self.parent.manager.parent,
@@ -398,7 +407,8 @@ class ConverterPanel(ScrolledPanel, PanelBase):
def validate_inputs(self):
msg = "You must select a"
- if self.q_input.GetPath() == '' and self.data_type != 'bsl':
+ if self.q_input.GetPath() == '' and self.data_type != 'bsl' \
+ and self.data_type != 'ascii2d':
msg += " Q Axis input file."
elif self.iq_input.GetPath() == '':
msg += "n Intensity input file."
@@ -471,7 +481,7 @@ class ConverterPanel(ScrolledPanel, PanelBase):
event.Skip()
dtype = event.GetEventObject().GetName()
self.data_type = dtype
- if dtype == 'bsl':
+ if dtype == 'bsl' or dtype == 'ascii2d':
self.q_input.SetPath("")
self.q_input.Disable()
self.output.SetWildcard("NXcanSAS HDF5 File (*.h5)|*.h5")
@@ -499,13 +509,15 @@ class ConverterPanel(ScrolledPanel, PanelBase):
vbox = wx.BoxSizer(wx.VERTICAL)
instructions = (
- "Select linked single column 1D ASCII files containing the Q-axis and "
- "Intensity-axis data, or 1D BSL/OTOKO files, or a 2D BSL/OTOKO file, "
- "then choose where to save the converted file, and click Convert.\n"
- "1D ASCII and BSL/OTOKO files can be converted to CanSAS (XML) or "
- "NXcanSAS (HDF5) formats. 2D BSL/OTOKO files can only be converted to "
- "the NXcanSAS format.\n"
- "Metadata can be optionally added for the CanSAS XML format."
+ "If converting a 1D dataset, select linked single-column ASCII files "
+ "containing the Q-axis and intensity-axis data, or a 1D BSL/OTOKO file."
+ " If converting 2D data, select an ASCII file in the ISIS 2D file "
+ "format, or a 2D BSL/OTOKO file. Choose where to save the converted "
+ "file and click convert.\n"
+ "One dimensional ASCII and BSL/OTOKO files can be converted to CanSAS "
+ "(XML) or NXcanSAS (HDF5) formats. Two dimensional datasets can only be"
+ " converted to the NXcanSAS format.\n"
+ "Metadata can also be optionally added to the output file."
)
instruction_label = wx.StaticText(self, -1, instructions,
@@ -525,17 +537,20 @@ class ConverterPanel(ScrolledPanel, PanelBase):
input_grid.Add(data_type_label, (y,0), (1,1),
wx.ALIGN_CENTER_VERTICAL, 5)
radio_sizer = wx.BoxSizer(wx.HORIZONTAL)
- ascii_btn = wx.RadioButton(self, -1, "ASCII", name="ascii",
+ ascii_btn = wx.RadioButton(self, -1, "ASCII 1D", name="ascii",
style=wx.RB_GROUP)
ascii_btn.Bind(wx.EVT_RADIOBUTTON, self.datatype_changed)
radio_sizer.Add(ascii_btn)
+ ascii2d_btn = wx.RadioButton(self, -1, "ASCII 2D", name="ascii2d")
+ ascii2d_btn.Bind(wx.EVT_RADIOBUTTON, self.datatype_changed)
+ radio_sizer.Add(ascii2d_btn)
otoko_btn = wx.RadioButton(self, -1, "BSL 1D", name="otoko")
otoko_btn.Bind(wx.EVT_RADIOBUTTON, self.datatype_changed)
radio_sizer.Add(otoko_btn)
- input_grid.Add(radio_sizer, (y,1), (1,1), wx.ALL, 5)
bsl_btn = wx.RadioButton(self, -1, "BSL 2D", name="bsl")
bsl_btn.Bind(wx.EVT_RADIOBUTTON, self.datatype_changed)
radio_sizer.Add(bsl_btn)
+ input_grid.Add(radio_sizer, (y,1), (1,1), wx.ALL, 5)
y += 1
q_label = wx.StaticText(self, -1, "Q-Axis Data: ")
@@ -548,7 +563,7 @@ class ConverterPanel(ScrolledPanel, PanelBase):
input_grid.Add(self.q_input, (y,1), (1,1), wx.ALL, 5)
y += 1
- iq_label = wx.StaticText(self, -1, "Intensity-Axis Data: ")
+ iq_label = wx.StaticText(self, -1, "Intensity Data: ")
input_grid.Add(iq_label, (y,0), (1,1), wx.ALIGN_CENTER_VERTICAL, 5)
self.iq_input = wx.FilePickerCtrl(self, -1,
@@ -646,7 +661,7 @@ class ConverterWindow(widget.CHILD_FRAME):
"""Displays ConverterPanel"""
def __init__(self, parent=None, title='File Converter', base=None,
- manager=None, size=(PANEL_SIZE * 1.05, PANEL_SIZE / 1.1),
+ manager=None, size=(PANEL_SIZE * 0.96, PANEL_SIZE * 0.9),
*args, **kwargs):
kwargs['title'] = title
kwargs['size'] = size
diff --git a/src/sas/sasgui/perspectives/file_converter/file_converter.py b/src/sas/sasgui/perspectives/file_converter/file_converter.py
index 48b303f..ad3500f 100644
--- a/src/sas/sasgui/perspectives/file_converter/file_converter.py
+++ b/src/sas/sasgui/perspectives/file_converter/file_converter.py
@@ -6,6 +6,8 @@ import logging
from sas.sasgui.guiframe.plugin_base import PluginBase
from sas.sasgui.perspectives.file_converter.converter_panel import ConverterWindow
+logger = logging.getLogger(__name__)
+
class Plugin(PluginBase):
"""
This class defines the interface for a Plugin class
@@ -14,7 +16,7 @@ class Plugin(PluginBase):
def __init__(self):
PluginBase.__init__(self, name="File Converter")
- logging.info("File Converter plug-in started")
+ logger.info("File Converter plug-in started")
self._sub_menu = "Tool"
self.converter_frame = None
@@ -22,7 +24,7 @@ class Plugin(PluginBase):
"""
Returns a set of menu entries
"""
- help_txt = "Convert single column ASCII data to CanSAS format"
+ help_txt = "Convert ASCII or BSL/OTOKO data to CanSAS or NXcanSAS formats"
return [("File Converter", help_txt, self.on_file_converter)]
def on_file_converter(self, event):
diff --git a/src/sas/sasgui/perspectives/file_converter/media/file_converter_help.rst b/src/sas/sasgui/perspectives/file_converter/media/file_converter_help.rst
index e7238e0..9a55b2f 100644
--- a/src/sas/sasgui/perspectives/file_converter/media/file_converter_help.rst
+++ b/src/sas/sasgui/perspectives/file_converter/media/file_converter_help.rst
@@ -17,6 +17,9 @@ Supported input file formats (examples may be found in the /test/convertible_fil
* Single-column ASCII data, with lines that end without any delimiter,
or with a comma or semi-colon delimiter
+* 2D `ISIS ASCII formatted
+ <http://www.isis.stfc.ac.uk/instruments/loq/software/
+ colette-ascii-file-format-descriptions9808.pdf>`_ data
* `1D BSL/OTOKO format
<http://www.diamond.ac.uk/Beamlines/Soft-Condensed-Matter/small-angle/
SAXS-Software/CCP13/BSL.html>`_ data
@@ -35,7 +38,7 @@ Using the Tool
--------------
1) Select the files containing your Q-axis and Intensity-axis data
-2) Choose whether the files are in ASCII, 1D BSL/OTOKO or 2D BSL/OTOKO format
+2) Choose whether the files are in ASCII 1D, ASCII 2D, 1D BSL/OTOKO or 2D BSL/OTOKO format
3) Choose where you would like to save the converted file
4) Optionally, input some metadata such as sample size, detector name, etc
5) Click *Convert* to save the converted file
@@ -46,7 +49,7 @@ Files With Multiple Frames
If a BSL/OTOKO file with multiple frames is selected for the Intensity-axis
file, a dialog will appear asking which frames you would like converted. You
may enter a start frame, end frame & increment, and all frames in that subset
-will be converted. For example, entering 0, 50 and 10 will convert frames 0,
+will be converted. For example, entering 0, 50 and 10 will convert frames 0,
10, 20, 30, 40 & 50.
To convert a single frame, enter the same value for first frame & last frame,
@@ -55,11 +58,11 @@ and 1 as the increment.
CanSAS XML files can become quite large when exporting multiple frames to a
single file, so there is an option in the *Select Frame* dialog to output each
frame to its own file. The single file option will produce one file with
-multiple `<SASdata>` elements. The multiple file option will output a separate
-file with one `<SASdata>` element for each frame. The frame number will also be
+multiple `<SASdata>` elements. The multiple file option will output a separate
+file with one `<SASdata>` element for each frame. The frame number will also be
appended to the file name.
-The multiple file option is not available when exporting to NXcanSAS because
+The multiple file option is not available when exporting to NXcanSAS because
the HDF5 format is more efficient at handling large amounts of data.
diff --git a/src/sas/sasgui/perspectives/fitting/__init__.py b/src/sas/sasgui/perspectives/fitting/__init__.py
index 9367b5b..9bde9b2 100644
--- a/src/sas/sasgui/perspectives/fitting/__init__.py
+++ b/src/sas/sasgui/perspectives/fitting/__init__.py
@@ -1,48 +1,45 @@
-PLUGIN_ID = "Fitting plug-in 1.0"
-import os
-from fitting import *
-from distutils.filelist import findall
-def get_data_path(media):
- """
- """
- # Check for data path in the package
- path = os.path.join(os.path.dirname(__file__), media)
- if os.path.isdir(path):
- return path
-
- # Check for data path next to exe/zip file.
- # If we are inside a py2exe zip file, we need to go up
- # to get to the directory containing
- # the media for this module
- path = os.path.dirname(__file__)
- #Look for maximum n_dir up of the current dir to find media
- n_dir = 12
- for i in range(n_dir):
- path, _ = os.path.split(path)
- media_path = os.path.join(path, media)
- if os.path.isdir(media_path):
- module_media_path = os.path.join(media_path, 'fitting_media')
- if os.path.isdir(module_media_path):
- return module_media_path
- return media_path
-
- raise RuntimeError('Could not find models media files')
-
-def data_files():
- """
- Return the data files associated with media.
-
- The format is a list of (directory, [files...]) pairs which can be
- used directly in setup(...,data_files=...) for setup.py.
-
- """
- data_files = []
- path = os.path.dirname(__file__)
- p_path = os.path.join(path, 'plugin_models')
- for f in findall(p_path):
- data_files.append(('plugin_models', [f]))
- # path = get_data_path(media="media")
- for f in findall(path):
- data_files.append(('media/fitting_media', [f]))
-
- return data_files
+PLUGIN_ID = "Fitting plug-in 1.0"
+import os
+from fitting import *
+from distutils.filelist import findall
+def get_data_path(media):
+ """
+ """
+ # Check for data path in the package
+ path = os.path.join(os.path.dirname(__file__), media)
+ if os.path.isdir(path):
+ return path
+
+ # Check for data path next to exe/zip file.
+ # If we are inside a py2exe zip file, we need to go up
+ # to get to the directory containing
+ # the media for this module
+ path = os.path.dirname(__file__)
+ #Look for maximum n_dir up of the current dir to find media
+ n_dir = 12
+ for i in range(n_dir):
+ path, _ = os.path.split(path)
+ media_path = os.path.join(path, media)
+ if os.path.isdir(media_path):
+ module_media_path = os.path.join(media_path, 'fitting_media')
+ if os.path.isdir(module_media_path):
+ return module_media_path
+ return media_path
+
+ raise RuntimeError('Could not find models media files')
+
+def data_files():
+ """
+ Return the data files associated with media.
+
+ The format is a list of (directory, [files...]) pairs which can be
+ used directly in setup(...,data_files=...) for setup.py.
+
+ """
+ data_files = []
+ # Note: windows installer requires the plugin_models directory
+ plugin_models = os.path.join(os.path.dirname(__file__), "plugin_models")
+ data_files.append(('plugin_models', findall(plugin_models)))
+ data_files.append(('media/fitting_media', findall(get_data_path("media"))))
+
+ return data_files
diff --git a/src/sas/sasgui/perspectives/fitting/basepage.py b/src/sas/sasgui/perspectives/fitting/basepage.py
index a5508c9..411e3c8 100644
--- a/src/sas/sasgui/perspectives/fitting/basepage.py
+++ b/src/sas/sasgui/perspectives/fitting/basepage.py
@@ -1,21 +1,33 @@
"""
Base Page for fitting
"""
+from __future__ import print_function
+
import sys
import os
-import wx
-import numpy
import time
import copy
import math
import json
import logging
import traceback
-
+from Queue import Queue
+from threading import Thread
from collections import defaultdict
+
+import numpy as np
+
+import wx
from wx.lib.scrolledpanel import ScrolledPanel
+from sasmodels.sasview_model import MultiplicationModel
from sasmodels.weights import MODELS as POLYDISPERSITY_MODELS
+from sasmodels.weights import GaussianDispersion
+
+from sas.sascalc.dataloader.data_info import Detector
+from sas.sascalc.dataloader.data_info import Source
+from sas.sascalc.fit.pagestate import PageState
+from sas.sascalc.fit.models import PLUGIN_NAME_BASE
from sas.sasgui.guiframe.panel_base import PanelBase
from sas.sasgui.guiframe.utils import format_number, check_float, IdList, \
@@ -27,12 +39,13 @@ from sas.sasgui.guiframe.dataFitting import Data2D
from sas.sasgui.guiframe.dataFitting import Data1D
from sas.sasgui.guiframe.dataFitting import check_data_validity
from sas.sasgui.guiframe.gui_style import GUIFRAME_ID
-from sas.sascalc.dataloader.data_info import Detector
-from sas.sascalc.dataloader.data_info import Source
-from sas.sasgui.perspectives.fitting.pagestate import PageState
from sas.sasgui.guiframe.CategoryInstaller import CategoryInstaller
from sas.sasgui.guiframe.documentation_window import DocumentationWindow
+from .report_dialog import ReportDialog
+from .utils import get_weight
+
+logger = logging.getLogger(__name__)
(PageInfoEvent, EVT_PAGE_INFO) = wx.lib.newevent.NewEvent()
(PreviousStateEvent, EVT_PREVIOUS_STATE) = wx.lib.newevent.NewEvent()
@@ -99,7 +112,7 @@ class BasicPage(ScrolledPanel, PanelBase):
self.uid = wx.NewId()
self.graph_id = None
# Q range for data set
- self.qmin_data_set = numpy.inf
+ self.qmin_data_set = np.inf
self.qmax_data_set = None
self.npts_data_set = 0
# Q range
@@ -149,7 +162,7 @@ class BasicPage(ScrolledPanel, PanelBase):
self.disp_cb_dict = {}
- # self.state = PageState(parent=parent)
+ # self.state = PageState()
# dictionary containing list of models
self.model_list_box = {}
@@ -196,8 +209,7 @@ class BasicPage(ScrolledPanel, PanelBase):
# check that the fit range is correct to plot the model again
self.fitrange = True
# Create memento to save the current state
- self.state = PageState(parent=self.parent,
- model=self.model, data=self.data)
+ self.state = PageState(model=self.model, data=self.data)
# flag to determine if state has change
self.state_change = False
# save customized array
@@ -237,6 +249,17 @@ class BasicPage(ScrolledPanel, PanelBase):
# layout
self.set_layout()
+ # Setting up a thread for the fitting
+ self.threaded_draw_queue = Queue()
+
+ self.draw_worker_thread = Thread(target = self._threaded_draw_worker,
+ args = (self.threaded_draw_queue,))
+ self.draw_worker_thread.setDaemon(True)
+ self.draw_worker_thread.start()
+
+ # And a home for the thread submission times
+ self.last_time_fit_submitted = 0.00
+
def set_index_model(self, index):
"""
Index related to this page
@@ -250,7 +273,7 @@ class BasicPage(ScrolledPanel, PanelBase):
"""
if not hasattr(self, "model_view"):
return
- toggle_mode_on = self.model_view.IsEnabled()
+ toggle_mode_on = self.model_view.IsEnabled() or self.data is None
if toggle_mode_on:
if self.enable2D and not check_data_validity(self.data):
self._create_default_2d_data()
@@ -277,8 +300,8 @@ class BasicPage(ScrolledPanel, PanelBase):
:warning: This data is never plotted.
"""
- x = numpy.linspace(start=self.qmin_x, stop=self.qmax_x,
- num=self.npts_x, endpoint=True)
+ x = np.linspace(start=self.qmin_x, stop=self.qmax_x,
+ num=self.npts_x, endpoint=True)
self.data = Data1D(x=x)
self.data.xaxis('\\rm{Q}', "A^{-1}")
self.data.yaxis('\\rm{Intensity}', "cm^{-1}")
@@ -294,17 +317,17 @@ class BasicPage(ScrolledPanel, PanelBase):
"""
if self.qmin_x >= 1.e-10:
- qmin = numpy.log10(self.qmin_x)
+ qmin = np.log10(self.qmin_x)
else:
qmin = -10.
if self.qmax_x <= 1.e10:
- qmax = numpy.log10(self.qmax_x)
+ qmax = np.log10(self.qmax_x)
else:
qmax = 10.
- x = numpy.logspace(start=qmin, stop=qmax,
- num=self.npts_x, endpoint=True, base=10.0)
+ x = np.logspace(start=qmin, stop=qmax,
+ num=self.npts_x, endpoint=True, base=10.0)
self.data = Data1D(x=x)
self.data.xaxis('\\rm{Q}', "A^{-1}")
self.data.yaxis('\\rm{Intensity}', "cm^{-1}")
@@ -340,25 +363,25 @@ class BasicPage(ScrolledPanel, PanelBase):
ymin = -qmax
qstep = self.npts_x
- x = numpy.linspace(start=xmin, stop=xmax, num=qstep, endpoint=True)
- y = numpy.linspace(start=ymin, stop=ymax, num=qstep, endpoint=True)
+ x = np.linspace(start=xmin, stop=xmax, num=qstep, endpoint=True)
+ y = np.linspace(start=ymin, stop=ymax, num=qstep, endpoint=True)
# use data info instead
- new_x = numpy.tile(x, (len(y), 1))
- new_y = numpy.tile(y, (len(x), 1))
+ new_x = np.tile(x, (len(y), 1))
+ new_y = np.tile(y, (len(x), 1))
new_y = new_y.swapaxes(0, 1)
# all data reuire now in 1d array
qx_data = new_x.flatten()
qy_data = new_y.flatten()
- q_data = numpy.sqrt(qx_data * qx_data + qy_data * qy_data)
+ q_data = np.sqrt(qx_data * qx_data + qy_data * qy_data)
# set all True (standing for unmasked) as default
- mask = numpy.ones(len(qx_data), dtype=bool)
+ mask = np.ones(len(qx_data), dtype=bool)
# store x and y bin centers in q space
x_bins = x
y_bins = y
self.data.source = Source()
- self.data.data = numpy.ones(len(mask))
- self.data.err_data = numpy.ones(len(mask))
+ self.data.data = np.ones(len(mask))
+ self.data.err_data = np.ones(len(mask))
self.data.qx_data = qx_data
self.data.qy_data = qy_data
self.data.q_data = q_data
@@ -493,30 +516,28 @@ class BasicPage(ScrolledPanel, PanelBase):
self._manager = manager
self.state.manager = manager
- def populate_box(self, model_dict):
+ def populate_box(self, model_list_box):
"""
Store list of model
- :param model_dict: dictionary containing list of models
-
+ :param model_list_box: dictionary containing categorized models
"""
- self.model_list_box = model_dict
- self.state.model_list_box = self.model_list_box
+ self.model_list_box = model_list_box
self.initialize_combox()
- def set_model_dictionary(self, model_dict):
+ def set_model_dictionary(self, model_dictionary):
"""
Store a dictionary linking model name -> model object
- :param model_dict: dictionary containing list of models
+ :param model_dictionary: dictionary containing all models
"""
- self.model_dict = model_dict
+ self.model_dictionary = model_dictionary
def initialize_combox(self):
"""
put default value in the combo box
"""
- if self.model_list_box is not None and len(self.model_list_box) > 0:
+ if self.model_list_box:
self._populate_box(self.structurebox,
self.model_list_box["Structure Factors"])
self.structurebox.Insert("None", 0, None)
@@ -615,8 +636,52 @@ class BasicPage(ScrolledPanel, PanelBase):
"""
# Get plot image from plotpanel
images, canvases = self.get_images()
- # get the report dialog
- self.state.report(images, canvases)
+ imgRAM, images, refs = self._build_plots_for_report(images, canvases)
+
+ # get the strings for report
+ report_str, text_str = self.state.report(fig_urls=refs)
+
+ # Show the dialog
+ report_list = [report_str, text_str, images]
+ dialog = ReportDialog(report_list, None, wx.ID_ANY, "")
+ dialog.Show()
+
+ def _build_plots_for_report(self, figs, canvases):
+ """
+ Build image state that wx.html understand
+ by plotting, putting it into wx.FileSystem image object
+ """
+ images = []
+ refs = []
+
+ # For no figures in the list, prepare empty plot
+ if figs is None or len(figs) == 0:
+ figs = [None]
+
+ # Loop over the list of figures
+ # use wx.MemoryFSHandler
+ imgRAM = wx.MemoryFSHandler()
+ for fig in figs:
+ if fig is not None:
+ ind = figs.index(fig)
+ canvas = canvases[ind]
+
+ # store the image in wx.FileSystem Object
+ wx.FileSystem.AddHandler(wx.MemoryFSHandler())
+
+ # index of the fig
+ ind = figs.index(fig)
+
+ # AddFile, image can be retrieved with 'memory:filename'
+ name = 'img_fit%s.png' % ind
+ refs.append('memory:' + name)
+ imgRAM.AddFile(name, canvas.bitmap, wx.BITMAP_TYPE_PNG)
+
+ # append figs
+ images.append(fig)
+
+ return imgRAM, images, refs
+
def on_save(self, event):
"""
@@ -655,10 +720,10 @@ class BasicPage(ScrolledPanel, PanelBase):
event.Skip()
# It seems MAC needs wxCallAfter
if event.GetId() == GUIFRAME_ID.COPYEX_ID:
- print "copy excel"
+ print("copy excel")
wx.CallAfter(self.get_copy_excel)
elif event.GetId() == GUIFRAME_ID.COPYLAT_ID:
- print "copy latex"
+ print("copy latex")
wx.CallAfter(self.get_copy_latex)
else:
wx.CallAfter(self.get_copy)
@@ -781,8 +846,8 @@ class BasicPage(ScrolledPanel, PanelBase):
weights.append(weight)
except Exception:
# Skip non-data lines
- logging.error(traceback.format_exc())
- return numpy.array(angles), numpy.array(weights)
+ logger.error(traceback.format_exc())
+ return np.array(angles), np.array(weights)
except:
raise
@@ -838,7 +903,6 @@ class BasicPage(ScrolledPanel, PanelBase):
self.state.enable_disp = self.enable_disp.GetValue()
self.state.disable_disp = self.disable_disp.GetValue()
- self.state.smearer = copy.deepcopy(self.current_smearer)
if hasattr(self, "enable_smearer"):
self.state.enable_smearer = \
copy.deepcopy(self.enable_smearer.GetValue())
@@ -854,7 +918,7 @@ class BasicPage(ScrolledPanel, PanelBase):
if len(self._disp_obj_dict) > 0:
for k, v in self._disp_obj_dict.iteritems():
- self.state._disp_obj_dict[k] = v.type
+ self.state.disp_obj_dict[k] = v.type
self.state.values = copy.deepcopy(self.values)
self.state.weights = copy.deepcopy(self.weights)
@@ -872,7 +936,7 @@ class BasicPage(ScrolledPanel, PanelBase):
self._copy_parameters_state(self.str_parameters,
self.state.str_parameters)
self._copy_parameters_state(self.orientation_params,
- self.state.orientation_params)
+ self.state.orientation_params)
self._copy_parameters_state(self.orientation_params_disp,
self.state.orientation_params_disp)
@@ -903,7 +967,6 @@ class BasicPage(ScrolledPanel, PanelBase):
self.state.enable_disp = self.enable_disp.GetValue()
self.state.disable_disp = self.disable_disp.GetValue()
- self.state.smearer = copy.deepcopy(self.current_smearer)
if hasattr(self, "enable_smearer"):
self.state.enable_smearer = \
copy.deepcopy(self.enable_smearer.GetValue())
@@ -927,11 +990,11 @@ class BasicPage(ScrolledPanel, PanelBase):
else:
try:
self.state.disp_cb_dict[k] = v.GetValue()
- except:
+ except Exception:
self.state.disp_cb_dict[k] = None
if len(self._disp_obj_dict) > 0:
for k, v in self._disp_obj_dict.iteritems():
- self.state._disp_obj_dict[k] = v.type
+ self.state.disp_obj_dict[k] = v.type
self.state.values = copy.deepcopy(self.values)
self.state.weights = copy.deepcopy(self.weights)
@@ -973,7 +1036,7 @@ class BasicPage(ScrolledPanel, PanelBase):
try:
# to support older version
category_pos = int(state.categorycombobox)
- except:
+ except Exception:
category_pos = 0
for ind_cat in range(self.categorybox.GetCount()):
if self.categorycombobox.GetString(ind_cat) == \
@@ -985,7 +1048,7 @@ class BasicPage(ScrolledPanel, PanelBase):
try:
# to support older version
formfactor_pos = int(state.formfactorcombobox)
- except:
+ except Exception:
formfactor_pos = 0
for ind_form in range(self.formfactorbox.GetCount()):
if self.formfactorbox.GetString(ind_form) == \
@@ -998,7 +1061,7 @@ class BasicPage(ScrolledPanel, PanelBase):
try:
# to support older version
structfactor_pos = int(state.structurecombobox)
- except:
+ except Exception:
structfactor_pos = 0
for ind_struct in range(self.structurebox.GetCount()):
if self.structurebox.GetString(ind_struct) == \
@@ -1165,15 +1228,14 @@ class BasicPage(ScrolledPanel, PanelBase):
self.categorybox.Select(category_pos)
self._show_combox(None)
- from models import PLUGIN_NAME_BASE
- if self.categorybox.GetValue() == CUSTOM_MODEL \
- and PLUGIN_NAME_BASE not in state.formfactorcombobox:
+ if (self.categorybox.GetValue() == CUSTOM_MODEL
+ and PLUGIN_NAME_BASE not in state.formfactorcombobox):
state.formfactorcombobox = \
PLUGIN_NAME_BASE + state.formfactorcombobox
formfactor_pos = 0
for ind_form in range(self.formfactorbox.GetCount()):
- if self.formfactorbox.GetString(ind_form) == \
- (state.formfactorcombobox):
+ if (self.formfactorbox.GetString(ind_form)
+ == state.formfactorcombobox):
formfactor_pos = int(ind_form)
break
@@ -1183,8 +1245,8 @@ class BasicPage(ScrolledPanel, PanelBase):
if state.structurecombobox is not None:
state.structurecombobox = unicode(state.structurecombobox)
for ind_struct in range(self.structurebox.GetCount()):
- if self.structurebox.GetString(ind_struct) == \
- (state.structurecombobox):
+ if (self.structurebox.GetString(ind_struct)
+ == state.structurecombobox):
structfactor_pos = int(ind_struct)
break
@@ -1235,7 +1297,7 @@ class BasicPage(ScrolledPanel, PanelBase):
self.dI_didata.SetValue(state.dI_didata)
self.dI_sqrdata.SetValue(state.dI_sqrdata)
self.dI_idata.SetValue(state.dI_idata)
- except:
+ except Exception:
# to support older state file formats
self.dI_noweight.SetValue(False)
self.dI_didata.SetValue(True)
@@ -1291,7 +1353,7 @@ class BasicPage(ScrolledPanel, PanelBase):
self.values = copy.deepcopy(state.values)
self.weights = copy.deepcopy(state.weights)
- for key, disp_type in state._disp_obj_dict.iteritems():
+ for key, disp_type in state.disp_obj_dict.iteritems():
# disp_model = disp
disp_model = POLYDISPERSITY_MODELS[disp_type]()
self._disp_obj_dict[key] = disp_model
@@ -1303,7 +1365,7 @@ class BasicPage(ScrolledPanel, PanelBase):
self.model._persistency_dict[key] = \
[state.values, state.weights]
except Exception:
- logging.error(traceback.format_exc())
+ logger.error(traceback.format_exc())
selection = self._find_polyfunc_selection(disp_model)
for list in self.fittable_param:
if list[1] == key and list[7] is not None:
@@ -1320,7 +1382,7 @@ class BasicPage(ScrolledPanel, PanelBase):
list[5].Disable()
list[6].Disable()
except Exception:
- logging.error(traceback.format_exc())
+ logger.error(traceback.format_exc())
# For array, disable all fixed params
if selection == 1:
for item in self.fixed_param:
@@ -1329,7 +1391,7 @@ class BasicPage(ScrolledPanel, PanelBase):
try:
item[2].Disable()
except Exception:
- logging.error(traceback.format_exc())
+ logger.error(traceback.format_exc())
def _selectDlg(self):
"""
@@ -1448,22 +1510,9 @@ class BasicPage(ScrolledPanel, PanelBase):
self.create_default_data()
self.state_change = True
self._draw_model()
- # Time delay has been introduced to prevent _handle error
- # on Windows
- # This part of code is executed when model is selected and
- # it's parameters are changed (with respect to previously
- # selected model). There are two Iq evaluations occuring one
- # after another and therefore there may be compilation error
- # if model is calculated for the first time.
- # This seems to be Windows only issue - haven't tested on Linux
- # though.The proper solution (other than time delay) requires
- # more fundemental code refatoring
- # Wojtek P. Nov 7, 2016
- if not ON_MAC:
- time.sleep(0.1)
self.Refresh()
- # logging.info("is_modified flag set to %g",is_modified)
+ # logger.info("is_modified flag set to %g",is_modified)
return is_modified
def _update_paramv_on_fit(self):
@@ -1538,7 +1587,7 @@ class BasicPage(ScrolledPanel, PanelBase):
# No data in the panel
try:
self.npts_x = float(self.Npts_total.GetValue())
- except:
+ except Exception:
flag = False
return flag
flag = True
@@ -1568,7 +1617,7 @@ class BasicPage(ScrolledPanel, PanelBase):
try:
self.save_current_state()
except Exception:
- logging.error(traceback.format_exc())
+ logger.error(traceback.format_exc())
return flag, is_modified
@@ -1579,10 +1628,9 @@ class BasicPage(ScrolledPanel, PanelBase):
if len(statelist) == 0 or len(listtorestore) == 0:
return
- for j in range(len(listtorestore)):
+ for item_page in listtorestore:
for param in statelist:
- if param[1] == listtorestore[j][1]:
- item_page = listtorestore[j]
+ if param[1] == item_page[1]:
item_page_info = param
if (item_page_info[1] == "theta" or item_page_info[1] ==
"phi") and not self._is_2D():
@@ -1628,11 +1676,8 @@ class BasicPage(ScrolledPanel, PanelBase):
listtorestore = copy.deepcopy(statelist)
- for j in range(len(listtorestore)):
- item_page = listtorestore[j]
- item_page_info = statelist[j]
+ for item_page, item_page_info in zip(listtorestore, statelist):
# change the state of the check box for simple parameters
-
if item_page[0] is not None:
item_page[0].SetValue(format_number(item_page_info[0], True))
@@ -1702,7 +1747,24 @@ class BasicPage(ScrolledPanel, PanelBase):
:param chisqr: update chisqr value [bool]
"""
- wx.CallAfter(self._draw_model_after, update_chisqr, source)
+ self.threaded_draw_queue.put([copy.copy(update_chisqr), copy.copy(source)])
+
+ def _threaded_draw_worker(self, threaded_draw_queue):
+ while True:
+ # sit and wait for the next task
+ next_task = threaded_draw_queue.get()
+
+ # sleep for 1/10th second in case some other tasks accumulate
+ time.sleep(0.1)
+
+ # skip all intermediate tasks
+ while self.threaded_draw_queue.qsize() > 0:
+ self.threaded_draw_queue.task_done()
+ next_task = self.threaded_draw_queue.get()
+
+ # and finally, do the task
+ self._draw_model_after(*next_task)
+ threaded_draw_queue.task_done()
def _draw_model_after(self, update_chisqr=True, source='model'):
"""
@@ -1720,11 +1782,11 @@ class BasicPage(ScrolledPanel, PanelBase):
if not self.disable_smearer.GetValue():
temp_smear = self.current_smearer
# compute weight for the current data
- from sas.sasgui.perspectives.fitting.utils import get_weight
flag = self.get_weight_flag()
weight = get_weight(data=self.data, is2d=self._is_2D(), flag=flag)
toggle_mode_on = self.model_view.IsEnabled()
is_2d = self._is_2D()
+
self._manager.draw_model(self.model,
data=self.data,
smearer=temp_smear,
@@ -1746,7 +1808,6 @@ class BasicPage(ScrolledPanel, PanelBase):
x, y = self.model.getProfile()
from sas.sasgui.plottools import Data1D as pf_data1d
- # from sas.sasgui.perspectives.theory.profile_dialog import SLDPanel
from sas.sasgui.guiframe.local_perspectives.plotting.profile_dialog \
import SLDPanel
sld_data = pf_data1d(x, y)
@@ -1807,12 +1868,12 @@ class BasicPage(ScrolledPanel, PanelBase):
try:
if mod_cat == CUSTOM_MODEL:
for model in self.model_list_box[mod_cat]:
- m_list.append(self.model_dict[model.name])
+ m_list.append(self.model_dictionary[model.name])
else:
cat_dic = self.master_category_dict[mod_cat]
- for (model, enabled) in cat_dic:
+ for model, enabled in cat_dic:
if enabled:
- m_list.append(self.model_dict[model])
+ m_list.append(self.model_dictionary[model])
except Exception:
msg = traceback.format_exc()
wx.PostEvent(self._manager.parent,
@@ -1850,7 +1911,6 @@ class BasicPage(ScrolledPanel, PanelBase):
for models in list:
if models.name != "NoStructure":
mlist.append((models.name, models))
-
# Sort the models
mlist_sorted = sorted(mlist)
for item in mlist_sorted:
@@ -1885,7 +1945,7 @@ class BasicPage(ScrolledPanel, PanelBase):
sys.exc_info()[1]
wx.PostEvent(self.parent, StatusEvent(status=msg))
return
- except:
+ except Exception:
tcrtl.SetBackgroundColour("pink")
msg = "Model Error: wrong value entered: %s" % sys.exc_info()[1]
wx.PostEvent(self.parent, StatusEvent(status=msg))
@@ -1942,7 +2002,7 @@ class BasicPage(ScrolledPanel, PanelBase):
sys.exc_info()[1]
wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
return
- except:
+ except Exception:
tcrtl.SetBackgroundColour("pink")
msg = "Model Error: wrong value entered: %s" % sys.exc_info()[1]
wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
@@ -2042,7 +2102,6 @@ class BasicPage(ScrolledPanel, PanelBase):
struct_factor = self.structurebox.GetClientData(s_id)
if struct_factor is not None:
- from sasmodels.sasview_model import MultiplicationModel
self.model = MultiplicationModel(form_factor(self.multi_factor),
struct_factor())
# multifunctional form factor
@@ -2119,13 +2178,13 @@ class BasicPage(ScrolledPanel, PanelBase):
return flag
for data in self.data_list:
# q value from qx and qy
- radius = numpy.sqrt(data.qx_data * data.qx_data +
- data.qy_data * data.qy_data)
+ radius = np.sqrt(data.qx_data * data.qx_data +
+ data.qy_data * data.qy_data)
# get unmasked index
index_data = (float(self.qmin.GetValue()) <= radius) & \
(radius <= float(self.qmax.GetValue()))
index_data = (index_data) & (data.mask)
- index_data = (index_data) & (numpy.isfinite(data.data))
+ index_data = (index_data) & (np.isfinite(data.data))
if len(index_data[index_data]) < 10:
# change the color pink.
@@ -2160,7 +2219,7 @@ class BasicPage(ScrolledPanel, PanelBase):
# get unmasked index
index_data = (float(self.qmin.GetValue()) <= radius) & \
(radius <= float(self.qmax.GetValue()))
- index_data = (index_data) & (numpy.isfinite(data.y))
+ index_data = (index_data) & (np.isfinite(data.y))
if len(index_data[index_data]) < 5:
# change the color pink.
@@ -2232,8 +2291,8 @@ class BasicPage(ScrolledPanel, PanelBase):
continue
# Check that min is less than max
- low = -numpy.inf if min_str == "" else float(min_str)
- high = numpy.inf if max_str == "" else float(max_str)
+ low = -np.inf if min_str == "" else float(min_str)
+ high = np.inf if max_str == "" else float(max_str)
if high < low:
min_ctrl.SetBackgroundColour("pink")
min_ctrl.Refresh()
@@ -2349,7 +2408,7 @@ class BasicPage(ScrolledPanel, PanelBase):
"""
put gaussian dispersity into current model
"""
- if len(self.param_toFit) > 0:
+ if self.param_toFit:
for item in self.fittable_param:
if item in self.param_toFit:
self.param_toFit.remove(item)
@@ -2364,14 +2423,9 @@ class BasicPage(ScrolledPanel, PanelBase):
self.values = {}
self.weights = {}
- # from sas.models.dispersion_models import GaussianDispersion
- from sasmodels.weights import GaussianDispersion
- if len(self.disp_cb_dict) == 0:
- self.save_current_state()
+ if not self.disp_cb_dict:
self.sizer4_4.Clear(True)
- self.Layout()
- return
- if (len(self.disp_cb_dict) > 0):
+ else:
for p in self.disp_cb_dict:
# The parameter was un-selected.
# Go back to Gaussian model (with 0 pts)
@@ -2383,7 +2437,7 @@ class BasicPage(ScrolledPanel, PanelBase):
try:
self.model.set_dispersion(p, disp_model)
except Exception:
- logging.error(traceback.format_exc())
+ logger.error(traceback.format_exc())
# save state into
self.save_current_state()
@@ -2444,7 +2498,7 @@ class BasicPage(ScrolledPanel, PanelBase):
# self._reset_array_disp(param_name)
self._disp_obj_dict[name1] = disp_model
self.model.set_dispersion(param_name, disp_model)
- self.state._disp_obj_dict[name1] = disp_model.type
+ self.state.disp_obj_dict[name1] = disp_model.type
value1 = str(format_number(self.model.getParam(name1), True))
value2 = str(format_number(self.model.getParam(name2)))
@@ -2498,7 +2552,7 @@ class BasicPage(ScrolledPanel, PanelBase):
self._draw_model()
self.Refresh()
except Exception:
- logging.error(traceback.format_exc())
+ logger.error(traceback.format_exc())
# Error msg
msg = "Error occurred:"
msg += " Could not select the distribution function..."
@@ -2559,7 +2613,7 @@ class BasicPage(ScrolledPanel, PanelBase):
disp.set_weights(values, weights)
self._disp_obj_dict[name] = disp
self.model.set_dispersion(name.split('.')[0], disp)
- self.state._disp_obj_dict[name] = disp.type
+ self.state.disp_obj_dict[name] = disp.type
self.values[name] = values
self.weights[name] = weights
# Store the object to make it persist outside the
@@ -2599,7 +2653,7 @@ class BasicPage(ScrolledPanel, PanelBase):
del self.model._persistency_dict[name.split('.')[0]]
del self.state.model._persistency_dict[name.split('.')[0]]
except Exception:
- logging.error(traceback.format_exc())
+ logger.error(traceback.format_exc())
def _lay_out(self):
"""
@@ -2608,19 +2662,9 @@ class BasicPage(ScrolledPanel, PanelBase):
:Note: Mac seems to like this better when self.
Layout is called after fitting.
"""
- self._sleep4sec()
self.Layout()
return
- def _sleep4sec(self):
- """
- sleep for 1 sec only applied on Mac
- Note: This 1sec helps for Mac not to crash on self.
- Layout after self._draw_model
- """
- if ON_MAC:
- time.sleep(1)
-
def _find_polyfunc_selection(self, disp_func=None):
"""
FInd Comboox selection from disp_func
@@ -2653,7 +2697,7 @@ class BasicPage(ScrolledPanel, PanelBase):
y = max(math.fabs(self.data.ymin), math.fabs(self.data.ymax))
self.qmin_x = data_min
self.qmax_x = math.sqrt(x * x + y * y)
- # self.data.mask = numpy.ones(len(self.data.data),dtype=bool)
+ # self.data.mask = np.ones(len(self.data.data),dtype=bool)
# check smearing
if not self.disable_smearer.GetValue():
# set smearing value whether or
@@ -2741,7 +2785,7 @@ class BasicPage(ScrolledPanel, PanelBase):
canvases.append(item2.canvas)
except Exception:
# Not for control panels
- logging.error(traceback.format_exc())
+ logger.error(traceback.format_exc())
# Make sure the resduals plot goes to the last
if res_item is not None:
graphs.append(res_item[0])
@@ -2771,7 +2815,7 @@ class BasicPage(ScrolledPanel, PanelBase):
_doc_viewer = DocumentationWindow(self, wx.ID_ANY, _TreeLocation,
"", name + " Help")
else:
- _TreeLocation = 'user/index.html'
+ _TreeLocation = 'user/sasgui/perspectives/fitting/models/index.html'
_doc_viewer = DocumentationWindow(self, wx.ID_ANY, _TreeLocation,
"", "General Model Help")
@@ -2808,7 +2852,7 @@ class BasicPage(ScrolledPanel, PanelBase):
def _on_mag_angle_help(self, event):
"""
- Bring up Magnetic Angle definition bmp image whenever the ? button
+ Bring up Magnetic Angle definition.png image whenever the ? button
is clicked. Calls DocumentationWindow with the path of the location
within the documentation tree (after /doc/ ....". When using old
versions of Wx (i.e. before 2.9 and therefore not part of release
@@ -2822,13 +2866,13 @@ class BasicPage(ScrolledPanel, PanelBase):
:param evt: Triggers on clicking ? in Magnetic Angles? box
"""
- _TreeLocation = "_images/M_angles_pic.bmp"
+ _TreeLocation = "_images/M_angles_pic.png"
_doc_viewer = DocumentationWindow(self, wx.ID_ANY, _TreeLocation, "",
"Magnetic Angle Defintions")
def _on_mag_help(self, event):
"""
- Bring up Magnetic Angle definition bmp image whenever the ? button
+ Bring up Magnetic Angle definition.png image whenever the ? button
is clicked. Calls DocumentationWindow with the path of the location
within the documentation tree (after /doc/ ....". When using old
versions of Wx (i.e. before 2.9 and therefore not part of release
@@ -2842,7 +2886,7 @@ class BasicPage(ScrolledPanel, PanelBase):
:param evt: Triggers on clicking ? in Magnetic Angles? box
"""
- _TreeLocation = "user/magnetism.html"
+ _TreeLocation = "user/sasgui/perspectives/fitting/magnetism/magnetism.html"
_doc_viewer = DocumentationWindow(self, wx.ID_ANY, _TreeLocation, "",
"Polarized Beam/Magnetc Help")
@@ -2888,7 +2932,7 @@ class BasicPage(ScrolledPanel, PanelBase):
:param event: Triggers on clicking ? in polydispersity box
"""
- _TreeLocation = "user/sasgui/perspectives/fitting/pd_help.html"
+ _TreeLocation = "user/sasgui/perspectives/fitting/pd/polydispersity.html"
_PageAnchor = ""
_doc_viewer = DocumentationWindow(self, wx.ID_ANY, _TreeLocation,
_PageAnchor, "Polydispersity Help")
@@ -2927,27 +2971,62 @@ class BasicPage(ScrolledPanel, PanelBase):
# go through the parameters
strings = self._get_copy_helper(self.parameters,
- self.orientation_params)
+ self.orientation_params)
content += strings
# go through the fittables
strings = self._get_copy_helper(self.fittable_param,
- self.orientation_params_disp)
+ self.orientation_params_disp)
content += strings
# go through the fixed params
strings = self._get_copy_helper(self.fixed_param,
- self.orientation_params_disp)
+ self.orientation_params_disp)
content += strings
# go through the str params
strings = self._get_copy_helper(self.str_parameters,
- self.orientation_params)
+ self.orientation_params)
content += strings
return content
else:
return False
+
+ def _get_copy_params_details(self):
+ """
+ Combines polydisperse parameters with self.parameters so that they can
+ be written to the clipboard (for Excel or LaTeX). Also returns a list of
+ the names of parameters that have been fitted
+
+ :returns: all_params - A list of all parameters, in the format of
+ self.parameters
+ :returns: fitted_par_names - A list of the names of parameters that have
+ been fitted
+ """
+ # Names of params that are being fitted
+ fitted_par_names = [param[1] for param in self.param_toFit]
+ # Names of params with associated polydispersity
+ disp_params = [param[1].split('.')[0] for param in self.fittable_param]
+
+ # Create array of all parameters
+ all_params = copy.copy(self.parameters)
+ for param in self.parameters:
+ if param[1] in disp_params:
+ # Polydisperse params aren't in self.parameters, so need adding
+ # to all_params
+ name = param[1] + ".width"
+ index = all_params.index(param) + 1
+ to_insert = []
+ if name in fitted_par_names:
+ # Param is fitted, so already has a param list in self.param_toFit
+ to_insert = self.param_toFit[fitted_par_names.index(name)]
+ else:
+ # Param isn't fitted, so mockup a param list
+ to_insert = [None, name, self.model.getParam(name), None, None]
+ all_params.insert(index, to_insert)
+ return all_params, fitted_par_names
+
def get_copy_excel(self):
"""
Get copy params to clipboard
@@ -2961,32 +3040,45 @@ class BasicPage(ScrolledPanel, PanelBase):
"""
Get the string copies of the param names and values in the tap
"""
- content = ''
+ if not self.parameters:
+ # Do nothing if parameters doesn't exist
+ return False
+ content = ''
crlf = chr(13) + chr(10)
tab = chr(9)
- # Do it if params exist
- if self.parameters:
+ all_params, fitted_param_names = self._get_copy_params_details()
- for param in self.parameters:
- content += param[1] # parameter name
- content += tab
- content += param[1] + "_err"
+ # Construct row of parameter names
+ for param in all_params:
+ name = param[1] # Parameter name
+ content += name
+ content += tab
+ if name in fitted_param_names:
+ # Only print errors for fitted parameters
+ content += name + "_err"
content += tab
- content += crlf
+ content += crlf
- # row of values and errors...
- for param in self.parameters:
- content += param[2].GetValue() # value
- content += tab
- content += param[4].GetValue() # error
+ # Construct row of parameter values and errors
+ for param in all_params:
+ value = param[2]
+ if hasattr(value, 'GetValue'):
+ # param[2] is a text box
+ value = value.GetValue()
+ else:
+ # param[2] is a float (from our self._get_copy_params_details)
+ value = str(value)
+ content += value
+ content += tab
+ if param[1] in fitted_param_names:
+ # Only print errors for fitted parameters
+ content += param[4].GetValue()
content += tab
- return content
- else:
- return False
+ return content
def get_copy_latex(self):
"""
@@ -3001,45 +3093,61 @@ class BasicPage(ScrolledPanel, PanelBase):
"""
Get the string copies of the param names and values in the tap
"""
- content = '\\begin{table}'
- content += '\\begin{tabular}[h]'
+ if not self.parameters:
+ # Do nothing if self.parameters doesn't exist
+ return False
+
+ content = r'\begin{table}'
+ content += r'\begin{tabular}[h]'
crlf = chr(13) + chr(10)
tab = chr(9)
- # Do it if params exist
- if self.parameters:
+ all_params, fitted_param_names = self._get_copy_params_details()
- content += '{|'
- for param in self.parameters:
- content += 'l|l|'
- content += '}\hline'
- content += crlf
+ content += '{|'
+ for param in all_params:
+ content += 'l|l|'
+ content += r'}\hline'
+ content += crlf
- for index, param in enumerate(self.parameters):
- content += param[1].replace('_', '\_') # parameter name
+ # Construct row of parameter names
+ for index, param in enumerate(all_params):
+ name = param[1] # Parameter name
+ content += name.replace('_', r'\_') # Escape underscores
+ if name in fitted_param_names:
+ # Only print errors for fitted parameters
content += ' & '
- content += param[1].replace('_', '\_') + "\_err"
- if index < len(self.parameters) - 1:
- content += ' & '
- content += '\\\\ \\hline'
- content += crlf
-
- # row of values and errors...
- for index, param in enumerate(self.parameters):
- content += param[2].GetValue() # parameter value
+ content += name.replace('_', r'\_') + r"\_err"
+ if index < len(all_params) - 1:
content += ' & '
- content += param[4].GetValue() # parameter error
- if index < len(self.parameters) - 1:
- content += ' & '
- content += '\\\\ \\hline'
- content += crlf
-
- content += '\\end{tabular}'
- content += '\\end{table}'
- return content
- else:
- return False
+
+ content += r'\\ \hline'
+ content += crlf
+
+ # Construct row of values and errors
+ for index, param in enumerate(all_params):
+ value = param[2]
+ if hasattr(value, "GetValue"):
+ # value is a text box
+ value = value.GetValue()
+ else:
+ # value is a float (from self._get_copy_params_details)
+ value = str(value)
+ content += value
+ if param[1] in fitted_param_names:
+ # Only print errors for fitted params
+ content += ' & '
+ content += param[4].GetValue()
+ if index < len(all_params) - 1:
+ content += ' & '
+
+ content += r'\\ \hline'
+ content += crlf
+ content += r'\end{tabular}'
+ content += r'\end{table}'
+
+ return content
def set_clipboard(self, content=None):
"""
@@ -3074,7 +3182,7 @@ class BasicPage(ScrolledPanel, PanelBase):
if item[7].__class__.__name__ == 'ComboBox':
disfunc = str(item[7].GetValue())
except Exception:
- logging.error(traceback.format_exc())
+ logger.error(traceback.format_exc())
# 2D
if self.data.__class__.__name__ == "Data2D":
@@ -3117,7 +3225,7 @@ class BasicPage(ScrolledPanel, PanelBase):
for weight in self.weights[name]:
disfunc += ' ' + str(weight)
except Exception:
- logging.error(traceback.format_exc())
+ logger.error(traceback.format_exc())
content += name + ',' + str(check) + ',' + value + disfunc + ',' + \
bound_lo + ',' + bound_hi + ':'
@@ -3294,7 +3402,7 @@ class BasicPage(ScrolledPanel, PanelBase):
pd = float(pd)
if name.endswith('.npts'):
pd = int(pd)
- except:
+ except Exception:
# continue
if not pd and pd != '':
continue
@@ -3365,8 +3473,8 @@ class BasicPage(ScrolledPanel, PanelBase):
disp_model = dispersity()
if value[1] == 'array':
- pd_vals = numpy.array(value[2])
- pd_weights = numpy.array(value[3])
+ pd_vals = np.array(value[2])
+ pd_weights = np.array(value[3])
if len(pd_vals) == 0 or len(pd_vals) != len(pd_weights):
msg = ("bad array distribution parameters for %s"
% param_name)
@@ -3380,7 +3488,7 @@ class BasicPage(ScrolledPanel, PanelBase):
self._set_disp_cb(False, item=item)
self._disp_obj_dict[name] = disp_model
self.model.set_dispersion(param_name, disp_model)
- self.state._disp_obj_dict[name] = disp_model.type
+ self.state.disp_obj_dict[name] = disp_model.type
# TODO: It's not an array, why update values and weights?
self.model._persistency_dict[param_name] = \
[self.values, self.weights]
@@ -3388,9 +3496,9 @@ class BasicPage(ScrolledPanel, PanelBase):
self.state.weights = self.weights
except Exception:
- logging.error(traceback.format_exc())
- print "Error in BasePage._paste_poly_help: %s" % \
- sys.exc_info()[1]
+ logger.error(traceback.format_exc())
+ print("Error in BasePage._paste_poly_help: %s" % \
+ sys.exc_info()[1])
def _set_disp_cb(self, isarray, item):
"""
@@ -3419,7 +3527,7 @@ class BasicPage(ScrolledPanel, PanelBase):
Method to be called by sub-classes
Moveit; This method doesn't belong here
"""
- print "BasicPage.update_pinhole_smear was called: skipping"
+ print("BasicPage.update_pinhole_smear was called: skipping")
return
def _read_category_info(self):
@@ -3480,15 +3588,15 @@ class BasicPage(ScrolledPanel, PanelBase):
return
self.model_box.Clear()
- if category == 'Plugin Models':
+ if category == CUSTOM_MODEL:
for model in self.model_list_box[category]:
str_m = str(model).split(".")[0]
self.model_box.Append(str_m)
else:
- for (model, enabled) in sorted(self.master_category_dict[category],
- key=lambda name: name[0]):
- if(enabled):
+ for model, enabled in sorted(self.master_category_dict[category],
+ key=lambda name: name[0]):
+ if enabled:
self.model_box.Append(model)
def _fill_model_sizer(self, sizer):
@@ -3595,7 +3703,7 @@ class BasicPage(ScrolledPanel, PanelBase):
wx.EVT_COMBOBOX(self.multifactorbox, wx.ID_ANY, self._on_select_model)
# check model type to show sizer
if self.model is not None:
- print "_set_model_sizer_selection: disabled."
+ print("_set_model_sizer_selection: disabled.")
# self._set_model_sizer_selection(self.model)
sizer_selection.Add(self.text1)
@@ -3729,12 +3837,12 @@ class ModelTextCtrl(wx.TextCtrl):
if set_focus_callback is None else set_focus_callback
self.Bind(wx.EVT_SET_FOCUS, self._on_set_focus)
self.Bind(wx.EVT_KILL_FOCUS, self._silent_kill_focus
- if kill_focus_callback is None else kill_focus_callback)
+ if kill_focus_callback is None else kill_focus_callback)
self.Bind(wx.EVT_TEXT_ENTER, parent._onparamEnter
- if text_enter_callback is None else text_enter_callback)
+ if text_enter_callback is None else text_enter_callback)
if not ON_MAC:
self.Bind(wx.EVT_LEFT_UP, self._highlight_text
- if mouse_up_callback is None else mouse_up_callback)
+ if mouse_up_callback is None else mouse_up_callback)
def _on_set_focus(self, event):
"""
@@ -3774,4 +3882,4 @@ class ModelTextCtrl(wx.TextCtrl):
"""
event.Skip()
- # pass
+ # pass
\ No newline at end of file
diff --git a/src/sas/sasgui/perspectives/fitting/batchfitpage.py b/src/sas/sasgui/perspectives/fitting/batchfitpage.py
index 5089da6..143bd7f 100644
--- a/src/sas/sasgui/perspectives/fitting/batchfitpage.py
+++ b/src/sas/sasgui/perspectives/fitting/batchfitpage.py
@@ -4,8 +4,14 @@ Batch panel
import wx
import wx.lib.newevent
import math
+
+from sas.sascalc.fit.qsmearing import smear_selection
+
from sas.sasgui.guiframe.events import StatusEvent
from sas.sasgui.guiframe.events import NewPlotEvent
+from sas.sasgui.perspectives.fitting.basepage import PageInfoEvent
+from sas.sasgui.perspectives.fitting.fitpage import FitPage
+from sas.sasgui.perspectives.fitting.fitpage import check_data_validity
(Chi2UpdateEvent, EVT_CHI2_UPDATE) = wx.lib.newevent.NewEvent()
_BOX_WIDTH = 76
@@ -13,11 +19,6 @@ _DATA_BOX_WIDTH = 300
SMEAR_SIZE_L = 0.00
SMEAR_SIZE_H = 0.00
-from sas.sasgui.perspectives.fitting.basepage import PageInfoEvent
-from sas.sascalc.data_util.qsmearing import smear_selection
-from sas.sasgui.perspectives.fitting.fitpage import FitPage
-from sas.sasgui.perspectives.fitting.fitpage import check_data_validity
-
class BatchFitPage(FitPage):
"""
Batch Page
@@ -75,117 +76,117 @@ class BatchFitPage(FitPage):
# add access to npts
# """
# is_2Ddata = False
-#
+#
# # Check if data is 2D
# if self.data.__class__.__name__ == "Data2D" or \
# self.enable2D:
# is_2Ddata = True
-#
-# title = "Fitting"
+#
+# title = "Fitting"
# self._get_smear_info()
-#
+#
# #Sizers
# box_description_range = wx.StaticBox(self, wx.ID_ANY, str(title))
-# boxsizer_range = wx.StaticBoxSizer(box_description_range, wx.VERTICAL)
+# boxsizer_range = wx.StaticBoxSizer(box_description_range, wx.VERTICAL)
# self.sizer_set_smearer = wx.BoxSizer(wx.VERTICAL)
# #sizer_smearer = wx.BoxSizer(wx.HORIZONTAL)
# self.sizer_new_smear = wx.BoxSizer(wx.HORIZONTAL)
# self.sizer_set_masking = wx.BoxSizer(wx.HORIZONTAL)
# sizer_chi2 = wx.BoxSizer(wx.VERTICAL)
-#
+#
# sizer_fit = wx.GridSizer(2, 4, 2, 6)
# #Fit button
# self.btFit = wx.Button(self, self._ids.next(), 'Fit', size=(88, 25))
# self.default_bt_colour = self.btFit.GetDefaultAttributes()
# self.btFit.Bind(wx.EVT_BUTTON, self._onFit, id= self.btFit.GetId())
# self.btFit.SetToolTipString("Start fitting.")
-#
+#
# # Update and Draw button
# self.draw_button = wx.Button(self, self._ids.next(), 'Compute', size=(88, 24))
# self.draw_button.Bind(wx.EVT_BUTTON, \
# self._onDraw,id=self.draw_button.GetId())
-# self.draw_button.SetToolTipString("Compute and Draw.")
+# self.draw_button.SetToolTipString("Compute and Draw.")
# sizer_fit.Add(self.draw_button, 0, 0)
-# sizer_fit.Add(self.btFit, 0, 0)
+# sizer_fit.Add(self.btFit, 0, 0)
# sizer_chi2.Add((-1, 5))
# # get smear_selection
# self.current_smearer = smear_selection( self.data, self.model )
# boxsizer_range.Add(self.sizer_set_masking)
# #2D data? default
# is_2Ddata = False
-#
+#
# #check if it is 2D data
# if self.data.__class__.__name__ == "Data2D" or \
# self.enable2D:
# is_2Ddata = True
-#
+#
# self.sizer5.Clear(True)
-#
+#
# self.qmin = ModelTextCtrl(self, wx.ID_ANY, size=(_BOX_WIDTH, 20),
-# style=wx.TE_PROCESS_ENTER,
+# style=wx.TE_PROCESS_ENTER,
# text_enter_callback = self._onQrangeEnter)
# self.qmin.SetValue(str(self.qmin_x))
# self.qmin.SetToolTipString("Minimun value of Q in linear scale.")
-#
+#
# self.qmax = ModelTextCtrl(self, wx.ID_ANY, size=(_BOX_WIDTH, 20),
-# style=wx.TE_PROCESS_ENTER,
+# style=wx.TE_PROCESS_ENTER,
# text_enter_callback=self._onQrangeEnter)
# self.qmax.SetValue(str(self.qmax_x))
# self.qmax.SetToolTipString("Maximum value of Q in linear scale.")
-#
+#
# id = self._ids.next()
# self.reset_qrange =wx.Button(self, id, 'Reset', size=(77, 20))
-#
+#
# self.reset_qrange.Bind(wx.EVT_BUTTON, self.on_reset_clicked, id=id)
# self.reset_qrange.SetToolTipString(\
# "Reset Q range to the default values")
-#
+#
# sizer_horizontal = wx.BoxSizer(wx.HORIZONTAL)
# sizer = wx.GridSizer(2, 4, 2, 6)
-#
+#
# self.btEditMask = wx.Button(self, self._ids.next(),'Editor', size=(88, 23))
-# self.btEditMask.Bind(wx.EVT_BUTTON,
+# self.btEditMask.Bind(wx.EVT_BUTTON,
# self._onMask,id=self.btEditMask.GetId())
# self.btEditMask.SetToolTipString("Edit Mask.")
# self.EditMask_title = wx.StaticText(self, wx.ID_ANY, ' Masking(2D)')
-#
+#
# sizer.Add(wx.StaticText(self, wx.ID_ANY, 'Q range'))
# sizer.Add(wx.StaticText(self, wx.ID_ANY, ' Min[1/A]'))
# sizer.Add(wx.StaticText(self, wx.ID_ANY, ' Max[1/A]'))
# sizer.Add(self.EditMask_title)
-#
-# sizer.Add(self.reset_qrange)
+#
+# sizer.Add(self.reset_qrange)
# sizer.Add(self.qmin)
# sizer.Add(self.qmax)
-#
+#
# sizer.Add(self.btEditMask)
-# boxsizer_range.Add(sizer_chi2)
+# boxsizer_range.Add(sizer_chi2)
# boxsizer_range.Add((10, 10))
# boxsizer_range.Add(sizer)
-#
+#
# boxsizer_range.Add((10, 15))
# boxsizer_range.Add(sizer_fit)
# if is_2Ddata:
-# self.btEditMask.Enable()
-# self.EditMask_title.Enable()
+# self.btEditMask.Enable()
+# self.EditMask_title.Enable()
# else:
-# self.btEditMask.Disable()
+# self.btEditMask.Disable()
# self.EditMask_title.Disable()
-#
+#
# ## save state
# #self.save_current_state()
-#
+#
# self.sizer5.Add(boxsizer_range, 0, wx.EXPAND | wx.ALL, 10)
# self.sizer5.Layout()
-#
-# def _on_select_model(self, event=None):
+#
+# def _on_select_model(self, event=None):
# """
# call back for model selection
-# """
-#
-# self.Show(False)
-# self._on_select_model_helper()
-# self.set_model_param_sizer(self.model)
+# """
+#
+# self.Show(False)
+# self._on_select_model_helper()
+# self.set_model_param_sizer(self.model)
# if self.model is None:
# self._set_bookmark_flag(False)
# self._keep.Enable(False)
@@ -198,36 +199,36 @@ class BatchFitPage(FitPage):
# pass
# self.state.structurecombobox = self.structurebox.GetCurrentSelection()
# self.state.formfactorcombobox = self.formfactorbox.GetCurrentSelection()
-#
-# if self.model != None:
+#
+# if self.model is not None:
# self._set_copy_flag(True)
# self._set_paste_flag(True)
-# if self.data != None:
+# if self.data is not None:
# self._set_bookmark_flag(False)
# self._keep.Enable(False)
-#
+#
# temp_smear = None
# ## event to post model to fit to fitting plugins
# (ModelEventbox, _) = wx.lib.newevent.NewEvent()
-#
-# ## set smearing value whether or not
+#
+# ## set smearing value whether or not
# # the data contain the smearing info
-# evt = ModelEventbox(model=self.model,
-# smearer=temp_smear,
+# evt = ModelEventbox(model=self.model,
+# smearer=temp_smear,
# qmin=float(self.qmin_x),
# uid=self.uid,
-# qmax=float(self.qmax_x))
-#
+# qmax=float(self.qmax_x))
+#
# self._manager._on_model_panel(evt=evt)
# self.mbox_description.SetLabel("Model [%s]" % str(self.model.name))
# self.state.model = self.model.clone()
# self.state.model.name = self.model.name
-#
-#
-# if event != None:
+#
+#
+# if event is not None:
# ## post state to fit panel
# new_event = PageInfoEvent(page = self)
-# wx.PostEvent(self.parent, new_event)
+# wx.PostEvent(self.parent, new_event)
# #update list of plugins if new plugin is available
# if self.plugin_rbutton.GetValue():
# temp = self.parent.update_model_list()
@@ -242,8 +243,8 @@ class BatchFitPage(FitPage):
# else:
# self._draw_model()
# self.SetupScrolling()
-# self.Show(True)
-#
+# self.Show(True)
+#
# def _update_paramv_on_fit(self):
# """
# make sure that update param values just before the fitting
@@ -252,16 +253,16 @@ class BatchFitPage(FitPage):
# flag = True
# self.fitrange = True
# is_modified = False
-#
-# if self.model != None:
+#
+# if self.model is not None:
# ##Check the values
# self._check_value_enter( self.fittable_param)
# self._check_value_enter( self.fixed_param)
# self._check_value_enter( self.parameters)
-#
-# # If qmin and qmax have been modified, update qmin and qmax and
+#
+# # If qmin and qmax have been modified, update qmin and qmax and
# # Here we should check whether the boundaries have been modified.
-# # If qmin and qmax have been modified, update qmin and qmax and
+# # If qmin and qmax have been modified, update qmin and qmax and
# # set the is_modified flag to True
# self.fitrange = self._validate_qrange(self.qmin, self.qmax)
# if self.fitrange:
@@ -272,40 +273,40 @@ class BatchFitPage(FitPage):
# if tempmax != self.qmax_x:
# self.qmax_x = tempmax
# if tempmax == tempmin:
-# flag = False
+# flag = False
# #temp_smearer = None
# if self._is_2D():
-# # only 2D case set mask
+# # only 2D case set mask
# flag = self._validate_Npts()
# if not flag:
# return flag
# else: flag = False
-# else:
+# else:
# flag = False
-#
-# #For invalid q range, disable the mask editor and fit button, vs.
+#
+# #For invalid q range, disable the mask editor and fit button, vs.
# if not self.fitrange:
# #self.btFit.Disable()
# if self._is_2D():
# self.btEditMask.Disable()
# else:
# #self.btFit.Enable(True)
-# if self._is_2D() and self.data != None:
+# if self._is_2D() and self.data is not None:
# self.btEditMask.Enable(True)
-#
+#
# if not flag:
# msg = "Cannot Plot or Fit :Must select a "
# msg += " model or Fitting range is not valid!!! "
# wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
-#
+#
# self.save_current_state()
-#
-# return flag
+#
+# return flag
# def save_current_state(self):
# """
# Currently no save option implemented for batch page
# """
-# pass
+# pass
# def save_current_state_fit(self):
# """
# Currently no save option implemented for batch page
@@ -313,7 +314,7 @@ class BatchFitPage(FitPage):
# pass
# def set_data(self, data):
# """
-# reset the current data
+# reset the current data
# """
# #id = None
# group_id = None
@@ -334,34 +335,34 @@ class BatchFitPage(FitPage):
# self._keep.Enable(False)
# self._set_save_flag(False)
# else:
-# if self.model != None:
+# if self.model is not None:
# self._set_bookmark_flag(False)
# self._keep.Enable(False)
# self._set_save_flag(False)
# self._set_preview_flag(True)
-#
+#
# self.formfactorbox.Enable()
# self.structurebox.Enable()
# data_name = self.data.name
# #set maximum range for x in linear scale
# if not hasattr(self.data,"data"): #Display only for 1D data fit
-# # Minimum value of data
+# # Minimum value of data
# data_min = min(self.data.x)
-# # Maximum value of data
+# # Maximum value of data
# data_max = max(self.data.x)
-# self.btEditMask.Disable()
+# self.btEditMask.Disable()
# self.EditMask_title.Disable()
# else:
-#
-# ## Minimum value of data
+#
+# ## Minimum value of data
# data_min = 0
-# x = max(math.fabs(self.data.xmin), math.fabs(self.data.xmax))
+# x = max(math.fabs(self.data.xmin), math.fabs(self.data.xmax))
# y = max(math.fabs(self.data.ymin), math.fabs(self.data.ymax))
-# ## Maximum value of data
+# ## Maximum value of data
# data_max = math.sqrt(x*x + y*y)
-# self.btEditMask.Enable()
-# self.EditMask_title.Enable()
-#
+# self.btEditMask.Enable()
+# self.EditMask_title.Enable()
+#
# self.dataSource.SetValue(data_name)
# self.qmin_x = data_min
# self.qmax_x = data_max
@@ -374,7 +375,7 @@ class BatchFitPage(FitPage):
# self.state.data = data
# self.state.qmin = self.qmin_x
# self.state.qmax = self.qmax_x
-#
+#
# #update model plot with new data information
# if flag:
# #set model view button
@@ -384,14 +385,14 @@ class BatchFitPage(FitPage):
# else:
# self.enable2D = False
# self.model_view.SetLabel("1D Mode")
-#
+#
# self.model_view.Disable()
-#
-# wx.PostEvent(self._manager.parent,
+#
+# wx.PostEvent(self._manager.parent,
# NewPlotEvent(group_id=group_id,
# action="delete"))
# #plot the current selected data
-# wx.PostEvent(self._manager.parent, NewPlotEvent(plot=self.data,
+# wx.PostEvent(self._manager.parent, NewPlotEvent(plot=self.data,
# title=str(self.data.title)))
# self._manager.store_data(uid=self.uid, data=data,
# data_list=self.data_list,
diff --git a/src/sas/sasgui/perspectives/fitting/console.py b/src/sas/sasgui/perspectives/fitting/console.py
index 8d49823..7a2d0dc 100644
--- a/src/sas/sasgui/perspectives/fitting/console.py
+++ b/src/sas/sasgui/perspectives/fitting/console.py
@@ -1,183 +1,183 @@
-
-
-
-from sas.sasgui.guiframe.events import StatusEvent
-import time
-import wx
-from sas.sascalc.fit import FitHandler
-
-class ConsoleUpdate(FitHandler):
- """
- Print progress to the console.
- """
- isbetter = False
- """Record whether results improved since last update"""
- progress_delta = 60
- """Number of seconds between progress updates"""
- improvement_delta = 5
- """Number of seconds between improvement updates"""
- def __init__(self, parent, manager=None,
- quiet=False, progress_delta=60, improvement_delta=5):
- """
- If quiet is true, only print out final summary, not progress and
- improvements.
-
- :attr parent: the object that handle the messages
-
- """
- self.parent = parent
- self.manager = manager
- self.progress_time = time.time()
- self.progress_percent = 0
- self.improvement_time = self.progress_time
- self.isbetter = False
- self.quiet = quiet
- self.progress_delta = progress_delta
- self.improvement_delta = improvement_delta
- self.elapsed_time = time.time()
- self.update_duration = time.time()
- self.fit_duration = 0
-
-
- def progress(self, k, n):
- """
- Report on progress.
- """
- if self.quiet: return
-
- t = time.time()
- p = int((100 * k) // n)
-
- # Show improvements if there are any
- dt = t - self.improvement_time
- if self.isbetter and dt > self.improvement_delta:
- #self.result.print_summary()
- self.update_fit()
- self.isbetter = False
- self.improvement_time = t
-
- # Update percent complete
- dp = p - self.progress_percent
- if dp < 1: return
- dt = t - self.progress_time
- if dt > self.progress_delta:
- if 1 <= dp <= 2:
- self.progress_percent = p
- self.progress_time = t
- self.update_fit()
- elif 2 < dp <= 5:
- if p // 5 != self.progress_percent // 5:
- self.progress_percent = p
- self.progress_time = t
- else:
- if p // 10 != self.progress_percent // 10:
- self.progress_percent = p
- self.progress_time = t
- self.update_fit()
-
- def improvement(self):
- """
- Called when a result is observed which is better than previous
- results from the fit.
- """
- self.isbetter = True
-
- def print_result(self):
- """
- Print result object
- """
- msg = " \n %s \n" % str(self.result)
- wx.PostEvent(self.parent, StatusEvent(status=msg))
-
- def error(self, msg):
- """
- Model had an error; print traceback
- """
- if self.isbetter:
- #self.result.print_summary()
- self.update_fit()
-
- message = str(msg) + " \n %s \n" % self.result.__str__()
- wx.PostEvent(self.parent, StatusEvent(status=message,
- info="error", type="stop"))
- def stop(self, msg):
- """
- Post event msg and stop
- """
- if self.isbetter:
- #self.result.print_summary()
- self.update_fit()
-
- message = str(msg) + " \n %s \n" % self.result.__str__()
- wx.PostEvent(self.parent, StatusEvent(status=message,
- info="info", type="stop"))
-
- def finalize(self):
- """
- """
- if self.isbetter:
- #self.result.print_summary()
- self.update_fit()
-
- def abort(self):
- """
- """
- if self.isbetter:
- #self.result.print_summary()
- self.update_fit()
-
-
- def update_fit(self, last=False):
- """
- """
- t1 = time.time()
- self.elapsed_time = t1 - self.update_duration
- self.update_duration = t1
- self.fit_duration += self.elapsed_time
- str_time = time.strftime("%Y-%m-%d %H:%M:%S ", time.localtime(t1))
- UPDATE_INTERVAL = 5.0
- u_flag = False
- if self.fit_duration >= UPDATE_INTERVAL:
- self.fit_duration = 0
- u_flag = True
- msg = str_time
- if u_flag or last:
- if self.result is not None:
- data_name, model_name = None, None
- d_flag = (hasattr(self.result, "data") and \
- self.result.data is not None and \
- hasattr(self.result.data, "sas_data") and
- self.result.data.sas_data is not None)
- m_flag = (hasattr(self.result, "model") and \
- self.result.model is not None)
- if d_flag:
- data_name = self.result.data.sas_data.name
- if m_flag:
- model_name = str(self.result.model.name)
- if m_flag and d_flag:
- msg += "Data : %s \n" % (str(data_name))#,
- #str(model_name))
- msg += str(self.result)
- msg += "\n"
- else:
- msg += "No result available\n"
- wx.PostEvent(self.parent, StatusEvent(status=msg, info="info",
- type="progress"))
-
- def starting_fit(self):
- """
- """
- wx.PostEvent(self.parent, StatusEvent(status="Starting the Fit...",
- info="info", type="progress"))
-
- def set_result(self, result):
- """
- """
- self.result = result
-
- def get_result(self):
- """
- """
- return self.result
-
-
+
+
+
+from sas.sasgui.guiframe.events import StatusEvent
+import time
+import wx
+from sas.sascalc.fit import FitHandler
+
+class ConsoleUpdate(FitHandler):
+ """
+ Print progress to the console.
+ """
+ isbetter = False
+ """Record whether results improved since last update"""
+ progress_delta = 60
+ """Number of seconds between progress updates"""
+ improvement_delta = 5
+ """Number of seconds between improvement updates"""
+ def __init__(self, parent, manager=None,
+ quiet=False, progress_delta=60, improvement_delta=5):
+ """
+ If quiet is true, only print out final summary, not progress and
+ improvements.
+
+ :attr parent: the object that handle the messages
+
+ """
+ self.parent = parent
+ self.manager = manager
+ self.progress_time = time.time()
+ self.progress_percent = 0
+ self.improvement_time = self.progress_time
+ self.isbetter = False
+ self.quiet = quiet
+ self.progress_delta = progress_delta
+ self.improvement_delta = improvement_delta
+ self.elapsed_time = time.time()
+ self.update_duration = time.time()
+ self.fit_duration = 0
+
+
+ def progress(self, k, n):
+ """
+ Report on progress.
+ """
+ if self.quiet: return
+
+ t = time.time()
+ p = int((100 * k) // n)
+
+ # Show improvements if there are any
+ dt = t - self.improvement_time
+ if self.isbetter and dt > self.improvement_delta:
+ #self.result.print_summary()
+ self.update_fit()
+ self.isbetter = False
+ self.improvement_time = t
+
+ # Update percent complete
+ dp = p - self.progress_percent
+ if dp < 1: return
+ dt = t - self.progress_time
+ if dt > self.progress_delta:
+ if 1 <= dp <= 2:
+ self.progress_percent = p
+ self.progress_time = t
+ self.update_fit()
+ elif 2 < dp <= 5:
+ if p // 5 != self.progress_percent // 5:
+ self.progress_percent = p
+ self.progress_time = t
+ else:
+ if p // 10 != self.progress_percent // 10:
+ self.progress_percent = p
+ self.progress_time = t
+ self.update_fit()
+
+ def improvement(self):
+ """
+ Called when a result is observed which is better than previous
+ results from the fit.
+ """
+ self.isbetter = True
+
+ def print_result(self):
+ """
+ Print result object
+ """
+ msg = " \n %s \n" % str(self.result)
+ wx.PostEvent(self.parent, StatusEvent(status=msg))
+
+ def error(self, msg):
+ """
+ Model had an error; print traceback
+ """
+ if self.isbetter:
+ #self.result.print_summary()
+ self.update_fit()
+
+ message = str(msg) + " \n %s \n" % self.result.__str__()
+ wx.PostEvent(self.parent, StatusEvent(status=message,
+ info="error", type="stop"))
+ def stop(self, msg):
+ """
+ Post event msg and stop
+ """
+ if self.isbetter:
+ #self.result.print_summary()
+ self.update_fit()
+
+ message = str(msg) + " \n %s \n" % self.result.__str__()
+ wx.PostEvent(self.parent, StatusEvent(status=message,
+ info="info", type="stop"))
+
+ def finalize(self):
+ """
+ """
+ if self.isbetter:
+ #self.result.print_summary()
+ self.update_fit()
+
+ def abort(self):
+ """
+ """
+ if self.isbetter:
+ #self.result.print_summary()
+ self.update_fit()
+
+
+ def update_fit(self, last=False):
+ """
+ """
+ t1 = time.time()
+ self.elapsed_time = t1 - self.update_duration
+ self.update_duration = t1
+ self.fit_duration += self.elapsed_time
+ str_time = time.strftime("%Y-%m-%d %H:%M:%S ", time.localtime(t1))
+ UPDATE_INTERVAL = 5.0
+ u_flag = False
+ if self.fit_duration >= UPDATE_INTERVAL:
+ self.fit_duration = 0
+ u_flag = True
+ msg = str_time
+ if u_flag or last:
+ if self.result is not None:
+ data_name, model_name = None, None
+ d_flag = (hasattr(self.result, "data") and \
+ self.result.data is not None and \
+ hasattr(self.result.data, "sas_data") and
+ self.result.data.sas_data is not None)
+ m_flag = (hasattr(self.result, "model") and \
+ self.result.model is not None)
+ if d_flag:
+ data_name = self.result.data.sas_data.name
+ if m_flag:
+ model_name = str(self.result.model.name)
+ if m_flag and d_flag:
+ msg += "Data : %s \n" % (str(data_name))#,
+ #str(model_name))
+ msg += str(self.result)
+ msg += "\n"
+ else:
+ msg += "No result available\n"
+ wx.PostEvent(self.parent, StatusEvent(status=msg, info="info",
+ type="progress"))
+
+ def starting_fit(self):
+ """
+ """
+ wx.PostEvent(self.parent, StatusEvent(status="Starting the Fit...",
+ info="info", type="progress"))
+
+ def set_result(self, result):
+ """
+ """
+ self.result = result
+
+ def get_result(self):
+ """
+ """
+ return self.result
+
+
diff --git a/src/sas/sasgui/perspectives/fitting/fit_thread.py b/src/sas/sasgui/perspectives/fitting/fit_thread.py
index 9af054e..86c4354 100644
--- a/src/sas/sasgui/perspectives/fitting/fit_thread.py
+++ b/src/sas/sasgui/perspectives/fitting/fit_thread.py
@@ -1,108 +1,104 @@
-
-import sys
-import time
-from sas.sascalc.data_util.calcthread import CalcThread
-
-def map_getattr(classInstance, classFunc, *args):
- """
- Take an instance of a class and a function name as a string.
- Execute class.function and return result
- """
- return getattr(classInstance, classFunc)(*args)
-
-def map_apply(arguments):
- return apply(arguments[0], arguments[1:])
-
-class FitThread(CalcThread):
- """Thread performing the fit """
-
- def __init__(self,
- fn,
- page_id,
- handler,
- batch_outputs,
- batch_inputs=None,
- pars=None,
- completefn=None,
- updatefn=None,
- yieldtime=0.03,
- worktime=0.03,
- reset_flag=False):
- CalcThread.__init__(self,
- completefn,
- updatefn,
- yieldtime,
- worktime)
- self.handler = handler
- self.fitter = fn
- self.pars = pars
- self.batch_inputs = batch_inputs
- self.batch_outputs = batch_outputs
- self.page_id = page_id
- self.starttime = time.time()
- self.updatefn = updatefn
- #Relative error desired in the sum of squares.
- self.reset_flag = reset_flag
-
- def isquit(self):
- """
- :raise KeyboardInterrupt: when the thread is interrupted
-
- """
- try:
- CalcThread.isquit(self)
- except KeyboardInterrupt:
- msg = "Fitting: terminated by the user."
- raise KeyboardInterrupt, msg
-
- def compute(self):
- """
- Perform a fit
- """
- msg = ""
- try:
- import copy
- list_handler = []
- list_curr_thread = []
- list_reset_flag = []
- list_map_get_attr = []
- list_fit_function = []
- list_q = []
- for i in range(len(self.fitter)):
- list_handler.append(self.handler)
- list_q.append(None)
- list_curr_thread.append(self)
- list_reset_flag.append(self.reset_flag)
- list_fit_function.append('fit')
- list_map_get_attr.append(map_getattr)
- #from multiprocessing import Pool
- inputs = zip(list_map_get_attr, self.fitter, list_fit_function,
- list_q, list_q, list_handler, list_curr_thread,
- list_reset_flag)
- result = map(map_apply, inputs)
-
- self.complete(result=result,
- batch_inputs=self.batch_inputs,
- batch_outputs=self.batch_outputs,
- page_id=self.page_id,
- pars=self.pars,
- elapsed=time.time() - self.starttime)
-
- except KeyboardInterrupt, msg:
- # Thread was interrupted, just proceed and re-raise.
- # Real code should not print, but this is an example...
- #print "keyboard exception"
- #Stop on exception during fitting. Todo: need to put
- #some mssg and reset progress bar.
-
- # Shouldn't this be re-raising? ConsoleUpdate doesn't act on it.
- # raise KeyboardInterrupt
- if self.handler is not None:
- self.handler.stop(msg=msg)
- except:
- import traceback
- if self.handler is not None:
- self.handler.error(msg=traceback.format_exc())
-
-
-
+
+import sys
+import time
+from sas.sascalc.data_util.calcthread import CalcThread
+
+def map_getattr(classInstance, classFunc, *args):
+ """
+ Take an instance of a class and a function name as a string.
+ Execute class.function and return result
+ """
+ return getattr(classInstance, classFunc)(*args)
+
+def map_apply(arguments):
+ return apply(arguments[0], arguments[1:])
+
+class FitThread(CalcThread):
+ """Thread performing the fit """
+
+ def __init__(self,
+ fn,
+ page_id,
+ handler,
+ batch_outputs,
+ batch_inputs=None,
+ pars=None,
+ completefn=None,
+ updatefn=None,
+ yieldtime=0.03,
+ worktime=0.03,
+ reset_flag=False):
+ CalcThread.__init__(self, completefn, updatefn, yieldtime, worktime)
+ self.handler = handler
+ self.fitter = fn
+ self.pars = pars
+ self.batch_inputs = batch_inputs
+ self.batch_outputs = batch_outputs
+ self.page_id = page_id
+ self.starttime = time.time()
+ self.updatefn = updatefn
+ #Relative error desired in the sum of squares.
+ self.reset_flag = reset_flag
+
+ def isquit(self):
+ """
+ :raise KeyboardInterrupt: when the thread is interrupted
+
+ """
+ try:
+ CalcThread.isquit(self)
+ except KeyboardInterrupt:
+ msg = "Fitting: terminated by the user."
+ raise KeyboardInterrupt, msg
+
+ def compute(self):
+ """
+ Perform a fit
+ """
+ msg = ""
+ try:
+ import copy
+ list_handler = []
+ list_curr_thread = []
+ list_reset_flag = []
+ list_map_get_attr = []
+ list_fit_function = []
+ list_q = []
+ for i in range(len(self.fitter)):
+ list_handler.append(self.handler)
+ list_q.append(None)
+ list_curr_thread.append(self)
+ list_reset_flag.append(self.reset_flag)
+ list_fit_function.append('fit')
+ list_map_get_attr.append(map_getattr)
+ #from multiprocessing import Pool
+ inputs = zip(list_map_get_attr, self.fitter, list_fit_function,
+ list_q, list_q, list_handler, list_curr_thread,
+ list_reset_flag)
+ result = map(map_apply, inputs)
+
+ self.complete(result=result,
+ batch_inputs=self.batch_inputs,
+ batch_outputs=self.batch_outputs,
+ page_id=self.page_id,
+ pars=self.pars,
+ elapsed=time.time() - self.starttime)
+
+ except KeyboardInterrupt, msg:
+ # Thread was interrupted, just proceed and re-raise.
+ # Real code should not print, but this is an example...
+ #print "keyboard exception"
+ #Stop on exception during fitting. Todo: need to put
+ #some mssg and reset progress bar.
+
+ # Shouldn't this be re-raising? ConsoleUpdate doesn't act on it.
+ # raise KeyboardInterrupt
+ if self.handler is not None:
+ self.handler.stop(msg=msg)
+ except: # catch-all: show every exception which stops the thread
+ import traceback
+ if self.handler is not None:
+ self.handler.error(msg=traceback.format_exc())
+
+
+
diff --git a/src/sas/sasgui/perspectives/fitting/fitpage.py b/src/sas/sasgui/perspectives/fitting/fitpage.py
index b00398f..3a89b27 100644
--- a/src/sas/sasgui/perspectives/fitting/fitpage.py
+++ b/src/sas/sasgui/perspectives/fitting/fitpage.py
@@ -5,7 +5,7 @@
import sys
import wx
import wx.lib.newevent
-import numpy
+import numpy as np
import copy
import math
import time
@@ -13,6 +13,8 @@ import traceback
from sasmodels.weights import MODELS as POLYDISPERSITY_MODELS
+from sas.sascalc.fit.qsmearing import smear_selection
+
from sas.sasgui.guiframe.events import StatusEvent, NewPlotEvent, \
PlotQrangeEvent
from sas.sasgui.guiframe.dataFitting import check_data_validity
@@ -22,7 +24,6 @@ from sas.sasgui.guiframe.documentation_window import DocumentationWindow
from sas.sasgui.perspectives.fitting.basepage import BasicPage as BasicPage
from sas.sasgui.perspectives.fitting.basepage import PageInfoEvent as \
PageInfoEvent
-from sas.sascalc.data_util.qsmearing import smear_selection
from .basepage import ModelTextCtrl
(Chi2UpdateEvent, EVT_CHI2_UPDATE) = wx.lib.newevent.NewEvent()
@@ -288,7 +289,7 @@ class FitPage(BasicPage):
self.btFitHelp = wx.Button(self, wx.ID_ANY, 'Help')
self.btFitHelp.SetToolTipString("General fitting help.")
self.btFitHelp.Bind(wx.EVT_BUTTON, self._onFitHelp)
-
+
# Resolution Smearing Help button (for now use same technique as
# used for dI help to get tiniest possible button that works
# both on MAC and PC. Should completely rewrite the fitting sizer
@@ -302,7 +303,7 @@ class FitPage(BasicPage):
style=wx.BU_EXACTFIT, size=size_q)
self.btSmearHelp.SetToolTipString("Resolution smearing help.")
self.btSmearHelp.Bind(wx.EVT_BUTTON, self._onSmearHelp)
-
+
# textcntrl for custom resolution
self.smear_pinhole_percent = ModelTextCtrl(self, wx.ID_ANY,
size=(_BOX_WIDTH - 25, 20),
@@ -563,13 +564,13 @@ class FitPage(BasicPage):
sizer.Add(self.points_sizer, 0, 0)
sizer.Add(self.draw_button, 0, 0)
sizer.Add((-1, 5))
-
+
sizer.Add(self.tcChi, 0, 0)
sizer.Add(self.Npts_fit, 0, 0)
sizer.Add(self.Npts_total, 0, 0)
sizer.Add(self.btFit, 0, 0)
sizer.Add(self.btFitHelp, 0, 0)
-
+
boxsizer_range.Add(sizer_chi2)
boxsizer_range.Add(sizer)
if is_2d_data:
@@ -1077,7 +1078,7 @@ class FitPage(BasicPage):
:param evt: Triggers on clicking the help button
"""
- _TreeLocation = "user/sasgui/perspectives/fitting/sm_help.html"
+ _TreeLocation = "user/sasgui/perspectives/fitting/resolution.html"
_doc_viewer = DocumentationWindow(self, wx.ID_ANY, _TreeLocation, "",
"Instrumental Resolution Smearing \
Help")
@@ -1114,13 +1115,13 @@ class FitPage(BasicPage):
for item in button_list:
if item.GetValue():
if button_list.index(item) == 0:
- flag = 0 # dy = numpy.ones_like(dy_data)
+ flag = 0 # dy = np.ones_like(dy_data)
elif button_list.index(item) == 1:
flag = 1 # dy = dy_data
elif button_list.index(item) == 2:
- flag = 2 # dy = numpy.sqrt(numpy.abs(data))
+ flag = 2 # dy = np.sqrt(np.abs(data))
elif button_list.index(item) == 3:
- flag = 3 # dy = numpy.abs(data)
+ flag = 3 # dy = np.abs(data)
break
return flag
@@ -1141,22 +1142,35 @@ class FitPage(BasicPage):
if self.model is not None:
self.model.name = "M" + str(self.index_model)
- def _on_select_model(self, event=None):
+ def _on_select_model(self, event=None, keep_pars=False):
"""
call back for model selection
"""
self.Show(False)
- copy_flag = False
- is_poly_enabled = None
if event is not None:
- if (event.GetEventObject() == self.formfactorbox
- and self.structurebox.GetLabel() != 'None')\
- or event.GetEventObject() == self.structurebox\
- or event.GetEventObject() == self.multifactorbox:
- copy_flag = self.get_copy_params()
- is_poly_enabled = self.enable_disp.GetValue()
-
- self._on_select_model_helper()
+ control = event.GetEventObject()
+ if ((control == self.formfactorbox
+ and self.structurebox.GetLabel() != 'None')
+ or control == self.structurebox
+ or control == self.multifactorbox):
+ keep_pars = True
+
+ if keep_pars:
+ saved_pars = self.get_copy_params()
+ is_poly_enabled = self.enable_disp.GetValue()
+ else:
+ saved_pars = None
+ is_poly_enabled = None
+
+ try:
+ self._on_select_model_helper()
+ except Exception as e:
+ evt = StatusEvent(status=e.message, info="error")
+ wx.PostEvent(self._manager.parent, evt)
+ # Set S(Q) to None
+ self.structurebox.SetSelection(0)
+ self._on_select_model()
+ return
self.set_model_param_sizer(self.model)
if self.model is None:
self._set_bookmark_flag(False)
@@ -1169,7 +1183,7 @@ class FitPage(BasicPage):
# Note: if we fix this, then remove ID_DISPERSER_HELP from basepage
try:
self.set_dispers_sizer()
- except:
+ except Exception:
pass
self.state.enable_disp = self.enable_disp.GetValue()
self.state.disable_disp = self.disable_disp.GetValue()
@@ -1230,37 +1244,37 @@ class FitPage(BasicPage):
self.state.model = self.model.clone()
self.state.model.name = self.model.name
+ # when select a model only from guictr/button
+ if is_poly_enabled is not None:
+ self.enable_disp.SetValue(is_poly_enabled)
+ self.disable_disp.SetValue(not is_poly_enabled)
+ self._set_dipers_Param(event=None)
+ self.state.enable_disp = self.enable_disp.GetValue()
+ self.state.disable_disp = self.disable_disp.GetValue()
+
+ # Keep the previous param values
+ if saved_pars:
+ self.get_paste_params(saved_pars)
+
if event is not None:
+ # update list of plugins if new plugin is available
+ # mod_cat = self.categorybox.GetStringSelection()
+ # if mod_cat == CUSTOM_MODEL:
+ # temp = self.parent.update_model_list()
+ # for v in self.parent.model_dictionary.values():
+ # if v.id == self.model.id:
+ # self.model = v()
+ # break
+ # if temp:
+ # self.model_list_box = temp
+ # current_val = self.formfactorbox.GetLabel()
+ # pos = self.formfactorbox.GetSelection()
+ # self._show_combox_helper()
+ # self.formfactorbox.SetStringSelection(current_val)
+ # self.formfactorbox.SetValue(current_val)
# post state to fit panel
new_event = PageInfoEvent(page=self)
wx.PostEvent(self.parent, new_event)
- # update list of plugins if new plugin is available
- mod_cat = self.categorybox.GetStringSelection()
- if mod_cat == CUSTOM_MODEL:
- temp_id = self.model.id
- temp = self.parent.update_model_list()
- for v in self.parent.model_dictionary.values():
- if v.id == temp_id:
- self.model = v()
- break
- if temp:
- self.model_list_box = temp
- current_val = self.formfactorbox.GetLabel()
- pos = self.formfactorbox.GetSelection()
- self._show_combox_helper()
- self.formfactorbox.SetSelection(pos)
- self.formfactorbox.SetValue(current_val)
- # when select a model only from guictr/button
- if is_poly_enabled is not None:
- self.enable_disp.SetValue(is_poly_enabled)
- self.disable_disp.SetValue(not is_poly_enabled)
- self._set_dipers_Param(event=None)
- self.state.enable_disp = self.enable_disp.GetValue()
- self.state.disable_disp = self.disable_disp.GetValue()
-
- # Keep the previous param values
- if copy_flag:
- self.get_paste_params(copy_flag)
wx.CallAfter(self._onDraw, None)
else:
@@ -1425,7 +1439,7 @@ class FitPage(BasicPage):
return
key = event.GetKeyCode()
length = len(self.data.x)
- indx = (numpy.abs(self.data.x - x_data)).argmin()
+ indx = (np.abs(self.data.x - x_data)).argmin()
# return array.flat[idx]
if key == wx.WXK_PAGEUP or key == wx.WXK_NUMPAD_PAGEUP:
indx += 1
@@ -1480,11 +1494,11 @@ class FitPage(BasicPage):
if self.data.__class__.__name__ == "Data2D" or \
self.enable2D:
# set mask
- radius = numpy.sqrt(self.data.qx_data * self.data.qx_data +
+ radius = np.sqrt(self.data.qx_data * self.data.qx_data +
self.data.qy_data * self.data.qy_data)
index_data = ((self.qmin_x <= radius) & (radius <= self.qmax_x))
index_data = (index_data) & (self.data.mask)
- index_data = (index_data) & (numpy.isfinite(self.data.data))
+ index_data = (index_data) & (np.isfinite(self.data.data))
if len(index_data[index_data]) < 10:
msg = "Cannot Plot :No or too little npts in"
msg += " that data range!!! "
@@ -1601,13 +1615,13 @@ class FitPage(BasicPage):
and data.dqx_data.any() != 0 \
and data.dqx_data.any() != 0:
self.smear_type = "Pinhole2d"
- self.dq_l = format_number(numpy.average(data.dqx_data))
- self.dq_r = format_number(numpy.average(data.dqy_data))
+ self.dq_l = format_number(np.average(data.dqx_data))
+ self.dq_r = format_number(np.average(data.dqy_data))
return
else:
return
# check if it is pinhole smear and get min max if it is.
- if data.dx is not None and numpy.any(data.dx):
+ if data.dx is not None and np.any(data.dx):
self.smear_type = "Pinhole"
self.dq_l = data.dx[0]
self.dq_r = data.dx[-1]
@@ -1615,9 +1629,9 @@ class FitPage(BasicPage):
# check if it is slit smear and get min max if it is.
elif data.dxl is not None or data.dxw is not None:
self.smear_type = "Slit"
- if data.dxl is not None and numpy.all(data.dxl, 0):
+ if data.dxl is not None and np.all(data.dxl, 0):
self.dq_l = data.dxl[0]
- if data.dxw is not None and numpy.all(data.dxw, 0):
+ if data.dxw is not None and np.all(data.dxw, 0):
self.dq_r = data.dxw[0]
# return self.smear_type,self.dq_l,self.dq_r
@@ -1718,8 +1732,8 @@ class FitPage(BasicPage):
# build function (combo)box
ind = 0
while(ind < len(list)):
- for key, val in list.iteritems():
- if (val == ind):
+ for key, val in list.items():
+ if val == ind:
fun_box.Append(key, val)
break
ind += 1
@@ -1812,13 +1826,6 @@ class FitPage(BasicPage):
if not flag:
self.onSmear(None)
- def _mac_sleep(self, sec=0.2):
- """
- Give sleep to MAC
- """
- if self.is_mac:
- time.sleep(sec)
-
def get_view_mode(self):
"""
return True if the panel allow 2D or False if 1D
@@ -1924,19 +1931,19 @@ class FitPage(BasicPage):
self.pinhole_smearer.Enable(True)
self.default_mask = copy.deepcopy(self.data.mask)
if self.data.err_data is not None \
- and numpy.any(self.data.err_data):
+ and np.any(self.data.err_data):
di_flag = True
if self.data.dqx_data is not None \
- and numpy.any(self.data.dqx_data):
+ and np.any(self.data.dqx_data):
dq_flag = True
else:
self.slit_smearer.Enable(True)
self.pinhole_smearer.Enable(True)
- if self.data.dy is not None and numpy.any(self.data.dy):
+ if self.data.dy is not None and np.any(self.data.dy):
di_flag = True
- if self.data.dx is not None and numpy.any(self.data.dx):
+ if self.data.dx is not None and np.any(self.data.dx):
dq_flag = True
- elif self.data.dxl is not None and numpy.any(self.data.dxl):
+ elif self.data.dxl is not None and np.any(self.data.dxl):
dq_flag = True
if dq_flag:
@@ -2041,6 +2048,8 @@ class FitPage(BasicPage):
self.select_param()
# Save state_fit
self.save_current_state_fit()
+ self.onSmear(None)
+ self._onDraw(None)
except:
self._show_combox_helper()
msg = "Error: This model state has missing or outdated "
@@ -2070,11 +2079,11 @@ class FitPage(BasicPage):
qmin, qmax = self.get_range()
if self.data.__class__.__name__ == "Data2D" or \
self.enable2D:
- radius = numpy.sqrt(self.data.qx_data * self.data.qx_data +
+ radius = np.sqrt(self.data.qx_data * self.data.qx_data +
self.data.qy_data * self.data.qy_data)
index_data = (self.qmin_x <= radius) & (radius <= self.qmax_x)
index_data = (index_data) & (self.data.mask)
- index_data = (index_data) & (numpy.isfinite(self.data.data))
+ index_data = (index_data) & (np.isfinite(self.data.data))
npts2fit = len(self.data.data[index_data])
else:
for qx in self.data.x:
@@ -2107,7 +2116,7 @@ class FitPage(BasicPage):
# make sure stop button to fit button all the time
self._on_fit_complete()
- if out is None or not numpy.isfinite(chisqr):
+ if out is None or not np.isfinite(chisqr):
raise ValueError, "Fit error occured..."
is_modified = False
@@ -2118,7 +2127,7 @@ class FitPage(BasicPage):
self._clear_Err_on_Fit()
# Check if chi2 is finite
- if chisqr is not None and numpy.isfinite(chisqr):
+ if chisqr is not None and np.isfinite(chisqr):
# format chi2
chi2 = format_number(chisqr, True)
self.tcChi.SetValue(chi2)
@@ -2170,7 +2179,7 @@ class FitPage(BasicPage):
pass
if cov[ind] is not None:
- if numpy.isfinite(float(cov[ind])):
+ if np.isfinite(float(cov[ind])):
val_err = format_number(cov[ind], True)
item[4].SetForegroundColour(wx.BLACK)
else:
@@ -2194,7 +2203,6 @@ class FitPage(BasicPage):
if not self.is_mac:
self.Layout()
self.Refresh()
- self._mac_sleep(0.1)
# plot model ( when drawing, do not update chisqr value again)
self._draw_model(update_chisqr=False, source='fit')
@@ -2294,12 +2302,12 @@ class FitPage(BasicPage):
if self._is_2D():
self.smear_type = 'Pinhole2d'
len_data = len(data.data)
- data.dqx_data = numpy.zeros(len_data)
- data.dqy_data = numpy.zeros(len_data)
+ data.dqx_data = np.zeros(len_data)
+ data.dqy_data = np.zeros(len_data)
else:
self.smear_type = 'Pinhole'
len_data = len(data.x)
- data.dx = numpy.zeros(len_data)
+ data.dx = np.zeros(len_data)
data.dxl = None
data.dxw = None
msg = None
@@ -2472,11 +2480,11 @@ class FitPage(BasicPage):
try:
self.dxl = float(self.smear_slit_height.GetValue())
- data.dxl = self.dxl * numpy.ones(data_len)
+ data.dxl = self.dxl * np.ones(data_len)
self.smear_slit_height.SetBackgroundColour(wx.WHITE)
except:
self.dxl = None
- data.dxl = numpy.zeros(data_len)
+ data.dxl = np.zeros(data_len)
if self.smear_slit_height.GetValue().lstrip().rstrip() != "":
self.smear_slit_height.SetBackgroundColour("pink")
msg = "Wrong value entered... "
@@ -2485,10 +2493,10 @@ class FitPage(BasicPage):
try:
self.dxw = float(self.smear_slit_width.GetValue())
self.smear_slit_width.SetBackgroundColour(wx.WHITE)
- data.dxw = self.dxw * numpy.ones(data_len)
+ data.dxw = self.dxw * np.ones(data_len)
except:
self.dxw = None
- data.dxw = numpy.zeros(data_len)
+ data.dxw = np.zeros(data_len)
if self.smear_slit_width.GetValue().lstrip().rstrip() != "":
self.smear_slit_width.SetBackgroundColour("pink")
msg = "Wrong Fit value entered... "
@@ -2615,7 +2623,7 @@ class FitPage(BasicPage):
try:
if event is None:
output = "-"
- elif not numpy.isfinite(event.output):
+ elif not np.isfinite(event.output):
output = "-"
else:
output = event.output
@@ -2789,7 +2797,7 @@ class FitPage(BasicPage):
# no numbers
else:
return cmp(a.lower(), b.lower())
-
+
# keys obtained now from ordered dict, so commenting alphabetical
# ordering keys.sort(custom_compare)
diff --git a/src/sas/sasgui/perspectives/fitting/fitpanel.py b/src/sas/sasgui/perspectives/fitting/fitpanel.py
index ad59331..3836347 100644
--- a/src/sas/sasgui/perspectives/fitting/fitpanel.py
+++ b/src/sas/sasgui/perspectives/fitting/fitpanel.py
@@ -8,13 +8,19 @@ FitPanel class contains fields allowing to fit models and data
import wx
from wx.aui import AuiNotebook as nb
+from sas.sascalc.fit.models import ModelManager
+
from sas.sasgui.guiframe.panel_base import PanelBase
from sas.sasgui.guiframe.events import PanelOnFocusEvent, StatusEvent
from sas.sasgui.guiframe.dataFitting import check_data_validity
-from sas.sasgui.perspectives.fitting.simfitpage import SimultaneousFitPage
-import basepage
-import models
+
+from . import basepage
+from .fitpage import FitPage
+from .simfitpage import SimultaneousFitPage
+from .batchfitpage import BatchFitPage
+from .fitting_widgets import BatchDataDialog
+
_BOX_WIDTH = 80
@@ -45,7 +51,7 @@ class FitPanel(nb, PanelBase):
self.parent = parent
self.event_owner = None
# dictionary of miodel {model class name, model class}
- self.menu_mng = models.ModelManager()
+ self.menu_mng = ModelManager()
self.model_list_box = self.menu_mng.get_model_list()
# pageClosedEvent = nb.EVT_FLATNOTEBOOK_PAGE_CLOSING
self.model_dictionary = self.menu_mng.get_model_dictionary()
@@ -113,17 +119,15 @@ class FitPanel(nb, PanelBase):
"""
"""
temp = self.menu_mng.update()
- if len(temp):
+ if temp:
self.model_list_box = temp
return temp
def reset_pmodel_list(self):
"""
"""
- temp = self.menu_mng.plugins_reset()
- if len(temp):
- self.model_list_box = temp
- return temp
+ self.model_list_box = self.menu_mng.plugins_reset()
+ return self.model_list_box
def get_page_by_id(self, uid):
"""
@@ -297,11 +301,11 @@ class FitPanel(nb, PanelBase):
"""
self.model_list_box = dict
- def set_model_dict(self, m_dict):
+ def set_model_dictionary(self, model_dictionary):
"""
copy a dictionary of model name -> model object
- :param m_dict: dictionary linking model name -> model object
+ :param model_dictionary: dictionary linking model name -> model object
"""
def get_current_page(self):
@@ -315,7 +319,6 @@ class FitPanel(nb, PanelBase):
"""
Add the simultaneous fit page
"""
- from simfitpage import SimultaneousFitPage
page_finder = self._manager.get_page_finder()
if caption == "Const & Simul Fit":
self.sim_page = SimultaneousFitPage(self, page_finder=page_finder,
@@ -343,14 +346,12 @@ class FitPanel(nb, PanelBase):
add an empty page
"""
if self.batch_on:
- from batchfitpage import BatchFitPage
panel = BatchFitPage(parent=self)
self.batch_page_index += 1
caption = "BatchPage" + str(self.batch_page_index)
panel.set_index_model(self.batch_page_index)
else:
# Increment index of fit page
- from fitpage import FitPage
panel = FitPage(parent=self)
self.fit_page_index += 1
caption = "FitPage" + str(self.fit_page_index)
@@ -358,7 +359,7 @@ class FitPanel(nb, PanelBase):
panel.batch_on = self.batch_on
panel._set_save_flag(not panel.batch_on)
panel.set_model_dictionary(self.model_dictionary)
- panel.populate_box(model_dict=self.model_list_box)
+ panel.populate_box(model_list_box=self.model_list_box)
panel.formfactor_combo_init()
panel.set_manager(self._manager)
panel.window_caption = caption
@@ -406,7 +407,6 @@ class FitPanel(nb, PanelBase):
pos = self.GetPageIndex(self.sim_page)
self.SetSelection(pos)
self.on_close_page(event=None)
- temp = self.GetSelection()
self.DeletePage(pos)
self.sim_page = None
self.batch_on = False
@@ -445,8 +445,6 @@ class FitPanel(nb, PanelBase):
break
if data_1d_list and data_2d_list:
# need to warning the user that this batch is a special case
- from sas.sasgui.perspectives.fitting.fitting_widgets import \
- BatchDataDialog
dlg = BatchDataDialog(self)
if dlg.ShowModal() == wx.ID_OK:
data_type = dlg.get_data()
@@ -503,10 +501,15 @@ class FitPanel(nb, PanelBase):
if data is None:
return None
+ focused_page = self.GetPage(self.GetSelection())
for page in self.opened_pages.values():
# check if the selected data existing in the fitpanel
pos = self.GetPageIndex(page)
if not check_data_validity(page.get_data()) and not page.batch_on:
+ if page.model is not None and page != focused_page:
+ # Page has an active theory and is in background - don't
+ # send data here.
+ continue
# make sure data get placed in 1D empty tab if data is 1D
# else data get place on 2D tab empty tab
enable2D = page.get_view_mode()
diff --git a/src/sas/sasgui/perspectives/fitting/fitproblem.py b/src/sas/sasgui/perspectives/fitting/fitproblem.py
index 14a2e0b..b5fadbd 100644
--- a/src/sas/sasgui/perspectives/fitting/fitproblem.py
+++ b/src/sas/sasgui/perspectives/fitting/fitproblem.py
@@ -1,752 +1,585 @@
-"""
-Inferface containing information to store data, model, range of data, etc...
-and retreive this information. This is an inferface
-for a fitProblem i.e relationship between data and model.
-"""
-################################################################################
-#This software was developed by the University of Tennessee as part of the
-#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
-#project funded by the US National Science Foundation.
-#
-#See the license text in license.txt
-#
-#copyright 2009, University of Tennessee
-################################################################################
-import copy
-from sas.sascalc.data_util.qsmearing import smear_selection
-
-class FitProblemComponent(object):
- """
- Inferface containing information to store data, model, range of data, etc...
- and retreive this information. This is an inferface
- for a fitProblem i.e relationship between data and model.
- """
- def enable_smearing(self, flag=False):
- """
- :param flag: bool.When flag is 1 get the computer smear value. When
- flag is 0 ingore smear value.
- """
-
- def get_smearer(self):
- """
- return smear object
- """
- def save_model_name(self, name):
- """
- """
-
- def get_name(self):
- """
- """
-
- def set_model(self, model):
- """
- associates each model with its new created name
- :param model: model selected
- :param name: name created for model
- """
-
- def get_model(self):
- """
- :return: saved model
- """
-
- def set_residuals(self, residuals):
- """
- save a copy of residual
- :param data: data selected
- """
-
- def get_residuals(self):
- """
- :return: residuals
- """
-
- def set_theory_data(self, data):
- """
- save a copy of the data select to fit
- :param data: data selected
- """
-
- def get_theory_data(self):
- """
- :return: list of data dList
- """
-
- def set_fit_data(self, data):
- """
- Store of list of data and create by create new fitproblem of each data
- id, if there was existing information about model, this information
- get copy to the new fitproblem
- :param data: list of data selected
- """
-
- def get_fit_data(self):
- """
- """
-
- def set_model_param(self, name, value=None):
- """
- Store the name and value of a parameter of this fitproblem's model
- :param name: name of the given parameter
- :param value: value of that parameter
- """
-
- def set_param2fit(self, list):
- """
- Store param names to fit (checked)
- :param list: list of the param names
- """
-
- def get_param2fit(self):
- """
- return the list param names to fit
- """
-
- def get_model_param(self):
- """
- return list of couple of parameter name and value
- """
-
- def schedule_tofit(self, schedule=0):
- """
- set schedule to true to decide if this fit must be performed
- """
-
- def get_scheduled(self):
- """
- return true or false if a problem as being schedule for fitting
- """
-
- def set_range(self, qmin=None, qmax=None):
- """
- set fitting range
- """
-
- def get_range(self):
- """
- :return: fitting range
- """
-
- def set_weight(self, flag=None):
- """
- set fitting range
- """
-
- def get_weight(self):
- """
- get fitting weight
- """
-
- def clear_model_param(self):
- """
- clear constraint info
- """
-
- def set_fit_tab_caption(self, caption):
- """
- store the caption of the page associated with object
- """
-
- def get_fit_tab_caption(self):
- """
- Return the caption of the page associated with object
- """
-
- def set_graph_id(self, id):
- """
- Set graph id (from data_group_id at the time the graph produced)
- """
-
- def get_graph_id(self):
- """
- Get graph_id
- """
-
- def set_result(self, result):
- """
- """
-
- def get_result(self):
- """
- get result
- """
-
-
-class FitProblemDictionary(FitProblemComponent, dict):
- """
- This module implements a dictionary of fitproblem objects
- """
- def __init__(self):
- FitProblemComponent.__init__(self)
- dict.__init__(self)
- ## the current model
- self.model = None
- ## if 1 this fit problem will be selected to fit , if 0
- ## it will not be selected for fit
- self.schedule = 0
- ##list containing parameter name and value
- self.list_param = []
- ## fitting range
- self.qmin = None
- self.qmax = None
- self.graph_id = None
- self._smear_on = False
- self.scheduled = 0
- self.fit_tab_caption = ''
- self.nbr_residuals_computed = 0
- self.batch_inputs = {}
- self.batch_outputs = {}
-
- def enable_smearing(self, flag=False, fid=None):
- """
- :param flag: bool.When flag is 1 get the computer smear value. When
- flag is 0 ingore smear value.
- """
- self._smear_on = flag
- if fid is None:
- for value in self.itervalues():
- value.enable_smearing(flag)
- else:
- if fid in self.iterkeys():
- self[fid].enable_smearing(flag)
-
- def set_smearer(self, smearer, fid=None):
- """
- save reference of smear object on fitdata
- :param smear: smear object from DataLoader
- """
- if fid is None:
- for value in self.itervalues():
- value.set_smearer(smearer)
- else:
- if fid in self.iterkeys():
- self[fid].set_smearer(smearer)
-
- def get_smearer(self, fid=None):
- """
- return smear object
- """
- if fid in self.iterkeys():
- return self[fid].get_smearer()
-
- def save_model_name(self, name, fid=None):
- """
- """
- if fid is None:
- for value in self.itervalues():
- value.save_model_name(name)
- else:
- if fid in self.iterkeys():
- self[fid].save_model_name(name)
-
- def get_name(self, fid=None):
- """
- """
- result = []
- if fid is None:
- for value in self.itervalues():
- result.append(value.get_name())
- else:
- if fid in self.iterkeys():
- result.append(self[fid].get_name())
- return result
-
- def set_model(self, model, fid=None):
- """
- associates each model with its new created name
- :param model: model selected
- :param name: name created for model
- """
- self.model = model
- if fid is None:
- for value in self.itervalues():
- value.set_model(self.model)
- else:
- if fid in self.iterkeys():
- self[fid].set_model(self.model)
-
- def get_model(self, fid):
- """
- :return: saved model
- """
- if fid in self.iterkeys():
- return self[fid].get_model()
-
- def set_fit_tab_caption(self, caption):
- """
- store the caption of the page associated with object
- """
- self.fit_tab_caption = caption
-
- def get_fit_tab_caption(self):
- """
- Return the caption of the page associated with object
- """
- return self.fit_tab_caption
-
- def set_residuals(self, residuals, fid):
- """
- save a copy of residual
- :param data: data selected
- """
- if fid in self.iterkeys():
- self[fid].set_residuals(residuals)
-
- def get_residuals(self, fid):
- """
- :return: residuals
- """
- if fid in self.iterkeys():
- return self[fid].get_residuals()
-
- def set_theory_data(self, fid, data=None):
- """
- save a copy of the data select to fit
- :param data: data selected
- """
- if fid in self.iterkeys():
- self[fid].set_theory_data(data)
-
- def get_theory_data(self, fid):
- """
- :return: list of data dList
- """
- if fid in self.iterkeys():
- return self[fid].get_theory_data()
-
- def add_data(self, data):
- """
- Add data to the current dictionary of fitproblem. if data id does not
- exist create a new fit problem.
- :note: only data changes in the fit problem
- """
- if data.id not in self.iterkeys():
- self[data.id] = FitProblem()
- self[data.id].set_fit_data(data)
-
- def set_fit_data(self, data):
- """
- save a copy of the data select to fit
- :param data: data selected
-
- """
- self.clear()
- if data is None:
- data = []
- for d in data:
- if (d is not None):
- if (d.id not in self.iterkeys()):
- self[d.id] = FitProblem()
- self[d.id].set_fit_data(d)
- self[d.id].set_model(self.model)
- self[d.id].set_range(self.qmin, self.qmax)
-
- def get_fit_data(self, fid):
- """
- return data for the given fitproblem id
- :param fid: key representing a fitproblem, usually extract from data id
- """
- if fid in self.iterkeys():
- return self[fid].get_fit_data()
-
- def set_model_param(self, name, value=None, fid=None):
- """
- Store the name and value of a parameter of this fitproblem's model
- :param name: name of the given parameter
- :param value: value of that parameter
- """
- if fid is None:
- for value in self.itervalues():
- value.set_model_param(name, value)
- else:
- if fid in self.iterkeys():
- self[fid].set_model_param(name, value)
-
- def get_model_param(self, fid):
- """
- return list of couple of parameter name and value
- """
- if fid in self.iterkeys():
- return self[fid].get_model_param()
-
- def set_param2fit(self, list):
- """
- Store param names to fit (checked)
- :param list: list of the param names
- """
- self.list_param2fit = list
-
- def get_param2fit(self):
- """
- return the list param names to fit
- """
- return self.list_param2fit
-
- def schedule_tofit(self, schedule=0):
- """
- set schedule to true to decide if this fit must be performed
- """
- self.scheduled = schedule
- for value in self.itervalues():
- value.schedule_tofit(schedule)
-
- def get_scheduled(self):
- """
- return true or false if a problem as being schedule for fitting
- """
- return self.scheduled
-
- def set_range(self, qmin=None, qmax=None, fid=None):
- """
- set fitting range
- """
- self.qmin = qmin
- self.qmax = qmax
- if fid is None:
- for value in self.itervalues():
- value.set_range(self.qmin, self.qmax)
- else:
- if fid in self.iterkeys():
- self[fid].value.set_range(self.qmin, self.qmax)
-
- def get_range(self, fid):
- """
- :return: fitting range
- """
- if fid in self.iterkeys():
- return self[fid].get_range()
-
- def set_weight(self, is2d, flag=None, fid=None):
- """
- fit weight
- """
- if fid is None:
- for value in self.itervalues():
- value.set_weight(flag=flag, is2d=is2d)
- else:
- if fid in self.iterkeys():
- self[fid].set_weight(flag=flag, is2d=is2d)
-
- def get_weight(self, fid=None):
- """
- return fit weight
- """
- if fid in self.iterkeys():
- return self[fid].get_weight()
-
- def clear_model_param(self, fid=None):
- """
- clear constraint info
- """
- if fid is None:
- for value in self.itervalues():
- value.clear_model_param()
- else:
- if fid in self.iterkeys():
- self[fid].clear_model_param()
-
- def get_fit_problem(self):
- """
- return fitproblem contained in this dictionary
- """
- return self.itervalues()
-
- def set_result(self, result, fid):
- """
- """
- if fid in self.iterkeys():
- self[fid].set_result(result)
-
- def set_batch_result(self, batch_inputs, batch_outputs):
- """
- set a list of result
- """
- self.batch_inputs = batch_inputs
- self.batch_outputs = batch_outputs
-
- def get_result(self, fid):
- """
- get result
- """
- if fid in self.iterkeys():
- return self[fid].get_result()
-
- def get_batch_result(self):
- """
- get result
- """
- return self.batch_inputs, self.batch_outputs
-
- def set_graph_id(self, id):
- """
- Set graph id (from data_group_id at the time the graph produced)
- """
- self.graph_id = id
-
- def get_graph_id(self):
- """
- Get graph_id
- """
- return self.graph_id
-
-
-class FitProblem(FitProblemComponent):
- """
- FitProblem class allows to link a model with the new name created in _on_model,
- a name theory created with that model and the data fitted with the model.
- FitProblem is mostly used as value of the dictionary by fitting module.
- """
- def __init__(self):
- FitProblemComponent.__init__(self)
- """
- contains information about data and model to fit
- """
- ## data used for fitting
- self.fit_data = None
- self.theory_data = None
- self.residuals = None
- # original data: should not be modified
- self.original_data = None
- ## the current model
- self.model = None
- ## if 1 this fit problem will be selected to fit , if 0
- ## it will not be selected for fit
- self.schedule = 0
- ##list containing parameter name and value
- self.list_param = []
- ## smear object to smear or not data1D
- self.smearer_computed = False
- self.smearer_enable = False
- self.smearer_computer_value = None
- ## fitting range
- self.qmin = None
- self.qmax = None
- # fit weight
- self.weight = None
- self.result = None
-
- def enable_smearing(self, flag=False):
- """
- :param flag: bool.When flag is 1 get the computer smear value. When
- flag is 0 ingore smear value.
- """
- self.smearer_enable = flag
-
- def set_smearer(self, smearer):
- """
- save reference of smear object on fitdata
-
- :param smear: smear object from DataLoader
-
- """
- self.smearer_computer_value = smearer
-
- def get_smearer(self):
- """
- return smear object
- """
- if not self.smearer_enable:
- return None
- if not self.smearer_computed:
- #smeari_selection should be call only once per fitproblem
- self.smearer_computer_value = smear_selection(self.fit_data,
- self.model)
- self.smearer_computed = True
- return self.smearer_computer_value
-
- def save_model_name(self, name):
- """
- """
- self.name_per_page = name
-
- def get_name(self):
- """
- """
- return self.name_per_page
-
- def set_model(self, model):
- """
- associates each model with its new created name
- :param model: model selected
- :param name: name created for model
- """
- self.model = model
- self.smearer_computer_value = smear_selection(self.fit_data,
- self.model)
- self.smearer_computed = True
-
- def get_model(self):
- """
- :return: saved model
- """
- return self.model
-
- def set_residuals(self, residuals):
- """
- save a copy of residual
- :param data: data selected
- """
- self.residuals = residuals
-
- def get_residuals(self):
- """
- :return: residuals
- """
- return self.residuals
-
- def set_theory_data(self, data):
- """
- save a copy of the data select to fit
-
- :param data: data selected
-
- """
- self.theory_data = copy.deepcopy(data)
-
- def get_theory_data(self):
- """
- :return: theory generated with the current model and data of this class
- """
- return self.theory_data
-
- def set_fit_data(self, data):
- """
- Store data associated with this class
- :param data: list of data selected
- """
- self.original_data = None
- self.fit_data = None
- # original data: should not be modified
- self.original_data = data
- # fit data: used for fit and can be modified for convenience
- self.fit_data = copy.deepcopy(data)
- self.smearer_computer_value = smear_selection(self.fit_data,
- self.model)
- self.smearer_computed = True
- self.result = None
-
- def get_fit_data(self):
- """
- :return: data associate with this class
- """
- return self.fit_data
-
- def get_origin_data(self):
- """
- """
- return self.original_data
-
- def set_weight(self, is2d, flag=None):
- """
- Received flag and compute error on data.
- :param flag: flag to transform error of data.
- :param is2d: flag to distinguish 1D to 2D Data
- """
- from sas.sasgui.perspectives.fitting.utils import get_weight
- # send original data for weighting
- self.weight = get_weight(data=self.original_data, is2d=is2d, flag=flag)
- if is2d:
- self.fit_data.err_data = self.weight
- else:
- self.fit_data.dy = self.weight
-
- def get_weight(self):
- """
- returns weight array
- """
- return self.weight
-
- def set_param2fit(self, list):
- """
- Store param names to fit (checked)
- :param list: list of the param names
- """
- self.list_param2fit = list
-
- def get_param2fit(self):
- """
- return the list param names to fit
- """
- return self.list_param2fit
-
- def set_model_param(self, name, value=None):
- """
- Store the name and value of a parameter of this fitproblem's model
- :param name: name of the given parameter
- :param value: value of that parameter
- """
- self.list_param.append([name, value])
-
- def get_model_param(self):
- """
- return list of couple of parameter name and value
- """
- return self.list_param
-
- def schedule_tofit(self, schedule=0):
- """
- set schedule to true to decide if this fit must be performed
- """
- self.schedule = schedule
-
- def get_scheduled(self):
- """
- return true or false if a problem as being schedule for fitting
- """
- return self.schedule
-
- def set_range(self, qmin=None, qmax=None):
- """
- set fitting range
- :param qmin: minimum value to consider for the fit range
- :param qmax: maximum value to consider for the fit range
- """
- self.qmin = qmin
- self.qmax = qmax
-
- def get_range(self):
- """
- :return: fitting range
-
- """
- return self.qmin, self.qmax
-
- def clear_model_param(self):
- """
- clear constraint info
- """
- self.list_param = []
-
- def set_fit_tab_caption(self, caption):
- """
- """
- self.fit_tab_caption = str(caption)
-
- def get_fit_tab_caption(self):
- """
- """
- return self.fit_tab_caption
-
- def set_graph_id(self, id):
- """
- Set graph id (from data_group_id at the time the graph produced)
- """
- self.graph_id = id
-
- def get_graph_id(self):
- """
- Get graph_id
- """
- return self.graph_id
-
- def set_result(self, result):
- """
- """
- self.result = result
-
- def get_result(self):
- """
- get result
- """
- return self.result
+"""
+Inferface containing information to store data, model, range of data, etc...
+and retreive this information. This is an inferface
+for a fitProblem i.e relationship between data and model.
+"""
+################################################################################
+#This software was developed by the University of Tennessee as part of the
+#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
+#project funded by the US National Science Foundation.
+#
+#See the license text in license.txt
+#
+#copyright 2009, University of Tennessee
+################################################################################
+import copy
+
+from sas.sascalc.fit.qsmearing import smear_selection
+
+class FitProblem(object):
+ """
+ Define the relationship between data and model, including range, weights,
+ etc.
+ """
+ def __init__(self):
+ """
+ contains information about data and model to fit
+ """
+ ## data used for fitting
+ self.fit_data = None
+ self.theory_data = None
+ self.residuals = None
+ # original data: should not be modified
+ self.original_data = None
+ ## the current model
+ self.model = None
+ ## if 1 this fit problem will be selected to fit , if 0
+ ## it will not be selected for fit
+ self.schedule = 0
+ ##list containing parameter name and value
+ self.list_param = []
+ self.list_param2fit = []
+ ## smear object to smear or not data1D
+ self.smearer_computed = False
+ self.smearer_enable = False
+ self.smearer_computer_value = None
+ ## fitting range
+ self.qmin = None
+ self.qmax = None
+ # fit weight
+ self.weight = None
+ self.result = None
+ self.fit_tab_caption = None
+ self.name_per_page = None
+
+ def enable_smearing(self, flag=False):
+ """
+ :param flag: bool.When flag is 1 get the computer smear value. When
+ flag is 0 ingore smear value.
+ """
+ self.smearer_enable = flag
+
+ def set_smearer(self, smearer):
+ """
+ save reference of smear object on fitdata
+
+ :param smear: smear object from DataLoader
+
+ """
+ self.smearer_computer_value = smearer
+
+ def get_smearer(self):
+ """
+ return smear object
+ """
+ if not self.smearer_enable:
+ return None
+ if not self.smearer_computed:
+ #smeari_selection should be call only once per fitproblem
+ self.smearer_computer_value = smear_selection(self.fit_data,
+ self.model)
+ self.smearer_computed = True
+ return self.smearer_computer_value
+
+ def save_model_name(self, name):
+ """
+ """
+ self.name_per_page = name
+
+ def get_name(self):
+ """
+ """
+ return self.name_per_page
+
+ def set_model(self, model):
+ """
+ associates each model with its new created name
+ :param model: model selected
+ :param name: name created for model
+ """
+ self.model = model
+ self.smearer_computer_value = smear_selection(self.fit_data,
+ self.model)
+ self.smearer_computed = True
+
+ def get_model(self):
+ """
+ :return: saved model
+ """
+ return self.model
+
+ def set_residuals(self, residuals):
+ """
+ save a copy of residual
+ :param data: data selected
+ """
+ self.residuals = residuals
+
+ def get_residuals(self):
+ """
+ :return: residuals
+ """
+ return self.residuals
+
+ def set_theory_data(self, data):
+ """
+ save a copy of the data select to fit
+
+ :param data: data selected
+
+ """
+ self.theory_data = copy.deepcopy(data)
+
+ def get_theory_data(self):
+ """
+ :return: theory generated with the current model and data of this class
+ """
+ return self.theory_data
+
+ def set_fit_data(self, data):
+ """
+ Store data associated with this class
+ :param data: list of data selected
+ """
+ self.original_data = None
+ self.fit_data = None
+ # original data: should not be modified
+ self.original_data = data
+ # fit data: used for fit and can be modified for convenience
+ self.fit_data = copy.deepcopy(data)
+ self.smearer_computer_value = smear_selection(self.fit_data, self.model)
+ self.smearer_computed = True
+ self.result = None
+
+ def get_fit_data(self):
+ """
+ :return: data associate with this class
+ """
+ return self.fit_data
+
+ def get_origin_data(self):
+ """
+ """
+ return self.original_data
+
+ def set_weight(self, is2d, flag=None):
+ """
+ Received flag and compute error on data.
+ :param flag: flag to transform error of data.
+ :param is2d: flag to distinguish 1D to 2D Data
+ """
+ from sas.sasgui.perspectives.fitting.utils import get_weight
+ # send original data for weighting
+ self.weight = get_weight(data=self.original_data, is2d=is2d, flag=flag)
+ if is2d:
+ self.fit_data.err_data = self.weight
+ else:
+ self.fit_data.dy = self.weight
+
+ def get_weight(self):
+ """
+ returns weight array
+ """
+ return self.weight
+
+ def set_param2fit(self, list):
+ """
+ Store param names to fit (checked)
+ :param list: list of the param names
+ """
+ self.list_param2fit = list
+
+ def get_param2fit(self):
+ """
+ return the list param names to fit
+ """
+ return self.list_param2fit
+
+ def set_model_param(self, name, value=None):
+ """
+ Store the name and value of a parameter of this fitproblem's model
+ :param name: name of the given parameter
+ :param value: value of that parameter
+ """
+ self.list_param.append([name, value])
+
+ def get_model_param(self):
+ """
+ return list of couple of parameter name and value
+ """
+ return self.list_param
+
+ def schedule_tofit(self, schedule=0):
+ """
+ set schedule to true to decide if this fit must be performed
+ """
+ self.schedule = schedule
+
+ def get_scheduled(self):
+ """
+ return true or false if a problem as being schedule for fitting
+ """
+ return self.schedule
+
+ def set_range(self, qmin=None, qmax=None):
+ """
+ set fitting range
+ :param qmin: minimum value to consider for the fit range
+ :param qmax: maximum value to consider for the fit range
+ """
+ self.qmin = qmin
+ self.qmax = qmax
+
+ def get_range(self):
+ """
+ :return: fitting range
+
+ """
+ return self.qmin, self.qmax
+
+ def clear_model_param(self):
+ """
+ clear constraint info
+ """
+ self.list_param = []
+
+ def set_fit_tab_caption(self, caption):
+ """
+ """
+ self.fit_tab_caption = str(caption)
+
+ def get_fit_tab_caption(self):
+ """
+ """
+ return self.fit_tab_caption
+
+ def set_graph_id(self, id):
+ """
+ Set graph id (from data_group_id at the time the graph produced)
+ """
+ self.graph_id = id
+
+ def get_graph_id(self):
+ """
+ Get graph_id
+ """
+ return self.graph_id
+
+ def set_result(self, result):
+ """
+ """
+ self.result = result
+
+ def get_result(self):
+ """
+ get result
+ """
+ return self.result
+
+
+class FitProblemDictionary(dict):
+ """
+ This module implements a dictionary of fitproblem objects
+ """
+ def __init__(self):
+ dict.__init__(self)
+ ## the current model
+ self.model = None
+ ## if 1 this fit problem will be selected to fit , if 0
+ ## it will not be selected for fit
+ self.schedule = 0
+ ##list containing parameter name and value
+ self.list_param = []
+ ## fitting range
+ self.qmin = None
+ self.qmax = None
+ self.graph_id = None
+ self._smear_on = False
+ self.scheduled = 0
+ self.fit_tab_caption = ''
+ self.nbr_residuals_computed = 0
+ self.batch_inputs = {}
+ self.batch_outputs = {}
+
+ def enable_smearing(self, flag=False, fid=None):
+ """
+ :param flag: bool.When flag is 1 get the computer smear value. When
+ flag is 0 ingore smear value.
+ """
+ self._smear_on = flag
+ if fid is None:
+ for value in self.values():
+ value.enable_smearing(flag)
+ elif fid in self:
+ self[fid].enable_smearing(flag)
+
+ def set_smearer(self, smearer, fid=None):
+ """
+ save reference of smear object on fitdata
+ :param smear: smear object from DataLoader
+ """
+ if fid is None:
+ for value in self.values():
+ value.set_smearer(smearer)
+ elif fid in self:
+ self[fid].set_smearer(smearer)
+
+ def get_smearer(self, fid=None):
+ """
+ return smear object
+ """
+ if fid in self:
+ return self[fid].get_smearer()
+
+ def save_model_name(self, name, fid=None):
+ """
+ """
+ if fid is None:
+ for value in self.values():
+ value.save_model_name(name)
+ elif fid in self:
+ self[fid].save_model_name(name)
+
+ def get_name(self, fid=None):
+ """
+ """
+ result = []
+ if fid is None:
+ for value in self.values():
+ result.append(value.get_name())
+ elif fid in self:
+ result.append(self[fid].get_name())
+ return result
+
+ def set_model(self, model, fid=None):
+ """
+ associates each model with its new created name
+ :param model: model selected
+ :param name: name created for model
+ """
+ self.model = model
+ if fid is None:
+ for value in self.values():
+ value.set_model(self.model)
+ elif fid in self:
+ self[fid].set_model(self.model)
+
+ def get_model(self, fid):
+ """
+ :return: saved model
+ """
+ if fid in self:
+ return self[fid].get_model()
+
+ def set_fit_tab_caption(self, caption):
+ """
+ store the caption of the page associated with object
+ """
+ self.fit_tab_caption = caption
+
+ def get_fit_tab_caption(self):
+ """
+ Return the caption of the page associated with object
+ """
+ return self.fit_tab_caption
+
+ def set_residuals(self, residuals, fid):
+ """
+ save a copy of residual
+ :param data: data selected
+ """
+ if fid in self:
+ self[fid].set_residuals(residuals)
+
+ def get_residuals(self, fid):
+ """
+ :return: residuals
+ """
+ if fid in self:
+ return self[fid].get_residuals()
+
+ def set_theory_data(self, fid, data=None):
+ """
+ save a copy of the data select to fit
+ :param data: data selected
+ """
+ if fid in self:
+ self[fid].set_theory_data(data)
+
+ def get_theory_data(self, fid):
+ """
+ :return: list of data dList
+ """
+ if fid in self:
+ return self[fid].get_theory_data()
+
+ def add_data(self, data):
+ """
+ Add data to the current dictionary of fitproblem. if data id does not
+ exist create a new fit problem.
+ :note: only data changes in the fit problem
+ """
+ if data.id not in self:
+ self[data.id] = FitProblem()
+ self[data.id].set_fit_data(data)
+
+ def set_fit_data(self, data):
+ """
+ save a copy of the data select to fit
+ :param data: data selected
+
+ """
+ self.clear()
+ if data is None:
+ data = []
+ for d in data:
+ if d is not None:
+ if d.id not in self:
+ self[d.id] = FitProblem()
+ self[d.id].set_fit_data(d)
+ self[d.id].set_model(self.model)
+ self[d.id].set_range(self.qmin, self.qmax)
+
+ def get_fit_data(self, fid):
+ """
+ return data for the given fitproblem id
+ :param fid: key representing a fitproblem, usually extract from data id
+ """
+ if fid in self:
+ return self[fid].get_fit_data()
+
+ def set_model_param(self, name, value=None, fid=None):
+ """
+ Store the name and value of a parameter of this fitproblem's model
+ :param name: name of the given parameter
+ :param value: value of that parameter
+ """
+ if fid is None:
+ for value in self.values():
+ value.set_model_param(name, value)
+ elif fid in self:
+ self[fid].set_model_param(name, value)
+
+ def get_model_param(self, fid):
+ """
+ return list of couple of parameter name and value
+ """
+ if fid in self:
+ return self[fid].get_model_param()
+
+ def set_param2fit(self, list):
+ """
+ Store param names to fit (checked)
+ :param list: list of the param names
+ """
+ self.list_param2fit = list
+
+ def get_param2fit(self):
+ """
+ return the list param names to fit
+ """
+ return self.list_param2fit
+
+ def schedule_tofit(self, schedule=0):
+ """
+ set schedule to true to decide if this fit must be performed
+ """
+ self.scheduled = schedule
+ for value in self.values():
+ value.schedule_tofit(schedule)
+
+ def get_scheduled(self):
+ """
+ return true or false if a problem as being schedule for fitting
+ """
+ return self.scheduled
+
+ def set_range(self, qmin=None, qmax=None, fid=None):
+ """
+ set fitting range
+ """
+ self.qmin = qmin
+ self.qmax = qmax
+ if fid is None:
+ for value in self.values():
+ value.set_range(self.qmin, self.qmax)
+ elif fid in self:
+ self[fid].value.set_range(self.qmin, self.qmax)
+
+ def get_range(self, fid):
+ """
+ :return: fitting range
+ """
+ if fid in self:
+ return self[fid].get_range()
+
+ def set_weight(self, is2d, flag=None, fid=None):
+ """
+ fit weight
+ """
+ if fid is None:
+ for value in self.values():
+ value.set_weight(flag=flag, is2d=is2d)
+ elif fid in self:
+ self[fid].set_weight(flag=flag, is2d=is2d)
+
+ def get_weight(self, fid=None):
+ """
+ return fit weight
+ """
+ if fid in self:
+ return self[fid].get_weight()
+
+ def clear_model_param(self, fid=None):
+ """
+ clear constraint info
+ """
+ if fid is None:
+ for value in self.values():
+ value.clear_model_param()
+ elif fid in self:
+ self[fid].clear_model_param()
+
+ def get_fit_problem(self):
+ """
+ return fitproblem contained in this dictionary
+ """
+ return self.values()
+
+ def set_result(self, result, fid):
+ """
+ """
+ if fid in self:
+ self[fid].set_result(result)
+
+ def set_batch_result(self, batch_inputs, batch_outputs):
+ """
+ set a list of result
+ """
+ self.batch_inputs = batch_inputs
+ self.batch_outputs = batch_outputs
+
+ def get_result(self, fid):
+ """
+ get result
+ """
+ if fid in self:
+ return self[fid].get_result()
+
+ def get_batch_result(self):
+ """
+ get result
+ """
+ return self.batch_inputs, self.batch_outputs
+
+ def set_graph_id(self, id):
+ """
+ Set graph id (from data_group_id at the time the graph produced)
+ """
+ self.graph_id = id
+
+ def get_graph_id(self):
+ """
+ Get graph_id
+ """
+ return self.graph_id
diff --git a/src/sas/sasgui/perspectives/fitting/fitting.py b/src/sas/sasgui/perspectives/fitting/fitting.py
index bdb2103..d5921ef 100755
--- a/src/sas/sasgui/perspectives/fitting/fitting.py
+++ b/src/sas/sasgui/perspectives/fitting/fitting.py
@@ -10,17 +10,31 @@
#
#copyright 2009, University of Tennessee
################################################################################
+from __future__ import print_function
+
import re
import sys
import os
import wx
import logging
-import numpy
+import numpy as np
import time
from copy import deepcopy
import traceback
+import bumps.options
+from bumps.gui.fit_dialog import show_fit_config
+try:
+ from bumps.gui.fit_dialog import EVT_FITTER_CHANGED
+except ImportError:
+ # CRUFT: bumps 0.7.5.8 and below
+ EVT_FITTER_CHANGED = None # type: wx.PyCommandEvent
+
from sas.sascalc.dataloader.loader import Loader
+from sas.sascalc.fit.BumpsFitting import BumpsFit as Fit
+from sas.sascalc.fit.pagestate import Reader, PageState, SimFitPageState
+from sas.sascalc.fit import models
+
from sas.sasgui.guiframe.dataFitting import Data2D
from sas.sasgui.guiframe.dataFitting import Data1D
from sas.sasgui.guiframe.dataFitting import check_data_validity
@@ -31,22 +45,24 @@ from sas.sasgui.guiframe.events import EVT_SLICER_PARS_UPDATE
from sas.sasgui.guiframe.gui_style import GUIFRAME_ID
from sas.sasgui.guiframe.plugin_base import PluginBase
from sas.sasgui.guiframe.data_processor import BatchCell
-from sas.sascalc.fit.BumpsFitting import BumpsFit as Fit
-from sas.sasgui.perspectives.fitting.console import ConsoleUpdate
-from sas.sasgui.perspectives.fitting.fitproblem import FitProblemDictionary
-from sas.sasgui.perspectives.fitting.fitpanel import FitPanel
-from sas.sasgui.perspectives.fitting.resultpanel import ResultPanel, PlotResultEvent
-
-from sas.sasgui.perspectives.fitting.fit_thread import FitThread
-from sas.sasgui.perspectives.fitting.pagestate import Reader
-from sas.sasgui.perspectives.fitting.fitpage import Chi2UpdateEvent
-from sas.sasgui.perspectives.calculator.model_editor import TextDialog
-from sas.sasgui.perspectives.calculator.model_editor import EditorWindow
from sas.sasgui.guiframe.gui_manager import MDIFrame
from sas.sasgui.guiframe.documentation_window import DocumentationWindow
-from sas.sasgui.perspectives.fitting.gpu_options import GpuOptions
-from . import models
+from sas.sasgui.perspectives.calculator.model_editor import TextDialog
+from sas.sasgui.perspectives.calculator.model_editor import EditorWindow
+from sas.sasgui.perspectives.calculator.pyconsole import PyConsole
+
+from .fitting_widgets import DataDialog
+from .fit_thread import FitThread
+from .fitpage import Chi2UpdateEvent
+from .console import ConsoleUpdate
+from .fitproblem import FitProblemDictionary
+from .fitpanel import FitPanel
+from .model_thread import Calc1D, Calc2D
+from .resultpanel import ResultPanel, PlotResultEvent
+from .gpu_options import GpuOptions
+
+logger = logging.getLogger(__name__)
MAX_NBR_DATA = 4
@@ -58,13 +74,6 @@ if sys.platform == "win32":
else:
ON_MAC = True
-import bumps.options
-from bumps.gui.fit_dialog import show_fit_config
-try:
- from bumps.gui.fit_dialog import EVT_FITTER_CHANGED
-except ImportError:
- # CRUFT: bumps 0.7.5.8 and below
- EVT_FITTER_CHANGED = None # type: wx.PyCommandEvent
class Plugin(PluginBase):
"""
@@ -118,7 +127,7 @@ class Plugin(PluginBase):
# take care of saving data, model and page associated with each other
self.page_finder = {}
# Log startup
- logging.info("Fitting plug-in started")
+ logger.info("Fitting plug-in started")
self.batch_capable = self.get_batch_capable()
def get_batch_capable(self):
@@ -235,7 +244,6 @@ class Plugin(PluginBase):
"""
event_id = event.GetId()
label = self.edit_menu.GetLabel(event_id)
- from sas.sasgui.perspectives.calculator.pyconsole import PyConsole
filename = os.path.join(models.find_plugins_dir(), label)
frame = PyConsole(parent=self.parent, manager=self,
panel=self.fit_panel,
@@ -252,9 +260,17 @@ class Plugin(PluginBase):
label = self.delete_menu.GetLabel(event_id)
toks = os.path.splitext(label)
path = os.path.join(models.find_plugins_dir(), toks[0])
+ message = "Are you sure you want to delete the file {}?".format(path)
+ dlg = wx.MessageDialog(self.frame, message, '', wx.YES_NO | wx.ICON_QUESTION)
+ if not dlg.ShowModal() == wx.ID_YES:
+ return
try:
for ext in ['.py', '.pyc']:
p_path = path + ext
+ if ext == '.pyc' and not os.path.isfile(path + ext):
+ # If model is invalid, .pyc file may not exist as model has
+ # never been compiled. Don't try and delete it
+ continue
os.remove(p_path)
self.update_custom_combo()
if os.path.isfile(p_path):
@@ -277,7 +293,7 @@ class Plugin(PluginBase):
wx.PostEvent(self.parent, evt)
break
except Exception:
- import traceback; traceback.print_exc()
+ traceback.print_exc()
msg = 'Delete Error: \nCould not delete the file; Check if in use.'
wx.MessageBox(msg, 'Error')
@@ -287,7 +303,7 @@ class Plugin(PluginBase):
"""
event_id = event.GetId()
model_manager = models.ModelManager()
- model_list = model_manager.get_model_name_list()
+ model_list = model_manager.composable_models()
plug_dir = models.find_plugins_dir()
textdial = TextDialog(None, self, wx.ID_ANY, 'Easy Sum/Multi(p1, p2) Editor',
model_list, plug_dir)
@@ -299,7 +315,7 @@ class Plugin(PluginBase):
"""
Make new model
"""
- if self.new_model_frame != None:
+ if self.new_model_frame is not None:
self.new_model_frame.Show(False)
self.new_model_frame.Show(True)
else:
@@ -327,25 +343,42 @@ class Plugin(PluginBase):
# Update edit menus
self.set_edit_menu_helper(self.parent, self.edit_custom_model)
self.set_edit_menu_helper(self.parent, self.delete_custom_model)
- temp = self.fit_panel.reset_pmodel_list()
- if temp:
- # Set the new plugin model list for all fit pages
- for uid, page in self.fit_panel.opened_pages.iteritems():
- if hasattr(page, "formfactorbox"):
- page.model_list_box = temp
- current_val = page.formfactorbox.GetLabel()
- #if page.plugin_rbutton.GetValue():
- mod_cat = page.categorybox.GetStringSelection()
- if mod_cat == custom_model:
- #pos = page.formfactorbox.GetSelection()
- page._show_combox_helper()
- new_val = page.formfactorbox.GetLabel()
- if current_val != new_val and new_val != '':
- page.formfactorbox.SetLabel(new_val)
- else:
- page.formfactorbox.SetLabel(current_val)
- except:
- logging.error("update_custom_combo: %s", sys.exc_value)
+ new_pmodel_list = self.fit_panel.reset_pmodel_list()
+ if not new_pmodel_list:
+ return
+ # Set the new plugin model list for all fit pages
+ for uid, page in self.fit_panel.opened_pages.iteritems():
+ if hasattr(page, "formfactorbox"):
+ page.model_list_box = new_pmodel_list
+ mod_cat = page.categorybox.GetStringSelection()
+ if mod_cat == custom_model:
+ box = page.formfactorbox
+ model_name = box.GetValue()
+ model = (box.GetClientData(box.GetCurrentSelection())
+ if model_name else None)
+ page._show_combox_helper()
+ new_index = box.FindString(model_name)
+ new_model = (box.GetClientData(new_index)
+ if new_index >= 0 else None)
+ if new_index >= 0:
+ box.SetStringSelection(model_name)
+ else:
+ box.SetStringSelection('')
+ if model and new_model != model:
+ page._on_select_model(keep_pars=True)
+ if hasattr(page, "structurebox"):
+ selected_name = page.structurebox.GetStringSelection()
+
+ page.structurebox.Clear()
+ page.initialize_combox()
+
+ index = page.structurebox.FindString(selected_name)
+ if index == -1:
+ index = 0
+ page.structurebox.SetSelection(index)
+ page._on_select_model()
+ except Exception:
+ logger.error("update_custom_combo: %s", sys.exc_value)
def set_edit_menu(self, owner):
"""
@@ -354,9 +387,9 @@ class Plugin(PluginBase):
wx_id = wx.NewId()
#new_model_menu = wx.Menu()
self.edit_model_menu.Append(wx_id, 'New Plugin Model',
- 'Add a new model function')
+ 'Add a new model function')
wx.EVT_MENU(owner, wx_id, self.make_new_model)
-
+
wx_id = wx.NewId()
self.edit_model_menu.Append(wx_id, 'Sum|Multi(p1, p2)',
'Sum of two model functions')
@@ -378,12 +411,12 @@ class Plugin(PluginBase):
self.edit_model_menu.Append(wx_id, 'Load Plugin Models',
'(Re)Load all models present in user plugin_models folder')
wx.EVT_MENU(owner, wx_id, self.load_plugin_models)
-
+
def set_edit_menu_helper(self, owner=None, menu=None):
"""
help for setting list of the edit model menu labels
"""
- if menu == None:
+ if menu is None:
menu = self.edit_custom_model
list_fnames = os.listdir(models.find_plugins_dir())
list_fnames.sort()
@@ -438,7 +471,7 @@ class Plugin(PluginBase):
msg = "%s already opened\n" % str(page.window_caption)
wx.PostEvent(self.parent, StatusEvent(status=msg))
- if page != None:
+ if page is not None:
return set_focus_page(page)
if caption == "Const & Simul Fit":
self.sim_page = self.fit_panel.add_sim_page(caption=caption)
@@ -551,7 +584,6 @@ class Plugin(PluginBase):
self.add_fit_page(data=data_list)
else:
if len(data_list) > MAX_NBR_DATA:
- from fitting_widgets import DataDialog
dlg = DataDialog(data_list=data_list, nb_data=MAX_NBR_DATA)
if dlg.ShowModal() == wx.ID_OK:
selected_data_list = dlg.get_data()
@@ -585,7 +617,7 @@ class Plugin(PluginBase):
except Exception:
msg = "Fitting: cannot deal with the theory received"
evt = StatusEvent(status=msg, info="error")
- logging.error("set_theory " + msg + "\n" + str(sys.exc_value))
+ logger.error("set_theory " + msg + "\n" + str(sys.exc_value))
wx.PostEvent(self.parent, evt)
def set_state(self, state=None, datainfo=None, format=None):
@@ -596,13 +628,13 @@ class Plugin(PluginBase):
: param state: PageState object
: param datainfo: data
"""
- from pagestate import PageState
- from simfitpage import SimFitPageState
if isinstance(state, PageState):
state = state.clone()
self.temp_state.append(state)
elif isinstance(state, SimFitPageState):
- state.load_from_save_state(self)
+ if self.fit_panel.sim_page is None:
+ self.fit_panel.add_sim_page()
+ self.fit_panel.sim_page.load_from_save_state(state)
else:
self.temp_state = []
# index to start with for a new set_state
@@ -631,13 +663,13 @@ class Plugin(PluginBase):
# Load fitting state
state = self.temp_state[self.state_index]
#panel state should have model selection to set_state
- if state.formfactorcombobox != None:
+ if state.formfactorcombobox is not None:
#set state
data = self.parent.create_gui_data(state.data)
data.group_id = state.data.group_id
self.parent.add_data(data_list={data.id: data})
wx.PostEvent(self.parent, NewPlotEvent(plot=data,
- title=data.title))
+ title=data.title))
#need to be fix later make sure we are sendind guiframe.data
#to panel
state.data = data
@@ -648,11 +680,11 @@ class Plugin(PluginBase):
data.group_id = state.data.group_id
self.parent.add_data(data_list={data.id: data})
wx.PostEvent(self.parent, NewPlotEvent(plot=data,
- title=data.title))
+ title=data.title))
page = self.add_fit_page([data])
caption = page.window_caption
self.store_data(uid=page.uid, data_list=page.get_data_list(),
- caption=caption)
+ caption=caption)
self.mypanels.append(page)
# get ready for the next set_state
@@ -769,7 +801,7 @@ class Plugin(PluginBase):
"""
if item.find(".") >= 0:
- param_names = re.split("\.", item)
+ param_names = re.split(r"\.", item)
model_name = param_names[0]
##Assume max len is 3; eg., M0.radius.width
if len(param_names) == 3:
@@ -872,15 +904,8 @@ class Plugin(PluginBase):
weight = self.page_finder[uid].get_weight(fid=fid)
self.draw_model(model=model, data=data, page_id=uid, smearer=smear,
- enable1D=enable1D, enable2D=enable2D,
- qmin=qmin, qmax=qmax, weight=weight)
-
- def _mac_sleep(self, sec=0.2):
- """
- Give sleep to MAC
- """
- if ON_MAC:
- time.sleep(sec)
+ enable1D=enable1D, enable2D=enable2D,
+ qmin=qmin, qmax=qmax, weight=weight)
def draw_model(self, model, page_id, data=None, smearer=None,
enable1D=True, enable2D=False,
@@ -923,18 +948,18 @@ class Plugin(PluginBase):
else:
## draw model 2D with no initial data
self._draw_model2D(model=model,
- page_id=page_id,
- data=data,
- enable2D=enable2D,
- smearer=smearer,
- qmin=qmin,
- qmax=qmax,
- fid=fid,
- weight=weight,
- state=state,
- toggle_mode_on=toggle_mode_on,
- update_chisqr=update_chisqr,
- source=source)
+ page_id=page_id,
+ data=data,
+ enable2D=enable2D,
+ smearer=smearer,
+ qmin=qmin,
+ qmax=qmax,
+ fid=fid,
+ weight=weight,
+ state=state,
+ toggle_mode_on=toggle_mode_on,
+ update_chisqr=update_chisqr,
+ source=source)
def onFit(self, uid):
"""
@@ -943,7 +968,8 @@ class Plugin(PluginBase):
corresponding panels.
:param uid: id related to the panel currently calling this fit function.
"""
- if uid is None: raise RuntimeError("no page to fit") # Should never happen
+ if uid is None:
+ raise RuntimeError("no page to fit") # Should never happen
sim_page_uid = getattr(self.sim_page, 'uid', None)
batch_page_uid = getattr(self.batch_page, 'uid', None)
@@ -977,8 +1003,8 @@ class Plugin(PluginBase):
page_info.nbr_residuals_computed = 0
page = self.fit_panel.get_page_by_id(page_id)
self.set_fit_weight(uid=page.uid,
- flag=page.get_weight_flag(),
- is2d=page._is_2D())
+ flag=page.get_weight_flag(),
+ is2d=page._is_2D())
if not page.param_toFit:
msg = "No fitting parameters for %s" % page.window_caption
evt = StatusEvent(status=msg, info="error", type="stop")
@@ -1002,9 +1028,9 @@ class Plugin(PluginBase):
else:
fitter = sim_fitter
self._add_problem_to_fit(fitproblem=fitproblem,
- pars=pars,
- fitter=fitter,
- fit_id=fit_id)
+ pars=pars,
+ fitter=fitter,
+ fit_id=fit_id)
fit_id += 1
list_page_id.append(page_id)
page_info.clear_model_param()
@@ -1020,7 +1046,7 @@ class Plugin(PluginBase):
wx.PostEvent(self.parent, evt)
return False
## If a thread is already started, stop it
- #if self.calc_fit!= None and self.calc_fit.isrunning():
+ #if self.calc_fitis not None and self.calc_fit.isrunning():
# self.calc_fit.stop()
msg = "Fitting is in progress..."
wx.PostEvent(self.parent, StatusEvent(status=msg, type="progress"))
@@ -1029,7 +1055,6 @@ class Plugin(PluginBase):
handler = ConsoleUpdate(parent=self.parent,
manager=self,
improvement_delta=0.1)
- self._mac_sleep(0.2)
# batch fit
batch_inputs = {}
@@ -1052,12 +1077,12 @@ class Plugin(PluginBase):
else:
## Perform more than 1 fit at the time
calc_fit = FitThread(handler=handler,
- fn=fitter_list,
- batch_inputs=batch_inputs,
- batch_outputs=batch_outputs,
- page_id=list_page_id,
- updatefn=handler.update_fit,
- completefn=self._fit_completed)
+ fn=fitter_list,
+ batch_inputs=batch_inputs,
+ batch_outputs=batch_outputs,
+ page_id=list_page_id,
+ updatefn=handler.update_fit,
+ completefn=self._fit_completed)
#self.fit_thread_list[current_page_id] = calc_fit
self.fit_thread_list[uid] = calc_fit
calc_fit.queue()
@@ -1111,14 +1136,14 @@ class Plugin(PluginBase):
try:
page = self.fit_panel.add_empty_page()
# add data associated to the page created
- if page != None:
+ if page is not None:
evt = StatusEvent(status="Page Created", info="info")
wx.PostEvent(self.parent, evt)
else:
msg = "Page was already Created"
evt = StatusEvent(status=msg, info="warning")
wx.PostEvent(self.parent, evt)
- except:
+ except Exception:
msg = "Creating Fit page: %s" % sys.exc_value
wx.PostEvent(self.parent, StatusEvent(status=msg, info="error"))
@@ -1130,7 +1155,7 @@ class Plugin(PluginBase):
"""
page = self.fit_panel.set_data(data)
# page could be None when loading state files
- if page == None:
+ if page is None:
return page
#append Data1D to the panel containing its theory
#if theory already plotted
@@ -1142,19 +1167,19 @@ class Plugin(PluginBase):
if theory_data is not None:
group_id = str(page.uid) + " Model1D"
wx.PostEvent(self.parent,
- NewPlotEvent(group_id=group_id,
- action="delete"))
+ NewPlotEvent(group_id=group_id,
+ action="delete"))
self.parent.update_data(prev_data=theory_data,
- new_data=data)
+ new_data=data)
else:
if theory_data is not None:
group_id = str(page.uid) + " Model2D"
data.group_id = theory_data.group_id
wx.PostEvent(self.parent,
- NewPlotEvent(group_id=group_id,
- action="delete"))
+ NewPlotEvent(group_id=group_id,
+ action="delete"))
self.parent.update_data(prev_data=theory_data,
- new_data=data)
+ new_data=data)
self.store_data(uid=page.uid, data_list=page.get_data_list(),
caption=page.window_caption)
if self.sim_page is not None and not self.batch_on:
@@ -1198,7 +1223,7 @@ class Plugin(PluginBase):
unschedule or schedule all fitproblem to be fit
"""
# case that uid is not specified
- if uid == None:
+ if uid is None:
for page_id in self.page_finder.keys():
self.page_finder[page_id].schedule_tofit(value)
# when uid is given
@@ -1221,7 +1246,7 @@ class Plugin(PluginBase):
if len(param) > 0:
for item in param:
## check if constraint
- if item[0] != None and item[1] != None:
+ if item[0] is not None and item[1] is not None:
listOfConstraint.append((item[0], item[1]))
new_model = model
fitter.set_model(new_model, fit_id, pars, data=data,
@@ -1236,7 +1261,7 @@ class Plugin(PluginBase):
added to self.page_finder
"""
panel = self.plot_panel
- if panel == None:
+ if panel is None:
raise ValueError, "Fitting:_onSelect: NonType panel"
Plugin.on_perspective(self, event=event)
self.select_data(panel)
@@ -1258,7 +1283,7 @@ class Plugin(PluginBase):
def update_fit(self, result=None, msg=""):
"""
"""
- print "update_fit result", result
+ print("update_fit result", result)
def _batch_fit_complete(self, result, pars, page_id,
batch_outputs, batch_inputs, elapsed=None):
@@ -1269,7 +1294,6 @@ class Plugin(PluginBase):
:param page_id: list of page ids which called fit function
:param elapsed: time spent at the fitting level
"""
- self._mac_sleep(0.2)
uid = page_id[0]
if uid in self.fit_thread_list.keys():
del self.fit_thread_list[uid]
@@ -1322,7 +1346,7 @@ class Plugin(PluginBase):
data = data.sas_data
is_data2d = issubclass(data.__class__, Data2D)
- #check consistency of arrays
+ # Check consistency of arrays
if not is_data2d:
if len(res.theory) == len(res.index[res.index]) and \
len(res.index) == len(data.y):
@@ -1331,18 +1355,24 @@ class Plugin(PluginBase):
copy_data = deepcopy(data)
new_theory = copy_data.data
new_theory[res.index] = res.theory
- new_theory[res.index == False] = numpy.nan
+ new_theory[res.index == False] = np.nan
correct_result = True
- #get all fittable parameters of the current model
+ # Get all fittable parameters of the current model
param_list = model.getParamList()
for param in model.getDispParamList():
- if not model.is_fittable(param) and \
+ if '.' in param and param in param_list:
+ # Ensure polydispersity results are displayed
+ p1, p2 = param.split('.')
+ if not model.is_fittable(p1) and not (p2 == 'width' and param in res.param_list)\
+ and param in param_list:
+ param_list.remove(param)
+ elif not model.is_fittable(param) and \
param in param_list:
param_list.remove(param)
if not correct_result or res.fitness is None or \
- not numpy.isfinite(res.fitness) or \
- numpy.any(res.pvec == None) or not \
- numpy.all(numpy.isfinite(res.pvec)):
+ not np.isfinite(res.fitness) or \
+ np.any(res.pvec is None) or not \
+ np.all(np.isfinite(res.pvec)):
data_name = str(None)
if data is not None:
data_name = str(data.name)
@@ -1351,23 +1381,23 @@ class Plugin(PluginBase):
model_name = str(model.name)
msg += "Data %s and Model %s did not fit.\n" % (data_name,
model_name)
- ERROR = numpy.NAN
+ ERROR = np.NAN
cell = BatchCell()
cell.label = res.fitness
cell.value = res.fitness
batch_outputs["Chi2"].append(ERROR)
for param in param_list:
- # save value of fixed parameters
+ # Save value of fixed parameters
if param not in res.param_list:
batch_outputs[str(param)].append(ERROR)
else:
- #save only fitted values
+ # Save only fitted values
batch_outputs[param].append(ERROR)
batch_inputs["error on %s" % str(param)].append(ERROR)
else:
- # TODO: Why sometimes res.pvec comes with numpy.float64?
+ # TODO: Why sometimes res.pvec comes with np.float64?
# probably from scipy lmfit
- if res.pvec.__class__ == numpy.float64:
+ if res.pvec.__class__ == np.float64:
res.pvec = [res.pvec]
cell = BatchCell()
@@ -1458,12 +1488,11 @@ class Plugin(PluginBase):
#fill batch result information
if "Data" not in batch_outputs.keys():
batch_outputs["Data"] = []
- from sas.sasgui.guiframe.data_processor import BatchCell
cell = BatchCell()
cell.label = data.name
cell.value = index
- if theory_data != None:
+ if theory_data is not None:
#Suucessful fit
theory_data.id = wx.NewId()
theory_data.name = model.name + "[%s]" % str(data.name)
@@ -1519,7 +1548,6 @@ class Plugin(PluginBase):
if page_id is None:
page_id = []
## fit more than 1 model at the same time
- self._mac_sleep(0.2)
try:
index = 0
# Update potential simfit page(s)
@@ -1532,18 +1560,18 @@ class Plugin(PluginBase):
res = result[index]
fit_msg = res.mesg
if res.fitness is None or \
- not numpy.isfinite(res.fitness) or \
- numpy.any(res.pvec == None) or \
- not numpy.all(numpy.isfinite(res.pvec)):
+ not np.isfinite(res.fitness) or \
+ np.any(res.pvec is None) or \
+ not np.all(np.isfinite(res.pvec)):
fit_msg += "\nFitting did not converge!!!"
wx.CallAfter(self._update_fit_button, page_id)
else:
#set the panel when fit result are float not list
- if res.pvec.__class__ == numpy.float64:
+ if res.pvec.__class__ == np.float64:
pvec = [res.pvec]
else:
pvec = res.pvec
- if res.stderr.__class__ == numpy.float64:
+ if res.stderr.__class__ == np.float64:
stderr = [res.stderr]
else:
stderr = res.stderr
@@ -1551,7 +1579,7 @@ class Plugin(PluginBase):
# Make sure we got all results
#(CallAfter is important to MAC)
try:
- #if res != None:
+ #if res is not None:
wx.CallAfter(cpage.onsetValues, res.fitness,
res.param_list,
pvec, stderr)
@@ -1559,16 +1587,16 @@ class Plugin(PluginBase):
wx.CallAfter(cpage._on_fit_complete)
except KeyboardInterrupt:
fit_msg += "\nSingular point: Fitting stopped."
- except:
+ except Exception:
fit_msg += "\nSingular point: Fitting error occurred."
if fit_msg:
- evt = StatusEvent(status=fit_msg, info="warning", type="stop")
- wx.PostEvent(self.parent, evt)
+ evt = StatusEvent(status=fit_msg, info="warning", type="stop")
+ wx.PostEvent(self.parent, evt)
- except:
+ except Exception:
msg = ("Fit completed but the following error occurred: %s"
% sys.exc_value)
- #import traceback; msg = "\n".join((traceback.format_exc(), msg))
+ #msg = "\n".join((traceback.format_exc(), msg))
evt = StatusEvent(status=msg, info="warning", type="stop")
wx.PostEvent(self.parent, evt)
@@ -1594,7 +1622,7 @@ class Plugin(PluginBase):
Set batch_reset_flag
"""
event.Skip()
- if self.menu1 == None:
+ if self.menu1 is None:
return
menu_item = self.menu1.FindItemById(self.id_reset_flag)
flag = menu_item.IsChecked()
@@ -1653,7 +1681,7 @@ class Plugin(PluginBase):
qmax = evt.qmax
caption = evt.caption
enable_smearer = evt.enable_smearer
- if model == None:
+ if model is None:
return
if uid not in self.page_finder.keys():
return
@@ -1691,7 +1719,7 @@ class Plugin(PluginBase):
new_plot = Data1D(x=x, y=y)
if dy is None:
new_plot.is_data = False
- new_plot.dy = numpy.zeros(len(y))
+ new_plot.dy = np.zeros(len(y))
# If this is a theory curve, pick the proper symbol to make it a curve
new_plot.symbol = GUIFRAME_ID.CURVE_SYMBOL_NUM
else:
@@ -1705,7 +1733,7 @@ class Plugin(PluginBase):
_xaxis, _xunit = data.get_xaxis()
new_plot.title = data.name
new_plot.group_id = data.group_id
- if new_plot.group_id == None:
+ if new_plot.group_id is None:
new_plot.group_id = data.group_id
new_plot.id = data_id
# Find if this theory was already plotted and replace that plot given
@@ -1723,7 +1751,7 @@ class Plugin(PluginBase):
self.page_finder[page_id].set_theory_data(data=new_plot,
fid=data.id)
self.parent.update_theory(data_id=data.id, theory=new_plot,
- state=state)
+ state=state)
return new_plot
def _complete1D(self, x, y, page_id, elapsed, index, model,
@@ -1739,73 +1767,88 @@ class Plugin(PluginBase):
@param unsmeared_data: data, rescaled to unsmeared model
@param unsmeared_error: data error, rescaled to unsmeared model
"""
- try:
- numpy.nan_to_num(y)
- new_plot = self.create_theory_1D(x, y, page_id, model, data, state,
- data_description=model.name,
- data_id=str(page_id) + " " + data.name)
- if unsmeared_model is not None:
- self.create_theory_1D(x, unsmeared_model, page_id, model, data, state,
- data_description=model.name + " unsmeared",
- data_id=str(page_id) + " " + data.name + " unsmeared")
-
- if unsmeared_data is not None and unsmeared_error is not None:
- self.create_theory_1D(x, unsmeared_data, page_id, model, data, state,
- data_description="Data unsmeared",
- data_id="Data " + data.name + " unsmeared",
- dy=unsmeared_error)
- # Comment this out until we can get P*S models with correctly populated parameters
- #if sq_model is not None and pq_model is not None:
- # self.create_theory_1D(x, sq_model, page_id, model, data, state,
- # data_description=model.name + " S(q)",
- # data_id=str(page_id) + " " + data.name + " S(q)")
- # self.create_theory_1D(x, pq_model, page_id, model, data, state,
- # data_description=model.name + " P(q)",
- # data_id=str(page_id) + " " + data.name + " P(q)")
-
- current_pg = self.fit_panel.get_page_by_id(page_id)
- title = new_plot.title
- batch_on = self.fit_panel.get_page_by_id(page_id).batch_on
- if not batch_on:
- wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot,
- title=str(title)))
- elif plot_result:
- top_data_id = self.fit_panel.get_page_by_id(page_id).data.id
- if data.id == top_data_id:
- wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot,
- title=str(title)))
- caption = current_pg.window_caption
- self.page_finder[page_id].set_fit_tab_caption(caption=caption)
-
- self.page_finder[page_id].set_theory_data(data=new_plot,
- fid=data.id)
- if toggle_mode_on:
- wx.PostEvent(self.parent,
- NewPlotEvent(group_id=str(page_id) + " Model2D",
- action="Hide"))
+ number_finite = np.count_nonzero(np.isfinite(y))
+ np.nan_to_num(y)
+ new_plot = self.create_theory_1D(x, y, page_id, model, data, state,
+ data_description=model.name,
+ data_id=str(page_id) + " " + data.name)
+ plots_to_update = [] # List of plottables that have changed since last calculation
+ # Create the new theories
+ if unsmeared_model is not None:
+ unsmeared_model_plot = self.create_theory_1D(x, unsmeared_model,
+ page_id, model, data, state,
+ data_description=model.name + " unsmeared",
+ data_id=str(page_id) + " " + data.name + " unsmeared")
+ plots_to_update.append(unsmeared_model_plot)
+
+ if unsmeared_data is not None and unsmeared_error is not None:
+ unsmeared_data_plot = self.create_theory_1D(x, unsmeared_data,
+ page_id, model, data, state,
+ data_description="Data unsmeared",
+ data_id="Data " + data.name + " unsmeared",
+ dy=unsmeared_error)
+ plots_to_update.append(unsmeared_data_plot)
+ if sq_model is not None and pq_model is not None:
+ sq_id = str(page_id) + " " + data.name + " S(q)"
+ sq_plot = self.create_theory_1D(x, sq_model, page_id, model, data, state,
+ data_description=model.name + " S(q)",
+ data_id=sq_id)
+ plots_to_update.append(sq_plot)
+ pq_id = str(page_id) + " " + data.name + " P(q)"
+ pq_plot = self.create_theory_1D(x, pq_model, page_id, model, data, state,
+ data_description=model.name + " P(q)",
+ data_id=pq_id)
+ plots_to_update.append(pq_plot)
+ # Update the P(Q), S(Q) and unsmeared theory plots if they exist
+ wx.PostEvent(self.parent, NewPlotEvent(plots=plots_to_update,
+ action='update'))
+
+ current_pg = self.fit_panel.get_page_by_id(page_id)
+ title = new_plot.title
+ batch_on = self.fit_panel.get_page_by_id(page_id).batch_on
+ if not batch_on:
+ wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title=str(title)))
+ elif plot_result:
+ top_data_id = self.fit_panel.get_page_by_id(page_id).data.id
+ if data.id == top_data_id:
+ wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title=str(title)))
+ caption = current_pg.window_caption
+ self.page_finder[page_id].set_fit_tab_caption(caption=caption)
+
+ self.page_finder[page_id].set_theory_data(data=new_plot,
+ fid=data.id)
+ if toggle_mode_on:
+ wx.PostEvent(self.parent,
+ NewPlotEvent(group_id=str(page_id) + " Model2D",
+ action="Hide"))
+ else:
+ if update_chisqr:
+ output = self._cal_chisqr(data=data,
+ fid=fid,
+ weight=weight,
+ page_id=page_id,
+ index=index)
+ wx.PostEvent(current_pg, Chi2UpdateEvent(output=output))
else:
- if update_chisqr:
- wx.PostEvent(current_pg,
- Chi2UpdateEvent(output=self._cal_chisqr(
- data=data,
- fid=fid,
- weight=weight,
- page_id=page_id,
- index=index)))
- else:
- self._plot_residuals(page_id=page_id, data=data, fid=fid,
- index=index, weight=weight)
+ self._plot_residuals(page_id=page_id, data=data, fid=fid,
+ index=index, weight=weight)
+ if not number_finite:
+ logger.error("Using the present parameters the model does not return any finite value. ")
+ msg = "Computing Error: Model did not return any finite value."
+ wx.PostEvent(self.parent, StatusEvent(status=msg, info="error"))
+ else:
msg = "Computation completed!"
+ if number_finite != y.size:
+ msg += ' PROBLEM: For some Q values the model returns non finite intensities!'
+ logger.error("For some Q values the model returns non finite intensities.")
wx.PostEvent(self.parent, StatusEvent(status=msg, type="stop"))
- except:
- raise
def _calc_exception(self, etype, value, tb):
"""
Handle exception from calculator by posting it as an error.
"""
- logging.error("".join(traceback.format_exception(etype, value, tb)))
+ logger.error("".join(traceback.format_exception(etype, value, tb)))
msg = traceback.format_exception(etype, value, tb, limit=1)
evt = StatusEvent(status="".join(msg), type="stop", info="error")
wx.PostEvent(self.parent, evt)
@@ -1818,13 +1861,14 @@ class Plugin(PluginBase):
wx.PostEvent(self.parent, StatusEvent(msg, type="update"))
def _complete2D(self, image, data, model, page_id, elapsed, index, qmin,
- qmax, fid=None, weight=None, toggle_mode_on=False, state=None,
- update_chisqr=True, source='model', plot_result=True):
+ qmax, fid=None, weight=None, toggle_mode_on=False, state=None,
+ update_chisqr=True, source='model', plot_result=True):
"""
Complete get the result of modelthread and create model 2D
that can be plot.
"""
- numpy.nan_to_num(image)
+ number_finite = np.count_nonzero(np.isfinite(image))
+ np.nan_to_num(image)
new_plot = Data2D(image=image, err_image=data.err_data)
new_plot.name = model.name + '2d'
new_plot.title = "Analytical model 2D "
@@ -1859,31 +1903,39 @@ class Plugin(PluginBase):
self.page_finder[page_id].set_theory_data(data=theory_data,
fid=data.id)
self.parent.update_theory(data_id=data.id,
- theory=new_plot,
- state=state)
+ theory=new_plot,
+ state=state)
current_pg = self.fit_panel.get_page_by_id(page_id)
title = new_plot.title
if not source == 'fit' and plot_result:
- wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot,
- title=title))
+ wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title=title))
if toggle_mode_on:
wx.PostEvent(self.parent,
- NewPlotEvent(group_id=str(page_id) + " Model1D",
- action="Hide"))
+ NewPlotEvent(group_id=str(page_id) + " Model1D",
+ action="Hide"))
else:
# Chisqr in fitpage
if update_chisqr:
- wx.PostEvent(current_pg,
- Chi2UpdateEvent(output=self._cal_chisqr(data=data,
- weight=weight,
- fid=fid,
- page_id=page_id,
- index=index)))
+ output = self._cal_chisqr(data=data,
+ weight=weight,
+ fid=fid,
+ page_id=page_id,
+ index=index)
+ wx.PostEvent(current_pg, Chi2UpdateEvent(output=output))
else:
self._plot_residuals(page_id=page_id, data=data, fid=fid,
- index=index, weight=weight)
- msg = "Computation completed!"
- wx.PostEvent(self.parent, StatusEvent(status=msg, type="stop"))
+ index=index, weight=weight)
+
+ if not number_finite:
+ logger.error("Using the present parameters the model does not return any finite value. ")
+ msg = "Computing Error: Model did not return any finite value."
+ wx.PostEvent(self.parent, StatusEvent(status=msg, info="error"))
+ else:
+ msg = "Computation completed!"
+ if number_finite != image.size:
+ msg += ' PROBLEM: For some Qx,Qy values the model returns non finite intensities!'
+ logger.error("For some Qx,Qy values the model returns non finite intensities.")
+ wx.PostEvent(self.parent, StatusEvent(status=msg, type="stop"))
def _draw_model2D(self, model, page_id, qmin,
qmax,
@@ -1893,7 +1945,7 @@ class Plugin(PluginBase):
fid=None,
weight=None,
toggle_mode_on=False,
- update_chisqr=True, source='model'):
+ update_chisqr=True, source='model'):
"""
draw model in 2D
@@ -1908,7 +1960,6 @@ class Plugin(PluginBase):
if not enable2D:
return None
try:
- from model_thread import Calc2D
## If a thread is already started, stop it
if (self.calc_2D is not None) and self.calc_2D.isrunning():
self.calc_2D.stop()
@@ -1917,7 +1968,7 @@ class Plugin(PluginBase):
## an actual problem. Seems the fix should also go here
## and may be the cause of other noted instabilities
##
- ## -PDB August 12, 2014
+ ## -PDB August 12, 2014
while self.calc_2D.isrunning():
time.sleep(0.1)
self.calc_2D = Calc2D(model=model,
@@ -1940,11 +1991,9 @@ class Plugin(PluginBase):
def _draw_model1D(self, model, page_id, data,
qmin, qmax, smearer=None,
- state=None,
- weight=None,
- fid=None,
- toggle_mode_on=False, update_chisqr=True, source='model',
- enable1D=True):
+ state=None, weight=None, fid=None,
+ toggle_mode_on=False, update_chisqr=True, source='model',
+ enable1D=True):
"""
Draw model 1D from loaded data1D
@@ -1955,11 +2004,10 @@ class Plugin(PluginBase):
if not enable1D:
return
try:
- from model_thread import Calc1D
## If a thread is already started, stop it
if (self.calc_1D is not None) and self.calc_1D.isrunning():
self.calc_1D.stop()
- ## stop just raises the flag -- the thread is supposed to
+ ## stop just raises the flag -- the thread is supposed to
## then kill itself but cannot. Paul Kienzle came up with
## this fix to prevent threads from stepping on each other
## which was causing a simple custom plugin model to crash
@@ -1971,7 +2019,7 @@ class Plugin(PluginBase):
## that the GUI can still respond to user input including
## a request to stop the computation.
## It seems thus that the whole thread approach used here
- ## May need rethinking
+ ## May need rethinking
##
## -PDB August 12, 2014
while self.calc_1D.isrunning():
@@ -2009,33 +2057,33 @@ class Plugin(PluginBase):
# default chisqr
chisqr = None
#to compute chisq make sure data has valid data
- # return None if data == None
- if not check_data_validity(data_copy) or data_copy == None:
+ # return None if data is None
+ if not check_data_validity(data_copy) or data_copy is None:
return chisqr
# Get data: data I, theory I, and data dI in order
if data_copy.__class__.__name__ == "Data2D":
- if index == None:
- index = numpy.ones(len(data_copy.data), dtype=bool)
- if weight != None:
+ if index is None:
+ index = np.ones(len(data_copy.data), dtype=bool)
+ if weight is not None:
data_copy.err_data = weight
# get rid of zero error points
index = index & (data_copy.err_data != 0)
- index = index & (numpy.isfinite(data_copy.data))
+ index = index & (np.isfinite(data_copy.data))
fn = data_copy.data[index]
theory_data = self.page_finder[page_id].get_theory_data(fid=data_copy.id)
- if theory_data == None:
+ if theory_data is None:
return chisqr
gn = theory_data.data[index]
en = data_copy.err_data[index]
else:
# 1 d theory from model_thread is only in the range of index
- if index == None:
- index = numpy.ones(len(data_copy.y), dtype=bool)
- if weight != None:
+ if index is None:
+ index = np.ones(len(data_copy.y), dtype=bool)
+ if weight is not None:
data_copy.dy = weight
- if data_copy.dy == None or data_copy.dy == []:
- dy = numpy.ones(len(data_copy.y))
+ if data_copy.dy is None or data_copy.dy == []:
+ dy = np.ones(len(data_copy.y))
else:
## Set consistently w/AbstractFitengine:
# But this should be corrected later.
@@ -2044,7 +2092,7 @@ class Plugin(PluginBase):
fn = data_copy.y[index]
theory_data = self.page_finder[page_id].get_theory_data(fid=data_copy.id)
- if theory_data == None:
+ if theory_data is None:
return chisqr
gn = theory_data.y
en = dy[index]
@@ -2053,12 +2101,12 @@ class Plugin(PluginBase):
try:
res = (fn - gn) / en
except ValueError:
- print "Unmatch lengths %s, %s, %s" % (len(fn), len(gn), len(en))
+ print("Unmatch lengths %s, %s, %s" % (len(fn), len(gn), len(en)))
return
- residuals = res[numpy.isfinite(res)]
+ residuals = res[np.isfinite(res)]
# get chisqr only w/finite
- chisqr = numpy.average(residuals * residuals)
+ chisqr = np.average(residuals * residuals)
self._plot_residuals(page_id=page_id, data=data_copy,
fid=fid,
@@ -2087,7 +2135,7 @@ class Plugin(PluginBase):
fn = data_copy.data
theory_data = self.page_finder[page_id].get_theory_data(fid=data_copy.id)
gn = theory_data.data
- if weight == None:
+ if weight is None:
en = data_copy.err_data
else:
en = weight
@@ -2095,7 +2143,7 @@ class Plugin(PluginBase):
residuals.qx_data = data_copy.qx_data
residuals.qy_data = data_copy.qy_data
residuals.q_data = data_copy.q_data
- residuals.err_data = numpy.ones(len(residuals.data))
+ residuals.err_data = np.ones(len(residuals.data))
residuals.xmin = min(residuals.qx_data)
residuals.xmax = max(residuals.qx_data)
residuals.ymin = min(residuals.qy_data)
@@ -2108,11 +2156,11 @@ class Plugin(PluginBase):
return
else:
# 1 d theory from model_thread is only in the range of index
- if data_copy.dy == None or data_copy.dy == []:
- dy = numpy.ones(len(data_copy.y))
+ if data_copy.dy is None or data_copy.dy == []:
+ dy = np.ones(len(data_copy.y))
else:
- if weight == None:
- dy = numpy.ones(len(data_copy.y))
+ if weight is None:
+ dy = np.ones(len(data_copy.y))
## Set consitently w/AbstractFitengine:
## But this should be corrected later.
else:
@@ -2131,12 +2179,12 @@ class Plugin(PluginBase):
wx.PostEvent(self.parent, StatusEvent(status=msg, info="error"))
residuals.y = (fn - gn[index]) / en
residuals.x = data_copy.x[index]
- residuals.dy = numpy.ones(len(residuals.y))
+ residuals.dy = np.ones(len(residuals.y))
residuals.dx = None
residuals.dxl = None
residuals.dxw = None
residuals.ytransform = 'y'
- # For latter scale changes
+ # For latter scale changes
residuals.xaxis('\\rm{Q} ', 'A^{-1}')
residuals.yaxis('\\rm{Residuals} ', 'normalized')
theory_name = str(theory_data.name.split()[0])
@@ -2149,7 +2197,7 @@ class Plugin(PluginBase):
new_plot.id = "res" + str(data_copy.id) + str(theory_name)
##group_id specify on which panel to plot this data
group_id = self.page_finder[page_id].get_graph_id()
- if group_id == None:
+ if group_id is None:
group_id = data.group_id
new_plot.group_id = "res" + str(group_id)
#new_plot.is_data = True
diff --git a/src/sas/sasgui/perspectives/fitting/fitting_widgets.py b/src/sas/sasgui/perspectives/fitting/fitting_widgets.py
index 4fca6ef..9d5808e 100644
--- a/src/sas/sasgui/perspectives/fitting/fitting_widgets.py
+++ b/src/sas/sasgui/perspectives/fitting/fitting_widgets.py
@@ -1,188 +1,188 @@
-
-################################################################################
-#This software was developed by the University of Tennessee as part of the
-#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
-#project funded by the US National Science Foundation.
-#
-#See the license text in license.txt
-#
-#copyright 2009, University of Tennessee
-################################################################################
-import wx
-from wx.lib.scrolledpanel import ScrolledPanel
-
-MAX_NBR_DATA = 4
-WIDTH = 430
-HEIGHT = 350
-
-
-class DialogPanel(ScrolledPanel):
- def __init__(self, *args, **kwds):
- ScrolledPanel.__init__(self, *args, **kwds)
- self.SetupScrolling()
-
-
-class BatchDataDialog(wx.Dialog):
- """
- The current design of Batch fit allows only of type of data in the data
- set. This allows the user to make a quick selection of the type of data
- to use in fit tab.
- """
- def __init__(self, parent=None, *args, **kwds):
- wx.Dialog.__init__(self, parent, *args, **kwds)
- self.SetSize((WIDTH, HEIGHT))
- self.data_1d_selected = None
- self.data_2d_selected = None
- self._do_layout()
-
- def _do_layout(self):
- """
- Draw the content of the current dialog window
- """
- vbox = wx.BoxSizer(wx.VERTICAL)
- box_description = wx.StaticBox(self, wx.ID_ANY, str("Hint"))
- hint_sizer = wx.StaticBoxSizer(box_description, wx.VERTICAL)
- selection_sizer = wx.GridBagSizer(5, 5)
- button_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.data_1d_selected = wx.RadioButton(self, wx.ID_ANY, 'Data1D',
- style=wx.RB_GROUP)
- self.data_2d_selected = wx.RadioButton(self, wx.ID_ANY, 'Data2D')
- self.data_1d_selected.SetValue(True)
- self.data_2d_selected.SetValue(False)
- button_cancel = wx.Button(self, wx.ID_CANCEL, "Cancel")
- button_OK = wx.Button(self, wx.ID_OK, "Ok")
- button_OK.SetFocus()
- hint = "Selected Data set contains both 1D and 2D Data.\n"
- hint += "Please select on type of analysis before proceeding.\n"
- hint_sizer.Add(wx.StaticText(self, wx.ID_ANY, hint))
- #draw area containing radio buttons
- ix = 0
- iy = 0
- selection_sizer.Add(self.data_1d_selected, (iy, ix),
- (1, 1), wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- iy += 1
- selection_sizer.Add(self.data_2d_selected, (iy, ix),
- (1, 1), wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- #contruction the sizer contaning button
- button_sizer.Add((20, 20), 1, wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- button_sizer.Add(button_cancel, 0,
- wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 10)
- button_sizer.Add(button_OK, 0,
- wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 10)
- vbox.Add(hint_sizer, 0, wx.EXPAND | wx.ALL, 10)
- vbox.Add(selection_sizer, 0, wx.TOP | wx.BOTTOM, 10)
- vbox.Add(wx.StaticLine(self, wx.ID_ANY), 0, wx.EXPAND, 0)
- vbox.Add(button_sizer, 0, wx.TOP | wx.BOTTOM, 10)
- self.SetSizer(vbox)
- self.Layout()
-
- def get_data(self):
- """
- return 1 if user requested Data1D , 2 if user requested Data2D
- """
- if self.data_1d_selected.GetValue():
- return 1
- else:
- return 2
-
-
-class DataDialog(wx.Dialog):
- """
- Allow file selection at loading time
- """
- def __init__(self, data_list, parent=None, text='',
- nb_data=MAX_NBR_DATA, *args, **kwds):
- wx.Dialog.__init__(self, parent, *args, **kwds)
- self.SetTitle("Data Selection")
- self._max_data = nb_data
- self._nb_selected_data = nb_data
-
- self.SetSize((WIDTH, HEIGHT))
- self.list_of_ctrl = []
- if not data_list:
- return
- select_data_text = " %s Data selected.\n" % str(self._nb_selected_data)
- self._data_text_ctrl = wx.StaticText(self, wx.ID_ANY, str(select_data_text))
-
- self._data_text_ctrl.SetForegroundColour('blue')
- self._sizer_main = wx.BoxSizer(wx.VERTICAL)
- self._sizer_txt = wx.BoxSizer(wx.VERTICAL)
- self._sizer_button = wx.BoxSizer(wx.HORIZONTAL)
- self._choice_sizer = wx.GridBagSizer(5, 5)
- self._panel = DialogPanel(self, style=wx.RAISED_BORDER,
- size=(WIDTH - 20, HEIGHT / 3))
- self.__do_layout(data_list, text=text)
-
- def __do_layout(self, data_list, text=''):
- """
- layout the dialog
- """
- if not data_list or len(data_list) <= 1:
- return
- #add text
- if text.strip() == "":
- text = "Fitting: We recommend that you selected"
- text += " no more than '%s' data\n" % str(self._max_data)
- text += "for adequate plot display size. \n"
- text += "unchecked data won't be send to fitting . \n"
- text_ctrl = wx.StaticText(self, wx.ID_ANY, str(text))
- self._sizer_txt.Add(text_ctrl)
- iy = 0
- ix = 0
- data_count = 0
- for i in range(len(data_list)):
- data_count += 1
- cb = wx.CheckBox(self._panel, wx.ID_ANY, str(data_list[i].name), (10, 10))
- wx.EVT_CHECKBOX(self, cb.GetId(), self._count_selected_data)
- if data_count <= MAX_NBR_DATA:
- cb.SetValue(True)
- else:
- cb.SetValue(False)
- self.list_of_ctrl.append((cb, data_list[i]))
- self._choice_sizer.Add(cb, (iy, ix),
- (1, 1), wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- iy += 1
- self._panel.SetSizer(self._choice_sizer)
- #add sizer
- self._sizer_button.Add((20, 20), 1, wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- button_cancel = wx.Button(self, wx.ID_CANCEL, "Cancel")
- self._sizer_button.Add(button_cancel, 0,
- wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 10)
- button_OK = wx.Button(self, wx.ID_OK, "Ok")
- button_OK.SetFocus()
- self._sizer_button.Add(button_OK, 0,
- wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 10)
- static_line = wx.StaticLine(self, wx.ID_ANY)
- self._sizer_txt.Add(self._panel, 0, wx.EXPAND | wx.ALL, 10)
- self._sizer_main.Add(self._sizer_txt, 0, wx.EXPAND | wx.ALL, 10)
- self._sizer_main.Add(self._data_text_ctrl, 0, wx.EXPAND | wx.ALL, 10)
- self._sizer_main.Add(static_line, 0, wx.EXPAND, 0)
- self._sizer_main.Add(self._sizer_button, 0, wx.EXPAND | wx.ALL, 10)
- self.SetSizer(self._sizer_main)
- self.Layout()
-
- def get_data(self):
- """
- return the selected data
- """
- temp = []
- for item in self.list_of_ctrl:
- cb, data = item
- if cb.GetValue():
- temp.append(data)
- return temp
-
- def _count_selected_data(self, event):
- """
- count selected data
- """
- if event.GetEventObject().GetValue():
- self._nb_selected_data += 1
- else:
- self._nb_selected_data -= 1
- select_data_text = " %s Data selected.\n" % str(self._nb_selected_data)
- self._data_text_ctrl.SetLabel(select_data_text)
- if self._nb_selected_data <= self._max_data:
- self._data_text_ctrl.SetForegroundColour('blue')
- else:
- self._data_text_ctrl.SetForegroundColour('red')
+
+################################################################################
+#This software was developed by the University of Tennessee as part of the
+#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
+#project funded by the US National Science Foundation.
+#
+#See the license text in license.txt
+#
+#copyright 2009, University of Tennessee
+################################################################################
+import wx
+from wx.lib.scrolledpanel import ScrolledPanel
+
+MAX_NBR_DATA = 4
+WIDTH = 430
+HEIGHT = 350
+
+
+class DialogPanel(ScrolledPanel):
+ def __init__(self, *args, **kwds):
+ ScrolledPanel.__init__(self, *args, **kwds)
+ self.SetupScrolling()
+
+
+class BatchDataDialog(wx.Dialog):
+ """
+ The current design of Batch fit allows only of type of data in the data
+ set. This allows the user to make a quick selection of the type of data
+ to use in fit tab.
+ """
+ def __init__(self, parent=None, *args, **kwds):
+ wx.Dialog.__init__(self, parent, *args, **kwds)
+ self.SetSize((WIDTH, HEIGHT))
+ self.data_1d_selected = None
+ self.data_2d_selected = None
+ self._do_layout()
+
+ def _do_layout(self):
+ """
+ Draw the content of the current dialog window
+ """
+ vbox = wx.BoxSizer(wx.VERTICAL)
+ box_description = wx.StaticBox(self, wx.ID_ANY, str("Hint"))
+ hint_sizer = wx.StaticBoxSizer(box_description, wx.VERTICAL)
+ selection_sizer = wx.GridBagSizer(5, 5)
+ button_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.data_1d_selected = wx.RadioButton(self, wx.ID_ANY, 'Data1D',
+ style=wx.RB_GROUP)
+ self.data_2d_selected = wx.RadioButton(self, wx.ID_ANY, 'Data2D')
+ self.data_1d_selected.SetValue(True)
+ self.data_2d_selected.SetValue(False)
+ button_cancel = wx.Button(self, wx.ID_CANCEL, "Cancel")
+ button_OK = wx.Button(self, wx.ID_OK, "Ok")
+ button_OK.SetFocus()
+ hint = "Selected Data set contains both 1D and 2D Data.\n"
+ hint += "Please select on type of analysis before proceeding.\n"
+ hint_sizer.Add(wx.StaticText(self, wx.ID_ANY, hint))
+ #draw area containing radio buttons
+ ix = 0
+ iy = 0
+ selection_sizer.Add(self.data_1d_selected, (iy, ix),
+ (1, 1), wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ iy += 1
+ selection_sizer.Add(self.data_2d_selected, (iy, ix),
+ (1, 1), wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ #contruction the sizer contaning button
+ button_sizer.Add((20, 20), 1, wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ button_sizer.Add(button_cancel, 0,
+ wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 10)
+ button_sizer.Add(button_OK, 0,
+ wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 10)
+ vbox.Add(hint_sizer, 0, wx.EXPAND | wx.ALL, 10)
+ vbox.Add(selection_sizer, 0, wx.TOP | wx.BOTTOM, 10)
+ vbox.Add(wx.StaticLine(self, wx.ID_ANY), 0, wx.EXPAND, 0)
+ vbox.Add(button_sizer, 0, wx.TOP | wx.BOTTOM, 10)
+ self.SetSizer(vbox)
+ self.Layout()
+
+ def get_data(self):
+ """
+ return 1 if user requested Data1D , 2 if user requested Data2D
+ """
+ if self.data_1d_selected.GetValue():
+ return 1
+ else:
+ return 2
+
+
+class DataDialog(wx.Dialog):
+ """
+ Allow file selection at loading time
+ """
+ def __init__(self, data_list, parent=None, text='',
+ nb_data=MAX_NBR_DATA, *args, **kwds):
+ wx.Dialog.__init__(self, parent, *args, **kwds)
+ self.SetTitle("Data Selection")
+ self._max_data = nb_data
+ self._nb_selected_data = nb_data
+
+ self.SetSize((WIDTH, HEIGHT))
+ self.list_of_ctrl = []
+ if not data_list:
+ return
+ select_data_text = " %s Data selected.\n" % str(self._nb_selected_data)
+ self._data_text_ctrl = wx.StaticText(self, wx.ID_ANY, str(select_data_text))
+
+ self._data_text_ctrl.SetForegroundColour('blue')
+ self._sizer_main = wx.BoxSizer(wx.VERTICAL)
+ self._sizer_txt = wx.BoxSizer(wx.VERTICAL)
+ self._sizer_button = wx.BoxSizer(wx.HORIZONTAL)
+ self._choice_sizer = wx.GridBagSizer(5, 5)
+ self._panel = DialogPanel(self, style=wx.RAISED_BORDER,
+ size=(WIDTH - 20, HEIGHT / 3))
+ self.__do_layout(data_list, text=text)
+
+ def __do_layout(self, data_list, text=''):
+ """
+ layout the dialog
+ """
+ if not data_list or len(data_list) <= 1:
+ return
+ #add text
+ if text.strip() == "":
+ text = "Fitting: We recommend that you selected"
+ text += " no more than '%s' data\n" % str(self._max_data)
+ text += "for adequate plot display size. \n"
+ text += "unchecked data won't be send to fitting . \n"
+ text_ctrl = wx.StaticText(self, wx.ID_ANY, str(text))
+ self._sizer_txt.Add(text_ctrl)
+ iy = 0
+ ix = 0
+ data_count = 0
+ for i in range(len(data_list)):
+ data_count += 1
+ cb = wx.CheckBox(self._panel, wx.ID_ANY, str(data_list[i].name), (10, 10))
+ wx.EVT_CHECKBOX(self, cb.GetId(), self._count_selected_data)
+ if data_count <= MAX_NBR_DATA:
+ cb.SetValue(True)
+ else:
+ cb.SetValue(False)
+ self.list_of_ctrl.append((cb, data_list[i]))
+ self._choice_sizer.Add(cb, (iy, ix),
+ (1, 1), wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ iy += 1
+ self._panel.SetSizer(self._choice_sizer)
+ #add sizer
+ self._sizer_button.Add((20, 20), 1, wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ button_cancel = wx.Button(self, wx.ID_CANCEL, "Cancel")
+ self._sizer_button.Add(button_cancel, 0,
+ wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 10)
+ button_OK = wx.Button(self, wx.ID_OK, "Ok")
+ button_OK.SetFocus()
+ self._sizer_button.Add(button_OK, 0,
+ wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 10)
+ static_line = wx.StaticLine(self, wx.ID_ANY)
+ self._sizer_txt.Add(self._panel, 0, wx.EXPAND | wx.ALL, 10)
+ self._sizer_main.Add(self._sizer_txt, 0, wx.EXPAND | wx.ALL, 10)
+ self._sizer_main.Add(self._data_text_ctrl, 0, wx.EXPAND | wx.ALL, 10)
+ self._sizer_main.Add(static_line, 0, wx.EXPAND, 0)
+ self._sizer_main.Add(self._sizer_button, 0, wx.EXPAND | wx.ALL, 10)
+ self.SetSizer(self._sizer_main)
+ self.Layout()
+
+ def get_data(self):
+ """
+ return the selected data
+ """
+ temp = []
+ for item in self.list_of_ctrl:
+ cb, data = item
+ if cb.GetValue():
+ temp.append(data)
+ return temp
+
+ def _count_selected_data(self, event):
+ """
+ count selected data
+ """
+ if event.GetEventObject().GetValue():
+ self._nb_selected_data += 1
+ else:
+ self._nb_selected_data -= 1
+ select_data_text = " %s Data selected.\n" % str(self._nb_selected_data)
+ self._data_text_ctrl.SetLabel(select_data_text)
+ if self._nb_selected_data <= self._max_data:
+ self._data_text_ctrl.SetForegroundColour('blue')
+ else:
+ self._data_text_ctrl.SetForegroundColour('red')
diff --git a/src/sas/sasgui/perspectives/fitting/gpu_options.py b/src/sas/sasgui/perspectives/fitting/gpu_options.py
index b8d10fb..bc09b4d 100644
--- a/src/sas/sasgui/perspectives/fitting/gpu_options.py
+++ b/src/sas/sasgui/perspectives/fitting/gpu_options.py
@@ -317,7 +317,7 @@ class GpuOptions(wx.Dialog):
"""
Provide help on opencl options.
"""
- TreeLocation = "user/gpu_computations.html"
+ TreeLocation = "user/sasgui/perspectives/fitting/gpu_setup.html"
anchor = "#device-selection"
DocumentationWindow(self, -1,
TreeLocation, anchor, "OpenCL Options Help")
diff --git a/src/sas/sasgui/perspectives/fitting/hint_fitpage.py b/src/sas/sasgui/perspectives/fitting/hint_fitpage.py
index 389ff30..2d53931 100644
--- a/src/sas/sasgui/perspectives/fitting/hint_fitpage.py
+++ b/src/sas/sasgui/perspectives/fitting/hint_fitpage.py
@@ -1,55 +1,55 @@
-"""
- This class provide general structure of fitpanel page
-"""
-import wx
-from sas.sasgui.guiframe.panel_base import PanelBase
-
-class HintFitPage(wx.ScrolledWindow, PanelBase):
- """
- This class provide general structure of fitpanel page
- """
- ## Internal name for the AUI manager
- window_name = "Hint Page"
- ## Title to appear on top of the window
- window_caption = "Hint page "
-
- def __init__(self, parent):
- wx.ScrolledWindow.__init__(self, parent,
- style=wx.FULL_REPAINT_ON_RESIZE)
- PanelBase.__init__(self, parent)
- msg = "right click on the data when it is highlighted "
- msg += "the select option to fit for futher options"
- self.do_layout()
-
- def do_layout(self):
- """
- Draw the page
- """
- name = "Hint"
- box_description = wx.StaticBox(self, wx.ID_ANY, name)
- boxsizer = wx.StaticBoxSizer(box_description, wx.VERTICAL)
- msg = " How to link data to the control panel: \n \n"
- msg += " First load data file from 'File' menu. \n"
- msg += " Then Highlight and right click on the data plot. \n"
- msg += " Finally, select 'Select data for fitting' in the pop-up menu. \n"
- self.hint_txt = wx.StaticText(self, wx.ID_ANY, msg, style=wx.ALIGN_LEFT)
- boxsizer.Add(self.hint_txt, wx.ALL | wx.EXPAND, 20)
- self.vbox = wx.BoxSizer(wx.VERTICAL)
- self.vbox.Add(boxsizer)
- self.vbox.Layout()
- self.vbox.Fit(self)
- self.SetSizer(self.vbox)
- self.SetScrollbars(20, 20, 25, 65)
- self.Layout()
-
- def createMemento(self):
- return
-
-
-class HelpWindow(wx.Frame):
- def __init__(self, parent, id, title):
- wx.Frame.__init__(self, parent, id, title, size=(570, 400))
-
- self.page = HintFitPage(self)
- self.Centre()
- self.Show(True)
+"""
+ This class provide general structure of fitpanel page
+"""
+import wx
+from sas.sasgui.guiframe.panel_base import PanelBase
+
+class HintFitPage(wx.ScrolledWindow, PanelBase):
+ """
+ This class provide general structure of fitpanel page
+ """
+ ## Internal name for the AUI manager
+ window_name = "Hint Page"
+ ## Title to appear on top of the window
+ window_caption = "Hint page "
+
+ def __init__(self, parent):
+ wx.ScrolledWindow.__init__(self, parent,
+ style=wx.FULL_REPAINT_ON_RESIZE)
+ PanelBase.__init__(self, parent)
+ msg = "right click on the data when it is highlighted "
+ msg += "the select option to fit for futher options"
+ self.do_layout()
+
+ def do_layout(self):
+ """
+ Draw the page
+ """
+ name = "Hint"
+ box_description = wx.StaticBox(self, wx.ID_ANY, name)
+ boxsizer = wx.StaticBoxSizer(box_description, wx.VERTICAL)
+ msg = " How to link data to the control panel: \n \n"
+ msg += " First load data file from 'File' menu. \n"
+ msg += " Then Highlight and right click on the data plot. \n"
+ msg += " Finally, select 'Select data for fitting' in the pop-up menu. \n"
+ self.hint_txt = wx.StaticText(self, wx.ID_ANY, msg, style=wx.ALIGN_LEFT)
+ boxsizer.Add(self.hint_txt, wx.ALL | wx.EXPAND, 20)
+ self.vbox = wx.BoxSizer(wx.VERTICAL)
+ self.vbox.Add(boxsizer)
+ self.vbox.Layout()
+ self.vbox.Fit(self)
+ self.SetSizer(self.vbox)
+ self.SetScrollbars(20, 20, 25, 65)
+ self.Layout()
+
+ def createMemento(self):
+ return
+
+
+class HelpWindow(wx.Frame):
+ def __init__(self, parent, id, title):
+ wx.Frame.__init__(self, parent, id, title, size=(570, 400))
+
+ self.page = HintFitPage(self)
+ self.Centre()
+ self.Show(True)
diff --git a/src/sas/sasgui/perspectives/fitting/media/M_angles_pic.bmp b/src/sas/sasgui/perspectives/fitting/media/M_angles_pic.bmp
deleted file mode 100644
index 2c85ec1..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/M_angles_pic.bmp and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/batch_button_area.bmp b/src/sas/sasgui/perspectives/fitting/media/batch_button_area.bmp
deleted file mode 100644
index a72a96f..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/batch_button_area.bmp and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/batch_button_area.png b/src/sas/sasgui/perspectives/fitting/media/batch_button_area.png
new file mode 100644
index 0000000..da343a3
Binary files /dev/null and b/src/sas/sasgui/perspectives/fitting/media/batch_button_area.png differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/cat_fig0.bmp b/src/sas/sasgui/perspectives/fitting/media/cat_fig0.bmp
deleted file mode 100644
index 3621494..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/cat_fig0.bmp and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/cat_fig0.png b/src/sas/sasgui/perspectives/fitting/media/cat_fig0.png
new file mode 100644
index 0000000..1255d58
Binary files /dev/null and b/src/sas/sasgui/perspectives/fitting/media/cat_fig0.png differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/cat_fig1.bmp b/src/sas/sasgui/perspectives/fitting/media/cat_fig1.bmp
deleted file mode 100644
index fe51aa7..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/cat_fig1.bmp and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/cat_fig1.png b/src/sas/sasgui/perspectives/fitting/media/cat_fig1.png
new file mode 100644
index 0000000..3e327df
Binary files /dev/null and b/src/sas/sasgui/perspectives/fitting/media/cat_fig1.png differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/cat_fig2.bmp b/src/sas/sasgui/perspectives/fitting/media/cat_fig2.bmp
deleted file mode 100644
index 6b4a977..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/cat_fig2.bmp and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/cat_fig2.png b/src/sas/sasgui/perspectives/fitting/media/cat_fig2.png
new file mode 100644
index 0000000..54060f2
Binary files /dev/null and b/src/sas/sasgui/perspectives/fitting/media/cat_fig2.png differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/combine_batch_grid.png b/src/sas/sasgui/perspectives/fitting/media/combine_batch_grid.png
new file mode 100644
index 0000000..49f1a5a
Binary files /dev/null and b/src/sas/sasgui/perspectives/fitting/media/combine_batch_grid.png differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/combine_batch_page.png b/src/sas/sasgui/perspectives/fitting/media/combine_batch_page.png
new file mode 100644
index 0000000..c566f70
Binary files /dev/null and b/src/sas/sasgui/perspectives/fitting/media/combine_batch_page.png differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/combine_batch_plot.png b/src/sas/sasgui/perspectives/fitting/media/combine_batch_plot.png
new file mode 100644
index 0000000..4952427
Binary files /dev/null and b/src/sas/sasgui/perspectives/fitting/media/combine_batch_plot.png differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/dm_eq.gif b/src/sas/sasgui/perspectives/fitting/media/dm_eq.gif
deleted file mode 100644
index f95b013..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/dm_eq.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/edit_menu.bmp b/src/sas/sasgui/perspectives/fitting/media/edit_menu.bmp
deleted file mode 100644
index bbd17b4..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/edit_menu.bmp and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/edit_menu.png b/src/sas/sasgui/perspectives/fitting/media/edit_menu.png
new file mode 100644
index 0000000..f4e835a
Binary files /dev/null and b/src/sas/sasgui/perspectives/fitting/media/edit_menu.png differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/file_menu.bmp b/src/sas/sasgui/perspectives/fitting/media/file_menu.bmp
deleted file mode 100644
index fd010b7..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/file_menu.bmp and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/file_menu.png b/src/sas/sasgui/perspectives/fitting/media/file_menu.png
new file mode 100644
index 0000000..898e1b3
Binary files /dev/null and b/src/sas/sasgui/perspectives/fitting/media/file_menu.png differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/fitting.rst b/src/sas/sasgui/perspectives/fitting/media/fitting.rst
index 7e8c9d7..a75b5cf 100644
--- a/src/sas/sasgui/perspectives/fitting/media/fitting.rst
+++ b/src/sas/sasgui/perspectives/fitting/media/fitting.rst
@@ -12,19 +12,22 @@ Fitting Documentation
Assessing Fit Quality <residuals_help>
- Polydispersity Distributions <pd_help>
-
- Smearing Functions <sm_help>
-
- Polarisation/Magnetic Scattering <mag_help>
-
- Information on the SasView Optimisers <optimizer.rst>
-
- Converting SANS to SESANS for Fitting <../../../sans_to_sesans>
-
- Fitting SESANS Data <../../../sesans_fitting.rst>
-
- Writing a Plugin Model <plugin.rst>
-
- Computations with a GPU <../../../gpu_computations>
-
\ No newline at end of file
+ Polydispersity Distributions <pd/polydispersity>
+
+ Smearing Functions <resolution>
+
+ Polarisation/Magnetic Scattering <magnetism/magnetism>
+
+ Information on the SasView Optimisers <optimizer>
+
+ Converting SANS to SESANS for Fitting <sesans/sans_to_sesans>
+
+ Fitting SESANS Data <sesans/sesans_fitting>
+
+ Writing a Plugin Model <plugin>
+
+ Computations with a GPU <gpu_setup>
+
+ Scripting interface to sasmodels <scripting>
+
+ References <refs>
\ No newline at end of file
diff --git a/src/sas/sasgui/perspectives/fitting/media/fitting_help.rst b/src/sas/sasgui/perspectives/fitting/media/fitting_help.rst
index 2c35c1d..0bb8aeb 100644
--- a/src/sas/sasgui/perspectives/fitting/media/fitting_help.rst
+++ b/src/sas/sasgui/perspectives/fitting/media/fitting_help.rst
@@ -3,17 +3,6 @@
.. This is a port of the original SasView html help file to ReSTructured text
.. by S King, ISIS, during SasView CodeCamp-III in Feb 2015.
-.. |inlineimage004| image:: sm_image004.gif
-.. |inlineimage005| image:: sm_image005.gif
-.. |inlineimage008| image:: sm_image008.gif
-.. |inlineimage009| image:: sm_image009.gif
-.. |inlineimage010| image:: sm_image010.gif
-.. |inlineimage011| image:: sm_image011.gif
-.. |inlineimage012| image:: sm_image012.gif
-.. |inlineimage018| image:: sm_image018.gif
-.. |inlineimage019| image:: sm_image019.gif
-
-
Fitting
=======
@@ -37,7 +26,9 @@ SasView can fit data in one of three ways:
the *same* model with/without constrained parameters (this might be useful,
for example, if you have measured the same sample at different contrasts)
-* in *Batch* fit mode - multiple data sets are fitted sequentially to the *same* model (this might be useful, for example, if you have performed a kinetic or time-resolved experiment and have *lots* of data sets!)
+* in *Batch* fit mode - multiple data sets are fitted sequentially to the
+ *same* model (this might be useful, for example, if you have performed
+ a kinetic or time-resolved experiment and have *lots* of data sets!)
.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
@@ -53,7 +44,8 @@ The models in SasView are grouped into categories. By default these consist of:
* *Sphere* - sheroidal shapes (sphere, core multishell, vesicle, etc)
* *Lamellae* - lamellar shapes (lamellar, core shell lamellar, stacked
lamellar, etc)
-* *Shape-Independent* - models describing structure in terms of density correlation functions, fractals, peaks, power laws, etc
+* *Shape-Independent* - models describing structure in terms of density
+ correlation functions, fractals, peaks, power laws, etc
* *Paracrystal* - semi ordered structures (bcc, fcc, etc)
* *Structure Factor* - S(Q) models
* *Plugin Models* - User-created (custom/non-library) Python models
@@ -89,13 +81,13 @@ Category Manager
To change the model categorizations, either choose *Category Manager* from the
*View* option on the menubar, or click on the *Modify* button on the *Fit Page*.
-.. image:: cat_fig0.bmp
+.. image:: cat_fig0.png
The categorization of all models except the user supplied Plugin Models can be
reassigned, added to, and removed using *Category Manager*. Models can also be
hidden from view in the drop-down menus.
-.. image:: cat_fig1.bmp
+.. image:: cat_fig1.png
Changing category
^^^^^^^^^^^^^^^^^
@@ -104,7 +96,7 @@ To change category, highlight a model in the list by left-clicking on its entry
and then click the *Modify* button. Use the *Change Category* panel that appears
to make the required changes.
-.. image:: cat_fig2.bmp
+.. image:: cat_fig2.png
To create a category for the selected model, click the *Add* button. In order
to delete a category, select the category name and click the *Remove Selected*
@@ -142,7 +134,7 @@ There are essentially three ways to generate new fitting models for SasView:
* Using the SasView :ref:`New_Plugin_Model` helper dialog (best for beginners
and/or relatively simple models)
* By copying/editing an existing model (this can include models generated by
- the New Plugin Model* dialog) in the :ref:`Python_shell` or
+ the New Plugin Model* dialog) in the :ref:`Python_shell` or
:ref:`Advanced_Plugin_Editor` (suitable for all use cases)
* By writing a model from scratch outside of SasView (only recommended for code
monkeys!)
@@ -178,13 +170,13 @@ New Plugin Model
Relatively straightforward models can be programmed directly from the SasView
GUI using the *New Plugin Model Function*.
-.. image:: new_model.bmp
+.. image:: new_model.png
-When using this feature, be aware that even if your code has errors, including
-syntax errors, a model file is still generated. When you then correct the errors
-and click 'Apply' again to re-compile you will get an error informing you that
-the model already exists if the 'Overwrite' box is not checked. In this case you
-will need to supply a new model function name. By default the 'Overwrite' box is
+When using this feature, be aware that even if your code has errors, including
+syntax errors, a model file is still generated. When you then correct the errors
+and click 'Apply' again to re-compile you will get an error informing you that
+the model already exists if the 'Overwrite' box is not checked. In this case you
+will need to supply a new model function name. By default the 'Overwrite' box is
*checked*\ .
Also note that the 'Fit Parameters' have been split into two sections: those
@@ -194,10 +186,40 @@ not (eg, scattering length densities).
A model file generated by this option can be viewed and further modified using
the :ref:`Advanced_Plugin_Editor` .
+**SasView version 4.2** made it possible to specify whether a plugin created with
+the *New Plugin Model* dialog is actually a form factor P(Q) or a structure factor
+S(Q). To do this, simply add one or other of the following lines under the *import*
+statements.
+
+For a form factor::
+
+ form_factor = True
+
+or for a structure factor::
+
+ structure_factor = True
+
+If the plugin is a structure factor it is *also* necessary to add two variables to
+the parameter list::
+
+ parameters = [
+ ['radius_effective', '', 1, [0.0, numpy.inf], 'volume', ''],
+ ['volfraction', '', 1, [0.0, 1.0], '', ''],
+ [...],
+
+and to the declarations of the functions Iq and Iqxy:::
+
+ def Iq(x , radius_effective, volfraction, ...):
+
+ def Iqxy(x, y, radius_effective, volfraction, ...):
+
+Such a plugin should then be available in the S(Q) drop-down box on a FitPage (once
+a P(Q) model has been selected).
+
Sum|Multi(p1,p2)
^^^^^^^^^^^^^^^^
-.. image:: sum_model.bmp
+.. image:: sum_model.png
This option creates a custom Plugin Model of the form::
@@ -205,14 +227,52 @@ This option creates a custom Plugin Model of the form::
or::
- Plugin Model = scale_factor * model_1 /* model_2 + background
+ Plugin Model = scale_factor * (model1 * model2) + background
In the *Easy Sum/Multi Editor* give the new model a function name and brief
description (to appear under the *Details* button on the *FitPage*). Then select
two existing models, as p1 and p2, and the required operator, '+' or '*' between
-them. Finally, click the *Apply* button to generate the model and then click *Close*.
+them. Finally, click the *Apply* button to generate and test the model and then click *Close*.
-Any changes to a plugin model generated in this way only become effective *after* it is re-selected from the model drop-down menu on the FitPage.
+Any changes to a plugin model generated in this way only become effective *after* it is re-selected
+from the plugin models drop-down menu on the FitPage. If the model is not listed you can force a
+recompilation of the plugins by selecting *Fitting* > *Plugin Model Operations* > *Load Plugin Models*.
+
+**SasView version 4.2** introduced a much simplified and more extensible structure for plugin models
+generated through the Easy Sum/Multi Editor. For example, the code for a combination of a sphere model
+with a power law model now looks like this::
+
+ from sasmodels.core import load_model_info
+ from sasmodels.sasview_model import make_model_from_info
+
+ model_info = load_model_info('sphere+power_law')
+ model_info.name = 'MyPluginModel'
+ model_info.description = 'sphere + power_law'
+ Model = make_model_from_info(model_info)
+
+To change the models or operators contributing to this plugin it is only necessary to edit the string
+in the brackets after *load_model_info*, though it would also be a good idea to update the model name
+and description too!!!
+
+The model specification string can handle multiple models and combinations of operators (+ or *) which
+are processed according to normal conventions. Thus 'model1+model2*model3' would be valid and would
+multiply model2 by model3 before adding model1. In this example, parameters in the *FitPage* would be
+prefixed A (for model2), B (for model3) and C (for model1). Whilst this might appear a little
+confusing, unless you were creating a plugin model from multiple instances of the same model the parameter
+assignments ought to be obvious when you load the plugin.
+
+If you need to include another plugin model in the model specification string, just prefix the name of
+that model with *custom*. For instance::
+
+ sphere+custom.MyPluginModel
+
+To create a P(Q)*\S(Q) model use the @ symbol instead of * like this::
+
+ sphere at hardsphere
+
+This streamlined approach to building complex plugin models from existing library models, or models
+available on the *Model Marketplace*, also permits the creation of P(Q)*\S(Q) plugin models, something
+that was not possible in earlier versions of SasView.
.. _Advanced_Plugin_Editor:
@@ -380,13 +440,13 @@ the corresponding uncertainties on the optimised values.
*'correlated').*
In the bottom left corner of the *Fit Page* is a box displaying the normalised value
-of the statistical |chi|\ :sup:`2` parameter returned by the optimiser.
+of the statistical $\chi^2$ parameter returned by the optimiser.
Now check the box for another model parameter and click *Fit* again. Repeat this
process until most or all parameters are checked and have been optimised. As the
fit of the theory to the experimental data improves the value of 'chi2/Npts' will
decrease. A good model fit should easily produce values of 'chi2/Npts' that are
-close to zero, and certainly <100. See :ref:`Assessing_Fit_Quality`.
+close to one, and certainly <100. See :ref:`Assessing_Fit_Quality`.
SasView has a number of different optimisers (see the section :ref:`Fitting_Options`).
The DREAM optimiser is the most sophisticated, but may not necessarily be the best
@@ -402,7 +462,7 @@ Simultaneous Fit Mode
*the Data Explorer is checked (see the section* :ref:`Loading_data` *).*
This mode is an extension of the :ref:`Single_Fit_Mode` that fits two or more data
-sets *to the same model* simultaneously. If necessary it is possible to constrain
+sets *to the same model* simultaneously. If necessary it is possible to constrain
fit parameters between data sets (eg, to fix a background level, or radius, etc).
If the data to be fit are in multiple files, load each file, then select each file
@@ -483,6 +543,8 @@ bottom of that *FitPage* to recalculate. Also see :ref:`Assessing_Fit_Quality`.
.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
+.. _Batch_Fit_Mode:
+
Batch Fit Mode
--------------
@@ -508,7 +570,7 @@ Method
Now *Select All Data* in the *Data Explorer*, check the *Batch Mode* radio button
at the bottom of that panel and *Send To Fitting*. A *BatchPage* will be created.
-.. image:: batch_button_area.bmp
+.. image:: batch_button_area.png
*NB: The Batch Page can also be created by checking the Batch Mode radio button*
*and selecting New Fit Page under Fitting in the menu bar.*
@@ -530,7 +592,7 @@ a *Data set* in the *Grid Window* and then click the *View Fits* button. The
data and the model fit will be displayed. If you select mutliple data sets they
will all appear on one graph.
-.. image:: view_button.bmp
+.. image:: view_button.png
*NB: In theory, returning to the BatchPage and changing the name of the I(Q)*
*data source should also work, but at the moment whilst this does change the*
@@ -566,7 +628,7 @@ It will be displayed automatically when a batch fit completes, but may be
opened at any time by selecting *Show Grid Window* under *View* in the menu
bar.
-.. image:: restore_batch_window.bmp
+.. image:: restore_batch_window.png
Once a batch fit is completed, all model parameters are displayed but *not*
their uncertainties. To view the uncertainties, click on a given column then
@@ -582,7 +644,7 @@ allows you to re-order columns.
All of the above functions are also available by right-clicking on a column
label.
-.. image:: edit_menu.bmp
+.. image:: edit_menu.png
*NB: If there is an existing Grid Window and another batch fit is performed,*
*an additional 'Table' tab will be added to the Grid Window.*
@@ -595,7 +657,7 @@ batch fit was performed.
Saved CSV files can be reloaded by choosing *Open* under *File* in the *Grid*
*Window* menu bar. The loaded parameters will appear in a new table tab.
-.. image:: file_menu.bmp
+.. image:: file_menu.png
*NB: Saving the Grid Window does not save any experimental data, residuals*
*or actual model fits. Consequently if you reload a saved CSV file the*
@@ -613,12 +675,12 @@ When the *Add* button is clicked, *SasView* also automatically completes the
*X/Y-axis Label* text box with the heading from Row 1 of the selected table,
but different labels and units can be entered manually.
-.. image:: plot_button.bmp
+.. image:: plot_button.png
The *X/Y-axis Selection Range* can be edited manually. The text control box
recognises the operators +, -, \*, /, or 'pow', and allows the following
types of expression :
-
+
1) if an axis label range is a function of 1 or more *columns*, write
this type of expression
@@ -638,4 +700,70 @@ types of expression :
.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
-.. note:: This help document was last changed by Steve King, 10Oct2016
+Combined Batch Fit Mode
+-----------------------
+
+The purpose of the Combined Batch Fit is to allow running two or more batch
+fits in sequence without overwriting the output table of results. This may be
+of interest for example if one is fitting a series of data sets where there is
+a shape change occurring in the series that requires changing the model part
+way through the series; for example a sphere to rod transition. Indeed the
+regular batch mode does not allow for multiple models and requires all the
+files in the series to be fit with single model and set of parameters. While
+it is of course possible to just run part of the series as a batch fit using
+model one followed by running another batch fit on the rest of the series with
+model two (and/or model three etc), doing so will overwrite the table of
+outputs from the previous batch fit(s). This may not be desirable if one is
+interested in comparing the parameters: for example the sphere radius of set
+one and the cylinder radius of set two.
+
+Method
+^^^^^^
+
+In order to use the *Combined Batch Fit*, first load all the data needed as
+described in :ref:`Loading_data`. Next start up two or more *BatchPage* fits
+following the instructions in :ref:`Batch_Fit_Mode` but **DO NOT PRESS FIT**.
+At this point the *Combine Batch Fit* menu item under the *Fitting menu* should
+be active (if there is one or no *BatchPage* the menu item will be greyed out
+and inactive). Clicking on *Combine Batch Fit* will bring up a new panel,
+similar to the *Const & Simult Fit* panel. In this case there will be a
+checkbox for each *BatchPage* instead of each *FitPage* that should be included
+in the fit. Once all are selected, click the Fit button on
+the *BatchPage* to run each batch fit in *sequence*
+
+.. image:: combine_batch_page.png
+
+The batch table will then pop up at the end as for the case of the simple Batch
+Fitting with the following caveats:
+
+.. note::
+ The order matters. The parameters in the table will be taken from the model
+ used in the first *BatchPage* of the list. Any parameters from the
+ second and later *BatchPage* s that have the same name as a parameter in the
+ first will show up allowing for plotting of that parameter across the
+ models. The other parameters will not be available in the grid.
+.. note::
+ a corralary of the above is that currently models created as a sum|multiply
+ model will not work as desired because the generated model parameters have a
+ p#_ appended to the beginning and thus radius and p1_radius will not be
+ recognized as the same parameter.
+
+.. image:: combine_batch_grid.png
+
+In the example shown above the data is a time series with a shifting peak.
+The first part of the series was fitted using the *broad_peak* model, while
+the rest of the data were fit using the *gaussian_peak* model. Unfortunately the
+time is not listed in the file but the file name contains the information. As
+described in :ref:`Grid_Window`, a column can be added manually, in this case
+called time, and the peak position plotted against time.
+
+.. image:: combine_batch_plot.png
+
+Note the discontinuity in the peak position. This reflects the fact that the
+Gaussian fit is a rather poor model for the data and is not actually
+finding the peak.
+
+.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
+
+.. note:: This help document was last changed by Paul Butler, 10 September
+ 2017
diff --git a/src/sas/sasgui/perspectives/fitting/media/m0x_eq.gif b/src/sas/sasgui/perspectives/fitting/media/m0x_eq.gif
deleted file mode 100644
index 9d64eb1..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/m0x_eq.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/m0y_eq.gif b/src/sas/sasgui/perspectives/fitting/media/m0y_eq.gif
deleted file mode 100644
index 6222758..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/m0y_eq.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/m0z_eq.gif b/src/sas/sasgui/perspectives/fitting/media/m0z_eq.gif
deleted file mode 100644
index 70f22cd..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/m0z_eq.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/mag_help.rst b/src/sas/sasgui/perspectives/fitting/media/mag_help.rst
deleted file mode 100644
index b8bbfc7..0000000
--- a/src/sas/sasgui/perspectives/fitting/media/mag_help.rst
+++ /dev/null
@@ -1,107 +0,0 @@
-.. mag_help.rst
-
-.. This is a port of text from the original SasView html help file to ReSTructured text
-.. by S King, ISIS, during SasView CodeCamp-III in Feb 2015.
-
-.. |inlineimage004| image:: sm_image004.gif
-.. |inlineimage005| image:: sm_image005.gif
-.. |inlineimage008| image:: sm_image008.gif
-.. |inlineimage009| image:: sm_image009.gif
-.. |inlineimage010| image:: sm_image010.gif
-.. |inlineimage011| image:: sm_image011.gif
-.. |inlineimage012| image:: sm_image012.gif
-.. |inlineimage018| image:: sm_image018.gif
-.. |inlineimage019| image:: sm_image019.gif
-
-
-.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
-
-Polarisation/Magnetic Scattering
---------------------------------
-
-Magnetic scattering is implemented in five (2D) models
-
-* *sphere*
-* *core_shell_sphere*
-* *core_multi_shell*
-* *cylinder*
-* *parallelepiped*
-
-In general, the scattering length density (SLD, = |beta|) in each region where the
-SLD is uniform, is a combination of the nuclear and magnetic SLDs and, for polarised
-neutrons, also depends on the spin states of the neutrons.
-
-For magnetic scattering, only the magnetization component, *M*\ :sub:`perp`,
-perpendicular to the scattering vector *Q* contributes to the the magnetic
-scattering length.
-
-.. image:: mag_vector.bmp
-
-The magnetic scattering length density is then
-
-.. image:: dm_eq.gif
-
-where |gamma| = -1.913 is the gyromagnetic ratio, |mu|\ :sub:`B` is the
-Bohr magneton, *r*\ :sub:`0` is the classical radius of electron, and |sigma|
-is the Pauli spin.
-
-Assuming that incident neutrons are polarized parallel (+) and anti-parallel (-)
-to the *x'* axis, the possible spin states after the sample are then
-
-No spin-flips (+ +) and (- -)
-
-Spin-flips (+ -) and (- +)
-
-.. image:: M_angles_pic.bmp
-
-If the angles of the *Q* vector and the spin-axis (*x'*) to the *x*-axis are |phi|
-and |theta|\ :sub:`up`, respectively, then, depending on the spin state of the
-neutrons, the scattering length densities, including the nuclear scattering
-length density (|beta|\ :sub:`N`) are
-
-.. image:: sld1.gif
-
-when there are no spin-flips, and
-
-.. image:: sld2.gif
-
-when there are, and
-
-.. image:: mxp.gif
-
-.. image:: myp.gif
-
-.. image:: mzp.gif
-
-.. image:: mqx.gif
-
-.. image:: mqy.gif
-
-Here, *M*\ :sub:`0x`, *M*\ :sub:`0y` and *M*\ :sub:`0z` are the x, y and z components
-of the magnetization vector given in the laboratory xyz frame given by
-
-.. image:: m0x_eq.gif
-
-.. image:: m0y_eq.gif
-
-.. image:: m0z_eq.gif
-
-and the magnetization angles |theta|\ :sub:`M` and |phi|\ :sub:`M` are defined in
-the figure above.
-
-The user input parameters are:
-
-=========== ================================================================
- M0_sld = *D*\ :sub:`M` *M*\ :sub:`0`
- Up_theta = |theta|\ :sub:`up`
- M_theta = |theta|\ :sub:`M`
- M_phi = |phi|\ :sub:`M`
- Up_frac_i = (spin up)/(spin up + spin down) neutrons *before* the sample
- Up_frac_f = (spin up)/(spin up + spin down) neutrons *after* the sample
-=========== ================================================================
-
-*Note:* The values of the 'Up_frac_i' and 'Up_frac_f' must be in the range 0 to 1.
-
-.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
-
-.. note:: This help document was last changed by Steve King, 02May2015
diff --git a/src/sas/sasgui/perspectives/fitting/media/mag_vector.bmp b/src/sas/sasgui/perspectives/fitting/media/mag_vector.bmp
deleted file mode 100644
index 869a144..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/mag_vector.bmp and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/mqx.gif b/src/sas/sasgui/perspectives/fitting/media/mqx.gif
deleted file mode 100644
index a2f60a0..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/mqx.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/mqy.gif b/src/sas/sasgui/perspectives/fitting/media/mqy.gif
deleted file mode 100644
index db1fef2..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/mqy.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/mxp.gif b/src/sas/sasgui/perspectives/fitting/media/mxp.gif
deleted file mode 100644
index d1d42ca..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/mxp.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/myp.gif b/src/sas/sasgui/perspectives/fitting/media/myp.gif
deleted file mode 100644
index 87dc8ae..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/myp.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/mzp.gif b/src/sas/sasgui/perspectives/fitting/media/mzp.gif
deleted file mode 100644
index 3699f89..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/mzp.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/new_model.bmp b/src/sas/sasgui/perspectives/fitting/media/new_model.bmp
deleted file mode 100644
index 4d69253..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/new_model.bmp and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/new_model.png b/src/sas/sasgui/perspectives/fitting/media/new_model.png
new file mode 100644
index 0000000..76cab33
Binary files /dev/null and b/src/sas/sasgui/perspectives/fitting/media/new_model.png differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/pd_help.rst b/src/sas/sasgui/perspectives/fitting/media/pd_help.rst
deleted file mode 100644
index 8b98bfc..0000000
--- a/src/sas/sasgui/perspectives/fitting/media/pd_help.rst
+++ /dev/null
@@ -1,194 +0,0 @@
-.. pd_help.rst
-
-.. This is a port of the original SasView html help file to ReSTructured text
-.. by S King, ISIS, during SasView CodeCamp-III in Feb 2015.
-
-.. |inlineimage004| image:: sm_image004.gif
-.. |inlineimage005| image:: sm_image005.gif
-.. |inlineimage008| image:: sm_image008.gif
-.. |inlineimage009| image:: sm_image009.gif
-.. |inlineimage010| image:: sm_image010.gif
-.. |inlineimage011| image:: sm_image011.gif
-.. |inlineimage012| image:: sm_image012.gif
-.. |inlineimage018| image:: sm_image018.gif
-.. |inlineimage019| image:: sm_image019.gif
-
-
-.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
-
-Polydispersity Distributions
-----------------------------
-
-With some models SasView can calculate the average form factor for a population
-of particles that exhibit size and/or orientational polydispersity. The resultant
-form factor is normalized by the average particle volume such that
-
-*P(q) = scale* * \ <F*\F> / *V + bkg*
-
-where F is the scattering amplitude and the \<\> denote an average over the size
-distribution.
-
-Users should note that this computation is very intensive. Applying polydispersion
-to multiple parameters at the same time, or increasing the number of *Npts* values
-in the fit, will require patience! However, the calculations are generally more
-robust with more data points or more angles.
-
-SasView uses the term *PD* for a size distribution (and not to be confused with a
-molecular weight distributions in polymer science) and the term *Sigma* for an
-angular distribution.
-
-The following five distribution functions are provided:
-
-* *Rectangular Distribution*
-* *Gaussian Distribution*
-* *Lognormal Distribution*
-* *Schulz Distribution*
-* *Array Distribution*
-
-These are all implemented in SasView as *number-average* distributions.
-
-.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
-
-Rectangular Distribution
-^^^^^^^^^^^^^^^^^^^^^^^^
-
-The Rectangular Distribution is defined as
-
-.. image:: pd_image001.png
-
-where *xmean* is the mean of the distribution, *w* is the half-width, and *Norm* is a
-normalization factor which is determined during the numerical calculation.
-
-Note that the standard deviation and the half width *w* are different!
-
-The standard deviation is
-
-.. image:: pd_image002.png
-
-whilst the polydispersity is
-
-.. image:: pd_image003.png
-
-.. image:: pd_image004.jpg
-
-.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
-
-Gaussian Distribution
-^^^^^^^^^^^^^^^^^^^^^
-
-The Gaussian Distribution is defined as
-
-.. image:: pd_image005.png
-
-where *xmean* is the mean of the distribution and *Norm* is a normalization factor
-which is determined during the numerical calculation.
-
-The polydispersity is
-
-.. image:: pd_image003.png
-
-
-.. image:: pd_image006.jpg
-
-.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
-
-Lognormal Distribution
-^^^^^^^^^^^^^^^^^^^^^^
-
-The Lognormal Distribution is defined as
-
-.. image:: pd_image007.png
-
-where |mu|\ =ln(*xmed*), *xmed* is the median value of the distribution, and
-*Norm* is a normalization factor which will be determined during the numerical
-calculation.
-
-The median value for the distribution will be the value given for the respective
-size parameter in the *FitPage*, for example, radius = 60.
-
-The polydispersity is given by |sigma|
-
-.. image:: pd_image008.png
-
-For the angular distribution
-
-.. image:: pd_image009.png
-
-The mean value is given by *xmean*\ =exp(|mu|\ +p\ :sup:`2`\ /2). The peak value
-is given by *xpeak*\ =exp(|mu|-p\ :sup:`2`\ ).
-
-.. image:: pd_image010.jpg
-
-This distribution function spreads more, and the peak shifts to the left, as *p*
-increases, requiring higher values of Nsigmas and Npts.
-
-.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
-
-Schulz Distribution
-^^^^^^^^^^^^^^^^^^^
-
-The Schulz distribution is defined as
-
-.. image:: pd_image011.png
-
-where *xmean* is the mean of the distribution and *Norm* is a normalization factor
-which is determined during the numerical calculation, and *z* is a measure of the
-width of the distribution such that
-
-z = (1-p\ :sup:`2`\ ) / p\ :sup:`2`
-
-The polydispersity is
-
-.. image:: pd_image012.png
-
-Note that larger values of PD might need larger values of Npts and Nsigmas.
-For example, at PD=0.7 and radius=60 |Ang|, Npts>=160 and Nsigmas>=15 at least.
-
-.. image:: pd_image013.jpg
-
-For further information on the Schulz distribution see:
-M Kotlarchyk & S-H Chen, *J Chem Phys*, (1983), 79, 2461.
-
-.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
-
-Array Distribution
-^^^^^^^^^^^^^^^^^^
-
-This user-definable distribution should be given as as a simple ASCII text file
-where the array is defined by two columns of numbers: *x* and *f(x)*. The *f(x)*
-will be normalized by SasView during the computation.
-
-Example of what an array distribution file should look like:
-
-==== =====
- 30 0.1
- 32 0.3
- 35 0.4
- 36 0.5
- 37 0.6
- 39 0.7
- 41 0.9
-==== =====
-
-SasView only uses these array values during the computation, therefore any mean
-value of the parameter represented by *x* present in the *FitPage*
-will be ignored.
-
-.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
-
-Note about DLS polydispersity
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Many commercial Dynamic Light Scattering (DLS) instruments produce a size
-polydispersity parameter, sometimes even given the symbol *p*! This parameter is
-defined as the relative standard deviation coefficient of variation of the size
-distribution and is NOT the same as the polydispersity parameters in the Lognormal
-and Schulz distributions above (though they all related) except when the DLS
-polydispersity parameter is <0.13.
-
-For more information see:
-S King, C Washington & R Heenan, *Phys Chem Chem Phys*, (2005), 7, 143
-
-.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
-
-.. note:: This help document was last changed by Steve King, 01May2015
diff --git a/src/sas/sasgui/perspectives/fitting/media/pd_image001.png b/src/sas/sasgui/perspectives/fitting/media/pd_image001.png
deleted file mode 100644
index 19b9c16..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/pd_image001.png and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/pd_image002.png b/src/sas/sasgui/perspectives/fitting/media/pd_image002.png
deleted file mode 100644
index aba6e91..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/pd_image002.png and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/pd_image003.png b/src/sas/sasgui/perspectives/fitting/media/pd_image003.png
deleted file mode 100644
index 1a2c0c9..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/pd_image003.png and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/pd_image004.jpg b/src/sas/sasgui/perspectives/fitting/media/pd_image004.jpg
deleted file mode 100644
index 4a4ad6d..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/pd_image004.jpg and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/pd_image005.png b/src/sas/sasgui/perspectives/fitting/media/pd_image005.png
deleted file mode 100644
index e2633ae..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/pd_image005.png and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/pd_image006.jpg b/src/sas/sasgui/perspectives/fitting/media/pd_image006.jpg
deleted file mode 100644
index e255e3b..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/pd_image006.jpg and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/pd_image007.png b/src/sas/sasgui/perspectives/fitting/media/pd_image007.png
deleted file mode 100644
index 939cbfa..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/pd_image007.png and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/pd_image008.png b/src/sas/sasgui/perspectives/fitting/media/pd_image008.png
deleted file mode 100644
index 4deefac..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/pd_image008.png and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/pd_image009.png b/src/sas/sasgui/perspectives/fitting/media/pd_image009.png
deleted file mode 100644
index d257354..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/pd_image009.png and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/pd_image010.jpg b/src/sas/sasgui/perspectives/fitting/media/pd_image010.jpg
deleted file mode 100644
index 537537a..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/pd_image010.jpg and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/pd_image011.png b/src/sas/sasgui/perspectives/fitting/media/pd_image011.png
deleted file mode 100644
index e0a04e0..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/pd_image011.png and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/pd_image012.png b/src/sas/sasgui/perspectives/fitting/media/pd_image012.png
deleted file mode 100644
index 6697445..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/pd_image012.png and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/pd_image013.jpg b/src/sas/sasgui/perspectives/fitting/media/pd_image013.jpg
deleted file mode 100644
index 9ce7a9f..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/pd_image013.jpg and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/plot_button.bmp b/src/sas/sasgui/perspectives/fitting/media/plot_button.bmp
deleted file mode 100644
index 7768c28..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/plot_button.bmp and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/plot_button.png b/src/sas/sasgui/perspectives/fitting/media/plot_button.png
new file mode 100644
index 0000000..eb61d2c
Binary files /dev/null and b/src/sas/sasgui/perspectives/fitting/media/plot_button.png differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/plugin.rst b/src/sas/sasgui/perspectives/fitting/media/plugin.rst
deleted file mode 100644
index 991b4db..0000000
--- a/src/sas/sasgui/perspectives/fitting/media/plugin.rst
+++ /dev/null
@@ -1,1012 +0,0 @@
-.. _Writing_a_Plugin:
-
-Writing a Plugin Model
-======================
-
-.. note:: If some code blocks are not readable, expand the documentation window
-
-Introduction
-^^^^^^^^^^^^
-
-There are essentially three ways to generate new fitting models for SasView:
-
-* Using the SasView :ref:`New_Plugin_Model` helper dialog (best for beginners
- and/or relatively simple models)
-* By copying/editing an existing model (this can include models generated by
- the *New Plugin Model* dialog) in the :ref:`Python_shell` or
- :ref:`Advanced_Plugin_Editor` as described below (suitable for all use cases)
-* By writing a model from scratch outside of SasView (only recommended for
- code monkeys!)
-
-Overview
-^^^^^^^^
-
-If you write your own model and save it to the the SasView *plugin_models* folder
-
- *C:\\Users\\{username}\\.sasview\\plugin_models* (on Windows)
-
-the next time SasView is started it will compile the plugin and add
-it to the list of *Plugin Models* in a FitPage.
-
-SasView models can be of three types:
-
-- A pure python model : Example -
- `broadpeak.py <https://github.com/SasView/sasmodels/blob/master/sasmodels/models/broad_peak.py>`_
-- A python model with embedded C : Example -
- `sphere.py <https://github.com/SasView/sasmodels/blob/master/sasmodels/models/sphere.py>`_
-- A python wrapper with separate C code : Example -
- `cylinder.py <https://github.com/SasView/sasmodels/blob/master/sasmodels/models/cylinder.py>`_,
- `cylinder.c <https://github.com/SasView/sasmodels/blob/master/sasmodels/models/cylinder.c>`_
-
-The built-in modules are available in the *sasmodels-data\\models* subdirectory
-of your SasView installation folder. On Windows, this will be something like
-*C:\\Program Files (x86)\\SasView\\sasmodels-data\\models*. On Mac OSX, these will be within
-the application bundle as
-*/Applications/SasView 4.0.app/Contents/Resources/sasmodels-data/models*.
-
-Other models are available for download from our
-`Model Marketplace <http://marketplace.sasview.org/>`_. You can contribute your own models to the
-Marketplace aswell.
-
-Create New Model Files
-^^^^^^^^^^^^^^^^^^^^^^
-
-In the *~\\.sasview\\plugin_models* directory, copy the appropriate files
-(we recommend using the examples above as templates) to mymodel.py (and mymodel.c, etc)
-as required, where "mymodel" is the name for the model you are creating.
-
-*Please follow these naming rules:*
-
-- No capitalization and thus no CamelCase
-- If necessary use underscore to separate words (i.e. barbell not BarBell or
- broad_peak not BroadPeak)
-- Do not include "model" in the name (i.e. barbell not BarBellModel)
-
-
-Edit New Model Files
-^^^^^^^^^^^^^^^^^^^^
-
-Model Contents
-..............
-
-The model interface definition is in the .py file. This file contains:
-
-- a **model name**:
- - this is the **name** string in the *.py* file
- - titles should be:
-
- - all in *lower* case
- - without spaces (use underscores to separate words instead)
- - without any capitalization or CamelCase
- - without incorporating the word "model"
- - examples: *barbell* **not** *BarBell*; *broad_peak* **not** *BroadPeak*;
- *barbell* **not** *BarBellModel*
-
-- a **model title**:
- - this is the **title** string in the *.py* file
- - this is a one or two line description of the model, which will appear
- at the start of the model documentation and as a tooltip in the SasView GUI
-
-- a **short discription**:
- - this is the **description** string in the *.py* file
- - this is a medium length description which appears when you click
- *Description* on the model FitPage
-
-- a **parameter table**:
- - this will be auto-generated from the *parameters* in the *.py* file
-
-- a **long description**:
- - this is ReStructuredText enclosed between the r""" and """ delimiters
- at the top of the *.py* file
- - what you write here is abstracted into the SasView help documentation
- - this is what other users will refer to when they want to know what your model does;
- so please be helpful!
-
-- a **definition** of the model:
- - as part of the **long description**
-
-- a **formula** defining the function the model calculates:
- - as part of the **long description**
-
-- an **explanation of the parameters**:
- - as part of the **long description**
- - explaining how the symbols in the formula map to the model parameters
-
-- a **plot** of the function, with a **figure caption**:
- - this is automatically generated from your default parameters
-
-- at least one **reference**:
- - as part of the **long description**
- - specifying where the reader can obtain more information about the model
-
-- the **name of the author**
- - as part of the **long description**
- - the *.py* file should also contain a comment identifying *who*
- converted/created the model file
-
-Models that do not conform to these requirements will *never* be incorporated
-into the built-in library.
-
-More complete documentation for the sasmodels package can be found at
-`<http://www.sasview.org/sasmodels>`_. In particular,
-`<http://www.sasview.org/sasmodels/api/generate.html#module-sasmodels.generate>`_
-describes the structure of a model.
-
-
-Model Documentation
-...................
-
-The *.py* file starts with an r (for raw) and three sets of quotes
-to start the doc string and ends with a second set of three quotes.
-For example::
-
- r"""
- Definition
- ----------
-
- The 1D scattering intensity of the sphere is calculated in the following
- way (Guinier, 1955)
-
- .. math::
-
- I(q) = \frac{\text{scale}}{V} \cdot \left[
- 3V(\Delta\rho) \cdot \frac{\sin(qr) - qr\cos(qr))}{(qr)^3}
- \right]^2 + \text{background}
-
- where *scale* is a volume fraction, $V$ is the volume of the scatterer,
- $r$ is the radius of the sphere and *background* is the background level.
- *sld* and *sld_solvent* are the scattering length densities (SLDs) of the
- scatterer and the solvent respectively, whose difference is $\Delta\rho$.
-
- You can included figures in your documentation, as in the following
- figure for the cylinder model.
-
- .. figure:: img/cylinder_angle_definition.jpg
-
- Definition of the angles for oriented cylinders.
-
- References
- ----------
-
- A Guinier, G Fournet, *Small-Angle Scattering of X-Rays*,
- John Wiley and Sons, New York, (1955)
- """
-
-This is where the FULL documentation for the model goes (to be picked up by
-the automatic documentation system). Although it feels odd, you
-should start the documentation immediately with the **definition**---the model
-name, a brief description and the parameter table are automatically inserted
-above the definition, and the a plot of the model is automatically inserted
-before the **reference**.
-
-Figures can be included using the *figure* command, with the name
-of the *.png* file containing the figure and a caption to appear below the
-figure. Figure numbers will be added automatically.
-
-See this `Sphinx cheat sheet <http://matplotlib.org/sampledoc/cheatsheet.html>`_
-for a quick guide to the documentation layout commands, or the
-`Sphinx Documentation <http://www.sphinx-doc.org/en/stable/>`_ for
-complete details.
-
-The model should include a **formula** written using LaTeX markup.
-The example above uses the *math* command to make a displayed equation. You
-can also use *\$formula\$* for an inline formula. This is handy for defining
-the relationship between the model parameters and formula variables, such
-as the phrase "\$r\$ is the radius" used above. The live demo MathJax
-page `<http://www.mathjax.org/>`_ is handy for checking that the equations
-will look like you intend.
-
-Math layout uses the `amsmath <http://www.ams.org/publications/authors/tex/amslatex>`_
-package for aligning equations (see amsldoc.pdf on that page for complete documentation).
-You will automatically be in an aligned environment, with blank lines separating
-the lines of the equation. Place an ampersand before the operator on which to
-align. For example::
-
- .. math::
-
- x + y &= 1 \\
- y &= x - 1
-
-produces
-
-.. math::
-
- x + y &= 1 \\
- y &= x - 1
-
-If you need more control, use::
-
- .. math::
- :nowrap:
-
-
-Model Definition
-................
-
-Following the documentation string, there are a series of definitions::
-
- name = "sphere" # optional: defaults to the filename without .py
-
- title = "Spheres with uniform scattering length density"
-
- description = """\
- P(q)=(scale/V)*[3V(sld-sld_solvent)*(sin(qr)-qr cos(qr))
- /(qr)^3]^2 + background
- r: radius of sphere
- V: The volume of the scatter
- sld: the SLD of the sphere
- sld_solvent: the SLD of the solvent
- """
-
- category = "shape:sphere"
-
- single = True # optional: defaults to True
-
- opencl = False # optional: defaults to False
-
- structure_factor = False # optional: defaults to False
-
-**name = "mymodel"** defines the name of the model that is shown to the user.
-If it is not provided, it will use the name of the model file, with '_'
-replaced by spaces and the parts capitalized. So *adsorbed_layer.py* will
-become *Adsorbed Layer*. The predefined models all use the name of the
-model file as the name of the model, so the default may be changed.
-
-**title = "short description"** is short description of the model which
-is included after the model name in the automatically generated documentation.
-The title can also be used for a tooltip.
-
-**description = """doc string"""** is a longer description of the model. It
-shows up when you press the "Description" button of the SasView FitPage.
-It should give a brief description of the equation and the parameters
-without the need to read the entire model documentation. The triple quotes
-allow you to write the description over multiple lines. Keep the lines
-short since the GUI will wrap each one separately if they are too long.
-**Make sure the parameter names in the description match the model definition!**
-
-**category = "shape:sphere"** defines where the model will appear in the
-model documentation. In this example, the model will appear alphabetically
-in the list of spheroid models in the *Shape* category.
-
-**single = True** indicates that the model can be run using single
-precision floating point values. Set it to False if the numerical
-calculation for the model is unstable, which is the case for about 20 of
-the built in models. It is worthwhile modifying the calculation to support
-single precision, allowing models to run up to 10 times faster. The
-section `Test_Your_New_Model`_ describes how to compare model values for
-single vs. double precision so you can decide if you need to set
-single to False.
-
-**opencl = False** indicates that the model should not be run using OpenCL.
-This may be because the model definition includes code that cannot be
-compiled for the GPU (for example, goto statements). It can also be used
-for large models which can't run on most GPUs. This flag has not been
-used on any of the built in models; models which were failing were
-streamlined so this flag was not necessary.
-
-**structure_factor = True** indicates that the model can be used as a
-structure factor to account for interactions between particles. See
-`Form_Factors`_ for more details.
-
-Model Parameters
-................
-
-Next comes the parameter table. For example::
-
- # pylint: disable=bad-whitespace, line-too-long
- # ["name", "units", default, [min, max], "type", "description"],
- parameters = [
- ["sld", "1e-6/Ang^2", 1, [-inf, inf], "sld", "Layer scattering length density"],
- ["sld_solvent", "1e-6/Ang^2", 6, [-inf, inf], "sld", "Solvent scattering length density"],
- ["radius", "Ang", 50, [0, inf], "volume", "Sphere radius"],
- ]
- # pylint: enable=bad-whitespace, line-too-long
-
-**parameters = [["name", "units", default, [min,max], "type", "tooltip"],...]**
-defines the parameters that form the model.
-
-**Note: The order of the parameters in the definition will be the order of the
-parameters in the user interface and the order of the parameters in Iq(),
-Iqxy() and form_volume(). And** *scale* **and** *background* **parameters are
-implicit to all models, so they do not need to be included in the parameter table.**
-
-- **"name"** is the name of the parameter shown on the FitPage.
-
- - parameter names should follow the mathematical convention; e.g.,
- *radius_core* not *core_radius*, or *sld_solvent* not *solvent_sld*.
-
- - model parameter names should be consistent between different models,
- so *sld_solvent*, for example, should have exactly the same name
- in every model.
-
- - to see all the parameter names currently in use, type the following in the
- python shell/editor under the Tools menu::
-
- import sasmodels.list_pars
- sasmodels.list_pars.list_pars()
-
- *re-use* as many as possible!!!
-
- - use "name[n]" for multiplicity parameters, where *n* is the name of
- the parameter defining the number of shells/layers/segments, etc.
-
-- **"units"** are displayed along with the parameter name
-
- - every parameter should have units; use "None" if there are no units.
-
- - **sld's should be given in units of 1e-6/Ang^2, and not simply
- 1/Ang^2 to be consistent with the builtin models. Adjust your formulas
- appropriately.**
-
- - fancy units markup is available for some units, including::
-
- Ang, 1/Ang, 1/Ang^2, 1e-6/Ang^2, degrees, 1/cm, Ang/cm, g/cm^3, mg/m^2
-
- - the list of units is defined in the variable *RST_UNITS* within
- `sasmodels/generate.py <https://github.com/SasView/sasmodels/tree/master/sasmodels/generate.py>`_
-
- - new units can be added using the macros defined in *doc/rst_prolog*
- in the sasmodels source.
- - units should be properly formatted using sub-/super-scripts
- and using negative exponents instead of the / operator, though
- the unit name should use the / operator for consistency.
- - please post a message to the SasView developers mailing list with your changes.
-
-- **default** is the initial value for the parameter.
-
- - **the parameter default values are used to auto-generate a plot of
- the model function in the documentation.**
-
-- **[min, max]** are the lower and upper limits on the parameter.
-
- - lower and upper limits can be any number, or *-inf* or *inf*.
-
- - the limits will show up as the default limits for the fit making it easy,
- for example, to force the radius to always be greater than zero.
-
- - these are hard limits defining the valid range of parameter values;
- polydisperity distributions will be truncated at the limits.
-
-- **"type"** can be one of: "", "sld", "volume", or "orientation".
-
- - "sld" parameters can have magnetic moments when fitting magnetic models;
- depending on the spin polarization of the beam and the $q$ value being
- examined, the effective sld for that material will be used to compute the
- scattered intensity.
-
- - "volume" parameters are passed to Iq(), Iqxy(), and form_volume(), and
- have polydispersity loops generated automatically.
-
- - "orientation" parameters are only passed to Iqxy(), and have angular
- dispersion.
-
-
-Model Computation
-.................
-
-Models can be defined as pure python models, or they can be a mixture of
-python and C models. C models are run on the GPU if it is available,
-otherwise they are compiled and run on the CPU.
-
-Models are defined by the scattering kernel, which takes a set of parameter
-values defining the shape, orientation and material, and returns the
-expected scattering. Polydispersity and angular dispersion are defined
-by the computational infrastructure. Any parameters defined as "volume"
-parameters are polydisperse, with polydispersity defined in proportion
-to their value. "orientation" parameters use angular dispersion defined
-in degrees, and are not relative to the current angle.
-
-Based on a weighting function $G(x)$ and a number of points $n$, the
-computed value is
-
-.. math::
-
- \hat I(q)
- = \frac{\int G(x) I(q, x)\,dx}{\int G(x) V(x)\,dx}
- \approx \frac{\sum_{i=1}^n G(x_i) I(q,x_i)}{\sum_{i=1}^n G(x_i) V(x_i)}
-
-That is, the indivdual models do not need to include polydispersity
-calculations, but instead rely on numerical integration to compute the
-appropriately smeared pattern. Angular dispersion values over polar angle
-$\theta$ requires an additional $\cos \theta$ weighting due to decreased
-arc length for the equatorial angle $\phi$ with increasing latitude.
-
-Python Models
-.............
-
-For pure python models, define the *Iq* function::
-
- import numpy as np
- from numpy import cos, sin, ...
-
- def Iq(q, par1, par2, ...):
- return I(q, par1, par2, ...)
- Iq.vectorized = True
-
-The parameters *par1, par2, ...* are the list of non-orientation parameters
-to the model in the order that they appear in the parameter table.
-**Note that the autogenerated model file uses** *x* **rather than** *q*.
-
-The *.py* file should import trigonometric and exponential functions from
-numpy rather than from math. This lets us evaluate the model for the whole
-range of $q$ values at once rather than looping over each $q$ separately in
-python. With $q$ as a vector, you cannot use if statements, but must instead
-do tricks like
-
-::
-
- a = x*q*(q>0) + y*q*(q<=0)
-
-or
-
-::
-
- a = np.empty_like(q)
- index = q>0
- a[index] = x*q[index]
- a[~index] = y*q[~index]
-
-which sets $a$ to $q \cdot x$ if $q$ is positive or $q \cdot y$ if $q$
-is zero or negative. If you have not converted your function to use $q$
-vectors, you can set the following and it will only receive one $q$
-value at a time::
-
- Iq.vectorized = False
-
-Return np.NaN if the parameters are not valid (e.g., cap_radius < radius in
-barbell). If I(q; pars) is NaN for any $q$, then those parameters will be
-ignored, and not included in the calculation of the weighted polydispersity.
-
-Similar to *Iq*, you can define *Iqxy(qx, qy, par1, par2, ...)* where the
-parameter list includes any orientation parameters. If *Iqxy* is not defined,
-then it will default to *Iqxy = Iq(sqrt(qx**2+qy**2), par1, par2, ...)*.
-
-Models should define *form_volume(par1, par2, ...)* where the parameter
-list includes the *volume* parameters in order. This is used for a weighted
-volume normalization so that scattering is on an absolute scale. If
-*form_volume* is not defined, then the default *form_volume = 1.0* will be
-used.
-
-Embedded C Models
-.................
-
-Like pure python models, inline C models need to define an *Iq* function::
-
- Iq = """
- return I(q, par1, par2, ...);
- """
-
-This expands into the equivalent C code::
-
- #include <math.h>
- double Iq(double q, double par1, double par2, ...);
- double Iq(double q, double par1, double par2, ...)
- {
- return I(q, par1, par2, ...);
- }
-
-*Iqxy* is similar to *Iq*, except it uses parameters *qx, qy* instead of *q*,
-and it includes orientation parameters.
-
-*form_volume* defines the volume of the shape. As in python models, it
-includes only the volume parameters.
-
-*Iqxy* will default to *Iq(sqrt(qx**2 + qy**2), par1, ...)* and
-*form_volume* will default to 1.0.
-
-**source=['fn.c', ...]** includes the listed C source files in the
-program before *Iq* and *Iqxy* are defined. This allows you to extend the
-library of C functions available to your model.
-
-Models are defined using double precision declarations for the
-parameters and return values. When a model is run using single
-precision or long double precision, each variable is converted
-to the target type, depending on the precision requested.
-
-**Floating point constants must include the decimal point.** This allows us
-to convert values such as 1.0 (double precision) to 1.0f (single precision)
-so that expressions that use these values are not promoted to double precision
-expressions. Some graphics card drivers are confused when functions
-that expect floating point values are passed integers, such as 4*atan(1); it
-is safest to not use integers in floating point expressions. Even better,
-use the builtin constant M_PI rather than 4*atan(1); it is faster and smaller!
-
-The C model operates on a single $q$ value at a time. The code will be
-run in parallel across different $q$ values, either on the graphics card
-or the processor.
-
-Rather than returning NAN from Iq, you must define the *INVALID(v)*. The
-*v* parameter lets you access all the parameters in the model using
-*v.par1*, *v.par2*, etc. For example::
-
- #define INVALID(v) (v.bell_radius < v.radius)
-
-Special Functions
-.................
-
-The C code follows the C99 standard, with the usual math functions,
-as defined in
-`OpenCL <https://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/mathFunctions.html>`_.
-This includes the following:
-
- M_PI, M_PI_2, M_PI_4, M_SQRT1_2, M_E:
- $\pi$, $\pi/2$, $\pi/4$, $1/\sqrt{2}$ and Euler's constant $e$
- exp, log, pow(x,y), expm1, sqrt:
- Power functions $e^x$, $\ln x$, $x^y$, $e^x - 1$, $\sqrt{x}$.
- The function expm1(x) is accurate across all $x$, including $x$
- very close to zero.
- sin, cos, tan, asin, acos, atan:
- Trigonometry functions and inverses, operating on radians.
- sinh, cos, tanh, asinh, acosh, atanh:
- Hyperbolic trigonometry functions.
- atan2(y,x):
- Angle from the $x$\ -axis to the point $(x,y)$, which is equal to
- $\tan^{-1}(y/x)$ corrected for quadrant. That is, if $x$ and $y$ are
- both negative, then atan2(y,x) returns a value in quadrant III where
- atan(y/x) would return a value in quadrant I. Similarly for
- quadrants II and IV when $x$ and $y$ have opposite sign.
- fmin(x,y), fmax(x,y), trunc, rint:
- Floating point functions. rint(x) returns the nearest integer.
- NAN:
- NaN, Not a Number, $0/0$. Use isnan(x) to test for NaN. Note that
- you cannot use :code:`x == NAN` to test for NaN values since that
- will always return false. NAN does not equal NAN!
- INFINITY:
- $\infty, 1/0$. Use isinf(x) to test for infinity, or isfinite(x)
- to test for finite and not NaN.
- erf, erfc, tgamma, lgamma: **do not use**
- Special functions that should be part of the standard, but are missing
- or inaccurate on some platforms. Use sas_erf, sas_erfc and sas_gamma
- instead (see below). Note: lgamma(x) has not yet been tested.
-
-Some non-standard constants and functions are also provided:
-
- M_PI_180, M_4PI_3:
- $\frac{\pi}{180}$, $\frac{4\pi}{3}$
- SINCOS(x, s, c):
- Macro which sets s=sin(x) and c=cos(x). The variables *c* and *s*
- must be declared first.
- square(x):
- $x^2$
- cube(x):
- $x^3$
- sas_sinx_x(x):
- $\sin(x)/x$, with limit $\sin(0)/0 = 1$.
- powr(x, y):
- $x^y$ for $x \ge 0$; this is faster than general $x^y$ on some GPUs.
- pown(x, n):
- $x^n$ for $n$ integer; this is faster than general $x^n$ on some GPUs.
- FLOAT_SIZE:
- The number of bytes in a floating point value. Even though all
- variables are declared double, they may be converted to single
- precision float before running. If your algorithm depends on
- precision (which is not uncommon for numerical algorithms), use
- the following::
-
- #if FLOAT_SIZE>4
- ... code for double precision ...
- #else
- ... code for single precision ...
- #endif
- SAS_DOUBLE:
- A replacement for :code:`double` so that the declared variable will
- stay double precision; this should generally not be used since some
- graphics cards do not support double precision. There is no provision
- for forcing a constant to stay double precision.
-
-The following special functions and scattering calculations are defined in
-`sasmodels/models/lib <https://github.com/SasView/sasmodels/tree/master/sasmodels/models/lib>`_.
-These functions have been tuned to be fast and numerically stable down
-to $q=0$ even in single precision. In some cases they work around bugs
-which appear on some platforms but not others, so use them where needed.
-Add the files listed in :code:`source = ["lib/file.c", ...]` to your *model.py*
-file in the order given, otherwise these functions will not be available.
-
- polevl(x, c, n):
- Polynomial evaluation $p(x) = \sum_{i=0}^n c_i x^i$ using Horner's
- method so it is faster and more accurate.
-
- $c = \{c_n, c_{n-1}, \ldots, c_0 \}$ is the table of coefficients,
- sorted from highest to lowest.
-
- :code:`source = ["lib/polevl.c", ...]` (`link to code <https://github.com/SasView/sasmodels/tree/master/sasmodels/models/lib/polevl.c>`_)
-
- p1evl(x, c, n):
- Evaluation of normalized polynomial $p(x) = x^n + \sum_{i=0}^{n-1} c_i x^i$
- using Horner's method so it is faster and more accurate.
-
- $c = \{c_{n-1}, c_{n-2} \ldots, c_0 \}$ is the table of coefficients,
- sorted from highest to lowest.
-
- :code:`source = ["lib/polevl.c", ...]`
- (`link to code <https://github.com/SasView/sasmodels/tree/master/sasmodels/models/lib/polevl.c>`_)
-
- sas_gamma(x):
- Gamma function $\text{sas_gamma}(x) = \Gamma(x)$.
-
- The standard math function, tgamma(x) is unstable for $x < 1$
- on some platforms.
-
- :code:`source = ["lib/sasgamma.c", ...]`
- (`link to code <https://github.com/SasView/sasmodels/tree/master/sasmodels/models/lib/sas_gamma.c>`_)
-
- sas_erf(x), sas_erfc(x):
- Error function
- $\text{sas_erf}(x) = \frac{2}{\sqrt\pi}\int_0^x e^{-t^2}\,dt$
- and complementary error function
- $\text{sas_erfc}(x) = \frac{2}{\sqrt\pi}\int_x^{\infty} e^{-t^2}\,dt$.
-
- The standard math functions erf(x) and erfc(x) are slower and broken
- on some platforms.
-
- :code:`source = ["lib/polevl.c", "lib/sas_erf.c", ...]`
- (`link to error functions' code <https://github.com/SasView/sasmodels/tree/master/sasmodels/models/lib/sas_erf.c>`_)
-
- sas_J0(x):
- Bessel function of the first kind $\text{sas_J0}(x)=J_0(x)$ where
- $J_0(x) = \frac{1}{\pi}\int_0^\pi \cos(x\sin(\tau))\,d\tau$.
-
- The standard math function j0(x) is not available on all platforms.
-
- :code:`source = ["lib/polevl.c", "lib/sas_J0.c", ...]`
- (`link to Bessel function's code <https://github.com/SasView/sasmodels/tree/master/sasmodels/models/lib/sas_J0.c>`_)
-
- sas_J1(x):
- Bessel function of the first kind $\text{sas_J1}(x)=J_1(x)$ where
- $J_1(x) = \frac{1}{\pi}\int_0^\pi \cos(\tau - x\sin(\tau))\,d\tau$.
-
- The standard math function j1(x) is not available on all platforms.
-
- :code:`source = ["lib/polevl.c", "lib/sas_J1.c", ...]`
- (`link to Bessel function's code <https://github.com/SasView/sasmodels/tree/master/sasmodels/models/lib/sas_J1.c>`_)
-
- sas_JN(n, x):
- Bessel function of the first kind and integer order $n$:
- $\text{sas_JN}(n, x)=J_n(x)$ where
- $J_n(x) = \frac{1}{\pi}\int_0^\pi \cos(n\tau - x\sin(\tau))\,d\tau$.
- If $n$ = 0 or 1, it uses sas_J0(x) or sas_J1(x), respectively.
-
- The standard math function jn(n, x) is not available on all platforms.
-
- :code:`source = ["lib/polevl.c", "lib/sas_J0.c", "lib/sas_J1.c", "lib/sas_JN.c", ...]`
- (`link to Bessel function's code <https://github.com/SasView/sasmodels/tree/master/sasmodels/models/lib/sas_JN.c>`_)
-
- sas_Si(x):
- Sine integral $\text{Si}(x) = \int_0^x \tfrac{\sin t}{t}\,dt$.
-
- This function uses Taylor series for small and large arguments:
-
- For large arguments,
-
- .. math::
-
- \text{Si}(x) \sim \frac{\pi}{2}
- - \frac{\cos(x)}{x}\left(1 - \frac{2!}{x^2} + \frac{4!}{x^4} - \frac{6!}{x^6} \right)
- - \frac{\sin(x)}{x}\left(\frac{1}{x} - \frac{3!}{x^3} + \frac{5!}{x^5} - \frac{7!}{x^7}\right)
-
- For small arguments,
-
- .. math::
-
- \text{Si}(x) \sim x
- - \frac{x^3}{3\times 3!} + \frac{x^5}{5 \times 5!} - \frac{x^7}{7 \times 7!}
- + \frac{x^9}{9\times 9!} - \frac{x^{11}}{11\times 11!}
-
- :code:`source = ["lib/Si.c", ...]`
- (`link to code <https://github.com/SasView/sasmodels/tree/master/sasmodels/models/lib/Si.c>`_)
-
- sas_3j1x_x(x):
- Spherical Bessel form
- $\text{sph_j1c}(x) = 3 j_1(x)/x = 3 (\sin(x) - x \cos(x))/x^3$,
- with a limiting value of 1 at $x=0$, where $j_1(x)$ is the spherical
- Bessel function of the first kind and first order.
-
- This function uses a Taylor series for small $x$ for numerical accuracy.
-
- :code:`source = ["lib/sas_3j1x_x.c", ...]`
- (`link to code <https://github.com/SasView/sasmodels/tree/master/sasmodels/models/lib/sas_3j1x_x.c>`_)
-
-
- sas_2J1x_x(x):
- Bessel form $\text{sas_J1c}(x) = 2 J_1(x)/x$, with a limiting value
- of 1 at $x=0$, where $J_1(x)$ is the Bessel function of first kind
- and first order.
-
- :code:`source = ["lib/polevl.c", "lib/sas_J1.c", ...]`
- (`link to Bessel form's code <https://github.com/SasView/sasmodels/tree/master/sasmodels/models/lib/sas_J1.c>`_)
-
-
- Gauss76Z[i], Gauss76Wt[i]:
- Points $z_i$ and weights $w_i$ for 76-point Gaussian quadrature, respectively,
- computing $\int_{-1}^1 f(z)\,dz \approx \sum_{i=1}^{76} w_i\,f(z_i)$.
-
- Similar arrays are available in :code:`gauss20.c` for 20-point
- quadrature and in :code:`gauss150.c` for 150-point quadrature.
-
- :code:`source = ["lib/gauss76.c", ...]`
- (`link to code <https://github.com/SasView/sasmodels/tree/master/sasmodels/models/lib/gauss76.c>`_)
-
-
-
-Problems with C models
-......................
-
-The graphics processor (GPU) in your computer is a specialized computer tuned
-for certain kinds of problems. This leads to strange restrictions that you
-need to be aware of. Your code may work fine on some platforms or for some
-models, but then return bad values on other platforms. Some examples of
-particular problems:
-
- **(1) Code is too complex, or uses too much memory.** GPU devices only have a
- limited amount of memory available for each processor. If you run programs
- which take too much memory, then rather than running multiple values in parallel
- as it usually does, the GPU may only run a single version of the code at a
- time, making it slower than running on the CPU. It may fail to run on
- some platforms, or worse, cause the screen to go blank or the system to reboot.
-
- **(2) Code takes too long.** Because GPU devices are used for the computer
- display, the OpenCL drivers are very careful about the amount of time they
- will allow any code to run. For example, on OS X, the model will stop running
- after 5 seconds regardless of whether the computation is complete. You may end up
- with only some of your 2D array defined, with the rest containing random
- data. Or it may cause the screen to go blank or the system to reboot.
-
- **(3) Memory is not aligned**. The GPU hardware is specialized to operate on
- multiple values simultaneously. To keep the GPU simple the values in memory
- must be aligned with the different GPU compute engines. Not following these
- rules can lead to unexpected values being loaded into memory, and wrong answers
- computed. The conclusion from a very long and strange debugging session was
- that any arrays that you declare in your model should be a multiple of four.
- For example::
-
- double Iq(q, p1, p2, ...)
- {
- double vector[8]; // Only going to use seven slots, but declare 8
- ...
- }
-
-The first step when your model is behaving strangely is to set **single=False**.
-This automatically restricts the model to only run on the CPU, or on high-end
-GPU cards. There can still be problems even on high-end cards, so you can force
-the model off the GPU by setting **opencl=False**. This runs the model
-as a normal C program without any GPU restrictions so you know that
-strange results are probably from your code rather than the environment. Once
-the code is debugged, you can compare your output to the output on the GPU.
-
-Although it can be difficult to get your model to work on the GPU, the reward
-can be a model that runs 1000x faster on a good card. Even your laptop may
-show a 50x improvement or more over the equivalent pure python model.
-
-External C Models
-.................
-
-External C models are very much like embedded C models, except that
-*Iq*, *Iqxy* and *form_volume* are defined in an external source file
-loaded using the *source=[...]* statement. You need to supply the function
-declarations for each of these that you need instead of building them
-automatically from the parameter table.
-
-
-.. _Form_Factors:
-
-Form Factors
-............
-
-Away from the dilute limit you can estimate scattering including
-particle-particle interactions using $I(q) = P(q)*S(q)$ where $P(q)$
-is the form factor and $S(q)$ is the structure factor. The simplest
-structure factor is the *hardsphere* interaction, which
-uses the effective radius of the form factor as an input to the structure
-factor model. The effective radius is the average radius of the
-form averaged over all the polydispersity values.
-
-::
-
- def ER(radius, thickness):
- """Effective radius of a core-shell sphere."""
- return radius + thickness
-
-Now consider the *core_shell_sphere*, which has a simple effective radius
-equal to the radius of the core plus the thickness of the shell, as
-shown above. Given polydispersity over *(r1, r2, ..., rm)* in radius and
-*(t1, t2, ..., tn)* in thickness, *ER* is called with a mesh
-grid covering all possible combinations of radius and thickness.
-That is, *radius* is *(r1, r2, ..., rm, r1, r2, ..., rm, ...)*
-and *thickness* is *(t1, t1, ... t1, t2, t2, ..., t2, ...)*.
-The *ER* function returns one effective radius for each combination.
-The effective radius calculator weights each of these according to
-the polydispersity distributions and calls the structure factor
-with the average *ER*.
-
-::
-
- def VR(radius, thickness):
- """Sphere and shell volumes for a core-shell sphere."""
- whole = 4.0/3.0 * pi * (radius + thickness)**3
- core = 4.0/3.0 * pi * radius**3
- return whole, whole - core
-
-Core-shell type models have an additional volume ratio which scales
-the structure factor. The *VR* function returns the volume of
-the whole sphere and the volume of the shell. Like *ER*, there is
-one return value for each point in the mesh grid.
-
-*NOTE: we may be removing or modifying this feature soon. As of the
-time of writing, core-shell sphere returns (1., 1.) for VR, giving a volume
-ratio of 1.0.*
-
-Unit Tests
-..........
-
-THESE ARE VERY IMPORTANT. Include at least one test for each model and
-PLEASE make sure that the answer value is correct (i.e. not a random number).
-
-::
-
- tests = [
- [{}, 0.2, 0.726362],
- [{"scale": 1., "background": 0., "sld": 6., "sld_solvent": 1.,
- "radius": 120., "radius_pd": 0.2, "radius_pd_n":45},
- 0.2, 0.228843],
- [{"radius": 120., "radius_pd": 0.2, "radius_pd_n":45}, "ER", 120.],
- [{"radius": 120., "radius_pd": 0.2, "radius_pd_n":45}, "VR", 1.],
- ]
-
-
-**tests=[[{parameters}, q, result], ...]** is a list of lists.
-Each list is one test and contains, in order:
-
-- a dictionary of parameter values. This can be {} using the default
- parameters, or filled with some parameters that will be different
- from the default, such as {‘radius’:10.0, ‘sld’:4}. Unlisted parameters
- will be given the default values.
-- the input $q$ value or tuple of $(q_x, q_y)$ values.
-- the output $I(q)$ or $I(q_x,q_y)$ expected of the model for the parameters
- and input value given.
-- input and output values can themselves be lists if you have several
- $q$ values to test for the same model parameters.
-- for testing *ER* and *VR*, give the inputs as "ER" and "VR" respectively;
- the output for *VR* should be the sphere/shell ratio, not the individual
- sphere and shell values.
-
-.. _Test_Your_New_Model:
-
-Test Your New Model
-^^^^^^^^^^^^^^^^^^^
-
-Minimal Testing
-...............
-
-Either open the :ref:`Python_shell` (*Tools* > *Python Shell/Editor*) or the :ref:`Advanced_Plugin_Editor` (*Fitting* > *Plugin Model Operations* > *Advanced
-Plugin Editor*), load your model, and then select *Run > Check Model* from the
-menu bar.
-
-An *Info* box will appear with the results of the compilation and a check that
-the model runs.
-
-Recommended Testing
-...................
-
-If the model compiles and runs, you can next run the unit tests that
-you have added using the **test =** values. Switch to the *Shell* tab
-and type the following::
-
- from sasmodels.model_test import run_one
- run_one("~/.sasview/plugin_models/model.py")
-
-This should print::
-
- test_model_python (sasmodels.model_test.ModelTestCase) ... ok
-
-To check whether single precision is good enough, type the following::
-
- from sasmodels.compare import main
- main("~/.sasview/plugin_models/model.py")
-
-This will pop up a plot showing the difference between single precision
-and double precision on a range of $q$ values.
-
-::
-
- demo = dict(scale=1, background=0,
- sld=6, sld_solvent=1,
- radius=120,
- radius_pd=.2, radius_pd_n=45)
-
-**demo={'par': value, ...}** in the model file sets the default values for
-the comparison. You can include polydispersity parameters such as
-*radius_pd=0.2, radius_pd_n=45* which would otherwise be zero.
-
-The options to compare are quite extensive; type the following for help::
-
- main()
-
-Options will need to be passed as separate strings.
-For example to run your model with a random set of parameters::
-
- main("-random", "-pars", "~/.sasview/plugin_models/model.py")
-
-For the random models,
-
-- *sld* will be in the range (-0.5,10.5),
-- angles (*theta, phi, psi*) will be in the range (-180,180),
-- angular dispersion will be in the range (0,45),
-- polydispersity will be in the range (0,1)
-- other values will be in the range (0, 2\ *v*), where *v* is the value of the parameter in demo.
-
-Dispersion parameters *n*\, *sigma* and *type* will be unchanged from demo so that
-run times are predictable.
-
-If your model has 2D orientational calculation, then you should also
-test with::
-
- main("-2d", "~/.sasview/plugin_models/model.py")
-
-
-Clean Lint - (Developer Version Only)
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-**NB: For now we are not providing pylint with the installer version of SasView;
-so unless you have a SasView build environment available, you can ignore this section!**
-
-Run the lint check with::
-
- python -m pylint --rcfile=extra/pylint.rc ~/.sasview/plugin_models/model.py
-
-We are not aiming for zero lint just yet, only keeping it to a minimum.
-For now, don't worry too much about *invalid-name*. If you really want a
-variable name *Rg* for example because $R_g$ is the right name for the model
-parameter then ignore the lint errors. Also, ignore *missing-docstring*
-for standard model functions *Iq*, *Iqxy*, etc.
-
-We will have delinting sessions at the SasView Code Camps, where we can
-decide on standards for model files, parameter names, etc.
-
-For now, you can tell pylint to ignore things. For example, to align your
-parameters in blocks::
-
- # pylint: disable=bad-whitespace,line-too-long
- # ["name", "units", default, [lower, upper], "type", "description"],
- parameters = [
- ["contrast_factor", "barns", 10.0, [-inf, inf], "", "Contrast factor of the polymer"],
- ["bjerrum_length", "Ang", 7.1, [0, inf], "", "Bjerrum length"],
- ["virial_param", "1/Ang^2", 12.0, [-inf, inf], "", "Virial parameter"],
- ["monomer_length", "Ang", 10.0, [0, inf], "", "Monomer length"],
- ["salt_concentration", "mol/L", 0.0, [-inf, inf], "", "Concentration of monovalent salt"],
- ["ionization_degree", "", 0.05, [0, inf], "", "Degree of ionization"],
- ["polymer_concentration", "mol/L", 0.7, [0, inf], "", "Polymer molar concentration"],
- ]
- # pylint: enable=bad-whitespace,line-too-long
-
-Don't put in too many pylint statements, though, since they make the code ugly.
-
-Check The Docs - (Developer Version Only)
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-You can get a rough idea of how the documentation will look using the
-following::
-
- from sasmodels.generate import view_html
- view_html('~/.sasview/plugin_models/model.py')
-
-This does not use the same styling as the SasView docs, but it will allow
-you to check that your ReStructuredText and LaTeX formatting. Here are
-some tools to help with the inevitable syntax errors:
-
-- `Sphinx cheat sheet <http://matplotlib.org/sampledoc/cheatsheet.html>`_
-- `Sphinx Documentation <http://www.sphinx-doc.org/en/stable/>`_
-- `MathJax <http://www.mathjax.org/>`_
-- `amsmath <http://www.ams.org/publications/authors/tex/amslatex>`_
-
-There is also a neat online WYSIWYG ReStructuredText editor at http://rst.ninjs.org\ .
-
-Share Your Model!
-^^^^^^^^^^^^^^^^^
-
-Once compare and the unit test(s) pass properly and everything is done,
-consider adding your model to the
-`Model Marketplace <http://marketplace.sasview.org/>`_ so that others may use it!
-
-.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
-
-.. note:: This help document was last changed by Steve King, 25Oct2016
diff --git a/src/sas/sasgui/perspectives/fitting/media/residuals_help.rst b/src/sas/sasgui/perspectives/fitting/media/residuals_help.rst
index d877130..d7460ab 100644
--- a/src/sas/sasgui/perspectives/fitting/media/residuals_help.rst
+++ b/src/sas/sasgui/perspectives/fitting/media/residuals_help.rst
@@ -17,7 +17,7 @@ One way is obviously to just inspect the graph of the experimental data and to
see how closely (or not!) the 'theory' calculation matches it. But *SasView*
also provides two other measures of the quality of a fit:
-* |chi|\ :sup:`2` (or 'Chi2'; pronounced 'chi-squared')
+* $\chi^2$ (or 'Chi2'; pronounced 'chi-squared')
* *Residuals*
.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
@@ -25,23 +25,33 @@ also provides two other measures of the quality of a fit:
Chi2
^^^^
-Chi2 is a statistical parameter that quantifies the differences between an observed
-data set and an expected dataset (or 'theory').
+$\chi^2$ is a statistical parameter that quantifies the differences between
+an observed data set and an expected dataset (or 'theory').
-*SasView* actually returns this parameter normalized to the number of data points,
-*Npts* such that
+When showing the a model with the data, *SasView* displays this parameter
+normalized to the number of data points, $N_\mathrm{pts}$ such that
- *Chi2/Npts* = { SUM[(*Y_i* - *Y_theory_i*)^2 / (*Y_error_i*)^2] } / *Npts*
+.. math::
-This differs slightly from what is sometimes called the 'reduced chi-squared'
-because it does not take into account the number of fitting parameters (to
-calculate the number of 'degrees of freedom'), but the 'normalized chi-squared'
-and the 'reduced chi-squared' are very close to each other when *Npts* >> number of
-parameters.
+ \chi^2_N
+ = \sum[(Y_i - \mathrm{theory}_i)^2 / \mathrm{error}_i^2] / N_\mathrm{pts}
-For a good fit, *Chi2/Npts* tends to 0.
+When performing a fit, *SasView* instead displays the reduced $\chi^2_R$,
+which takes into account the number of fitting parameters $N_\mathrm{par}$
+(to calculate the number of 'degrees of freedom'). This is computed as
-*Chi2/Npts* is sometimes referred to as the 'goodness-of-fit' parameter.
+.. math::
+
+ \chi^2_R
+ = \sum[(Y_i - \mathrm{theory}_i)^2 / \mathrm{error}_i^2]
+ / [N_\mathrm{pts} - N_\mathrm{par}]
+
+The normalized $\chi^2_N$ and the reduced $\chi^2_R$ are very close to each
+other when $N_\mathrm{pts} \gg N_\mathrm{par}$.
+
+For a good fit, $\chi^2_R$ tends to 1.
+
+$\chi^2_R$ is sometimes referred to as the 'goodness-of-fit' parameter.
.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
@@ -49,16 +59,33 @@ Residuals
^^^^^^^^^
A residual is the difference between an observed value and an estimate of that
-value, such as a 'theory' calculation (whereas the difference between an observed
-value and its *true* value is its error).
+value, such as a 'theory' calculation (whereas the difference between an
+observed value and its *true* value is its error).
-*SasView* calculates 'normalized residuals', *R_i*, for each data point in the
+*SasView* calculates 'normalized residuals', $R_i$, for each data point in the
fit:
- *R_i* = (*Y_i* - *Y_theory_i*) / (*Y_err_i*)
+.. math::
-For a good fit, *R_i* ~ 0.
+ R_i = (Y_i - \mathrm{theory}_i) / \mathrm{error}_i
+
+Think of each normalized residual as the number of standard deviations
+between the measured value and the theory. For a good fit, 68% of $R_i$
+will be within one standard deviation, which will show up in the Residuals
+plot as $R_i$ values between $-1$ and $+1$. Almost all the values should
+be between $-3$ and $+3$.
+
+Residuals values larger than $\pm 3$ indicate that the model
+is not fit correctly, the wrong model was chosen (e.g., because there is
+more than one phase in your system), or there are problems in
+the data reduction. Since the goodness of fit is calculated from the
+sum-squared residuals, these extreme values will drive the choice of fit
+parameters. Any uncertainties calculated for the fitting parameters will
+be meaningless.
.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
-.. note:: This help document was last changed by Steve King, 08Jun2015
+*Document History*
+
+| 2015-06-08 Steve King
+| 2017-09-28 Paul Kienzle
\ No newline at end of file
diff --git a/src/sas/sasgui/perspectives/fitting/media/restore_batch_window.bmp b/src/sas/sasgui/perspectives/fitting/media/restore_batch_window.bmp
deleted file mode 100644
index 9214a50..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/restore_batch_window.bmp and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/restore_batch_window.png b/src/sas/sasgui/perspectives/fitting/media/restore_batch_window.png
new file mode 100644
index 0000000..e7b8534
Binary files /dev/null and b/src/sas/sasgui/perspectives/fitting/media/restore_batch_window.png differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/sld1.gif b/src/sas/sasgui/perspectives/fitting/media/sld1.gif
deleted file mode 100644
index 591aa0b..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/sld1.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/sld2.gif b/src/sas/sasgui/perspectives/fitting/media/sld2.gif
deleted file mode 100644
index c868742..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/sld2.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/sm_help.rst b/src/sas/sasgui/perspectives/fitting/media/sm_help.rst
deleted file mode 100644
index cfcc1ef..0000000
--- a/src/sas/sasgui/perspectives/fitting/media/sm_help.rst
+++ /dev/null
@@ -1,235 +0,0 @@
-.. sm_help.rst
-
-.. This is a port of the original SasView html help file to ReSTructured text
-.. by S King, ISIS, during SasView CodeCamp-III in Feb 2015.
-
-.. |inlineimage004| image:: sm_image004.gif
-.. |inlineimage005| image:: sm_image005.gif
-.. |inlineimage008| image:: sm_image008.gif
-.. |inlineimage009| image:: sm_image009.gif
-.. |inlineimage010| image:: sm_image010.gif
-.. |inlineimage011| image:: sm_image011.gif
-.. |inlineimage012| image:: sm_image012.gif
-.. |inlineimage018| image:: sm_image018.gif
-.. |inlineimage019| image:: sm_image019.gif
-
-
-.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
-
-Smearing Functions
-==================
-
-Sometimes the instrumental geometry used to acquire the experimental data has
-an impact on the clarity of features in the reduced scattering curve. For
-example, peaks or fringes might be slightly broadened. This is known as
-*Q resolution smearing*. To compensate for this effect one can either try and
-remove the resolution contribution - a process called *desmearing* - or add the
-resolution contribution into a model calculation/simulation (which by definition
-will be exact) to make it more representative of what has been measured
-experimentally - a process called *smearing*. SasView will do the latter.
-
-Both smearing and desmearing rely on functions to describe the resolution
-effect. SasView provides three smearing algorithms:
-
-* *Slit Smearing*
-* *Pinhole Smearing*
-* *2D Smearing*
-
-SasView also has an option to use Q resolution data (estimated at the time of
-data reduction) supplied in a reduced data file: the *Use dQ data* radio button.
-
-.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
-
-dQ Smearing
------------
-
-If this option is checked, SasView will assume that the supplied dQ values
-represent the standard deviations of Gaussian functions.
-
-.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
-
-Slit Smearing
--------------
-
-**This type of smearing is normally only encountered with data from X-ray Kratky**
-**cameras or X-ray/neutron Bonse-Hart USAXS/USANS instruments.**
-
-The slit-smeared scattering intensity is defined by
-
-.. image:: sm_image002.gif
-
-where *Norm* is given by
-
-.. image:: sm_image003.gif
-
-**[Equation 1]**
-
-The functions |inlineimage004| and |inlineimage005|
-refer to the slit width weighting function and the slit height weighting
-determined at the given *q* point, respectively. It is assumed that the weighting
-function is described by a rectangular function, such that
-
-.. image:: sm_image006.gif
-
-**[Equation 2]**
-
-and
-
-.. image:: sm_image007.gif
-
-**[Equation 3]**
-
-so that |inlineimage008| |inlineimage009| for |inlineimage010| and *u*\ .
-
-Here |inlineimage011| and |inlineimage012| stand for
-the slit height (FWHM/2) and the slit width (FWHM/2) in *q* space.
-
-This simplifies the integral in Equation 1 to
-
-.. image:: sm_image013.gif
-
-**[Equation 4]**
-
-which may be solved numerically, depending on the nature of |inlineimage011| and |inlineimage012| .
-
-Solution 1
-^^^^^^^^^^
-
-**For** |inlineimage012| **= 0 and** |inlineimage011| **= constant.**
-
-.. image:: sm_image016.gif
-
-For discrete *q* values, at the *q* values of the data points and at the *q*
-values extended up to *q*\ :sub:`N`\ = *q*\ :sub:`i` + |inlineimage011| the smeared
-intensity can be approximately calculated as
-
-.. image:: sm_image017.gif
-
-**[Equation 5]**
-
-where |inlineimage018| = 0 for *I*\ :sub:`s` when *j* < *i* or *j* > *N-1*.
-
-Solution 2
-^^^^^^^^^^
-
-**For** |inlineimage012| **= constant and** |inlineimage011| **= 0.**
-
-Similar to Case 1
-
-|inlineimage019| for *q*\ :sub:`p` = *q*\ :sub:`i` - |inlineimage012| and *q*\ :sub:`N` = *q*\ :sub:`i` + |inlineimage012|
-
-**[Equation 6]**
-
-where |inlineimage018| = 0 for *I*\ :sub:`s` when *j* < *p* or *j* > *N-1*.
-
-Solution 3
-^^^^^^^^^^
-
-**For** |inlineimage011| **= constant and** |inlineimage011| **= constant.**
-
-In this case, the best way is to perform the integration of Equation 1
-numerically for both slit height and slit width. However, the numerical
-integration is imperfect unless a large number of iterations, say, at
-least 10000 by 10000 for each element of the matrix *W*, is performed.
-This is usually too slow for routine use.
-
-An alternative approach is used in SasView which assumes
-slit width << slit height. This method combines Solution 1 with the
-numerical integration for the slit width. Then
-
-.. image:: sm_image020.gif
-
-**[Equation 7]**
-
-for *q*\ :sub:`p` = *q*\ :sub:`i` - |inlineimage012| and *q*\ :sub:`N` = *q*\ :sub:`i` + |inlineimage012|
-
-where |inlineimage018| = 0 for *I*\ :sub:`s` when *j* < *p* or *j* > *N-1*.
-
-.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
-
-Pinhole Smearing
-----------------
-
-**This is the type of smearing normally encountered with data from synchrotron**
-**SAXS cameras and SANS instruments.**
-
-The pinhole smearing computation is performed in a similar fashion to the slit-
-smeared case above except that the weight function used is a Gaussian. Thus
-Equation 6 becomes
-
-.. image:: sm_image021.gif
-
-**[Equation 8]**
-
-.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
-
-2D Smearing
------------
-
-The 2D smearing computation is performed in a similar fashion to the 1D pinhole
-smearing above except that the weight function used is a 2D elliptical Gaussian.
-Thus
-
-.. image:: sm_image022.gif
-
-**[Equation 9]**
-
-In Equation 9, *x*\ :sub:`0` = *q* cos(|theta|), *y*\ :sub:`0` = *q* sin(|theta|), and
-the primed axes, are all in the coordinate rotated by an angle |theta| about
-the z-axis (see the figure below) so that *x'*\ :sub:`0` = *x*\ :sub:`0` cos(|theta|) +
-*y*\ :sub:`0` sin(|theta|) and *y'*\ :sub:`0` = -*x*\ :sub:`0` sin(|theta|) +
-*y*\ :sub:`0` cos(|theta|). Note that the rotation angle is zero for a x-y symmetric
-elliptical Gaussian distribution. The *A* is a normalization factor.
-
-.. image:: sm_image023.gif
-
-Now we consider a numerical integration where each of the bins in |theta| and *R* are
-*evenly* (this is to simplify the equation below) distributed by |bigdelta|\ |theta|
-and |bigdelta|\ R, respectively, and it is further assumed that *I(x',y')* is constant
-within the bins. Then
-
-.. image:: sm_image024.gif
-
-**[Equation 10]**
-
-Since the weighting factor on each of the bins is known, it is convenient to
-transform *x'-y'* back to *x-y* coordinates (by rotating it by -|theta| around the
-*z* axis).
-
-Then, for a polar symmetric smear
-
-.. image:: sm_image025.gif
-
-**[Equation 11]**
-
-where
-
-.. image:: sm_image026.gif
-
-while for a *x-y* symmetric smear
-
-.. image:: sm_image027.gif
-
-**[Equation 12]**
-
-where
-
-.. image:: sm_image028.gif
-
-The current version of the SasView uses Equation 11 for 2D smearing, assuming
-that all the Gaussian weighting functions are aligned in the polar coordinate.
-
-.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
-
-Weighting & Normalization
--------------------------
-
-In all the cases above, the weighting matrix *W* is calculated on the first call
-to a smearing function, and includes ~60 *q* values (finely and evenly binned)
-below (>0) and above the *q* range of data in order to smear all data points for
-a given model and slit/pinhole size. The *Norm* factor is found numerically with the
-weighting matrix and applied on the computation of *I*\ :sub:`s`.
-
-.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
-
-.. note:: This help document was last changed by Steve King, 01May2015
diff --git a/src/sas/sasgui/perspectives/fitting/media/sm_image002.gif b/src/sas/sasgui/perspectives/fitting/media/sm_image002.gif
deleted file mode 100644
index 71d3c6b..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/sm_image002.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/sm_image003.gif b/src/sas/sasgui/perspectives/fitting/media/sm_image003.gif
deleted file mode 100644
index d437071..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/sm_image003.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/sm_image004.gif b/src/sas/sasgui/perspectives/fitting/media/sm_image004.gif
deleted file mode 100644
index cd8b384..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/sm_image004.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/sm_image005.gif b/src/sas/sasgui/perspectives/fitting/media/sm_image005.gif
deleted file mode 100644
index 6e601a7..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/sm_image005.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/sm_image006.gif b/src/sas/sasgui/perspectives/fitting/media/sm_image006.gif
deleted file mode 100644
index 75df2d4..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/sm_image006.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/sm_image007.gif b/src/sas/sasgui/perspectives/fitting/media/sm_image007.gif
deleted file mode 100644
index 3b8d1bd..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/sm_image007.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/sm_image008.gif b/src/sas/sasgui/perspectives/fitting/media/sm_image008.gif
deleted file mode 100644
index aae96ff..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/sm_image008.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/sm_image009.gif b/src/sas/sasgui/perspectives/fitting/media/sm_image009.gif
deleted file mode 100644
index e9618d5..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/sm_image009.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/sm_image010.gif b/src/sas/sasgui/perspectives/fitting/media/sm_image010.gif
deleted file mode 100644
index 8e7d681..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/sm_image010.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/sm_image011.gif b/src/sas/sasgui/perspectives/fitting/media/sm_image011.gif
deleted file mode 100644
index 60affb8..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/sm_image011.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/sm_image012.gif b/src/sas/sasgui/perspectives/fitting/media/sm_image012.gif
deleted file mode 100644
index 9c6096f..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/sm_image012.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/sm_image013.gif b/src/sas/sasgui/perspectives/fitting/media/sm_image013.gif
deleted file mode 100644
index 2733a66..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/sm_image013.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/sm_image016.gif b/src/sas/sasgui/perspectives/fitting/media/sm_image016.gif
deleted file mode 100644
index e5d7153..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/sm_image016.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/sm_image017.gif b/src/sas/sasgui/perspectives/fitting/media/sm_image017.gif
deleted file mode 100644
index 2f7301e..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/sm_image017.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/sm_image018.gif b/src/sas/sasgui/perspectives/fitting/media/sm_image018.gif
deleted file mode 100644
index fe2e668..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/sm_image018.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/sm_image019.gif b/src/sas/sasgui/perspectives/fitting/media/sm_image019.gif
deleted file mode 100644
index 87ce88b..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/sm_image019.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/sm_image020.gif b/src/sas/sasgui/perspectives/fitting/media/sm_image020.gif
deleted file mode 100644
index e6ee0e5..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/sm_image020.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/sm_image021.gif b/src/sas/sasgui/perspectives/fitting/media/sm_image021.gif
deleted file mode 100644
index 45b3be3..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/sm_image021.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/sm_image022.gif b/src/sas/sasgui/perspectives/fitting/media/sm_image022.gif
deleted file mode 100644
index dcc21d3..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/sm_image022.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/sm_image023.gif b/src/sas/sasgui/perspectives/fitting/media/sm_image023.gif
deleted file mode 100644
index 5f930ae..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/sm_image023.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/sm_image024.gif b/src/sas/sasgui/perspectives/fitting/media/sm_image024.gif
deleted file mode 100644
index c7402d4..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/sm_image024.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/sm_image025.gif b/src/sas/sasgui/perspectives/fitting/media/sm_image025.gif
deleted file mode 100644
index 8b43497..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/sm_image025.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/sm_image026.gif b/src/sas/sasgui/perspectives/fitting/media/sm_image026.gif
deleted file mode 100644
index c008fb1..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/sm_image026.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/sm_image027.gif b/src/sas/sasgui/perspectives/fitting/media/sm_image027.gif
deleted file mode 100644
index 130608e..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/sm_image027.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/sm_image028.gif b/src/sas/sasgui/perspectives/fitting/media/sm_image028.gif
deleted file mode 100644
index 5ee54b2..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/sm_image028.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/sum_model.bmp b/src/sas/sasgui/perspectives/fitting/media/sum_model.bmp
deleted file mode 100644
index 83541a4..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/sum_model.bmp and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/sum_model.png b/src/sas/sasgui/perspectives/fitting/media/sum_model.png
new file mode 100644
index 0000000..c4e4e10
Binary files /dev/null and b/src/sas/sasgui/perspectives/fitting/media/sum_model.png differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/view_button.bmp b/src/sas/sasgui/perspectives/fitting/media/view_button.bmp
deleted file mode 100644
index ba64d3d..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/view_button.bmp and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/view_button.png b/src/sas/sasgui/perspectives/fitting/media/view_button.png
new file mode 100644
index 0000000..daed8af
Binary files /dev/null and b/src/sas/sasgui/perspectives/fitting/media/view_button.png differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/view_data_model.bmp b/src/sas/sasgui/perspectives/fitting/media/view_data_model.bmp
deleted file mode 100644
index 372ca6a..0000000
Binary files a/src/sas/sasgui/perspectives/fitting/media/view_data_model.bmp and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/fitting/media/view_data_model.png b/src/sas/sasgui/perspectives/fitting/media/view_data_model.png
new file mode 100644
index 0000000..d868050
Binary files /dev/null and b/src/sas/sasgui/perspectives/fitting/media/view_data_model.png differ
diff --git a/src/sas/sasgui/perspectives/fitting/model_thread.py b/src/sas/sasgui/perspectives/fitting/model_thread.py
index 001b3c0..39c4384 100644
--- a/src/sas/sasgui/perspectives/fitting/model_thread.py
+++ b/src/sas/sasgui/perspectives/fitting/model_thread.py
@@ -1,10 +1,12 @@
"""
- Calculation thread for modeling
+Calculation thread for modeling
"""
import time
-import numpy
import math
+
+import numpy as np
+
from sas.sascalc.data_util.calcthread import CalcThread
from sas.sascalc.fit.MultiplicationModel import MultiplicationModel
@@ -27,7 +29,7 @@ class Calc2D(CalcThread):
yieldtime=0.04,
worktime=0.04,
exception_handler=None,
- ):
+ ):
CalcThread.__init__(self, completefn, updatefn, yieldtime, worktime,
exception_handler=exception_handler)
self.qmin = qmin
@@ -52,29 +54,26 @@ class Calc2D(CalcThread):
"""
self.starttime = time.time()
# Determine appropriate q range
- if self.qmin == None:
+ if self.qmin is None:
self.qmin = 0
- if self.qmax == None:
- if self.data != None:
- newx = math.pow(max(math.fabs(self.data.xmax),
- math.fabs(self.data.xmin)), 2)
- newy = math.pow(max(math.fabs(self.data.ymax),
- math.fabs(self.data.ymin)), 2)
- self.qmax = math.sqrt(newx + newy)
+ if self.qmax is None:
+ if self.data is not None:
+ newx = max(math.fabs(self.data.xmax), math.fabs(self.data.xmin))
+ newy = max(math.fabs(self.data.ymax), math.fabs(self.data.ymin))
+ self.qmax = math.sqrt(newx**2 + newy**2)
if self.data is None:
msg = "Compute Calc2D receive data = %s.\n" % str(self.data)
raise ValueError, msg
# Define matrix where data will be plotted
- radius = numpy.sqrt((self.data.qx_data * self.data.qx_data) + \
- (self.data.qy_data * self.data.qy_data))
+ radius = np.sqrt(self.data.qx_data**2 + self.data.qy_data**2)
- # For theory, qmax is based on 1d qmax
+ # For theory, qmax is based on 1d qmax
# so that must be mulitified by sqrt(2) to get actual max for 2d
index_model = (self.qmin <= radius) & (radius <= self.qmax)
- index_model = index_model & self.data.mask
- index_model = index_model & numpy.isfinite(self.data.data)
+ index_model &= self.data.mask
+ index_model &= np.isfinite(self.data.data)
if self.smearer is not None:
# Set smearer w/ data, model and index.
@@ -90,29 +89,30 @@ class Calc2D(CalcThread):
self.data.qx_data[index_model],
self.data.qy_data[index_model]
])
- output = numpy.zeros(len(self.data.qx_data))
+ # Initialize output to NaN so masked elements do not get plotted.
+ output = np.empty_like(self.data.qx_data)
# output default is None
# This method is to distinguish between masked
#point(nan) and data point = 0.
- output = output / output
+ output[:] = np.NaN
# set value for self.mask==True, else still None to Plottools
output[index_model] = value
elapsed = time.time() - self.starttime
self.complete(image=output,
- data=self.data,
- page_id=self.page_id,
- model=self.model,
- state=self.state,
- toggle_mode_on=self.toggle_mode_on,
- elapsed=elapsed,
- index=index_model,
- fid=self.fid,
- qmin=self.qmin,
- qmax=self.qmax,
- weight=self.weight,
- #qstep=self.qstep,
- update_chisqr=self.update_chisqr,
- source=self.source)
+ data=self.data,
+ page_id=self.page_id,
+ model=self.model,
+ state=self.state,
+ toggle_mode_on=self.toggle_mode_on,
+ elapsed=elapsed,
+ index=index_model,
+ fid=self.fid,
+ qmin=self.qmin,
+ qmax=self.qmax,
+ weight=self.weight,
+ #qstep=self.qstep,
+ update_chisqr=self.update_chisqr,
+ source=self.source)
class Calc1D(CalcThread):
@@ -136,7 +136,7 @@ class Calc1D(CalcThread):
yieldtime=0.01,
worktime=0.01,
exception_handler=None,
- ):
+ ):
"""
"""
CalcThread.__init__(self, completefn, updatefn, yieldtime, worktime,
@@ -162,7 +162,7 @@ class Calc1D(CalcThread):
Compute model 1d value given qmin , qmax , x value
"""
self.starttime = time.time()
- output = numpy.zeros((len(self.data.x)))
+ output = np.zeros((len(self.data.x)))
index = (self.qmin <= self.data.x) & (self.data.x <= self.qmax)
# If we use a smearer, also return the unsmeared model
@@ -174,7 +174,7 @@ class Calc1D(CalcThread):
first_bin, last_bin = self.smearer.get_bin_range(self.qmin,
self.qmax)
mask = self.data.x[first_bin:last_bin+1]
- unsmeared_output = numpy.zeros((len(self.data.x)))
+ unsmeared_output = np.zeros((len(self.data.x)))
unsmeared_output[first_bin:last_bin+1] = self.model.evalDistribution(mask)
self.smearer.model = self.model
output = self.smearer(unsmeared_output, first_bin, last_bin)
@@ -182,40 +182,39 @@ class Calc1D(CalcThread):
# Rescale data to unsmeared model
# Check that the arrays are compatible. If we only have a model but no data,
# the length of data.y will be zero.
- if isinstance(self.data.y, numpy.ndarray) and output.shape == self.data.y.shape:
- unsmeared_data = numpy.zeros((len(self.data.x)))
- unsmeared_error = numpy.zeros((len(self.data.x)))
+ if isinstance(self.data.y, np.ndarray) and output.shape == self.data.y.shape:
+ unsmeared_data = np.zeros((len(self.data.x)))
+ unsmeared_error = np.zeros((len(self.data.x)))
unsmeared_data[first_bin:last_bin+1] = self.data.y[first_bin:last_bin+1]\
* unsmeared_output[first_bin:last_bin+1]\
/ output[first_bin:last_bin+1]
unsmeared_error[first_bin:last_bin+1] = self.data.dy[first_bin:last_bin+1]\
* unsmeared_output[first_bin:last_bin+1]\
/ output[first_bin:last_bin+1]
- unsmeared_output=unsmeared_output[index]
- unsmeared_data=unsmeared_data[index]
- unsmeared_error=unsmeared_error
+ unsmeared_output = unsmeared_output[index]
+ unsmeared_data = unsmeared_data[index]
+ unsmeared_error = unsmeared_error
else:
output[index] = self.model.evalDistribution(self.data.x[index])
+ x=self.data.x[index]
+ y=output[index]
sq_values = None
pq_values = None
- s_model = None
- p_model = None
if isinstance(self.model, MultiplicationModel):
s_model = self.model.s_model
p_model = self.model.p_model
- elif hasattr(self.model, "get_composition_models"):
- p_model, s_model = self.model.get_composition_models()
+ sq_values = s_model.evalDistribution(x)
+ pq_values = p_model.evalDistribution(x)
+ elif hasattr(self.model, "calc_composition_models"):
+ results = self.model.calc_composition_models(x)
+ if results is not None:
+ pq_values, sq_values = results
- if p_model is not None and s_model is not None:
- sq_values = numpy.zeros((len(self.data.x)))
- pq_values = numpy.zeros((len(self.data.x)))
- sq_values[index] = s_model.evalDistribution(self.data.x[index])
- pq_values[index] = p_model.evalDistribution(self.data.x[index])
elapsed = time.time() - self.starttime
- self.complete(x=self.data.x[index], y=output[index],
+ self.complete(x=x, y=y,
page_id=self.page_id,
state=self.state,
weight=self.weight,
@@ -242,13 +241,13 @@ Example: ::
class CalcCommandline:
def __init__(self, n=20000):
- #print thread.get_ident()
- from sas.models.CylinderModel import CylinderModel
+ #print(thread.get_ident())
- model = CylinderModel()
+ from sasmodels.sasview_model import _make_standard_model
+ cylinder = _make_standard_model('cylinder')
+ model = cylinder()
-
- print model.runXY([0.01, 0.02])
+ print(model.runXY([0.01, 0.02]))
qmax = 0.01
qstep = 0.0001
@@ -257,12 +256,11 @@ Example: ::
x = numpy.arange(-qmax, qmax+qstep*0.01, qstep)
y = numpy.arange(-qmax, qmax+qstep*0.01, qstep)
-
calc_thread_2D = Calc2D(x, y, None, model.clone(),None,
-qmax, qmax,qstep,
- completefn=self.complete,
- updatefn=self.update ,
- yieldtime=0.0)
+ completefn=self.complete,
+ updatefn=self.update ,
+ yieldtime=0.0)
calc_thread_2D.queue()
calc_thread_2D.ready(2.5)
@@ -271,10 +269,10 @@ Example: ::
time.sleep(1)
def update(self,output):
- print "update"
+ print("update")
def complete(self, image, data, model, elapsed, qmin, qmax,index, qstep ):
- print "complete"
+ print("complete")
self.done = True
if __name__ == "__main__":
diff --git a/src/sas/sasgui/perspectives/fitting/models.py b/src/sas/sasgui/perspectives/fitting/models.py
deleted file mode 100644
index 9111026..0000000
--- a/src/sas/sasgui/perspectives/fitting/models.py
+++ /dev/null
@@ -1,455 +0,0 @@
-"""
- Utilities to manage models
-"""
-import traceback
-import os
-import sys
-import os.path
-# Time is needed by the log method
-import time
-import datetime
-import logging
-import py_compile
-import shutil
-# Explicitly import from the pluginmodel module so that py2exe
-# places it in the distribution. The Model1DPlugin class is used
-# as the base class of plug-in models.
-from sas.sascalc.fit.pluginmodel import Model1DPlugin
-from sas.sasgui.guiframe.CategoryInstaller import CategoryInstaller
-from sasmodels.sasview_model import load_custom_model, load_standard_models
-from sas.sasgui.perspectives.fitting.fitpage import CUSTOM_MODEL
-
-
-PLUGIN_DIR = 'plugin_models'
-PLUGIN_LOG = os.path.join(os.path.expanduser("~"), '.sasview', PLUGIN_DIR,
- "plugins.log")
-PLUGIN_NAME_BASE = '[plug-in] '
-
-def get_model_python_path():
- """
- Returns the python path for a model
- """
- return os.path.dirname(__file__)
-
-
-def plugin_log(message):
- """
- Log a message in a file located in the user's home directory
- """
- out = open(PLUGIN_LOG, 'a')
- now = time.time()
- stamp = datetime.datetime.fromtimestamp(now).strftime('%Y-%m-%d %H:%M:%S')
- out.write("%s: %s\n" % (stamp, message))
- out.close()
-
-
-def _check_plugin(model, name):
- """
- Do some checking before model adding plugins in the list
-
- :param model: class model to add into the plugin list
- :param name:name of the module plugin
-
- :return model: model if valid model or None if not valid
-
- """
- #Check if the plugin is of type Model1DPlugin
- if not issubclass(model, Model1DPlugin):
- msg = "Plugin %s must be of type Model1DPlugin \n" % str(name)
- plugin_log(msg)
- return None
- if model.__name__ != "Model":
- msg = "Plugin %s class name must be Model \n" % str(name)
- plugin_log(msg)
- return None
- try:
- new_instance = model()
- except:
- msg = "Plugin %s error in __init__ \n\t: %s %s\n" % (str(name),
- str(sys.exc_type),
- sys.exc_info()[1])
- plugin_log(msg)
- return None
-
- if hasattr(new_instance, "function"):
- try:
- value = new_instance.function()
- except:
- msg = "Plugin %s: error writing function \n\t :%s %s\n " % \
- (str(name), str(sys.exc_type), sys.exc_info()[1])
- plugin_log(msg)
- return None
- else:
- msg = "Plugin %s needs a method called function \n" % str(name)
- plugin_log(msg)
- return None
- return model
-
-
-def find_plugins_dir():
- """
- Find path of the plugins directory.
- The plugin directory is located in the user's home directory.
- """
- dir = os.path.join(os.path.expanduser("~"), '.sasview', PLUGIN_DIR)
-
- # If the plugin directory doesn't exist, create it
- if not os.path.isdir(dir):
- os.makedirs(dir)
-
- # Find paths needed
- try:
- # For source
- if os.path.isdir(os.path.dirname(__file__)):
- p_dir = os.path.join(os.path.dirname(__file__), PLUGIN_DIR)
- else:
- raise
- except:
- # Check for data path next to exe/zip file.
- #Look for maximum n_dir up of the current dir to find plugins dir
- n_dir = 12
- p_dir = None
- f_dir = os.path.join(os.path.dirname(__file__))
- for i in range(n_dir):
- if i > 1:
- f_dir, _ = os.path.split(f_dir)
- plugin_path = os.path.join(f_dir, PLUGIN_DIR)
- if os.path.isdir(plugin_path):
- p_dir = plugin_path
- break
- if not p_dir:
- raise
- # Place example user models as needed
- if os.path.isdir(p_dir):
- for file in os.listdir(p_dir):
- file_path = os.path.join(p_dir, file)
- if os.path.isfile(file_path):
- if file.split(".")[-1] == 'py' and\
- file.split(".")[0] != '__init__':
- if not os.path.isfile(os.path.join(dir, file)):
- shutil.copy(file_path, dir)
-
- return dir
-
-
-class ReportProblem:
- """
- Class to check for problems with specific values
- """
- def __nonzero__(self):
- type, value, tb = sys.exc_info()
- if type is not None and issubclass(type, py_compile.PyCompileError):
- print "Problem with", repr(value)
- raise type, value, tb
- return 1
-
-report_problem = ReportProblem()
-
-
-def compile_file(dir):
- """
- Compile a py file
- """
- try:
- import compileall
- compileall.compile_dir(dir=dir, ddir=dir, force=1,
- quiet=report_problem)
- except:
- return sys.exc_info()[1]
- return None
-
-
-def _findModels(dir):
- """
- Find custom models
- """
- # List of plugin objects
- dir = find_plugins_dir()
- # Go through files in plug-in directory
- if not os.path.isdir(dir):
- msg = "SasView couldn't locate Model plugin folder %r." % dir
- logging.warning(msg)
- return {}
-
- plugin_log("looking for models in: %s" % str(dir))
- #compile_file(dir) #always recompile the folder plugin
- logging.info("plugin model dir: %s" % str(dir))
-
- plugins = {}
- for filename in os.listdir(dir):
- name, ext = os.path.splitext(filename)
- if ext == '.py' and not name == '__init__':
- path = os.path.abspath(os.path.join(dir, filename))
- try:
- model = load_custom_model(path)
- model.name = PLUGIN_NAME_BASE + model.name
- plugins[model.name] = model
- except Exception:
- msg = traceback.format_exc()
- msg += "\nwhile accessing model in %r" % path
- plugin_log(msg)
- logging.warning("Failed to load plugin %r. See %s for details"
- % (path, PLUGIN_LOG))
-
- return plugins
-
-
-class ModelList(object):
- """
- Contains dictionary of model and their type
- """
- def __init__(self):
- """
- """
- self.mydict = {}
-
- def set_list(self, name, mylist):
- """
- :param name: the type of the list
- :param mylist: the list to add
-
- """
- if name not in self.mydict.keys():
- self.reset_list(name, mylist)
-
- def reset_list(self, name, mylist):
- """
- :param name: the type of the list
- :param mylist: the list to add
- """
- self.mydict[name] = mylist
-
- def get_list(self):
- """
- return all the list stored in a dictionary object
- """
- return self.mydict
-
-
-class ModelManagerBase:
- """
- Base class for the model manager
- """
- ## external dict for models
- model_combobox = ModelList()
- ## Dictionary of form factor models
- form_factor_dict = {}
- ## dictionary of structure factor models
- struct_factor_dict = {}
- ##list of structure factors
- struct_list = []
- ##list of model allowing multiplication by a structure factor
- multiplication_factor = []
- ##list of multifunctional shapes (i.e. that have user defined number of levels
- multi_func_list = []
- ## list of added models -- currently python models found in the plugin dir.
- plugins = []
- ## Event owner (guiframe)
- event_owner = None
- last_time_dir_modified = 0
-
- def __init__(self):
- self.model_dictionary = {}
- self.stored_plugins = {}
- self._getModelList()
-
- def findModels(self):
- """
- find plugin model in directory of plugin .recompile all file
- in the directory if file were modified
- """
- temp = {}
- if self.is_changed():
- temp = _findModels(dir)
- self.last_time_dir_modified = time.time()
- return temp
- logging.info("plugin model : %s" % str(temp))
- return temp
-
- def _getModelList(self):
- """
- List of models we want to make available by default
- for this application
-
- :return: the next free event ID following the new menu events
-
- """
-
- # regular model names only
- self.model_name_list = []
-
- #Build list automagically from sasmodels package
- for model in load_standard_models():
- self.model_dictionary[model.name] = model
- if model.is_structure_factor:
- self.struct_list.append(model)
- if model.is_form_factor:
- self.multiplication_factor.append(model)
- if model.is_multiplicity_model:
- self.multi_func_list.append(model)
- else:
- self.model_name_list.append(model.name)
-
- #Looking for plugins
- self.stored_plugins = self.findModels()
- self.plugins = self.stored_plugins.values()
- for name, plug in self.stored_plugins.iteritems():
- self.model_dictionary[name] = plug
-
- self._get_multifunc_models()
-
- return 0
-
- def is_changed(self):
- """
- check the last time the plugin dir has changed and return true
- is the directory was modified else return false
- """
- is_modified = False
- plugin_dir = find_plugins_dir()
- if os.path.isdir(plugin_dir):
- temp = os.path.getmtime(plugin_dir)
- if self.last_time_dir_modified < temp:
- is_modified = True
- self.last_time_dir_modified = temp
-
- return is_modified
-
- def update(self):
- """
- return a dictionary of model if
- new models were added else return empty dictionary
- """
- self.plugins = []
- new_plugins = self.findModels()
- if new_plugins:
- for name, plug in new_plugins.items():
- self.stored_plugins[name] = plug
- self.plugins.append(plug)
- self.model_dictionary[name] = plug
- self.model_combobox.set_list(CUSTOM_MODEL, self.plugins)
- return self.model_combobox.get_list()
- else:
- return {}
-
- def plugins_reset(self):
- """
- return a dictionary of model
- """
- self.plugins = []
- new_plugins = _findModels(dir)
- for name, plug in new_plugins.iteritems():
- for stored_name, stored_plug in self.stored_plugins.iteritems():
- if name == stored_name:
- del self.stored_plugins[name]
- del self.model_dictionary[name]
- break
- self.stored_plugins[name] = plug
- self.plugins.append(plug)
- self.model_dictionary[name] = plug
-
- self.model_combobox.reset_list("Plugin Models", self.plugins)
- return self.model_combobox.get_list()
-
- def _on_model(self, evt):
- """
- React to a model menu event
-
- :param event: wx menu event
-
- """
- if int(evt.GetId()) in self.form_factor_dict.keys():
- from sasmodels.sasview_model import MultiplicationModel
- self.model_dictionary[MultiplicationModel.__name__] = MultiplicationModel
- model1, model2 = self.form_factor_dict[int(evt.GetId())]
- model = MultiplicationModel(model1, model2)
- else:
- model = self.struct_factor_dict[str(evt.GetId())]()
-
-
- def _get_multifunc_models(self):
- """
- Get the multifunctional models
- """
- items = [item for item in self.plugins if item.is_multiplicity_model]
- self.multi_func_list = items
-
- def get_model_list(self):
- """
- return dictionary of models for fitpanel use
-
- """
- ## Model_list now only contains attribute lists not category list.
- ## Eventually this should be in one master list -- read in category
- ## list then pull those models that exist and get attributes then add
- ## to list ..and if model does not exist remove from list as now
- ## and update json file.
- ##
- ## -PDB April 26, 2014
-
-# self.model_combobox.set_list("Shapes", self.shape_list)
-# self.model_combobox.set_list("Shape-Independent",
-# self.shape_indep_list)
- self.model_combobox.set_list("Structure Factors", self.struct_list)
- self.model_combobox.set_list("Plugin Models", self.plugins)
- self.model_combobox.set_list("P(Q)*S(Q)", self.multiplication_factor)
- self.model_combobox.set_list("multiplication",
- self.multiplication_factor)
- self.model_combobox.set_list("Multi-Functions", self.multi_func_list)
- return self.model_combobox.get_list()
-
- def get_model_name_list(self):
- """
- return regular model name list
- """
- return self.model_name_list
-
- def get_model_dictionary(self):
- """
- return dictionary linking model names to objects
- """
- return self.model_dictionary
-
-
-class ModelManager(object):
- """
- implement model
- """
- __modelmanager = ModelManagerBase()
- cat_model_list = [__modelmanager.model_dictionary[model_name] for model_name \
- in __modelmanager.model_dictionary.keys() \
- if model_name not in __modelmanager.stored_plugins.keys()]
-
- CategoryInstaller.check_install(model_list=cat_model_list)
- def findModels(self):
- return self.__modelmanager.findModels()
-
- def _getModelList(self):
- return self.__modelmanager._getModelList()
-
- def is_changed(self):
- return self.__modelmanager.is_changed()
-
- def update(self):
- return self.__modelmanager.update()
-
- def plugins_reset(self):
- return self.__modelmanager.plugins_reset()
-
- def populate_menu(self, modelmenu, event_owner):
- return self.__modelmanager.populate_menu(modelmenu, event_owner)
-
- def _on_model(self, evt):
- return self.__modelmanager._on_model(evt)
-
- def _get_multifunc_models(self):
- return self.__modelmanager._get_multifunc_models()
-
- def get_model_list(self):
- return self.__modelmanager.get_model_list()
-
- def get_model_name_list(self):
- return self.__modelmanager.get_model_name_list()
-
- def get_model_dictionary(self):
- return self.__modelmanager.get_model_dictionary()
diff --git a/src/sas/sasgui/perspectives/fitting/plugin_models/__init__.py b/src/sas/sasgui/perspectives/fitting/plugin_models/__init__.py
index e69de29..5cfb546 100644
--- a/src/sas/sasgui/perspectives/fitting/plugin_models/__init__.py
+++ b/src/sas/sasgui/perspectives/fitting/plugin_models/__init__.py
@@ -0,0 +1,6 @@
+"""
+Example plugin models to be added to the SasView plugin directory on startup
+if no plugins are present.
+
+This is currently empty.
+"""
\ No newline at end of file
diff --git a/src/sas/sasgui/perspectives/fitting/report_dialog.py b/src/sas/sasgui/perspectives/fitting/report_dialog.py
index e4378b4..e9a0078 100644
--- a/src/sas/sasgui/perspectives/fitting/report_dialog.py
+++ b/src/sas/sasgui/perspectives/fitting/report_dialog.py
@@ -1,173 +1,114 @@
-"""
-Dialog report panel to show and summarize the results of
-the fitting calculation.
-"""
-################################################################################
-#This software was developed by the University of Tennessee as part of the
-#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
-#project funded by the US National Science Foundation.
-#
-#See the license text in license.txt
-#
-#copyright 2009, University of Tennessee
-################################################################################
-
-import wx
-import os
-import wx.html as html
-
-from sas.sasgui.guiframe.report_dialog import BaseReportDialog
-
-class ReportDialog(BaseReportDialog):
- """
- The report dialog box.
- """
-
- def __init__(self, report_list, *args, **kwds):
- """
- Initialization. The parameters added to Dialog are:
-
- :param report_list: list of html_str, text_str, image
- from invariant_state
- """
- super(ReportDialog, self).__init__(report_list, *args, **kwds)
-
- # title
- self.SetTitle("Report: Fitting")
-
- # number of images of plot
- self.nimages = len(self.report_list[2])
-
- if self.report_list[2] != None:
- # put image path in the report string
- if len(self.report_list[2]) == 1:
- self.report_html = self.report_list[0] % \
- "memory:img_fit0.png"
- elif len(self.report_list[2]) == 2:
- self.report_html = self.report_list[0] % \
- ("memory:img_fit0.png",
- "memory:img_fit1.png")
- # allows up to three images
- else:
- self.report_html = self.report_list[0] % \
- ("memory:img_fit0.png",
- "memory:img_fit1.png",
- "memory:img_fit2.png")
- else:
- self.report_html = self.report_list[0]
- # layout
- self._setup_layout()
-
- def onSave(self, event=None):
- """
- Save
- """
- #todo: complete saving fig file and as a txt file
- dlg = wx.FileDialog(self, "Choose a file",
- wildcard=self.wild_card,
- style=wx.SAVE | wx.OVERWRITE_PROMPT | wx.CHANGE_DIR)
- dlg.SetFilterIndex(0) # Set .html files to be default
-
- if dlg.ShowModal() != wx.ID_OK:
- dlg.Destroy()
- return
-
- fName = dlg.GetPath()
- ext_num = dlg.GetFilterIndex()
-
- #set file extensions
- img_ext = []
- pic_fname = []
- #PDF
- if ext_num == (0 + 2 * self.index_offset):
- # TODO: Sort this case out
- ext = '.pdf'
-
- fName = os.path.splitext(fName)[0] + ext
- dlg.Destroy()
- #pic (png) file path/name
- for num in range(self.nimages):
- im_ext = '_img%s.png' % num
- #img_ext.append(im_ext)
- pic_name = os.path.splitext(fName)[0] + im_ext
- pic_fname.append(pic_name)
- # save the image for use with pdf writer
- self.report_list[2][num].savefig(pic_name)
-
- #put the image path in html string
- report_frame = self.report_list[0]
- #put image name strings into the html file
- #Note:The str for pic_fname shouldn't be removed.
- if self.nimages == 1:
- html = report_frame % str(pic_fname[0])
- elif self.nimages == 2:
- html = report_frame % (str(pic_fname[0]), str(pic_fname[1]))
- elif self.nimages == 3:
- html = report_frame % (str(pic_fname[0]), str(pic_fname[1]),
- str(pic_fname[2]))
-
- # make/open file in case of absence
- f = open(fName, 'w')
- f.close()
- # write pdf as a pdf file
- pdf = self.HTML2PDF(data=html, filename=fName)
-
- #open pdf
- if pdf:
- try:
- #Windows
- os.startfile(str(fName))
- except:
- try:
- #Mac
- os.system("open %s" % fName)
- except:
- #DO not open
- pass
- #delete image file
- for num in range(self.nimages):
- os.remove(pic_fname[num])
- return
- #HTML + png(graph)
- elif ext_num == (1 - self.index_offset):
- ext = '.html'
- for num in range(self.nimages):
- img_ext.append('_img4html%s.png' % num)
- report_frame = self.report_list[0]
- #TEXT + pdf(graph)
- elif ext_num == (2 - self.index_offset):
- ext = '.txt'
- # changing the image extension actually changes the image
- # format on saving
- for num in range(self.nimages):
- img_ext.append('_img4txt%s.pdf' % num)
- report = self.report_list[1]
- else:
- return
-
- #file name
- fName = os.path.splitext(fName)[0] + ext
- dlg.Destroy()
-
- #pic (png) file path/name
- for num in range(self.nimages):
- pic_name = os.path.splitext(fName)[0] + img_ext[num]
- pic_fname.append(pic_name)
- #put the image path in html string
- if ext_num == (1 - self.index_offset):
- if self.nimages == 1:
- report = report_frame % os.path.basename(pic_fname[0])
- elif self.nimages == 2:
- report = report_frame % (os.path.basename(pic_fname[0]),
- os.path.basename(pic_fname[1]))
- elif self.nimages == 3:
- report = report_frame % (os.path.basename(pic_fname[0]),
- os.path.basename(pic_fname[1]),
- os.path.basename(pic_fname[2]))
- f = open(fName, 'w')
- f.write(report)
- f.close()
- self.Update()
- #save png file using pic_fname
- for num in range(self.nimages):
- self.report_list[2][num].savefig(pic_fname[num])
+"""
+Dialog report panel to show and summarize the results of
+the fitting calculation.
+"""
+################################################################################
+#This software was developed by the University of Tennessee as part of the
+#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
+#project funded by the US National Science Foundation.
+#
+#See the license text in license.txt
+#
+#copyright 2009, University of Tennessee
+################################################################################
+
+import wx
+import os
+import wx.html as html
+
+from sas.sasgui.guiframe.report_dialog import BaseReportDialog
+
+class ReportDialog(BaseReportDialog):
+ """
+ The report dialog box.
+ """
+
+ def __init__(self, report_list, *args, **kwds):
+ """
+ Initialization. The parameters added to Dialog are:
+
+ :param report_list: list of html_str, text_str, image
+ from invariant_state
+ """
+ super(ReportDialog, self).__init__(report_list, *args, **kwds)
+
+ # title
+ self.SetTitle("Report: Fitting")
+
+ # number of images of plot
+ self.nimages = len(self.report_list[2])
+ self.report_html = self.report_list[0]
+ # layout
+ self._setup_layout()
+
+ def onSave(self, event=None):
+ """
+ Save
+ """
+ #todo: complete saving fig file and as a txt file
+ dlg = wx.FileDialog(self, "Choose a file",
+ wildcard=self.wild_card,
+ style=wx.SAVE | wx.OVERWRITE_PROMPT | wx.CHANGE_DIR)
+ dlg.SetFilterIndex(0) # Set .html files to be default
+
+ if dlg.ShowModal() != wx.ID_OK:
+ dlg.Destroy()
+ return
+
+ fName = dlg.GetPath()
+ basename = os.path.splitext(fName)[0]
+ ext_num = dlg.GetFilterIndex()
+ dlg.Destroy()
+
+ if ext_num == 0 and self.index_offset == 0: # has pdf
+ ext = ".pdf"
+ elif ext_num == 1 - self.index_offset:
+ ext = ".html"
+ elif ext_num == 2 - self.index_offset:
+ ext = ".txt"
+ else:
+ logger.warn("unknown export format in report dialog")
+ return
+ filename = basename + ext
+
+ # save figures
+ pictures = []
+ for num in range(self.nimages):
+ pic_name = basename + '_img%s.png' % num
+ # save the image for use with pdf writer
+ self.report_list[2][num].savefig(pic_name)
+ pictures.append(pic_name)
+
+ # translate png references int html from in-memory name to on-disk name
+ html = self.report_html.replace("memory:img_fit", basename+'_img')
+
+ #set file extensions
+ img_ext = []
+ if ext == ".pdf":
+ # write pdf as a pdf file
+ pdf = self.HTML2PDF(data=html, filename=filename)
+
+ # delete images used to create the pdf
+ for pic_name in pictures:
+ os.remove(pic_name)
+
+ #open pdf viewer
+ if pdf:
+ try:
+ if os.name == 'nt': # Windows
+ os.startfile(fName)
+ elif sys.platform == "darwin": # Mac
+ os.system("open %s" % fName)
+ except Exception as exc:
+ # cannot open pdf
+ logging.error(str(exc))
+
+ elif ext == ".html":
+ with open(filename, 'w') as f:
+ f.write(html)
+
+ elif ext == ".txt":
+ with open(filename, 'w') as f:
+ f.write(self.report_list[1])
+
+ self.Update()
diff --git a/src/sas/sasgui/perspectives/fitting/resultpanel.py b/src/sas/sasgui/perspectives/fitting/resultpanel.py
index b7c1524..2ed83bf 100644
--- a/src/sas/sasgui/perspectives/fitting/resultpanel.py
+++ b/src/sas/sasgui/perspectives/fitting/resultpanel.py
@@ -1,99 +1,99 @@
-"""
-FitPanel class contains fields allowing to fit models and data
-
-:note: For Fit to be performed the user should check at least one parameter
- on fit Panel window.
-
-"""
-import wx
-import wx.lib.newevent
-from wx.aui import AuiNotebook as Notebook
-
-import datetime
-
-from bumps.gui.convergence_view import ConvergenceView
-from bumps.gui.uncertainty_view import UncertaintyView, CorrelationView, TraceView
-from bumps.dream.stats import var_stats, format_vars
-
-from sas.sasgui.guiframe.panel_base import PanelBase
-from sas.sasgui.guiframe.events import StatusEvent
-
-(PlotResultEvent, EVT_PLOT_RESULT) = wx.lib.newevent.NewEvent()
-
-
-class ResultPanel(Notebook, PanelBase):
- """
- FitPanel class contains fields allowing to fit models and data
-
- :note: For Fit to be performed the user should check at least one parameter
- on fit Panel window.
-
- """
- ## Internal name for the AUI manager
- window_name = "Result panel"
- ## Title to appear on top of the window
- window_caption = "Result Panel"
- CENTER_PANE = True
-
- def __init__(self, parent, manager=None, *args, **kwargs):
- """
- """
- style = ((wx.aui.AUI_NB_WINDOWLIST_BUTTON
- | wx.aui.AUI_NB_DEFAULT_STYLE
- | wx.CLIP_CHILDREN)
- & ~wx.aui.AUI_NB_CLOSE_ON_ACTIVE_TAB)
- Notebook.__init__(self, parent, wx.ID_ANY, style=style)
- PanelBase.__init__(self, parent)
- self.frame = parent
- self.Bind(EVT_PLOT_RESULT, self.on_plot_results)
- self.frame.Bind(wx.EVT_CLOSE, self.on_close)
- self._manager = None
-
- def on_close(self, event):
- if event.CanVeto():
- self.frame.Hide()
- event.Veto()
- else:
- event.Skip()
-
- def on_plot_results(self, event):
- self.frame.Show(True)
- result = event.result[0][0]
- filename = result.data.sas_data.filename
- current_time = datetime.datetime.now().strftime("%I:%M%p, %B %d, %Y")
- self.parent.SetTitle(self.window_name + " - " + filename + " - " + current_time)
- if hasattr(result, 'convergence'):
- best, pop = result.convergence[:, 0], result.convergence[:, 1:]
- self._get_view(ConvergenceView).update(best, pop)
- else:
- self._del_view(ConvergenceView)
- if hasattr(result, 'uncertainty_state'):
- stats = var_stats(result.uncertainty_state.draw())
- msg = format_vars(stats)
- self._get_view(CorrelationView).update(result.uncertainty_state)
- self._get_view(UncertaintyView).update((result.uncertainty_state, stats))
- self._get_view(TraceView).update(result.uncertainty_state)
- # TODO: stats should be stored in result rather than computed in bumps UncertaintyView
- wx.PostEvent(self.frame.parent,
- StatusEvent(status=msg, info="info"))
- else:
- for view in (CorrelationView, UncertaintyView, TraceView):
- self._del_view(view)
-
- def get_frame(self):
- return self.frame
-
- def _get_view(self, view_class):
- for idx in range(self.PageCount):
- if self.GetPageText(idx) == view_class.title:
- return self.GetPage(idx)
- else:
- panel = view_class(self)
- self.AddPage(panel, panel.title)
- return panel
-
- def _del_view(self, view_class):
- for idx in range(self.PageCount):
- if self.GetPageText(idx) == view_class.title:
- self.DeletePage(idx)
-
+"""
+FitPanel class contains fields allowing to fit models and data
+
+:note: For Fit to be performed the user should check at least one parameter
+ on fit Panel window.
+
+"""
+import wx
+import wx.lib.newevent
+from wx.aui import AuiNotebook as Notebook
+
+import datetime
+
+from bumps.gui.convergence_view import ConvergenceView
+from bumps.gui.uncertainty_view import UncertaintyView, CorrelationView, TraceView
+from bumps.dream.stats import var_stats, format_vars
+
+from sas.sasgui.guiframe.panel_base import PanelBase
+from sas.sasgui.guiframe.events import StatusEvent
+
+(PlotResultEvent, EVT_PLOT_RESULT) = wx.lib.newevent.NewEvent()
+
+
+class ResultPanel(Notebook, PanelBase):
+ """
+ FitPanel class contains fields allowing to fit models and data
+
+ :note: For Fit to be performed the user should check at least one parameter
+ on fit Panel window.
+
+ """
+ ## Internal name for the AUI manager
+ window_name = "Result panel"
+ ## Title to appear on top of the window
+ window_caption = "Result Panel"
+ CENTER_PANE = True
+
+ def __init__(self, parent, manager=None, *args, **kwargs):
+ """
+ """
+ style = ((wx.aui.AUI_NB_WINDOWLIST_BUTTON
+ | wx.aui.AUI_NB_DEFAULT_STYLE
+ | wx.CLIP_CHILDREN)
+ & ~wx.aui.AUI_NB_CLOSE_ON_ACTIVE_TAB)
+ Notebook.__init__(self, parent, wx.ID_ANY, style=style)
+ PanelBase.__init__(self, parent)
+ self.frame = parent
+ self.Bind(EVT_PLOT_RESULT, self.on_plot_results)
+ self.frame.Bind(wx.EVT_CLOSE, self.on_close)
+ self._manager = None
+
+ def on_close(self, event):
+ if event.CanVeto():
+ self.frame.Hide()
+ event.Veto()
+ else:
+ event.Skip()
+
+ def on_plot_results(self, event):
+ self.frame.Show(True)
+ result = event.result[0][0]
+ filename = result.data.sas_data.filename
+ current_time = datetime.datetime.now().strftime("%I:%M%p, %B %d, %Y")
+ self.parent.SetTitle(self.window_name + " - " + filename + " - " + current_time)
+ if hasattr(result, 'convergence'):
+ best, pop = result.convergence[:, 0], result.convergence[:, 1:]
+ self._get_view(ConvergenceView).update(best, pop)
+ else:
+ self._del_view(ConvergenceView)
+ if hasattr(result, 'uncertainty_state'):
+ stats = var_stats(result.uncertainty_state.draw())
+ msg = format_vars(stats)
+ self._get_view(CorrelationView).update(result.uncertainty_state)
+ self._get_view(UncertaintyView).update((result.uncertainty_state, stats))
+ self._get_view(TraceView).update(result.uncertainty_state)
+ # TODO: stats should be stored in result rather than computed in bumps UncertaintyView
+ wx.PostEvent(self.frame.parent,
+ StatusEvent(status=msg, info="info"))
+ else:
+ for view in (CorrelationView, UncertaintyView, TraceView):
+ self._del_view(view)
+
+ def get_frame(self):
+ return self.frame
+
+ def _get_view(self, view_class):
+ for idx in range(self.PageCount):
+ if self.GetPageText(idx) == view_class.title:
+ return self.GetPage(idx)
+ else:
+ panel = view_class(self)
+ self.AddPage(panel, panel.title)
+ return panel
+
+ def _del_view(self, view_class):
+ for idx in range(self.PageCount):
+ if self.GetPageText(idx) == view_class.title:
+ self.DeletePage(idx)
+
diff --git a/src/sas/sasgui/perspectives/fitting/simfitpage.py b/src/sas/sasgui/perspectives/fitting/simfitpage.py
index ed4868a..0108fc3 100644
--- a/src/sas/sasgui/perspectives/fitting/simfitpage.py
+++ b/src/sas/sasgui/perspectives/fitting/simfitpage.py
@@ -1,1101 +1,1105 @@
-"""
- Simultaneous fit page
-"""
-import sys
-from collections import namedtuple
-
-import wx
-import wx.lib.newevent
-from wx.lib.scrolledpanel import ScrolledPanel
-
-from sas.sasgui.guiframe.events import StatusEvent, PanelOnFocusEvent
-from sas.sasgui.guiframe.panel_base import PanelBase
-from sas.sasgui.guiframe.utils import IdList
-from sas.sasgui.guiframe.documentation_window import DocumentationWindow
-
-# Control panel width
-if sys.platform.count("darwin") == 0:
- PANEL_WID = 420
- FONT_VARIANT = 0
-else:
- PANEL_WID = 490
- FONT_VARIANT = 1
-
-
-# Each constraint requires five widgets and sizer. Package them in
-# a named tuple for easy access.
-ConstraintLine = namedtuple('ConstraintLine',
- 'model_cbox param_cbox egal_txt constraint btRemove sizer')
-
-
-def get_fittableParam(model):
- """
- return list of fittable parameters from a model
-
- :param model: the model used
-
- """
- fittable_param = []
- for item in model.getParamList():
- if not item in model.getDispParamList():
- if not item in model.non_fittable:
- fittable_param.append(item)
-
- for item in model.fixed:
- fittable_param.append(item)
-
- return fittable_param
-
-
-class SimultaneousFitPage(ScrolledPanel, PanelBase):
- """
- Simultaneous fitting panel
- All that needs to be defined are the
- two data members window_name and window_caption
- """
- # Internal name for the AUI manager
- window_name = "Simultaneous Fit Page"
- # Title to appear on top of the window
- window_caption = "Simultaneous Fit Page"
- ID_DOC = wx.NewId()
- ID_SET_ALL = wx.NewId()
- ID_FIT = wx.NewId()
- ID_ADD = wx.NewId()
- _id_pool = IdList()
-
- def __init__(self, parent, page_finder={}, id=wx.ID_ANY, batch_on=False,
- *args, **kwargs):
- ScrolledPanel.__init__(self, parent, id=id,
- style=wx.FULL_REPAINT_ON_RESIZE,
- *args, **kwargs)
- PanelBase.__init__(self, parent)
- """
- Simultaneous page display
- """
- self._ids = iter(self._id_pool)
- self.SetupScrolling()
- # Font size
- self.SetWindowVariant(variant=FONT_VARIANT)
- self.uid = wx.NewId()
- self.parent = parent
- self.batch_on = batch_on
- # store page_finder
- self.page_finder = page_finder
- # list containing info to set constraint
- # look like self.constraint_dict[page_id]= page
- self.constraint_dict = {}
- # item list
- # self.constraints_list=[combobox1, combobox2,=,textcrtl, button ]
- self.constraints_list = []
- # list of current model
- self.model_list = []
- # selected model to fit
- self.model_to_fit = []
- # Control the fit state
- self.fit_started = False
- # number of constraint
- self.nb_constraint = 0
- self.state = SimFitPageState()
- self.model_cbox_left = None
- self.model_cbox_right = None
- # draw page
- self.define_page_structure()
- self.draw_page()
- self._set_save_flag(False)
-
- def define_page_structure(self):
- """
- Create empty sizers, their hierarchy and set the sizer for the panel
- """
- self.vbox = wx.BoxSizer(wx.VERTICAL)
- self.data_selection_sizer = wx.BoxSizer(wx.VERTICAL)
- self.constraints_sizer = wx.BoxSizer(wx.VERTICAL)
- self.run_fit_sizer = wx.BoxSizer(wx.VERTICAL)
-
- self.data_selection_sizer.SetMinSize((PANEL_WID, -1))
- self.constraints_sizer.SetMinSize((PANEL_WID, -1))
- self.run_fit_sizer.SetMinSize((PANEL_WID, -1))
- self.vbox.Add(self.data_selection_sizer)
- self.vbox.Add(self.constraints_sizer)
- self.vbox.Add(self.run_fit_sizer)
- self.SetSizer(self.vbox)
- self.Centre()
-
- def set_state(self):
- """
- Define a set of state parameters for saving simultaneous fits.
- """
- self._set_constraint()
- self.state.fit_page_no = self.uid
- self.state.select_all = self.cb1.GetValue()
- self.state.model_list = self.model_list
- self.state.model_to_fit = self.model_to_fit
- self.state.no_constraint = self.nb_constraint
- self.state.constraint_dict = self.constraint_dict
- self.state.constraints_list = self.constraints_list
- return self.get_state()
-
- def get_state(self):
- """
- Return the state of the current page
- :return: self.state
- """
- return self.state
-
- def draw_page(self):
- """
- Construct the Simultaneous/Constrained fit page. fills the first
- region (sizer1) with the list of available fit page pairs of data
- and models. Then fills sizer2 with the checkbox for adding
- constraints, and finally fills sizer3 with the fit button and
- instructions.
- """
-
- # create blank list of constraints
- self.model_list = []
- self.model_to_fit = []
- self.constraints_list = []
- self.constraint_dict = {}
- self.nb_constraint = 0
- self.model_cbox_left = None
- self.model_cbox_right = None
-
- if len(self.model_list) > 0:
- for item in self.model_list:
- item[0].SetValue(False)
- self.manager.schedule_for_fit(value=0, uid=item[2])
-
- #-------------------------------------------------------
- # setup sizer1 (which fitpages to include)
- self.data_selection_sizer.Clear(True)
- box_description = wx.StaticBox(self, wx.ID_ANY, "Fit Combinations")
- boxsizer1 = wx.StaticBoxSizer(box_description, wx.VERTICAL)
- sizer_title = wx.BoxSizer(wx.HORIZONTAL)
- sizer_couples = wx.GridBagSizer(5, 5)
-
- # The wx GUI has a flag to enable a menu item, but can still be
- # reached via scripting. There is no guearantee future GUI
- # implementations force this check, either.
- # IMHO, this if statement should stay -- JRK 2016-OCT-05
- if len(self.page_finder) == 0:
- msg = " No fit combinations are found! \n\n"
- msg += " Please load data and set up "
- msg += "at least one fit panels first..."
- sizer_title.Add(wx.StaticText(self, wx.ID_ANY, msg))
- else:
- # store model
- self._store_model()
-
- self.cb1 = wx.CheckBox(self, wx.ID_ANY, 'Select all')
- self.cb1.SetValue(False)
- wx.EVT_CHECKBOX(self, self.cb1.GetId(), self.check_all_model_name)
-
- sizer_title.Add((10, 10), 0,
- wx.TOP | wx.BOTTOM | wx.EXPAND | wx.ADJUST_MINSIZE, border=5)
- sizer_title.Add(self.cb1, 0,
- wx.TOP | wx.BOTTOM | wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE,
- border=5)
-
- # draw list of model and data names
- self._fill_sizer_model_list(sizer_couples)
-
- boxsizer1.Add(sizer_title, flag=wx.TOP | wx.BOTTOM, border=5)
- boxsizer1.Add(sizer_couples, 1, flag=wx.TOP | wx.BOTTOM, border=5)
- self.data_selection_sizer.Add(boxsizer1, 1, wx.EXPAND | wx.ALL, 10)
- # self.sizer1.Layout()
-
- #--------------------------------------------------------
- # set up the other 2 sizers: the constraints list and the
- # buttons (fit, help etc) sizer at the bottom of the page.
- # Note: the if statement should be removed along with the above
- # if statement as soon as it can be properly tested.
- # Nov. 22 2015 --PDB
- # As above, this page can be accessed through other means than the
- # base SasView GUI.
- # Oct. 5, 2016 --JRK
- if len(self.page_finder) > 0:
- # draw the sizer containing constraint info
- if not self.batch_on:
- self._fill_sizer_constraint()
- # draw fit button sizer
- self._fill_sizer_fit()
-
- def _fill_sizer_model_list(self, sizer):
- """
- Receive a dictionary containing information to display model name
- """
- ix = 0
- iy = 0
- sizer.Clear(True)
-
- new_name = wx.StaticText(self, wx.ID_ANY, ' Model Title ',
- style=wx.ALIGN_CENTER)
- new_name.SetBackgroundColour('orange')
- new_name.SetForegroundColour(wx.WHITE)
- sizer.Add(new_name, (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- ix += 2
- model_type = wx.StaticText(self, wx.ID_ANY, ' Model ')
- model_type.SetBackgroundColour('grey')
- model_type.SetForegroundColour(wx.WHITE)
- sizer.Add(model_type, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 1
- data_used = wx.StaticText(self, wx.ID_ANY, ' Data ')
- data_used.SetBackgroundColour('grey')
- data_used.SetForegroundColour(wx.WHITE)
- sizer.Add(data_used, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 1
- tab_used = wx.StaticText(self, wx.ID_ANY, ' FitPage ')
- tab_used.SetBackgroundColour('grey')
- tab_used.SetForegroundColour(wx.WHITE)
- sizer.Add(tab_used, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- for id, value in self.page_finder.iteritems():
- if id not in self.parent.opened_pages:
- continue
-
- if self.batch_on != self.parent.get_page_by_id(id).batch_on:
- continue
-
- data_list = []
- model_list = []
- # get data name and model objetta
- for fitproblem in value.get_fit_problem():
-
- data = fitproblem.get_fit_data()
- if not data.is_data:
- continue
- name = '-'
- if data is not None and data.is_data:
- name = str(data.name)
- data_list.append(name)
-
- model = fitproblem.get_model()
- if model is None:
- continue
- model_list.append(model)
-
- if len(model_list) == 0:
- continue
- # Draw sizer
- ix = 0
- iy += 1
- model = model_list[0]
- name = '_'
- if model is not None:
- name = str(model.name)
- cb = wx.CheckBox(self, wx.ID_ANY, name)
- cb.SetValue(False)
- cb.Enable(model is not None and data.is_data)
- sizer.Add(cb, (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- wx.EVT_CHECKBOX(self, cb.GetId(), self.check_model_name)
- ix += 2
- model_type = wx.StaticText(self, wx.ID_ANY,
- model.__class__.__name__)
- sizer.Add(model_type, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- if self.batch_on:
- data_used = wx.ComboBox(self, wx.ID_ANY, style=wx.CB_READONLY)
- data_used.AppendItems(data_list)
- data_used.SetSelection(0)
- else:
- data_used = wx.StaticText(self, wx.ID_ANY, data_list[0])
-
- ix += 1
- sizer.Add(data_used, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 1
- caption = value.get_fit_tab_caption()
- tab_caption_used = wx.StaticText(self, wx.ID_ANY, str(caption))
- sizer.Add(tab_caption_used, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
-
- self.model_list.append([cb, value, id, model])
-
- iy += 1
- sizer.Add((20, 20), (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
-
- def _fill_sizer_constraint(self):
- """
- Fill sizer containing constraint info
- """
- msg = "Select at least 1 model to add constraint "
- wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
-
- self.constraints_sizer.Clear(True)
- if self.batch_on:
- if self.constraints_sizer.IsShown():
- self.constraints_sizer.Show(False)
- return
- box_description = wx.StaticBox(self, wx.ID_ANY, "Fit Constraints")
- box_sizer1 = wx.StaticBoxSizer(box_description, wx.VERTICAL)
- sizer_title = wx.BoxSizer(wx.HORIZONTAL)
- self.sizer_all_constraints = wx.BoxSizer(wx.HORIZONTAL)
- self.sizer_constraints = wx.BoxSizer(wx.VERTICAL)
- sizer_button = wx.BoxSizer(wx.HORIZONTAL)
-
- self.hide_constraint = wx.RadioButton(self, wx.ID_ANY, 'No', (10, 10),
- style=wx.RB_GROUP)
- self.show_constraint = wx.RadioButton(self, wx.ID_ANY, 'Yes', (10, 30))
- self.Bind(wx.EVT_RADIOBUTTON, self._display_constraint,
- id=self.hide_constraint.GetId())
- self.Bind(wx.EVT_RADIOBUTTON, self._display_constraint,
- id=self.show_constraint.GetId())
- if self.batch_on:
- self.hide_constraint.Enable(False)
- self.show_constraint.Enable(False)
- self.hide_constraint.SetValue(True)
- self.show_constraint.SetValue(False)
-
- sizer_title.Add(wx.StaticText(self, wx.ID_ANY, " Model"))
- sizer_title.Add((10, 10))
- sizer_title.Add(wx.StaticText(self, wx.ID_ANY, " Parameter"))
- sizer_title.Add((10, 10))
- sizer_title.Add(wx.StaticText(self, wx.ID_ANY, " Add Constraint?"))
- sizer_title.Add((10, 10))
- sizer_title.Add(self.show_constraint)
- sizer_title.Add(self.hide_constraint)
- sizer_title.Add((10, 10))
-
- self.btAdd = wx.Button(self, self.ID_ADD, 'Add')
- self.btAdd.Bind(wx.EVT_BUTTON, self._on_add_constraint,
- id=self.btAdd.GetId())
- self.btAdd.SetToolTipString("Add another constraint?")
- self.btAdd.Hide()
-
- text_hint = wx.StaticText(self, wx.ID_ANY,
- "Example: [M0][parameter] = M1.parameter")
- sizer_button.Add(text_hint, 0,
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 10)
- sizer_button.Add(self.btAdd, 0,
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 10)
-
- box_sizer1.Add(sizer_title, flag=wx.TOP | wx.BOTTOM, border=10)
- box_sizer1.Add(self.sizer_all_constraints, flag=wx.TOP | wx.BOTTOM,
- border=10)
- box_sizer1.Add(self.sizer_constraints, flag=wx.TOP | wx.BOTTOM,
- border=10)
- box_sizer1.Add(sizer_button, flag=wx.TOP | wx.BOTTOM, border=10)
-
- self.constraints_sizer.Add(box_sizer1, 0, wx.EXPAND | wx.ALL, 10)
-
- def _fill_sizer_fit(self):
- """
- Draw fit button
- """
- self.run_fit_sizer.Clear(True)
- box_description = wx.StaticBox(self, wx.ID_ANY, "Fit ")
- boxsizer1 = wx.StaticBoxSizer(box_description, wx.VERTICAL)
- sizer_button = wx.BoxSizer(wx.HORIZONTAL)
-
- # Fit button
- self.btFit = wx.Button(self, self.ID_FIT, 'Fit', size=wx.DefaultSize)
- self.btFit.Bind(wx.EVT_BUTTON, self.on_fit, id=self.btFit.GetId())
- self.btFit.SetToolTipString("Perform fit.")
-
- # General Help button
- self.btHelp = wx.Button(self, wx.ID_HELP, 'HELP')
- self.btHelp.SetToolTipString("Simultaneous/Constrained Fitting help.")
- self.btHelp.Bind(wx.EVT_BUTTON, self._on_help)
-
- # hint text on button line
- if self.batch_on:
- text = " Fit in Parallel all Data sets\n"
- text += "and model selected."
- else:
- text = " At least one set of model and data\n"
- text += " must be selected for fitting."
- text_hint = wx.StaticText(self, wx.ID_ANY, text)
-
- sizer_button.Add(text_hint)
- sizer_button.Add(self.btFit, 0, wx.LEFT | wx.ADJUST_MINSIZE, 10)
- sizer_button.Add(self.btHelp, 0, wx.LEFT | wx.ADJUST_MINSIZE, 10)
-
- boxsizer1.Add(sizer_button, flag=wx.TOP | wx.BOTTOM, border=10)
- self.run_fit_sizer.Add(boxsizer1, 0, wx.EXPAND | wx.ALL, 10)
-
- def on_remove(self, event):
- """
- Remove constraint fields
- """
- if len(self.constraints_list) == 1:
- self.hide_constraint.SetValue(True)
- self._hide_constraint()
- return
- if len(self.constraints_list) == 0:
- return
- wx.CallAfter(self._remove_after, event.GetId())
- # self._onAdd_constraint(None)
-
- def _remove_after(self, id):
- for item in self.constraints_list:
- if id == item.btRemove.GetId():
- self.sizer_constraints.Hide(item.sizer)
- item.sizer.Clear(True)
- self.sizer_constraints.Remove(item.sizer)
- self.constraints_list.remove(item)
- self.nb_constraint -= 1
- self.constraints_sizer.Layout()
- self.FitInside()
- break
-
- def on_fit(self, event):
- """
- signal for fitting
-
- """
- if self.fit_started:
- self._stop_fit()
- self.fit_started = False
- return
-
- flag = False
- # check if the current page a simultaneous fit page or a batch page
- if self == self._manager.sim_page:
- flag = (self._manager.sim_page.uid == self.uid)
-
- # making sure all parameters content a constraint
- if not self.batch_on and self.show_constraint.GetValue():
- if not self._set_constraint():
- return
- # model was actually selected from this page to be fit
- if len(self.model_to_fit) >= 1:
- self.manager._reset_schedule_problem(value=0)
- for item in self.model_list:
- if item[0].GetValue():
- self.manager.schedule_for_fit(value=1, uid=item[2])
- try:
- self.fit_started = True
- wx.CallAfter(self.set_fitbutton)
- if not self.manager.onFit(uid=self.uid):
- return
- except:
- msg = "Select at least one parameter to fit in the FitPages."
- wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
- else:
- msg = "Select at least one model check box to fit "
- wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
- self.set_state()
-
- def _on_fit_complete(self):
- """
- Set the completion flag and display the updated fit button label.
- """
- self.fit_started = False
- self.set_fitbutton()
-
- def _stop_fit(self, event=None):
- """
- Attempt to stop the fitting thread
-
- :param event: Event handler when stop fit is clicked
- """
- if event is not None:
- event.Skip()
- self.manager.stop_fit(self.uid)
- self.manager._reset_schedule_problem(value=0)
- self._on_fit_complete()
-
- def set_fitbutton(self):
- """
- Set fit button label depending on the fit_started
- """
- label = "Stop" if self.fit_started else "Fit"
- color = "red" if self.fit_started else "black"
-
- self.btFit.SetLabel(label)
- self.btFit.SetForegroundColour(color)
- self.btFit.Enable(True)
-
- def _on_help(self, event):
- """
- Bring up the simultaneous Fitting Documentation whenever the HELP
- button is clicked.
-
- Calls DocumentationWindow with the path of the location within the
- documentation tree (after /doc/ ....". Note that when using old
- versions of Wx (before 2.9) and thus not the release version of
- installers, the help comes up at the top level of the file as
- web browser does not pass anything past the # to the browser when it is
- running "file:///...."
-
- :param event: Triggers on clicking the help button
- """
- _TreeLocation = "user/sasgui/perspectives/fitting/fitting_help.html"
- _PageAnchor = "#simultaneous-fit-mode"
- _doc_viewer = DocumentationWindow(self, self.ID_DOC, _TreeLocation,
- _PageAnchor,
- "Simultaneous/Constrained Fitting Help")
-
- def set_manager(self, manager):
- """
- set panel manager
-
- :param manager: instance of plugin fitting
- """
- self.manager = manager
-
- def check_all_model_name(self, event=None):
- """
- check all models names
- """
- self.model_to_fit = []
- if self.cb1.GetValue():
- for item in self.model_list:
- if item[0].IsEnabled():
- item[0].SetValue(True)
- self.model_to_fit.append(item)
-
- # constraint info
- self._store_model()
- if not self.batch_on:
- # display constraint fields
- if (self.show_constraint.GetValue() and
- len(self.constraints_list) == 0):
- self._show_all_constraint()
- self._show_constraint()
- else:
- for item in self.model_list:
- item[0].SetValue(False)
-
- if not self.batch_on:
- # constraint info
- self._hide_constraint()
-
- self._update_easy_setup_cb()
- self.FitInside()
-
- def check_model_name(self, event):
- """
- Save information related to checkbox and their states
- """
- self.model_to_fit = []
- for item in self.model_list:
- if item[0].GetValue():
- self.model_to_fit.append(item)
- else:
- if item in self.model_to_fit:
- self.model_to_fit.remove(item)
- self.cb1.SetValue(False)
-
- # display constraint fields
- if len(self.model_to_fit) >= 1:
- self._store_model()
- if not self.batch_on and self.show_constraint.GetValue() and\
- len(self.constraints_list) == 0:
- self._show_all_constraint()
- self._show_constraint()
-
- elif len(self.model_to_fit) < 1:
- # constraint info
- self._hide_constraint()
-
- self._update_easy_setup_cb()
- # set the value of the main check button
- if len(self.model_list) == len(self.model_to_fit):
- self.cb1.SetValue(True)
- self.FitInside()
- return
- else:
- self.cb1.SetValue(False)
- self.FitInside()
-
- def _update_easy_setup_cb(self):
- """
- Update easy setup combobox on selecting a model
- """
- if self.model_cbox_left is None or self.model_cbox_right is None:
- return
-
- models = [(item[3].name, item[3]) for item in self.model_to_fit]
- setComboBoxItems(self.model_cbox_left, models)
- setComboBoxItems(self.model_cbox_right, models)
- for item in self.constraints_list:
- setComboBoxItems(item[0], models)
- if self.model_cbox_left.GetSelection() == wx.NOT_FOUND:
- self.model_cbox_left.SetSelection(0)
- self.constraints_sizer.Layout()
-
- def _store_model(self):
- """
- Store selected model
- """
- if len(self.model_to_fit) < 1:
- return
- for item in self.model_to_fit:
- model = item[3]
- page_id = item[2]
- self.constraint_dict[page_id] = model
-
- def _display_constraint(self, event):
- """
- Show fields to add constraint
- """
- if len(self.model_to_fit) < 1:
- msg = "Select at least 1 model to add constraint "
- wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
- # hide button
- self._hide_constraint()
- return
- if self.show_constraint.GetValue():
- self._show_all_constraint()
- self._show_constraint()
- self.FitInside()
- return
- else:
- self._hide_constraint()
- return
-
- def _show_all_constraint(self):
- """
- Show constraint fields
- """
- box_description = wx.StaticBox(self, wx.ID_ANY, "Easy Setup ")
- box_sizer = wx.StaticBoxSizer(box_description, wx.HORIZONTAL)
- sizer_constraint = wx.BoxSizer(wx.HORIZONTAL)
- self.model_cbox_left = wx.ComboBox(self, wx.ID_ANY, style=wx.CB_READONLY)
- self.model_cbox_left.Clear()
- self.model_cbox_right = wx.ComboBox(self, wx.ID_ANY, style=wx.CB_READONLY)
- self.model_cbox_right.Clear()
- wx.EVT_COMBOBOX(self.model_cbox_left, wx.ID_ANY, self._on_select_modelcb)
- wx.EVT_COMBOBOX(self.model_cbox_right, wx.ID_ANY, self._on_select_modelcb)
- egal_txt = wx.StaticText(self, wx.ID_ANY, " = ")
- self.set_button = wx.Button(self, self.ID_SET_ALL, 'Set All')
- self.set_button.Bind(wx.EVT_BUTTON, self._on_set_all_equal,
- id=self.set_button.GetId())
- set_tip = "Add constraints for all the adjustable parameters "
- set_tip += "(checked in FitPages) if exist."
- self.set_button.SetToolTipString(set_tip)
- self.set_button.Disable()
-
- for id, model in self.constraint_dict.iteritems():
- # check if all parameters have been selected for constraint
- # then do not allow add constraint on parameters
- self.model_cbox_left.Append(str(model.name), model)
- self.model_cbox_left.Select(0)
- for id, model in self.constraint_dict.iteritems():
- # check if all parameters have been selected for constraint
- # then do not allow add constraint on parameters
- self.model_cbox_right.Append(str(model.name), model)
- box_sizer.Add(self.model_cbox_left,
- flag=wx.RIGHT | wx.EXPAND, border=10)
- # box_sizer.Add(wx.StaticText(self, wx.ID_ANY, ".parameters"),
- # flag=wx.RIGHT | wx.EXPAND, border=5)
- box_sizer.Add(egal_txt, flag=wx.RIGHT | wx.EXPAND, border=5)
- box_sizer.Add(self.model_cbox_right,
- flag=wx.RIGHT | wx.EXPAND, border=10)
- # box_sizer.Add(wx.StaticText(self, wx.ID_ANY, ".parameters"),
- # flag=wx.RIGHT | wx.EXPAND, border=5)
- box_sizer.Add((20, -1))
- box_sizer.Add(self.set_button, flag=wx.RIGHT | wx.EXPAND, border=5)
- sizer_constraint.Add(box_sizer, flag=wx.RIGHT | wx.EXPAND, border=5)
- self.sizer_all_constraints.Insert(before=0,
- item=sizer_constraint,
- flag=wx.TOP | wx.BOTTOM | wx.EXPAND, border=5)
- self.FitInside()
-
- def _on_select_modelcb(self, event):
- """
- On select model left or right combobox
- """
- event.Skip()
- flag = True
- if self.model_cbox_left.GetValue().strip() == '':
- flag = False
- if self.model_cbox_right.GetValue().strip() == '':
- flag = False
- if (self.model_cbox_left.GetValue() ==
- self.model_cbox_right.GetValue()):
- flag = False
- self.set_button.Enable(flag)
-
- def _on_set_all_equal(self, event):
- """
- On set button
- """
- event.Skip()
- length = len(self.constraints_list)
- if length < 1:
- return
- param_list = []
- param_list_b = []
- selection = self.model_cbox_left.GetCurrentSelection()
- model_left = self.model_cbox_left.GetValue()
- model = self.model_cbox_left.GetClientData(selection)
- selection_b = self.model_cbox_right.GetCurrentSelection()
- model_right = self.model_cbox_right.GetValue()
- model_b = self.model_cbox_right.GetClientData(selection_b)
- for id, dic_model in self.constraint_dict.iteritems():
- if model == dic_model:
- param_list = self.page_finder[id].get_param2fit()
- if model_b == dic_model:
- param_list_b = self.page_finder[id].get_param2fit()
- if len(param_list) > 0 and len(param_list_b) > 0:
- break
- num_cbox = 0
- has_param = False
- for param in param_list:
- num_cbox += 1
- if param in param_list_b:
- item = self.constraints_list[-1]
- item.model_cbox.SetStringSelection(model_left)
- self._on_select_model(None)
- item.param_cbox.Clear()
- item.param_cbox.Append(str(param), model)
- item.param_cbox.SetStringSelection(str(param))
- item.constraint.SetValue(str(model_right + "." + str(param)))
- has_param = True
- if num_cbox == (len(param_list) + 1):
- break
- self._show_constraint()
-
- self.FitInside()
- if not has_param:
- msg = " There is no adjustable parameter (checked to fit)"
- msg += " either one of the models."
- wx.PostEvent(self.parent.parent, StatusEvent(info="warning",
- status=msg))
- else:
- msg = " The constraints are added."
- wx.PostEvent(self.parent.parent, StatusEvent(info="info",
- status=msg))
-
- def _show_constraint(self):
- """
- Show constraint fields
- :param dict: dictionary mapping constraint values
- """
- self.btAdd.Show(True)
- if len(self.constraints_list) != 0:
- nb_fit_param = 0
- for id, model in self.constraint_dict.iteritems():
- nb_fit_param += len(self.page_finder[id].get_param2fit())
- # Don't add anymore
- if len(self.constraints_list) == nb_fit_param:
- msg = "Cannot add another constraint. Maximum of number "
- msg += "Parameters name reached %s" % str(nb_fit_param)
- wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
- self.sizer_constraints.Layout()
- self.constraints_sizer.Layout()
- return
- if len(self.model_to_fit) < 1:
- msg = "Select at least 1 model to add constraint "
- wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
- self.sizer_constraints.Layout()
- self.constraints_sizer.Layout()
- return
-
- sizer_constraint = wx.BoxSizer(wx.HORIZONTAL)
-
- # Model list
- model_cbox = wx.ComboBox(self, wx.ID_ANY, style=wx.CB_READONLY)
- model_cbox.Clear()
- for id, model in self.constraint_dict.iteritems():
- # check if all parameters have been selected for constraint
- # then do not allow add constraint on parameters
- model_cbox.Append(str(model.name), model)
- wx.EVT_COMBOBOX(model_cbox, wx.ID_ANY, self._on_select_model)
-
- # Parameters in model
- param_cbox = wx.ComboBox(self, wx.ID_ANY, style=wx.CB_READONLY,
- size=(100, -1))
- param_cbox.Hide()
- wx.EVT_COMBOBOX(param_cbox, wx.ID_ANY, self._on_select_param)
-
- egal_txt = wx.StaticText(self, wx.ID_ANY, " = ")
-
- # Parameter constraint
- constraint = wx.TextCtrl(self, wx.ID_ANY)
-
- # Remove button
- #btRemove = wx.Button(self, self.ID_REMOVE, 'Remove')
- bt_remove = wx.Button(self, self._ids.next(), 'Remove')
- bt_remove.Bind(wx.EVT_BUTTON, self.on_remove,
- id=bt_remove.GetId())
- bt_remove.SetToolTipString("Remove constraint.")
- bt_remove.Hide()
-
- # Hid the add button, if it exists
- if hasattr(self, "btAdd"):
- self.btAdd.Hide()
-
- sizer_constraint.Add((5, -1))
- sizer_constraint.Add(model_cbox, flag=wx.RIGHT | wx.EXPAND, border=10)
- sizer_constraint.Add(param_cbox, flag=wx.RIGHT | wx.EXPAND, border=5)
- sizer_constraint.Add(egal_txt, flag=wx.RIGHT | wx.EXPAND, border=5)
- sizer_constraint.Add(constraint, flag=wx.RIGHT | wx.EXPAND, border=10)
- sizer_constraint.Add(bt_remove, flag=wx.RIGHT | wx.EXPAND, border=10)
-
- self.sizer_constraints.Insert(before=self.nb_constraint,
- item=sizer_constraint, flag=wx.TOP | wx.BOTTOM | wx.EXPAND,
- border=5)
- c = ConstraintLine(model_cbox, param_cbox, egal_txt,
- constraint, bt_remove, sizer_constraint)
- self.constraints_list.append(c)
-
- self.nb_constraint += 1
- self.sizer_constraints.Layout()
- self.constraints_sizer.Layout()
- self.Layout()
-
- def _hide_constraint(self):
- """
- hide buttons related constraint
- """
- for id in self.page_finder.iterkeys():
- self.page_finder[id].clear_model_param()
-
- self.nb_constraint = 0
- self.constraint_dict = {}
- if hasattr(self, "btAdd"):
- self.btAdd.Hide()
- self._store_model()
- if self.model_cbox_left is not None:
- self.model_cbox_left.Clear()
- self.model_cbox_left = None
- if self.model_cbox_right is not None:
- self.model_cbox_right.Clear()
- self.model_cbox_right = None
- self.constraints_list = []
- self.sizer_all_constraints.Clear(True)
- self.sizer_all_constraints.Layout()
- self.sizer_constraints.Clear(True)
- self.sizer_constraints.Layout()
- self.constraints_sizer.Layout()
- self.Layout()
- self.FitInside()
-
- def _on_select_model(self, event):
- """
- fill combo box with list of parameters
- """
- if not self.constraints_list:
- return
-
- # This way PC/MAC both work, instead of using event.GetClientData().
- model_cbox = self.constraints_list[-1].model_cbox
- n = model_cbox.GetCurrentSelection()
- if n == wx.NOT_FOUND:
- return
-
- model = model_cbox.GetClientData(n)
- param_list = []
- for id, dic_model in self.constraint_dict.iteritems():
- if model == dic_model:
- param_list = self.page_finder[id].get_param2fit()
- break
-
- param_cbox = self.constraints_list[-1].param_cbox
- param_cbox.Clear()
- # insert only fittable paramaters
- for param in param_list:
- param_cbox.Append(str(param), model)
- param_cbox.Show(True)
-
- bt_remove = self.constraints_list[-1].btRemove
- bt_remove.Show(True)
- self.btAdd.Show(True)
-# self.Layout()
- self.FitInside()
-
- def _on_select_param(self, event):
- """
- Store the appropriate constraint in the page_finder
- """
- # This way PC/MAC both work, instead of using event.GetClientData().
- # n = self.param_cbox.GetCurrentSelection()
- # model = self.param_cbox.GetClientData(n)
- # param = event.GetString()
-
- if self.constraints_list:
- self.constraints_list[-1].egal_txt.Show(True)
- self.constraints_list[-1].constraint.Show(True)
-
- def _on_add_constraint(self, event):
- """
- Add another line for constraint
- """
- if not self.show_constraint.GetValue():
- msg = " Select Yes to add Constraint "
- wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
- return
- # check that a constraint is added
- # before allow to add another constraint
- for item in self.constraints_list:
- if item.model_cbox.GetString(0) == "":
- msg = " Select a model Name! "
- wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
- return
- if item.param_cbox.GetString(0) == "":
- msg = " Select a parameter Name! "
- wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
- return
- if item.constraint.GetValue().lstrip().rstrip() == "":
- model = item.param_cbox.GetClientData(
- item.param_cbox.GetCurrentSelection())
- if model is not None:
- msg = " Enter a constraint for %s.%s! " % (model.name,
- item.param_cbox.GetString(0))
- else:
- msg = " Enter a constraint"
- wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
- return
- # some model or parameters can be constrained
- self._show_constraint()
- self.FitInside()
-
- def _set_constraint(self):
- """
- get values from the constraint textcrtl ,parses them into model name
- parameter name and parameters values.
- store them in a list self.params .when when params is not empty
- set_model uses it to reset the appropriate model
- and its appropriates parameters
- """
- for item in self.constraints_list:
- select0 = item.model_cbox.GetSelection()
- if select0 == wx.NOT_FOUND:
- continue
- model = item.model_cbox.GetClientData(select0)
- select1 = item.param_cbox.GetSelection()
- if select1 == wx.NOT_FOUND:
- continue
- param = item.param_cbox.GetString(select1)
- constraint = item.constraint.GetValue().lstrip().rstrip()
- if param.lstrip().rstrip() == "":
- param = None
- msg = " Constraint will be ignored!. missing parameters"
- msg += " in combobox to set constraint! "
- wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
- for id, value in self.constraint_dict.iteritems():
- if model == value:
- if constraint == "":
- msg = " Constraint will be ignored!. missing value"
- msg += " in textcrtl to set constraint! "
- wx.PostEvent(self.parent.parent,
- StatusEvent(status=msg))
- constraint = None
- if str(param) in self.page_finder[id].get_param2fit():
- msg = " Checking constraint for parameter: %s ", param
- wx.PostEvent(self.parent.parent,
- StatusEvent(info="info", status=msg))
- else:
- model_name = item[0].GetLabel()
- fitpage = self.page_finder[id].get_fit_tab_caption()
- msg = "All constrainted parameters must be set "
- msg += " adjustable: '%s.%s' " % (model_name, param)
- msg += "is NOT checked in '%s'. " % fitpage
- msg += " Please check it to fit or"
- msg += " remove the line of the constraint."
- wx.PostEvent(self.parent.parent,
- StatusEvent(info="error", status=msg))
- return False
-
- for fid in self.page_finder[id].iterkeys():
- # wrap in param/constraint in str() to remove unicode
- self.page_finder[id].set_model_param(str(param),
- str(constraint), fid=fid)
- break
- return True
-
- def on_set_focus(self, event=None):
- """
- The derivative class is on focus if implemented
- """
- if self.parent is not None:
- if self.parent.parent is not None:
- wx.PostEvent(self.parent.parent, PanelOnFocusEvent(panel=self))
- self.page_finder = self.parent._manager.get_page_finder()
-
-
-def setComboBoxItems(cbox, items):
- assert isinstance(cbox, wx.ComboBox)
- selected = cbox.GetStringSelection()
- cbox.Clear()
- for k, (name, value) in enumerate(items):
- cbox.Append(name, value)
- cbox.SetStringSelection(selected)
-
-
-class SimFitPageState:
- """
- State of the simultaneous fit page for saving purposes
- """
-
- def __init__(self):
- # Sim Fit Page Number
- self.fit_page_no = None
- # Select all data
- self.select_all = False
- # Data sets sent to fit page
- self.model_list = []
- # Data sets to be fit
- self.model_to_fit = []
- # Number of constraints
- self.no_constraint = 0
- # Dictionary of constraints
- self.constraint_dict = {}
- # List of constraints
- self.constraints_list = []
-
- def load_from_save_state(self, fit):
- """
- Load in a simultaneous/constrained fit from a save state
- :param fit: Fitpanel object
- :return: None
- """
-
- model_map = {}
- if fit.fit_panel.sim_page is None:
- fit.fit_panel.add_sim_page()
- sim_page = fit.fit_panel.sim_page
-
- # Process each model and associate old M# with new M#
- i = 0
- for model in sim_page.model_list:
- model_id = self._format_id(model[1].keys()[0])
- for saved_model in self.model_list:
- save_id = saved_model.pop('name')
- saved_model['name'] = save_id
- save_id = self._format_id(save_id)
- if save_id == model_id:
- model_map[saved_model.pop('fit_page_source')] = \
- model[3].name
- check = bool(saved_model.pop('checked'))
- sim_page.model_list[i][0].SetValue(check)
- break
- i += 1
- sim_page.check_model_name(None)
-
- if len(self.constraints_list) > 0:
- sim_page.hide_constraint.SetValue(False)
- sim_page.show_constraint.SetValue(True)
- sim_page._display_constraint(None)
-
- for index, item in enumerate(self.constraints_list):
- model_cbox = item.pop('model_cbox')
- if model_cbox != "":
- constraint_value = item.pop('constraint')
- param = item.pop('param_cbox')
- equality = item.pop('egal_txt')
- for key, value in model_map.iteritems():
- model_cbox.replace(key, value)
- constraint_value.replace(key, value)
-
- sim_page.constraints_list[index][0].SetValue(model_cbox)
- sim_page._on_select_model(None)
- sim_page.constraints_list[index][1].SetValue(param)
- sim_page.constraints_list[index][2].SetLabel(equality)
- sim_page.constraints_list[index][3].SetValue(constraint_value)
- sim_page._on_add_constraint(None)
- sim_page._manager.sim_page = sim_page
-
- def _format_id(self, original_id):
- original_id = original_id.rstrip('1234567890.')
- new_id_list = original_id.split()
- new_id = ' '.join(new_id_list)
- return new_id
\ No newline at end of file
+"""
+ Simultaneous or Batch fit page
+"""
+# Note that this is used for both Simultaneous/Constrained fit AND for
+# combined batch fit. This is done through setting of the batch_on parameter.
+# There are the a half dozen or so places where an if statement is used as in
+# if not batch_on:
+# xxxx
+# else:
+# xxxx
+# This is just wrong but dont have time to fix this go. Proper approach would be
+# to strip all parts of the code that depend on batch_on and create the top
+# level class from which a contrained/simultaneous fit page and a combined
+# batch page inherit.
+#
+# 04/09/2017 --PDB
+
+import sys
+from collections import namedtuple
+
+import wx
+import wx.lib.newevent
+from wx.lib.scrolledpanel import ScrolledPanel
+
+from sas.sascalc.fit.pagestate import SimFitPageState
+from sas.sasgui.guiframe.events import StatusEvent, PanelOnFocusEvent
+from sas.sasgui.guiframe.panel_base import PanelBase
+from sas.sasgui.guiframe.utils import IdList
+from sas.sasgui.guiframe.documentation_window import DocumentationWindow
+
+# Control panel width
+if sys.platform.count("darwin") == 0:
+ PANEL_WID = 420
+ FONT_VARIANT = 0
+else:
+ PANEL_WID = 490
+ FONT_VARIANT = 1
+
+
+# Each constraint requires five widgets and sizer. Package them in
+# a named tuple for easy access.
+ConstraintLine = namedtuple('ConstraintLine',
+ 'model_cbox param_cbox egal_txt constraint btRemove sizer')
+
+
+def get_fittableParam(model):
+ """
+ return list of fittable parameters from a model
+
+ :param model: the model used
+
+ """
+ fittable_param = []
+ for item in model.getParamList():
+ if not item in model.getDispParamList():
+ if not item in model.non_fittable:
+ fittable_param.append(item)
+
+ for item in model.fixed:
+ fittable_param.append(item)
+
+ return fittable_param
+
+class SimultaneousFitPage(ScrolledPanel, PanelBase):
+ """
+ Simultaneous fitting panel
+ All that needs to be defined are the
+ two data members window_name and window_caption
+ """
+ # Internal name for the AUI manager
+ window_name = "Simultaneous Fit Page"
+ # Title to appear on top of the window
+ window_caption = "Simultaneous Fit Page"
+ ID_DOC = wx.NewId()
+ ID_SET_ALL = wx.NewId()
+ ID_FIT = wx.NewId()
+ ID_ADD = wx.NewId()
+ _id_pool = IdList()
+
+ def __init__(self, parent, page_finder={}, id=wx.ID_ANY, batch_on=False,
+ *args, **kwargs):
+ ScrolledPanel.__init__(self, parent, id=id,
+ style=wx.FULL_REPAINT_ON_RESIZE,
+ *args, **kwargs)
+ PanelBase.__init__(self, parent)
+ """
+ Simultaneous page display
+ """
+ self._ids = iter(self._id_pool)
+ self.SetupScrolling()
+ # Font size
+ self.SetWindowVariant(variant=FONT_VARIANT)
+ self.uid = wx.NewId()
+ self.parent = parent
+ self.batch_on = batch_on
+ # store page_finder
+ self.page_finder = page_finder
+ # list containing info to set constraint
+ # look like self.constraint_dict[page_id]= page
+ self.constraint_dict = {}
+ # item list
+ # self.constraints_list=[combobox1, combobox2,=,textcrtl, button ]
+ self.constraints_list = []
+ # list of current model
+ self.model_list = []
+ # selected model to fit
+ self.model_to_fit = []
+ # Control the fit state
+ self.fit_started = False
+ # number of constraint
+ self.nb_constraint = 0
+ self.state = SimFitPageState()
+ self.model_cbox_left = None
+ self.model_cbox_right = None
+ # draw page
+ self.define_page_structure()
+ self.draw_page()
+ self._set_save_flag(False)
+
+ def define_page_structure(self):
+ """
+ Create empty sizers, their hierarchy and set the sizer for the panel
+ """
+ self.vbox = wx.BoxSizer(wx.VERTICAL)
+ self.data_selection_sizer = wx.BoxSizer(wx.VERTICAL)
+ self.constraints_sizer = wx.BoxSizer(wx.VERTICAL)
+ self.run_fit_sizer = wx.BoxSizer(wx.VERTICAL)
+
+ self.data_selection_sizer.SetMinSize((PANEL_WID, -1))
+ self.constraints_sizer.SetMinSize((PANEL_WID, -1))
+ self.run_fit_sizer.SetMinSize((PANEL_WID, -1))
+ self.vbox.Add(self.data_selection_sizer)
+ self.vbox.Add(self.constraints_sizer)
+ self.vbox.Add(self.run_fit_sizer)
+ self.SetSizer(self.vbox)
+ self.Centre()
+
+ def set_state(self):
+ """
+ Define a set of state parameters for saving simultaneous fits.
+ """
+ self._set_constraint()
+ self.state.fit_page_no = self.uid
+ self.state.select_all = self.cb1.GetValue()
+ self.state.model_list = self.model_list
+ self.state.model_to_fit = self.model_to_fit
+ self.state.no_constraint = self.nb_constraint
+ self.state.constraint_dict = self.constraint_dict
+ self.state.constraints_list = self.constraints_list
+ return self.get_state()
+
+ def get_state(self):
+ """
+ Return the state of the current page
+ :return: self.state
+ """
+ return self.state
+
+ def load_from_save_state(self, sim_state):
+ """
+ Load in a simultaneous/constrained fit from a save state
+ :param fit: Fitpanel object
+ :return: None
+ """
+ init_map = {}
+ final_map = {}
+ # Process each model and associate old M# with new M#
+ i = 0
+ for model in self.model_list:
+ model_id = self._format_id(model[1].keys()[0])
+ for saved_model in sim_state.model_list:
+ save_id = saved_model.pop('name')
+ saved_model['name'] = save_id
+ save_id = self._format_id(save_id)
+ if save_id == model_id:
+ inter_id = str(i)*5
+ init_map[saved_model.pop('fit_page_source')] = inter_id
+ final_map[inter_id] = model[3].name
+ check = bool(saved_model.pop('checked'))
+ self.model_list[i][0].SetValue(check)
+ break
+ i += 1
+
+ self.check_model_name(None)
+
+ if len(sim_state.constraints_list) > 0:
+ self.hide_constraint.SetValue(False)
+ self.show_constraint.SetValue(True)
+ self._display_constraint(None)
+
+ for index, item in enumerate(sim_state.constraints_list):
+ model_cbox = item.pop('model_cbox')
+ if model_cbox != "":
+ constraint_value = item.pop('constraint')
+ param = item.pop('param_cbox')
+ equality = item.pop('egal_txt')
+ for key, value in init_map.items():
+ model_cbox = model_cbox.replace(key, value)
+ constraint_value = constraint_value.replace(key, value)
+ for key, value in final_map.items():
+ model_cbox = model_cbox.replace(key, value)
+ constraint_value = constraint_value.replace(key, value)
+
+ self.constraints_list[index][0].SetValue(model_cbox)
+ self._on_select_model(None)
+ self.constraints_list[index][1].SetValue(param)
+ self.constraints_list[index][2].SetLabel(equality)
+ self.constraints_list[index][3].SetValue(constraint_value)
+ self._on_add_constraint(None)
+ self._manager.sim_page = self
+
+ def _format_id(self, original_id):
+ original_id = original_id.rstrip('1234567890.')
+ new_id_list = original_id.split()
+ new_id = ' '.join(new_id_list)
+ return new_id
+
+
+
+ def draw_page(self):
+ """
+ Construct the Simultaneous/Constrained fit page. fills the first
+ region (sizer1) with the list of available fit page pairs of data
+ and models. Then fills sizer2 with the checkbox for adding
+ constraints, and finally fills sizer3 with the fit button and
+ instructions.
+ """
+
+ # create blank list of constraints
+ self.model_list = []
+ self.model_to_fit = []
+ self.constraints_list = []
+ self.constraint_dict = {}
+ self.nb_constraint = 0
+ self.model_cbox_left = None
+ self.model_cbox_right = None
+
+ if len(self.model_list) > 0:
+ for item in self.model_list:
+ item[0].SetValue(False)
+ self.manager.schedule_for_fit(value=0, uid=item[2])
+
+ #-------------------------------------------------------
+ # setup sizer1 (which fitpages to include)
+ self.data_selection_sizer.Clear(True)
+ box_description = wx.StaticBox(self, wx.ID_ANY, "Fit Combinations")
+ boxsizer1 = wx.StaticBoxSizer(box_description, wx.VERTICAL)
+ sizer_title = wx.BoxSizer(wx.HORIZONTAL)
+ sizer_couples = wx.GridBagSizer(5, 5)
+
+ # The wx GUI has a flag to enable a menu item, but can still be
+ # reached via scripting. There is no guearantee future GUI
+ # implementations force this check, either.
+ # IMHO, this if statement should stay -- JRK 2016-OCT-05
+ if len(self.page_finder) == 0:
+ msg = " No fit combinations are found! \n\n"
+ msg += " Please load data and set up "
+ msg += "at least one fit panels first..."
+ sizer_title.Add(wx.StaticText(self, wx.ID_ANY, msg))
+ else:
+ # store model
+ self._store_model()
+
+ self.cb1 = wx.CheckBox(self, wx.ID_ANY, 'Select all')
+ self.cb1.SetValue(False)
+ wx.EVT_CHECKBOX(self, self.cb1.GetId(), self.check_all_model_name)
+
+ sizer_title.Add((10, 10), 0,
+ wx.TOP | wx.BOTTOM | wx.EXPAND | wx.ADJUST_MINSIZE, border=5)
+ sizer_title.Add(self.cb1, 0,
+ wx.TOP | wx.BOTTOM | wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE,
+ border=5)
+
+ # draw list of model and data names
+ self._fill_sizer_model_list(sizer_couples)
+
+ boxsizer1.Add(sizer_title, flag=wx.TOP | wx.BOTTOM, border=5)
+ boxsizer1.Add(sizer_couples, 1, flag=wx.TOP | wx.BOTTOM, border=5)
+ self.data_selection_sizer.Add(boxsizer1, 1, wx.EXPAND | wx.ALL, 10)
+ # self.sizer1.Layout()
+
+ #--------------------------------------------------------
+ # set up the other 2 sizers: the constraints list and the
+ # buttons (fit, help etc) sizer at the bottom of the page.
+ # Note: the if statement should be removed along with the above
+ # if statement as soon as it can be properly tested.
+ # Nov. 22 2015 --PDB
+ # As above, this page can be accessed through other means than the
+ # base SasView GUI.
+ # Oct. 5, 2016 --JRK
+ if len(self.page_finder) > 0:
+ # draw the sizer containing constraint info
+ if not self.batch_on:
+ self._fill_sizer_constraint()
+ # draw fit button sizer
+ self._fill_sizer_fit()
+
+ def _fill_sizer_model_list(self, sizer):
+ """
+ Receive a dictionary containing information to display model name
+ """
+ ix = 0
+ iy = 0
+ sizer.Clear(True)
+
+ new_name = wx.StaticText(self, wx.ID_ANY, ' Model Title ',
+ style=wx.ALIGN_CENTER)
+ new_name.SetBackgroundColour('orange')
+ new_name.SetForegroundColour(wx.WHITE)
+ sizer.Add(new_name, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ ix += 2
+ model_type = wx.StaticText(self, wx.ID_ANY, ' Model ')
+ model_type.SetBackgroundColour('grey')
+ model_type.SetForegroundColour(wx.WHITE)
+ sizer.Add(model_type, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix += 1
+ data_used = wx.StaticText(self, wx.ID_ANY, ' Data ')
+ data_used.SetBackgroundColour('grey')
+ data_used.SetForegroundColour(wx.WHITE)
+ sizer.Add(data_used, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix += 1
+ tab_used = wx.StaticText(self, wx.ID_ANY, ' FitPage ')
+ tab_used.SetBackgroundColour('grey')
+ tab_used.SetForegroundColour(wx.WHITE)
+ sizer.Add(tab_used, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ for id, value in self.page_finder.iteritems():
+ if id not in self.parent.opened_pages:
+ continue
+
+ if self.batch_on != self.parent.get_page_by_id(id).batch_on:
+ continue
+
+ data_list = []
+ model_list = []
+ # get data name and model objetta
+ for fitproblem in value.get_fit_problem():
+
+ data = fitproblem.get_fit_data()
+ if not data.is_data:
+ continue
+ name = '-'
+ if data is not None and data.is_data:
+ name = str(data.name)
+ data_list.append(name)
+
+ model = fitproblem.get_model()
+ if model is None:
+ continue
+ model_list.append(model)
+
+ if len(model_list) == 0:
+ continue
+ # Draw sizer
+ ix = 0
+ iy += 1
+ model = model_list[0]
+ name = '_'
+ if model is not None:
+ name = str(model.name)
+ cb = wx.CheckBox(self, wx.ID_ANY, name)
+ cb.SetValue(False)
+ cb.Enable(model is not None and data.is_data)
+ sizer.Add(cb, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ wx.EVT_CHECKBOX(self, cb.GetId(), self.check_model_name)
+ ix += 2
+ model_type = wx.StaticText(self, wx.ID_ANY,
+ model.__class__.__name__)
+ sizer.Add(model_type, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ if self.batch_on:
+ data_used = wx.ComboBox(self, wx.ID_ANY, style=wx.CB_READONLY)
+ data_used.AppendItems(data_list)
+ data_used.SetSelection(0)
+ else:
+ data_used = wx.StaticText(self, wx.ID_ANY, data_list[0])
+
+ ix += 1
+ sizer.Add(data_used, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix += 1
+ caption = value.get_fit_tab_caption()
+ tab_caption_used = wx.StaticText(self, wx.ID_ANY, str(caption))
+ sizer.Add(tab_caption_used, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+
+ self.model_list.append([cb, value, id, model])
+
+ iy += 1
+ sizer.Add((20, 20), (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+
+ def _fill_sizer_constraint(self):
+ """
+ Fill sizer containing constraint info
+ """
+ msg = "Select at least 1 model to add constraint "
+ wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
+
+ self.constraints_sizer.Clear(True)
+ if self.batch_on:
+ if self.constraints_sizer.IsShown():
+ self.constraints_sizer.Show(False)
+ return
+ box_description = wx.StaticBox(self, wx.ID_ANY, "Fit Constraints")
+ box_sizer1 = wx.StaticBoxSizer(box_description, wx.VERTICAL)
+ sizer_title = wx.BoxSizer(wx.HORIZONTAL)
+ self.sizer_all_constraints = wx.BoxSizer(wx.HORIZONTAL)
+ self.sizer_constraints = wx.BoxSizer(wx.VERTICAL)
+ sizer_button = wx.BoxSizer(wx.HORIZONTAL)
+
+ self.hide_constraint = wx.RadioButton(self, wx.ID_ANY, 'No', (10, 10),
+ style=wx.RB_GROUP)
+ self.show_constraint = wx.RadioButton(self, wx.ID_ANY, 'Yes', (10, 30))
+ self.Bind(wx.EVT_RADIOBUTTON, self._display_constraint,
+ id=self.hide_constraint.GetId())
+ self.Bind(wx.EVT_RADIOBUTTON, self._display_constraint,
+ id=self.show_constraint.GetId())
+ if self.batch_on:
+ self.hide_constraint.Enable(False)
+ self.show_constraint.Enable(False)
+ self.hide_constraint.SetValue(True)
+ self.show_constraint.SetValue(False)
+
+ sizer_title.Add(wx.StaticText(self, wx.ID_ANY, " Model"))
+ sizer_title.Add((10, 10))
+ sizer_title.Add(wx.StaticText(self, wx.ID_ANY, " Parameter"))
+ sizer_title.Add((10, 10))
+ sizer_title.Add(wx.StaticText(self, wx.ID_ANY, " Add Constraint?"))
+ sizer_title.Add((10, 10))
+ sizer_title.Add(self.show_constraint)
+ sizer_title.Add(self.hide_constraint)
+ sizer_title.Add((10, 10))
+
+ self.btAdd = wx.Button(self, self.ID_ADD, 'Add')
+ self.btAdd.Bind(wx.EVT_BUTTON, self._on_add_constraint,
+ id=self.btAdd.GetId())
+ self.btAdd.SetToolTipString("Add another constraint?")
+ self.btAdd.Hide()
+
+ text_hint = wx.StaticText(self, wx.ID_ANY,
+ "Example: [M0][parameter] = M1.parameter")
+ sizer_button.Add(text_hint, 0,
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 10)
+ sizer_button.Add(self.btAdd, 0,
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 10)
+
+ box_sizer1.Add(sizer_title, flag=wx.TOP | wx.BOTTOM, border=10)
+ box_sizer1.Add(self.sizer_all_constraints, flag=wx.TOP | wx.BOTTOM,
+ border=10)
+ box_sizer1.Add(self.sizer_constraints, flag=wx.TOP | wx.BOTTOM,
+ border=10)
+ box_sizer1.Add(sizer_button, flag=wx.TOP | wx.BOTTOM, border=10)
+
+ self.constraints_sizer.Add(box_sizer1, 0, wx.EXPAND | wx.ALL, 10)
+
+ def _fill_sizer_fit(self):
+ """
+ Draw fit button
+ """
+ self.run_fit_sizer.Clear(True)
+ box_description = wx.StaticBox(self, wx.ID_ANY, "Fit ")
+ boxsizer1 = wx.StaticBoxSizer(box_description, wx.VERTICAL)
+ sizer_button = wx.BoxSizer(wx.HORIZONTAL)
+
+ # Fit button
+ self.btFit = wx.Button(self, self.ID_FIT, 'Fit', size=wx.DefaultSize)
+ self.btFit.Bind(wx.EVT_BUTTON, self.on_fit, id=self.btFit.GetId())
+ self.btFit.SetToolTipString("Perform fit.")
+
+ # General Help button
+ self.btHelp = wx.Button(self, wx.ID_HELP, 'HELP')
+ if self.batch_on:
+ self.btHelp.SetToolTipString("Combined Batch Fitting help.")
+ else:
+ self.btHelp.SetToolTipString("Simultaneous/Constrained Fitting help.")
+ self.btHelp.Bind(wx.EVT_BUTTON, self._on_help)
+
+ # hint text on button line
+ if self.batch_on:
+ text = " Fit in Parallel all Data sets\n"
+ text += "and model selected."
+ else:
+ text = " At least one set of model and data\n"
+ text += " must be selected for fitting."
+ text_hint = wx.StaticText(self, wx.ID_ANY, text)
+
+ sizer_button.Add(text_hint)
+ sizer_button.Add(self.btFit, 0, wx.LEFT | wx.ADJUST_MINSIZE, 10)
+ sizer_button.Add(self.btHelp, 0, wx.LEFT | wx.ADJUST_MINSIZE, 10)
+
+ boxsizer1.Add(sizer_button, flag=wx.TOP | wx.BOTTOM, border=10)
+ self.run_fit_sizer.Add(boxsizer1, 0, wx.EXPAND | wx.ALL, 10)
+
+ def on_remove(self, event):
+ """
+ Remove constraint fields
+ """
+ if len(self.constraints_list) == 1:
+ self.hide_constraint.SetValue(True)
+ self._hide_constraint()
+ return
+ if len(self.constraints_list) == 0:
+ return
+ wx.CallAfter(self._remove_after, event.GetId())
+ # self._onAdd_constraint(None)
+
+ def _remove_after(self, id):
+ for item in self.constraints_list:
+ if id == item.btRemove.GetId():
+ self.sizer_constraints.Hide(item.sizer)
+ item.sizer.Clear(True)
+ self.sizer_constraints.Remove(item.sizer)
+ self.constraints_list.remove(item)
+ self.nb_constraint -= 1
+ self.constraints_sizer.Layout()
+ self.FitInside()
+ break
+
+ def on_fit(self, event):
+ """
+ signal for fitting
+
+ """
+ if self.fit_started:
+ self._stop_fit()
+ self.fit_started = False
+ return
+
+ flag = False
+ # check if the current page a simultaneous fit page or a batch page
+ if self == self._manager.sim_page:
+ flag = (self._manager.sim_page.uid == self.uid)
+
+ # making sure all parameters content a constraint
+ if not self.batch_on and self.show_constraint.GetValue():
+ if not self._set_constraint():
+ return
+ # model was actually selected from this page to be fit
+ if len(self.model_to_fit) >= 1:
+ self.manager._reset_schedule_problem(value=0)
+ for item in self.model_list:
+ if item[0].GetValue():
+ self.manager.schedule_for_fit(value=1, uid=item[2])
+ try:
+ self.fit_started = True
+ wx.CallAfter(self.set_fitbutton)
+ if not self.manager.onFit(uid=self.uid):
+ return
+ except:
+ msg = "Select at least one parameter to fit in the FitPages."
+ wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
+ else:
+ msg = "Select at least one model check box to fit "
+ wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
+ self.set_state()
+
+ def _on_fit_complete(self):
+ """
+ Set the completion flag and display the updated fit button label.
+ """
+ self.fit_started = False
+ self.set_fitbutton()
+
+ def _stop_fit(self, event=None):
+ """
+ Attempt to stop the fitting thread
+
+ :param event: Event handler when stop fit is clicked
+ """
+ if event is not None:
+ event.Skip()
+ self.manager.stop_fit(self.uid)
+ self.manager._reset_schedule_problem(value=0)
+ self._on_fit_complete()
+
+ def set_fitbutton(self):
+ """
+ Set fit button label depending on the fit_started
+ """
+ label = "Stop" if self.fit_started else "Fit"
+ color = "red" if self.fit_started else "black"
+
+ self.btFit.SetLabel(label)
+ self.btFit.SetForegroundColour(color)
+ self.btFit.Enable(True)
+
+ def _on_help(self, event):
+ """
+ Bring up the simultaneous Fitting Documentation whenever the HELP
+ button is clicked.
+
+ Calls DocumentationWindow with the path of the location within the
+ documentation tree (after /doc/ ....". Note that when using old
+ versions of Wx (before 2.9) and thus not the release version of
+ installers, the help comes up at the top level of the file as
+ web browser does not pass anything past the # to the browser when it is
+ running "file:///...."
+
+ :param event: Triggers on clicking the help button
+ """
+ _TreeLocation = "user/sasgui/perspectives/fitting/fitting_help.html"
+ if not self.batch_on:
+ _PageAnchor = "#simultaneous-fit-mode"
+ _doc_viewer = DocumentationWindow(self, self.ID_DOC, _TreeLocation,
+ _PageAnchor,
+ "Simultaneous/Constrained Fitting Help")
+ else:
+ _PageAnchor = "#combined-batch-fit-mode"
+ _doc_viewer = DocumentationWindow(self, self.ID_DOC, _TreeLocation,
+ _PageAnchor,
+ "Combined Batch Fit Help")
+
+ def set_manager(self, manager):
+ """
+ set panel manager
+
+ :param manager: instance of plugin fitting
+ """
+ self.manager = manager
+
+ def check_all_model_name(self, event=None):
+ """
+ check all models names
+ """
+ self.model_to_fit = []
+ if self.cb1.GetValue():
+ for item in self.model_list:
+ if item[0].IsEnabled():
+ item[0].SetValue(True)
+ self.model_to_fit.append(item)
+
+ # constraint info
+ self._store_model()
+ if not self.batch_on:
+ # display constraint fields
+ if (self.show_constraint.GetValue() and
+ len(self.constraints_list) == 0):
+ self._show_all_constraint()
+ self._show_constraint()
+ else:
+ for item in self.model_list:
+ item[0].SetValue(False)
+
+ if not self.batch_on:
+ # constraint info
+ self._hide_constraint()
+
+ self._update_easy_setup_cb()
+ self.FitInside()
+
+ def check_model_name(self, event):
+ """
+ Save information related to checkbox and their states
+ """
+ self.model_to_fit = []
+ for item in self.model_list:
+ if item[0].GetValue():
+ self.model_to_fit.append(item)
+ else:
+ if item in self.model_to_fit:
+ self.model_to_fit.remove(item)
+ self.cb1.SetValue(False)
+
+ # display constraint fields
+ if len(self.model_to_fit) >= 1:
+ self._store_model()
+ if not self.batch_on and self.show_constraint.GetValue() and\
+ len(self.constraints_list) == 0:
+ self._show_all_constraint()
+ self._show_constraint()
+
+ elif len(self.model_to_fit) < 1:
+ # constraint info
+ self._hide_constraint()
+
+ self._update_easy_setup_cb()
+ # set the value of the main check button
+ if len(self.model_list) == len(self.model_to_fit):
+ self.cb1.SetValue(True)
+ self.FitInside()
+ return
+ else:
+ self.cb1.SetValue(False)
+ self.FitInside()
+
+ def _update_easy_setup_cb(self):
+ """
+ Update easy setup combobox on selecting a model
+ """
+ if self.model_cbox_left is None or self.model_cbox_right is None:
+ return
+
+ models = [(item[3].name, item[3]) for item in self.model_to_fit]
+ setComboBoxItems(self.model_cbox_left, models)
+ setComboBoxItems(self.model_cbox_right, models)
+ for item in self.constraints_list:
+ setComboBoxItems(item[0], models)
+ if self.model_cbox_left.GetSelection() == wx.NOT_FOUND:
+ self.model_cbox_left.SetSelection(0)
+ self.constraints_sizer.Layout()
+
+ def _store_model(self):
+ """
+ Store selected model
+ """
+ if len(self.model_to_fit) < 1:
+ return
+ for item in self.model_to_fit:
+ model = item[3]
+ page_id = item[2]
+ self.constraint_dict[page_id] = model
+
+ def _display_constraint(self, event):
+ """
+ Show fields to add constraint
+ """
+ if len(self.model_to_fit) < 1:
+ msg = "Select at least 1 model to add constraint "
+ wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
+ # hide button
+ self._hide_constraint()
+ return
+ if self.show_constraint.GetValue():
+ self._show_all_constraint()
+ self._show_constraint()
+ self.FitInside()
+ return
+ else:
+ self._hide_constraint()
+ return
+
+ def _show_all_constraint(self):
+ """
+ Show constraint fields
+ """
+ box_description = wx.StaticBox(self, wx.ID_ANY, "Easy Setup ")
+ box_sizer = wx.StaticBoxSizer(box_description, wx.HORIZONTAL)
+ sizer_constraint = wx.BoxSizer(wx.HORIZONTAL)
+ self.model_cbox_left = wx.ComboBox(self, wx.ID_ANY, style=wx.CB_READONLY)
+ self.model_cbox_left.Clear()
+ self.model_cbox_right = wx.ComboBox(self, wx.ID_ANY, style=wx.CB_READONLY)
+ self.model_cbox_right.Clear()
+ wx.EVT_COMBOBOX(self.model_cbox_left, wx.ID_ANY, self._on_select_modelcb)
+ wx.EVT_COMBOBOX(self.model_cbox_right, wx.ID_ANY, self._on_select_modelcb)
+ egal_txt = wx.StaticText(self, wx.ID_ANY, " = ")
+ self.set_button = wx.Button(self, self.ID_SET_ALL, 'Set All')
+ self.set_button.Bind(wx.EVT_BUTTON, self._on_set_all_equal,
+ id=self.set_button.GetId())
+ set_tip = "Add constraints for all the adjustable parameters "
+ set_tip += "(checked in FitPages) if exist."
+ self.set_button.SetToolTipString(set_tip)
+ self.set_button.Disable()
+
+ for id, model in self.constraint_dict.iteritems():
+ # check if all parameters have been selected for constraint
+ # then do not allow add constraint on parameters
+ self.model_cbox_left.Append(str(model.name), model)
+ self.model_cbox_left.Select(0)
+ for id, model in self.constraint_dict.iteritems():
+ # check if all parameters have been selected for constraint
+ # then do not allow add constraint on parameters
+ self.model_cbox_right.Append(str(model.name), model)
+ box_sizer.Add(self.model_cbox_left,
+ flag=wx.RIGHT | wx.EXPAND, border=10)
+ # box_sizer.Add(wx.StaticText(self, wx.ID_ANY, ".parameters"),
+ # flag=wx.RIGHT | wx.EXPAND, border=5)
+ box_sizer.Add(egal_txt, flag=wx.RIGHT | wx.EXPAND, border=5)
+ box_sizer.Add(self.model_cbox_right,
+ flag=wx.RIGHT | wx.EXPAND, border=10)
+ # box_sizer.Add(wx.StaticText(self, wx.ID_ANY, ".parameters"),
+ # flag=wx.RIGHT | wx.EXPAND, border=5)
+ box_sizer.Add((20, -1))
+ box_sizer.Add(self.set_button, flag=wx.RIGHT | wx.EXPAND, border=5)
+ sizer_constraint.Add(box_sizer, flag=wx.RIGHT | wx.EXPAND, border=5)
+ self.sizer_all_constraints.Insert(before=0,
+ item=sizer_constraint,
+ flag=wx.TOP | wx.BOTTOM | wx.EXPAND, border=5)
+ self.FitInside()
+
+ def _on_select_modelcb(self, event):
+ """
+ On select model left or right combobox
+ """
+ event.Skip()
+ flag = True
+ if self.model_cbox_left.GetValue().strip() == '':
+ flag = False
+ if self.model_cbox_right.GetValue().strip() == '':
+ flag = False
+ if (self.model_cbox_left.GetValue() ==
+ self.model_cbox_right.GetValue()):
+ flag = False
+ self.set_button.Enable(flag)
+
+ def _on_set_all_equal(self, event):
+ """
+ On set button
+ """
+ event.Skip()
+ length = len(self.constraints_list)
+ if length < 1:
+ return
+ param_list = []
+ param_list_b = []
+ selection = self.model_cbox_left.GetCurrentSelection()
+ model_left = self.model_cbox_left.GetValue()
+ model = self.model_cbox_left.GetClientData(selection)
+ selection_b = self.model_cbox_right.GetCurrentSelection()
+ model_right = self.model_cbox_right.GetValue()
+ model_b = self.model_cbox_right.GetClientData(selection_b)
+ for id, dic_model in self.constraint_dict.iteritems():
+ if model == dic_model:
+ param_list = self.page_finder[id].get_param2fit()
+ if model_b == dic_model:
+ param_list_b = self.page_finder[id].get_param2fit()
+ if len(param_list) > 0 and len(param_list_b) > 0:
+ break
+ num_cbox = 0
+ has_param = False
+ for param in param_list:
+ num_cbox += 1
+ if param in param_list_b:
+ item = self.constraints_list[-1]
+ item.model_cbox.SetStringSelection(model_left)
+ self._on_select_model(None)
+ item.param_cbox.Clear()
+ item.param_cbox.Append(str(param), model)
+ item.param_cbox.SetStringSelection(str(param))
+ item.constraint.SetValue(str(model_right + "." + str(param)))
+ has_param = True
+ if num_cbox == (len(param_list) + 1):
+ break
+ self._show_constraint()
+
+ self.FitInside()
+ if not has_param:
+ msg = " There is no adjustable parameter (checked to fit)"
+ msg += " either one of the models."
+ wx.PostEvent(self.parent.parent, StatusEvent(info="warning",
+ status=msg))
+ else:
+ msg = " The constraints are added."
+ wx.PostEvent(self.parent.parent, StatusEvent(info="info",
+ status=msg))
+
+ def _show_constraint(self):
+ """
+ Show constraint fields
+ :param dict: dictionary mapping constraint values
+ """
+ self.btAdd.Show(True)
+ if len(self.constraints_list) != 0:
+ nb_fit_param = 0
+ for id, model in self.constraint_dict.iteritems():
+ nb_fit_param += len(self.page_finder[id].get_param2fit())
+ # Don't add anymore
+ if len(self.constraints_list) == nb_fit_param:
+ msg = "Cannot add another constraint. Maximum of number "
+ msg += "Parameters name reached %s" % str(nb_fit_param)
+ wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
+ self.sizer_constraints.Layout()
+ self.constraints_sizer.Layout()
+ return
+ if len(self.model_to_fit) < 1:
+ msg = "Select at least 1 model to add constraint "
+ wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
+ self.sizer_constraints.Layout()
+ self.constraints_sizer.Layout()
+ return
+
+ sizer_constraint = wx.BoxSizer(wx.HORIZONTAL)
+
+ # Model list
+ model_cbox = wx.ComboBox(self, wx.ID_ANY, style=wx.CB_READONLY)
+ model_cbox.Clear()
+ for id, model in self.constraint_dict.iteritems():
+ # check if all parameters have been selected for constraint
+ # then do not allow add constraint on parameters
+ model_cbox.Append(str(model.name), model)
+ wx.EVT_COMBOBOX(model_cbox, wx.ID_ANY, self._on_select_model)
+
+ # Parameters in model
+ param_cbox = wx.ComboBox(self, wx.ID_ANY, style=wx.CB_READONLY,
+ size=(100, -1))
+ param_cbox.Hide()
+ wx.EVT_COMBOBOX(param_cbox, wx.ID_ANY, self._on_select_param)
+
+ egal_txt = wx.StaticText(self, wx.ID_ANY, " = ")
+
+ # Parameter constraint
+ constraint = wx.TextCtrl(self, wx.ID_ANY)
+
+ # Remove button
+ #btRemove = wx.Button(self, self.ID_REMOVE, 'Remove')
+ bt_remove = wx.Button(self, self._ids.next(), 'Remove')
+ bt_remove.Bind(wx.EVT_BUTTON, self.on_remove,
+ id=bt_remove.GetId())
+ bt_remove.SetToolTipString("Remove constraint.")
+ bt_remove.Hide()
+
+ # Hid the add button, if it exists
+ if hasattr(self, "btAdd"):
+ self.btAdd.Hide()
+
+ sizer_constraint.Add((5, -1))
+ sizer_constraint.Add(model_cbox, flag=wx.RIGHT | wx.EXPAND, border=10)
+ sizer_constraint.Add(param_cbox, flag=wx.RIGHT | wx.EXPAND, border=5)
+ sizer_constraint.Add(egal_txt, flag=wx.RIGHT | wx.EXPAND, border=5)
+ sizer_constraint.Add(constraint, flag=wx.RIGHT | wx.EXPAND, border=10)
+ sizer_constraint.Add(bt_remove, flag=wx.RIGHT | wx.EXPAND, border=10)
+
+ self.sizer_constraints.Insert(before=self.nb_constraint,
+ item=sizer_constraint, flag=wx.TOP | wx.BOTTOM | wx.EXPAND,
+ border=5)
+ c = ConstraintLine(model_cbox, param_cbox, egal_txt,
+ constraint, bt_remove, sizer_constraint)
+ self.constraints_list.append(c)
+
+ self.nb_constraint += 1
+ self.sizer_constraints.Layout()
+ self.constraints_sizer.Layout()
+ self.Layout()
+
+ def _hide_constraint(self):
+ """
+ hide buttons related constraint
+ """
+ for id in self.page_finder.iterkeys():
+ self.page_finder[id].clear_model_param()
+
+ self.nb_constraint = 0
+ self.constraint_dict = {}
+ if hasattr(self, "btAdd"):
+ self.btAdd.Hide()
+ self._store_model()
+ if self.model_cbox_left is not None:
+ self.model_cbox_left.Clear()
+ self.model_cbox_left = None
+ if self.model_cbox_right is not None:
+ self.model_cbox_right.Clear()
+ self.model_cbox_right = None
+ self.constraints_list = []
+ self.sizer_all_constraints.Clear(True)
+ self.sizer_all_constraints.Layout()
+ self.sizer_constraints.Clear(True)
+ self.sizer_constraints.Layout()
+ self.constraints_sizer.Layout()
+ self.Layout()
+ self.FitInside()
+
+ def _on_select_model(self, event):
+ """
+ fill combo box with list of parameters
+ """
+ if not self.constraints_list:
+ return
+
+ # This way PC/MAC both work, instead of using event.GetClientData().
+ model_cbox = self.constraints_list[-1].model_cbox
+ n = model_cbox.GetCurrentSelection()
+ if n == wx.NOT_FOUND:
+ return
+
+ model = model_cbox.GetClientData(n)
+ param_list = []
+ for id, dic_model in self.constraint_dict.iteritems():
+ if model == dic_model:
+ param_list = self.page_finder[id].get_param2fit()
+ break
+
+ param_cbox = self.constraints_list[-1].param_cbox
+ param_cbox.Clear()
+ # insert only fittable paramaters
+ for param in param_list:
+ param_cbox.Append(str(param), model)
+ param_cbox.Show(True)
+
+ bt_remove = self.constraints_list[-1].btRemove
+ bt_remove.Show(True)
+ self.btAdd.Show(True)
+# self.Layout()
+ self.FitInside()
+
+ def _on_select_param(self, event):
+ """
+ Store the appropriate constraint in the page_finder
+ """
+ # This way PC/MAC both work, instead of using event.GetClientData().
+ # n = self.param_cbox.GetCurrentSelection()
+ # model = self.param_cbox.GetClientData(n)
+ # param = event.GetString()
+
+ if self.constraints_list:
+ self.constraints_list[-1].egal_txt.Show(True)
+ self.constraints_list[-1].constraint.Show(True)
+
+ def _on_add_constraint(self, event):
+ """
+ Add another line for constraint
+ """
+ if not self.show_constraint.GetValue():
+ msg = " Select Yes to add Constraint "
+ wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
+ return
+ # check that a constraint is added
+ # before allow to add another constraint
+ for item in self.constraints_list:
+ if item.model_cbox.GetString(0) == "":
+ msg = " Select a model Name! "
+ wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
+ return
+ if item.param_cbox.GetString(0) == "":
+ msg = " Select a parameter Name! "
+ wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
+ return
+ if item.constraint.GetValue().lstrip().rstrip() == "":
+ model = item.param_cbox.GetClientData(
+ item.param_cbox.GetCurrentSelection())
+ if model is not None:
+ msg = " Enter a constraint for %s.%s! " % (model.name,
+ item.param_cbox.GetString(0))
+ else:
+ msg = " Enter a constraint"
+ wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
+ return
+ # some model or parameters can be constrained
+ self._show_constraint()
+ self.FitInside()
+
+ def _set_constraint(self):
+ """
+ get values from the constraint textcrtl ,parses them into model name
+ parameter name and parameters values.
+ store them in a list self.params .when when params is not empty
+ set_model uses it to reset the appropriate model
+ and its appropriates parameters
+ """
+ for item in self.constraints_list:
+ select0 = item.model_cbox.GetSelection()
+ if select0 == wx.NOT_FOUND:
+ continue
+ model = item.model_cbox.GetClientData(select0)
+ select1 = item.param_cbox.GetSelection()
+ if select1 == wx.NOT_FOUND:
+ continue
+ param = item.param_cbox.GetString(select1)
+ constraint = item.constraint.GetValue().lstrip().rstrip()
+ if param.lstrip().rstrip() == "":
+ param = None
+ msg = " Constraint will be ignored!. missing parameters"
+ msg += " in combobox to set constraint! "
+ wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
+ for id, value in self.constraint_dict.iteritems():
+ if model == value:
+ if constraint == "":
+ msg = " Constraint will be ignored!. missing value"
+ msg += " in textcrtl to set constraint! "
+ wx.PostEvent(self.parent.parent,
+ StatusEvent(status=msg))
+ constraint = None
+ if str(param) in self.page_finder[id].get_param2fit():
+ msg = " Checking constraint for parameter: %s ", param
+ wx.PostEvent(self.parent.parent,
+ StatusEvent(info="info", status=msg))
+ else:
+ model_name = item[0].GetLabel()
+ fitpage = self.page_finder[id].get_fit_tab_caption()
+ msg = "All constrainted parameters must be set "
+ msg += " adjustable: '%s.%s' " % (model_name, param)
+ msg += "is NOT checked in '%s'. " % fitpage
+ msg += " Please check it to fit or"
+ msg += " remove the line of the constraint."
+ wx.PostEvent(self.parent.parent,
+ StatusEvent(info="error", status=msg))
+ return False
+
+ for fid in self.page_finder[id].iterkeys():
+ # wrap in param/constraint in str() to remove unicode
+ self.page_finder[id].set_model_param(str(param),
+ str(constraint), fid=fid)
+ break
+ return True
+
+ def on_set_focus(self, event=None):
+ """
+ The derivative class is on focus if implemented
+ """
+ if self.parent is not None:
+ if self.parent.parent is not None:
+ wx.PostEvent(self.parent.parent, PanelOnFocusEvent(panel=self))
+ self.page_finder = self.parent._manager.get_page_finder()
+
+
+def setComboBoxItems(cbox, items):
+ assert isinstance(cbox, wx.ComboBox)
+ selected = cbox.GetStringSelection()
+ cbox.Clear()
+ for k, (name, value) in enumerate(items):
+ cbox.Append(name, value)
+ cbox.SetStringSelection(selected)
diff --git a/src/sas/sasgui/perspectives/fitting/utils.py b/src/sas/sasgui/perspectives/fitting/utils.py
index 30100c9..d163b9b 100644
--- a/src/sas/sasgui/perspectives/fitting/utils.py
+++ b/src/sas/sasgui/perspectives/fitting/utils.py
@@ -1,28 +1,28 @@
-"""
-Module contains functions frequently used in this package
-"""
-import numpy
-
-
-def get_weight(data, is2d, flag=None):
- """
- Received flag and compute error on data.
- :param flag: flag to transform error of data.
- :param is2d: flag to distinguish 1D to 2D Data
- """
- weight = None
- if is2d:
- dy_data = data.err_data
- data = data.data
- else:
- dy_data = data.dy
- data = data.y
- if flag == 0:
- weight = numpy.ones_like(data)
- elif flag == 1:
- weight = dy_data
- elif flag == 2:
- weight = numpy.sqrt(numpy.abs(data))
- elif flag == 3:
- weight = numpy.abs(data)
- return weight
+"""
+Module contains functions frequently used in this package
+"""
+import numpy as np
+
+
+def get_weight(data, is2d, flag=None):
+ """
+ Received flag and compute error on data.
+ :param flag: flag to transform error of data.
+ :param is2d: flag to distinguish 1D to 2D Data
+ """
+ weight = None
+ if is2d:
+ dy_data = data.err_data
+ data = data.data
+ else:
+ dy_data = data.dy
+ data = data.y
+ if flag == 0:
+ weight = np.ones_like(data)
+ elif flag == 1:
+ weight = dy_data
+ elif flag == 2:
+ weight = np.sqrt(np.abs(data))
+ elif flag == 3:
+ weight = np.abs(data)
+ return weight
diff --git a/src/sas/sasgui/perspectives/invariant/__init__.py b/src/sas/sasgui/perspectives/invariant/__init__.py
index 44b48f8..301a4a8 100644
--- a/src/sas/sasgui/perspectives/invariant/__init__.py
+++ b/src/sas/sasgui/perspectives/invariant/__init__.py
@@ -1,45 +1,43 @@
-PLUGIN_ID = "Invariant plug-in 1.0"
-import os
-
-from distutils.filelist import findall
-from invariant import *
-
-def get_data_path(media):
- """
- """
- # Check for data path in the package
- path = os.path.join(os.path.dirname(__file__), media)
- if os.path.isdir(path):
- return path
-
- # Check for data path next to exe/zip file.
- # If we are inside a py2exe zip file, we need to go up
- # to get to the directory containing
- # the media for this module
- path = os.path.dirname(__file__)
- #Look for maximum n_dir up of the current dir to find media
- n_dir = 12
- for i in range(n_dir):
- path, _ = os.path.split(path)
- media_path = os.path.join(path, media)
- if os.path.isdir(media_path):
- module_media_path = os.path.join(media_path, 'invariant_media')
- if os.path.isdir(module_media_path):
- return module_media_path
- return media_path
-
- raise RuntimeError('Could not find invariant media files')
-
-def data_files():
- """
- Return the data files associated with media invariant.
-
- The format is a list of (directory, [files...]) pairs which can be
- used directly in setup(...,data_files=...) for setup.py.
-
- """
- data_files = []
- path = get_data_path(media="media")
- for f in findall(path):
- data_files.append(('media/invariant_media', [f]))
+PLUGIN_ID = "Invariant plug-in 1.0"
+import os
+
+from distutils.filelist import findall
+from invariant import *
+
+def get_data_path(media):
+ """
+ """
+ # Check for data path in the package
+ path = os.path.join(os.path.dirname(__file__), media)
+ if os.path.isdir(path):
+ return path
+
+ # Check for data path next to exe/zip file.
+ # If we are inside a py2exe zip file, we need to go up
+ # to get to the directory containing
+ # the media for this module
+ path = os.path.dirname(__file__)
+ #Look for maximum n_dir up of the current dir to find media
+ n_dir = 12
+ for i in range(n_dir):
+ path, _ = os.path.split(path)
+ media_path = os.path.join(path, media)
+ if os.path.isdir(media_path):
+ module_media_path = os.path.join(media_path, 'invariant_media')
+ if os.path.isdir(module_media_path):
+ return module_media_path
+ return media_path
+
+ raise RuntimeError('Could not find invariant media files')
+
+def data_files():
+ """
+ Return the data files associated with media invariant.
+
+ The format is a list of (directory, [files...]) pairs which can be
+ used directly in setup(...,data_files=...) for setup.py.
+
+ """
+ data_files = []
+ data_files.append(('media/invariant_media', findall(get_data_path("media"))))
return data_files
\ No newline at end of file
diff --git a/src/sas/sasgui/perspectives/invariant/invariant.py b/src/sas/sasgui/perspectives/invariant/invariant.py
index 5b668fc..eeb7b6b 100644
--- a/src/sas/sasgui/perspectives/invariant/invariant.py
+++ b/src/sas/sasgui/perspectives/invariant/invariant.py
@@ -1,357 +1,359 @@
-
-
-
-################################################################################
-# This software was developed by the University of Tennessee as part of the
-# Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
-# project funded by the US National Science Foundation.
-#
-# See the license text in license.txt
-#
-# copyright 2009, University of Tennessee
-################################################################################
-
-
-import sys
-import wx
-import copy
-import logging
-from sas.sasgui.guiframe.gui_manager import MDIFrame
-from sas.sasgui.guiframe.dataFitting import Data1D
-from sas.sasgui.guiframe.events import NewPlotEvent
-from sas.sasgui.guiframe.events import StatusEvent
-from sas.sasgui.guiframe.gui_style import GUIFRAME_ID
-from sas.sasgui.perspectives.invariant.invariant_state import Reader as reader
-from sas.sascalc.dataloader.loader import Loader
-from sas.sasgui.perspectives.invariant.invariant_panel import InvariantPanel
-from sas.sasgui.guiframe.plugin_base import PluginBase
-
-class Plugin(PluginBase):
- """
- This class defines the interface for invariant Plugin class
- that can be used by the gui_manager.
- """
-
- def __init__(self):
- PluginBase.__init__(self, name="Invariant")
-
- # dictionary containing data name and error on dy of that data
- self.err_dy = {}
-
- # default state objects
- self.state_reader = None
- self._extensions = '.inv'
- self.temp_state = None
- self.__data = None
-
- # Log startup
- logging.info("Invariant plug-in started")
-
- def get_data(self):
- """
- """
- return self.__data
-
- def get_panels(self, parent):
- """
- Create and return the list of wx.Panels for your plug-in.
- Define the plug-in perspective.
-
- Panels should inherit from DefaultPanel defined below,
- or should present the same interface. They must define
- "window_caption" and "window_name".
-
- :param parent: parent window
-
- :return: list of panels
- """
- # # Save a reference to the parent
- self.parent = parent
- self.frame = MDIFrame(self.parent, None, 'None', (100, 200))
- self.invariant_panel = InvariantPanel(parent=self.frame)
- self.frame.set_panel(self.invariant_panel)
- self._frame_set_helper()
- self.invariant_panel.set_manager(manager=self)
- self.perspective.append(self.invariant_panel.window_name)
- # Create reader when fitting panel are created
- self.state_reader = reader(self.set_state)
- # append that reader to list of available reader
- loader = Loader()
- loader.associate_file_reader(".inv", self.state_reader)
- # loader.associate_file_reader(".svs", self.state_reader)
- # Return the list of panels
- return [self.invariant_panel]
-
- def get_context_menu(self, plotpanel=None):
- """
- This method is optional.
-
- When the context menu of a plot is rendered, the
- get_context_menu method will be called to give you a
- chance to add a menu item to the context menu.
-
- A ref to a Graph object is passed so that you can
- investigate the plot content and decide whether you
- need to add items to the context menu.
-
- This method returns a list of menu items.
- Each item is itself a list defining the text to
- appear in the menu, a tool-tip help text, and a
- call-back method.
-
- :param graph: the Graph object to which we attach the context menu
-
- :return: a list of menu items with call-back function
- """
- graph = plotpanel.graph
- invariant_option = "Compute invariant"
- invariant_hint = "Will displays the invariant panel for"
- invariant_hint += " further computation"
-
- if graph.selected_plottable not in plotpanel.plots:
- return []
- data = plotpanel.plots[graph.selected_plottable]
-
- if issubclass(data.__class__, Data1D):
- if data.name != "$I_{obs}(q)$" and data.name != " $P_{fit}(r)$":
- return [[invariant_option, invariant_hint, self._compute_invariant]]
- return []
-
- def _compute_invariant(self, event):
- """
- Open the invariant panel to invariant computation
- """
- self.panel = event.GetEventObject()
- Plugin.on_perspective(self, event=event)
- id = self.panel.graph.selected_plottable
- data = self.panel.plots[self.panel.graph.selected_plottable]
- if data is None:
- return
- if not issubclass(data.__class__, Data1D):
- name = data.__class__.__name__
- msg = "Invariant use only Data1D got: [%s] " % str(name)
- raise ValueError, msg
- self.compute_helper(data=data)
-
- def set_data(self, data_list=None):
- """
- receive a list of data and compute invariant
- """
- msg = ""
- data = None
- if data_list is None:
- data_list = []
- if len(data_list) >= 1:
- if len(data_list) == 1:
- data = data_list[0]
- else:
- data_1d_list = []
- data_2d_list = []
- error_msg = ""
- # separate data into data1d and data2d list
- for data in data_list:
- if data is not None:
- if issubclass(data.__class__, Data1D):
- data_1d_list.append(data)
- else:
- error_msg += " %s type %s \n" % (str(data.name),
- str(data.__class__.__name__))
- data_2d_list.append(data)
- if len(data_2d_list) > 0:
- msg = "Invariant does not support the following data types:\n"
- msg += error_msg
- if len(data_1d_list) == 0:
- wx.PostEvent(self.parent, StatusEvent(status=msg, info='error'))
- return
- msg += "Invariant panel does not allow multiple data!\n"
- msg += "Please select one.\n"
- if len(data_list) > 1:
- from invariant_widgets import DataDialog
- dlg = DataDialog(data_list=data_1d_list, text=msg)
- if dlg.ShowModal() == wx.ID_OK:
- data = dlg.get_data()
- else:
- data = None
- dlg.Destroy()
-
- if data is None:
- msg += "invariant receives no data. \n"
- wx.PostEvent(self.parent, StatusEvent(status=msg, info='error'))
- return
- if not issubclass(data.__class__, Data1D):
- msg += "invariant cannot be computed for data of "
- msg += "type %s\n" % (data.__class__.__name__)
- wx.PostEvent(self.parent, StatusEvent(status=msg, info='error'))
- return
- else:
- wx.PostEvent(self.parent, NewPlotEvent(plot=data, title=data.title))
- try:
- self.compute_helper(data)
- except:
- msg = "Invariant Set_data: " + str(sys.exc_value)
- wx.PostEvent(self.parent, StatusEvent(status=msg, info="error"))
- else:
- msg = "invariant cannot be computed for data of "
- msg += "type %s" % (data.__class__.__name__)
- wx.PostEvent(self.parent, StatusEvent(status=msg, info='error'))
-
- def delete_data(self, data_id):
- """
- """
- if self.__data is None:
- return
- for id in data_id:
- if id == self.__data.id:
- self.clear_panel()
-
- def clear_panel(self):
- """
- """
- self.invariant_panel.clear_panel()
-
- def compute_helper(self, data):
- """
- """
- if data is None:
- return
- # set current data if not it's a state data
- if not self.invariant_panel.is_state_data:
- # Store reference to data
- self.__data = data
- # Set the data set to be user for invariant calculation
- self.invariant_panel.set_data(data=data)
-
- def save_file(self, filepath, state=None):
- """
- Save data in provided state object.
-
- :param filepath: path of file to write to
- :param state: invariant state
- """
- # Write the state to file
- # First, check that the data is of the right type
- current_plottable = self.__data
-
- if issubclass(current_plottable.__class__, Data1D):
- self.state_reader.write(filepath, current_plottable, state)
- else:
- msg = "invariant.save_file: the data being saved is"
- msg += " not a sas.sascalc.dataloader.data_info.Data1D object"
- raise RuntimeError, msg
-
- def set_state(self, state=None, datainfo=None):
- """
- Call-back method for the state reader.
- This method is called when a .inv/.svs file is loaded.
-
- :param state: State object
- """
- self.temp_state = None
- try:
- if datainfo.__class__.__name__ == 'list':
- data = datainfo[0]
- else:
- data = datainfo
- if data is None:
- msg = "invariant.set_state: datainfo parameter cannot"
- msg += " be None in standalone mode"
- raise RuntimeError, msg
- # Make sure the user sees the invariant panel after loading
- # self.parent.set_perspective(self.perspective)
- self.on_perspective(event=None)
- name = data.meta_data['invstate'].file
- data.meta_data['invstate'].file = name
- data.name = name
- data.filename = name
-
- data = self.parent.create_gui_data(data, None)
- self.__data = data
- wx.PostEvent(self.parent, NewPlotEvent(plot=self.__data,
- reset=True, title=self.__data.title))
- data_dict = {self.__data.id:self.__data}
- self.parent.add_data(data_list=data_dict)
- # set state
- self.invariant_panel.is_state_data = True
-
- # Load the invariant states
- self.temp_state = state
- # Requires to have self.__data and self.temp_state first.
- self.on_set_state_helper(None)
-
- except:
- logging.error("invariant.set_state: %s" % sys.exc_value)
-
- def on_set_state_helper(self, event=None):
- """
- Set the state when called by EVT_STATE_UPDATE event from guiframe
- after a .inv/.svs file is loaded
- """
- self.invariant_panel.set_state(state=self.temp_state,
- data=self.__data)
- self.temp_state = None
-
-
- def plot_theory(self, data=None, name=None):
- """
- Receive a data set and post a NewPlotEvent to parent.
-
- :param data: extrapolated data to be plotted
- :param name: Data's name to use for the legend
- """
- # import copy
- if data is None:
- id = str(self.__data.id) + name
- group_id = self.__data.group_id
- wx.PostEvent(self.parent, NewPlotEvent(id=id, group_id=group_id, action='Remove'))
- return
-
- new_plot = Data1D(x=[], y=[], dy=None)
- new_plot.symbol = GUIFRAME_ID.CURVE_SYMBOL_NUM
- scale = self.invariant_panel.get_scale()
- background = self.invariant_panel.get_background()
-
- if scale != 0:
- # Put back the sacle and bkg for plotting
- data.y = (data.y + background) / scale
- new_plot = Data1D(x=data.x, y=data.y, dy=None)
- new_plot.symbol = GUIFRAME_ID.CURVE_SYMBOL_NUM
- else:
- msg = "Scale can not be zero."
- raise ValueError, msg
- if len(new_plot.x) == 0:
- return
-
- new_plot.name = name
- new_plot.xaxis(self.__data._xaxis, self.__data._xunit)
- new_plot.yaxis(self.__data._yaxis, self.__data._yunit)
- new_plot.group_id = self.__data.group_id
- new_plot.id = str(self.__data.id) + name
- new_plot.title = self.__data.title
- # Save theory_data in a state
- if data != None:
- name_head = name.split('-')
- if name_head[0] == 'Low':
- self.invariant_panel.state.theory_lowQ = copy.deepcopy(new_plot)
- elif name_head[0] == 'High':
- self.invariant_panel.state.theory_highQ = copy.deepcopy(new_plot)
-
- self.parent.update_theory(data_id=self.__data.id, theory=new_plot)
- wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot,
- title=self.__data.title))
-
- def plot_data(self, scale, background):
- """
- replot the current data if the user enters a new scale or background
- """
- new_plot = scale * self.__data - background
- new_plot.name = self.__data.name
- new_plot.group_id = self.__data.group_id
- new_plot.id = self.__data.id
- new_plot.title = self.__data.title
-
- # Save data in a state: but seems to never happen
- if new_plot != None:
- self.invariant_panel.state.data = copy.deepcopy(new_plot)
- wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot,
- title=new_plot.title))
-
+
+
+
+################################################################################
+# This software was developed by the University of Tennessee as part of the
+# Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
+# project funded by the US National Science Foundation.
+#
+# See the license text in license.txt
+#
+# copyright 2009, University of Tennessee
+################################################################################
+
+
+import sys
+import wx
+import copy
+import logging
+from sas.sasgui.guiframe.gui_manager import MDIFrame
+from sas.sasgui.guiframe.dataFitting import Data1D
+from sas.sasgui.guiframe.events import NewPlotEvent
+from sas.sasgui.guiframe.events import StatusEvent
+from sas.sasgui.guiframe.gui_style import GUIFRAME_ID
+from sas.sasgui.perspectives.invariant.invariant_state import Reader as reader
+from sas.sascalc.dataloader.loader import Loader
+from sas.sasgui.perspectives.invariant.invariant_panel import InvariantPanel
+from sas.sasgui.guiframe.plugin_base import PluginBase
+
+logger = logging.getLogger(__name__)
+
+class Plugin(PluginBase):
+ """
+ This class defines the interface for invariant Plugin class
+ that can be used by the gui_manager.
+ """
+
+ def __init__(self):
+ PluginBase.__init__(self, name="Invariant")
+
+ # dictionary containing data name and error on dy of that data
+ self.err_dy = {}
+
+ # default state objects
+ self.state_reader = None
+ self._extensions = '.inv'
+ self.temp_state = None
+ self.__data = None
+
+ # Log startup
+ logger.info("Invariant plug-in started")
+
+ def get_data(self):
+ """
+ """
+ return self.__data
+
+ def get_panels(self, parent):
+ """
+ Create and return the list of wx.Panels for your plug-in.
+ Define the plug-in perspective.
+
+ Panels should inherit from DefaultPanel defined below,
+ or should present the same interface. They must define
+ "window_caption" and "window_name".
+
+ :param parent: parent window
+
+ :return: list of panels
+ """
+ # # Save a reference to the parent
+ self.parent = parent
+ self.frame = MDIFrame(self.parent, None, 'None', (100, 200))
+ self.invariant_panel = InvariantPanel(parent=self.frame)
+ self.frame.set_panel(self.invariant_panel)
+ self._frame_set_helper()
+ self.invariant_panel.set_manager(manager=self)
+ self.perspective.append(self.invariant_panel.window_name)
+ # Create reader when fitting panel are created
+ self.state_reader = reader(self.set_state)
+ # append that reader to list of available reader
+ loader = Loader()
+ loader.associate_file_reader(".inv", self.state_reader)
+ # loader.associate_file_reader(".svs", self.state_reader)
+ # Return the list of panels
+ return [self.invariant_panel]
+
+ def get_context_menu(self, plotpanel=None):
+ """
+ This method is optional.
+
+ When the context menu of a plot is rendered, the
+ get_context_menu method will be called to give you a
+ chance to add a menu item to the context menu.
+
+ A ref to a Graph object is passed so that you can
+ investigate the plot content and decide whether you
+ need to add items to the context menu.
+
+ This method returns a list of menu items.
+ Each item is itself a list defining the text to
+ appear in the menu, a tool-tip help text, and a
+ call-back method.
+
+ :param graph: the Graph object to which we attach the context menu
+
+ :return: a list of menu items with call-back function
+ """
+ graph = plotpanel.graph
+ invariant_option = "Compute invariant"
+ invariant_hint = "Will displays the invariant panel for"
+ invariant_hint += " further computation"
+
+ if graph.selected_plottable not in plotpanel.plots:
+ return []
+ data = plotpanel.plots[graph.selected_plottable]
+
+ if issubclass(data.__class__, Data1D):
+ if data.name != "$I_{obs}(q)$" and data.name != " $P_{fit}(r)$":
+ return [[invariant_option, invariant_hint, self._compute_invariant]]
+ return []
+
+ def _compute_invariant(self, event):
+ """
+ Open the invariant panel to invariant computation
+ """
+ self.panel = event.GetEventObject()
+ Plugin.on_perspective(self, event=event)
+ id = self.panel.graph.selected_plottable
+ data = self.panel.plots[self.panel.graph.selected_plottable]
+ if data is None:
+ return
+ if not issubclass(data.__class__, Data1D):
+ name = data.__class__.__name__
+ msg = "Invariant use only Data1D got: [%s] " % str(name)
+ raise ValueError, msg
+ self.compute_helper(data=data)
+
+ def set_data(self, data_list=None):
+ """
+ receive a list of data and compute invariant
+ """
+ msg = ""
+ data = None
+ if data_list is None:
+ data_list = []
+ if len(data_list) >= 1:
+ if len(data_list) == 1:
+ data = data_list[0]
+ else:
+ data_1d_list = []
+ data_2d_list = []
+ error_msg = ""
+ # separate data into data1d and data2d list
+ for data in data_list:
+ if data is not None:
+ if issubclass(data.__class__, Data1D):
+ data_1d_list.append(data)
+ else:
+ error_msg += " %s type %s \n" % (str(data.name),
+ str(data.__class__.__name__))
+ data_2d_list.append(data)
+ if len(data_2d_list) > 0:
+ msg = "Invariant does not support the following data types:\n"
+ msg += error_msg
+ if len(data_1d_list) == 0:
+ wx.PostEvent(self.parent, StatusEvent(status=msg, info='error'))
+ return
+ msg += "Invariant panel does not allow multiple data!\n"
+ msg += "Please select one.\n"
+ if len(data_list) > 1:
+ from invariant_widgets import DataDialog
+ dlg = DataDialog(data_list=data_1d_list, text=msg)
+ if dlg.ShowModal() == wx.ID_OK:
+ data = dlg.get_data()
+ else:
+ data = None
+ dlg.Destroy()
+
+ if data is None:
+ msg += "invariant receives no data. \n"
+ wx.PostEvent(self.parent, StatusEvent(status=msg, info='error'))
+ return
+ if not issubclass(data.__class__, Data1D):
+ msg += "invariant cannot be computed for data of "
+ msg += "type %s\n" % (data.__class__.__name__)
+ wx.PostEvent(self.parent, StatusEvent(status=msg, info='error'))
+ return
+ else:
+ wx.PostEvent(self.parent, NewPlotEvent(plot=data, title=data.title))
+ try:
+ self.compute_helper(data)
+ except:
+ msg = "Invariant Set_data: " + str(sys.exc_value)
+ wx.PostEvent(self.parent, StatusEvent(status=msg, info="error"))
+ else:
+ msg = "invariant cannot be computed for data of "
+ msg += "type %s" % (data.__class__.__name__)
+ wx.PostEvent(self.parent, StatusEvent(status=msg, info='error'))
+
+ def delete_data(self, data_id):
+ """
+ """
+ if self.__data is None:
+ return
+ for id in data_id:
+ if id == self.__data.id:
+ self.clear_panel()
+
+ def clear_panel(self):
+ """
+ """
+ self.invariant_panel.clear_panel()
+
+ def compute_helper(self, data):
+ """
+ """
+ if data is None:
+ return
+ # set current data if not it's a state data
+ if not self.invariant_panel.is_state_data:
+ # Store reference to data
+ self.__data = data
+ # Set the data set to be user for invariant calculation
+ self.invariant_panel.set_data(data=data)
+
+ def save_file(self, filepath, state=None):
+ """
+ Save data in provided state object.
+
+ :param filepath: path of file to write to
+ :param state: invariant state
+ """
+ # Write the state to file
+ # First, check that the data is of the right type
+ current_plottable = self.__data
+
+ if issubclass(current_plottable.__class__, Data1D):
+ self.state_reader.write(filepath, current_plottable, state)
+ else:
+ msg = "invariant.save_file: the data being saved is"
+ msg += " not a sas.sascalc.dataloader.data_info.Data1D object"
+ raise RuntimeError, msg
+
+ def set_state(self, state=None, datainfo=None):
+ """
+ Call-back method for the state reader.
+ This method is called when a .inv/.svs file is loaded.
+
+ :param state: State object
+ """
+ self.temp_state = None
+ try:
+ if datainfo.__class__.__name__ == 'list':
+ data = datainfo[0]
+ else:
+ data = datainfo
+ if data is None:
+ msg = "invariant.set_state: datainfo parameter cannot"
+ msg += " be None in standalone mode"
+ raise RuntimeError, msg
+ # Make sure the user sees the invariant panel after loading
+ # self.parent.set_perspective(self.perspective)
+ self.on_perspective(event=None)
+ name = data.meta_data['invstate'].file
+ data.meta_data['invstate'].file = name
+ data.name = name
+ data.filename = name
+
+ data = self.parent.create_gui_data(data, None)
+ self.__data = data
+ wx.PostEvent(self.parent, NewPlotEvent(plot=self.__data,
+ reset=True, title=self.__data.title))
+ data_dict = {self.__data.id:self.__data}
+ self.parent.add_data(data_list=data_dict)
+ # set state
+ self.invariant_panel.is_state_data = True
+
+ # Load the invariant states
+ self.temp_state = state
+ # Requires to have self.__data and self.temp_state first.
+ self.on_set_state_helper(None)
+
+ except:
+ logger.error("invariant.set_state: %s" % sys.exc_value)
+
+ def on_set_state_helper(self, event=None):
+ """
+ Set the state when called by EVT_STATE_UPDATE event from guiframe
+ after a .inv/.svs file is loaded
+ """
+ self.invariant_panel.set_state(state=self.temp_state,
+ data=self.__data)
+ self.temp_state = None
+
+
+ def plot_theory(self, data=None, name=None):
+ """
+ Receive a data set and post a NewPlotEvent to parent.
+
+ :param data: extrapolated data to be plotted
+ :param name: Data's name to use for the legend
+ """
+ # import copy
+ if data is None:
+ id = str(self.__data.id) + name
+ group_id = self.__data.group_id
+ wx.PostEvent(self.parent, NewPlotEvent(id=id, group_id=group_id, action='Remove'))
+ return
+
+ new_plot = Data1D(x=[], y=[], dy=None)
+ new_plot.symbol = GUIFRAME_ID.CURVE_SYMBOL_NUM
+ scale = self.invariant_panel.get_scale()
+ background = self.invariant_panel.get_background()
+
+ if scale != 0:
+ # Put back the sacle and bkg for plotting
+ data.y = (data.y + background) / scale
+ new_plot = Data1D(x=data.x, y=data.y, dy=None)
+ new_plot.symbol = GUIFRAME_ID.CURVE_SYMBOL_NUM
+ else:
+ msg = "Scale can not be zero."
+ raise ValueError, msg
+ if len(new_plot.x) == 0:
+ return
+
+ new_plot.name = name
+ new_plot.xaxis(self.__data._xaxis, self.__data._xunit)
+ new_plot.yaxis(self.__data._yaxis, self.__data._yunit)
+ new_plot.group_id = self.__data.group_id
+ new_plot.id = str(self.__data.id) + name
+ new_plot.title = self.__data.title
+ # Save theory_data in a state
+ if data is not None:
+ name_head = name.split('-')
+ if name_head[0] == 'Low':
+ self.invariant_panel.state.theory_lowQ = copy.deepcopy(new_plot)
+ elif name_head[0] == 'High':
+ self.invariant_panel.state.theory_highQ = copy.deepcopy(new_plot)
+
+ self.parent.update_theory(data_id=self.__data.id, theory=new_plot)
+ wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot,
+ title=self.__data.title))
+
+ def plot_data(self, scale, background):
+ """
+ replot the current data if the user enters a new scale or background
+ """
+ new_plot = scale * self.__data - background
+ new_plot.name = self.__data.name
+ new_plot.group_id = self.__data.group_id
+ new_plot.id = self.__data.id
+ new_plot.title = self.__data.title
+
+ # Save data in a state: but seems to never happen
+ if new_plot is not None:
+ self.invariant_panel.state.data = copy.deepcopy(new_plot)
+ wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot,
+ title=new_plot.title))
+
diff --git a/src/sas/sasgui/perspectives/invariant/invariant_details.py b/src/sas/sasgui/perspectives/invariant/invariant_details.py
index dc413b3..7d70e91 100644
--- a/src/sas/sasgui/perspectives/invariant/invariant_details.py
+++ b/src/sas/sasgui/perspectives/invariant/invariant_details.py
@@ -1,542 +1,542 @@
-"""
- Invariant panel
-"""
-import wx
-import sys
-
-from sas.sasgui.guiframe.utils import format_number
-from invariant_widgets import OutputTextCtrl
-# Dimensions related to chart
-RECTANGLE_WIDTH = 400.0
-RECTANGLE_HEIGHT = 20
-# Invariant panel size
-_BOX_WIDTH = 76
-
-# scale to use for a bar of value zero
-RECTANGLE_SCALE = 0.0001
-DEFAULT_QSTAR = 1.0
-
-if sys.platform.count("win32") > 0:
- _STATICBOX_WIDTH = 450
- PANEL_WIDTH = 500
- PANEL_HEIGHT = 430
- FONT_VARIANT = 0
-else:
- _STATICBOX_WIDTH = 480
- PANEL_WIDTH = 530
- PANEL_HEIGHT = 430
- FONT_VARIANT = 1
-
-ERROR_COLOR = wx.Colour(255, 0, 0, 128)
-EXTRAPOLATION_COLOR = wx.Colour(169, 169, 168, 128)
-INVARIANT_COLOR = wx.Colour(67, 208, 128, 128)
-
-
-class InvariantContainer(wx.Object):
- """
- This class stores some values resulting resulting from invariant
- calculations. Given the value of total invariant, this class can also
- determine the percentage of invariants resulting from extrapolation.
- """
- def __init__(self):
- # invariant at low range
- self.qstar_low = None
- # invariant at low range error
- self.qstar_low_err = None
- # invariant
- self.qstar = None
- # invariant error
- self.qstar_err = None
- # invariant at high range
- self.qstar_high = None
- # invariant at high range error
- self.qstar_high_err = None
- # invariant total
- self.qstar_total = None
- # invariant error
- self.qstar_total_err = None
- # scale
- self.qstar_low_percent = None
- self.qstar_high_percent = None
- self.qstar_percent = None
- # warning message
- self.existing_warning = False
- self.warning_msg = "No Details on calculations available...\n"
-
- def compute_percentage(self):
- """
- Compute percentage of each invariant
- """
- if self.qstar_total is None:
- self.qstar_percent = None
- self.qstar_low = None
- self.qstar_high = None
- self.check_values()
- return
-
- # compute invariant percentage
- if self.qstar is None:
- self.qstar_percent = None
- else:
- try:
- self.qstar_percent = float(self.qstar) / float(self.qstar_total)
- except:
- self.qstar_percent = 'error'
- # compute low q invariant percentage
- if self.qstar_low is None:
- self.qstar_low_percent = None
- else:
- try:
- self.qstar_low_percent = float(self.qstar_low)\
- / float(self.qstar_total)
- except:
- self.qstar_low_percent = 'error'
- # compute high q invariant percentage
- if self.qstar_high is None:
- self.qstar_high_percent = None
- else:
- try:
- self.qstar_high_percent = float(self.qstar_high)\
- / float(self.qstar_total)
- except:
- self.qstar_high_percent = 'error'
- wx.CallAfter(self.check_values)
-
- def check_values(self):
- """
- check the validity if invariant
- """
- if self.qstar_total is None and self.qstar is None:
- self.warning_msg = "Invariant not calculated.\n"
- return
- if self.qstar_total == 0:
- self.existing_warning = True
- self.warning_msg = "Invariant is zero. \n"
- self.warning_msg += "The calculations are likely "
- self.warning_msg += "to be unreliable!\n"
- return
- # warning to the user when the extrapolated invariant is greater than %5
- msg = ''
- if self.qstar_percent == 'error':
- try:
- float(self.qstar)
- except:
- self.existing_warning = True
- msg += 'Error occurred when computing invariant from data.\n '
- if self.qstar_percent > 1:
- self.existing_warning = True
- msg += "Invariant Q contribution is greater "
- msg += "than 100% .\n"
- if self.qstar_low_percent == 'error':
- try:
- float(self.qstar_low)
- except:
- self.existing_warning = True
- msg += "Error occurred when computing extrapolated invariant"
- msg += " at low-Q region.\n"
- elif self.qstar_low_percent is not None:
- if self.qstar_low_percent >= 0.05:
- self.existing_warning = True
- msg += "Extrapolated contribution at Low Q is higher "
- msg += "than 5% of the invariant.\n"
- elif self.qstar_low_percent < 0:
- self.existing_warning = True
- msg += "Extrapolated contribution at Low Q < 0.\n"
- elif self.qstar_low_percent > 1:
- self.existing_warning = True
- msg += "Extrapolated contribution at Low Q is greater "
- msg += "than 100% .\n"
- if self.qstar_high_percent == 'error':
- try:
- float(self.qstar_high)
- except:
- self.existing_warning = True
- msg += 'Error occurred when computing extrapolated'
- msg += ' invariant at high-Q region.\n'
- elif self.qstar_high_percent is not None:
- if self.qstar_high_percent >= 0.05:
- self.existing_warning = True
- msg += "Extrapolated contribution at High Q is higher "
- msg += "than 5% of the invariant.\n"
- elif self.qstar_high_percent < 0:
- self.existing_warning = True
- msg += "Extrapolated contribution at High Q < 0.\n"
- elif self.qstar_high_percent > 1:
- self.existing_warning = True
- msg += "Extrapolated contribution at High Q is greater "
- msg += "than 100% .\n"
- if (self.qstar_low_percent not in [None, "error"]) and \
- (self.qstar_high_percent not in [None, "error"])\
- and self.qstar_low_percent + self.qstar_high_percent >= 0.05:
- self.existing_warning = True
- msg += "The sum of all extrapolated contributions is higher "
- msg += "than 5% of the invariant.\n"
-
- if self.existing_warning:
- self.warning_msg = ''
- self.warning_msg += msg
- self.warning_msg += "The calculations are likely to be"
- self.warning_msg += " unreliable!\n"
- else:
- self.warning_msg = "No Details on calculations available...\n"
-
-class InvariantDetailsPanel(wx.Dialog):
- """
- This panel describes proportion of invariants
- """
- def __init__(self, parent=None, id=-1, qstar_container=None,
- title="Invariant Details",
- size=(PANEL_WIDTH, PANEL_HEIGHT)):
- wx.Dialog.__init__(self, parent=parent, id=id, title=title, size=size)
-
- # Font size
- self.SetWindowVariant(variant=FONT_VARIANT)
- self.parent = parent
- # self.qstar_container
- self.qstar_container = qstar_container
- # warning message
- self.warning_msg = self.qstar_container.warning_msg
-
- # Define scale of each bar
- self.low_inv_percent = self.qstar_container.qstar_low_percent
- self.low_scale = self.get_scale(percentage=self.low_inv_percent,
- scale_name="Extrapolated at Low Q")
- self.inv_percent = self.qstar_container.qstar_percent
- self.inv_scale = self.get_scale(percentage=self.inv_percent,
- scale_name="Inv in Q range")
- self.high_inv_percent = self.qstar_container.qstar_high_percent
- self.high_scale = self.get_scale(percentage=self.high_inv_percent,
- scale_name="Extrapolated at High Q")
-
- # Default color the extrapolation bar is grey
- self.extrapolation_color_low = EXTRAPOLATION_COLOR
- self.extrapolation_color_high = EXTRAPOLATION_COLOR
- self.invariant_color = INVARIANT_COLOR
- # change color of high and low bar when necessary
- self.set_color_bar()
- # draw the panel itself
- self._do_layout()
- self.set_values()
-
- def _define_structure(self):
- """
- Define main sizers needed for this panel
- """
- # Box sizers must be defined first before defining buttons/textctrls
- # (MAC).
- self.main_sizer = wx.BoxSizer(wx.VERTICAL)
- # Sizer related to chart
- chart_box = wx.StaticBox(self, -1, "Invariant Chart")
- self.chart_sizer = wx.StaticBoxSizer(chart_box, wx.VERTICAL)
- self.chart_sizer.SetMinSize((PANEL_WIDTH - 50, 110))
- # Sizer related to invariant values
- self.invariant_sizer = wx.GridBagSizer(4, 4)
- invariant_box = wx.StaticBox(self, -1, "Numerical Values")
- self.invariant_box_sizer = wx.StaticBoxSizer(invariant_box, wx.HORIZONTAL)
-
- self.invariant_box_sizer.SetMinSize((PANEL_WIDTH - 50, -1))
- # Sizer related to warning message
- warning_box = wx.StaticBox(self, -1, "Warning")
- self.warning_sizer = wx.StaticBoxSizer(warning_box, wx.VERTICAL)
- self.warning_sizer.SetMinSize((PANEL_WIDTH - 50, -1))
- # Sizer related to button
- self.button_sizer = wx.BoxSizer(wx.HORIZONTAL)
-
- def _layout_shart(self):
- """
- Draw widgets related to chart
- """
- self.panel_chart = wx.Panel(self)
- self.panel_chart.Bind(wx.EVT_PAINT, self.on_paint)
- self.chart_sizer.Add(self.panel_chart, 1, wx.EXPAND | wx.ALL, 0)
-
- def _layout_invariant(self):
- """
- Draw widgets related to invariant
- """
- uncertainty = "+/-"
- unit_invariant = '[1/(cm * A^3)]'
-
- invariant_txt = wx.StaticText(self, -1, 'Q* from Data ')
- invariant_txt.SetToolTipString("Invariant in the data set's Q range.")
- self.invariant_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH, -1))
- hint_msg = "Invariant in the data set's Q range."
- self.invariant_tcl.SetToolTipString(hint_msg)
- self.invariant_err_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH, -1))
- hint_msg = "Uncertainty on the invariant from data's range."
- self.invariant_err_tcl.SetToolTipString(hint_msg)
- invariant_units_txt = wx.StaticText(self, -1, unit_invariant)
- hint_msg = "Unit of the invariant from data's Q range"
- invariant_units_txt.SetToolTipString(hint_msg)
-
- invariant_low_txt = wx.StaticText(self, -1, 'Q* from Low-Q')
- hint_msg = "Extrapolated invariant from low-Q range."
- invariant_low_txt.SetToolTipString(hint_msg)
- self.invariant_low_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH, -1))
- hint_msg = "Extrapolated invariant from low-Q range."
- self.invariant_low_tcl.SetToolTipString(hint_msg)
- self.invariant_low_err_tcl = OutputTextCtrl(self, -1,
- size=(_BOX_WIDTH, -1))
- hint_msg = "Uncertainty on the invariant from low-Q range."
- self.invariant_low_err_tcl.SetToolTipString(hint_msg)
- invariant_low_units_txt = wx.StaticText(self, -1, unit_invariant)
- hint_msg = "Unit of the extrapolated invariant from low-Q range"
- invariant_low_units_txt.SetToolTipString(hint_msg)
-
- invariant_high_txt = wx.StaticText(self, -1, 'Q* from High-Q')
- hint_msg = "Extrapolated invariant from high-Q range"
- invariant_high_txt.SetToolTipString(hint_msg)
- self.invariant_high_tcl = OutputTextCtrl(self, -1,
- size=(_BOX_WIDTH, -1))
- hint_msg = "Extrapolated invariant from high-Q range"
- self.invariant_high_tcl.SetToolTipString(hint_msg)
- self.invariant_high_err_tcl = OutputTextCtrl(self, -1,
- size=(_BOX_WIDTH, -1))
- hint_msg = "Uncertainty on the invariant from high-Q range."
- self.invariant_high_err_tcl.SetToolTipString(hint_msg)
- invariant_high_units_txt = wx.StaticText(self, -1, unit_invariant)
- hint_msg = "Unit of the extrapolated invariant from high-Q range"
- invariant_high_units_txt.SetToolTipString(hint_msg)
-
- # Invariant low
- iy = 0
- ix = 0
- self.invariant_sizer.Add(invariant_low_txt, (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- ix += 1
- self.invariant_sizer.Add(self.invariant_low_tcl, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 1
- self.invariant_sizer.Add(wx.StaticText(self, -1, uncertainty),
- (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 1
- self.invariant_sizer.Add(self.invariant_low_err_tcl, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 1
- self.invariant_sizer.Add(invariant_low_units_txt,
- (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- # Invariant
- iy += 1
- ix = 0
- self.invariant_sizer.Add(invariant_txt, (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- ix += 1
- self.invariant_sizer.Add(self.invariant_tcl, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 1
- self.invariant_sizer.Add(wx.StaticText(self, -1, uncertainty),
- (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 1
- self.invariant_sizer.Add(self.invariant_err_tcl, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 1
- self.invariant_sizer.Add(invariant_units_txt,
- (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- # Invariant high
- iy += 1
- ix = 0
- self.invariant_sizer.Add(invariant_high_txt, (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- ix += 1
- self.invariant_sizer.Add(self.invariant_high_tcl, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 1
- self.invariant_sizer.Add(wx.StaticText(self, -1, uncertainty),
- (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 1
- self.invariant_sizer.Add(self.invariant_high_err_tcl, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 1
- self.invariant_sizer.Add(invariant_high_units_txt,
- (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- self.invariant_box_sizer.Add(self.invariant_sizer, 0, wx.TOP | wx.BOTTOM, 10)
-
- def _layout_warning(self):
- """
- Draw widgets related to warning
- """
- # Warning [string]
- self.warning_msg_txt = wx.StaticText(self, -1, self.warning_msg)
- if self.qstar_container.existing_warning:
- self.warning_msg_txt.SetForegroundColour('red')
- self.warning_sizer.AddMany([(self.warning_msg_txt, 0,
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 10)])
-
- def _layout_button(self):
- """
- Draw widgets related to button
- """
- # Close button
- id = wx.NewId()
- button_ok = wx.Button(self, id, "Ok")
- button_ok.SetToolTipString("Give Details on Computation")
- self.Bind(wx.EVT_BUTTON, self.on_close, id=id)
- self.button_sizer.AddMany([((20, 20), 0, wx.LEFT, 350),
- (button_ok, 0, wx.RIGHT, 10)])
- def _do_layout(self):
- """
- Draw window content
- """
- self._define_structure()
- self._layout_shart()
- self._layout_invariant()
- self._layout_warning()
- self._layout_button()
- self.main_sizer.AddMany([(self.chart_sizer, 0, wx.ALL, 10),
- (self.invariant_box_sizer, 0, wx.ALL, 10),
- (self.warning_sizer, 0, wx.ALL, 10),
- (self.button_sizer, 0, wx.ALL, 10)])
- self.SetSizer(self.main_sizer)
-
-
- def set_values(self):
- """
- Set value of txtcrtl
- """
- value = format_number(self.qstar_container.qstar)
- self.invariant_tcl.SetValue(value)
- value = format_number(self.qstar_container.qstar_err)
- self.invariant_err_tcl.SetValue(value)
- value = format_number(self.qstar_container.qstar_low)
- self.invariant_low_tcl.SetValue(value)
- value = format_number(self.qstar_container.qstar_low_err)
- self.invariant_low_err_tcl.SetValue(value)
- value = format_number(self.qstar_container.qstar_high)
- self.invariant_high_tcl.SetValue(value)
- value = format_number(self.qstar_container.qstar_high_err)
- self.invariant_high_err_tcl.SetValue(value)
-
- def get_scale(self, percentage, scale_name='scale'):
- """
- Check scale receive in this panel.
- """
- scale = RECTANGLE_SCALE
- try:
- if percentage in [None, 0.0, "error"]:
- scale = RECTANGLE_SCALE
- return scale
- elif percentage < 0:
- scale = RECTANGLE_SCALE
- return scale
- scale = float(percentage)
- except:
- scale = RECTANGLE_SCALE
- self.warning_msg += "Recieve an invalid scale for %s\n"
- self.warning_msg += "check this value : %s\n" % str(percentage)
- return scale
-
- def set_color_bar(self):
- """
- Change the color for low and high bar when necessary
- """
- self.extrapolation_color_low = EXTRAPOLATION_COLOR
- self.extrapolation_color_high = EXTRAPOLATION_COLOR
- self.invariant_color = INVARIANT_COLOR
- # warning to the user when the extrapolated invariant is greater than %5
- if self.low_scale >= 0.05 or self.low_scale > 1 or self.low_scale < 0:
- self.extrapolation_color_low = ERROR_COLOR
- if self.high_scale >= 0.05 or self.high_scale > 1 or self.high_scale < 0:
- self.extrapolation_color_high = ERROR_COLOR
- if self.inv_scale > 1 or self.inv_scale < 0:
- self.invariant_color = ERROR_COLOR
-
- def on_close(self, event):
- """
- Close the current window
- """
- self.Close()
-
- def on_paint(self, event):
- """
- Draw the chart
- """
- dc = wx.PaintDC(self.panel_chart)
- try:
- gc = wx.GraphicsContext.Create(dc)
- except NotImplementedError:
- msg = "This build of wxPython does not support "
- msg += "the wx.GraphicsContext family of classes."
- dc.DrawText(msg, 25, 25)
- return
- # Start the drawing
- font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
- font.SetWeight(wx.BOLD)
- gc.SetFont(font)
- # Draw a rectangle
- path = gc.CreatePath()
- path.AddRectangle(-RECTANGLE_WIDTH / 2, -RECTANGLE_HEIGHT / 2,
- RECTANGLE_WIDTH / 2, RECTANGLE_HEIGHT / 2)
- x_origine = 20
- y_origine = 15
- # Draw low rectangle
- gc.PushState()
- label = "Q* from Low-Q "
- PathFunc = gc.DrawPath
- w, h = gc.GetTextExtent(label)
- gc.DrawText(label, x_origine, y_origine)
- # Translate the rectangle
- x_center = x_origine + RECTANGLE_WIDTH * self.low_scale / 2 + w + 10
- y_center = y_origine + h
- gc.Translate(x_center, y_center)
- gc.SetPen(wx.Pen("black", 1))
- gc.SetBrush(wx.Brush(self.extrapolation_color_low))
- if self.low_inv_percent is None:
- low_percent = 'Not Computed'
- elif self.low_inv_percent == 'error':
- low_percent = 'Error'
- else:
- low_percent = format_number(self.low_inv_percent * 100) + '%'
- x_center = 20
- y_center = -h
- gc.DrawText(low_percent, x_center, y_center)
- # Increase width by self.low_scale
- gc.Scale(self.low_scale, 1.0)
- PathFunc(path)
- gc.PopState()
- # Draw rectangle for invariant
- gc.PushState() # save it again
- y_origine += 20
- gc.DrawText("Q* from Data ", x_origine, y_origine)
- # offset to the lower part of the window
- x_center = x_origine + RECTANGLE_WIDTH * self.inv_scale / 2 + w + 10
- y_center = y_origine + h
- gc.Translate(x_center, y_center)
- # 128 == half transparent
- gc.SetBrush(wx.Brush(self.invariant_color))
- # Increase width by self.inv_scale
- if self.inv_percent is None:
- inv_percent = 'Not Computed'
- elif self.inv_percent == 'error':
- inv_percent = 'Error'
- else:
- inv_percent = format_number(self.inv_percent * 100) + '%'
- x_center = 20
- y_center = -h
- gc.DrawText(inv_percent, x_center, y_center)
- gc.Scale(self.inv_scale, 1.0)
- gc.DrawPath(path)
- gc.PopState()
- # restore saved state
- # Draw rectangle for high invariant
- gc.PushState()
- y_origine += 20
- gc.DrawText("Q* from High-Q ", x_origine, y_origine)
- # define the position of the new rectangle
- x_center = x_origine + RECTANGLE_WIDTH * self.high_scale / 2 + w + 10
- y_center = y_origine + h
- gc.Translate(x_center, y_center)
- gc.SetBrush(wx.Brush(self.extrapolation_color_high))
- # increase scale by self.high_scale
- if self.high_inv_percent is None:
- high_percent = 'Not Computed'
- elif self.high_inv_percent == 'error':
- high_percent = 'Error'
- else:
- high_percent = format_number(self.high_inv_percent * 100) + '%'
- x_center = 20
- y_center = -h
- gc.DrawText(high_percent, x_center, y_center)
-
- gc.Scale(self.high_scale, 1.0)
- gc.DrawPath(path)
- gc.PopState()
+"""
+ Invariant panel
+"""
+import wx
+import sys
+
+from sas.sasgui.guiframe.utils import format_number
+from invariant_widgets import OutputTextCtrl
+# Dimensions related to chart
+RECTANGLE_WIDTH = 400.0
+RECTANGLE_HEIGHT = 20
+# Invariant panel size
+_BOX_WIDTH = 76
+
+# scale to use for a bar of value zero
+RECTANGLE_SCALE = 0.0001
+DEFAULT_QSTAR = 1.0
+
+if sys.platform.count("win32") > 0:
+ _STATICBOX_WIDTH = 450
+ PANEL_WIDTH = 500
+ PANEL_HEIGHT = 430
+ FONT_VARIANT = 0
+else:
+ _STATICBOX_WIDTH = 480
+ PANEL_WIDTH = 530
+ PANEL_HEIGHT = 430
+ FONT_VARIANT = 1
+
+ERROR_COLOR = wx.Colour(255, 0, 0, 128)
+EXTRAPOLATION_COLOR = wx.Colour(169, 169, 168, 128)
+INVARIANT_COLOR = wx.Colour(67, 208, 128, 128)
+
+
+class InvariantContainer(wx.Object):
+ """
+ This class stores some values resulting resulting from invariant
+ calculations. Given the value of total invariant, this class can also
+ determine the percentage of invariants resulting from extrapolation.
+ """
+ def __init__(self):
+ # invariant at low range
+ self.qstar_low = None
+ # invariant at low range error
+ self.qstar_low_err = None
+ # invariant
+ self.qstar = None
+ # invariant error
+ self.qstar_err = None
+ # invariant at high range
+ self.qstar_high = None
+ # invariant at high range error
+ self.qstar_high_err = None
+ # invariant total
+ self.qstar_total = None
+ # invariant error
+ self.qstar_total_err = None
+ # scale
+ self.qstar_low_percent = None
+ self.qstar_high_percent = None
+ self.qstar_percent = None
+ # warning message
+ self.existing_warning = False
+ self.warning_msg = "No Details on calculations available...\n"
+
+ def compute_percentage(self):
+ """
+ Compute percentage of each invariant
+ """
+ if self.qstar_total is None:
+ self.qstar_percent = None
+ self.qstar_low = None
+ self.qstar_high = None
+ self.check_values()
+ return
+
+ # compute invariant percentage
+ if self.qstar is None:
+ self.qstar_percent = None
+ else:
+ try:
+ self.qstar_percent = float(self.qstar) / float(self.qstar_total)
+ except:
+ self.qstar_percent = 'error'
+ # compute low q invariant percentage
+ if self.qstar_low is None:
+ self.qstar_low_percent = None
+ else:
+ try:
+ self.qstar_low_percent = float(self.qstar_low)\
+ / float(self.qstar_total)
+ except:
+ self.qstar_low_percent = 'error'
+ # compute high q invariant percentage
+ if self.qstar_high is None:
+ self.qstar_high_percent = None
+ else:
+ try:
+ self.qstar_high_percent = float(self.qstar_high)\
+ / float(self.qstar_total)
+ except:
+ self.qstar_high_percent = 'error'
+ wx.CallAfter(self.check_values)
+
+ def check_values(self):
+ """
+ check the validity if invariant
+ """
+ if self.qstar_total is None and self.qstar is None:
+ self.warning_msg = "Invariant not calculated.\n"
+ return
+ if self.qstar_total == 0:
+ self.existing_warning = True
+ self.warning_msg = "Invariant is zero. \n"
+ self.warning_msg += "The calculations are likely "
+ self.warning_msg += "to be unreliable!\n"
+ return
+ # warning to the user when the extrapolated invariant is greater than %5
+ msg = ''
+ if self.qstar_percent == 'error':
+ try:
+ float(self.qstar)
+ except:
+ self.existing_warning = True
+ msg += 'Error occurred when computing invariant from data.\n '
+ if self.qstar_percent > 1:
+ self.existing_warning = True
+ msg += "Invariant Q contribution is greater "
+ msg += "than 100% .\n"
+ if self.qstar_low_percent == 'error':
+ try:
+ float(self.qstar_low)
+ except:
+ self.existing_warning = True
+ msg += "Error occurred when computing extrapolated invariant"
+ msg += " at low-Q region.\n"
+ elif self.qstar_low_percent is not None:
+ if self.qstar_low_percent >= 0.05:
+ self.existing_warning = True
+ msg += "Extrapolated contribution at Low Q is higher "
+ msg += "than 5% of the invariant.\n"
+ elif self.qstar_low_percent < 0:
+ self.existing_warning = True
+ msg += "Extrapolated contribution at Low Q < 0.\n"
+ elif self.qstar_low_percent > 1:
+ self.existing_warning = True
+ msg += "Extrapolated contribution at Low Q is greater "
+ msg += "than 100% .\n"
+ if self.qstar_high_percent == 'error':
+ try:
+ float(self.qstar_high)
+ except:
+ self.existing_warning = True
+ msg += 'Error occurred when computing extrapolated'
+ msg += ' invariant at high-Q region.\n'
+ elif self.qstar_high_percent is not None:
+ if self.qstar_high_percent >= 0.05:
+ self.existing_warning = True
+ msg += "Extrapolated contribution at High Q is higher "
+ msg += "than 5% of the invariant.\n"
+ elif self.qstar_high_percent < 0:
+ self.existing_warning = True
+ msg += "Extrapolated contribution at High Q < 0.\n"
+ elif self.qstar_high_percent > 1:
+ self.existing_warning = True
+ msg += "Extrapolated contribution at High Q is greater "
+ msg += "than 100% .\n"
+ if (self.qstar_low_percent not in [None, "error"]) and \
+ (self.qstar_high_percent not in [None, "error"])\
+ and self.qstar_low_percent + self.qstar_high_percent >= 0.05:
+ self.existing_warning = True
+ msg += "The sum of all extrapolated contributions is higher "
+ msg += "than 5% of the invariant.\n"
+
+ if self.existing_warning:
+ self.warning_msg = ''
+ self.warning_msg += msg
+ self.warning_msg += "The calculations are likely to be"
+ self.warning_msg += " unreliable!\n"
+ else:
+ self.warning_msg = "No Details on calculations available...\n"
+
+class InvariantDetailsPanel(wx.Dialog):
+ """
+ This panel describes proportion of invariants
+ """
+ def __init__(self, parent=None, id=-1, qstar_container=None,
+ title="Invariant Details",
+ size=(PANEL_WIDTH, PANEL_HEIGHT)):
+ wx.Dialog.__init__(self, parent=parent, id=id, title=title, size=size)
+
+ # Font size
+ self.SetWindowVariant(variant=FONT_VARIANT)
+ self.parent = parent
+ # self.qstar_container
+ self.qstar_container = qstar_container
+ # warning message
+ self.warning_msg = self.qstar_container.warning_msg
+
+ # Define scale of each bar
+ self.low_inv_percent = self.qstar_container.qstar_low_percent
+ self.low_scale = self.get_scale(percentage=self.low_inv_percent,
+ scale_name="Extrapolated at Low Q")
+ self.inv_percent = self.qstar_container.qstar_percent
+ self.inv_scale = self.get_scale(percentage=self.inv_percent,
+ scale_name="Inv in Q range")
+ self.high_inv_percent = self.qstar_container.qstar_high_percent
+ self.high_scale = self.get_scale(percentage=self.high_inv_percent,
+ scale_name="Extrapolated at High Q")
+
+ # Default color the extrapolation bar is grey
+ self.extrapolation_color_low = EXTRAPOLATION_COLOR
+ self.extrapolation_color_high = EXTRAPOLATION_COLOR
+ self.invariant_color = INVARIANT_COLOR
+ # change color of high and low bar when necessary
+ self.set_color_bar()
+ # draw the panel itself
+ self._do_layout()
+ self.set_values()
+
+ def _define_structure(self):
+ """
+ Define main sizers needed for this panel
+ """
+ # Box sizers must be defined first before defining buttons/textctrls
+ # (MAC).
+ self.main_sizer = wx.BoxSizer(wx.VERTICAL)
+ # Sizer related to chart
+ chart_box = wx.StaticBox(self, -1, "Invariant Chart")
+ self.chart_sizer = wx.StaticBoxSizer(chart_box, wx.VERTICAL)
+ self.chart_sizer.SetMinSize((PANEL_WIDTH - 50, 110))
+ # Sizer related to invariant values
+ self.invariant_sizer = wx.GridBagSizer(4, 4)
+ invariant_box = wx.StaticBox(self, -1, "Numerical Values")
+ self.invariant_box_sizer = wx.StaticBoxSizer(invariant_box, wx.HORIZONTAL)
+
+ self.invariant_box_sizer.SetMinSize((PANEL_WIDTH - 50, -1))
+ # Sizer related to warning message
+ warning_box = wx.StaticBox(self, -1, "Warning")
+ self.warning_sizer = wx.StaticBoxSizer(warning_box, wx.VERTICAL)
+ self.warning_sizer.SetMinSize((PANEL_WIDTH - 50, -1))
+ # Sizer related to button
+ self.button_sizer = wx.BoxSizer(wx.HORIZONTAL)
+
+ def _layout_shart(self):
+ """
+ Draw widgets related to chart
+ """
+ self.panel_chart = wx.Panel(self)
+ self.panel_chart.Bind(wx.EVT_PAINT, self.on_paint)
+ self.chart_sizer.Add(self.panel_chart, 1, wx.EXPAND | wx.ALL, 0)
+
+ def _layout_invariant(self):
+ """
+ Draw widgets related to invariant
+ """
+ uncertainty = "+/-"
+ unit_invariant = '[1/(cm * A^3)]'
+
+ invariant_txt = wx.StaticText(self, -1, 'Q* from Data ')
+ invariant_txt.SetToolTipString("Invariant in the data set's Q range.")
+ self.invariant_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH, -1))
+ hint_msg = "Invariant in the data set's Q range."
+ self.invariant_tcl.SetToolTipString(hint_msg)
+ self.invariant_err_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH, -1))
+ hint_msg = "Uncertainty on the invariant from data's range."
+ self.invariant_err_tcl.SetToolTipString(hint_msg)
+ invariant_units_txt = wx.StaticText(self, -1, unit_invariant)
+ hint_msg = "Unit of the invariant from data's Q range"
+ invariant_units_txt.SetToolTipString(hint_msg)
+
+ invariant_low_txt = wx.StaticText(self, -1, 'Q* from Low-Q')
+ hint_msg = "Extrapolated invariant from low-Q range."
+ invariant_low_txt.SetToolTipString(hint_msg)
+ self.invariant_low_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH, -1))
+ hint_msg = "Extrapolated invariant from low-Q range."
+ self.invariant_low_tcl.SetToolTipString(hint_msg)
+ self.invariant_low_err_tcl = OutputTextCtrl(self, -1,
+ size=(_BOX_WIDTH, -1))
+ hint_msg = "Uncertainty on the invariant from low-Q range."
+ self.invariant_low_err_tcl.SetToolTipString(hint_msg)
+ invariant_low_units_txt = wx.StaticText(self, -1, unit_invariant)
+ hint_msg = "Unit of the extrapolated invariant from low-Q range"
+ invariant_low_units_txt.SetToolTipString(hint_msg)
+
+ invariant_high_txt = wx.StaticText(self, -1, 'Q* from High-Q')
+ hint_msg = "Extrapolated invariant from high-Q range"
+ invariant_high_txt.SetToolTipString(hint_msg)
+ self.invariant_high_tcl = OutputTextCtrl(self, -1,
+ size=(_BOX_WIDTH, -1))
+ hint_msg = "Extrapolated invariant from high-Q range"
+ self.invariant_high_tcl.SetToolTipString(hint_msg)
+ self.invariant_high_err_tcl = OutputTextCtrl(self, -1,
+ size=(_BOX_WIDTH, -1))
+ hint_msg = "Uncertainty on the invariant from high-Q range."
+ self.invariant_high_err_tcl.SetToolTipString(hint_msg)
+ invariant_high_units_txt = wx.StaticText(self, -1, unit_invariant)
+ hint_msg = "Unit of the extrapolated invariant from high-Q range"
+ invariant_high_units_txt.SetToolTipString(hint_msg)
+
+ # Invariant low
+ iy = 0
+ ix = 0
+ self.invariant_sizer.Add(invariant_low_txt, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ ix += 1
+ self.invariant_sizer.Add(self.invariant_low_tcl, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix += 1
+ self.invariant_sizer.Add(wx.StaticText(self, -1, uncertainty),
+ (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix += 1
+ self.invariant_sizer.Add(self.invariant_low_err_tcl, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix += 1
+ self.invariant_sizer.Add(invariant_low_units_txt,
+ (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ # Invariant
+ iy += 1
+ ix = 0
+ self.invariant_sizer.Add(invariant_txt, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ ix += 1
+ self.invariant_sizer.Add(self.invariant_tcl, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix += 1
+ self.invariant_sizer.Add(wx.StaticText(self, -1, uncertainty),
+ (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix += 1
+ self.invariant_sizer.Add(self.invariant_err_tcl, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix += 1
+ self.invariant_sizer.Add(invariant_units_txt,
+ (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ # Invariant high
+ iy += 1
+ ix = 0
+ self.invariant_sizer.Add(invariant_high_txt, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ ix += 1
+ self.invariant_sizer.Add(self.invariant_high_tcl, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix += 1
+ self.invariant_sizer.Add(wx.StaticText(self, -1, uncertainty),
+ (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix += 1
+ self.invariant_sizer.Add(self.invariant_high_err_tcl, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix += 1
+ self.invariant_sizer.Add(invariant_high_units_txt,
+ (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ self.invariant_box_sizer.Add(self.invariant_sizer, 0, wx.TOP | wx.BOTTOM, 10)
+
+ def _layout_warning(self):
+ """
+ Draw widgets related to warning
+ """
+ # Warning [string]
+ self.warning_msg_txt = wx.StaticText(self, -1, self.warning_msg)
+ if self.qstar_container.existing_warning:
+ self.warning_msg_txt.SetForegroundColour('red')
+ self.warning_sizer.AddMany([(self.warning_msg_txt, 0,
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 10)])
+
+ def _layout_button(self):
+ """
+ Draw widgets related to button
+ """
+ # Close button
+ id = wx.NewId()
+ button_ok = wx.Button(self, id, "Ok")
+ button_ok.SetToolTipString("Give Details on Computation")
+ self.Bind(wx.EVT_BUTTON, self.on_close, id=id)
+ self.button_sizer.AddMany([((20, 20), 0, wx.LEFT, 350),
+ (button_ok, 0, wx.RIGHT, 10)])
+ def _do_layout(self):
+ """
+ Draw window content
+ """
+ self._define_structure()
+ self._layout_shart()
+ self._layout_invariant()
+ self._layout_warning()
+ self._layout_button()
+ self.main_sizer.AddMany([(self.chart_sizer, 0, wx.ALL, 10),
+ (self.invariant_box_sizer, 0, wx.ALL, 10),
+ (self.warning_sizer, 0, wx.ALL, 10),
+ (self.button_sizer, 0, wx.ALL, 10)])
+ self.SetSizer(self.main_sizer)
+
+
+ def set_values(self):
+ """
+ Set value of txtcrtl
+ """
+ value = format_number(self.qstar_container.qstar)
+ self.invariant_tcl.SetValue(value)
+ value = format_number(self.qstar_container.qstar_err)
+ self.invariant_err_tcl.SetValue(value)
+ value = format_number(self.qstar_container.qstar_low)
+ self.invariant_low_tcl.SetValue(value)
+ value = format_number(self.qstar_container.qstar_low_err)
+ self.invariant_low_err_tcl.SetValue(value)
+ value = format_number(self.qstar_container.qstar_high)
+ self.invariant_high_tcl.SetValue(value)
+ value = format_number(self.qstar_container.qstar_high_err)
+ self.invariant_high_err_tcl.SetValue(value)
+
+ def get_scale(self, percentage, scale_name='scale'):
+ """
+ Check scale receive in this panel.
+ """
+ scale = RECTANGLE_SCALE
+ try:
+ if percentage in [None, 0.0, "error"]:
+ scale = RECTANGLE_SCALE
+ return scale
+ elif percentage < 0:
+ scale = RECTANGLE_SCALE
+ return scale
+ scale = float(percentage)
+ except:
+ scale = RECTANGLE_SCALE
+ self.warning_msg += "Recieve an invalid scale for %s\n"
+ self.warning_msg += "check this value : %s\n" % str(percentage)
+ return scale
+
+ def set_color_bar(self):
+ """
+ Change the color for low and high bar when necessary
+ """
+ self.extrapolation_color_low = EXTRAPOLATION_COLOR
+ self.extrapolation_color_high = EXTRAPOLATION_COLOR
+ self.invariant_color = INVARIANT_COLOR
+ # warning to the user when the extrapolated invariant is greater than %5
+ if self.low_scale >= 0.05 or self.low_scale > 1 or self.low_scale < 0:
+ self.extrapolation_color_low = ERROR_COLOR
+ if self.high_scale >= 0.05 or self.high_scale > 1 or self.high_scale < 0:
+ self.extrapolation_color_high = ERROR_COLOR
+ if self.inv_scale > 1 or self.inv_scale < 0:
+ self.invariant_color = ERROR_COLOR
+
+ def on_close(self, event):
+ """
+ Close the current window
+ """
+ self.Close()
+
+ def on_paint(self, event):
+ """
+ Draw the chart
+ """
+ dc = wx.PaintDC(self.panel_chart)
+ try:
+ gc = wx.GraphicsContext.Create(dc)
+ except NotImplementedError:
+ msg = "This build of wxPython does not support "
+ msg += "the wx.GraphicsContext family of classes."
+ dc.DrawText(msg, 25, 25)
+ return
+ # Start the drawing
+ font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
+ font.SetWeight(wx.BOLD)
+ gc.SetFont(font)
+ # Draw a rectangle
+ path = gc.CreatePath()
+ path.AddRectangle(-RECTANGLE_WIDTH / 2, -RECTANGLE_HEIGHT / 2,
+ RECTANGLE_WIDTH / 2, RECTANGLE_HEIGHT / 2)
+ x_origine = 20
+ y_origine = 15
+ # Draw low rectangle
+ gc.PushState()
+ label = "Q* from Low-Q "
+ PathFunc = gc.DrawPath
+ w, h = gc.GetTextExtent(label)
+ gc.DrawText(label, x_origine, y_origine)
+ # Translate the rectangle
+ x_center = x_origine + RECTANGLE_WIDTH * self.low_scale / 2 + w + 10
+ y_center = y_origine + h
+ gc.Translate(x_center, y_center)
+ gc.SetPen(wx.Pen("black", 1))
+ gc.SetBrush(wx.Brush(self.extrapolation_color_low))
+ if self.low_inv_percent is None:
+ low_percent = 'Not Computed'
+ elif self.low_inv_percent == 'error':
+ low_percent = 'Error'
+ else:
+ low_percent = format_number(self.low_inv_percent * 100) + '%'
+ x_center = 20
+ y_center = -h
+ gc.DrawText(low_percent, x_center, y_center)
+ # Increase width by self.low_scale
+ gc.Scale(self.low_scale, 1.0)
+ PathFunc(path)
+ gc.PopState()
+ # Draw rectangle for invariant
+ gc.PushState() # save it again
+ y_origine += 20
+ gc.DrawText("Q* from Data ", x_origine, y_origine)
+ # offset to the lower part of the window
+ x_center = x_origine + RECTANGLE_WIDTH * self.inv_scale / 2 + w + 10
+ y_center = y_origine + h
+ gc.Translate(x_center, y_center)
+ # 128 == half transparent
+ gc.SetBrush(wx.Brush(self.invariant_color))
+ # Increase width by self.inv_scale
+ if self.inv_percent is None:
+ inv_percent = 'Not Computed'
+ elif self.inv_percent == 'error':
+ inv_percent = 'Error'
+ else:
+ inv_percent = format_number(self.inv_percent * 100) + '%'
+ x_center = 20
+ y_center = -h
+ gc.DrawText(inv_percent, x_center, y_center)
+ gc.Scale(self.inv_scale, 1.0)
+ gc.DrawPath(path)
+ gc.PopState()
+ # restore saved state
+ # Draw rectangle for high invariant
+ gc.PushState()
+ y_origine += 20
+ gc.DrawText("Q* from High-Q ", x_origine, y_origine)
+ # define the position of the new rectangle
+ x_center = x_origine + RECTANGLE_WIDTH * self.high_scale / 2 + w + 10
+ y_center = y_origine + h
+ gc.Translate(x_center, y_center)
+ gc.SetBrush(wx.Brush(self.extrapolation_color_high))
+ # increase scale by self.high_scale
+ if self.high_inv_percent is None:
+ high_percent = 'Not Computed'
+ elif self.high_inv_percent == 'error':
+ high_percent = 'Error'
+ else:
+ high_percent = format_number(self.high_inv_percent * 100) + '%'
+ x_center = 20
+ y_center = -h
+ gc.DrawText(high_percent, x_center, y_center)
+
+ gc.Scale(self.high_scale, 1.0)
+ gc.DrawPath(path)
+ gc.PopState()
diff --git a/src/sas/sasgui/perspectives/invariant/invariant_panel.py b/src/sas/sasgui/perspectives/invariant/invariant_panel.py
index 9c65f80..733eba6 100644
--- a/src/sas/sasgui/perspectives/invariant/invariant_panel.py
+++ b/src/sas/sasgui/perspectives/invariant/invariant_panel.py
@@ -1,1965 +1,1967 @@
-"""
-This module provides the GUI for the invariant perspective panel
-
-"""
-import copy
-import time
-import sys
-import os
-import wx
-import logging
-
-from wx.lib.scrolledpanel import ScrolledPanel
-from sas.sascalc.invariant import invariant
-
-from sas.sasgui.guiframe.utils import format_number
-from sas.sasgui.guiframe.utils import check_float
-from sas.sasgui.guiframe.events import StatusEvent
-from sas.sasgui.guiframe.events import AppendBookmarkEvent
-from sas.sasgui.perspectives.invariant.invariant_details import InvariantDetailsPanel
-from sas.sasgui.perspectives.invariant.invariant_details import InvariantContainer
-from sas.sasgui.perspectives.invariant.invariant_widgets import OutputTextCtrl
-from sas.sasgui.perspectives.invariant.invariant_widgets import InvTextCtrl
-from sas.sasgui.perspectives.invariant.invariant_state import InvariantState as IState
-from sas.sasgui.guiframe.panel_base import PanelBase
-from sas.sasgui.guiframe.documentation_window import DocumentationWindow
-
-# The minimum q-value to be used when extrapolating
-Q_MINIMUM = 1e-5
-# The maximum q-value to be used when extrapolating
-Q_MAXIMUM = 10
-# the ratio of maximum q value/(qmax of data) to plot the theory data
-Q_MAXIMUM_PLOT = 3
-# the number of points to consider during fit
-NPTS = 10
-#Default value for background
-BACKGROUND = 0.0
-#default value for the scale
-SCALE = 1.0
-#default value of the contrast
-CONTRAST = 1.0
-#default value of the power used for power law
-POWER = 4.0
-#Invariant panel size
-_BOX_WIDTH = 76
-
-
-if sys.platform.count("win32") > 0:
- _STATICBOX_WIDTH = 450
- PANEL_WIDTH = 500
- PANEL_HEIGHT = 700
- FONT_VARIANT = 0
-else:
- _STATICBOX_WIDTH = 490
- PANEL_WIDTH = 530
- PANEL_HEIGHT = 700
- FONT_VARIANT = 1
-
-
-class InvariantPanel(ScrolledPanel, PanelBase):
- """
- Main class defining the sizers (wx "panels") used to draw the
- Invariant GUI.
- """
- ## Internal nickname for the window, used by the AUI manager
- window_name = "Invariant"
- ## Name to appear on the window title bar
- window_caption = "Invariant"
- ## Flag to tell the AUI manager to put this panel in the center pane
- CENTER_PANE = True
- def __init__(self, parent, data=None, manager=None, *args, **kwds):
- kwds["size"] = (PANEL_WIDTH, PANEL_HEIGHT)
- kwds["style"] = wx.FULL_REPAINT_ON_RESIZE
- ScrolledPanel.__init__(self, parent=parent, *args, **kwds)
- PanelBase.__init__(self, parent)
- self.SetupScrolling()
- #Font size
- self.SetWindowVariant(variant=FONT_VARIANT)
- #Object that receive status event
- self.parent = parent.parent
- #plug-in using this panel
- self._manager = manager
- #Data uses for computation
- self._data = data
- self._scale = SCALE
- self._background = BACKGROUND
- self._bmark = None
- self.bookmark_num = 0
- self.state = None
- self.popUpMenu = None
- self._set_bookmark_menu()
- #Init state
- self.set_state()
- # default flags for state
- self.new_state = False
- self.is_state_data = False
- self.is_power_out = False
- self._set_analysis(False)
-
- #container of invariant value
- self.inv_container = None
- #sizers
- self.main_sizer = None
- self.outputs_sizer = None
- self.data_name_boxsizer = None
- self.hint_msg_sizer = None
- self.data_name_sizer = None
- self.data_range_sizer = None
- self.sizer_input = None
- self.inputs_sizer = None
- self.extrapolation_sizer = None
- self.extrapolation_range_sizer = None
- self.extrapolation_low_high_sizer = None
- self.low_extrapolation_sizer = None
- self.low_q_sizer = None
- self.high_extrapolation_sizer = None
- self.high_q_sizer = None
- self.volume_surface_sizer = None
- self.invariant_sizer = None
- self.button_sizer = None
- self.save_button_sizer = None
- self.hint_msg_txt = None
- self.data_name_tcl = None
- self.data_min_tcl = None
- self.data_max_tcl = None
- #Draw the panel
- self._do_layout()
- self.reset_panel()
- self._reset_state_list()
- ## Default file location for save
- self._default_save_location = os.getcwd()
- if self.parent is not None:
- msg = ""
- wx.PostEvent(self.parent, StatusEvent(status=msg, info="info"))
- self._default_save_location = \
- self.parent.get_save_location()
-
- self._set_bookmark_flag(False)
-
- def get_data(self):
- """
- """
- return self._manager.get_data()
-
- def get_state(self):
- """
- """
- return self.state
-
- def set_data(self, data):
- """
- Set the data
- """
- self._data = data
- #edit the panel
- if self._data is not None:
- self._delete_bookmark_items()
- self.get_state_by_num(0)
- data_name = self._data.name
- data_qmin = min(self._data.x)
- data_qmax = max(self._data.x)
- self.data_name_tcl.SetValue(str(data_name))
- self.data_min_tcl.SetValue(str(data_qmin))
- self.data_max_tcl.SetValue(str(data_qmax))
- self.reset_panel()
- self.compute_invariant(event=None)
- self.state.file = self._data.name
- #Reset the list of states
- self.state.data = copy.deepcopy(data)
- self._set_save_flag(True)
- self._set_preview_flag(False)
- self._reset_state_list()
- self._set_bookmark_flag(True)
- self._set_analysis(True)
- return True
-
- def _delete_bookmark_items(self):
- """
- Delete bookmark menu items
- """
- # delete toolbar menu
- self.parent.reset_bookmark_menu(self)
- self.parent._update_toolbar_helper()
- # delete popUpMenu items
- pos = 0
- for item in self.popUpMenu.GetMenuItems():
- pos += 1
- if pos < 3:
- continue
- self.popUpMenu.DestroyItem(item)
-
- def set_message(self):
- """
- Display warning message if available
- """
- if self.inv_container is not None:
- if self.inv_container.existing_warning:
- msg = "Warning! Computations on invariant require your "
- msg += "attention.\nPlease click on Details button."
- self.hint_msg_txt.SetForegroundColour("red")
-
- wx.PostEvent(self.parent,
- StatusEvent(status=msg, info="warning"))
- else:
- msg = "For more information, click on Details button."
- self.hint_msg_txt.SetForegroundColour("black")
- wx.PostEvent(self.parent,
- StatusEvent(status=msg, info="info"))
- self.hint_msg_txt.SetLabel(msg)
- self.Layout()
-
- def set_manager(self, manager):
- """
- set value for the manager
- """
- self._manager = manager
-
- def save_project(self, doc=None):
- """
- return an xml node containing state of the panel
- that guiframe can write to file
- """
- data = self.get_data()
- state = self.get_state()
- if data is not None:
- new_doc = self._manager.state_reader.write_toXML(data, state)
- if new_doc is not None:
- if doc is not None and hasattr(doc, "firstChild"):
- child = new_doc.getElementsByTagName("SASentry")
- for item in child:
- doc.firstChild.appendChild(item)
- else:
- doc = new_doc
- return doc
-
- def set_state(self, state=None, data=None):
- """
- set state when loading it from a .inv/.svs file
- """
-
- if state == None and data == None:
- self.state = IState()
- elif state == None or data == None:
- return
- else:
- new_state = copy.deepcopy(state)
- self.new_state = True
- if not self.set_data(data):
- return
-
- self.state = new_state
- self.state.file = data.name
-
- num = self.state.saved_state['state_num']
- if int(num) > 0:
- self._set_undo_flag(True)
- if int(num) < len(state.state_list) - 1:
- self._set_redo_flag(True)
-
- # get bookmarks
- self.bookmark_num = len(self.state.bookmark_list)
- total_bookmark_num = self.bookmark_num + 1
-
- for ind in range(1, total_bookmark_num):
- #bookmark_num = ind
- value = self.state.bookmark_list[ind]
- name = "%d] bookmarked at %s on %s" % (ind, value[0], value[1])
- # append it to menu
- id = wx.NewId()
- self.popUpMenu.Append(id, name, str(''))
- wx.EVT_MENU(self, id, self._back_to_bookmark)
- wx.PostEvent(self.parent,
- AppendBookmarkEvent(title=name,
- hint='',
- handler=self._back_to_bookmark))
-
- self.get_state_by_num(state_num=str(num))
-
- self._get_input_list()
- #make sure that the data is reset (especially
- # when loaded from a inv file)
- self.state.data = self._data
- self._set_preview_flag(False)
- self.new_state = False
- self.is_state_data = False
- self._set_analysis(True)
-
- def clear_panel(self):
- """
- Clear panel to defaults, used by set_state of manager
- """
-
- self._data = None
- # default data testctrl
- self.hint_msg_txt.SetLabel('')
- data_name = ''
- data_qmin = ''
- data_qmax = ''
- self.data_name_tcl.SetValue(str(data_name))
- self.data_min_tcl.SetValue(str(data_qmin))
- self.data_max_tcl.SetValue(str(data_qmax))
- #reset output textctrl
- self._reset_output()
- #reset panel
- self.reset_panel()
- #reset state w/o data
- self.set_state()
- # default flags for state
- self.new_state = False
- self.is_state_data = False
- self.is_power_out = False
-
- def get_background(self):
- """
- return the background textcrtl value as a float
- """
- background = self.background_tcl.GetValue().lstrip().rstrip()
- if background == "":
- raise ValueError, "Need a background"
- if check_float(self.background_tcl):
- return float(background)
- else:
- msg = "Receive invalid value for background : %s" % (background)
- raise ValueError, msg
-
- def get_scale(self):
- """
- return the scale textcrtl value as a float
- """
- scale = self.scale_tcl.GetValue().lstrip().rstrip()
- if scale == "":
- raise ValueError, "Need a background"
- if check_float(self.scale_tcl):
- if float(scale) <= 0.0:
- self.scale_tcl.SetBackgroundColour("pink")
- self.scale_tcl.Refresh()
- msg = "Receive invalid value for scale: %s" % (scale)
- raise ValueError, msg
- return float(scale)
- else:
- raise ValueError, "Receive invalid value for scale : %s" % (scale)
-
- def get_contrast(self):
- """
- return the contrast textcrtl value as a float
- """
- par_str = self.contrast_tcl.GetValue().strip()
- contrast = None
- if par_str != " " and check_float(self.contrast_tcl):
- contrast = float(par_str)
- return contrast
-
- def get_extrapolation_type(self, low_q, high_q):
- """
- get extrapolation type
- """
- extrapolation = None
- if low_q and not high_q:
- extrapolation = "low"
- elif not low_q and high_q:
- extrapolation = "high"
- elif low_q and high_q:
- extrapolation = "both"
- return extrapolation
-
- def get_porod_const(self):
- """
- return the porod constant textcrtl value as a float
- """
- par_str = self.porod_constant_tcl.GetValue().strip()
- porod_const = None
- if par_str != "" and check_float(self.porod_constant_tcl):
- porod_const = float(par_str)
- return porod_const
-
- def get_volume(self, inv, contrast, extrapolation):
- """
- get volume fraction
- """
- if contrast is not None:
- try:
- v, dv = inv.get_volume_fraction_with_error(contrast=contrast,
- extrapolation=extrapolation)
- self.volume_tcl.SetValue(format_number(v))
- self.volume_err_tcl.SetValue(format_number(dv))
- except:
- self.volume_tcl.SetValue(format_number(None))
- self.volume_err_tcl.SetValue(format_number(None))
- msg = "Error occurred computing volume "
- msg += " fraction: %s" % sys.exc_value
- wx.PostEvent(self.parent, StatusEvent(status=msg,
- info="error",
- type="stop"))
-
- def get_surface(self, inv, contrast, porod_const, extrapolation):
- """
- get surface value
- """
- if contrast is not None and porod_const is not None:
- try:
- s, ds = inv.get_surface_with_error(contrast=contrast,
- porod_const=porod_const,
- extrapolation=extrapolation)
- self.surface_tcl.SetValue(format_number(s))
- self.surface_err_tcl.SetValue(format_number(ds))
- except:
- self.surface_tcl.SetValue(format_number(None))
- self.surface_err_tcl.SetValue(format_number(None))
- msg = "Error occurred computing "
- msg += "specific surface: %s" % sys.exc_value
- wx.PostEvent(self.parent, StatusEvent(status=msg, info="error",
- type="stop"))
-
- def get_total_qstar(self, inv, extrapolation):
- """
- get total qstar
- """
- try:
- qstar_total, qstar_total_err = \
- inv.get_qstar_with_error(extrapolation)
- self.invariant_total_tcl.SetValue(format_number(qstar_total))
- self.invariant_total_err_tcl.SetValue(\
- format_number(qstar_total_err))
- self.inv_container.qstar_total = qstar_total
- self.inv_container.qstar_total_err = qstar_total_err
- except:
- self.inv_container.qstar_total = "Error"
- self.inv_container.qstar_total_err = "Error"
- self.invariant_total_tcl.SetValue(format_number(None))
- self.invariant_total_err_tcl.SetValue(format_number(None))
- msg = "Error occurred computing invariant using"
- msg += " extrapolation: %s" % sys.exc_value
- wx.PostEvent(self.parent, StatusEvent(status=msg, type="stop"))
-
- def get_low_qstar(self, inv, npts_low, low_q=False):
- """
- get low qstar
- """
- if low_q:
- try:
- qstar_low, qstar_low_err = inv.get_qstar_low()
- self.inv_container.qstar_low = qstar_low
- self.inv_container.qstar_low_err = qstar_low_err
- extrapolated_data = inv.get_extra_data_low(npts_in=npts_low)
- power_low = inv.get_extrapolation_power(range='low')
- if self.power_law_low.GetValue():
- self.power_low_tcl.SetValue(format_number(power_low))
- self._manager.plot_theory(data=extrapolated_data,
- name="Low-Q extrapolation")
- except:
- self.inv_container.qstar_low = "ERROR"
- self.inv_container.qstar_low_err = "ERROR"
- self._manager.plot_theory(name="Low-Q extrapolation")
- msg = "Error occurred computing low-Q "
- msg += "invariant: %s" % sys.exc_value
- wx.PostEvent(self.parent,
- StatusEvent(status=msg, type="stop"))
- raise
- else:
- try:
- self._manager.plot_theory(name="Low-Q extrapolation")
- except:
- logging.error(sys.exc_value)
-
- def get_high_qstar(self, inv, high_q=False):
- """
- get high qstar
- """
- if high_q:
- try:
- qmax_plot = Q_MAXIMUM_PLOT * max(self._data.x)
- if qmax_plot > Q_MAXIMUM:
- qmax_plot = Q_MAXIMUM
- qstar_high, qstar_high_err = inv.get_qstar_high()
- self.inv_container.qstar_high = qstar_high
- self.inv_container.qstar_high_err = qstar_high_err
- power_high = inv.get_extrapolation_power(range='high')
- self.power_high_tcl.SetValue(format_number(power_high))
- high_out_data = inv.get_extra_data_high(q_end=qmax_plot,
- npts=500)
- self._manager.plot_theory(data=high_out_data,
- name="High-Q extrapolation")
- except:
- #raise
- self.inv_container.qstar_high = "ERROR"
- self.inv_container.qstar_high_err = "ERROR"
- self._manager.plot_theory(name="High-Q extrapolation")
- msg = "Error occurred computing high-Q "
- msg += "invariant: %s" % sys.exc_value
- wx.PostEvent(self.parent, StatusEvent(status=msg,
- type="stop"))
- raise
- else:
- try:
- self._manager.plot_theory(name="High-Q extrapolation")
- except:
- logging.error(sys.exc_value)
-
- def get_qstar(self, inv):
- """
- get qstar
- """
- qstar, qstar_err = inv.get_qstar_with_error()
- self.inv_container.qstar = qstar
- self.inv_container.qstar_err = qstar_err
-
- def set_extrapolation_low(self, inv, low_q=False):
- """
- return float value necessary to compute invariant a low q
- """
- #get funtion
- if self.guinier.GetValue():
- function_low = "guinier"
- # get the function
- power_low = None #2.0/3.0
- if self.power_law_low.GetValue():
- function_low = "power_law"
- if self.fit_enable_low.GetValue():
- #set value of power_low to none to allow fitting
- power_low = None
- else:
- power_low = self.power_low_tcl.GetValue().lstrip().rstrip()
- if check_float(self.power_low_tcl):
- power_low = float(power_low)
- else:
- if low_q:
- #Raise error only when qstar at low q is requested
- msg = "Expect float for power at low q, "
- msg += " got %s" % (power_low)
- wx.PostEvent(self.parent,
- StatusEvent(status=msg,
- info="error",
- type="stop"))
-
- #Get the number of points to extrapolated
- npts_low = self.npts_low_tcl.GetValue().lstrip().rstrip()
- if check_float(self.npts_low_tcl):
- npts_low = float(npts_low)
- else:
- if low_q:
- msg = "Expect float for number of points at low q,"
- msg += " got %s" % (npts_low)
- wx.PostEvent(self.parent,
- StatusEvent(status=msg,
- info="error",
- type="stop"))
- #Set the invariant calculator
- inv.set_extrapolation(range="low", npts=npts_low,
- function=function_low, power=power_low)
- return inv, npts_low
-
-
- def set_extrapolation_high(self, inv, high_q=False):
- """
- return float value necessary to compute invariant a high q
- """
- power_high = None
- #if self.power_law_high.GetValue():
- function_high = "power_law"
- if self.fit_enable_high.GetValue():
- #set value of power_high to none to allow fitting
- power_high = None
- else:
- power_high = self.power_high_tcl.GetValue().lstrip().rstrip()
- if check_float(self.power_high_tcl):
- power_high = float(power_high)
- else:
- if high_q:
- #Raise error only when qstar at high q is requested
- msg = "Expect float for power at high q,"
- msg += " got %s" % (power_high)
- wx.PostEvent(self.parent,
- StatusEvent(status=msg,
- info="error",
- type="stop"))
-
- npts_high = self.npts_high_tcl.GetValue().lstrip().rstrip()
- if check_float(self.npts_high_tcl):
- npts_high = float(npts_high)
- else:
- if high_q:
- msg = "Expect float for number of points at high q,"
- msg += " got %s" % (npts_high)
- wx.PostEvent(self.parent, StatusEvent(status=msg,
- info="error",
- type="stop"))
- inv.set_extrapolation(range="high", npts=npts_high,
- function=function_high, power=power_high)
- return inv, npts_high
-
- def display_details(self, event):
- """
- open another panel for more details on invariant calculation
- """
- panel = InvariantDetailsPanel(parent=self,
- qstar_container=self.inv_container)
- panel.ShowModal()
- panel.Destroy()
- self.button_calculate.SetFocus()
-
- def compute_invariant(self, event=None):
- """
- compute invariant
- """
- if self._data == None:
- msg = "\n\nData must be loaded first in order"
- msg += " to perform a compution..."
- wx.PostEvent(self.parent, StatusEvent(status=msg))
- # set a state for this computation for saving
- elif event != None:
- self._set_compute_state(state='compute')
- self._set_bookmark_flag(True)
- msg = "\n\nStarting a new invariant computation..."
- wx.PostEvent(self.parent, StatusEvent(status=msg))
-
-
- if self._data is None:
- return
- self.button_details.Enable()
- #clear outputs textctrl
- self._reset_output()
- try:
- background = self.get_background()
- scale = self.get_scale()
- except:
- msg = "Invariant Error: %s" % (sys.exc_value)
- wx.PostEvent(self.parent, StatusEvent(status=msg, type="stop"))
- return
-
- low_q = self.enable_low_cbox.GetValue()
- high_q = self.enable_high_cbox.GetValue()
- temp_data = copy.deepcopy(self._data)
-
- #set invariant calculator
- inv = invariant.InvariantCalculator(data=temp_data,
- background=background,
- scale=scale)
- try:
- inv, npts_low = self.set_extrapolation_low(inv=inv, low_q=low_q)
- inv, npts_high = self.set_extrapolation_high(inv=inv, high_q=high_q)
- except:
- msg = "Error occurred computing invariant: %s" % sys.exc_value
- wx.PostEvent(self.parent, StatusEvent(status=msg,
- info="warning", type="stop"))
- return
- #check the type of extrapolation
- extrapolation = self.get_extrapolation_type(low_q=low_q, high_q=high_q)
-
- #Compute invariant
- try:
- self.get_qstar(inv=inv)
- except:
- msg = "Error occurred computing invariant: %s" % sys.exc_value
- wx.PostEvent(self.parent, StatusEvent(status=msg,
- info="warning",
- type="stop"))
- return
- #self.Show(False)
- r_msg = ''
- try:
- r_msg = 'Low Q: '
- #Compute qstar extrapolated to low q range
- self.get_low_qstar(inv=inv, npts_low=npts_low, low_q=low_q)
- r_msg = 'High Q: '
- #Compute qstar extrapolated to high q range
- self.get_high_qstar(inv=inv, high_q=high_q)
- r_msg = ''
- #Compute qstar extrapolated to total q range
- #and set value to txtcrtl
- self.get_total_qstar(inv=inv, extrapolation=extrapolation)
- # Parse additional parameters
- porod_const = self.get_porod_const()
- contrast = self.get_contrast()
- except:
- msg = r_msg + "Error occurred computing invariant: %s" % \
- sys.exc_value
- wx.PostEvent(self.parent, StatusEvent(status=msg,
- info="error",
- type="stop"))
- try:
- #Compute volume and set value to txtcrtl
- self.get_volume(inv=inv, contrast=contrast,
- extrapolation=extrapolation)
- #compute surface and set value to txtcrtl
- except:
- msg = "Error occurred computing invariant: %s" % sys.exc_value
- wx.PostEvent(self.parent, StatusEvent(status=msg,
- info="warning",
- type="stop"))
- try:
- self.get_surface(inv=inv, contrast=contrast,
- porod_const=porod_const,
- extrapolation=extrapolation)
-
- except:
- msg = "Error occurred computing invariant: %s" % sys.exc_value
- wx.PostEvent(self.parent, StatusEvent(status=msg,
- info="warning",
- type="stop"))
-
- #compute percentage of each invariant
- self.inv_container.compute_percentage()
-
- #display a message
- self.set_message()
-
- # reset power_out to default to get ready for another '_on_text'
- if self.is_power_out == True:
- self.state.container = copy.deepcopy(self.inv_container)
- self.state.timestamp = self._get_time_stamp()
- msg = self.state.__str__()
- self.state.set_report_string()
- self.is_power_out = False
- wx.PostEvent(self.parent, StatusEvent(status=msg))
-
- #enable the button_ok for more details
- self._set_preview_flag(True)
-
- if event != None:
- self._set_preview_flag(True)
- self._set_save_flag(True)
- wx.PostEvent(self.parent,
- StatusEvent(status='\nFinished invariant computation...'))
- #self.Show(True)
- self.Refresh()
-
- def on_undo(self, event=None):
- """
- Go back to the previous state
-
- : param event: undo button event
- """
- if self.state.state_num < 0:
- return
- self.is_power_out = True
- # get the previous state_num
- pre_state_num = int(self.state.saved_state['state_num']) - 1
-
- self.get_state_by_num(state_num=str(pre_state_num))
-
- if float(pre_state_num) <= 0:
- self._set_undo_flag(False)
- else:
- self._set_undo_flag(True)
- self._set_redo_flag(True)
- self.is_power_out = False
- self._info_state_num()
-
-
- def on_redo(self, event=None):
- """
- Go forward to the previous state
-
- : param event: redo button event
- """
- self.is_power_out = True
- # get the next state_num
- next_state_num = int(self.state.saved_state['state_num']) + 1
-
- self.get_state_by_num(state_num=str(next_state_num))
-
- if float(next_state_num) + 2 > len(self.state.state_list):
- self._set_redo_flag(False)
- else:
- self._set_redo_flag(True)
-
- self._set_undo_flag(True)
- self.is_power_out = False
- self._info_state_num()
-
- def on_preview(self, event=None):
- """
- Invoke report dialog panel
-
- : param event: report button event
- """
- from sas.sasgui.perspectives.invariant.report_dialog import ReportDialog
-
- self.state.set_report_string()
- report_html_str = self.state.report_str
- report_text_str = self.state.__str__()
- report_img = self.state.image
- report_list = [report_html_str, report_text_str, report_img]
- dialog = ReportDialog(report_list, None, -1, "")
- dialog.Show()
-
- def get_state_by_num(self, state_num=None):
- """
- Get the state given by number
-
- : param state_num: the given state number
- """
- if state_num == None:
- return
-
- backup_state_list = copy.deepcopy(self.state.state_list)
-
- # get the previous state
- try:
- current_state = copy.deepcopy(self.state.state_list[str(state_num)])
- # get the previously computed state number
- #(computation before the state changes happened)
- current_compute_num = str(current_state['compute_num'])
- except:
- raise
-
- # get the state at pre_compute_num
- comp_state = copy.deepcopy(self.state.state_list[current_compute_num])
-
- # set the parameters
- for key in comp_state:
- value = comp_state[key]
- self._set_property_value(key, value)
-
- self.compute_invariant(event=None)
-
- # set the input params at the state at pre_state_num
- for key in current_state:
- # set the inputs and boxes
- value = current_state[key]
- self._set_property_value(key, value)
-
- self._enable_high_q_section(event=None)
- self._enable_low_q_section(event=None)
- self.state.state_list = backup_state_list
- self.state.saved_state = current_state
- self.state.state_num = state_num
-
- def _set_property_value(self, key, value):
- """
- Set a property value
- :param key: property name
- :param value: value of the property
- """
- try:
- if key in ['compute_num', 'file', 'is_time_machine', 'state_num']:
- return
- else:
- attr = getattr(self, key)
- if attr.__class__.__name__ == "StaticText":
- return
- if value in ["True", "False", True, False]:
- value = bool(value)
- else:
- value = str(value)
- attr.SetValue(value)
- except:
- logging.error("Invariant state: %s", sys.exc_value)
-
- def get_bookmark_by_num(self, num=None):
- """
- Get the bookmark state given by number
-
- : param num: the given bookmark number
-
- """
- current_state = {}
- comp_state = {}
- backup_state_list = copy.deepcopy(self.state.state_list)
-
- # get the previous state
- try:
- _, _, current_state, comp_state = self.state.bookmark_list[int(num)]
- except:
- logging.error(sys.exc_value)
- raise ValueError, "No such bookmark exists"
-
- # set the parameters
- for key in comp_state:
- value = comp_state[key]
- self._set_property_value(key, value)
-
- self.compute_invariant(event=None)
- # set the input params at the state of pre_state_num
- for key in current_state:
- value = current_state[key]
- self._set_property_value(key, value)
- self.state.saved_state = copy.deepcopy(current_state)
-
- self._enable_high_q_section(event=None)
- self._enable_low_q_section(event=None)
- self.state.state_list = backup_state_list
- #self.state.saved_state = current_state
- #self.state.state_num = state_num
-
- def reset_panel(self):
- """
- set the panel at its initial state.
- """
- self.background_tcl.SetValue(str(BACKGROUND))
- self.scale_tcl.SetValue(str(SCALE))
- self.contrast_tcl.SetValue(str(CONTRAST))
- self.porod_constant_tcl.SetValue('')
- self.npts_low_tcl.SetValue(str(NPTS))
- self.enable_low_cbox.SetValue(False)
- self.fix_enable_low.SetValue(True)
- self.power_low_tcl.SetValue(str(POWER))
- self.guinier.SetValue(True)
- self.power_low_tcl.Disable()
- self.enable_high_cbox.SetValue(False)
- self.fix_enable_high.SetValue(True)
- self.power_high_tcl.SetValue(str(POWER))
- self.npts_high_tcl.SetValue(str(NPTS))
- self.button_details.Disable()
- #Change the state of txtcrtl to enable/disable
- self._enable_low_q_section()
- #Change the state of txtcrtl to enable/disable
- self._enable_high_q_section()
- self._reset_output()
- self._set_undo_flag(False)
- self._set_redo_flag(False)
- self._set_bookmark_flag(False)
- self._set_preview_flag(False)
- self._set_save_flag(False)
- self.button_calculate.SetFocus()
- #self.SetupScrolling()
- self._set_analysis(False)
-
- def _set_state(self, event):
- """
- Set the state list
-
- :param event: rb/cb event
- """
- if event == None:
- return
- obj = event.GetEventObject()
- name = str(obj.GetName())
- value = str(obj.GetValue())
- rb_list = [['power_law_low', 'guinier'],
- ['fit_enable_low', 'fix_enable_low'],
- ['fit_enable_high', 'fix_enable_high']]
-
- try:
- if value == None or value.lstrip().rstrip() == '':
- value = 'None'
- setattr(self.state, name, str(value))
- self.state.saved_state[name] = str(value)
-
- # set the count part of radio button clicked
- #False for the saved_state
- for title, content in rb_list:
- if name == title:
- name = content
- value = False
- elif name == content:
- name = title
- value = False
- self.state.saved_state[name] = str(value)
-
- # Instead of changing the future, create a new future.
- max_state_num = len(self.state.state_list) - 1
- self.state.saved_state['state_num'] = max_state_num
-
- self.state.saved_state['state_num'] += 1
- self.state.state_num = self.state.saved_state['state_num']
- self.state.state_list[str(self.state.state_num)] = \
- self.state.clone_state()
- except:
- logging.error(sys.exc_value)
-
- self._set_undo_flag(True)
- self._set_redo_flag(False)
- #event.Skip()
-
- def _set_compute_state(self, state=None):
- """
- Notify the compute_invariant state to self.state
-
- : param state: set 'compute' when the computation is
- activated by the 'compute' button, else None
-
- """
- # reset the default
- if state != 'compute':
- self.new_state = False
- self.is_power_out = False
- else:
- self.is_power_out = True
- # Instead of changing the future, create a new future.
- max_state_num = len(self.state.state_list) - 1
- self.state.saved_state['state_num'] = max_state_num
- # A new computation is also A state
- #copy.deepcopy(self.state.saved_state)
- temp_saved_states = self.state.clone_state()
- temp_saved_states['state_num'] += 1
- self.state.state_num = temp_saved_states['state_num']
-
-
- # set the state number of the computation
- if state == 'compute':
- temp_saved_states['compute_num'] = self.state.state_num
- self.state.saved_state = copy.deepcopy(temp_saved_states)
- #copy.deepcopy(self.state.saved_state)
- self.state.state_list[str(self.state.state_num)] = \
- self.state.clone_state()
-
- # A computation is a new state, so delete the states with any higher
- # state numbers
- for i in range(self.state.state_num + 1, len(self.state.state_list)):
- try:
- del self.state.state_list[str(i)]
- except:
- logging.error(sys.exc_value)
- # Enable the undo button if it was not
- self._set_undo_flag(True)
- self._set_redo_flag(False)
-
- def _reset_state_list(self, data=None):
- """
- Reset the state_list just before data was loading:
- Used in 'set_current_data()'
- """
- #if data == None: return
- #temp_state = self.state.clone_state()
- #copy.deepcopy(self.state.saved_state)
- # Clear the list
- self.state.state_list.clear()
- self.state.bookmark_list.clear()
- # Set defaults
- self.state.saved_state['state_num'] = 0
- self.state.saved_state['compute_num'] = 0
- if self._data != None:
- self.state.saved_state['file'] = str(self._data.name)
- else:
- self.state.saved_state['file'] = 'None'
- self.state.file = self.state.saved_state['file']
-
- self.state.state_num = self.state.saved_state['state_num']
- self.state.timestamp = "('00:00:00', '00/00/0000')"
-
- # Put only the current state in the list
- #copy.deepcopy(self.state.saved_state)
- self.state.state_list[str(self.state.state_num)] = \
- self.state.clone_state()
- self._set_undo_flag(False)
- self._set_redo_flag(False)
- self._set_bookmark_flag(False)
- self._set_preview_flag(False)
- self._set_save_flag(False)
-
-
- def _on_text(self, event):
- """
- Catch text change event to add the state to the state_list
-
- :param event: txtctr event ; assumes not None
-
- """
- if self._data == None:
- return
- # check if this event is from do/undo button
- if self.state.saved_state['is_time_machine'] or self.new_state:
- #event.Skip()
- return
-
- # get the object
- obj = event.GetEventObject()
- name = str(obj.GetName())
- value = str(obj.GetValue())
- state_num = self.state.saved_state['state_num']
-
- # text event is a new state, so delete the states with higher state_num
- # i.e., change the future
- for i in range(int(state_num) + 1, len(self.state.state_list)):
- try:
- del self.state.state_list[str(i)]
- except:
- logging.error(sys.exc_value)
-
- # try to add new state of the text changes in the state_list
- try:
- if value.strip() == None:
- value = ''
- setattr(self.state, name, str(value))
- self.state.saved_state[name] = str(value)
- self.state.input_list[name] = str(value)
- if not self.is_power_out:
- if name != 'power_low_tcl' and name != 'power_high_tcl':
- self.state.saved_state['state_num'] += 1
- self.state.state_num = self.state.saved_state['state_num']
- self.state.state_list[str(self.state.state_num)] = self.state.clone_state()
- except:
- logging.error(sys.exc_value)
-
- self._set_undo_flag(True)
- self._set_redo_flag(False)
- self._set_bookmark_flag(True)
- self._set_preview_flag(False)
-
- def _on_out_text(self, event):
- """
- Catch ouput text change to add the state
-
- :param event: txtctr event ; assumes not None
-
- """
- # get the object
- obj = event.GetEventObject()
- name = str(obj.GetName())
- value = str(obj.GetValue())
- try:
- self.state.saved_state[name] = str(value)
- self.state.state_list[str(self.state.state_num)] = self.state.clone_state()
- except:
- logging.error(sys.exc_value)
-
- def _get_input_list(self):
- """
- get input_list; called by set_state
- """
- # get state num of the last compute state
- compute_num = self.state.saved_state['compute_num']
- # find values and put into the input list
- for key1, value1 in self.state.state_list[str(compute_num)].iteritems():
- for key, _ in self.state.input_list.iteritems():
- if key == key1:
- self.state.input_list[key] = value1
- break
-
- def _set_bookmark_menu(self):
- """
- Setup 'bookmark' context menu
- """
- ## Create context menu for page
- self.popUpMenu = wx.Menu()
- id = wx.NewId()
- self._bmark = wx.MenuItem(self.popUpMenu, id, "BookMark",
- " Bookmark the panel to recall it later")
- self.popUpMenu.AppendItem(self._bmark)
- self._bmark.Enable(True)
- wx.EVT_MENU(self, id, self.on_bookmark)
- self.popUpMenu.AppendSeparator()
- self.Bind(wx.EVT_CONTEXT_MENU, self._on_context_menu)
-
- def on_bookmark(self, event):
- """
- Save the panel state in memory and add the list on
- the popup menu on bookmark context menu event
- """
- if self._data == None:
- return
- if event == None:
- return
- self.bookmark_num += 1
- # date and time of the event
- my_time, date = self._get_time_stamp()
- _ = self.state.state_num
- compute_num = self.state.saved_state['compute_num']
- # name and message of the bookmark list
- msg = "State saved at %s on %s" % (my_time, date)
- ## post help message for the selected model
- msg += " Right click on the panel to retrieve this state"
- #wx.PostEvent(self.parent.parent, StatusEvent(status = msg ))
- name = "%d] bookmarked at %s on %s" % (self.bookmark_num, my_time, date)
-
- # append it to menu
- id = wx.NewId()
- self.popUpMenu.Append(id, name, str(msg))
- wx.EVT_MENU(self, id, self._back_to_bookmark)
- state = self.state.clone_state()
- comp_state = copy.deepcopy(self.state.state_list[str(compute_num)])
- self.state.bookmark_list[self.bookmark_num] = [my_time, date,
- state, comp_state]
- self.state.toXML(self, doc=None, entry_node=None)
-
- wx.PostEvent(self.parent, StatusEvent(status=msg, info="info"))
- wx.PostEvent(self.parent,
- AppendBookmarkEvent(title=name,
- hint=str(msg),
- handler=self._back_to_bookmark))
-
- def _back_to_bookmark(self, event):
- """
- Bring the panel back to the state of bookmarked requested by
- context menu event
- and set it as a new state
- """
- self._manager.on_perspective(event)
- menu = event.GetEventObject()
- ## post help message for the selected model
- msg = menu.GetHelpString(event.GetId())
- msg += " reloaded"
- wx.PostEvent(self.parent, StatusEvent(status=msg))
-
- name = menu.GetLabel(event.GetId())
-
- num, _ = name.split(']')
- current_state_num = self.state.state_num
- self.get_bookmark_by_num(num)
- state_num = int(current_state_num) + 1
-
- self.state.saved_state['state_num'] = state_num
- #copy.deepcopy(self.state.saved_state)
- self.state.state_list[str(state_num)] = self.state.clone_state()
- self.state.state_num = state_num
-
- self._set_undo_flag(True)
- self._info_bookmark_num(event)
-
- def _info_bookmark_num(self, event=None):
- """
- print the bookmark number in info
-
- : event: popUpMenu event
- """
- if event == None:
- return
- # get the object
- menu = event.GetEventObject()
- item = menu.FindItemById(event.GetId())
- text = item.GetText()
- num = text.split(']')[0]
- msg = "bookmark num = %s " % num
-
- wx.PostEvent(self.parent, StatusEvent(status=msg))
-
- def _info_state_num(self):
- """
- print the current state number in info
- """
- msg = "state num = "
- msg += self.state.state_num
-
- wx.PostEvent(self.parent, StatusEvent(status=msg))
-
- def _get_time_stamp(self):
- """
- return time and date stings
- """
- # date and time
- year, month, day, hour, minute, second, _, _, _ = \
- time.localtime()
- my_time = str(hour) + ":" + str(minute) + ":" + str(second)
- date = str(month) + "/" + str(day) + "/" + str(year)
- return my_time, date
-
-
- def on_save(self, evt=None):
- """
- Save invariant state into a file
- """
- # Ask the user the location of the file to write to.
- path = None
- if self.parent != None:
- self._default_save_location = self.parent.get_save_location()
- if self._default_save_location == None:
- self._default_save_location = os.getcwd()
- dlg = wx.FileDialog(self, "Choose a file",
- self._default_save_location, \
- self.window_caption, "*.inv", wx.SAVE)
- if dlg.ShowModal() == wx.ID_OK:
- path = dlg.GetPath()
- self._default_save_location = os.path.dirname(path)
- if self.parent != None:
- self.parent._default_save_location = \
- self._default_save_location
- else:
- return None
-
- dlg.Destroy()
- # MAC always needs the extension for saving
- extens = ".inv"
- # Make sure the ext included in the file name
- fName = os.path.splitext(path)[0] + extens
- self._manager.save_file(filepath=fName, state=self.state)
-
- def _show_message(self, mssg='', msg='Warning'):
- """
- Show warning message when resetting data
- """
- # no message for now
- return True
-
- def _reset_output(self):
- """
- clear outputs textcrtl
- """
- self.invariant_total_tcl.Clear()
- self.invariant_total_err_tcl.Clear()
- self.volume_tcl.Clear()
- self.volume_err_tcl.Clear()
- self.surface_tcl.Clear()
- self.surface_err_tcl.Clear()
- #prepare a new container to put result of invariant
- self.inv_container = InvariantContainer()
-
-
- def _on_context_menu(self, event):
- """
- On context menu
- """
- pos = event.GetPosition()
- pos = self.ScreenToClient(pos)
-
- self.PopupMenu(self.popUpMenu, pos)
-
- def _define_structure(self):
- """
- Define main sizers needed for this panel
- """
- ## Box sizers must be defined first before
- #defining buttons/textctrls (MAC).
- self.main_sizer = wx.BoxSizer(wx.VERTICAL)
- #Sizer related to outputs
- outputs_box = wx.StaticBox(self, -1, "Outputs")
- self.outputs_sizer = wx.StaticBoxSizer(outputs_box, wx.VERTICAL)
- self.outputs_sizer.SetMinSize((_STATICBOX_WIDTH, -1))
- #Sizer related to data
- data_name_box = wx.StaticBox(self, -1, "I(q) Data Source")
- self.data_name_boxsizer = wx.StaticBoxSizer(data_name_box, wx.VERTICAL)
- self.data_name_boxsizer.SetMinSize((_STATICBOX_WIDTH, -1))
- self.hint_msg_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.data_name_sizer = wx.BoxSizer(wx.HORIZONTAL)
-
- self.data_range_sizer = wx.BoxSizer(wx.HORIZONTAL)
- #Sizer related to inputs
- self.sizer_input = wx.FlexGridSizer(2, 6, 0, 0)
- #Sizer related to inputs
- inputs_box = wx.StaticBox(self, -1, "Customized Inputs")
- self.inputs_sizer = wx.StaticBoxSizer(inputs_box, wx.VERTICAL)
- self.inputs_sizer.SetMinSize((_STATICBOX_WIDTH, -1))
- #Sizer related to extrapolation
- extrapolation_box = wx.StaticBox(self, -1, "Extrapolation")
- self.extrapolation_sizer = wx.StaticBoxSizer(extrapolation_box,
- wx.VERTICAL)
- self.extrapolation_sizer.SetMinSize((_STATICBOX_WIDTH, -1))
- self.extrapolation_range_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.extrapolation_low_high_sizer = wx.BoxSizer(wx.HORIZONTAL)
- #Sizer related to extrapolation at low q range
- low_q_box = wx.StaticBox(self, -1, "Low Q")
- self.low_extrapolation_sizer = wx.StaticBoxSizer(low_q_box, wx.VERTICAL)
-
- self.low_q_sizer = wx.GridBagSizer(5, 5)
- #Sizer related to extrapolation at low q range
- high_q_box = wx.StaticBox(self, -1, "High Q")
- self.high_extrapolation_sizer = wx.StaticBoxSizer(high_q_box,
- wx.VERTICAL)
- self.high_q_sizer = wx.GridBagSizer(5, 5)
- #sizer to define outputs
- self.volume_surface_sizer = wx.GridBagSizer(5, 5)
- #Sizer related to invariant output
- self.invariant_sizer = wx.GridBagSizer(5, 5)
- #Sizer related to button
- self.button_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.button_sizer.SetMinSize((_STATICBOX_WIDTH, -1))
- #Sizer related to save button
- self.save_button_sizer = wx.BoxSizer(wx.HORIZONTAL)
-
- def _layout_data_name(self):
- """
- Draw widgets related to data's name
- """
- #Sizer hint
- hint_msg = ""
-
- self.hint_msg_txt = wx.StaticText(self, -1, hint_msg)
- self.hint_msg_txt.SetForegroundColour("red")
- msg = "Highlight = mouse the mouse's cursor on the data until"
- msg += " the plot's color changes to yellow"
- self.hint_msg_txt.SetToolTipString(msg)
- self.hint_msg_sizer.Add(self.hint_msg_txt)
- #Data name [string]
- data_name_txt = wx.StaticText(self, -1, 'Name:')
-
- self.data_name_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH * 4, 20),
- style=0)
- self.data_name_tcl.SetToolTipString("Data's name.")
- self.data_name_sizer.AddMany([(data_name_txt, 0, wx.LEFT | wx.RIGHT, 10),
- (self.data_name_tcl, 0, wx.EXPAND)])
- #Data range [string]
- data_range_txt = wx.StaticText(self, -1, 'Total Q Range (1/A): ')
- data_min_txt = wx.StaticText(self, -1, 'Min : ')
- self.data_min_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH, 20),
- style=0, name='data_min_tcl')
- self.data_min_tcl.SetToolTipString("The minimum value of q range.")
- data_max_txt = wx.StaticText(self, -1, 'Max : ')
- self.data_max_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH, 20),
- style=0, name='data_max_tcl')
- self.data_max_tcl.SetToolTipString("The maximum value of q range.")
- self.data_range_sizer.AddMany([(data_range_txt, 0, wx.RIGHT, 5),
- (data_min_txt, 0, wx.RIGHT, 5),
- (self.data_min_tcl, 0, wx.RIGHT, 20),
- (data_max_txt, 0, wx.RIGHT, 5),
- (self.data_max_tcl, 0, wx.RIGHT, 10)])
- self.data_name_boxsizer.AddMany([(self.hint_msg_sizer, 0, wx.ALL, 5),
- (self.data_name_sizer, 0, wx.ALL, 10),
- (self.data_range_sizer, 0, wx.ALL, 10)])
-
- def _enable_fit_power_law_low(self, event=None):
- """
- Enable and disable the power value editing
- """
- if event != None:
- self._set_bookmark_flag(True)
- self._set_preview_flag(False)
-
- if self.fix_enable_low.IsEnabled():
-
- if self.fix_enable_low.GetValue():
- self.fit_enable_low.SetValue(False)
- self.power_low_tcl.Enable()
- else:
- self.fit_enable_low.SetValue(True)
- self.power_low_tcl.Disable()
- self._set_state(event=event)
-
- def _enable_low_q_section(self, event=None):
- """
- Disable or enable some button if the user enable low q extrapolation
- """
- if event != None:
- self._set_bookmark_flag(True)
- self._set_preview_flag(False)
-
- if self.enable_low_cbox.GetValue():
- self.npts_low_tcl.Enable()
- self.fix_enable_low.Enable()
- self.fit_enable_low.Enable()
- self.guinier.Enable()
- self.power_law_low.Enable()
-
- else:
- self.npts_low_tcl.Disable()
- self.fix_enable_low.Disable()
- self.fit_enable_low.Disable()
- self.guinier.Disable()
- self.power_law_low.Disable()
-
- self._enable_power_law_low()
- self._enable_fit_power_law_low()
- self._set_state(event=event)
- self.button_calculate.SetFocus()
-
- def _enable_power_law_low(self, event=None):
- """
- Enable editing power law section at low q range
- """
- if event != None:
- self._set_bookmark_flag(True)
- self._set_preview_flag(False)
- if self.guinier.GetValue():
- self.power_law_low.SetValue(False)
- self.fix_enable_low.Disable()
- self.fit_enable_low.Disable()
- self.power_low_tcl.Disable()
- else:
- self.power_law_low.SetValue(True)
- self.fix_enable_low.Enable()
- self.fit_enable_low.Enable()
- self.power_low_tcl.Enable()
- self._enable_fit_power_law_low()
- self._set_state(event=event)
-
- def _layout_extrapolation_low(self):
- """
- Draw widgets related to extrapolation at low q range
- """
- self.enable_low_cbox = wx.CheckBox(self, -1,
- "Enable Extrapolate Low Q",
- name='enable_low_cbox')
- wx.EVT_CHECKBOX(self, self.enable_low_cbox.GetId(),
- self._enable_low_q_section)
- self.fix_enable_low = wx.RadioButton(self, -1, 'Fix',
- (10, 10), style=wx.RB_GROUP,
- name='fix_enable_low')
- self.Bind(wx.EVT_RADIOBUTTON, self._enable_fit_power_law_low,
- id=self.fix_enable_low.GetId())
- self.fit_enable_low = wx.RadioButton(self, -1, 'Fit', (10, 10),
- name='fit_enable_low')
- self.Bind(wx.EVT_RADIOBUTTON, self._enable_fit_power_law_low,
- id=self.fit_enable_low.GetId())
- self.guinier = wx.RadioButton(self, -1, 'Guinier',
- (10, 10), style=wx.RB_GROUP,
- name='guinier')
- self.Bind(wx.EVT_RADIOBUTTON, self._enable_power_law_low,
- id=self.guinier.GetId())
- self.power_law_low = wx.RadioButton(self, -1, 'Power Law',
- (10, 10), name='power_law_low')
- self.Bind(wx.EVT_RADIOBUTTON, self._enable_power_law_low,
- id=self.power_law_low.GetId())
-
- npts_low_txt = wx.StaticText(self, -1, 'Npts')
- self.npts_low_tcl = InvTextCtrl(self, -1,
- size=(_BOX_WIDTH * 2 / 3, -1),
- name='npts_low_tcl')
- wx.EVT_TEXT(self, self.npts_low_tcl.GetId(), self._on_text)
- msg_hint = "Number of Q points to consider"
- msg_hint += "while extrapolating the low-Q region"
- self.npts_low_tcl.SetToolTipString(msg_hint)
- power_txt = wx.StaticText(self, -1, 'Power')
- self.power_low_tcl = InvTextCtrl(self, -1, size=(_BOX_WIDTH * 2 / 3, -1),
- name='power_low_tcl')
- wx.EVT_TEXT(self, self.power_low_tcl.GetId(), self._on_text)
-
- power_hint_txt = "Exponent to apply to the Power_law function."
- self.power_low_tcl.SetToolTipString(power_hint_txt)
- iy = 0
- ix = 0
- self.low_q_sizer.Add(self.enable_low_cbox, (iy, ix), (1, 5),
- wx.TOP | wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- iy += 1
- ix = 0
- self.low_q_sizer.Add(npts_low_txt, (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- ix += 1
- self.low_q_sizer.Add(self.npts_low_tcl, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- iy += 1
- ix = 0
- self.low_q_sizer.Add(self.guinier, (iy, ix), (1, 2),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- iy += 1
- ix = 0
- self.low_q_sizer.Add(self.power_law_low, (iy, ix), (1, 2),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- # Parameter controls for power law
- ix = 1
- iy += 1
- self.low_q_sizer.Add(self.fix_enable_low, (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 1
- self.low_q_sizer.Add(self.fit_enable_low, (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix = 1
- iy += 1
- self.low_q_sizer.Add(power_txt, (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 1
- self.low_q_sizer.Add(self.power_low_tcl, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- self.low_extrapolation_sizer.Add(self.low_q_sizer)
-
- def _enable_fit_power_law_high(self, event=None):
- """
- Enable and disable the power value editing
- """
- if event != None:
- self._set_bookmark_flag(True)
-
- self._set_preview_flag(False)
- if self.fix_enable_high.IsEnabled():
- if self.fix_enable_high.GetValue():
- self.fit_enable_high.SetValue(False)
- self.power_high_tcl.Enable()
- else:
- self.fit_enable_high.SetValue(True)
- self.power_high_tcl.Disable()
- self._set_state(event=event)
-
- def _enable_high_q_section(self, event=None):
- """
- Disable or enable some button if the user enable high q extrapolation
- """
- if event != None:
- self._set_bookmark_flag(True)
- self._set_preview_flag(False)
- if self.enable_high_cbox.GetValue():
- self.npts_high_tcl.Enable()
- self.power_law_high.Enable()
- self.power_high_tcl.Enable()
- self.fix_enable_high.Enable()
- self.fit_enable_high.Enable()
- else:
- self.npts_high_tcl.Disable()
- self.power_law_high.Disable()
- self.power_high_tcl.Disable()
- self.fix_enable_high.Disable()
- self.fit_enable_high.Disable()
- self._enable_fit_power_law_high()
- self._set_state(event=event)
- self.button_calculate.SetFocus()
-
- def _layout_extrapolation_high(self):
- """
- Draw widgets related to extrapolation at high q range
- """
- self.enable_high_cbox = wx.CheckBox(self, -1,
- "Enable Extrapolate high-Q",
- name='enable_high_cbox')
- wx.EVT_CHECKBOX(self, self.enable_high_cbox.GetId(),
- self._enable_high_q_section)
- self.fix_enable_high = wx.RadioButton(self, -1, 'Fix',
- (10, 10), style=wx.RB_GROUP,
- name='fix_enable_high')
- self.Bind(wx.EVT_RADIOBUTTON, self._enable_fit_power_law_high,
- id=self.fix_enable_high.GetId())
- self.fit_enable_high = wx.RadioButton(self, -1, 'Fit', (10, 10),
- name='fit_enable_high')
- self.Bind(wx.EVT_RADIOBUTTON, self._enable_fit_power_law_high,
- id=self.fit_enable_high.GetId())
-
- self.power_law_high = wx.StaticText(self, -1, 'Power Law')
- msg_hint = "Check to extrapolate data at high-Q"
- self.power_law_high.SetToolTipString(msg_hint)
- npts_high_txt = wx.StaticText(self, -1, 'Npts')
- self.npts_high_tcl = InvTextCtrl(self, -1, size=(_BOX_WIDTH * 2 / 3, -1),
- name='npts_high_tcl')
- wx.EVT_TEXT(self, self.npts_high_tcl.GetId(), self._on_text)
- msg_hint = "Number of Q points to consider"
- msg_hint += "while extrapolating the high-Q region"
- self.npts_high_tcl.SetToolTipString(msg_hint)
- power_txt = wx.StaticText(self, -1, 'Power')
- self.power_high_tcl = InvTextCtrl(self, -1, size=(_BOX_WIDTH * 2 / 3, -1),
- name='power_high_tcl')
- wx.EVT_TEXT(self, self.power_high_tcl.GetId(), self._on_text)
- power_hint_txt = "Exponent to apply to the Power_law function."
- self.power_high_tcl.SetToolTipString(power_hint_txt)
- iy = 0
- ix = 0
- self.high_q_sizer.Add(self.enable_high_cbox, (iy, ix), (1, 5),
- wx.TOP | wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- iy += 1
- ix = 0
- self.high_q_sizer.Add(npts_high_txt, (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- ix += 1
- self.high_q_sizer.Add(self.npts_high_tcl, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- iy += 1
- ix = 0
- self.high_q_sizer.Add(self.power_law_high, (iy, ix), (1, 2),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
-
- # Parameter controls for power law
- ix = 1
- iy += 1
- self.high_q_sizer.Add(self.fix_enable_high, (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 1
- self.high_q_sizer.Add(self.fit_enable_high, (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix = 1
- iy += 1
- self.high_q_sizer.Add(power_txt, (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- ix += 1
- self.high_q_sizer.Add(self.power_high_tcl, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- self.high_extrapolation_sizer.Add(self.high_q_sizer, 0,
- wx.BOTTOM, 20)
-
- def _layout_extrapolation(self):
- """
- Draw widgets related to extrapolation
- """
- extra_hint = "Extrapolation \nMaximum Q Range [1/A]:"
- extra_hint_txt = wx.StaticText(self, -1, extra_hint)
- #Extrapolation range [string]
- extrapolation_min_txt = wx.StaticText(self, -1, 'Min:')
- self.extrapolation_min_tcl = OutputTextCtrl(self, -1,
- size=(_BOX_WIDTH, 20), style=0,
- name='extrapolation_min_tcl')
- self.extrapolation_min_tcl.SetValue(str(Q_MINIMUM))
- hint_msg = "The minimum extrapolated q value."
- self.extrapolation_min_tcl.SetToolTipString(hint_msg)
- extrapolation_max_txt = wx.StaticText(self, -1, 'Max:')
- self.extrapolation_max_tcl = OutputTextCtrl(self, -1,
- size=(_BOX_WIDTH, 20),
- style=0,
- name='extrapolation_max_tcl')
- self.extrapolation_max_tcl.SetValue(str(Q_MAXIMUM))
- hint_msg = "The maximum extrapolated q value."
- self.extrapolation_max_tcl.SetToolTipString(hint_msg)
- self.extrapolation_range_sizer.AddMany([(extra_hint_txt, 0,
- wx.LEFT, 5),
- (extrapolation_min_txt, 0,
- wx.LEFT, 10),
- (self.extrapolation_min_tcl,
- 0, wx.LEFT, 5),
- (extrapolation_max_txt, 0,
- wx.LEFT, 20),
- (self.extrapolation_max_tcl,
- 0, wx.LEFT, 5)])
- self._layout_extrapolation_low()
- self._layout_extrapolation_high()
- self.extrapolation_low_high_sizer.AddMany([(self.low_extrapolation_sizer,
- 0, wx.LEFT | wx.BOTTOM | wx.TOP, 5),
- (self.high_extrapolation_sizer,
- 0, wx.LEFT | wx.BOTTOM | wx.TOP, 5)])
- self.extrapolation_sizer.AddMany([(self.extrapolation_range_sizer),
- (self.extrapolation_low_high_sizer)])
-
- def _layout_volume_surface_sizer(self):
- """
- Draw widgets related to volume and surface
- """
- unit_volume = ''
- unit_surface = '[1/A]'
- uncertainty = "+/-"
- volume_txt = wx.StaticText(self, -1, 'Volume Fraction')
- self.volume_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH, -1),
- name='volume_tcl')
- wx.EVT_TEXT(self, self.volume_tcl.GetId(), self._on_out_text)
- self.volume_tcl.SetToolTipString("Volume fraction.")
- self.volume_err_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH, -1),
- name='volume_err_tcl')
- wx.EVT_TEXT(self, self.volume_err_tcl.GetId(), self._on_out_text)
- hint_msg = "Uncertainty on the volume fraction."
- self.volume_err_tcl.SetToolTipString(hint_msg)
- volume_units_txt = wx.StaticText(self, -1, unit_volume)
-
- surface_txt = wx.StaticText(self, -1, 'Specific Surface')
- self.surface_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH, -1),
- name='surface_tcl')
- wx.EVT_TEXT(self, self.surface_tcl.GetId(), self._on_out_text)
- self.surface_tcl.SetToolTipString("Specific surface value.")
- self.surface_err_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH, -1),
- name='surface_err_tcl')
- wx.EVT_TEXT(self, self.surface_err_tcl.GetId(), self._on_out_text)
- hint_msg = "Uncertainty on the specific surface."
- self.surface_err_tcl.SetToolTipString(hint_msg)
- surface_units_txt = wx.StaticText(self, -1, unit_surface)
- iy = 0
- ix = 0
- self.volume_surface_sizer.Add(volume_txt, (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- ix += 1
- self.volume_surface_sizer.Add(self.volume_tcl, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 20)
- ix += 1
- self.volume_surface_sizer.Add(wx.StaticText(self, -1, uncertainty),
- (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 10)
- ix += 1
- self.volume_surface_sizer.Add(self.volume_err_tcl, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 10)
- ix += 1
- self.volume_surface_sizer.Add(volume_units_txt, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 10)
- iy += 1
- ix = 0
- self.volume_surface_sizer.Add(surface_txt, (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- ix += 1
- self.volume_surface_sizer.Add(self.surface_tcl, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 20)
- ix += 1
- self.volume_surface_sizer.Add(wx.StaticText(self, -1, uncertainty),
- (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 10)
- ix += 1
- self.volume_surface_sizer.Add(self.surface_err_tcl, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 10)
- ix += 1
- self.volume_surface_sizer.Add(surface_units_txt, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 10)
- static_line = wx.StaticLine(self, -1)
- iy += 1
- ix = 0
-
- def _layout_invariant_sizer(self):
- """
- Draw widgets related to invariant
- """
- uncertainty = "+/-"
- unit_invariant = '[1/(cm*A^3)]'
- invariant_total_txt = wx.StaticText(self, -1, 'Invariant Total [Q*]')
- self.invariant_total_tcl = OutputTextCtrl(self, -1,
- size=(_BOX_WIDTH, -1),
- name='invariant_total_tcl')
- msg_hint = "Total invariant [Q*], including extrapolated regions."
- self.invariant_total_tcl.SetToolTipString(msg_hint)
- self.invariant_total_err_tcl = OutputTextCtrl(self, -1,
- size=(_BOX_WIDTH, -1),
- name='invariant_total_err_tcl')
- hint_msg = "Uncertainty on invariant."
- self.invariant_total_err_tcl.SetToolTipString(hint_msg)
- invariant_total_units_txt = wx.StaticText(self, -1, unit_invariant,
- size=(80, -1))
-
- #Invariant total
- iy = 0
- ix = 0
- self.invariant_sizer.Add(invariant_total_txt, (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- ix += 1
- self.invariant_sizer.Add(self.invariant_total_tcl, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 10)
- ix += 1
- self.invariant_sizer.Add(wx.StaticText(self, -1, uncertainty),
- (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 10)
- ix += 1
- self.invariant_sizer.Add(self.invariant_total_err_tcl, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 10)
- ix += 1
- self.invariant_sizer.Add(invariant_total_units_txt, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 10)
-
- def _layout_inputs_sizer(self):
- """
- Draw widgets related to inputs
- """
- contrast_txt = wx.StaticText(self, -1, 'Contrast:')
- self.contrast_tcl = InvTextCtrl(self, -1, size=(_BOX_WIDTH, 20),
- style=0, name='contrast_tcl')
- wx.EVT_TEXT(self, self.contrast_tcl.GetId(), self._on_text)
- contrast_hint_txt = "Contrast"
- self.contrast_tcl.SetToolTipString(contrast_hint_txt)
- contrast_unit_txt = wx.StaticText(self, -1, '[1/A^2]', size=(40, -1))
- porod_const_txt = wx.StaticText(self, -1,
- 'Porod\nConstant:\n(optional)\n')
- porod_unit_txt = wx.StaticText(self, -1, '[1/(cm*A^4)]', size=(80, -1))
- self.porod_constant_tcl = InvTextCtrl(self, -1,
- size=(_BOX_WIDTH, 20), style=0,
- name='porod_constant_tcl')
- wx.EVT_TEXT(self, self.porod_constant_tcl.GetId(), self._on_text)
- porod_const_hint_txt = "Porod Constant"
- self.porod_constant_tcl.SetToolTipString(porod_const_hint_txt)
-
- background_txt = wx.StaticText(self, -1, 'Background:')
- self.background_tcl = InvTextCtrl(self, -1, size=(_BOX_WIDTH, 20),
- style=0, name='background_tcl')
- wx.EVT_TEXT(self, self.background_tcl.GetId(), self._on_text)
- background_hint_txt = "Background"
- self.background_tcl.SetToolTipString(background_hint_txt)
- background_unit_txt = wx.StaticText(self, -1, '[1/cm]')
- scale_txt = wx.StaticText(self, -1, 'Scale:')
- self.scale_tcl = InvTextCtrl(self, -1, size=(_BOX_WIDTH, 20), style=0,
- name='scale_tcl')
- wx.EVT_TEXT(self, self.scale_tcl.GetId(), self._on_text)
- scale_hint_txt = "Scale"
- self.scale_tcl.SetToolTipString(scale_hint_txt)
- self.sizer_input.AddMany([(background_txt, 0, wx.LEFT | wx.BOTTOM, 5),
- (self.background_tcl, 0, wx.LEFT | wx.BOTTOM, 5),
- (background_unit_txt, 0, wx.LEFT | wx.BOTTOM, 5),
- (scale_txt, 0, wx.LEFT | wx.BOTTOM, 10),
- (self.scale_tcl, 0, wx.LEFT | wx.BOTTOM | wx.RIGHT, 5),
- (10, 10),
- (contrast_txt, 0, wx.LEFT | wx.BOTTOM, 5),
- (self.contrast_tcl, 0, wx.LEFT | wx.BOTTOM, 5),
- (contrast_unit_txt, 0, wx.LEFT | wx.BOTTOM, 5),
- (porod_const_txt, 0, wx.LEFT, 10),
- (self.porod_constant_tcl, 0, wx.LEFT | wx.BOTTOM | wx.RIGHT, 5),
- (porod_unit_txt, 0, wx.LEFT | wx.BOTTOM, 5)])
- self.inputs_sizer.Add(self.sizer_input)
-
- def _layout_outputs_sizer(self):
- """
- Draw widgets related to outputs
- """
- self._layout_volume_surface_sizer()
- self._layout_invariant_sizer()
- static_line = wx.StaticLine(self, -1)
- self.outputs_sizer.AddMany([(self.volume_surface_sizer,
- 0, wx.TOP | wx.BOTTOM, 10),
- (static_line, 0, wx.EXPAND, 0),
- (self.invariant_sizer, 0, wx.TOP | wx.BOTTOM, 10)])
- def _layout_button(self):
- """
- Do the layout for the button widgets
- """
- #compute button
- id = wx.NewId()
- self.button_calculate = wx.Button(self, id, "Compute",
- name='compute_invariant')
- self.button_calculate.SetToolTipString("Compute invariant")
- self.Bind(wx.EVT_BUTTON, self.compute_invariant, id=id)
- #detail button
- id = wx.NewId()
- self.button_details = wx.Button(self, id, "Details?")
- hint_msg = "Get more details of computation such as fraction from extrapolation"
- self.button_details.SetToolTipString(hint_msg)
- self.Bind(wx.EVT_BUTTON, self.display_details, id=id)
- #help button
- id = wx.NewId()
- self.button_help = wx.Button(self, id, "HELP")
- self.button_help.SetToolTipString("Invariant Documentation")
- self.Bind(wx.EVT_BUTTON, self.on_help, id=id)
- self.button_sizer.AddMany([((20, 20), 1, wx.EXPAND | wx.ADJUST_MINSIZE, 0),
- (self.button_details, 0, wx.ALL, 10),
- (self.button_calculate, 0,
- wx.RIGHT | wx.TOP | wx.BOTTOM, 10),
- (self.button_help, 0,
- wx.RIGHT | wx.TOP | wx.BOTTOM, 10),])
- def _do_layout(self):
- """
- Draw window content
- """
- self._define_structure()
- self._layout_data_name()
- self._layout_extrapolation()
- self._layout_inputs_sizer()
- self._layout_outputs_sizer()
- self._layout_button()
- self.main_sizer.AddMany([(self.data_name_boxsizer, 0, wx.ALL, 10),
- (self.outputs_sizer, 0,
- wx.LEFT | wx.RIGHT | wx.BOTTOM, 10),
- (self.button_sizer, 0, wx.LEFT | wx.RIGHT, 15),
- (self.inputs_sizer, 0,
- wx.LEFT | wx.RIGHT | wx.BOTTOM, 10),
- (self.extrapolation_sizer, 0,
- wx.LEFT | wx.RIGHT | wx.BOTTOM, 10)])
- self.SetSizer(self.main_sizer)
- self.SetAutoLayout(True)
-
- def on_help(self, event):
- """
- Bring up the Invariant Documentation whenever the HELP button is
- clicked.
-
- Calls DocumentationWindow with the path of the location within the
- documentation tree (after /doc/ ....". Note that when using old
- versions of Wx (before 2.9) and thus not the release version of
- installers, the help comes up at the top level of the file as
- webbrowser does not pass anything past the # to the browser when it is
- running "file:///...."
-
- :param evt: Triggers on clicking the help button
- """
-
- _TreeLocation = "user/sasgui/perspectives/invariant/invariant_help.html"
- _doc_viewer = DocumentationWindow(self, -1, _TreeLocation, "",
- "Invariant Help")
-
-
-class InvariantDialog(wx.Dialog):
- """
- Invariant Dialog
- """
- def __init__(self, parent=None, id=1, graph=None,
- data=None, title="Invariant", base=None):
- wx.Dialog.__init__(self, parent, id, title, size=(PANEL_WIDTH,
- PANEL_HEIGHT))
- self.panel = InvariantPanel(self)
- self.Centre()
- self.Show(True)
-
-class InvariantWindow(wx.Frame):
- """
- Invariant Window
- """
- def __init__(self, parent=None, id=1, graph=None,
- data=None, title="Invariant", base=None):
-
- wx.Frame.__init__(self, parent, id, title, size=(PANEL_WIDTH + 100,
- PANEL_HEIGHT + 100))
- from sas.sascalc.dataloader.loader import Loader
- self.loader = Loader()
- path = "C:/ECLPS/workspace/trunk/sasdataloader/test/ascii_test_3.txt"
- data = self.loader.load(path)
- self.panel = InvariantPanel(self)
-
- data.name = data.filename
- self.panel.set_data(data)
- self.Centre()
- self.Show(True)
-
-class MyApp(wx.App):
- """
- Test App
- """
- def OnInit(self):
- """
- Init
- """
- wx.InitAllImageHandlers()
- frame = InvariantWindow()
- frame.Show(True)
- self.SetTopWindow(frame)
-
- return True
-
-# end of class MyApp
-
-if __name__ == "__main__":
- app = MyApp(0)
- app.MainLoop()
+"""
+This module provides the GUI for the invariant perspective panel
+
+"""
+import copy
+import time
+import sys
+import os
+import wx
+import logging
+
+from wx.lib.scrolledpanel import ScrolledPanel
+from sas.sascalc.invariant import invariant
+
+from sas.sasgui.guiframe.utils import format_number
+from sas.sasgui.guiframe.utils import check_float
+from sas.sasgui.guiframe.events import StatusEvent
+from sas.sasgui.guiframe.events import AppendBookmarkEvent
+from sas.sasgui.perspectives.invariant.invariant_details import InvariantDetailsPanel
+from sas.sasgui.perspectives.invariant.invariant_details import InvariantContainer
+from sas.sasgui.perspectives.invariant.invariant_widgets import OutputTextCtrl
+from sas.sasgui.perspectives.invariant.invariant_widgets import InvTextCtrl
+from sas.sasgui.perspectives.invariant.invariant_state import InvariantState as IState
+from sas.sasgui.guiframe.panel_base import PanelBase
+from sas.sasgui.guiframe.documentation_window import DocumentationWindow
+
+logger = logging.getLogger(__name__)
+
+# The minimum q-value to be used when extrapolating
+Q_MINIMUM = 1e-5
+# The maximum q-value to be used when extrapolating
+Q_MAXIMUM = 10
+# the ratio of maximum q value/(qmax of data) to plot the theory data
+Q_MAXIMUM_PLOT = 3
+# the number of points to consider during fit
+NPTS = 10
+#Default value for background
+BACKGROUND = 0.0
+#default value for the scale
+SCALE = 1.0
+#default value of the contrast
+CONTRAST = 1.0
+#default value of the power used for power law
+POWER = 4.0
+#Invariant panel size
+_BOX_WIDTH = 76
+
+
+if sys.platform.count("win32") > 0:
+ _STATICBOX_WIDTH = 450
+ PANEL_WIDTH = 500
+ PANEL_HEIGHT = 700
+ FONT_VARIANT = 0
+else:
+ _STATICBOX_WIDTH = 490
+ PANEL_WIDTH = 530
+ PANEL_HEIGHT = 700
+ FONT_VARIANT = 1
+
+
+class InvariantPanel(ScrolledPanel, PanelBase):
+ """
+ Main class defining the sizers (wx "panels") used to draw the
+ Invariant GUI.
+ """
+ ## Internal nickname for the window, used by the AUI manager
+ window_name = "Invariant"
+ ## Name to appear on the window title bar
+ window_caption = "Invariant"
+ ## Flag to tell the AUI manager to put this panel in the center pane
+ CENTER_PANE = True
+ def __init__(self, parent, data=None, manager=None, *args, **kwds):
+ kwds["size"] = (PANEL_WIDTH, PANEL_HEIGHT)
+ kwds["style"] = wx.FULL_REPAINT_ON_RESIZE
+ ScrolledPanel.__init__(self, parent=parent, *args, **kwds)
+ PanelBase.__init__(self, parent)
+ self.SetupScrolling()
+ #Font size
+ self.SetWindowVariant(variant=FONT_VARIANT)
+ #Object that receive status event
+ self.parent = parent.parent
+ #plug-in using this panel
+ self._manager = manager
+ #Data uses for computation
+ self._data = data
+ self._scale = SCALE
+ self._background = BACKGROUND
+ self._bmark = None
+ self.bookmark_num = 0
+ self.state = None
+ self.popUpMenu = None
+ self._set_bookmark_menu()
+ #Init state
+ self.set_state()
+ # default flags for state
+ self.new_state = False
+ self.is_state_data = False
+ self.is_power_out = False
+ self._set_analysis(False)
+
+ #container of invariant value
+ self.inv_container = None
+ #sizers
+ self.main_sizer = None
+ self.outputs_sizer = None
+ self.data_name_boxsizer = None
+ self.hint_msg_sizer = None
+ self.data_name_sizer = None
+ self.data_range_sizer = None
+ self.sizer_input = None
+ self.inputs_sizer = None
+ self.extrapolation_sizer = None
+ self.extrapolation_range_sizer = None
+ self.extrapolation_low_high_sizer = None
+ self.low_extrapolation_sizer = None
+ self.low_q_sizer = None
+ self.high_extrapolation_sizer = None
+ self.high_q_sizer = None
+ self.volume_surface_sizer = None
+ self.invariant_sizer = None
+ self.button_sizer = None
+ self.save_button_sizer = None
+ self.hint_msg_txt = None
+ self.data_name_tcl = None
+ self.data_min_tcl = None
+ self.data_max_tcl = None
+ #Draw the panel
+ self._do_layout()
+ self.reset_panel()
+ self._reset_state_list()
+ ## Default file location for save
+ self._default_save_location = os.getcwd()
+ if self.parent is not None:
+ msg = ""
+ wx.PostEvent(self.parent, StatusEvent(status=msg, info="info"))
+ self._default_save_location = \
+ self.parent.get_save_location()
+
+ self._set_bookmark_flag(False)
+
+ def get_data(self):
+ """
+ """
+ return self._manager.get_data()
+
+ def get_state(self):
+ """
+ """
+ return self.state
+
+ def set_data(self, data):
+ """
+ Set the data
+ """
+ self._data = data
+ #edit the panel
+ if self._data is not None:
+ self._delete_bookmark_items()
+ self.get_state_by_num(0)
+ data_name = self._data.name
+ data_qmin = min(self._data.x)
+ data_qmax = max(self._data.x)
+ self.data_name_tcl.SetValue(str(data_name))
+ self.data_min_tcl.SetValue(str(data_qmin))
+ self.data_max_tcl.SetValue(str(data_qmax))
+ self.reset_panel()
+ self.compute_invariant(event=None)
+ self.state.file = self._data.name
+ #Reset the list of states
+ self.state.data = copy.deepcopy(data)
+ self._set_save_flag(True)
+ self._set_preview_flag(False)
+ self._reset_state_list()
+ self._set_bookmark_flag(True)
+ self._set_analysis(True)
+ return True
+
+ def _delete_bookmark_items(self):
+ """
+ Delete bookmark menu items
+ """
+ # delete toolbar menu
+ self.parent.reset_bookmark_menu(self)
+ self.parent._update_toolbar_helper()
+ # delete popUpMenu items
+ pos = 0
+ for item in self.popUpMenu.GetMenuItems():
+ pos += 1
+ if pos < 3:
+ continue
+ self.popUpMenu.DestroyItem(item)
+
+ def set_message(self):
+ """
+ Display warning message if available
+ """
+ if self.inv_container is not None:
+ if self.inv_container.existing_warning:
+ msg = "Warning! Computations on invariant require your "
+ msg += "attention.\nPlease click on Details button."
+ self.hint_msg_txt.SetForegroundColour("red")
+
+ wx.PostEvent(self.parent,
+ StatusEvent(status=msg, info="warning"))
+ else:
+ msg = "For more information, click on Details button."
+ self.hint_msg_txt.SetForegroundColour("black")
+ wx.PostEvent(self.parent,
+ StatusEvent(status=msg, info="info"))
+ self.hint_msg_txt.SetLabel(msg)
+ self.Layout()
+
+ def set_manager(self, manager):
+ """
+ set value for the manager
+ """
+ self._manager = manager
+
+ def save_project(self, doc=None):
+ """
+ return an xml node containing state of the panel
+ that guiframe can write to file
+ """
+ data = self.get_data()
+ state = self.get_state()
+ if data is not None:
+ new_doc = self._manager.state_reader.write_toXML(data, state)
+ if new_doc is not None:
+ if doc is not None and hasattr(doc, "firstChild"):
+ child = new_doc.getElementsByTagName("SASentry")
+ for item in child:
+ doc.firstChild.appendChild(item)
+ else:
+ doc = new_doc
+ return doc
+
+ def set_state(self, state=None, data=None):
+ """
+ set state when loading it from a .inv/.svs file
+ """
+
+ if state is None and data is None:
+ self.state = IState()
+ elif state is None or data is None:
+ return
+ else:
+ new_state = copy.deepcopy(state)
+ self.new_state = True
+ if not self.set_data(data):
+ return
+
+ self.state = new_state
+ self.state.file = data.name
+
+ num = self.state.saved_state['state_num']
+ if int(num) > 0:
+ self._set_undo_flag(True)
+ if int(num) < len(state.state_list) - 1:
+ self._set_redo_flag(True)
+
+ # get bookmarks
+ self.bookmark_num = len(self.state.bookmark_list)
+ total_bookmark_num = self.bookmark_num + 1
+
+ for ind in range(1, total_bookmark_num):
+ #bookmark_num = ind
+ value = self.state.bookmark_list[ind]
+ name = "%d] bookmarked at %s on %s" % (ind, value[0], value[1])
+ # append it to menu
+ id = wx.NewId()
+ self.popUpMenu.Append(id, name, str(''))
+ wx.EVT_MENU(self, id, self._back_to_bookmark)
+ wx.PostEvent(self.parent,
+ AppendBookmarkEvent(title=name,
+ hint='',
+ handler=self._back_to_bookmark))
+
+ self.get_state_by_num(state_num=str(num))
+
+ self._get_input_list()
+ #make sure that the data is reset (especially
+ # when loaded from a inv file)
+ self.state.data = self._data
+ self._set_preview_flag(False)
+ self.new_state = False
+ self.is_state_data = False
+ self._set_analysis(True)
+
+ def clear_panel(self):
+ """
+ Clear panel to defaults, used by set_state of manager
+ """
+
+ self._data = None
+ # default data testctrl
+ self.hint_msg_txt.SetLabel('')
+ data_name = ''
+ data_qmin = ''
+ data_qmax = ''
+ self.data_name_tcl.SetValue(str(data_name))
+ self.data_min_tcl.SetValue(str(data_qmin))
+ self.data_max_tcl.SetValue(str(data_qmax))
+ #reset output textctrl
+ self._reset_output()
+ #reset panel
+ self.reset_panel()
+ #reset state w/o data
+ self.set_state()
+ # default flags for state
+ self.new_state = False
+ self.is_state_data = False
+ self.is_power_out = False
+
+ def get_background(self):
+ """
+ return the background textcrtl value as a float
+ """
+ background = self.background_tcl.GetValue().lstrip().rstrip()
+ if background == "":
+ raise ValueError, "Need a background"
+ if check_float(self.background_tcl):
+ return float(background)
+ else:
+ msg = "Receive invalid value for background : %s" % (background)
+ raise ValueError, msg
+
+ def get_scale(self):
+ """
+ return the scale textcrtl value as a float
+ """
+ scale = self.scale_tcl.GetValue().lstrip().rstrip()
+ if scale == "":
+ raise ValueError, "Need a background"
+ if check_float(self.scale_tcl):
+ if float(scale) <= 0.0:
+ self.scale_tcl.SetBackgroundColour("pink")
+ self.scale_tcl.Refresh()
+ msg = "Receive invalid value for scale: %s" % (scale)
+ raise ValueError, msg
+ return float(scale)
+ else:
+ raise ValueError, "Receive invalid value for scale : %s" % (scale)
+
+ def get_contrast(self):
+ """
+ return the contrast textcrtl value as a float
+ """
+ par_str = self.contrast_tcl.GetValue().strip()
+ contrast = None
+ if par_str != " " and check_float(self.contrast_tcl):
+ contrast = float(par_str)
+ return contrast
+
+ def get_extrapolation_type(self, low_q, high_q):
+ """
+ get extrapolation type
+ """
+ extrapolation = None
+ if low_q and not high_q:
+ extrapolation = "low"
+ elif not low_q and high_q:
+ extrapolation = "high"
+ elif low_q and high_q:
+ extrapolation = "both"
+ return extrapolation
+
+ def get_porod_const(self):
+ """
+ return the porod constant textcrtl value as a float
+ """
+ par_str = self.porod_constant_tcl.GetValue().strip()
+ porod_const = None
+ if par_str != "" and check_float(self.porod_constant_tcl):
+ porod_const = float(par_str)
+ return porod_const
+
+ def get_volume(self, inv, contrast, extrapolation):
+ """
+ get volume fraction
+ """
+ if contrast is not None:
+ try:
+ v, dv = inv.get_volume_fraction_with_error(contrast=contrast,
+ extrapolation=extrapolation)
+ self.volume_tcl.SetValue(format_number(v))
+ self.volume_err_tcl.SetValue(format_number(dv))
+ except:
+ self.volume_tcl.SetValue(format_number(None))
+ self.volume_err_tcl.SetValue(format_number(None))
+ msg = "Error occurred computing volume "
+ msg += " fraction: %s" % sys.exc_value
+ wx.PostEvent(self.parent, StatusEvent(status=msg,
+ info="error",
+ type="stop"))
+
+ def get_surface(self, inv, contrast, porod_const, extrapolation):
+ """
+ get surface value
+ """
+ if contrast is not None and porod_const is not None:
+ try:
+ s, ds = inv.get_surface_with_error(contrast=contrast,
+ porod_const=porod_const,
+ extrapolation=extrapolation)
+ self.surface_tcl.SetValue(format_number(s))
+ self.surface_err_tcl.SetValue(format_number(ds))
+ except:
+ self.surface_tcl.SetValue(format_number(None))
+ self.surface_err_tcl.SetValue(format_number(None))
+ msg = "Error occurred computing "
+ msg += "specific surface: %s" % sys.exc_value
+ wx.PostEvent(self.parent, StatusEvent(status=msg, info="error",
+ type="stop"))
+
+ def get_total_qstar(self, inv, extrapolation):
+ """
+ get total qstar
+ """
+ try:
+ qstar_total, qstar_total_err = \
+ inv.get_qstar_with_error(extrapolation)
+ self.invariant_total_tcl.SetValue(format_number(qstar_total))
+ self.invariant_total_err_tcl.SetValue(\
+ format_number(qstar_total_err))
+ self.inv_container.qstar_total = qstar_total
+ self.inv_container.qstar_total_err = qstar_total_err
+ except:
+ self.inv_container.qstar_total = "Error"
+ self.inv_container.qstar_total_err = "Error"
+ self.invariant_total_tcl.SetValue(format_number(None))
+ self.invariant_total_err_tcl.SetValue(format_number(None))
+ msg = "Error occurred computing invariant using"
+ msg += " extrapolation: %s" % sys.exc_value
+ wx.PostEvent(self.parent, StatusEvent(status=msg, type="stop"))
+
+ def get_low_qstar(self, inv, npts_low, low_q=False):
+ """
+ get low qstar
+ """
+ if low_q:
+ try:
+ qstar_low, qstar_low_err = inv.get_qstar_low()
+ self.inv_container.qstar_low = qstar_low
+ self.inv_container.qstar_low_err = qstar_low_err
+ extrapolated_data = inv.get_extra_data_low(npts_in=npts_low)
+ power_low = inv.get_extrapolation_power(range='low')
+ if self.power_law_low.GetValue():
+ self.power_low_tcl.SetValue(format_number(power_low))
+ self._manager.plot_theory(data=extrapolated_data,
+ name="Low-Q extrapolation")
+ except:
+ self.inv_container.qstar_low = "ERROR"
+ self.inv_container.qstar_low_err = "ERROR"
+ self._manager.plot_theory(name="Low-Q extrapolation")
+ msg = "Error occurred computing low-Q "
+ msg += "invariant: %s" % sys.exc_value
+ wx.PostEvent(self.parent,
+ StatusEvent(status=msg, type="stop"))
+ raise
+ else:
+ try:
+ self._manager.plot_theory(name="Low-Q extrapolation")
+ except:
+ logger.error(sys.exc_value)
+
+ def get_high_qstar(self, inv, high_q=False):
+ """
+ get high qstar
+ """
+ if high_q:
+ try:
+ qmax_plot = Q_MAXIMUM_PLOT * max(self._data.x)
+ if qmax_plot > Q_MAXIMUM:
+ qmax_plot = Q_MAXIMUM
+ qstar_high, qstar_high_err = inv.get_qstar_high()
+ self.inv_container.qstar_high = qstar_high
+ self.inv_container.qstar_high_err = qstar_high_err
+ power_high = inv.get_extrapolation_power(range='high')
+ self.power_high_tcl.SetValue(format_number(power_high))
+ high_out_data = inv.get_extra_data_high(q_end=qmax_plot,
+ npts=500)
+ self._manager.plot_theory(data=high_out_data,
+ name="High-Q extrapolation")
+ except:
+ #raise
+ self.inv_container.qstar_high = "ERROR"
+ self.inv_container.qstar_high_err = "ERROR"
+ self._manager.plot_theory(name="High-Q extrapolation")
+ msg = "Error occurred computing high-Q "
+ msg += "invariant: %s" % sys.exc_value
+ wx.PostEvent(self.parent, StatusEvent(status=msg,
+ type="stop"))
+ raise
+ else:
+ try:
+ self._manager.plot_theory(name="High-Q extrapolation")
+ except:
+ logger.error(sys.exc_value)
+
+ def get_qstar(self, inv):
+ """
+ get qstar
+ """
+ qstar, qstar_err = inv.get_qstar_with_error()
+ self.inv_container.qstar = qstar
+ self.inv_container.qstar_err = qstar_err
+
+ def set_extrapolation_low(self, inv, low_q=False):
+ """
+ return float value necessary to compute invariant a low q
+ """
+ #get funtion
+ if self.guinier.GetValue():
+ function_low = "guinier"
+ # get the function
+ power_low = None #2.0/3.0
+ if self.power_law_low.GetValue():
+ function_low = "power_law"
+ if self.fit_enable_low.GetValue():
+ #set value of power_low to none to allow fitting
+ power_low = None
+ else:
+ power_low = self.power_low_tcl.GetValue().lstrip().rstrip()
+ if check_float(self.power_low_tcl):
+ power_low = float(power_low)
+ else:
+ if low_q:
+ #Raise error only when qstar at low q is requested
+ msg = "Expect float for power at low q, "
+ msg += " got %s" % (power_low)
+ wx.PostEvent(self.parent,
+ StatusEvent(status=msg,
+ info="error",
+ type="stop"))
+
+ #Get the number of points to extrapolated
+ npts_low = self.npts_low_tcl.GetValue().lstrip().rstrip()
+ if check_float(self.npts_low_tcl):
+ npts_low = float(npts_low)
+ else:
+ if low_q:
+ msg = "Expect float for number of points at low q,"
+ msg += " got %s" % (npts_low)
+ wx.PostEvent(self.parent,
+ StatusEvent(status=msg,
+ info="error",
+ type="stop"))
+ #Set the invariant calculator
+ inv.set_extrapolation(range="low", npts=npts_low,
+ function=function_low, power=power_low)
+ return inv, npts_low
+
+
+ def set_extrapolation_high(self, inv, high_q=False):
+ """
+ return float value necessary to compute invariant a high q
+ """
+ power_high = None
+ #if self.power_law_high.GetValue():
+ function_high = "power_law"
+ if self.fit_enable_high.GetValue():
+ #set value of power_high to none to allow fitting
+ power_high = None
+ else:
+ power_high = self.power_high_tcl.GetValue().lstrip().rstrip()
+ if check_float(self.power_high_tcl):
+ power_high = float(power_high)
+ else:
+ if high_q:
+ #Raise error only when qstar at high q is requested
+ msg = "Expect float for power at high q,"
+ msg += " got %s" % (power_high)
+ wx.PostEvent(self.parent,
+ StatusEvent(status=msg,
+ info="error",
+ type="stop"))
+
+ npts_high = self.npts_high_tcl.GetValue().lstrip().rstrip()
+ if check_float(self.npts_high_tcl):
+ npts_high = float(npts_high)
+ else:
+ if high_q:
+ msg = "Expect float for number of points at high q,"
+ msg += " got %s" % (npts_high)
+ wx.PostEvent(self.parent, StatusEvent(status=msg,
+ info="error",
+ type="stop"))
+ inv.set_extrapolation(range="high", npts=npts_high,
+ function=function_high, power=power_high)
+ return inv, npts_high
+
+ def display_details(self, event):
+ """
+ open another panel for more details on invariant calculation
+ """
+ panel = InvariantDetailsPanel(parent=self,
+ qstar_container=self.inv_container)
+ panel.ShowModal()
+ panel.Destroy()
+ self.button_calculate.SetFocus()
+
+ def compute_invariant(self, event=None):
+ """
+ compute invariant
+ """
+ if self._data is None:
+ msg = "\n\nData must be loaded first in order"
+ msg += " to perform a compution..."
+ wx.PostEvent(self.parent, StatusEvent(status=msg))
+ # set a state for this computation for saving
+ elif event is not None:
+ self._set_compute_state(state='compute')
+ self._set_bookmark_flag(True)
+ msg = "\n\nStarting a new invariant computation..."
+ wx.PostEvent(self.parent, StatusEvent(status=msg))
+
+
+ if self._data is None:
+ return
+ self.button_details.Enable()
+ #clear outputs textctrl
+ self._reset_output()
+ try:
+ background = self.get_background()
+ scale = self.get_scale()
+ except:
+ msg = "Invariant Error: %s" % (sys.exc_value)
+ wx.PostEvent(self.parent, StatusEvent(status=msg, type="stop"))
+ return
+
+ low_q = self.enable_low_cbox.GetValue()
+ high_q = self.enable_high_cbox.GetValue()
+ temp_data = copy.deepcopy(self._data)
+
+ #set invariant calculator
+ inv = invariant.InvariantCalculator(data=temp_data,
+ background=background,
+ scale=scale)
+ try:
+ inv, npts_low = self.set_extrapolation_low(inv=inv, low_q=low_q)
+ inv, npts_high = self.set_extrapolation_high(inv=inv, high_q=high_q)
+ except:
+ msg = "Error occurred computing invariant: %s" % sys.exc_value
+ wx.PostEvent(self.parent, StatusEvent(status=msg,
+ info="warning", type="stop"))
+ return
+ #check the type of extrapolation
+ extrapolation = self.get_extrapolation_type(low_q=low_q, high_q=high_q)
+
+ #Compute invariant
+ try:
+ self.get_qstar(inv=inv)
+ except:
+ msg = "Error occurred computing invariant: %s" % sys.exc_value
+ wx.PostEvent(self.parent, StatusEvent(status=msg,
+ info="warning",
+ type="stop"))
+ return
+ #self.Show(False)
+ r_msg = ''
+ try:
+ r_msg = 'Low Q: '
+ #Compute qstar extrapolated to low q range
+ self.get_low_qstar(inv=inv, npts_low=npts_low, low_q=low_q)
+ r_msg = 'High Q: '
+ #Compute qstar extrapolated to high q range
+ self.get_high_qstar(inv=inv, high_q=high_q)
+ r_msg = ''
+ #Compute qstar extrapolated to total q range
+ #and set value to txtcrtl
+ self.get_total_qstar(inv=inv, extrapolation=extrapolation)
+ # Parse additional parameters
+ porod_const = self.get_porod_const()
+ contrast = self.get_contrast()
+ except:
+ msg = r_msg + "Error occurred computing invariant: %s" % \
+ sys.exc_value
+ wx.PostEvent(self.parent, StatusEvent(status=msg,
+ info="error",
+ type="stop"))
+ try:
+ #Compute volume and set value to txtcrtl
+ self.get_volume(inv=inv, contrast=contrast,
+ extrapolation=extrapolation)
+ #compute surface and set value to txtcrtl
+ except:
+ msg = "Error occurred computing invariant: %s" % sys.exc_value
+ wx.PostEvent(self.parent, StatusEvent(status=msg,
+ info="warning",
+ type="stop"))
+ try:
+ self.get_surface(inv=inv, contrast=contrast,
+ porod_const=porod_const,
+ extrapolation=extrapolation)
+
+ except:
+ msg = "Error occurred computing invariant: %s" % sys.exc_value
+ wx.PostEvent(self.parent, StatusEvent(status=msg,
+ info="warning",
+ type="stop"))
+
+ #compute percentage of each invariant
+ self.inv_container.compute_percentage()
+
+ #display a message
+ self.set_message()
+
+ # reset power_out to default to get ready for another '_on_text'
+ if self.is_power_out == True:
+ self.state.container = copy.deepcopy(self.inv_container)
+ self.state.timestamp = self._get_time_stamp()
+ msg = self.state.__str__()
+ self.state.set_report_string()
+ self.is_power_out = False
+ wx.PostEvent(self.parent, StatusEvent(status=msg))
+
+ #enable the button_ok for more details
+ self._set_preview_flag(True)
+
+ if event is not None:
+ self._set_preview_flag(True)
+ self._set_save_flag(True)
+ wx.PostEvent(self.parent,
+ StatusEvent(status='\nFinished invariant computation...'))
+ #self.Show(True)
+ self.Refresh()
+
+ def on_undo(self, event=None):
+ """
+ Go back to the previous state
+
+ : param event: undo button event
+ """
+ if self.state.state_num < 0:
+ return
+ self.is_power_out = True
+ # get the previous state_num
+ pre_state_num = int(self.state.saved_state['state_num']) - 1
+
+ self.get_state_by_num(state_num=str(pre_state_num))
+
+ if float(pre_state_num) <= 0:
+ self._set_undo_flag(False)
+ else:
+ self._set_undo_flag(True)
+ self._set_redo_flag(True)
+ self.is_power_out = False
+ self._info_state_num()
+
+
+ def on_redo(self, event=None):
+ """
+ Go forward to the previous state
+
+ : param event: redo button event
+ """
+ self.is_power_out = True
+ # get the next state_num
+ next_state_num = int(self.state.saved_state['state_num']) + 1
+
+ self.get_state_by_num(state_num=str(next_state_num))
+
+ if float(next_state_num) + 2 > len(self.state.state_list):
+ self._set_redo_flag(False)
+ else:
+ self._set_redo_flag(True)
+
+ self._set_undo_flag(True)
+ self.is_power_out = False
+ self._info_state_num()
+
+ def on_preview(self, event=None):
+ """
+ Invoke report dialog panel
+
+ : param event: report button event
+ """
+ from sas.sasgui.perspectives.invariant.report_dialog import ReportDialog
+
+ self.state.set_report_string()
+ report_html_str = self.state.report_str
+ report_text_str = self.state.__str__()
+ report_img = self.state.image
+ report_list = [report_html_str, report_text_str, report_img]
+ dialog = ReportDialog(report_list, None, -1, "")
+ dialog.Show()
+
+ def get_state_by_num(self, state_num=None):
+ """
+ Get the state given by number
+
+ : param state_num: the given state number
+ """
+ if state_num is None:
+ return
+
+ backup_state_list = copy.deepcopy(self.state.state_list)
+
+ # get the previous state
+ try:
+ current_state = copy.deepcopy(self.state.state_list[str(state_num)])
+ # get the previously computed state number
+ #(computation before the state changes happened)
+ current_compute_num = str(current_state['compute_num'])
+ except:
+ raise
+
+ # get the state at pre_compute_num
+ comp_state = copy.deepcopy(self.state.state_list[current_compute_num])
+
+ # set the parameters
+ for key in comp_state:
+ value = comp_state[key]
+ self._set_property_value(key, value)
+
+ self.compute_invariant(event=None)
+
+ # set the input params at the state at pre_state_num
+ for key in current_state:
+ # set the inputs and boxes
+ value = current_state[key]
+ self._set_property_value(key, value)
+
+ self._enable_high_q_section(event=None)
+ self._enable_low_q_section(event=None)
+ self.state.state_list = backup_state_list
+ self.state.saved_state = current_state
+ self.state.state_num = state_num
+
+ def _set_property_value(self, key, value):
+ """
+ Set a property value
+ :param key: property name
+ :param value: value of the property
+ """
+ try:
+ if key in ['compute_num', 'file', 'is_time_machine', 'state_num']:
+ return
+ else:
+ attr = getattr(self, key)
+ if attr.__class__.__name__ == "StaticText":
+ return
+ if value in ["True", "False", True, False]:
+ value = bool(value)
+ else:
+ value = str(value)
+ attr.SetValue(value)
+ except:
+ logger.error("Invariant state: %s", sys.exc_value)
+
+ def get_bookmark_by_num(self, num=None):
+ """
+ Get the bookmark state given by number
+
+ : param num: the given bookmark number
+
+ """
+ current_state = {}
+ comp_state = {}
+ backup_state_list = copy.deepcopy(self.state.state_list)
+
+ # get the previous state
+ try:
+ _, _, current_state, comp_state = self.state.bookmark_list[int(num)]
+ except:
+ logger.error(sys.exc_value)
+ raise ValueError, "No such bookmark exists"
+
+ # set the parameters
+ for key in comp_state:
+ value = comp_state[key]
+ self._set_property_value(key, value)
+
+ self.compute_invariant(event=None)
+ # set the input params at the state of pre_state_num
+ for key in current_state:
+ value = current_state[key]
+ self._set_property_value(key, value)
+ self.state.saved_state = copy.deepcopy(current_state)
+
+ self._enable_high_q_section(event=None)
+ self._enable_low_q_section(event=None)
+ self.state.state_list = backup_state_list
+ #self.state.saved_state = current_state
+ #self.state.state_num = state_num
+
+ def reset_panel(self):
+ """
+ set the panel at its initial state.
+ """
+ self.background_tcl.SetValue(str(BACKGROUND))
+ self.scale_tcl.SetValue(str(SCALE))
+ self.contrast_tcl.SetValue(str(CONTRAST))
+ self.porod_constant_tcl.SetValue('')
+ self.npts_low_tcl.SetValue(str(NPTS))
+ self.enable_low_cbox.SetValue(False)
+ self.fix_enable_low.SetValue(True)
+ self.power_low_tcl.SetValue(str(POWER))
+ self.guinier.SetValue(True)
+ self.power_low_tcl.Disable()
+ self.enable_high_cbox.SetValue(False)
+ self.fix_enable_high.SetValue(True)
+ self.power_high_tcl.SetValue(str(POWER))
+ self.npts_high_tcl.SetValue(str(NPTS))
+ self.button_details.Disable()
+ #Change the state of txtcrtl to enable/disable
+ self._enable_low_q_section()
+ #Change the state of txtcrtl to enable/disable
+ self._enable_high_q_section()
+ self._reset_output()
+ self._set_undo_flag(False)
+ self._set_redo_flag(False)
+ self._set_bookmark_flag(False)
+ self._set_preview_flag(False)
+ self._set_save_flag(False)
+ self.button_calculate.SetFocus()
+ #self.SetupScrolling()
+ self._set_analysis(False)
+
+ def _set_state(self, event):
+ """
+ Set the state list
+
+ :param event: rb/cb event
+ """
+ if event is None:
+ return
+ obj = event.GetEventObject()
+ name = str(obj.GetName())
+ value = str(obj.GetValue())
+ rb_list = [['power_law_low', 'guinier'],
+ ['fit_enable_low', 'fix_enable_low'],
+ ['fit_enable_high', 'fix_enable_high']]
+
+ try:
+ if value is None or value.lstrip().rstrip() == '':
+ value = 'None'
+ setattr(self.state, name, str(value))
+ self.state.saved_state[name] = str(value)
+
+ # set the count part of radio button clicked
+ #False for the saved_state
+ for title, content in rb_list:
+ if name == title:
+ name = content
+ value = False
+ elif name == content:
+ name = title
+ value = False
+ self.state.saved_state[name] = str(value)
+
+ # Instead of changing the future, create a new future.
+ max_state_num = len(self.state.state_list) - 1
+ self.state.saved_state['state_num'] = max_state_num
+
+ self.state.saved_state['state_num'] += 1
+ self.state.state_num = self.state.saved_state['state_num']
+ self.state.state_list[str(self.state.state_num)] = \
+ self.state.clone_state()
+ except:
+ logger.error(sys.exc_value)
+
+ self._set_undo_flag(True)
+ self._set_redo_flag(False)
+ #event.Skip()
+
+ def _set_compute_state(self, state=None):
+ """
+ Notify the compute_invariant state to self.state
+
+ : param state: set 'compute' when the computation is
+ activated by the 'compute' button, else None
+
+ """
+ # reset the default
+ if state != 'compute':
+ self.new_state = False
+ self.is_power_out = False
+ else:
+ self.is_power_out = True
+ # Instead of changing the future, create a new future.
+ max_state_num = len(self.state.state_list) - 1
+ self.state.saved_state['state_num'] = max_state_num
+ # A new computation is also A state
+ #copy.deepcopy(self.state.saved_state)
+ temp_saved_states = self.state.clone_state()
+ temp_saved_states['state_num'] += 1
+ self.state.state_num = temp_saved_states['state_num']
+
+
+ # set the state number of the computation
+ if state == 'compute':
+ temp_saved_states['compute_num'] = self.state.state_num
+ self.state.saved_state = copy.deepcopy(temp_saved_states)
+ #copy.deepcopy(self.state.saved_state)
+ self.state.state_list[str(self.state.state_num)] = \
+ self.state.clone_state()
+
+ # A computation is a new state, so delete the states with any higher
+ # state numbers
+ for i in range(self.state.state_num + 1, len(self.state.state_list)):
+ try:
+ del self.state.state_list[str(i)]
+ except:
+ logger.error(sys.exc_value)
+ # Enable the undo button if it was not
+ self._set_undo_flag(True)
+ self._set_redo_flag(False)
+
+ def _reset_state_list(self, data=None):
+ """
+ Reset the state_list just before data was loading:
+ Used in 'set_current_data()'
+ """
+ #if data is None: return
+ #temp_state = self.state.clone_state()
+ #copy.deepcopy(self.state.saved_state)
+ # Clear the list
+ self.state.state_list.clear()
+ self.state.bookmark_list.clear()
+ # Set defaults
+ self.state.saved_state['state_num'] = 0
+ self.state.saved_state['compute_num'] = 0
+ if self._data is not None:
+ self.state.saved_state['file'] = str(self._data.name)
+ else:
+ self.state.saved_state['file'] = 'None'
+ self.state.file = self.state.saved_state['file']
+
+ self.state.state_num = self.state.saved_state['state_num']
+ self.state.timestamp = "('00:00:00', '00/00/0000')"
+
+ # Put only the current state in the list
+ #copy.deepcopy(self.state.saved_state)
+ self.state.state_list[str(self.state.state_num)] = \
+ self.state.clone_state()
+ self._set_undo_flag(False)
+ self._set_redo_flag(False)
+ self._set_bookmark_flag(False)
+ self._set_preview_flag(False)
+ self._set_save_flag(False)
+
+
+ def _on_text(self, event):
+ """
+ Catch text change event to add the state to the state_list
+
+ :param event: txtctr event ; assumes not None
+
+ """
+ if self._data is None:
+ return
+ # check if this event is from do/undo button
+ if self.state.saved_state['is_time_machine'] or self.new_state:
+ #event.Skip()
+ return
+
+ # get the object
+ obj = event.GetEventObject()
+ name = str(obj.GetName())
+ value = str(obj.GetValue())
+ state_num = self.state.saved_state['state_num']
+
+ # text event is a new state, so delete the states with higher state_num
+ # i.e., change the future
+ for i in range(int(state_num) + 1, len(self.state.state_list)):
+ try:
+ del self.state.state_list[str(i)]
+ except:
+ logger.error(sys.exc_value)
+
+ # try to add new state of the text changes in the state_list
+ try:
+ if value.strip() is None:
+ value = ''
+ setattr(self.state, name, str(value))
+ self.state.saved_state[name] = str(value)
+ self.state.input_list[name] = str(value)
+ if not self.is_power_out:
+ if name != 'power_low_tcl' and name != 'power_high_tcl':
+ self.state.saved_state['state_num'] += 1
+ self.state.state_num = self.state.saved_state['state_num']
+ self.state.state_list[str(self.state.state_num)] = self.state.clone_state()
+ except:
+ logger.error(sys.exc_value)
+
+ self._set_undo_flag(True)
+ self._set_redo_flag(False)
+ self._set_bookmark_flag(True)
+ self._set_preview_flag(False)
+
+ def _on_out_text(self, event):
+ """
+ Catch ouput text change to add the state
+
+ :param event: txtctr event ; assumes not None
+
+ """
+ # get the object
+ obj = event.GetEventObject()
+ name = str(obj.GetName())
+ value = str(obj.GetValue())
+ try:
+ self.state.saved_state[name] = str(value)
+ self.state.state_list[str(self.state.state_num)] = self.state.clone_state()
+ except:
+ logger.error(sys.exc_value)
+
+ def _get_input_list(self):
+ """
+ get input_list; called by set_state
+ """
+ # get state num of the last compute state
+ compute_num = self.state.saved_state['compute_num']
+ # find values and put into the input list
+ for key1, value1 in self.state.state_list[str(compute_num)].iteritems():
+ for key, _ in self.state.input_list.iteritems():
+ if key == key1:
+ self.state.input_list[key] = value1
+ break
+
+ def _set_bookmark_menu(self):
+ """
+ Setup 'bookmark' context menu
+ """
+ ## Create context menu for page
+ self.popUpMenu = wx.Menu()
+ id = wx.NewId()
+ self._bmark = wx.MenuItem(self.popUpMenu, id, "BookMark",
+ " Bookmark the panel to recall it later")
+ self.popUpMenu.AppendItem(self._bmark)
+ self._bmark.Enable(True)
+ wx.EVT_MENU(self, id, self.on_bookmark)
+ self.popUpMenu.AppendSeparator()
+ self.Bind(wx.EVT_CONTEXT_MENU, self._on_context_menu)
+
+ def on_bookmark(self, event):
+ """
+ Save the panel state in memory and add the list on
+ the popup menu on bookmark context menu event
+ """
+ if self._data is None:
+ return
+ if event is None:
+ return
+ self.bookmark_num += 1
+ # date and time of the event
+ my_time, date = self._get_time_stamp()
+ _ = self.state.state_num
+ compute_num = self.state.saved_state['compute_num']
+ # name and message of the bookmark list
+ msg = "State saved at %s on %s" % (my_time, date)
+ ## post help message for the selected model
+ msg += " Right click on the panel to retrieve this state"
+ #wx.PostEvent(self.parent.parent, StatusEvent(status = msg ))
+ name = "%d] bookmarked at %s on %s" % (self.bookmark_num, my_time, date)
+
+ # append it to menu
+ id = wx.NewId()
+ self.popUpMenu.Append(id, name, str(msg))
+ wx.EVT_MENU(self, id, self._back_to_bookmark)
+ state = self.state.clone_state()
+ comp_state = copy.deepcopy(self.state.state_list[str(compute_num)])
+ self.state.bookmark_list[self.bookmark_num] = [my_time, date,
+ state, comp_state]
+ self.state.toXML(self, doc=None, entry_node=None)
+
+ wx.PostEvent(self.parent, StatusEvent(status=msg, info="info"))
+ wx.PostEvent(self.parent,
+ AppendBookmarkEvent(title=name,
+ hint=str(msg),
+ handler=self._back_to_bookmark))
+
+ def _back_to_bookmark(self, event):
+ """
+ Bring the panel back to the state of bookmarked requested by
+ context menu event
+ and set it as a new state
+ """
+ self._manager.on_perspective(event)
+ menu = event.GetEventObject()
+ ## post help message for the selected model
+ msg = menu.GetHelpString(event.GetId())
+ msg += " reloaded"
+ wx.PostEvent(self.parent, StatusEvent(status=msg))
+
+ name = menu.GetLabel(event.GetId())
+
+ num, _ = name.split(']')
+ current_state_num = self.state.state_num
+ self.get_bookmark_by_num(num)
+ state_num = int(current_state_num) + 1
+
+ self.state.saved_state['state_num'] = state_num
+ #copy.deepcopy(self.state.saved_state)
+ self.state.state_list[str(state_num)] = self.state.clone_state()
+ self.state.state_num = state_num
+
+ self._set_undo_flag(True)
+ self._info_bookmark_num(event)
+
+ def _info_bookmark_num(self, event=None):
+ """
+ print the bookmark number in info
+
+ : event: popUpMenu event
+ """
+ if event is None:
+ return
+ # get the object
+ menu = event.GetEventObject()
+ item = menu.FindItemById(event.GetId())
+ text = item.GetText()
+ num = text.split(']')[0]
+ msg = "bookmark num = %s " % num
+
+ wx.PostEvent(self.parent, StatusEvent(status=msg))
+
+ def _info_state_num(self):
+ """
+ print the current state number in info
+ """
+ msg = "state num = "
+ msg += self.state.state_num
+
+ wx.PostEvent(self.parent, StatusEvent(status=msg))
+
+ def _get_time_stamp(self):
+ """
+ return time and date stings
+ """
+ # date and time
+ year, month, day, hour, minute, second, _, _, _ = \
+ time.localtime()
+ my_time = str(hour) + ":" + str(minute) + ":" + str(second)
+ date = str(month) + "/" + str(day) + "/" + str(year)
+ return my_time, date
+
+
+ def on_save(self, evt=None):
+ """
+ Save invariant state into a file
+ """
+ # Ask the user the location of the file to write to.
+ path = None
+ if self.parent is not None:
+ self._default_save_location = self.parent.get_save_location()
+ if self._default_save_location is None:
+ self._default_save_location = os.getcwd()
+ dlg = wx.FileDialog(self, "Choose a file",
+ self._default_save_location, \
+ self.window_caption, "*.inv", wx.SAVE)
+ if dlg.ShowModal() == wx.ID_OK:
+ path = dlg.GetPath()
+ self._default_save_location = os.path.dirname(path)
+ if self.parent is not None:
+ self.parent._default_save_location = \
+ self._default_save_location
+ else:
+ return None
+
+ dlg.Destroy()
+ # MAC always needs the extension for saving
+ extens = ".inv"
+ # Make sure the ext included in the file name
+ fName = os.path.splitext(path)[0] + extens
+ self._manager.save_file(filepath=fName, state=self.state)
+
+ def _show_message(self, mssg='', msg='Warning'):
+ """
+ Show warning message when resetting data
+ """
+ # no message for now
+ return True
+
+ def _reset_output(self):
+ """
+ clear outputs textcrtl
+ """
+ self.invariant_total_tcl.Clear()
+ self.invariant_total_err_tcl.Clear()
+ self.volume_tcl.Clear()
+ self.volume_err_tcl.Clear()
+ self.surface_tcl.Clear()
+ self.surface_err_tcl.Clear()
+ #prepare a new container to put result of invariant
+ self.inv_container = InvariantContainer()
+
+
+ def _on_context_menu(self, event):
+ """
+ On context menu
+ """
+ pos = event.GetPosition()
+ pos = self.ScreenToClient(pos)
+
+ self.PopupMenu(self.popUpMenu, pos)
+
+ def _define_structure(self):
+ """
+ Define main sizers needed for this panel
+ """
+ ## Box sizers must be defined first before
+ #defining buttons/textctrls (MAC).
+ self.main_sizer = wx.BoxSizer(wx.VERTICAL)
+ #Sizer related to outputs
+ outputs_box = wx.StaticBox(self, -1, "Outputs")
+ self.outputs_sizer = wx.StaticBoxSizer(outputs_box, wx.VERTICAL)
+ self.outputs_sizer.SetMinSize((_STATICBOX_WIDTH, -1))
+ #Sizer related to data
+ data_name_box = wx.StaticBox(self, -1, "I(q) Data Source")
+ self.data_name_boxsizer = wx.StaticBoxSizer(data_name_box, wx.VERTICAL)
+ self.data_name_boxsizer.SetMinSize((_STATICBOX_WIDTH, -1))
+ self.hint_msg_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.data_name_sizer = wx.BoxSizer(wx.HORIZONTAL)
+
+ self.data_range_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ #Sizer related to inputs
+ self.sizer_input = wx.FlexGridSizer(2, 6, 0, 0)
+ #Sizer related to inputs
+ inputs_box = wx.StaticBox(self, -1, "Customized Inputs")
+ self.inputs_sizer = wx.StaticBoxSizer(inputs_box, wx.VERTICAL)
+ self.inputs_sizer.SetMinSize((_STATICBOX_WIDTH, -1))
+ #Sizer related to extrapolation
+ extrapolation_box = wx.StaticBox(self, -1, "Extrapolation")
+ self.extrapolation_sizer = wx.StaticBoxSizer(extrapolation_box,
+ wx.VERTICAL)
+ self.extrapolation_sizer.SetMinSize((_STATICBOX_WIDTH, -1))
+ self.extrapolation_range_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.extrapolation_low_high_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ #Sizer related to extrapolation at low q range
+ low_q_box = wx.StaticBox(self, -1, "Low Q")
+ self.low_extrapolation_sizer = wx.StaticBoxSizer(low_q_box, wx.VERTICAL)
+
+ self.low_q_sizer = wx.GridBagSizer(5, 5)
+ #Sizer related to extrapolation at low q range
+ high_q_box = wx.StaticBox(self, -1, "High Q")
+ self.high_extrapolation_sizer = wx.StaticBoxSizer(high_q_box,
+ wx.VERTICAL)
+ self.high_q_sizer = wx.GridBagSizer(5, 5)
+ #sizer to define outputs
+ self.volume_surface_sizer = wx.GridBagSizer(5, 5)
+ #Sizer related to invariant output
+ self.invariant_sizer = wx.GridBagSizer(5, 5)
+ #Sizer related to button
+ self.button_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.button_sizer.SetMinSize((_STATICBOX_WIDTH, -1))
+ #Sizer related to save button
+ self.save_button_sizer = wx.BoxSizer(wx.HORIZONTAL)
+
+ def _layout_data_name(self):
+ """
+ Draw widgets related to data's name
+ """
+ #Sizer hint
+ hint_msg = ""
+
+ self.hint_msg_txt = wx.StaticText(self, -1, hint_msg)
+ self.hint_msg_txt.SetForegroundColour("red")
+ msg = "Highlight = mouse the mouse's cursor on the data until"
+ msg += " the plot's color changes to yellow"
+ self.hint_msg_txt.SetToolTipString(msg)
+ self.hint_msg_sizer.Add(self.hint_msg_txt)
+ #Data name [string]
+ data_name_txt = wx.StaticText(self, -1, 'Name:')
+
+ self.data_name_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH * 4, 20),
+ style=0)
+ self.data_name_tcl.SetToolTipString("Data's name.")
+ self.data_name_sizer.AddMany([(data_name_txt, 0, wx.LEFT | wx.RIGHT, 10),
+ (self.data_name_tcl, 0, wx.EXPAND)])
+ #Data range [string]
+ data_range_txt = wx.StaticText(self, -1, 'Total Q Range (1/A): ')
+ data_min_txt = wx.StaticText(self, -1, 'Min : ')
+ self.data_min_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH, 20),
+ style=0, name='data_min_tcl')
+ self.data_min_tcl.SetToolTipString("The minimum value of q range.")
+ data_max_txt = wx.StaticText(self, -1, 'Max : ')
+ self.data_max_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH, 20),
+ style=0, name='data_max_tcl')
+ self.data_max_tcl.SetToolTipString("The maximum value of q range.")
+ self.data_range_sizer.AddMany([(data_range_txt, 0, wx.RIGHT, 5),
+ (data_min_txt, 0, wx.RIGHT, 5),
+ (self.data_min_tcl, 0, wx.RIGHT, 20),
+ (data_max_txt, 0, wx.RIGHT, 5),
+ (self.data_max_tcl, 0, wx.RIGHT, 10)])
+ self.data_name_boxsizer.AddMany([(self.hint_msg_sizer, 0, wx.ALL, 5),
+ (self.data_name_sizer, 0, wx.ALL, 10),
+ (self.data_range_sizer, 0, wx.ALL, 10)])
+
+ def _enable_fit_power_law_low(self, event=None):
+ """
+ Enable and disable the power value editing
+ """
+ if event is not None:
+ self._set_bookmark_flag(True)
+ self._set_preview_flag(False)
+
+ if self.fix_enable_low.IsEnabled():
+
+ if self.fix_enable_low.GetValue():
+ self.fit_enable_low.SetValue(False)
+ self.power_low_tcl.Enable()
+ else:
+ self.fit_enable_low.SetValue(True)
+ self.power_low_tcl.Disable()
+ self._set_state(event=event)
+
+ def _enable_low_q_section(self, event=None):
+ """
+ Disable or enable some button if the user enable low q extrapolation
+ """
+ if event is not None:
+ self._set_bookmark_flag(True)
+ self._set_preview_flag(False)
+
+ if self.enable_low_cbox.GetValue():
+ self.npts_low_tcl.Enable()
+ self.fix_enable_low.Enable()
+ self.fit_enable_low.Enable()
+ self.guinier.Enable()
+ self.power_law_low.Enable()
+
+ else:
+ self.npts_low_tcl.Disable()
+ self.fix_enable_low.Disable()
+ self.fit_enable_low.Disable()
+ self.guinier.Disable()
+ self.power_law_low.Disable()
+
+ self._enable_power_law_low()
+ self._enable_fit_power_law_low()
+ self._set_state(event=event)
+ self.button_calculate.SetFocus()
+
+ def _enable_power_law_low(self, event=None):
+ """
+ Enable editing power law section at low q range
+ """
+ if event is not None:
+ self._set_bookmark_flag(True)
+ self._set_preview_flag(False)
+ if self.guinier.GetValue():
+ self.power_law_low.SetValue(False)
+ self.fix_enable_low.Disable()
+ self.fit_enable_low.Disable()
+ self.power_low_tcl.Disable()
+ else:
+ self.power_law_low.SetValue(True)
+ self.fix_enable_low.Enable()
+ self.fit_enable_low.Enable()
+ self.power_low_tcl.Enable()
+ self._enable_fit_power_law_low()
+ self._set_state(event=event)
+
+ def _layout_extrapolation_low(self):
+ """
+ Draw widgets related to extrapolation at low q range
+ """
+ self.enable_low_cbox = wx.CheckBox(self, -1,
+ "Enable Extrapolate Low Q",
+ name='enable_low_cbox')
+ wx.EVT_CHECKBOX(self, self.enable_low_cbox.GetId(),
+ self._enable_low_q_section)
+ self.fix_enable_low = wx.RadioButton(self, -1, 'Fix',
+ (10, 10), style=wx.RB_GROUP,
+ name='fix_enable_low')
+ self.Bind(wx.EVT_RADIOBUTTON, self._enable_fit_power_law_low,
+ id=self.fix_enable_low.GetId())
+ self.fit_enable_low = wx.RadioButton(self, -1, 'Fit', (10, 10),
+ name='fit_enable_low')
+ self.Bind(wx.EVT_RADIOBUTTON, self._enable_fit_power_law_low,
+ id=self.fit_enable_low.GetId())
+ self.guinier = wx.RadioButton(self, -1, 'Guinier',
+ (10, 10), style=wx.RB_GROUP,
+ name='guinier')
+ self.Bind(wx.EVT_RADIOBUTTON, self._enable_power_law_low,
+ id=self.guinier.GetId())
+ self.power_law_low = wx.RadioButton(self, -1, 'Power Law',
+ (10, 10), name='power_law_low')
+ self.Bind(wx.EVT_RADIOBUTTON, self._enable_power_law_low,
+ id=self.power_law_low.GetId())
+
+ npts_low_txt = wx.StaticText(self, -1, 'Npts')
+ self.npts_low_tcl = InvTextCtrl(self, -1,
+ size=(_BOX_WIDTH * 2 / 3, -1),
+ name='npts_low_tcl')
+ wx.EVT_TEXT(self, self.npts_low_tcl.GetId(), self._on_text)
+ msg_hint = "Number of Q points to consider"
+ msg_hint += "while extrapolating the low-Q region"
+ self.npts_low_tcl.SetToolTipString(msg_hint)
+ power_txt = wx.StaticText(self, -1, 'Power')
+ self.power_low_tcl = InvTextCtrl(self, -1, size=(_BOX_WIDTH * 2 / 3, -1),
+ name='power_low_tcl')
+ wx.EVT_TEXT(self, self.power_low_tcl.GetId(), self._on_text)
+
+ power_hint_txt = "Exponent to apply to the Power_law function."
+ self.power_low_tcl.SetToolTipString(power_hint_txt)
+ iy = 0
+ ix = 0
+ self.low_q_sizer.Add(self.enable_low_cbox, (iy, ix), (1, 5),
+ wx.TOP | wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ iy += 1
+ ix = 0
+ self.low_q_sizer.Add(npts_low_txt, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ ix += 1
+ self.low_q_sizer.Add(self.npts_low_tcl, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ iy += 1
+ ix = 0
+ self.low_q_sizer.Add(self.guinier, (iy, ix), (1, 2),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ iy += 1
+ ix = 0
+ self.low_q_sizer.Add(self.power_law_low, (iy, ix), (1, 2),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ # Parameter controls for power law
+ ix = 1
+ iy += 1
+ self.low_q_sizer.Add(self.fix_enable_low, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix += 1
+ self.low_q_sizer.Add(self.fit_enable_low, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix = 1
+ iy += 1
+ self.low_q_sizer.Add(power_txt, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix += 1
+ self.low_q_sizer.Add(self.power_low_tcl, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ self.low_extrapolation_sizer.Add(self.low_q_sizer)
+
+ def _enable_fit_power_law_high(self, event=None):
+ """
+ Enable and disable the power value editing
+ """
+ if event is not None:
+ self._set_bookmark_flag(True)
+
+ self._set_preview_flag(False)
+ if self.fix_enable_high.IsEnabled():
+ if self.fix_enable_high.GetValue():
+ self.fit_enable_high.SetValue(False)
+ self.power_high_tcl.Enable()
+ else:
+ self.fit_enable_high.SetValue(True)
+ self.power_high_tcl.Disable()
+ self._set_state(event=event)
+
+ def _enable_high_q_section(self, event=None):
+ """
+ Disable or enable some button if the user enable high q extrapolation
+ """
+ if event is not None:
+ self._set_bookmark_flag(True)
+ self._set_preview_flag(False)
+ if self.enable_high_cbox.GetValue():
+ self.npts_high_tcl.Enable()
+ self.power_law_high.Enable()
+ self.power_high_tcl.Enable()
+ self.fix_enable_high.Enable()
+ self.fit_enable_high.Enable()
+ else:
+ self.npts_high_tcl.Disable()
+ self.power_law_high.Disable()
+ self.power_high_tcl.Disable()
+ self.fix_enable_high.Disable()
+ self.fit_enable_high.Disable()
+ self._enable_fit_power_law_high()
+ self._set_state(event=event)
+ self.button_calculate.SetFocus()
+
+ def _layout_extrapolation_high(self):
+ """
+ Draw widgets related to extrapolation at high q range
+ """
+ self.enable_high_cbox = wx.CheckBox(self, -1,
+ "Enable Extrapolate high-Q",
+ name='enable_high_cbox')
+ wx.EVT_CHECKBOX(self, self.enable_high_cbox.GetId(),
+ self._enable_high_q_section)
+ self.fix_enable_high = wx.RadioButton(self, -1, 'Fix',
+ (10, 10), style=wx.RB_GROUP,
+ name='fix_enable_high')
+ self.Bind(wx.EVT_RADIOBUTTON, self._enable_fit_power_law_high,
+ id=self.fix_enable_high.GetId())
+ self.fit_enable_high = wx.RadioButton(self, -1, 'Fit', (10, 10),
+ name='fit_enable_high')
+ self.Bind(wx.EVT_RADIOBUTTON, self._enable_fit_power_law_high,
+ id=self.fit_enable_high.GetId())
+
+ self.power_law_high = wx.StaticText(self, -1, 'Power Law')
+ msg_hint = "Check to extrapolate data at high-Q"
+ self.power_law_high.SetToolTipString(msg_hint)
+ npts_high_txt = wx.StaticText(self, -1, 'Npts')
+ self.npts_high_tcl = InvTextCtrl(self, -1, size=(_BOX_WIDTH * 2 / 3, -1),
+ name='npts_high_tcl')
+ wx.EVT_TEXT(self, self.npts_high_tcl.GetId(), self._on_text)
+ msg_hint = "Number of Q points to consider"
+ msg_hint += "while extrapolating the high-Q region"
+ self.npts_high_tcl.SetToolTipString(msg_hint)
+ power_txt = wx.StaticText(self, -1, 'Power')
+ self.power_high_tcl = InvTextCtrl(self, -1, size=(_BOX_WIDTH * 2 / 3, -1),
+ name='power_high_tcl')
+ wx.EVT_TEXT(self, self.power_high_tcl.GetId(), self._on_text)
+ power_hint_txt = "Exponent to apply to the Power_law function."
+ self.power_high_tcl.SetToolTipString(power_hint_txt)
+ iy = 0
+ ix = 0
+ self.high_q_sizer.Add(self.enable_high_cbox, (iy, ix), (1, 5),
+ wx.TOP | wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ iy += 1
+ ix = 0
+ self.high_q_sizer.Add(npts_high_txt, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ ix += 1
+ self.high_q_sizer.Add(self.npts_high_tcl, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ iy += 1
+ ix = 0
+ self.high_q_sizer.Add(self.power_law_high, (iy, ix), (1, 2),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+
+ # Parameter controls for power law
+ ix = 1
+ iy += 1
+ self.high_q_sizer.Add(self.fix_enable_high, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix += 1
+ self.high_q_sizer.Add(self.fit_enable_high, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix = 1
+ iy += 1
+ self.high_q_sizer.Add(power_txt, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ ix += 1
+ self.high_q_sizer.Add(self.power_high_tcl, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ self.high_extrapolation_sizer.Add(self.high_q_sizer, 0,
+ wx.BOTTOM, 20)
+
+ def _layout_extrapolation(self):
+ """
+ Draw widgets related to extrapolation
+ """
+ extra_hint = "Extrapolation \nMaximum Q Range [1/A]:"
+ extra_hint_txt = wx.StaticText(self, -1, extra_hint)
+ #Extrapolation range [string]
+ extrapolation_min_txt = wx.StaticText(self, -1, 'Min:')
+ self.extrapolation_min_tcl = OutputTextCtrl(self, -1,
+ size=(_BOX_WIDTH, 20), style=0,
+ name='extrapolation_min_tcl')
+ self.extrapolation_min_tcl.SetValue(str(Q_MINIMUM))
+ hint_msg = "The minimum extrapolated q value."
+ self.extrapolation_min_tcl.SetToolTipString(hint_msg)
+ extrapolation_max_txt = wx.StaticText(self, -1, 'Max:')
+ self.extrapolation_max_tcl = OutputTextCtrl(self, -1,
+ size=(_BOX_WIDTH, 20),
+ style=0,
+ name='extrapolation_max_tcl')
+ self.extrapolation_max_tcl.SetValue(str(Q_MAXIMUM))
+ hint_msg = "The maximum extrapolated q value."
+ self.extrapolation_max_tcl.SetToolTipString(hint_msg)
+ self.extrapolation_range_sizer.AddMany([(extra_hint_txt, 0,
+ wx.LEFT, 5),
+ (extrapolation_min_txt, 0,
+ wx.LEFT, 10),
+ (self.extrapolation_min_tcl,
+ 0, wx.LEFT, 5),
+ (extrapolation_max_txt, 0,
+ wx.LEFT, 20),
+ (self.extrapolation_max_tcl,
+ 0, wx.LEFT, 5)])
+ self._layout_extrapolation_low()
+ self._layout_extrapolation_high()
+ self.extrapolation_low_high_sizer.AddMany([(self.low_extrapolation_sizer,
+ 0, wx.LEFT | wx.BOTTOM | wx.TOP, 5),
+ (self.high_extrapolation_sizer,
+ 0, wx.LEFT | wx.BOTTOM | wx.TOP, 5)])
+ self.extrapolation_sizer.AddMany([(self.extrapolation_range_sizer),
+ (self.extrapolation_low_high_sizer)])
+
+ def _layout_volume_surface_sizer(self):
+ """
+ Draw widgets related to volume and surface
+ """
+ unit_volume = ''
+ unit_surface = '[1/A]'
+ uncertainty = "+/-"
+ volume_txt = wx.StaticText(self, -1, 'Volume Fraction')
+ self.volume_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH, -1),
+ name='volume_tcl')
+ wx.EVT_TEXT(self, self.volume_tcl.GetId(), self._on_out_text)
+ self.volume_tcl.SetToolTipString("Volume fraction.")
+ self.volume_err_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH, -1),
+ name='volume_err_tcl')
+ wx.EVT_TEXT(self, self.volume_err_tcl.GetId(), self._on_out_text)
+ hint_msg = "Uncertainty on the volume fraction."
+ self.volume_err_tcl.SetToolTipString(hint_msg)
+ volume_units_txt = wx.StaticText(self, -1, unit_volume)
+
+ surface_txt = wx.StaticText(self, -1, 'Specific Surface')
+ self.surface_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH, -1),
+ name='surface_tcl')
+ wx.EVT_TEXT(self, self.surface_tcl.GetId(), self._on_out_text)
+ self.surface_tcl.SetToolTipString("Specific surface value.")
+ self.surface_err_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH, -1),
+ name='surface_err_tcl')
+ wx.EVT_TEXT(self, self.surface_err_tcl.GetId(), self._on_out_text)
+ hint_msg = "Uncertainty on the specific surface."
+ self.surface_err_tcl.SetToolTipString(hint_msg)
+ surface_units_txt = wx.StaticText(self, -1, unit_surface)
+ iy = 0
+ ix = 0
+ self.volume_surface_sizer.Add(volume_txt, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ ix += 1
+ self.volume_surface_sizer.Add(self.volume_tcl, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 20)
+ ix += 1
+ self.volume_surface_sizer.Add(wx.StaticText(self, -1, uncertainty),
+ (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 10)
+ ix += 1
+ self.volume_surface_sizer.Add(self.volume_err_tcl, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 10)
+ ix += 1
+ self.volume_surface_sizer.Add(volume_units_txt, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 10)
+ iy += 1
+ ix = 0
+ self.volume_surface_sizer.Add(surface_txt, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ ix += 1
+ self.volume_surface_sizer.Add(self.surface_tcl, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 20)
+ ix += 1
+ self.volume_surface_sizer.Add(wx.StaticText(self, -1, uncertainty),
+ (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 10)
+ ix += 1
+ self.volume_surface_sizer.Add(self.surface_err_tcl, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 10)
+ ix += 1
+ self.volume_surface_sizer.Add(surface_units_txt, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 10)
+ static_line = wx.StaticLine(self, -1)
+ iy += 1
+ ix = 0
+
+ def _layout_invariant_sizer(self):
+ """
+ Draw widgets related to invariant
+ """
+ uncertainty = "+/-"
+ unit_invariant = '[1/(cm*A^3)]'
+ invariant_total_txt = wx.StaticText(self, -1, 'Invariant Total [Q*]')
+ self.invariant_total_tcl = OutputTextCtrl(self, -1,
+ size=(_BOX_WIDTH, -1),
+ name='invariant_total_tcl')
+ msg_hint = "Total invariant [Q*], including extrapolated regions."
+ self.invariant_total_tcl.SetToolTipString(msg_hint)
+ self.invariant_total_err_tcl = OutputTextCtrl(self, -1,
+ size=(_BOX_WIDTH, -1),
+ name='invariant_total_err_tcl')
+ hint_msg = "Uncertainty on invariant."
+ self.invariant_total_err_tcl.SetToolTipString(hint_msg)
+ invariant_total_units_txt = wx.StaticText(self, -1, unit_invariant,
+ size=(80, -1))
+
+ #Invariant total
+ iy = 0
+ ix = 0
+ self.invariant_sizer.Add(invariant_total_txt, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ ix += 1
+ self.invariant_sizer.Add(self.invariant_total_tcl, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 10)
+ ix += 1
+ self.invariant_sizer.Add(wx.StaticText(self, -1, uncertainty),
+ (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 10)
+ ix += 1
+ self.invariant_sizer.Add(self.invariant_total_err_tcl, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 10)
+ ix += 1
+ self.invariant_sizer.Add(invariant_total_units_txt, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 10)
+
+ def _layout_inputs_sizer(self):
+ """
+ Draw widgets related to inputs
+ """
+ contrast_txt = wx.StaticText(self, -1, 'Contrast:')
+ self.contrast_tcl = InvTextCtrl(self, -1, size=(_BOX_WIDTH, 20),
+ style=0, name='contrast_tcl')
+ wx.EVT_TEXT(self, self.contrast_tcl.GetId(), self._on_text)
+ contrast_hint_txt = "Contrast"
+ self.contrast_tcl.SetToolTipString(contrast_hint_txt)
+ contrast_unit_txt = wx.StaticText(self, -1, '[1/A^2]', size=(40, -1))
+ porod_const_txt = wx.StaticText(self, -1,
+ 'Porod\nConstant:\n(optional)\n')
+ porod_unit_txt = wx.StaticText(self, -1, '[1/(cm*A^4)]', size=(80, -1))
+ self.porod_constant_tcl = InvTextCtrl(self, -1,
+ size=(_BOX_WIDTH, 20), style=0,
+ name='porod_constant_tcl')
+ wx.EVT_TEXT(self, self.porod_constant_tcl.GetId(), self._on_text)
+ porod_const_hint_txt = "Porod Constant"
+ self.porod_constant_tcl.SetToolTipString(porod_const_hint_txt)
+
+ background_txt = wx.StaticText(self, -1, 'Background:')
+ self.background_tcl = InvTextCtrl(self, -1, size=(_BOX_WIDTH, 20),
+ style=0, name='background_tcl')
+ wx.EVT_TEXT(self, self.background_tcl.GetId(), self._on_text)
+ background_hint_txt = "Background"
+ self.background_tcl.SetToolTipString(background_hint_txt)
+ background_unit_txt = wx.StaticText(self, -1, '[1/cm]')
+ scale_txt = wx.StaticText(self, -1, 'Scale:')
+ self.scale_tcl = InvTextCtrl(self, -1, size=(_BOX_WIDTH, 20), style=0,
+ name='scale_tcl')
+ wx.EVT_TEXT(self, self.scale_tcl.GetId(), self._on_text)
+ scale_hint_txt = "Scale"
+ self.scale_tcl.SetToolTipString(scale_hint_txt)
+ self.sizer_input.AddMany([(background_txt, 0, wx.LEFT | wx.BOTTOM, 5),
+ (self.background_tcl, 0, wx.LEFT | wx.BOTTOM, 5),
+ (background_unit_txt, 0, wx.LEFT | wx.BOTTOM, 5),
+ (scale_txt, 0, wx.LEFT | wx.BOTTOM, 10),
+ (self.scale_tcl, 0, wx.LEFT | wx.BOTTOM | wx.RIGHT, 5),
+ (10, 10),
+ (contrast_txt, 0, wx.LEFT | wx.BOTTOM, 5),
+ (self.contrast_tcl, 0, wx.LEFT | wx.BOTTOM, 5),
+ (contrast_unit_txt, 0, wx.LEFT | wx.BOTTOM, 5),
+ (porod_const_txt, 0, wx.LEFT, 10),
+ (self.porod_constant_tcl, 0, wx.LEFT | wx.BOTTOM | wx.RIGHT, 5),
+ (porod_unit_txt, 0, wx.LEFT | wx.BOTTOM, 5)])
+ self.inputs_sizer.Add(self.sizer_input)
+
+ def _layout_outputs_sizer(self):
+ """
+ Draw widgets related to outputs
+ """
+ self._layout_volume_surface_sizer()
+ self._layout_invariant_sizer()
+ static_line = wx.StaticLine(self, -1)
+ self.outputs_sizer.AddMany([(self.volume_surface_sizer,
+ 0, wx.TOP | wx.BOTTOM, 10),
+ (static_line, 0, wx.EXPAND, 0),
+ (self.invariant_sizer, 0, wx.TOP | wx.BOTTOM, 10)])
+ def _layout_button(self):
+ """
+ Do the layout for the button widgets
+ """
+ #compute button
+ id = wx.NewId()
+ self.button_calculate = wx.Button(self, id, "Compute",
+ name='compute_invariant')
+ self.button_calculate.SetToolTipString("Compute invariant")
+ self.Bind(wx.EVT_BUTTON, self.compute_invariant, id=id)
+ #detail button
+ id = wx.NewId()
+ self.button_details = wx.Button(self, id, "Details?")
+ hint_msg = "Get more details of computation such as fraction from extrapolation"
+ self.button_details.SetToolTipString(hint_msg)
+ self.Bind(wx.EVT_BUTTON, self.display_details, id=id)
+ #help button
+ id = wx.NewId()
+ self.button_help = wx.Button(self, id, "HELP")
+ self.button_help.SetToolTipString("Invariant Documentation")
+ self.Bind(wx.EVT_BUTTON, self.on_help, id=id)
+ self.button_sizer.AddMany([((20, 20), 1, wx.EXPAND | wx.ADJUST_MINSIZE, 0),
+ (self.button_details, 0, wx.ALL, 10),
+ (self.button_calculate, 0,
+ wx.RIGHT | wx.TOP | wx.BOTTOM, 10),
+ (self.button_help, 0,
+ wx.RIGHT | wx.TOP | wx.BOTTOM, 10),])
+ def _do_layout(self):
+ """
+ Draw window content
+ """
+ self._define_structure()
+ self._layout_data_name()
+ self._layout_extrapolation()
+ self._layout_inputs_sizer()
+ self._layout_outputs_sizer()
+ self._layout_button()
+ self.main_sizer.AddMany([(self.data_name_boxsizer, 0, wx.ALL, 10),
+ (self.outputs_sizer, 0,
+ wx.LEFT | wx.RIGHT | wx.BOTTOM, 10),
+ (self.button_sizer, 0, wx.LEFT | wx.RIGHT, 15),
+ (self.inputs_sizer, 0,
+ wx.LEFT | wx.RIGHT | wx.BOTTOM, 10),
+ (self.extrapolation_sizer, 0,
+ wx.LEFT | wx.RIGHT | wx.BOTTOM, 10)])
+ self.SetSizer(self.main_sizer)
+ self.SetAutoLayout(True)
+
+ def on_help(self, event):
+ """
+ Bring up the Invariant Documentation whenever the HELP button is
+ clicked.
+
+ Calls DocumentationWindow with the path of the location within the
+ documentation tree (after /doc/ ....". Note that when using old
+ versions of Wx (before 2.9) and thus not the release version of
+ installers, the help comes up at the top level of the file as
+ webbrowser does not pass anything past the # to the browser when it is
+ running "file:///...."
+
+ :param evt: Triggers on clicking the help button
+ """
+
+ _TreeLocation = "user/sasgui/perspectives/invariant/invariant_help.html"
+ _doc_viewer = DocumentationWindow(self, -1, _TreeLocation, "",
+ "Invariant Help")
+
+
+class InvariantDialog(wx.Dialog):
+ """
+ Invariant Dialog
+ """
+ def __init__(self, parent=None, id=1, graph=None,
+ data=None, title="Invariant", base=None):
+ wx.Dialog.__init__(self, parent, id, title, size=(PANEL_WIDTH,
+ PANEL_HEIGHT))
+ self.panel = InvariantPanel(self)
+ self.Centre()
+ self.Show(True)
+
+class InvariantWindow(wx.Frame):
+ """
+ Invariant Window
+ """
+ def __init__(self, parent=None, id=1, graph=None,
+ data=None, title="Invariant", base=None):
+
+ wx.Frame.__init__(self, parent, id, title, size=(PANEL_WIDTH + 100,
+ PANEL_HEIGHT + 100))
+ from sas.sascalc.dataloader.loader import Loader
+ self.loader = Loader()
+ path = "C:/ECLPS/workspace/trunk/sasdataloader/test/ascii_test_3.txt"
+ data = self.loader.load(path)
+ self.panel = InvariantPanel(self)
+
+ data.name = data.filename
+ self.panel.set_data(data)
+ self.Centre()
+ self.Show(True)
+
+class MyApp(wx.App):
+ """
+ Test App
+ """
+ def OnInit(self):
+ """
+ Init
+ """
+ wx.InitAllImageHandlers()
+ frame = InvariantWindow()
+ frame.Show(True)
+ self.SetTopWindow(frame)
+
+ return True
+
+# end of class MyApp
+
+if __name__ == "__main__":
+ app = MyApp(0)
+ app.MainLoop()
diff --git a/src/sas/sasgui/perspectives/invariant/invariant_state.py b/src/sas/sasgui/perspectives/invariant/invariant_state.py
index 54d975b..c15e85a 100644
--- a/src/sas/sasgui/perspectives/invariant/invariant_state.py
+++ b/src/sas/sasgui/perspectives/invariant/invariant_state.py
@@ -16,6 +16,8 @@ from sas.sasgui.guiframe.utils import format_number
from sas.sasgui.guiframe.gui_style import GUIFRAME_ID
from sas.sasgui.guiframe.dataFitting import Data1D
+logger = logging.getLogger(__name__)
+
INVNODE_NAME = 'invariant'
CANSAS_NS = "cansas1d/1.0"
@@ -278,7 +280,7 @@ class InvariantState(object):
# File name
element = newdoc.createElement("filename")
- if self.file != None and self.file != '':
+ if self.file is not None and self.file != '':
element.appendChild(newdoc.createTextNode(str(self.file)))
else:
element.appendChild(newdoc.createTextNode(str(file)))
@@ -380,7 +382,7 @@ class InvariantState(object):
except:
msg = "InvariantSate.fromXML: Could not read"
msg += " timestamp\n %s" % sys.exc_value
- logging.error(msg)
+ logger.error(msg)
# Parse bookmarks
entry_bookmark = get_content('ns:bookmark', node)
@@ -693,7 +695,7 @@ class Reader(CansasReader):
except:
msg = "XML document does not contain invariant"
msg += " information.\n %s" % sys.exc_value
- logging.info(msg)
+ logger.info(msg)
return state
def _read_cansas(self, path):
@@ -725,13 +727,11 @@ class Reader(CansasReader):
namespaces={'ns': CANSAS_NS})
for entry in entry_list:
-
- sas_entry, _ = self._parse_entry(entry)
invstate = self._parse_state(entry)
-
# invstate could be None when .svs file is loaded
# in this case, skip appending to output
- if invstate != None:
+ if invstate is not None:
+ sas_entry, _ = self._parse_entry(entry)
sas_entry.meta_data['invstate'] = invstate
sas_entry.filename = invstate.file
output.append(sas_entry)
@@ -784,9 +784,9 @@ class Reader(CansasReader):
msg += " instance: %s" % str(datainfo.__class__.__name__)
raise RuntimeError, msg
# make sure title and data run is filled up.
- if datainfo.title == None or datainfo.title == '':
+ if datainfo.title is None or datainfo.title == '':
datainfo.title = datainfo.name
- if datainfo.run_name == None or datainfo.run_name == {}:
+ if datainfo.run_name is None or datainfo.run_name == {}:
datainfo.run = [str(datainfo.name)]
datainfo.run_name[0] = datainfo.name
# Create basic XML document
diff --git a/src/sas/sasgui/perspectives/invariant/invariant_widgets.py b/src/sas/sasgui/perspectives/invariant/invariant_widgets.py
index c95aa1b..6d101e4 100644
--- a/src/sas/sasgui/perspectives/invariant/invariant_widgets.py
+++ b/src/sas/sasgui/perspectives/invariant/invariant_widgets.py
@@ -1,165 +1,165 @@
-################################################################################
-# This software was developed by the University of Tennessee as part of the
-# Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
-# project funded by the US National Science Foundation.
-#
-# See the license text in license.txt
-#
-# copyright 2009, University of Tennessee
-################################################################################
-
-import wx
-from wx.lib.scrolledpanel import ScrolledPanel
-
-WIDTH = 400
-HEIGHT = 350
-
-class DialogPanel(ScrolledPanel):
- def __init__(self, *args, **kwds):
- ScrolledPanel.__init__(self, *args, **kwds)
- self.SetupScrolling()
-
-class InvTextCtrl(wx.TextCtrl):
- """
- Text control for model and fit parameters.
- Binds the appropriate events for user interactions.
- """
- def __init__(self, *args, **kwds):
- wx.TextCtrl.__init__(self, *args, **kwds)
- # # Set to True when the mouse is clicked while
- # the whole string is selected
- self.full_selection = False
- # # Call back for EVT_SET_FOCUS events
- _on_set_focus_callback = None
-
- # Bind appropriate events
- self.Bind(wx.EVT_LEFT_UP, self._highlight_text)
- self.Bind(wx.EVT_SET_FOCUS, self._on_set_focus)
-
- def _on_set_focus(self, event):
- """
- Catch when the text control is set in focus to highlight the whole
- text if necessary
-
- :param event: mouse event
- """
- event.Skip()
- self.full_selection = True
-
- def _highlight_text(self, event):
- """
- Highlight text of a TextCtrl only of no text has be selected
-
- :param event: mouse event
- """
- # Make sure the mouse event is available to other listeners
- event.Skip()
- control = event.GetEventObject()
- if self.full_selection:
- self.full_selection = False
- # Check that we have a TextCtrl
- if issubclass(control.__class__, wx.TextCtrl):
- # Check whether text has been selected,
- # if not, select the whole string
- (start, end) = control.GetSelection()
- if start == end:
- control.SetSelection(-1, -1)
-
-
-class OutputTextCtrl(wx.TextCtrl):
- """
- Text control used to display outputs.
- No editing allowed. The background is
- grayed out. User can't select text.
- """
- def __init__(self, *args, **kwds):
- wx.TextCtrl.__init__(self, *args, **kwds)
- self.SetEditable(False)
- self.SetBackgroundColour(self.GetParent().GetBackgroundColour())
-
- # Bind to mouse event to avoid text highlighting
- # The event will be skipped once the call-back
- # is called.
-
- self.Bind(wx.EVT_MOUSE_EVENTS, self._click)
-
-
- def _click(self, event):
- """
- Prevent further handling of the mouse event
- by not calling Skip().
- """
- pass
-
-class DataDialog(wx.Dialog):
- """
- Allow file selection at loading time
- """
- def __init__(self, data_list, parent=None, text='', *args, **kwds):
- kwds['size'] = (WIDTH, HEIGHT)
- kwds['title'] = "Data Selection"
- wx.Dialog.__init__(self, parent, *args, **kwds)
- self.list_of_ctrl = []
- self._sizer_main = wx.BoxSizer(wx.VERTICAL)
- self._sizer_txt = wx.BoxSizer(wx.VERTICAL)
- self._sizer_button = wx.BoxSizer(wx.HORIZONTAL)
- self._choice_sizer = wx.GridBagSizer(5, 5)
- self._panel = DialogPanel(self, style=wx.RAISED_BORDER,
- size=(WIDTH - 20, HEIGHT / 3))
- self.SetSizer(self._sizer_main)
- self.__do_layout(data_list, text=text)
- self.Layout()
-
- def __do_layout(self, data_list, text=''):
- """
- layout the dialog
- """
- # add text
- if text.strip() == "":
- text = "This Perspective does not allow multiple data !\n"
- text += "Please select only one Data.\n"
- text_ctrl = wx.TextCtrl(self, -1, str(text), style=wx.TE_MULTILINE,
- size=(-1, HEIGHT / 3))
- text_ctrl.SetEditable(False)
- self._sizer_txt.Add(text_ctrl, 1, wx.EXPAND | wx.ALL, 10)
- iy = 0
- ix = 0
- rbox = wx.RadioButton(self._panel, -1, str(data_list[0].name),
- (10, 10), style=wx.RB_GROUP)
- rbox.SetValue(True)
- self.list_of_ctrl.append((rbox, data_list[0]))
- self._choice_sizer.Add(rbox, (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- for i in range(1, len(data_list)):
- iy += 1
- rbox = wx.RadioButton(self._panel, -1,
- str(data_list[i].name), (10, 10))
- rbox.SetValue(False)
- self.list_of_ctrl.append((rbox, data_list[i]))
- self._choice_sizer.Add(rbox, (iy, ix),
- (1, 1), wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- self._panel.SetSizer(self._choice_sizer)
- # add sizer
- self._sizer_button.Add((20, 20), 1, wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- button_cancel = wx.Button(self, wx.ID_CANCEL, "Cancel")
- self._sizer_button.Add(button_cancel, 0,
- wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 10)
- button_OK = wx.Button(self, wx.ID_OK, "Ok")
- button_OK.SetFocus()
- self._sizer_button.Add(button_OK, 0,
- wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 10)
- static_line = wx.StaticLine(self, -1)
-
- self._sizer_txt.Add(self._panel, 0, wx.EXPAND | wx.ALL, 5)
- self._sizer_main.Add(self._sizer_txt, 0, wx.EXPAND | wx.ALL, 5)
- self._sizer_main.Add(static_line, 0, wx.EXPAND, 0)
- self._sizer_main.Add(self._sizer_button, 0, wx.EXPAND | wx.ALL, 10)
-
- def get_data(self):
- """
- return the selected data
- """
- for item in self.list_of_ctrl:
- rbox, data = item
- if rbox.GetValue():
- return data
+################################################################################
+# This software was developed by the University of Tennessee as part of the
+# Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
+# project funded by the US National Science Foundation.
+#
+# See the license text in license.txt
+#
+# copyright 2009, University of Tennessee
+################################################################################
+
+import wx
+from wx.lib.scrolledpanel import ScrolledPanel
+
+WIDTH = 400
+HEIGHT = 350
+
+class DialogPanel(ScrolledPanel):
+ def __init__(self, *args, **kwds):
+ ScrolledPanel.__init__(self, *args, **kwds)
+ self.SetupScrolling()
+
+class InvTextCtrl(wx.TextCtrl):
+ """
+ Text control for model and fit parameters.
+ Binds the appropriate events for user interactions.
+ """
+ def __init__(self, *args, **kwds):
+ wx.TextCtrl.__init__(self, *args, **kwds)
+ # # Set to True when the mouse is clicked while
+ # the whole string is selected
+ self.full_selection = False
+ # # Call back for EVT_SET_FOCUS events
+ _on_set_focus_callback = None
+
+ # Bind appropriate events
+ self.Bind(wx.EVT_LEFT_UP, self._highlight_text)
+ self.Bind(wx.EVT_SET_FOCUS, self._on_set_focus)
+
+ def _on_set_focus(self, event):
+ """
+ Catch when the text control is set in focus to highlight the whole
+ text if necessary
+
+ :param event: mouse event
+ """
+ event.Skip()
+ self.full_selection = True
+
+ def _highlight_text(self, event):
+ """
+ Highlight text of a TextCtrl only of no text has be selected
+
+ :param event: mouse event
+ """
+ # Make sure the mouse event is available to other listeners
+ event.Skip()
+ control = event.GetEventObject()
+ if self.full_selection:
+ self.full_selection = False
+ # Check that we have a TextCtrl
+ if issubclass(control.__class__, wx.TextCtrl):
+ # Check whether text has been selected,
+ # if not, select the whole string
+ (start, end) = control.GetSelection()
+ if start == end:
+ control.SetSelection(-1, -1)
+
+
+class OutputTextCtrl(wx.TextCtrl):
+ """
+ Text control used to display outputs.
+ No editing allowed. The background is
+ grayed out. User can't select text.
+ """
+ def __init__(self, *args, **kwds):
+ wx.TextCtrl.__init__(self, *args, **kwds)
+ self.SetEditable(False)
+ self.SetBackgroundColour(self.GetParent().GetBackgroundColour())
+
+ # Bind to mouse event to avoid text highlighting
+ # The event will be skipped once the call-back
+ # is called.
+
+ self.Bind(wx.EVT_MOUSE_EVENTS, self._click)
+
+
+ def _click(self, event):
+ """
+ Prevent further handling of the mouse event
+ by not calling Skip().
+ """
+ pass
+
+class DataDialog(wx.Dialog):
+ """
+ Allow file selection at loading time
+ """
+ def __init__(self, data_list, parent=None, text='', *args, **kwds):
+ kwds['size'] = (WIDTH, HEIGHT)
+ kwds['title'] = "Data Selection"
+ wx.Dialog.__init__(self, parent, *args, **kwds)
+ self.list_of_ctrl = []
+ self._sizer_main = wx.BoxSizer(wx.VERTICAL)
+ self._sizer_txt = wx.BoxSizer(wx.VERTICAL)
+ self._sizer_button = wx.BoxSizer(wx.HORIZONTAL)
+ self._choice_sizer = wx.GridBagSizer(5, 5)
+ self._panel = DialogPanel(self, style=wx.RAISED_BORDER,
+ size=(WIDTH - 20, HEIGHT / 3))
+ self.SetSizer(self._sizer_main)
+ self.__do_layout(data_list, text=text)
+ self.Layout()
+
+ def __do_layout(self, data_list, text=''):
+ """
+ layout the dialog
+ """
+ # add text
+ if text.strip() == "":
+ text = "This Perspective does not allow multiple data !\n"
+ text += "Please select only one Data.\n"
+ text_ctrl = wx.TextCtrl(self, -1, str(text), style=wx.TE_MULTILINE,
+ size=(-1, HEIGHT / 3))
+ text_ctrl.SetEditable(False)
+ self._sizer_txt.Add(text_ctrl, 1, wx.EXPAND | wx.ALL, 10)
+ iy = 0
+ ix = 0
+ rbox = wx.RadioButton(self._panel, -1, str(data_list[0].name),
+ (10, 10), style=wx.RB_GROUP)
+ rbox.SetValue(True)
+ self.list_of_ctrl.append((rbox, data_list[0]))
+ self._choice_sizer.Add(rbox, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ for i in range(1, len(data_list)):
+ iy += 1
+ rbox = wx.RadioButton(self._panel, -1,
+ str(data_list[i].name), (10, 10))
+ rbox.SetValue(False)
+ self.list_of_ctrl.append((rbox, data_list[i]))
+ self._choice_sizer.Add(rbox, (iy, ix),
+ (1, 1), wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ self._panel.SetSizer(self._choice_sizer)
+ # add sizer
+ self._sizer_button.Add((20, 20), 1, wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ button_cancel = wx.Button(self, wx.ID_CANCEL, "Cancel")
+ self._sizer_button.Add(button_cancel, 0,
+ wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 10)
+ button_OK = wx.Button(self, wx.ID_OK, "Ok")
+ button_OK.SetFocus()
+ self._sizer_button.Add(button_OK, 0,
+ wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 10)
+ static_line = wx.StaticLine(self, -1)
+
+ self._sizer_txt.Add(self._panel, 0, wx.EXPAND | wx.ALL, 5)
+ self._sizer_main.Add(self._sizer_txt, 0, wx.EXPAND | wx.ALL, 5)
+ self._sizer_main.Add(static_line, 0, wx.EXPAND, 0)
+ self._sizer_main.Add(self._sizer_button, 0, wx.EXPAND | wx.ALL, 10)
+
+ def get_data(self):
+ """
+ return the selected data
+ """
+ for item in self.list_of_ctrl:
+ rbox, data = item
+ if rbox.GetValue():
+ return data
diff --git a/src/sas/sasgui/perspectives/invariant/media/image001.gif b/src/sas/sasgui/perspectives/invariant/media/image001.gif
deleted file mode 100644
index fdb2718..0000000
Binary files a/src/sas/sasgui/perspectives/invariant/media/image001.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/invariant/media/image002.gif b/src/sas/sasgui/perspectives/invariant/media/image002.gif
deleted file mode 100644
index 8e956f5..0000000
Binary files a/src/sas/sasgui/perspectives/invariant/media/image002.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/invariant/media/image003.gif b/src/sas/sasgui/perspectives/invariant/media/image003.gif
deleted file mode 100644
index 37504c2..0000000
Binary files a/src/sas/sasgui/perspectives/invariant/media/image003.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/invariant/media/image004.gif b/src/sas/sasgui/perspectives/invariant/media/image004.gif
deleted file mode 100644
index 46f481f..0000000
Binary files a/src/sas/sasgui/perspectives/invariant/media/image004.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/invariant/media/image005.gif b/src/sas/sasgui/perspectives/invariant/media/image005.gif
deleted file mode 100644
index a44b1cb..0000000
Binary files a/src/sas/sasgui/perspectives/invariant/media/image005.gif and /dev/null differ
diff --git a/src/sas/sasgui/perspectives/invariant/media/image005.png b/src/sas/sasgui/perspectives/invariant/media/image005.png
new file mode 100644
index 0000000..661f3a5
Binary files /dev/null and b/src/sas/sasgui/perspectives/invariant/media/image005.png differ
diff --git a/src/sas/sasgui/perspectives/invariant/media/invariant_help.rst b/src/sas/sasgui/perspectives/invariant/media/invariant_help.rst
index 458881a..c01f6f8 100644
--- a/src/sas/sasgui/perspectives/invariant/media/invariant_help.rst
+++ b/src/sas/sasgui/perspectives/invariant/media/invariant_help.rst
@@ -9,37 +9,44 @@ Invariant Calculation
Description
-----------
-The scattering, or Porod, invariant (Q*\) is a model-independent quantity that
+The scattering, or Porod, invariant ($Q^*$) is a model-independent quantity that
can be easily calculated from scattering data.
-For two phase systems, the scattering invariant is defined as the integral of
-the square of the wave transfer (Q) multiplied by the scattering cross section
-over the full range of Q from zero to infinity, that is
+For two phase systems, the scattering invariant is defined as the integral of
+the square of the wavevector transfer ($Q$) multiplied by the scattering cross section
+over the full range of $Q$ from zero to infinity, that is
-.. image:: image001.gif
+.. math::
-where *g = q* for pinhole geometry (SAS) and *g = q*\ :sub:`v` (the slit height) for
-slit geometry (USAS).
+ Q^* = \int_0^\infty q^2I(q)\,dq
-The worth of Q*\ is that it can be used to determine the volume fraction and
-the specific area of a sample. Whilst these quantities are useful in their own
+in the case of pinhole geometry. For slit geometry the invariant is given by
+
+.. math::
+
+ Q^* = \Delta q_v \int_0^\infty qI(q)\,dq
+
+where $\Delta q_v$ is the slit height.
+
+The worth of $Q^*$ is that it can be used to determine the volume fraction and
+the specific area of a sample. Whilst these quantities are useful in their own
right they can also be used in further analysis.
-The difficulty with using Q*\ arises from the fact that experimental data is
-never measured over the range 0 =< *Q* =< infinity. At best, combining USAS and
-WAS data might cover the range 1e-5 =< *Q* =< 10 1/\ |Ang| . Thus it is usually
-necessary to extrapolate the experimental data to low and high *Q*. For this
+The difficulty with using $Q^*$ arises from the fact that experimental data is
+never measured over the range $0 \le Q \le \infty$. At best, combining USAS and
+WAS data might cover the range $10^{-5} \le Q \le 10$ 1/\ |Ang| . Thus it is usually
+necessary to extrapolate the experimental data to low and high $Q$. For this
-High-*Q* region (>= *Qmax* in data)
+High-\ $Q$ region (>= *Qmax* in data)
-* The power law function *C*/*Q*\ :sup:`4` is used where the constant
- *C* (= 2.\ |pi|\ .(\ |bigdelta|\ |rho|\ ).\ *Sv*\ ) is to be found by fitting part of data
- within the range *Q*\ :sub:`N-m` to *Q*\ :sub:`N` (where m < N).
+* The power law function $C/Q^4$ is used where the constant
+ $C = 2 \pi \Delta\rho S_v$ is to be found by fitting part of data
+ within the range $Q_{N-m}$ to $Q_N$ (where $m < N$).
-Low-*Q* region (<= *Qmin* in data)
+Low-\ $Q$ region (<= *Qmin* in data)
-* The Guinier function *I0.exp(-Rg*\ :sup:`2`\ *Q*\ :sup:`2`\ */3)* where *I0*
- and *Rg* are obtained by fitting as for the high-*Q* region above.
+* The Guinier function $I_0 exp(-R_g^2 Q^2/3)$ where $I_0$
+ and $R_g$ are obtained by fitting as for the high-\ $Q$ region above.
Alternatively a power law can be used.
.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
@@ -51,33 +58,33 @@ Using invariant analysis
2) Load some data with the *Data Explorer*.
-3) Select a dataset and use the *Send To* button on the *Data Explorer* to load
+3) Select a dataset and use the *Send To* button on the *Data Explorer* to load
the dataset into the *Invariant* panel.
-4) Use the *Customised Input* boxes on the *Invariant* panel to subtract
- any background, specify the contrast (i.e. difference in SLDs - this must be
- specified for the eventual value of Q*\ to be on an absolute scale), or to
+4) Use the *Customised Input* boxes on the *Invariant* panel to subtract
+ any background, specify the contrast (i.e. difference in SLDs - this must be
+ specified for the eventual value of $Q^*$ to be on an absolute scale), or to
rescale the data.
-5) Adjust the extrapolation range as necessary. In most cases the default
+5) Adjust the extrapolation range as necessary. In most cases the default
values will suffice.
6) Click the *Compute* button.
-7) To include a lower and/or higher Q range, check the relevant *Enable
+7) To include a lower and/or higher $Q$ range, check the relevant *Enable
Extrapolate* check boxes.
-
- If power law extrapolations are chosen, the exponent can be either held
- fixed or fitted. The number of points, Npts, to be used for the basis of the
+
+ If power law extrapolations are chosen, the exponent can be either held
+ fixed or fitted. The number of points, Npts, to be used for the basis of the
extrapolation can also be specified.
-8) If the value of Q*\ calculated with the extrapolated regions is invalid, a
+8) If the value of $Q^*$ calculated with the extrapolated regions is invalid, a
red warning will appear at the top of the *Invariant* panel.
- The details of the calculation are available by clicking the *Details*
+ The details of the calculation are available by clicking the *Details*
button in the middle of the panel.
-.. image:: image005.gif
+.. image:: image005.png
.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
@@ -87,24 +94,30 @@ Parameters
Volume Fraction
^^^^^^^^^^^^^^^
-The volume fraction |phi| is related to Q*\ by
+The volume fraction $\phi$ is related to $Q^*$ by
+
+.. math::
-.. image:: image002.gif
+ \phi(1 - \phi) = \frac{Q^*}{2\pi^2(\Delta\rho)^2} \equiv A
-where |bigdelta|\ |rho| is the SLD contrast.
+where $\Delta\rho$ is the SLD contrast.
-.. image:: image003.gif
+.. math::
+
+ \phi = \frac{1 \pm \sqrt{1 - 4A}}{2}
.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
Specific Surface Area
^^^^^^^^^^^^^^^^^^^^^
-The specific surface area *Sv* is related to Q*\ by
+The specific surface area $S_v$ is related to $Q^*$ by
+
+.. math::
-.. image:: image004.gif
+ S_v = \frac{2\pi\phi(1-\phi)C_p}{Q^*} = \frac{2\pi A C_p}{Q^*}
-where *Cp* is the Porod constant.
+where $C_p$ is the Porod constant.
.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
diff --git a/src/sas/sasgui/perspectives/invariant/report_dialog.py b/src/sas/sasgui/perspectives/invariant/report_dialog.py
index 9dc937f..9620a67 100644
--- a/src/sas/sasgui/perspectives/invariant/report_dialog.py
+++ b/src/sas/sasgui/perspectives/invariant/report_dialog.py
@@ -1,124 +1,126 @@
-
-################################################################################
-# This software was developed by the University of Tennessee as part of the
-# Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
-# project funded by the US National Science Foundation.
-#
-# See the license text in license.txt
-#
-# copyright 2009, University of Tennessee
-################################################################################
-
-"""
-Dialog report panel to show and summarize the results of
-the invariant calculation.
-"""
-import wx
-import os
-import sys
-import logging
-
-from sas.sasgui.guiframe.report_dialog import BaseReportDialog
-
-class ReportDialog(BaseReportDialog):
- """
- The report dialog box.
- """
-
- def __init__(self, report_list, *args, **kwds):
- """
- Initialization. The parameters added to Dialog are:
-
- :param report_list: list of html_str, text_str, image
- from invariant_state
- """
- super(ReportDialog, self).__init__(report_list, *args, **kwds)
-
- # title
- self.SetTitle("Report: Invariant computaion")
-
- # put image path in the report string
- self.report_html = self.report_list[0] % "memory:img_inv.png"
- # layout
- self._setup_layout()
-
- def onSave(self, event=None):
- """
- Save
- """
- # todo: complete saving fig file and as a txt file
- dlg = wx.FileDialog(self, "Choose a file",
- wildcard=self.wild_card,
- style=wx.SAVE | wx.OVERWRITE_PROMPT | wx.CHANGE_DIR)
- dlg.SetFilterIndex(0) # Set .html files to be default
-
- if dlg.ShowModal() != wx.ID_OK:
- dlg.Destroy()
- return
-
- fName = dlg.GetPath()
- ext_num = dlg.GetFilterIndex()
- # set file extensions
- if ext_num == (0 + 2 * self.index_offset):
- # TODO: Sort this case out
- ext = '.pdf'
- img_ext = '_img.png'
- fName = os.path.splitext(fName)[0] + ext
- dlg.Destroy()
-
- # pic (png) file path/name
- pic_fname = os.path.splitext(fName)[0] + img_ext
- # save the image for use with pdf writer
- self.report_list[2].savefig(pic_fname)
-
- # put the image file path in the html data
- html = self.report_list[0] % str(pic_fname)
-
- # make/open file in case of absence
- f = open(fName, 'w')
- f.close()
- # write pdf as a pdf file
- pdf = self.HTML2PDF(data=html, filename=fName)
-
- # open pdf
- if pdf:
- try:
- # Windows
- os.startfile(str(fName))
- except:
- try:
- # Mac
- os.system("open %s" % fName)
- except:
- # DO not open
- logging.error("Could not open file: %s" % sys.exc_value)
- # delete image file
- os.remove(pic_fname)
- return
- elif ext_num == (1 - self.index_offset):
- ext = '.html'
- img_ext = '_img4html.png'
- report_frame = self.report_list[0]
- elif ext_num == (2 - self.index_offset):
- ext = '.txt'
- # changing the image extension actually changes the image
- # format on saving
- img_ext = '_img4txt.pdf'
- report = self.report_list[1]
- else:
- return
-
- # file name
- fName = os.path.splitext(fName)[0] + ext
- dlg.Destroy()
- # pic (png) file path/name
- pic_fname = os.path.splitext(fName)[0] + img_ext
- # put the image path in html string
- if ext_num == (1 - self.index_offset):
- report = report_frame % os.path.basename(pic_fname)
-
- f = open(fName, 'w')
- f.write(report)
- f.close()
- # save png file using pic_fname
- self.report_list[2].savefig(pic_fname)
+
+################################################################################
+# This software was developed by the University of Tennessee as part of the
+# Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
+# project funded by the US National Science Foundation.
+#
+# See the license text in license.txt
+#
+# copyright 2009, University of Tennessee
+################################################################################
+
+"""
+Dialog report panel to show and summarize the results of
+the invariant calculation.
+"""
+import wx
+import os
+import sys
+import logging
+
+from sas.sasgui.guiframe.report_dialog import BaseReportDialog
+
+logger = logging.getLogger(__name__)
+
+class ReportDialog(BaseReportDialog):
+ """
+ The report dialog box.
+ """
+
+ def __init__(self, report_list, *args, **kwds):
+ """
+ Initialization. The parameters added to Dialog are:
+
+ :param report_list: list of html_str, text_str, image
+ from invariant_state
+ """
+ super(ReportDialog, self).__init__(report_list, *args, **kwds)
+
+ # title
+ self.SetTitle("Report: Invariant computaion")
+
+ # put image path in the report string
+ self.report_html = self.report_list[0] % "memory:img_inv.png"
+ # layout
+ self._setup_layout()
+
+ def onSave(self, event=None):
+ """
+ Save
+ """
+ # todo: complete saving fig file and as a txt file
+ dlg = wx.FileDialog(self, "Choose a file",
+ wildcard=self.wild_card,
+ style=wx.SAVE | wx.OVERWRITE_PROMPT | wx.CHANGE_DIR)
+ dlg.SetFilterIndex(0) # Set .html files to be default
+
+ if dlg.ShowModal() != wx.ID_OK:
+ dlg.Destroy()
+ return
+
+ fName = dlg.GetPath()
+ ext_num = dlg.GetFilterIndex()
+ # set file extensions
+ if ext_num == (0 + 2 * self.index_offset):
+ # TODO: Sort this case out
+ ext = '.pdf'
+ img_ext = '_img.png'
+ fName = os.path.splitext(fName)[0] + ext
+ dlg.Destroy()
+
+ # pic (png) file path/name
+ pic_fname = os.path.splitext(fName)[0] + img_ext
+ # save the image for use with pdf writer
+ self.report_list[2].savefig(pic_fname)
+
+ # put the image file path in the html data
+ html = self.report_list[0] % str(pic_fname)
+
+ # make/open file in case of absence
+ f = open(fName, 'w')
+ f.close()
+ # write pdf as a pdf file
+ pdf = self.HTML2PDF(data=html, filename=fName)
+
+ # open pdf
+ if pdf:
+ try:
+ # Windows
+ os.startfile(str(fName))
+ except:
+ try:
+ # Mac
+ os.system("open %s" % fName)
+ except:
+ # DO not open
+ logger.error("Could not open file: %s" % sys.exc_value)
+ # delete image file
+ os.remove(pic_fname)
+ return
+ elif ext_num == (1 - self.index_offset):
+ ext = '.html'
+ img_ext = '_img4html.png'
+ report_frame = self.report_list[0]
+ elif ext_num == (2 - self.index_offset):
+ ext = '.txt'
+ # changing the image extension actually changes the image
+ # format on saving
+ img_ext = '_img4txt.pdf'
+ report = self.report_list[1]
+ else:
+ return
+
+ # file name
+ fName = os.path.splitext(fName)[0] + ext
+ dlg.Destroy()
+ # pic (png) file path/name
+ pic_fname = os.path.splitext(fName)[0] + img_ext
+ # put the image path in html string
+ if ext_num == (1 - self.index_offset):
+ report = report_frame % os.path.basename(pic_fname)
+
+ f = open(fName, 'w')
+ f.write(report)
+ f.close()
+ # save png file using pic_fname
+ self.report_list[2].savefig(pic_fname)
diff --git a/src/sas/sasgui/perspectives/pr/__init__.py b/src/sas/sasgui/perspectives/pr/__init__.py
index 2f0e5a5..44b7fec 100644
--- a/src/sas/sasgui/perspectives/pr/__init__.py
+++ b/src/sas/sasgui/perspectives/pr/__init__.py
@@ -1,2 +1,2 @@
-PLUGIN_ID = "P(r) plug-in 1.0"
+PLUGIN_ID = "P(r) plug-in 1.0"
from pr import *
\ No newline at end of file
diff --git a/src/sas/sasgui/perspectives/pr/explore_dialog.py b/src/sas/sasgui/perspectives/pr/explore_dialog.py
index 08bb248..9b63f16 100644
--- a/src/sas/sasgui/perspectives/pr/explore_dialog.py
+++ b/src/sas/sasgui/perspectives/pr/explore_dialog.py
@@ -1,425 +1,427 @@
-
-################################################################################
-#This software was developed by the University of Tennessee as part of the
-#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
-#project funded by the US National Science Foundation.
-#
-#See the license text in license.txt
-#
-#copyright 2009, University of Tennessee
-################################################################################
-
-"""
-Dialog panel to explore the P(r) inversion results for a range
-of D_max value. User picks a number of points and a range of
-distances, then can toggle between inversion outputs and see
-their distribution as a function of D_max.
-"""
-
-
-import wx
-import numpy
-import logging
-import sys
-
-# Avoid Matplotlib complaining about the lack of legend on the plot
-import warnings
-warnings.simplefilter("ignore")
-
-# Import plotting classes
-from sas.sasgui.plottools.PlotPanel import PlotPanel
-from sas.sasgui.plottools import Data1D as Model1D
-from sas.sasgui.guiframe.gui_style import GUIFRAME_ID
-from sas.sasgui.plottools.plottables import Graph
-
-from pr_widgets import PrTextCtrl
-
-# Default number of points on the output plot
-DEFAULT_NPTS = 10
-# Default output parameter to plot
-DEFAULT_OUTPUT = 'Chi2/dof'
-
-class OutputPlot(PlotPanel):
- """
- Plot panel used to show the selected results as a function
- of D_max
- """
- ## Title for plottools
- window_caption = "D Explorer"
-
- def __init__(self, d_min, d_max, parent, id= -1, color=None, \
- dpi=None, style=wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs):
- """
- Initialization. The parameters added to PlotPanel are:
-
- :param d_min: Minimum value of D_max to explore
- :param d_max: Maximum value of D_max to explore
-
- """
- PlotPanel.__init__(self, parent, id=id, style=style, **kwargs)
-
- self.parent = parent
- self.min = d_min
- self.max = d_max
- self.npts = DEFAULT_NPTS
-
- step = (self.max - self.min) / (self.npts - 1)
- self.x = numpy.arange(self.min, self.max + step * 0.01, step)
- dx = numpy.zeros(len(self.x))
- y = numpy.ones(len(self.x))
- dy = numpy.zeros(len(self.x))
-
- # Plot area
- self.plot = Model1D(self.x, y=y, dy=dy)
- self.plot.name = DEFAULT_OUTPUT
- self.plot.symbol = GUIFRAME_ID.CURVE_SYMBOL_NUM
-
- # Graph
- self.graph = Graph()
- self.graph.xaxis("\\rm{D_{max}}", 'A')
- self.graph.yaxis("\\rm{%s}" % DEFAULT_OUTPUT, "")
- self.graph.add(self.plot)
- self.graph.render(self)
-
- self.toolbar.DeleteToolByPos(0)
- self.toolbar.DeleteToolByPos(8)
- self.toolbar.Realize()
-
- def onContextMenu(self, event):
- """
- Default context menu for the plot panel
-
- :TODO: Would be nice to add printing and log/linear scales.
- The current verison of plottools no longer plays well with
- plots outside of guiframe. Guiframe team needs to fix this.
- """
- # Slicer plot popup menu
- wx_id = wx.NewId()
- slicerpop = wx.Menu()
- slicerpop.Append(wx_id, '&Save image', 'Save image as PNG')
- wx.EVT_MENU(self, wx_id, self.onSaveImage)
-
- wx_id = wx.NewId()
- slicerpop.AppendSeparator()
- slicerpop.Append(wx_id, '&Reset Graph')
- wx.EVT_MENU(self, wx_id, self.onResetGraph)
-
- pos = event.GetPosition()
- pos = self.ScreenToClient(pos)
- self.PopupMenu(slicerpop, pos)
-
-class Results(object):
- """
- Class to hold the inversion output parameters
- as a function of D_max
- """
- def __init__(self):
- """
- Initialization. Create empty arrays
- and dictionary of labels.
- """
- # Array of output for each inversion
- self.chi2 = []
- self.osc = []
- self.pos = []
- self.pos_err = []
- self.rg = []
- self.iq0 = []
- self.bck = []
- self.d_max = []
-
- # Dictionary of outputs
- self.outputs = {}
- self.outputs['Chi2/dof'] = ["\chi^2/dof", "a.u.", self.chi2]
- self.outputs['Oscillation parameter'] = ["Osc", "a.u.", self.osc]
- self.outputs['Positive fraction'] = ["P^+", "a.u.", self.pos]
- self.outputs['1-sigma positive fraction'] = ["P^+_{1\ \sigma}",
- "a.u.", self.pos_err]
- self.outputs['Rg'] = ["R_g", "A", self.rg]
- self.outputs['I(q=0)'] = ["I(q=0)", "1/A", self.iq0]
- self.outputs['Background'] = ["Bck", "1/A", self.bck]
-
-class ExploreDialog(wx.Dialog):
- """
- The explorer dialog box. This dialog is meant to be
- invoked by the InversionControl class.
- """
-
- def __init__(self, pr_state, nfunc, *args, **kwds):
- """
- Initialization. The parameters added to Dialog are:
-
- :param pr_state: sas.sascalc.pr.invertor.Invertor object
- :param nfunc: Number of terms in the expansion
-
- """
- kwds["style"] = wx.RESIZE_BORDER | wx.DEFAULT_DIALOG_STYLE
- wx.Dialog.__init__(self, *args, **kwds)
-
- # Initialize Results object
- self.results = Results()
-
- self.pr_state = pr_state
- self._default_min = 0.9 * self.pr_state.d_max
- self._default_max = 1.1 * self.pr_state.d_max
- self.nfunc = nfunc
-
- # Control for number of points
- self.npts_ctl = PrTextCtrl(self, -1, style=wx.TE_PROCESS_ENTER,
- size=(60, 20))
- # Control for the minimum value of D_max
- self.dmin_ctl = PrTextCtrl(self, -1, style=wx.TE_PROCESS_ENTER,
- size=(60, 20))
- # Control for the maximum value of D_max
- self.dmax_ctl = PrTextCtrl(self, -1, style=wx.TE_PROCESS_ENTER,
- size=(60, 20))
-
- # Output selection box for the y axis
- self.output_box = None
-
- # Create the plot object
- self.plotpanel = OutputPlot(self._default_min, self._default_max,
- self, -1, style=wx.RAISED_BORDER)
-
- # Create the layout of the dialog
- self.__do_layout()
- self.Fit()
-
- # Calculate exploration results
- self._recalc()
- # Graph the default output curve
- self._plot_output()
-
- class Event(object):
- """
- Class that holds the content of the form
- """
- ## Number of points to be plotted
- npts = 0
- ## Minimum value of D_max
- dmin = 0
- ## Maximum value of D_max
- dmax = 0
-
- def _get_values(self, event=None):
- """
- Invoked when the user changes a value of the form.
- Check that the values are of the right type.
-
- :return: ExploreDialog.Event object if the content is good,
- None otherwise
- """
- # Flag to make sure that all values are good
- flag = True
-
- # Empty ExploreDialog.Event content
- content_event = self.Event()
-
- # Read each text control and make sure the type is valid
- # Let the user know if a type is invalid by changing the
- # background color of the control.
- try:
- content_event.npts = int(self.npts_ctl.GetValue())
- self.npts_ctl.SetBackgroundColour(wx.WHITE)
- self.npts_ctl.Refresh()
- except:
- flag = False
- self.npts_ctl.SetBackgroundColour("pink")
- self.npts_ctl.Refresh()
-
- try:
- content_event.dmin = float(self.dmin_ctl.GetValue())
- self.dmin_ctl.SetBackgroundColour(wx.WHITE)
- self.dmin_ctl.Refresh()
- except:
- flag = False
- self.dmin_ctl.SetBackgroundColour("pink")
- self.dmin_ctl.Refresh()
-
- try:
- content_event.dmax = float(self.dmax_ctl.GetValue())
- self.dmax_ctl.SetBackgroundColour(wx.WHITE)
- self.dmax_ctl.Refresh()
- except:
- flag = False
- self.dmax_ctl.SetBackgroundColour("pink")
- self.dmax_ctl.Refresh()
-
- # If the content of the form is valid, return the content,
- # otherwise return None
- if flag:
- if event is not None:
- event.Skip(True)
- return content_event
- else:
- return None
-
- def _plot_output(self, event=None):
- """
- Invoked when a new output type is selected for plotting,
- or when a new computation is finished.
- """
- # Get the output type selection
- output_type = self.output_box.GetString(self.output_box.GetSelection())
-
- # If the selected output type is part of the results ojbect,
- # display the results.
- # Note: by design, the output type should always be part of the
- # results object.
- if self.results.outputs.has_key(output_type):
- self.plotpanel.plot.x = self.results.d_max
- self.plotpanel.plot.y = self.results.outputs[output_type][2]
- self.plotpanel.plot.name = '_nolegend_'
- y_label = "\\rm{%s}" % self.results.outputs[output_type][0]
- self.plotpanel.graph.yaxis(y_label,
- self.results.outputs[output_type][1])
-
- # Redraw
- self.plotpanel.graph.render(self.plotpanel)
- self.plotpanel.subplot.figure.canvas.draw_idle()
- else:
- msg = "ExploreDialog: the Results object's dictionary "
- msg += "does not contain "
- msg += "the [%s] output type. This must be indicative of "
- msg += "a change in the " % str(output_type)
- msg += "ExploreDialog code."
- logging.error(msg)
-
- def __do_layout(self):
- """
- Do the layout of the dialog
- """
- # Dialog box properties
- self.SetTitle("D_max Explorer")
- self.SetSize((600, 595))
-
- sizer_main = wx.BoxSizer(wx.VERTICAL)
- sizer_button = wx.BoxSizer(wx.HORIZONTAL)
- sizer_params = wx.GridBagSizer(5, 5)
-
- iy = 0
- ix = 0
- label_npts = wx.StaticText(self, -1, "Npts")
- sizer_params.Add(label_npts, (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- ix += 1
- sizer_params.Add(self.npts_ctl, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- self.npts_ctl.SetValue("%g" % DEFAULT_NPTS)
-
- ix += 1
- label_dmin = wx.StaticText(self, -1, "Min Distance [A]")
- sizer_params.Add(label_dmin, (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- ix += 1
- sizer_params.Add(self.dmin_ctl, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- self.dmin_ctl.SetValue(str(self._default_min))
-
- ix += 1
- label_dmax = wx.StaticText(self, -1, "Max Distance [A]")
- sizer_params.Add(label_dmax, (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- ix += 1
- sizer_params.Add(self.dmax_ctl, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- self.dmax_ctl.SetValue(str(self._default_max))
-
- # Ouput selection box
- selection_msg = wx.StaticText(self, -1, "Select a dependent variable:")
- self.output_box = wx.ComboBox(self, -1, style=wx.CB_READONLY)
- for item in self.results.outputs.keys():
- self.output_box.Append(item, "")
- self.output_box.SetStringSelection(DEFAULT_OUTPUT)
-
- output_sizer = wx.GridBagSizer(5, 5)
- output_sizer.Add(selection_msg, (0, 0), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 10)
- output_sizer.Add(self.output_box, (0, 1), (1, 2),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 10)
-
- wx.EVT_COMBOBOX(self.output_box, -1, self._plot_output)
- sizer_main.Add(output_sizer, 0, wx.EXPAND | wx.ALL, 10)
-
- sizer_main.Add(self.plotpanel, 0, wx.EXPAND | wx.ALL, 10)
- sizer_main.SetItemMinSize(self.plotpanel, 400, 400)
-
- sizer_main.Add(sizer_params, 0, wx.EXPAND | wx.ALL, 10)
- static_line_3 = wx.StaticLine(self, -1)
- sizer_main.Add(static_line_3, 0, wx.EXPAND, 0)
-
- # Bottom area with the close button
- sizer_button.Add((20, 20), 1, wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- button_OK = wx.Button(self, wx.ID_OK, "Close")
- sizer_button.Add(button_OK, 0, wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 10)
-
- sizer_main.Add(sizer_button, 0, wx.EXPAND | wx.BOTTOM | wx.TOP, 10)
- self.SetAutoLayout(True)
- self.SetSizer(sizer_main)
- self.Layout()
- self.Centre()
-
- # Bind the Enter key to recalculation
- self.Bind(wx.EVT_TEXT_ENTER, self._recalc)
-
- def set_plot_unfocus(self):
- """
- Not implemented
- """
- pass
-
- def send_focus_to_datapanel(self, name):
- """
- The GUI manager sometimes calls this method
- TODO: refactor this
- """
- pass
-
- def _recalc(self, event=None):
- """
- Invoked when the user changed a value on the form.
- Process the form and compute the output to be plottted.
- """
- # Get the content of the form
- content = self._get_values()
- # If the content of the form is invalid, return and do nothing
- if content is None:
- return
-
- # Results object to store the computation outputs.
- results = Results()
-
- # Loop over d_max values
- for i in range(content.npts):
- temp = (content.dmax - content.dmin) / (content.npts - 1.0)
- d = content.dmin + i * temp
-
- self.pr_state.d_max = d
- try:
- out, cov = self.pr_state.invert(self.nfunc)
-
- # Store results
- iq0 = self.pr_state.iq0(out)
- rg = self.pr_state.rg(out)
- pos = self.pr_state.get_positive(out)
- pos_err = self.pr_state.get_pos_err(out, cov)
- osc = self.pr_state.oscillations(out)
-
- results.d_max.append(self.pr_state.d_max)
- results.bck.append(self.pr_state.background)
- results.chi2.append(self.pr_state.chi2)
- results.iq0.append(iq0)
- results.rg.append(rg)
- results.pos.append(pos)
- results.pos_err.append(pos_err)
- results.osc.append(osc)
- except:
- # This inversion failed, skip this D_max value
- msg = "ExploreDialog: inversion failed "
- msg += "for D_max=%s\n%s" % (str(d), sys.exc_value)
- logging.error(msg)
-
- self.results = results
-
- # Plot the selected output
- self._plot_output()
+
+################################################################################
+#This software was developed by the University of Tennessee as part of the
+#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
+#project funded by the US National Science Foundation.
+#
+#See the license text in license.txt
+#
+#copyright 2009, University of Tennessee
+################################################################################
+
+"""
+Dialog panel to explore the P(r) inversion results for a range
+of D_max value. User picks a number of points and a range of
+distances, then can toggle between inversion outputs and see
+their distribution as a function of D_max.
+"""
+
+
+import wx
+import numpy as np
+import logging
+import sys
+
+logger = logging.getLogger(__name__)
+
+# Avoid Matplotlib complaining about the lack of legend on the plot
+import warnings
+warnings.simplefilter("ignore")
+
+# Import plotting classes
+from sas.sasgui.plottools.PlotPanel import PlotPanel
+from sas.sasgui.plottools import Data1D as Model1D
+from sas.sasgui.guiframe.gui_style import GUIFRAME_ID
+from sas.sasgui.plottools.plottables import Graph
+
+from pr_widgets import PrTextCtrl
+
+# Default number of points on the output plot
+DEFAULT_NPTS = 10
+# Default output parameter to plot
+DEFAULT_OUTPUT = 'Chi2/dof'
+
+class OutputPlot(PlotPanel):
+ """
+ Plot panel used to show the selected results as a function
+ of D_max
+ """
+ ## Title for plottools
+ window_caption = "D Explorer"
+
+ def __init__(self, d_min, d_max, parent, id= -1, color=None, \
+ dpi=None, style=wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs):
+ """
+ Initialization. The parameters added to PlotPanel are:
+
+ :param d_min: Minimum value of D_max to explore
+ :param d_max: Maximum value of D_max to explore
+
+ """
+ PlotPanel.__init__(self, parent, id=id, style=style, **kwargs)
+
+ self.parent = parent
+ self.min = d_min
+ self.max = d_max
+ self.npts = DEFAULT_NPTS
+
+ step = (self.max - self.min) / (self.npts - 1)
+ self.x = np.arange(self.min, self.max + step * 0.01, step)
+ dx = np.zeros(len(self.x))
+ y = np.ones(len(self.x))
+ dy = np.zeros(len(self.x))
+
+ # Plot area
+ self.plot = Model1D(self.x, y=y, dy=dy)
+ self.plot.name = DEFAULT_OUTPUT
+ self.plot.symbol = GUIFRAME_ID.CURVE_SYMBOL_NUM
+
+ # Graph
+ self.graph = Graph()
+ self.graph.xaxis("\\rm{D_{max}}", 'A')
+ self.graph.yaxis("\\rm{%s}" % DEFAULT_OUTPUT, "")
+ self.graph.add(self.plot)
+ self.graph.render(self)
+
+ self.toolbar.DeleteToolByPos(0)
+ self.toolbar.DeleteToolByPos(8)
+ self.toolbar.Realize()
+
+ def onContextMenu(self, event):
+ """
+ Default context menu for the plot panel
+
+ :TODO: Would be nice to add printing and log/linear scales.
+ The current verison of plottools no longer plays well with
+ plots outside of guiframe. Guiframe team needs to fix this.
+ """
+ # Slicer plot popup menu
+ wx_id = wx.NewId()
+ slicerpop = wx.Menu()
+ slicerpop.Append(wx_id, '&Save image', 'Save image as PNG')
+ wx.EVT_MENU(self, wx_id, self.onSaveImage)
+
+ wx_id = wx.NewId()
+ slicerpop.AppendSeparator()
+ slicerpop.Append(wx_id, '&Reset Graph')
+ wx.EVT_MENU(self, wx_id, self.onResetGraph)
+
+ pos = event.GetPosition()
+ pos = self.ScreenToClient(pos)
+ self.PopupMenu(slicerpop, pos)
+
+class Results(object):
+ """
+ Class to hold the inversion output parameters
+ as a function of D_max
+ """
+ def __init__(self):
+ """
+ Initialization. Create empty arrays
+ and dictionary of labels.
+ """
+ # Array of output for each inversion
+ self.chi2 = []
+ self.osc = []
+ self.pos = []
+ self.pos_err = []
+ self.rg = []
+ self.iq0 = []
+ self.bck = []
+ self.d_max = []
+
+ # Dictionary of outputs
+ self.outputs = {}
+ self.outputs['Chi2/dof'] = ["\chi^2/dof", "a.u.", self.chi2]
+ self.outputs['Oscillation parameter'] = ["Osc", "a.u.", self.osc]
+ self.outputs['Positive fraction'] = ["P^+", "a.u.", self.pos]
+ self.outputs['1-sigma positive fraction'] = ["P^+_{1\ \sigma}",
+ "a.u.", self.pos_err]
+ self.outputs['Rg'] = ["R_g", "A", self.rg]
+ self.outputs['I(q=0)'] = ["I(q=0)", "1/A", self.iq0]
+ self.outputs['Background'] = ["Bck", "1/A", self.bck]
+
+class ExploreDialog(wx.Dialog):
+ """
+ The explorer dialog box. This dialog is meant to be
+ invoked by the InversionControl class.
+ """
+
+ def __init__(self, pr_state, nfunc, *args, **kwds):
+ """
+ Initialization. The parameters added to Dialog are:
+
+ :param pr_state: sas.sascalc.pr.invertor.Invertor object
+ :param nfunc: Number of terms in the expansion
+
+ """
+ kwds["style"] = wx.RESIZE_BORDER | wx.DEFAULT_DIALOG_STYLE
+ wx.Dialog.__init__(self, *args, **kwds)
+
+ # Initialize Results object
+ self.results = Results()
+
+ self.pr_state = pr_state
+ self._default_min = 0.9 * self.pr_state.d_max
+ self._default_max = 1.1 * self.pr_state.d_max
+ self.nfunc = nfunc
+
+ # Control for number of points
+ self.npts_ctl = PrTextCtrl(self, -1, style=wx.TE_PROCESS_ENTER,
+ size=(60, 20))
+ # Control for the minimum value of D_max
+ self.dmin_ctl = PrTextCtrl(self, -1, style=wx.TE_PROCESS_ENTER,
+ size=(60, 20))
+ # Control for the maximum value of D_max
+ self.dmax_ctl = PrTextCtrl(self, -1, style=wx.TE_PROCESS_ENTER,
+ size=(60, 20))
+
+ # Output selection box for the y axis
+ self.output_box = None
+
+ # Create the plot object
+ self.plotpanel = OutputPlot(self._default_min, self._default_max,
+ self, -1, style=wx.RAISED_BORDER)
+
+ # Create the layout of the dialog
+ self.__do_layout()
+ self.Fit()
+
+ # Calculate exploration results
+ self._recalc()
+ # Graph the default output curve
+ self._plot_output()
+
+ class Event(object):
+ """
+ Class that holds the content of the form
+ """
+ ## Number of points to be plotted
+ npts = 0
+ ## Minimum value of D_max
+ dmin = 0
+ ## Maximum value of D_max
+ dmax = 0
+
+ def _get_values(self, event=None):
+ """
+ Invoked when the user changes a value of the form.
+ Check that the values are of the right type.
+
+ :return: ExploreDialog.Event object if the content is good,
+ None otherwise
+ """
+ # Flag to make sure that all values are good
+ flag = True
+
+ # Empty ExploreDialog.Event content
+ content_event = self.Event()
+
+ # Read each text control and make sure the type is valid
+ # Let the user know if a type is invalid by changing the
+ # background color of the control.
+ try:
+ content_event.npts = int(self.npts_ctl.GetValue())
+ self.npts_ctl.SetBackgroundColour(wx.WHITE)
+ self.npts_ctl.Refresh()
+ except:
+ flag = False
+ self.npts_ctl.SetBackgroundColour("pink")
+ self.npts_ctl.Refresh()
+
+ try:
+ content_event.dmin = float(self.dmin_ctl.GetValue())
+ self.dmin_ctl.SetBackgroundColour(wx.WHITE)
+ self.dmin_ctl.Refresh()
+ except:
+ flag = False
+ self.dmin_ctl.SetBackgroundColour("pink")
+ self.dmin_ctl.Refresh()
+
+ try:
+ content_event.dmax = float(self.dmax_ctl.GetValue())
+ self.dmax_ctl.SetBackgroundColour(wx.WHITE)
+ self.dmax_ctl.Refresh()
+ except:
+ flag = False
+ self.dmax_ctl.SetBackgroundColour("pink")
+ self.dmax_ctl.Refresh()
+
+ # If the content of the form is valid, return the content,
+ # otherwise return None
+ if flag:
+ if event is not None:
+ event.Skip(True)
+ return content_event
+ else:
+ return None
+
+ def _plot_output(self, event=None):
+ """
+ Invoked when a new output type is selected for plotting,
+ or when a new computation is finished.
+ """
+ # Get the output type selection
+ output_type = self.output_box.GetString(self.output_box.GetSelection())
+
+ # If the selected output type is part of the results ojbect,
+ # display the results.
+ # Note: by design, the output type should always be part of the
+ # results object.
+ if output_type in self.results.outputs:
+ self.plotpanel.plot.x = self.results.d_max
+ self.plotpanel.plot.y = self.results.outputs[output_type][2]
+ self.plotpanel.plot.name = '_nolegend_'
+ y_label = "\\rm{%s}" % self.results.outputs[output_type][0]
+ self.plotpanel.graph.yaxis(y_label,
+ self.results.outputs[output_type][1])
+
+ # Redraw
+ self.plotpanel.graph.render(self.plotpanel)
+ self.plotpanel.subplot.figure.canvas.draw_idle()
+ else:
+ msg = "ExploreDialog: the Results object's dictionary "
+ msg += "does not contain "
+ msg += "the [%s] output type. This must be indicative of "
+ msg += "a change in the " % str(output_type)
+ msg += "ExploreDialog code."
+ logger.error(msg)
+
+ def __do_layout(self):
+ """
+ Do the layout of the dialog
+ """
+ # Dialog box properties
+ self.SetTitle("D_max Explorer")
+ self.SetSize((600, 595))
+
+ sizer_main = wx.BoxSizer(wx.VERTICAL)
+ sizer_button = wx.BoxSizer(wx.HORIZONTAL)
+ sizer_params = wx.GridBagSizer(5, 5)
+
+ iy = 0
+ ix = 0
+ label_npts = wx.StaticText(self, -1, "Npts")
+ sizer_params.Add(label_npts, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ ix += 1
+ sizer_params.Add(self.npts_ctl, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ self.npts_ctl.SetValue("%g" % DEFAULT_NPTS)
+
+ ix += 1
+ label_dmin = wx.StaticText(self, -1, "Min Distance [A]")
+ sizer_params.Add(label_dmin, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ ix += 1
+ sizer_params.Add(self.dmin_ctl, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ self.dmin_ctl.SetValue(str(self._default_min))
+
+ ix += 1
+ label_dmax = wx.StaticText(self, -1, "Max Distance [A]")
+ sizer_params.Add(label_dmax, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ ix += 1
+ sizer_params.Add(self.dmax_ctl, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ self.dmax_ctl.SetValue(str(self._default_max))
+
+ # Ouput selection box
+ selection_msg = wx.StaticText(self, -1, "Select a dependent variable:")
+ self.output_box = wx.ComboBox(self, -1, style=wx.CB_READONLY)
+ for item in self.results.outputs.keys():
+ self.output_box.Append(item, "")
+ self.output_box.SetStringSelection(DEFAULT_OUTPUT)
+
+ output_sizer = wx.GridBagSizer(5, 5)
+ output_sizer.Add(selection_msg, (0, 0), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 10)
+ output_sizer.Add(self.output_box, (0, 1), (1, 2),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 10)
+
+ wx.EVT_COMBOBOX(self.output_box, -1, self._plot_output)
+ sizer_main.Add(output_sizer, 0, wx.EXPAND | wx.ALL, 10)
+
+ sizer_main.Add(self.plotpanel, 0, wx.EXPAND | wx.ALL, 10)
+ sizer_main.SetItemMinSize(self.plotpanel, 400, 400)
+
+ sizer_main.Add(sizer_params, 0, wx.EXPAND | wx.ALL, 10)
+ static_line_3 = wx.StaticLine(self, -1)
+ sizer_main.Add(static_line_3, 0, wx.EXPAND, 0)
+
+ # Bottom area with the close button
+ sizer_button.Add((20, 20), 1, wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ button_OK = wx.Button(self, wx.ID_OK, "Close")
+ sizer_button.Add(button_OK, 0, wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 10)
+
+ sizer_main.Add(sizer_button, 0, wx.EXPAND | wx.BOTTOM | wx.TOP, 10)
+ self.SetAutoLayout(True)
+ self.SetSizer(sizer_main)
+ self.Layout()
+ self.Centre()
+
+ # Bind the Enter key to recalculation
+ self.Bind(wx.EVT_TEXT_ENTER, self._recalc)
+
+ def set_plot_unfocus(self):
+ """
+ Not implemented
+ """
+ pass
+
+ def send_focus_to_datapanel(self, name):
+ """
+ The GUI manager sometimes calls this method
+ TODO: refactor this
+ """
+ pass
+
+ def _recalc(self, event=None):
+ """
+ Invoked when the user changed a value on the form.
+ Process the form and compute the output to be plottted.
+ """
+ # Get the content of the form
+ content = self._get_values()
+ # If the content of the form is invalid, return and do nothing
+ if content is None:
+ return
+
+ # Results object to store the computation outputs.
+ results = Results()
+
+ # Loop over d_max values
+ for i in range(content.npts):
+ temp = (content.dmax - content.dmin) / (content.npts - 1.0)
+ d = content.dmin + i * temp
+
+ self.pr_state.d_max = d
+ try:
+ out, cov = self.pr_state.invert(self.nfunc)
+
+ # Store results
+ iq0 = self.pr_state.iq0(out)
+ rg = self.pr_state.rg(out)
+ pos = self.pr_state.get_positive(out)
+ pos_err = self.pr_state.get_pos_err(out, cov)
+ osc = self.pr_state.oscillations(out)
+
+ results.d_max.append(self.pr_state.d_max)
+ results.bck.append(self.pr_state.background)
+ results.chi2.append(self.pr_state.chi2)
+ results.iq0.append(iq0)
+ results.rg.append(rg)
+ results.pos.append(pos)
+ results.pos_err.append(pos_err)
+ results.osc.append(osc)
+ except:
+ # This inversion failed, skip this D_max value
+ msg = "ExploreDialog: inversion failed "
+ msg += "for D_max=%s\n%s" % (str(d), sys.exc_value)
+ logger.error(msg)
+
+ self.results = results
+
+ # Plot the selected output
+ self._plot_output()
diff --git a/src/sas/sasgui/perspectives/pr/inversion_panel.py b/src/sas/sasgui/perspectives/pr/inversion_panel.py
index 825bc05..2bfc819 100644
--- a/src/sas/sasgui/perspectives/pr/inversion_panel.py
+++ b/src/sas/sasgui/perspectives/pr/inversion_panel.py
@@ -17,6 +17,8 @@ from pr_widgets import DataFileTextCtrl
from pr_widgets import OutputTextCtrl
from sas.sasgui.guiframe.documentation_window import DocumentationWindow
+logger = logging.getLogger(__name__)
+
if sys.platform.count("win32") > 0:
FONT_VARIANT = 0
else:
@@ -67,7 +69,11 @@ class InversionControl(ScrolledPanel, PanelBase):
self.rg_ctl = None
self.iq0_ctl = None
- self.bck_chk = None
+ self.bck_value = None
+ self.bck_est_ctl = None
+ self.bck_man_ctl = None
+ self.est_bck = True
+ self.bck_input = None
self.bck_ctl = None
# TextCtrl for fraction of positive P(r)
@@ -268,7 +274,7 @@ class InversionControl(ScrolledPanel, PanelBase):
"""
# Ask the user the location of the file to write to.
path = None
- if self.parent != None:
+ if self.parent is not None:
self._default_save_location = self.parent._default_save_location
dlg = wx.FileDialog(self, "Choose a file",
self._default_save_location,
@@ -276,7 +282,7 @@ class InversionControl(ScrolledPanel, PanelBase):
if dlg.ShowModal() == wx.ID_OK:
path = dlg.GetPath()
self._default_save_location = os.path.dirname(path)
- if self.parent != None:
+ if self.parent is not None:
self.parent._default_save_location = self._default_save_location
else:
return None
@@ -309,7 +315,7 @@ class InversionControl(ScrolledPanel, PanelBase):
# Read the panel's parameters
flag, alpha, dmax, nfunc, qmin, \
- qmax, height, width = self._read_pars()
+ qmax, height, width, bck = self._read_pars()
state.nfunc = nfunc
state.d_max = dmax
@@ -323,7 +329,8 @@ class InversionControl(ScrolledPanel, PanelBase):
state.file = self.plot_data.GetValue()
# Background evaluation checkbox
- state.estimate_bck = self.bck_chk.IsChecked()
+ state.estimate_bck = self.est_bck
+ state.bck_value = bck
# Estimates
state.nterms_estimate = self.nterms_estimate
@@ -368,8 +375,14 @@ class InversionControl(ScrolledPanel, PanelBase):
# Data file
self.plot_data.SetValue(str(state.file))
- # Background evaluation checkbox
- self.bck_chk.SetValue(state.estimate_bck)
+ # Background value
+ self.bck_est_ctl.SetValue(state.estimate_bck)
+ self.bck_man_ctl.SetValue(not state.estimate_bck)
+ if not state.estimate_bck:
+ self.bck_input.Enable()
+ self.bck_input.SetValue(str(state.bck_value))
+ self.est_bck = state.estimate_bck
+ self.bck_value = state.bck_value
# Estimates
if state.nterms_estimate is not None:
@@ -428,14 +441,42 @@ class InversionControl(ScrolledPanel, PanelBase):
pars_sizer.Add(self.plot_data, (iy, 1), (1, 1),
wx.EXPAND | wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 15)
- self.bck_chk = wx.CheckBox(self, -1, "Estimate background level")
- hint_msg = "Check box to let the fit estimate "
- hint_msg += "the constant background level."
- self.bck_chk.SetToolTipString(hint_msg)
- self.bck_chk.Bind(wx.EVT_CHECKBOX, self._on_pars_changed)
+ radio_sizer = wx.GridBagSizer(5, 5)
+
+ self.bck_est_ctl = wx.RadioButton(self, -1, "Estimate background level",
+ name="estimate_bck", style=wx.RB_GROUP)
+ self.bck_man_ctl = wx.RadioButton(self, -1, "Input manual background level",
+ name="manual_bck")
+
+ self.bck_est_ctl.Bind(wx.EVT_RADIOBUTTON, self._on_bck_changed)
+ self.bck_man_ctl.Bind(wx.EVT_RADIOBUTTON, self._on_bck_changed)
+
+ radio_sizer.Add(self.bck_est_ctl, (0,0), (1,1), wx.LEFT | wx.EXPAND)
+ radio_sizer.Add(self.bck_man_ctl, (0,1), (1,1), wx.RIGHT | wx.EXPAND)
+
iy += 1
- pars_sizer.Add(self.bck_chk, (iy, 0), (1, 2),
+ pars_sizer.Add(radio_sizer, (iy, 0), (1, 2),
wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+
+ background_label = wx.StaticText(self, -1, "Background: ")
+ self.bck_input = PrTextCtrl(self, -1, style=wx.TE_PROCESS_ENTER,
+ size=(60, 20), value="0.0")
+ self.bck_input.Disable()
+ self.bck_input.Bind(wx.EVT_TEXT, self._read_pars)
+ background_units = wx.StaticText(self, -1, "[A^(-1)]", size=(55, 20))
+ iy += 1
+
+ background_sizer = wx.GridBagSizer(5, 5)
+
+ background_sizer.Add(background_label, (0, 0), (1,1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 23)
+ background_sizer.Add(self.bck_input, (0, 1), (1,1),
+ wx.LEFT | wx.ADJUST_MINSIZE, 5)
+ background_sizer.Add(background_units, (0, 2), (1,1),
+ wx.LEFT | wx.ADJUST_MINSIZE, 5)
+ pars_sizer.Add(background_sizer, (iy, 0), (1, 2),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+
boxsizer1.Add(pars_sizer, 0, wx.EXPAND)
vbox.Add(boxsizer1, (iy_vb, 0), (1, 1),
wx.LEFT | wx.RIGHT | wx.EXPAND | wx.ADJUST_MINSIZE | wx.TOP, 5)
@@ -709,10 +750,10 @@ class InversionControl(ScrolledPanel, PanelBase):
float(alpha)
self.alpha_ctl.SetValue(alpha)
except ValueError:
- logging.error("InversionControl._on_accept_alpha got a value that was not a number: %s" % alpha )
+ logger.error("InversionControl._on_accept_alpha got a value that was not a number: %s" % alpha )
except:
# No estimate or bad estimate, either do nothing
- logging.error("InversionControl._on_accept_alpha: %s" % sys.exc_value)
+ logger.error("InversionControl._on_accept_alpha: %s" % sys.exc_value)
def _on_accept_nterms(self, evt):
"""
@@ -725,10 +766,10 @@ class InversionControl(ScrolledPanel, PanelBase):
float(nterms)
self.nfunc_ctl.SetValue(nterms)
except ValueError:
- logging.error("InversionControl._on_accept_nterms got a value that was not a number: %s" % nterms )
+ logger.error("InversionControl._on_accept_nterms got a value that was not a number: %s" % nterms )
except:
# No estimate or bad estimate, either do nothing
- logging.error("InversionControl._on_accept_nterms: %s" % sys.exc_value)
+ logger.error("InversionControl._on_accept_nterms: %s" % sys.exc_value)
def clear_panel(self):
"""
@@ -761,14 +802,20 @@ class InversionControl(ScrolledPanel, PanelBase):
self._on_pars_changed()
+ def _on_bck_changed(self, evt=None):
+ self.est_bck = self.bck_est_ctl.GetValue()
+ if self.est_bck:
+ self.bck_input.Disable()
+ else:
+ self.bck_input.Enable()
+
def _on_pars_changed(self, evt=None):
"""
Called when an input parameter has changed
We will estimate the alpha parameter behind the
scenes.
"""
- flag, alpha, dmax, nfunc, qmin, qmax, height, width = self._read_pars()
- has_bck = self.bck_chk.IsChecked()
+ flag, alpha, dmax, nfunc, qmin, qmax, height, width, bck = self._read_pars()
# If the pars are valid, estimate alpha
if flag:
@@ -780,7 +827,8 @@ class InversionControl(ScrolledPanel, PanelBase):
self._manager.estimate_plot_inversion(alpha=alpha, nfunc=nfunc,
d_max=dmax,
q_min=qmin, q_max=qmax,
- bck=has_bck,
+ est_bck=self.est_bck,
+ bck_val=bck,
height=height,
width=width)
@@ -794,6 +842,7 @@ class InversionControl(ScrolledPanel, PanelBase):
qmax = 0
height = 0
width = 0
+ background = 0
flag = True
# Read slit height
try:
@@ -887,7 +936,21 @@ class InversionControl(ScrolledPanel, PanelBase):
self.qmax_ctl.SetBackgroundColour("pink")
self.qmax_ctl.Refresh()
- return flag, alpha, dmax, nfunc, qmin, qmax, height, width
+ # Read background
+ if not self.est_bck:
+ try:
+ bck_str = self.bck_input.GetValue()
+ if len(bck_str.strip()) == 0:
+ background = 0.0
+ else:
+ background = float(bck_str)
+ self.bck_input.SetBackgroundColour(wx.WHITE)
+ except ValueError:
+ background = 0.0
+ self.bck_input.SetBackgroundColour("pink")
+ self.bck_input.Refresh()
+
+ return flag, alpha, dmax, nfunc, qmin, qmax, height, width, background
def _on_explore(self, evt):
"""
@@ -912,12 +975,11 @@ class InversionControl(ScrolledPanel, PanelBase):
# Get the data from the form
# Push it to the manager
- flag, alpha, dmax, nfunc, qmin, qmax, height, width = self._read_pars()
- has_bck = self.bck_chk.IsChecked()
+ flag, alpha, dmax, nfunc, qmin, qmax, height, width, bck = self._read_pars()
if flag:
dataset = self.plot_data.GetValue()
- if dataset == None or len(dataset.strip()) == 0:
+ if dataset is None or len(dataset.strip()) == 0:
message = "No data to invert. Select a data set before"
message += " proceeding with P(r) inversion."
wx.PostEvent(self._manager.parent, StatusEvent(status=message))
@@ -925,7 +987,8 @@ class InversionControl(ScrolledPanel, PanelBase):
self._manager.setup_plot_inversion(alpha=alpha, nfunc=nfunc,
d_max=dmax,
q_min=qmin, q_max=qmax,
- bck=has_bck,
+ est_bck=self.est_bck,
+ bck_val = bck,
height=height,
width=width)
else:
@@ -937,7 +1000,7 @@ class InversionControl(ScrolledPanel, PanelBase):
"""
Choose a new input file for I(q)
"""
- if not self._manager is None:
+ if self._manager is not None:
self.plot_data.SetValue(str(data.name))
try:
self._manager.show_data(data=data, reset=True)
@@ -946,7 +1009,7 @@ class InversionControl(ScrolledPanel, PanelBase):
self._set_analysis(True)
except:
msg = "InversionControl._change_file: %s" % sys.exc_value
- logging.error(msg)
+ logger.error(msg)
def on_help(self, event):
"""
diff --git a/src/sas/sasgui/perspectives/pr/inversion_state.py b/src/sas/sasgui/perspectives/pr/inversion_state.py
index 681225a..96ae522 100644
--- a/src/sas/sasgui/perspectives/pr/inversion_state.py
+++ b/src/sas/sasgui/perspectives/pr/inversion_state.py
@@ -1,531 +1,536 @@
-"""
- Handling of P(r) inversion states
-"""
-################################################################################
-#This software was developed by the University of Tennessee as part of the
-#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
-#project funded by the US National Science Foundation.
-#
-#See the license text in license.txt
-#
-#copyright 2009, University of Tennessee
-################################################################################
-
-
-import time
-import os
-import sys
-import logging
-from lxml import etree
-from sas.sasgui.guiframe.dataFitting import Data1D
-from sas.sascalc.dataloader.readers.cansas_reader import Reader as CansasReader
-from sas.sascalc.dataloader.readers.cansas_reader import get_content
-
-PRNODE_NAME = 'pr_inversion'
-CANSAS_NS = "cansas1d/1.0"
-
-# Translation of names between stored and object data
-## List of P(r) inversion inputs
-in_list = [["nterms", "nfunc"],
- ["d_max", "d_max"],
- ["alpha", "alpha"],
- ["slit_width", "width"],
- ["slit_height", "height"],
- ["qmin", "qmin"],
- ["qmax", "qmax"],
- ["estimate_bck", "estimate_bck"]]
-
-## List of P(r) inversion outputs
-out_list = [["elapsed", "elapsed"],
- ["rg", "rg"],
- ["iq0", "iq0"],
- ["bck", "bck"],
- ["chi2", "chi2"],
- ["osc", "osc"],
- ["pos", "pos"],
- ["pos_err", "pos_err"],
- ["alpha_estimate", "alpha_estimate"],
- ["nterms_estimate", "nterms_estimate"]]
-
-class InversionState(object):
- """
- Class to hold the state information of the InversionControl panel.
- """
- def __init__(self):
- """
- Default values
- """
- # Input
- self.file = None
- self.estimate_bck = False
- self.timestamp = time.time()
-
- # Inversion parameters
- self.nfunc = None
- self.d_max = None
- self.alpha = None
-
- # Slit parameters
- self.height = None
- self.width = None
-
- # Q range
- self.qmin = None
- self.qmax = None
-
- # Outputs
- self.elapsed = None
- self.rg = None
- self.iq0 = None
- self.bck = None
- self.chi2 = None
- self.osc = None
- self.pos = None
- self.pos_err = None
-
- # Estimates
- self.alpha_estimate = None
- self.nterms_estimate = None
-
- # Data
- self.q = None
- self.iq_obs = None
- self.iq_calc = None
-
- # Coefficients
- self.coefficients = None
- self.covariance = None
-
- def __str__(self):
- """
- Pretty print
-
- :return: string representing the state
-
- """
- state = "File: %s\n" % self.file
- state += "Timestamp: %s\n" % self.timestamp
- state += "Estimate bck: %s\n" % str(self.estimate_bck)
- state += "No. terms: %s\n" % str(self.nfunc)
- state += "D_max: %s\n" % str(self.d_max)
- state += "Alpha: %s\n" % str(self.alpha)
-
- state += "Slit height: %s\n" % str(self.height)
- state += "Slit width: %s\n" % str(self.width)
-
- state += "Qmin: %s\n" % str(self.qmin)
- state += "Qmax: %s\n" % str(self.qmax)
-
- state += "\nEstimates:\n"
- state += " Alpha: %s\n" % str(self.alpha_estimate)
- state += " Nterms: %s\n" % str(self.nterms_estimate)
-
- state += "\nOutputs:\n"
- state += " Elapsed: %s\n" % str(self.elapsed)
- state += " Rg: %s\n" % str(self.rg)
- state += " I(q=0): %s\n" % str(self.iq0)
- state += " Bck: %s\n" % str(self.bck)
- state += " Chi^2: %s\n" % str(self.chi2)
- state += " Oscillation:%s\n" % str(self.osc)
- state += " Positive: %s\n" % str(self.pos)
- state += " 1-sigma pos:%s\n" % str(self.pos_err)
-
- return state
-
- def toXML(self, file="pr_state.prv", doc=None, entry_node=None):
- """
- Writes the state of the InversionControl panel to file, as XML.
-
- Compatible with standalone writing, or appending to an
- already existing XML document. In that case, the XML document
- is required. An optional entry node in the XML document
- may also be given.
-
- :param file: file to write to
- :param doc: XML document object [optional]
- :param entry_node: XML node within the XML document at which
- we will append the data [optional]
-
- """
- #TODO: Get this to work
- from xml.dom.minidom import getDOMImplementation
-
- # Check whether we have to write a standalone XML file
- if doc is None:
- impl = getDOMImplementation()
-
- doc_type = impl.createDocumentType(PRNODE_NAME, "1.0", "1.0")
-
- newdoc = impl.createDocument(None, PRNODE_NAME, doc_type)
- top_element = newdoc.documentElement
- else:
- # We are appending to an existing document
- newdoc = doc
- top_element = newdoc.createElement(PRNODE_NAME)
- if entry_node is None:
- newdoc.documentElement.appendChild(top_element)
- else:
- entry_node.appendChild(top_element)
-
- attr = newdoc.createAttribute("version")
- attr.nodeValue = '1.0'
- top_element.setAttributeNode(attr)
-
- # File name
- element = newdoc.createElement("filename")
- if self.file is not None:
- element.appendChild(newdoc.createTextNode(str(self.file)))
- else:
- element.appendChild(newdoc.createTextNode(str(file)))
- top_element.appendChild(element)
-
- element = newdoc.createElement("timestamp")
- element.appendChild(newdoc.createTextNode(time.ctime(self.timestamp)))
- attr = newdoc.createAttribute("epoch")
- attr.nodeValue = str(self.timestamp)
- element.setAttributeNode(attr)
- top_element.appendChild(element)
-
- # Inputs
- inputs = newdoc.createElement("inputs")
- top_element.appendChild(inputs)
-
- for item in in_list:
- element = newdoc.createElement(item[0])
- element.appendChild(newdoc.createTextNode(str(getattr(self, item[1]))))
- inputs.appendChild(element)
-
- # Outputs
- outputs = newdoc.createElement("outputs")
- top_element.appendChild(outputs)
-
- for item in out_list:
- element = newdoc.createElement(item[0])
- element.appendChild(newdoc.createTextNode(str(getattr(self, item[1]))))
- outputs.appendChild(element)
-
- # Save output coefficients and its covariance matrix
- element = newdoc.createElement("coefficients")
- element.appendChild(newdoc.createTextNode(str(self.coefficients)))
- outputs.appendChild(element)
- element = newdoc.createElement("covariance")
- element.appendChild(newdoc.createTextNode(str(self.covariance)))
- outputs.appendChild(element)
-
- # Save the file
- if doc is None:
- fd = open(file, 'w')
- fd.write(newdoc.toprettyxml())
- fd.close()
- return None
- else:
- return newdoc
-
- def fromXML(self, file=None, node=None):
- """
- Load a P(r) inversion state from a file
-
- :param file: .prv file
- :param node: node of a XML document to read from
-
- """
- if file is not None:
- msg = "InversionState no longer supports non-CanSAS"
- msg += " format for P(r) files"
- raise RuntimeError, msg
-
- if node.get('version') and node.get('version') == '1.0':
-
- # Get file name
- entry = get_content('ns:filename', node)
- if entry is not None:
- self.file = entry.text.strip()
-
- # Get time stamp
- entry = get_content('ns:timestamp', node)
- if entry is not None and entry.get('epoch'):
- try:
- self.timestamp = float(entry.get('epoch'))
- except:
- msg = "InversionState.fromXML: Could not read "
- msg += "timestamp\n %s" % sys.exc_value
- logging.error(msg)
-
- # Parse inversion inputs
- entry = get_content('ns:inputs', node)
- if entry is not None:
- for item in in_list:
- input_field = get_content('ns:%s' % item[0], entry)
- if input_field is not None:
- try:
- setattr(self, item[1], float(input_field.text.strip()))
- except:
- setattr(self, item[1], None)
- input_field = get_content('ns:estimate_bck', entry)
- if input_field is not None:
- try:
- self.estimate_bck = input_field.text.strip() == 'True'
- except:
- self.estimate_bck = False
-
- # Parse inversion outputs
- entry = get_content('ns:outputs', node)
- if entry is not None:
- # Output parameters (scalars)
- for item in out_list:
- input_field = get_content('ns:%s' % item[0], entry)
- if input_field is not None:
- try:
- setattr(self, item[1], float(input_field.text.strip()))
- except:
- setattr(self, item[1], None)
-
- # Look for coefficients
- # Format is [value, value, value, value]
- coeff = get_content('ns:coefficients', entry)
- if coeff is not None:
- # Remove brackets
- c_values = coeff.text.strip().replace('[', '')
- c_values = c_values.replace(']', '')
- toks = c_values.split()
- self.coefficients = []
- for c in toks:
- try:
- self.coefficients.append(float(c))
- except:
- # Bad data, skip. We will count the number of
- # coefficients at the very end and deal with
- # inconsistencies then.
- pass
- # Sanity check
- if not len(self.coefficients) == self.nfunc:
- # Inconsistent number of coefficients.
- # Don't keep the data.
- err_msg = "InversionState.fromXML: inconsistant "
- err_msg += "number of coefficients: "
- err_msg += "%d %d" % (len(self.coefficients),
- self.nfunc)
- logging.error(err_msg)
- self.coefficients = None
-
- # Look for covariance matrix
- # Format is [ [value, value], [value, value] ]
- coeff = get_content('ns:covariance', entry)
- if coeff is not None:
- # Parse rows
- rows = coeff.text.strip().split('[')
- self.covariance = []
- for row in rows:
- row = row.strip()
- if len(row) == 0: continue
- # Remove end bracket
- row = row.replace(']', '')
- c_values = row.split()
- cov_row = []
- for c in c_values:
- try:
- cov_row.append(float(c))
- except:
- # Bad data, skip. We will count the number of
- # coefficients at the very end and deal with
- # inconsistencies then.
- pass
- # Sanity check: check the number of entries in the row
- if len(cov_row) == self.nfunc:
- self.covariance.append(cov_row)
- # Sanity check: check the number of rows in the covariance
- # matrix
- if not len(self.covariance) == self.nfunc:
- # Inconsistent dimensions of the covariance matrix.
- # Don't keep the data.
- err_msg = "InversionState.fromXML: "
- err_msg += "inconsistant dimensions of the "
- err_msg += " covariance matrix: "
- err_msg += "%d %d" % (len(self.covariance), self.nfunc)
- logging.error(err_msg)
- self.covariance = None
-
-class Reader(CansasReader):
- """
- Class to load a .prv P(r) inversion file
- """
- ## File type
- type_name = "P(r)"
-
- ## Wildcards
- type = ["P(r) files (*.prv)|*.prv",
- "SASView files (*.svs)|*.svs"]
- ## List of allowed extensions
- ext = ['.prv', '.PRV', '.svs', '.SVS']
-
- def __init__(self, call_back, cansas=True):
- """
- Initialize the call-back method to be called
- after we load a file
-
- :param call_back: call-back method
- :param cansas: True = files will be written/read in CanSAS format
- False = write CanSAS format
-
- """
- ## Call back method to be executed after a file is read
- self.call_back = call_back
- ## CanSAS format flag
- self.cansas = cansas
- self.state = None
-
- def read(self, path):
- """
- Load a new P(r) inversion state from file
-
- :param path: file path
-
- :return: None
-
- """
- if self.cansas == True:
- return self._read_cansas(path)
- else:
- return self._read_standalone(path)
-
- def _read_standalone(self, path):
- """
- Load a new P(r) inversion state from file.
- The P(r) node is assumed to be the top element.
-
- :param path: file path
-
- :return: None
-
- """
- # Read the new state from file
- state = InversionState()
- state.fromXML(file=path)
-
- # Call back to post the new state
- self.state = state
- #self.call_back(state)
- return None
-
- def _parse_prstate(self, entry):
- """
- Read a p(r) inversion result from an XML node
-
- :param entry: XML node to read from
-
- :return: InversionState object
-
- """
- state = None
-
- # Locate the P(r) node
- try:
- nodes = entry.xpath('ns:%s' % PRNODE_NAME,
- namespaces={'ns': CANSAS_NS})
- if nodes != []:
- # Create an empty state
- state = InversionState()
- state.fromXML(node=nodes[0])
- except:
- msg = "XML document does not contain P(r) "
- msg += "information.\n %s" % sys.exc_value
- logging.info(msg)
-
- return state
-
- def _read_cansas(self, path):
- """
- Load data and P(r) information from a CanSAS XML file.
-
- :param path: file path
-
- :return: Data1D object if a single SASentry was found,
- or a list of Data1D objects if multiple entries were found,
- or None of nothing was found
-
- :raise RuntimeError: when the file can't be opened
- :raise ValueError: when the length of the data vectors are inconsistent
-
- """
- output = []
-
- if os.path.isfile(path):
- basename = os.path.basename(path)
- root, extension = os.path.splitext(basename)
- #TODO: eventually remove the check for .xml once
- # the P(r) writer/reader is truly complete.
- if extension.lower() in self.ext or extension.lower() == '.xml':
-
- tree = etree.parse(path, parser=etree.ETCompatXMLParser())
- # Check the format version number
- # Specifying the namespace will take care of the file
- #format version
- root = tree.getroot()
-
- entry_list = root.xpath('/ns:SASroot/ns:SASentry',
- namespaces={'ns': CANSAS_NS})
-
- for entry in entry_list:
- sas_entry, _ = self._parse_entry(entry)
- prstate = self._parse_prstate(entry)
- #prstate could be None when .svs file is loaded
- #in this case, skip appending to output
- if prstate != None:
- sas_entry.meta_data['prstate'] = prstate
- sas_entry.filename = prstate.file
- output.append(sas_entry)
- else:
- raise RuntimeError, "%s is not a file" % path
-
- # Return output consistent with the loader's api
- if len(output) == 0:
- return None
- elif len(output) == 1:
- # Call back to post the new state
- self.call_back(output[0].meta_data['prstate'], datainfo=output[0])
- #self.state = output[0].meta_data['prstate']
- return output[0]
- else:
- return output
-
-
- def write(self, filename, datainfo=None, prstate=None):
- """
- Write the content of a Data1D as a CanSAS XML file
-
- :param filename: name of the file to write
- :param datainfo: Data1D object
- :param prstate: InversionState object
-
- """
- # Sanity check
- if self.cansas == True:
- doc = self.write_toXML(datainfo, prstate)
- # Write the XML document
- fd = open(filename, 'w')
- fd.write(doc.toprettyxml())
- fd.close()
- else:
- prstate.toXML(file=filename)
-
- def write_toXML(self, datainfo=None, state=None):
- """
- Write toXML, a helper for write()
-
- : return: xml doc
- """
- if datainfo is None:
- datainfo = Data1D(x=[], y=[])
- elif not issubclass(datainfo.__class__, Data1D):
- msg = "The cansas writer expects a Data1D "
- msg += "instance: %s" % str(datainfo.__class__.__name__)
- raise RuntimeError, msg
-
- # Create basic XML document
- doc, sasentry = self._to_xml_doc(datainfo)
-
- # Add the invariant information to the XML document
- if state is not None:
- doc = state.toXML(doc=doc, entry_node=sasentry)
-
- return doc
+"""
+ Handling of P(r) inversion states
+"""
+################################################################################
+#This software was developed by the University of Tennessee as part of the
+#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
+#project funded by the US National Science Foundation.
+#
+#See the license text in license.txt
+#
+#copyright 2009, University of Tennessee
+################################################################################
+
+
+import time
+import os
+import sys
+import logging
+from lxml import etree
+from sas.sasgui.guiframe.dataFitting import Data1D
+from sas.sascalc.dataloader.readers.cansas_reader import Reader as CansasReader
+from sas.sascalc.dataloader.readers.cansas_reader import get_content
+
+logger = logging.getLogger(__name__)
+
+PRNODE_NAME = 'pr_inversion'
+CANSAS_NS = "cansas1d/1.0"
+
+# Translation of names between stored and object data
+## List of P(r) inversion inputs
+in_list = [["nterms", "nfunc"],
+ ["d_max", "d_max"],
+ ["alpha", "alpha"],
+ ["slit_width", "width"],
+ ["slit_height", "height"],
+ ["qmin", "qmin"],
+ ["qmax", "qmax"],
+ ["estimate_bck", "estimate_bck"],
+ ["bck_value", "bck_value"]]
+
+## List of P(r) inversion outputs
+out_list = [["elapsed", "elapsed"],
+ ["rg", "rg"],
+ ["iq0", "iq0"],
+ ["bck", "bck"],
+ ["chi2", "chi2"],
+ ["osc", "osc"],
+ ["pos", "pos"],
+ ["pos_err", "pos_err"],
+ ["alpha_estimate", "alpha_estimate"],
+ ["nterms_estimate", "nterms_estimate"]]
+
+class InversionState(object):
+ """
+ Class to hold the state information of the InversionControl panel.
+ """
+ def __init__(self):
+ """
+ Default values
+ """
+ # Input
+ self.file = None
+ self.estimate_bck = False
+ self.timestamp = time.time()
+ self.bck_value = 0.0
+
+ # Inversion parameters
+ self.nfunc = None
+ self.d_max = None
+ self.alpha = None
+
+ # Slit parameters
+ self.height = None
+ self.width = None
+
+ # Q range
+ self.qmin = None
+ self.qmax = None
+
+ # Outputs
+ self.elapsed = None
+ self.rg = None
+ self.iq0 = None
+ self.bck = None
+ self.chi2 = None
+ self.osc = None
+ self.pos = None
+ self.pos_err = None
+
+ # Estimates
+ self.alpha_estimate = None
+ self.nterms_estimate = None
+
+ # Data
+ self.q = None
+ self.iq_obs = None
+ self.iq_calc = None
+
+ # Coefficients
+ self.coefficients = None
+ self.covariance = None
+
+ def __str__(self):
+ """
+ Pretty print
+
+ :return: string representing the state
+
+ """
+ state = "File: %s\n" % self.file
+ state += "Timestamp: %s\n" % self.timestamp
+ state += "Estimate bck: %s\n" % str(self.estimate_bck)
+ state += "Bck Value: %s\n" % str(self.bck_value)
+ state += "No. terms: %s\n" % str(self.nfunc)
+ state += "D_max: %s\n" % str(self.d_max)
+ state += "Alpha: %s\n" % str(self.alpha)
+
+ state += "Slit height: %s\n" % str(self.height)
+ state += "Slit width: %s\n" % str(self.width)
+
+ state += "Qmin: %s\n" % str(self.qmin)
+ state += "Qmax: %s\n" % str(self.qmax)
+
+ state += "\nEstimates:\n"
+ state += " Alpha: %s\n" % str(self.alpha_estimate)
+ state += " Nterms: %s\n" % str(self.nterms_estimate)
+
+ state += "\nOutputs:\n"
+ state += " Elapsed: %s\n" % str(self.elapsed)
+ state += " Rg: %s\n" % str(self.rg)
+ state += " I(q=0): %s\n" % str(self.iq0)
+ state += " Bck: %s\n" % str(self.bck)
+ state += " Chi^2: %s\n" % str(self.chi2)
+ state += " Oscillation:%s\n" % str(self.osc)
+ state += " Positive: %s\n" % str(self.pos)
+ state += " 1-sigma pos:%s\n" % str(self.pos_err)
+
+ return state
+
+ def toXML(self, file="pr_state.prv", doc=None, entry_node=None):
+ """
+ Writes the state of the InversionControl panel to file, as XML.
+
+ Compatible with standalone writing, or appending to an
+ already existing XML document. In that case, the XML document
+ is required. An optional entry node in the XML document
+ may also be given.
+
+ :param file: file to write to
+ :param doc: XML document object [optional]
+ :param entry_node: XML node within the XML document at which
+ we will append the data [optional]
+
+ """
+ #TODO: Get this to work
+ from xml.dom.minidom import getDOMImplementation
+
+ # Check whether we have to write a standalone XML file
+ if doc is None:
+ impl = getDOMImplementation()
+
+ doc_type = impl.createDocumentType(PRNODE_NAME, "1.0", "1.0")
+
+ newdoc = impl.createDocument(None, PRNODE_NAME, doc_type)
+ top_element = newdoc.documentElement
+ else:
+ # We are appending to an existing document
+ newdoc = doc
+ top_element = newdoc.createElement(PRNODE_NAME)
+ if entry_node is None:
+ newdoc.documentElement.appendChild(top_element)
+ else:
+ entry_node.appendChild(top_element)
+
+ attr = newdoc.createAttribute("version")
+ attr.nodeValue = '1.0'
+ top_element.setAttributeNode(attr)
+
+ # File name
+ element = newdoc.createElement("filename")
+ if self.file is not None:
+ element.appendChild(newdoc.createTextNode(str(self.file)))
+ else:
+ element.appendChild(newdoc.createTextNode(str(file)))
+ top_element.appendChild(element)
+
+ element = newdoc.createElement("timestamp")
+ element.appendChild(newdoc.createTextNode(time.ctime(self.timestamp)))
+ attr = newdoc.createAttribute("epoch")
+ attr.nodeValue = str(self.timestamp)
+ element.setAttributeNode(attr)
+ top_element.appendChild(element)
+
+ # Inputs
+ inputs = newdoc.createElement("inputs")
+ top_element.appendChild(inputs)
+
+ for item in in_list:
+ element = newdoc.createElement(item[0])
+ element.appendChild(newdoc.createTextNode(str(getattr(self, item[1]))))
+ inputs.appendChild(element)
+
+ # Outputs
+ outputs = newdoc.createElement("outputs")
+ top_element.appendChild(outputs)
+
+ for item in out_list:
+ element = newdoc.createElement(item[0])
+ element.appendChild(newdoc.createTextNode(str(getattr(self, item[1]))))
+ outputs.appendChild(element)
+
+ # Save output coefficients and its covariance matrix
+ element = newdoc.createElement("coefficients")
+ element.appendChild(newdoc.createTextNode(str(self.coefficients)))
+ outputs.appendChild(element)
+ element = newdoc.createElement("covariance")
+ element.appendChild(newdoc.createTextNode(str(self.covariance)))
+ outputs.appendChild(element)
+
+ # Save the file
+ if doc is None:
+ fd = open(file, 'w')
+ fd.write(newdoc.toprettyxml())
+ fd.close()
+ return None
+ else:
+ return newdoc
+
+ def fromXML(self, file=None, node=None):
+ """
+ Load a P(r) inversion state from a file
+
+ :param file: .prv file
+ :param node: node of a XML document to read from
+
+ """
+ if file is not None:
+ msg = "InversionState no longer supports non-CanSAS"
+ msg += " format for P(r) files"
+ raise RuntimeError, msg
+
+ if node.get('version') and node.get('version') == '1.0':
+
+ # Get file name
+ entry = get_content('ns:filename', node)
+ if entry is not None:
+ self.file = entry.text.strip()
+
+ # Get time stamp
+ entry = get_content('ns:timestamp', node)
+ if entry is not None and entry.get('epoch'):
+ try:
+ self.timestamp = float(entry.get('epoch'))
+ except:
+ msg = "InversionState.fromXML: Could not read "
+ msg += "timestamp\n %s" % sys.exc_value
+ logger.error(msg)
+
+ # Parse inversion inputs
+ entry = get_content('ns:inputs', node)
+ if entry is not None:
+ for item in in_list:
+ input_field = get_content('ns:%s' % item[0], entry)
+ if input_field is not None:
+ try:
+ setattr(self, item[1], float(input_field.text.strip()))
+ except:
+ setattr(self, item[1], None)
+ input_field = get_content('ns:estimate_bck', entry)
+ if input_field is not None:
+ try:
+ self.estimate_bck = input_field.text.strip() == 'True'
+ except:
+ self.estimate_bck = False
+
+ # Parse inversion outputs
+ entry = get_content('ns:outputs', node)
+ if entry is not None:
+ # Output parameters (scalars)
+ for item in out_list:
+ input_field = get_content('ns:%s' % item[0], entry)
+ if input_field is not None:
+ try:
+ setattr(self, item[1], float(input_field.text.strip()))
+ except:
+ setattr(self, item[1], None)
+
+ # Look for coefficients
+ # Format is [value, value, value, value]
+ coeff = get_content('ns:coefficients', entry)
+ if coeff is not None:
+ # Remove brackets
+ c_values = coeff.text.strip().replace('[', '')
+ c_values = c_values.replace(']', '')
+ toks = c_values.split()
+ self.coefficients = []
+ for c in toks:
+ try:
+ self.coefficients.append(float(c))
+ except:
+ # Bad data, skip. We will count the number of
+ # coefficients at the very end and deal with
+ # inconsistencies then.
+ pass
+ # Sanity check
+ if not len(self.coefficients) == self.nfunc:
+ # Inconsistent number of coefficients.
+ # Don't keep the data.
+ err_msg = "InversionState.fromXML: inconsistant "
+ err_msg += "number of coefficients: "
+ err_msg += "%d %d" % (len(self.coefficients),
+ self.nfunc)
+ logger.error(err_msg)
+ self.coefficients = None
+
+ # Look for covariance matrix
+ # Format is [ [value, value], [value, value] ]
+ coeff = get_content('ns:covariance', entry)
+ if coeff is not None:
+ # Parse rows
+ rows = coeff.text.strip().split('[')
+ self.covariance = []
+ for row in rows:
+ row = row.strip()
+ if len(row) == 0: continue
+ # Remove end bracket
+ row = row.replace(']', '')
+ c_values = row.split()
+ cov_row = []
+ for c in c_values:
+ try:
+ cov_row.append(float(c))
+ except:
+ # Bad data, skip. We will count the number of
+ # coefficients at the very end and deal with
+ # inconsistencies then.
+ pass
+ # Sanity check: check the number of entries in the row
+ if len(cov_row) == self.nfunc:
+ self.covariance.append(cov_row)
+ # Sanity check: check the number of rows in the covariance
+ # matrix
+ if not len(self.covariance) == self.nfunc:
+ # Inconsistent dimensions of the covariance matrix.
+ # Don't keep the data.
+ err_msg = "InversionState.fromXML: "
+ err_msg += "inconsistant dimensions of the "
+ err_msg += " covariance matrix: "
+ err_msg += "%d %d" % (len(self.covariance), self.nfunc)
+ logger.error(err_msg)
+ self.covariance = None
+
+class Reader(CansasReader):
+ """
+ Class to load a .prv P(r) inversion file
+ """
+ ## File type
+ type_name = "P(r)"
+
+ ## Wildcards
+ type = ["P(r) files (*.prv)|*.prv",
+ "SASView files (*.svs)|*.svs"]
+ ## List of allowed extensions
+ ext = ['.prv', '.PRV', '.svs', '.SVS']
+
+ def __init__(self, call_back, cansas=True):
+ """
+ Initialize the call-back method to be called
+ after we load a file
+
+ :param call_back: call-back method
+ :param cansas: True = files will be written/read in CanSAS format
+ False = write CanSAS format
+
+ """
+ ## Call back method to be executed after a file is read
+ self.call_back = call_back
+ ## CanSAS format flag
+ self.cansas = cansas
+ self.state = None
+
+ def read(self, path):
+ """
+ Load a new P(r) inversion state from file
+
+ :param path: file path
+
+ :return: None
+
+ """
+ if self.cansas == True:
+ return self._read_cansas(path)
+ else:
+ return self._read_standalone(path)
+
+ def _read_standalone(self, path):
+ """
+ Load a new P(r) inversion state from file.
+ The P(r) node is assumed to be the top element.
+
+ :param path: file path
+
+ :return: None
+
+ """
+ # Read the new state from file
+ state = InversionState()
+ state.fromXML(file=path)
+
+ # Call back to post the new state
+ self.state = state
+ #self.call_back(state)
+ return None
+
+ def _parse_prstate(self, entry):
+ """
+ Read a p(r) inversion result from an XML node
+
+ :param entry: XML node to read from
+
+ :return: InversionState object
+
+ """
+ state = None
+
+ # Locate the P(r) node
+ try:
+ nodes = entry.xpath('ns:%s' % PRNODE_NAME,
+ namespaces={'ns': CANSAS_NS})
+ if nodes != []:
+ # Create an empty state
+ state = InversionState()
+ state.fromXML(node=nodes[0])
+ except:
+ msg = "XML document does not contain P(r) "
+ msg += "information.\n %s" % sys.exc_value
+ logger.info(msg)
+
+ return state
+
+ def _read_cansas(self, path):
+ """
+ Load data and P(r) information from a CanSAS XML file.
+
+ :param path: file path
+
+ :return: Data1D object if a single SASentry was found,
+ or a list of Data1D objects if multiple entries were found,
+ or None of nothing was found
+
+ :raise RuntimeError: when the file can't be opened
+ :raise ValueError: when the length of the data vectors are inconsistent
+
+ """
+ output = []
+
+ if os.path.isfile(path):
+ basename = os.path.basename(path)
+ root, extension = os.path.splitext(basename)
+ #TODO: eventually remove the check for .xml once
+ # the P(r) writer/reader is truly complete.
+ if extension.lower() in self.ext or extension.lower() == '.xml':
+
+ tree = etree.parse(path, parser=etree.ETCompatXMLParser())
+ # Check the format version number
+ # Specifying the namespace will take care of the file
+ #format version
+ root = tree.getroot()
+
+ entry_list = root.xpath('/ns:SASroot/ns:SASentry',
+ namespaces={'ns': CANSAS_NS})
+
+ for entry in entry_list:
+ prstate = self._parse_prstate(entry)
+ #prstate could be None when .svs file is loaded
+ #in this case, skip appending to output
+ if prstate is not None:
+ sas_entry, _ = self._parse_entry(entry)
+ sas_entry.meta_data['prstate'] = prstate
+ sas_entry.filename = prstate.file
+ output.append(sas_entry)
+ else:
+ raise RuntimeError, "%s is not a file" % path
+
+ # Return output consistent with the loader's api
+ if len(output) == 0:
+ return None
+ elif len(output) == 1:
+ # Call back to post the new state
+ self.call_back(output[0].meta_data['prstate'], datainfo=output[0])
+ #self.state = output[0].meta_data['prstate']
+ return output[0]
+ else:
+ return output
+
+
+ def write(self, filename, datainfo=None, prstate=None):
+ """
+ Write the content of a Data1D as a CanSAS XML file
+
+ :param filename: name of the file to write
+ :param datainfo: Data1D object
+ :param prstate: InversionState object
+
+ """
+ # Sanity check
+ if self.cansas == True:
+ doc = self.write_toXML(datainfo, prstate)
+ # Write the XML document
+ fd = open(filename, 'w')
+ fd.write(doc.toprettyxml())
+ fd.close()
+ else:
+ prstate.toXML(file=filename)
+
+ def write_toXML(self, datainfo=None, state=None):
+ """
+ Write toXML, a helper for write()
+
+ : return: xml doc
+ """
+ if datainfo is None:
+ datainfo = Data1D(x=[], y=[])
+ elif not issubclass(datainfo.__class__, Data1D):
+ msg = "The cansas writer expects a Data1D "
+ msg += "instance: %s" % str(datainfo.__class__.__name__)
+ raise RuntimeError, msg
+
+ # Create basic XML document
+ doc, sasentry = self._to_xml_doc(datainfo)
+
+ # Add the invariant information to the XML document
+ if state is not None:
+ doc = state.toXML(doc=doc, entry_node=sasentry)
+
+ return doc
diff --git a/src/sas/sasgui/perspectives/pr/media/pr_help.rst b/src/sas/sasgui/perspectives/pr/media/pr_help.rst
index e355f54..d3d2c02 100644
--- a/src/sas/sasgui/perspectives/pr/media/pr_help.rst
+++ b/src/sas/sasgui/perspectives/pr/media/pr_help.rst
@@ -48,8 +48,10 @@ The user must enter
P(r) inversion requires that the background be perfectly subtracted. This is
often difficult to do well and thus many data sets will include a background.
-For those cases, the user should check the "estimate background" box and the
-module will do its best to estimate it.
+For those cases, the user should check the "Estimate background level" option
+and the module will do its best to estimate it. If you know the background value
+for your data, select the "Input manual background level" option. Note that
+this value will be treated as having 0 error.
The P(r) module is constantly computing in the background what the optimum
*number of terms* should be as well as the optimum *regularization constant*.
diff --git a/src/sas/sasgui/perspectives/pr/pr.py b/src/sas/sasgui/perspectives/pr/pr.py
index 3ff74d6..c519b58 100644
--- a/src/sas/sasgui/perspectives/pr/pr.py
+++ b/src/sas/sasgui/perspectives/pr/pr.py
@@ -1,1316 +1,1324 @@
-"""
- P(r) perspective for SasView
-"""
-################################################################################
-#This software was developed by the University of Tennessee as part of the
-#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
-#project funded by the US National Science Foundation.
-#
-#See the license text in license.txt
-#
-#copyright 2009, University of Tennessee
-################################################################################
-
-
-# Make sure the option of saving each curve is available
-# Use the I(q) curve as input and compare the output to P(r)
-
-import sys
-import wx
-import logging
-import time
-import math
-import numpy
-import pylab
-from sas.sasgui.guiframe.gui_manager import MDIFrame
-from sas.sasgui.guiframe.dataFitting import Data1D
-from sas.sasgui.guiframe.events import NewPlotEvent
-from sas.sasgui.guiframe.events import StatusEvent
-from sas.sasgui.guiframe.gui_style import GUIFRAME_ID
-from sas.sascalc.pr.invertor import Invertor
-from sas.sascalc.dataloader.loader import Loader
-import sas.sascalc.dataloader
-
-from pr_widgets import load_error
-from sas.sasgui.guiframe.plugin_base import PluginBase
-
-
-PR_FIT_LABEL = r"$P_{fit}(r)$"
-PR_LOADED_LABEL = r"$P_{loaded}(r)$"
-IQ_DATA_LABEL = r"$I_{obs}(q)$"
-IQ_FIT_LABEL = r"$I_{fit}(q)$"
-IQ_SMEARED_LABEL = r"$I_{smeared}(q)$"
-GROUP_ID_IQ_DATA = r"$I_{obs}(q)$"
-GROUP_ID_PR_FIT = r"$P_{fit}(r)$"
-
-
-
-class Plugin(PluginBase):
- """
- P(r) inversion perspective
- """
- DEFAULT_ALPHA = 0.0001
- DEFAULT_NFUNC = 10
- DEFAULT_DMAX = 140.0
-
- def __init__(self):
- PluginBase.__init__(self, name="Pr Inversion")
- ## Simulation window manager
- self.simview = None
-
- ## State data
- self.alpha = self.DEFAULT_ALPHA
- self.nfunc = self.DEFAULT_NFUNC
- self.max_length = self.DEFAULT_DMAX
- self.q_min = None
- self.q_max = None
- self.has_bck = False
- self.slit_height = 0
- self.slit_width = 0
- ## Remember last plottable processed
- self.last_data = ""
- self._current_file_data = None
- ## Time elapsed for last computation [sec]
- # Start with a good default
- self.elapsed = 0.022
- self.iq_data_shown = False
-
- ## Current invertor
- self.invertor = None
- self.pr = None
- self.data_id = IQ_DATA_LABEL
- # Copy of the last result in case we need to display it.
- self._last_pr = None
- self._last_out = None
- self._last_cov = None
- ## Calculation thread
- self.calc_thread = None
- ## Estimation thread
- self.estimation_thread = None
- ## Result panel
- self.control_panel = None
- ## Currently views plottable
- self.current_plottable = None
- ## Number of P(r) points to display on the output plot
- self._pr_npts = 51
- self._normalize_output = False
- self._scale_output_unity = False
-
- ## List of added P(r) plots
- self._added_plots = {}
- self._default_Iq = {}
- self.list_plot_id = []
-
- # Associate the inversion state reader with .prv files
- from inversion_state import Reader
-
- # Create a CanSAS/Pr reader
- self.state_reader = Reader(self.set_state)
- self._extensions = '.prv'
- l = Loader()
- l.associate_file_reader('.prv', self.state_reader)
- #l.associate_file_reader(".svs", self.state_reader)
-
- # Log startup
- logging.info("Pr(r) plug-in started")
-
- def delete_data(self, data_id):
- """
- delete the data association with prview
- """
- self.control_panel.clear_panel()
-
- def get_data(self):
- """
- Returns the current data
- """
- return self.current_plottable
-
- def set_state(self, state=None, datainfo=None):
- """
- Call-back method for the inversion state reader.
- This method is called when a .prv file is loaded.
-
- :param state: InversionState object
- :param datainfo: Data1D object [optional]
-
- """
- try:
- if datainfo.__class__.__name__ == 'list':
- if len(datainfo) >= 1:
- data = datainfo[0]
- else:
- data = None
- else:
- data = datainfo
- if data is None:
- msg = "Pr.set_state: datainfo parameter cannot "
- msg += "be None in standalone mode"
- raise RuntimeError, msg
-
- # Ensuring that plots are coordinated correctly
- t = time.localtime(data.meta_data['prstate'].timestamp)
- time_str = time.strftime("%b %d %H:%M", t)
-
- # Check that no time stamp is already appended
- max_char = data.meta_data['prstate'].file.find("[")
- if max_char < 0:
- max_char = len(data.meta_data['prstate'].file)
-
- datainfo.meta_data['prstate'].file = \
- data.meta_data['prstate'].file[0:max_char]\
- + ' [' + time_str + ']'
-
- data.filename = data.meta_data['prstate'].file
- # TODO:
- #remove this call when state save all information about the gui data
- # such as ID , Group_ID, etc...
- #make self.current_plottable = datainfo directly
- self.current_plottable = self.parent.create_gui_data(data, None)
- self.current_plottable.group_id = data.meta_data['prstate'].file
-
- # Make sure the user sees the P(r) panel after loading
- #self.parent.set_perspective(self.perspective)
- self.on_perspective(event=None)
- # Load the P(r) results
- #state = self.state_reader.get_state()
- data_dict = {self.current_plottable.id:self.current_plottable}
- self.parent.add_data(data_list=data_dict)
- wx.PostEvent(self.parent, NewPlotEvent(plot=self.current_plottable,
- title=self.current_plottable.title))
- self.control_panel.set_state(state)
- except:
- logging.error("prview.set_state: %s" % sys.exc_value)
-
-
- def help(self, evt):
- """
- Show a general help dialog.
-
- :TODO: replace the text with a nice image
-
- """
- from inversion_panel import HelpDialog
- dialog = HelpDialog(None, -1)
- if dialog.ShowModal() == wx.ID_OK:
- dialog.Destroy()
- else:
- dialog.Destroy()
-
- def _fit_pr(self, evt):
- """
- """
- # Generate P(r) for sphere
- radius = 60.0
- d_max = 2 * radius
-
- r = pylab.arange(0.01, d_max, d_max / 51.0)
- M = len(r)
- y = numpy.zeros(M)
- pr_err = numpy.zeros(M)
-
- total = 0.0
- for j in range(M):
- value = self.pr_theory(r[j], radius)
- total += value
- y[j] = value
- pr_err[j] = math.sqrt(y[j])
-
- y = y / total * d_max / len(r)
-
- # Perform fit
- pr = Invertor()
- pr.d_max = d_max
- pr.alpha = 0
- pr.x = r
- pr.y = y
- pr.err = pr_err
- out, cov = pr.pr_fit()
- for i in range(len(out)):
- print "%g +- %g" % (out[i], math.sqrt(cov[i][i]))
-
- # Show input P(r)
- title = "Pr"
- new_plot = Data1D(pr.x, pr.y, dy=pr.err)
- new_plot.name = "P_{obs}(r)"
- new_plot.xaxis("\\rm{r}", 'A')
- new_plot.yaxis("\\rm{P(r)} ", "cm^{-3}")
- new_plot.group_id = "P_{obs}(r)"
- new_plot.id = "P_{obs}(r)"
- new_plot.title = title
- self.parent.update_theory(data_id=self.data_id, theory=new_plot)
- wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title=title))
-
- # Show P(r) fit
- self.show_pr(out, pr)
-
- # Show I(q) fit
- q = pylab.arange(0.001, 0.1, 0.01 / 51.0)
- self.show_iq(out, pr, q)
-
- def show_shpere(self, x, radius=70.0, x_range=70.0):
- """
- """
- # Show P(r)
- y_true = numpy.zeros(len(x))
-
- sum_true = 0.0
- for i in range(len(x)):
- y_true[i] = self.pr_theory(x[i], radius)
- sum_true += y_true[i]
-
- y_true = y_true / sum_true * x_range / len(x)
-
- # Show the theory P(r)
- new_plot = Data1D(x, y_true)
- new_plot.symbol = GUIFRAME_ID.CURVE_SYMBOL_NUM
- new_plot.name = "P_{true}(r)"
- new_plot.xaxis("\\rm{r}", 'A')
- new_plot.yaxis("\\rm{P(r)} ", "cm^{-3}")
- new_plot.id = "P_{true}(r)"
- new_plot.group_id = "P_{true}(r)"
- self.parent.update_theory(data_id=self.data_id, theory=new_plot)
- #Put this call in plottables/guitools
- wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot,
- title="Sphere P(r)"))
-
- def get_npts(self):
- """
- Returns the number of points in the I(q) data
- """
- try:
- return len(self.pr.x)
- except:
- return 0
-
- def show_iq(self, out, pr, q=None):
- """
- Display computed I(q)
- """
- qtemp = pr.x
- if not q == None:
- qtemp = q
-
- # Make a plot
- maxq = -1
- for q_i in qtemp:
- if q_i > maxq:
- maxq = q_i
-
- minq = 0.001
-
- # Check for user min/max
- if not pr.q_min == None:
- minq = pr.q_min
- if not pr.q_max == None:
- maxq = pr.q_max
-
- x = pylab.arange(minq, maxq, maxq / 301.0)
- y = numpy.zeros(len(x))
- err = numpy.zeros(len(x))
- for i in range(len(x)):
- value = pr.iq(out, x[i])
- y[i] = value
- try:
- err[i] = math.sqrt(math.fabs(value))
- except:
- err[i] = 1.0
- print "Error getting error", value, x[i]
-
- new_plot = Data1D(x, y)
- new_plot.symbol = GUIFRAME_ID.CURVE_SYMBOL_NUM
- new_plot.name = IQ_FIT_LABEL
- new_plot.xaxis("\\rm{Q}", 'A^{-1}')
- new_plot.yaxis("\\rm{Intensity} ", "cm^{-1}")
- title = "I(q)"
- new_plot.title = title
-
- # If we have a group ID, use it
- if pr.info.has_key("plot_group_id"):
- new_plot.group_id = pr.info["plot_group_id"]
- new_plot.id = IQ_FIT_LABEL
- self.parent.update_theory(data_id=self.data_id, theory=new_plot)
-
- wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title=title))
-
- # If we have used slit smearing, plot the smeared I(q) too
- if pr.slit_width > 0 or pr.slit_height > 0:
- x = pylab.arange(minq, maxq, maxq / 301.0)
- y = numpy.zeros(len(x))
- err = numpy.zeros(len(x))
- for i in range(len(x)):
- value = pr.iq_smeared(out, x[i])
- y[i] = value
- try:
- err[i] = math.sqrt(math.fabs(value))
- except:
- err[i] = 1.0
- print "Error getting error", value, x[i]
-
- new_plot = Data1D(x, y)
- new_plot.symbol = GUIFRAME_ID.CURVE_SYMBOL_NUM
- new_plot.name = IQ_SMEARED_LABEL
- new_plot.xaxis("\\rm{Q}", 'A^{-1}')
- new_plot.yaxis("\\rm{Intensity} ", "cm^{-1}")
- # If we have a group ID, use it
- if pr.info.has_key("plot_group_id"):
- new_plot.group_id = pr.info["plot_group_id"]
- new_plot.id = IQ_SMEARED_LABEL
- new_plot.title = title
- self.parent.update_theory(data_id=self.data_id, theory=new_plot)
- wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title=title))
-
- def _on_pr_npts(self, evt):
- """
- Redisplay P(r) with a different number of points
- """
- from inversion_panel import PrDistDialog
- dialog = PrDistDialog(None, -1)
- dialog.set_content(self._pr_npts)
- if dialog.ShowModal() == wx.ID_OK:
- self._pr_npts = dialog.get_content()
- dialog.Destroy()
- self.show_pr(self._last_out, self._last_pr, self._last_cov)
- else:
- dialog.Destroy()
-
-
- def show_pr(self, out, pr, cov=None):
- """
- """
- # Show P(r)
- x = pylab.arange(0.0, pr.d_max, pr.d_max / self._pr_npts)
-
- y = numpy.zeros(len(x))
- dy = numpy.zeros(len(x))
- y_true = numpy.zeros(len(x))
-
- total = 0.0
- pmax = 0.0
- cov2 = numpy.ascontiguousarray(cov)
-
- for i in range(len(x)):
- if cov2 == None:
- value = pr.pr(out, x[i])
- else:
- (value, dy[i]) = pr.pr_err(out, cov2, x[i])
- total += value * pr.d_max / len(x)
-
- # keep track of the maximum P(r) value
- if value > pmax:
- pmax = value
-
- y[i] = value
-
- if self._normalize_output == True:
- y = y / total
- dy = dy / total
- elif self._scale_output_unity == True:
- y = y / pmax
- dy = dy / pmax
-
- if cov2 == None:
- new_plot = Data1D(x, y)
- new_plot.symbol = GUIFRAME_ID.CURVE_SYMBOL_NUM
- else:
- new_plot = Data1D(x, y, dy=dy)
- new_plot.name = PR_FIT_LABEL
- new_plot.xaxis("\\rm{r}", 'A')
- new_plot.yaxis("\\rm{P(r)} ", "cm^{-3}")
- new_plot.title = "P(r) fit"
- new_plot.id = PR_FIT_LABEL
- # Make sure that the plot is linear
- new_plot.xtransform = "x"
- new_plot.ytransform = "y"
- new_plot.group_id = GROUP_ID_PR_FIT
- self.parent.update_theory(data_id=self.data_id, theory=new_plot)
- wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title="P(r) fit"))
- return x, pr.d_max
-
- def load(self, data):
- """
- Load data. This will eventually be replaced
- by our standard DataLoader class.
- """
- class FileData(object):
- x = None
- y = None
- err = None
- path = None
-
- def __init__(self, path):
- self.path = path
-
- self._current_file_data = FileData(data.path)
-
- # Use data loader to load file
- dataread = data
- # Notify the user if we could not read the file
- if dataread is None:
- raise RuntimeError, "Invalid data"
-
- x = None
- y = None
- err = None
- if dataread.__class__.__name__ == 'Data1D':
- x = dataread.x
- y = dataread.y
- err = dataread.dy
- else:
- if isinstance(dataread, list) and len(dataread) > 0:
- x = dataread[0].x
- y = dataread[0].y
- err = dataread[0].dy
- msg = "PrView only allows a single data set at a time. "
- msg += "Only the first data set was loaded."
- wx.PostEvent(self.parent, StatusEvent(status=msg))
- else:
- if dataread is None:
- return x, y, err
- raise RuntimeError, "This tool can only read 1D data"
-
- self._current_file_data.x = x
- self._current_file_data.y = y
- self._current_file_data.err = err
- return x, y, err
-
- def load_columns(self, path="sphere_60_q0_2.txt"):
- """
- Load 2- or 3- column ascii
- """
- # Read the data from the data file
- data_x = numpy.zeros(0)
- data_y = numpy.zeros(0)
- data_err = numpy.zeros(0)
- scale = None
- min_err = 0.0
- if not path == None:
- input_f = open(path, 'r')
- buff = input_f.read()
- lines = buff.split('\n')
- for line in lines:
- try:
- toks = line.split()
- x = float(toks[0])
- y = float(toks[1])
- if len(toks) > 2:
- err = float(toks[2])
- else:
- if scale == None:
- scale = 0.05 * math.sqrt(y)
- #scale = 0.05/math.sqrt(y)
- min_err = 0.01 * y
- err = scale * math.sqrt(y) + min_err
- #err = 0
-
- data_x = numpy.append(data_x, x)
- data_y = numpy.append(data_y, y)
- data_err = numpy.append(data_err, err)
- except:
- logging.error(sys.exc_value)
-
- if not scale == None:
- message = "The loaded file had no error bars, statistical errors are assumed."
- wx.PostEvent(self.parent, StatusEvent(status=message))
- else:
- wx.PostEvent(self.parent, StatusEvent(status=''))
-
- return data_x, data_y, data_err
-
- def load_abs(self, path):
- """
- Load an IGOR .ABS reduced file
-
- :param path: file path
-
- :return: x, y, err vectors
-
- """
- # Read the data from the data file
- data_x = numpy.zeros(0)
- data_y = numpy.zeros(0)
- data_err = numpy.zeros(0)
- scale = None
- min_err = 0.0
-
- data_started = False
- if not path == None:
- input_f = open(path, 'r')
- buff = input_f.read()
- lines = buff.split('\n')
- for line in lines:
- if data_started == True:
- try:
- toks = line.split()
- x = float(toks[0])
- y = float(toks[1])
- if len(toks) > 2:
- err = float(toks[2])
- else:
- if scale == None:
- scale = 0.05 * math.sqrt(y)
- #scale = 0.05/math.sqrt(y)
- min_err = 0.01 * y
- err = scale * math.sqrt(y) + min_err
- #err = 0
-
- data_x = numpy.append(data_x, x)
- data_y = numpy.append(data_y, y)
- data_err = numpy.append(data_err, err)
- except:
- logging.error(sys.exc_value)
- elif line.find("The 6 columns") >= 0:
- data_started = True
-
- if not scale == None:
- message = "The loaded file had no error bars, statistical errors are assumed."
- wx.PostEvent(self.parent, StatusEvent(status=message))
- else:
- wx.PostEvent(self.parent, StatusEvent(status=''))
-
- return data_x, data_y, data_err
-
- def pr_theory(self, r, R):
- """
- Return P(r) of a sphere for a given R
- For test purposes
- """
- if r <= 2 * R:
- return 12.0 * ((0.5 * r / R) ** 2) * ((1.0 - 0.5 * r / R) ** 2) * (2.0 + 0.5 * r / R)
- else:
- return 0.0
-
- def get_context_menu(self, plotpanel=None):
- """
- Get the context menu items available for P(r)
-
- :param graph: the Graph object to which we attach the context menu
-
- :return: a list of menu items with call-back function
-
- """
- graph = plotpanel.graph
- # Look whether this Graph contains P(r) data
- if graph.selected_plottable not in plotpanel.plots:
- return []
- item = plotpanel.plots[graph.selected_plottable]
- if item.id == PR_FIT_LABEL:
- #add_data_hint = "Load a data file and display it on this plot"
- #["Add P(r) data",add_data_hint , self._on_add_data],
- change_n_hint = "Change the number of"
- change_n_hint += " points on the P(r) output"
- change_n_label = "Change number of P(r) points"
- m_list = [[change_n_label, change_n_hint, self._on_pr_npts]]
-
- if self._scale_output_unity or self._normalize_output:
- hint = "Let the output P(r) keep the scale of the data"
- m_list.append(["Disable P(r) scaling", hint,
- self._on_disable_scaling])
- if not self._scale_output_unity:
- m_list.append(["Scale P_max(r) to unity",
- "Scale P(r) so that its maximum is 1",
- self._on_scale_unity])
- if not self._normalize_output:
- m_list.append(["Normalize P(r) to unity",
- "Normalize the integral of P(r) to 1",
- self._on_normalize])
-
- return m_list
-
- elif item.id in [PR_LOADED_LABEL, IQ_DATA_LABEL, IQ_FIT_LABEL, IQ_SMEARED_LABEL]:
- return []
- elif item.id == graph.selected_plottable:
- if issubclass(item.__class__, Data1D):
- return [["Compute P(r)",
- "Compute P(r) from distribution",
- self._on_context_inversion]]
- return []
-
- def _on_disable_scaling(self, evt):
- """
- Disable P(r) scaling
-
- :param evt: Menu event
-
- """
- self._normalize_output = False
- self._scale_output_unity = False
- self.show_pr(self._last_out, self._last_pr, self._last_cov)
-
- # Now replot the original added data
- for plot in self._added_plots:
- self._added_plots[plot].y = numpy.copy(self._default_Iq[plot])
- wx.PostEvent(self.parent,
- NewPlotEvent(plot=self._added_plots[plot],
- title=self._added_plots[plot].name,
- update=True))
-
- # Need the update flag in the NewPlotEvent to protect against
- # the plot no longer being there...
-
- def _on_normalize(self, evt):
- """
- Normalize the area under the P(r) curve to 1.
- This operation is done for all displayed plots.
-
- :param evt: Menu event
-
- """
- self._normalize_output = True
- self._scale_output_unity = False
-
- self.show_pr(self._last_out, self._last_pr, self._last_cov)
-
- # Now scale the added plots too
- for plot in self._added_plots:
- total = numpy.sum(self._added_plots[plot].y)
- npts = len(self._added_plots[plot].x)
- total *= self._added_plots[plot].x[npts - 1] / npts
- y = self._added_plots[plot].y / total
-
- new_plot = Data1D(self._added_plots[plot].x, y)
- new_plot.symbol = GUIFRAME_ID.CURVE_SYMBOL_NUM
- new_plot.group_id = self._added_plots[plot].group_id
- new_plot.id = self._added_plots[plot].id
- new_plot.title = self._added_plots[plot].title
- new_plot.name = self._added_plots[plot].name
- new_plot.xaxis("\\rm{r}", 'A')
- new_plot.yaxis("\\rm{P(r)} ", "cm^{-3}")
- self.parent.update_theory(data_id=self.data_id, theory=new_plot)
- wx.PostEvent(self.parent,
- NewPlotEvent(plot=new_plot, update=True,
- title=self._added_plots[plot].name))
-
- def _on_scale_unity(self, evt):
- """
- Scale the maximum P(r) value on each displayed plot to 1.
-
- :param evt: Menu event
-
- """
- self._scale_output_unity = True
- self._normalize_output = False
-
- self.show_pr(self._last_out, self._last_pr, self._last_cov)
-
- # Now scale the added plots too
- for plot in self._added_plots:
- _max = 0
- for y in self._added_plots[plot].y:
- if y > _max:
- _max = y
- y = self._added_plots[plot].y / _max
-
- new_plot = Data1D(self._added_plots[plot].x, y)
- new_plot.symbol = GUIFRAME_ID.CURVE_SYMBOL_NUM
- new_plot.name = self._added_plots[plot].name
- new_plot.xaxis("\\rm{r}", 'A')
- new_plot.yaxis("\\rm{P(r)} ", "cm^{-3}")
- self.parent.update_theory(data_id=self.data_id, theory=new_plot)
- wx.PostEvent(self.parent,
- NewPlotEvent(plot=new_plot, update=True,
- title=self._added_plots[plot].name))
-
- def start_thread(self):
- """
- Start a calculation thread
- """
- from pr_thread import CalcPr
-
- # If a thread is already started, stop it
- if self.calc_thread != None and self.calc_thread.isrunning():
- self.calc_thread.stop()
- ## stop just raises the flag -- the thread is supposed to
- ## then kill itself. In August 2014 it was shown that this is
- ## incorrectly handled by fitting.py and a fix implemented.
- ## It is not clear whether it is properly used here, but the
- ## "fix" of waiting for the previous thread to end breaks the
- ## pr perspective completely as it causes an infinite loop.
- ## Thus it is likely the threading is bing properly handled.
- ## While the "fix" is no longer implemented the comment is
- ## left here till somebody ascertains that in fact the threads
- ## are being properly handled.
- ##
- ## -PDB January 25, 2015
-
- pr = self.pr.clone()
- self.calc_thread = CalcPr(pr, self.nfunc,
- error_func=self._thread_error,
- completefn=self._completed, updatefn=None)
- self.calc_thread.queue()
- self.calc_thread.ready(2.5)
-
- def _thread_error(self, error):
- """
- Call-back method for calculation errors
- """
- wx.PostEvent(self.parent, StatusEvent(status=error))
-
- def _estimate_completed(self, alpha, message, elapsed):
- """
- Parameter estimation completed,
- display the results to the user
-
- :param alpha: estimated best alpha
- :param elapsed: computation time
-
- """
- # Save useful info
- self.elapsed = elapsed
- self.control_panel.alpha_estimate = alpha
- if not message == None:
- wx.PostEvent(self.parent, StatusEvent(status=str(message)))
- self.perform_estimateNT()
-
- def _estimateNT_completed(self, nterms, alpha, message, elapsed):
- """
- Parameter estimation completed,
- display the results to the user
-
- :param alpha: estimated best alpha
- :param nterms: estimated number of terms
- :param elapsed: computation time
-
- """
- # Save useful info
- self.elapsed = elapsed
- self.control_panel.nterms_estimate = nterms
- self.control_panel.alpha_estimate = alpha
- if not message == None:
- wx.PostEvent(self.parent, StatusEvent(status=str(message)))
-
- def _completed(self, out, cov, pr, elapsed):
- """
- wxCallAfter Method called with the results when the inversion
- is done
-
- :param out: output coefficient for the base functions
- :param cov: covariance matrix
- :param pr: Invertor instance
- :param elapsed: time spent computing
- """
- # Ensure hat you have all inputs are ready at the time call happens:
- # Without CallAfter, it will freeze with wx >= 2.9.
- wx.CallAfter(self._completed_call, out, cov, pr, elapsed)
-
- def _completed_call(self, out, cov, pr, elapsed):
- """
- Method called with the results when the inversion
- is done
-
- :param out: output coefficient for the base functions
- :param cov: covariance matrix
- :param pr: Invertor instance
- :param elapsed: time spent computing
-
- """
- # Save useful info
- self.elapsed = elapsed
- # Keep a copy of the last result
- self._last_pr = pr.clone()
- self._last_out = out
- self._last_cov = cov
-
- # Save Pr invertor
- self.pr = pr
- cov = numpy.ascontiguousarray(cov)
-
- # Show result on control panel
- self.control_panel.chi2 = pr.chi2
- self.control_panel.elapsed = elapsed
- self.control_panel.oscillation = pr.oscillations(out)
- self.control_panel.positive = pr.get_positive(out)
- self.control_panel.pos_err = pr.get_pos_err(out, cov)
- self.control_panel.rg = pr.rg(out)
- self.control_panel.iq0 = pr.iq0(out)
- self.control_panel.bck = pr.background
-
- # Show I(q) fit
- self.show_iq(out, self.pr)
-
- # Show P(r) fit
- self.show_pr(out, self.pr, cov)
-
- def show_data(self, path=None, data=None, reset=False):
- """
- Show data read from a file
-
- :param path: file path
- :param reset: if True all other plottables will be cleared
-
- """
- #if path is not None:
- if data is not None:
- try:
- pr = self._create_file_pr(data)
- except:
- status = "Problem reading data: %s" % sys.exc_value
- wx.PostEvent(self.parent, StatusEvent(status=status))
- raise RuntimeError, status
-
- # If the file contains nothing, just return
- if pr is None:
- raise RuntimeError, "Loaded data is invalid"
-
- self.pr = pr
-
- # Make a plot of I(q) data
- if self.pr.err == None:
- new_plot = Data1D(self.pr.x, self.pr.y)
- new_plot.symbol = GUIFRAME_ID.CURVE_SYMBOL_NUM
- else:
- new_plot = Data1D(self.pr.x, self.pr.y, dy=self.pr.err)
- new_plot.name = IQ_DATA_LABEL
- new_plot.xaxis("\\rm{Q}", 'A^{-1}')
- new_plot.yaxis("\\rm{Intensity} ", "cm^{-1}")
- new_plot.interactive = True
- new_plot.group_id = GROUP_ID_IQ_DATA
- new_plot.id = self.data_id
- new_plot.title = "I(q)"
- wx.PostEvent(self.parent,
- NewPlotEvent(plot=new_plot, title="I(q)", reset=reset))
-
- self.current_plottable = new_plot
- # Get Q range
- self.control_panel.q_min = min(self.pr.x)
- self.control_panel.q_max = max(self.pr.x)
-
- def save_data(self, filepath, prstate=None):
- """
- Save data in provided state object.
-
- :TODO: move the state code away from inversion_panel and move it here.
- Then remove the "prstate" input and make this method private.
-
- :param filepath: path of file to write to
- :param prstate: P(r) inversion state
-
- """
- #TODO: do we need this or can we use DataLoader.loader.save directly?
-
- # Add output data and coefficients to state
- prstate.coefficients = self._last_out
- prstate.covariance = self._last_cov
-
- # Write the output to file
- # First, check that the data is of the right type
- if issubclass(self.current_plottable.__class__,
- sas.sascalc.dataloader.data_info.Data1D):
- self.state_reader.write(filepath, self.current_plottable, prstate)
- else:
- msg = "pr.save_data: the data being saved is not a"
- msg += " sas.data_info.Data1D object"
- raise RuntimeError, msg
-
- def setup_plot_inversion(self, alpha, nfunc, d_max, q_min=None, q_max=None,
- bck=False, height=0, width=0):
- """
- Set up inversion from plotted data
- """
- self.alpha = alpha
- self.nfunc = nfunc
- self.max_length = d_max
- self.q_min = q_min
- self.q_max = q_max
- self.has_bck = bck
- self.slit_height = height
- self.slit_width = width
-
- try:
- pr = self._create_plot_pr()
- if not pr == None:
- self.pr = pr
- self.perform_inversion()
- except:
- wx.PostEvent(self.parent, StatusEvent(status=sys.exc_value))
-
- def estimate_plot_inversion(self, alpha, nfunc, d_max,
- q_min=None, q_max=None,
- bck=False, height=0, width=0):
- """
- Estimate parameters from plotted data
- """
- self.alpha = alpha
- self.nfunc = nfunc
- self.max_length = d_max
- self.q_min = q_min
- self.q_max = q_max
- self.has_bck = bck
- self.slit_height = height
- self.slit_width = width
-
- try:
- pr = self._create_plot_pr()
- if not pr == None:
- self.pr = pr
- self.perform_estimate()
- except:
- wx.PostEvent(self.parent, StatusEvent(status=sys.exc_value))
-
- def _create_plot_pr(self, estimate=False):
- """
- Create and prepare invertor instance from
- a plottable data set.
-
- :param path: path of the file to read in
-
- """
- # Sanity check
- if self.current_plottable is None:
- msg = "Please load a valid data set before proceeding."
- wx.PostEvent(self.parent, StatusEvent(status=msg))
- return None
-
- # Get the data from the chosen data set and perform inversion
- pr = Invertor()
- pr.d_max = self.max_length
- pr.alpha = self.alpha
- pr.q_min = self.q_min
- pr.q_max = self.q_max
- pr.x = self.current_plottable.x
- pr.y = self.current_plottable.y
- pr.has_bck = self.has_bck
- pr.slit_height = self.slit_height
- pr.slit_width = self.slit_width
-
- # Keep track of the plot window title to ensure that
- # we can overlay the plots
- pr.info["plot_group_id"] = self.current_plottable.group_id
-
- # Fill in errors if none were provided
- err = self.current_plottable.dy
- all_zeros = True
- if err == None:
- err = numpy.zeros(len(pr.y))
- else:
- for i in range(len(err)):
- if err[i] > 0:
- all_zeros = False
-
- if all_zeros:
- scale = None
- min_err = 0.0
- for i in range(len(pr.y)):
- # Scale the error so that we can fit over several decades of Q
- if scale == None:
- scale = 0.05 * math.sqrt(pr.y[i])
- min_err = 0.01 * pr.y[i]
- err[i] = scale * math.sqrt(math.fabs(pr.y[i])) + min_err
- message = "The loaded file had no error bars, "
- message += "statistical errors are assumed."
- wx.PostEvent(self.parent, StatusEvent(status=message))
-
- pr.err = err
-
- return pr
-
- def setup_file_inversion(self, alpha, nfunc, d_max, data,
- path=None, q_min=None, q_max=None,
- bck=False, height=0, width=0):
- """
- Set up inversion
- """
- self.alpha = alpha
- self.nfunc = nfunc
- self.max_length = d_max
- self.q_min = q_min
- self.q_max = q_max
- self.has_bck = bck
- self.slit_height = height
- self.slit_width = width
-
- try:
- pr = self._create_file_pr(data)
- if not pr == None:
- self.pr = pr
- self.perform_inversion()
- except:
- wx.PostEvent(self.parent, StatusEvent(status=sys.exc_value))
-
- def estimate_file_inversion(self, alpha, nfunc, d_max, data,
- path=None, q_min=None, q_max=None,
- bck=False, height=0, width=0):
- """
- Estimate parameters for inversion
- """
- self.alpha = alpha
- self.nfunc = nfunc
- self.max_length = d_max
- self.q_min = q_min
- self.q_max = q_max
- self.has_bck = bck
- self.slit_height = height
- self.slit_width = width
-
- try:
- pr = self._create_file_pr(data)
- if not pr is None:
- self.pr = pr
- self.perform_estimate()
- except:
- wx.PostEvent(self.parent, StatusEvent(status=sys.exc_value))
-
- def _create_file_pr(self, data):
- """
- Create and prepare invertor instance from
- a file data set.
-
- :param path: path of the file to read in
-
- """
- # Reset the status bar so that we don't get mixed up
- # with old messages.
- #TODO: refactor this into a proper status handling
- wx.PostEvent(self.parent, StatusEvent(status=''))
- try:
- class FileData(object):
- x = None
- y = None
- err = None
- path = None
- def __init__(self, path):
- self.path = path
-
- self._current_file_data = FileData(data.path)
- self._current_file_data.x = data.x
- self._current_file_data.y = data.y
- self._current_file_data.err = data.dy
- x, y, err = data.x, data.y, data.dy
- except:
- load_error(sys.exc_value)
- return None
-
- # If the file contains no data, just return
- if x is None or len(x) == 0:
- load_error("The loaded file contains no data")
- return None
-
- # If we have not errors, add statistical errors
- if y is not None:
- if err == None or numpy.all(err) == 0:
- err = numpy.zeros(len(y))
- scale = None
- min_err = 0.0
- for i in range(len(y)):
- # Scale the error so that we can fit over several decades of Q
- if scale == None:
- scale = 0.05 * math.sqrt(y[i])
- min_err = 0.01 * y[i]
- err[i] = scale * math.sqrt(math.fabs(y[i])) + min_err
- message = "The loaded file had no error bars, "
- message += "statistical errors are assumed."
- wx.PostEvent(self.parent, StatusEvent(status=message))
-
- try:
- # Get the data from the chosen data set and perform inversion
- pr = Invertor()
- pr.d_max = self.max_length
- pr.alpha = self.alpha
- pr.q_min = self.q_min
- pr.q_max = self.q_max
- pr.x = x
- pr.y = y
- pr.err = err
- pr.has_bck = self.has_bck
- pr.slit_height = self.slit_height
- pr.slit_width = self.slit_width
- return pr
- except:
- load_error(sys.exc_value)
- return None
-
- def perform_estimate(self):
- """
- Perform parameter estimation
- """
- from pr_thread import EstimatePr
-
- # If a thread is already started, stop it
- if self.estimation_thread != None and \
- self.estimation_thread.isrunning():
- self.estimation_thread.stop()
- ## stop just raises the flag -- the thread is supposed to
- ## then kill itself. In August 2014 it was shown that this is
- ## incorrectly handled by fitting.py and a fix implemented.
- ## It is not clear whether it is properly used here, but the
- ## "fix" of waiting for the previous thread to end breaks the
- ## pr perspective completely as it causes an infinite loop.
- ## Thus it is likely the threading is bing properly handled.
- ## While the "fix" is no longer implemented the comment is
- ## left here till somebody ascertains that in fact the threads
- ## are being properly handled.
- ##
- ## -PDB January 25, 2015
- pr = self.pr.clone()
- self.estimation_thread = EstimatePr(pr, self.nfunc,
- error_func=self._thread_error,
- completefn=self._estimate_completed,
- updatefn=None)
- self.estimation_thread.queue()
- self.estimation_thread.ready(2.5)
-
- def perform_estimateNT(self):
- """
- Perform parameter estimation
- """
- from pr_thread import EstimateNT
-
- # If a thread is already started, stop it
- if self.estimation_thread != None and self.estimation_thread.isrunning():
- self.estimation_thread.stop()
- ## stop just raises the flag -- the thread is supposed to
- ## then kill itself. In August 2014 it was shown that this is
- ## incorrectly handled by fitting.py and a fix implemented.
- ## It is not clear whether it is properly used here, but the
- ## "fix" of waiting for the previous thread to end breaks the
- ## pr perspective completely as it causes an infinite loop.
- ## Thus it is likely the threading is bing properly handled.
- ## While the "fix" is no longer implemented the comment is
- ## left here till somebody ascertains that in fact the threads
- ## are being properly handled.
- ##
- ## -PDB January 25, 2015
- pr = self.pr.clone()
- # Skip the slit settings for the estimation
- # It slows down the application and it doesn't change the estimates
- pr.slit_height = 0.0
- pr.slit_width = 0.0
- self.estimation_thread = EstimateNT(pr, self.nfunc,
- error_func=self._thread_error,
- completefn=self._estimateNT_completed,
- updatefn=None)
- self.estimation_thread.queue()
- self.estimation_thread.ready(2.5)
-
- def perform_inversion(self):
- """
- Perform inversion
- """
- self.start_thread()
-
- def _on_context_inversion(self, event):
- """
- Call-back method for plot context menu
- """
- panel = event.GetEventObject()
- Plugin.on_perspective(self, event=event)
-
- # If we have more than one displayed plot, make the user choose
- if len(panel.plots) >= 1 and \
- panel.graph.selected_plottable in panel.plots:
- dataset = panel.plots[panel.graph.selected_plottable].name
- else:
- logging.info("Prview Error: No data is available")
- return
-
- # Store a reference to the current plottable
- # If we have a suggested value, use it.
- try:
- estimate = float(self.control_panel.alpha_estimate)
- self.control_panel.alpha = estimate
- except:
- self.control_panel.alpha = self.alpha
- logging.info("Prview :Alpha Not estimate yet")
- try:
- estimate = int(self.control_panel.nterms_estimate)
- self.control_panel.nfunc = estimate
- except:
- self.control_panel.nfunc = self.nfunc
- logging.info("Prview : ntemrs Not estimate yet")
-
- self.current_plottable = panel.plots[panel.graph.selected_plottable]
- self.set_data([self.current_plottable])
- self.control_panel.plotname = dataset
- #self.control_panel.nfunc = self.nfunc
- self.control_panel.d_max = self.max_length
- #self.parent.set_perspective(self.perspective)
- self.control_panel._on_invert(None)
-
- def get_panels(self, parent):
- """
- Create and return a list of panel objects
- """
- from inversion_panel import InversionControl
-
- self.parent = parent
- self.frame = MDIFrame(self.parent, None, 'None', (100, 200))
- self.control_panel = InversionControl(self.frame, -1,
- style=wx.RAISED_BORDER)
- self.frame.set_panel(self.control_panel)
- self._frame_set_helper()
- self.control_panel.set_manager(self)
- self.control_panel.nfunc = self.nfunc
- self.control_panel.d_max = self.max_length
- self.control_panel.alpha = self.alpha
- self.perspective = []
- self.perspective.append(self.control_panel.window_name)
-
- return [self.control_panel]
-
- def set_data(self, data_list=None):
- """
- receive a list of data to compute pr
- """
- if data_list is None:
- data_list = []
- if len(data_list) >= 1:
- if len(data_list) == 1:
- data = data_list[0]
- else:
- data_1d_list = []
- data_2d_list = []
- error_msg = ""
- # separate data into data1d and data2d list
- for data in data_list:
- if data is not None:
- if issubclass(data.__class__, Data1D):
- data_1d_list.append(data)
- else:
- error_msg += " %s type %s \n" % (str(data.name),
- str(data.__class__.__name__))
- data_2d_list.append(data)
- if len(data_2d_list) > 0:
- msg = "PrView does not support the following data types:\n"
- msg += error_msg
- if len(data_1d_list) == 0:
- wx.PostEvent(self.parent, StatusEvent(status=msg, info='error'))
- return
- msg = "Prview does not allow multiple data!\n"
- msg += "Please select one.\n"
- if len(data_list) > 1:
- from pr_widgets import DataDialog
- dlg = DataDialog(data_list=data_1d_list, text=msg)
- if dlg.ShowModal() == wx.ID_OK:
- data = dlg.get_data()
- else:
- data = None
- dlg.Destroy()
- if data is None:
- msg += "PrView receives no data. \n"
- wx.PostEvent(self.parent, StatusEvent(status=msg, info='error'))
- return
- if issubclass(data.__class__, Data1D):
- try:
- wx.PostEvent(self.parent,
- NewPlotEvent(action='remove',
- group_id=GROUP_ID_IQ_DATA,
- id=self.data_id))
- self.data_id = data.id
- self.control_panel._change_file(evt=None, data=data)
- except:
- msg = "Prview Set_data: " + str(sys.exc_value)
- wx.PostEvent(self.parent, StatusEvent(status=msg, info="error"))
- else:
- msg = "Pr cannot be computed for data of "
- msg += "type %s" % (data_list[0].__class__.__name__)
- wx.PostEvent(self.parent, StatusEvent(status=msg, info='error'))
- else:
- msg = "Pr contain no data"
- wx.PostEvent(self.parent, StatusEvent(status=msg, info='warning'))
-
- def post_init(self):
- """
- Post initialization call back to close the loose ends
- [Somehow openGL needs this call]
- """
- pass
+"""
+ P(r) perspective for SasView
+"""
+################################################################################
+#This software was developed by the University of Tennessee as part of the
+#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
+#project funded by the US National Science Foundation.
+#
+#See the license text in license.txt
+#
+#copyright 2009, University of Tennessee
+################################################################################
+
+
+# Make sure the option of saving each curve is available
+# Use the I(q) curve as input and compare the output to P(r)
+from __future__ import print_function
+
+import sys
+import wx
+import logging
+import time
+import math
+import numpy as np
+import pylab
+from sas.sasgui.guiframe.gui_manager import MDIFrame
+from sas.sasgui.guiframe.dataFitting import Data1D
+from sas.sasgui.guiframe.events import NewPlotEvent
+from sas.sasgui.guiframe.events import StatusEvent
+from sas.sasgui.guiframe.gui_style import GUIFRAME_ID
+from sas.sascalc.pr.invertor import Invertor
+from sas.sascalc.dataloader.loader import Loader
+import sas.sascalc.dataloader
+
+from pr_widgets import load_error
+from sas.sasgui.guiframe.plugin_base import PluginBase
+
+logger = logging.getLogger(__name__)
+
+
+PR_FIT_LABEL = r"$P_{fit}(r)$"
+PR_LOADED_LABEL = r"$P_{loaded}(r)$"
+IQ_DATA_LABEL = r"$I_{obs}(q)$"
+IQ_FIT_LABEL = r"$I_{fit}(q)$"
+IQ_SMEARED_LABEL = r"$I_{smeared}(q)$"
+GROUP_ID_IQ_DATA = r"$I_{obs}(q)$"
+GROUP_ID_PR_FIT = r"$P_{fit}(r)$"
+
+
+
+class Plugin(PluginBase):
+ """
+ P(r) inversion perspective
+ """
+ DEFAULT_ALPHA = 0.0001
+ DEFAULT_NFUNC = 10
+ DEFAULT_DMAX = 140.0
+
+ def __init__(self):
+ PluginBase.__init__(self, name="Pr Inversion")
+ ## Simulation window manager
+ self.simview = None
+
+ ## State data
+ self.alpha = self.DEFAULT_ALPHA
+ self.nfunc = self.DEFAULT_NFUNC
+ self.max_length = self.DEFAULT_DMAX
+ self.q_min = None
+ self.q_max = None
+ self.est_bck = False
+ self.bck_val = 0
+ self.slit_height = 0
+ self.slit_width = 0
+ ## Remember last plottable processed
+ self.last_data = ""
+ self._current_file_data = None
+ ## Time elapsed for last computation [sec]
+ # Start with a good default
+ self.elapsed = 0.022
+ self.iq_data_shown = False
+
+ ## Current invertor
+ self.invertor = None
+ self.pr = None
+ self.data_id = IQ_DATA_LABEL
+ # Copy of the last result in case we need to display it.
+ self._last_pr = None
+ self._last_out = None
+ self._last_cov = None
+ ## Calculation thread
+ self.calc_thread = None
+ ## Estimation thread
+ self.estimation_thread = None
+ ## Result panel
+ self.control_panel = None
+ ## Currently views plottable
+ self.current_plottable = None
+ ## Number of P(r) points to display on the output plot
+ self._pr_npts = 51
+ self._normalize_output = False
+ self._scale_output_unity = False
+
+ ## List of added P(r) plots
+ self._added_plots = {}
+ self._default_Iq = {}
+ self.list_plot_id = []
+
+ # Associate the inversion state reader with .prv files
+ from inversion_state import Reader
+
+ # Create a CanSAS/Pr reader
+ self.state_reader = Reader(self.set_state)
+ self._extensions = '.prv'
+ l = Loader()
+ l.associate_file_reader('.prv', self.state_reader)
+ #l.associate_file_reader(".svs", self.state_reader)
+
+ # Log startup
+ logger.info("Pr(r) plug-in started")
+
+ def delete_data(self, data_id):
+ """
+ delete the data association with prview
+ """
+ self.control_panel.clear_panel()
+
+ def get_data(self):
+ """
+ Returns the current data
+ """
+ return self.current_plottable
+
+ def set_state(self, state=None, datainfo=None):
+ """
+ Call-back method for the inversion state reader.
+ This method is called when a .prv file is loaded.
+
+ :param state: InversionState object
+ :param datainfo: Data1D object [optional]
+
+ """
+ try:
+ if datainfo.__class__.__name__ == 'list':
+ if len(datainfo) >= 1:
+ data = datainfo[0]
+ else:
+ data = None
+ else:
+ data = datainfo
+ if data is None:
+ msg = "Pr.set_state: datainfo parameter cannot "
+ msg += "be None in standalone mode"
+ raise RuntimeError, msg
+
+ # Ensuring that plots are coordinated correctly
+ t = time.localtime(data.meta_data['prstate'].timestamp)
+ time_str = time.strftime("%b %d %H:%M", t)
+
+ # Check that no time stamp is already appended
+ max_char = data.meta_data['prstate'].file.find("[")
+ if max_char < 0:
+ max_char = len(data.meta_data['prstate'].file)
+
+ datainfo.meta_data['prstate'].file = \
+ data.meta_data['prstate'].file[0:max_char]\
+ + ' [' + time_str + ']'
+
+ data.filename = data.meta_data['prstate'].file
+ # TODO:
+ #remove this call when state save all information about the gui data
+ # such as ID , Group_ID, etc...
+ #make self.current_plottable = datainfo directly
+ self.current_plottable = self.parent.create_gui_data(data, None)
+ self.current_plottable.group_id = data.meta_data['prstate'].file
+
+ # Make sure the user sees the P(r) panel after loading
+ #self.parent.set_perspective(self.perspective)
+ self.on_perspective(event=None)
+ # Load the P(r) results
+ #state = self.state_reader.get_state()
+ data_dict = {self.current_plottable.id:self.current_plottable}
+ self.parent.add_data(data_list=data_dict)
+ wx.PostEvent(self.parent, NewPlotEvent(plot=self.current_plottable,
+ title=self.current_plottable.title))
+ self.control_panel.set_state(state)
+ except:
+ logger.error("prview.set_state: %s" % sys.exc_value)
+
+
+ def help(self, evt):
+ """
+ Show a general help dialog.
+
+ :TODO: replace the text with a nice image
+
+ """
+ from inversion_panel import HelpDialog
+ dialog = HelpDialog(None, -1)
+ if dialog.ShowModal() == wx.ID_OK:
+ dialog.Destroy()
+ else:
+ dialog.Destroy()
+
+ def _fit_pr(self, evt):
+ """
+ """
+ # Generate P(r) for sphere
+ radius = 60.0
+ d_max = 2 * radius
+
+ r = pylab.arange(0.01, d_max, d_max / 51.0)
+ M = len(r)
+ y = np.zeros(M)
+ pr_err = np.zeros(M)
+
+ total = 0.0
+ for j in range(M):
+ value = self.pr_theory(r[j], radius)
+ total += value
+ y[j] = value
+ pr_err[j] = math.sqrt(y[j])
+
+ y = y / total * d_max / len(r)
+
+ # Perform fit
+ pr = Invertor()
+ pr.d_max = d_max
+ pr.alpha = 0
+ pr.x = r
+ pr.y = y
+ pr.err = pr_err
+ out, cov = pr.pr_fit()
+ for i in range(len(out)):
+ print("%g +- %g" % (out[i], math.sqrt(cov[i][i])))
+
+ # Show input P(r)
+ title = "Pr"
+ new_plot = Data1D(pr.x, pr.y, dy=pr.err)
+ new_plot.name = "P_{obs}(r)"
+ new_plot.xaxis("\\rm{r}", 'A')
+ new_plot.yaxis("\\rm{P(r)} ", "cm^{-3}")
+ new_plot.group_id = "P_{obs}(r)"
+ new_plot.id = "P_{obs}(r)"
+ new_plot.title = title
+ self.parent.update_theory(data_id=self.data_id, theory=new_plot)
+ wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title=title))
+
+ # Show P(r) fit
+ self.show_pr(out, pr)
+
+ # Show I(q) fit
+ q = pylab.arange(0.001, 0.1, 0.01 / 51.0)
+ self.show_iq(out, pr, q)
+
+ def show_shpere(self, x, radius=70.0, x_range=70.0):
+ """
+ """
+ # Show P(r)
+ y_true = np.zeros(len(x))
+
+ sum_true = 0.0
+ for i in range(len(x)):
+ y_true[i] = self.pr_theory(x[i], radius)
+ sum_true += y_true[i]
+
+ y_true = y_true / sum_true * x_range / len(x)
+
+ # Show the theory P(r)
+ new_plot = Data1D(x, y_true)
+ new_plot.symbol = GUIFRAME_ID.CURVE_SYMBOL_NUM
+ new_plot.name = "P_{true}(r)"
+ new_plot.xaxis("\\rm{r}", 'A')
+ new_plot.yaxis("\\rm{P(r)} ", "cm^{-3}")
+ new_plot.id = "P_{true}(r)"
+ new_plot.group_id = "P_{true}(r)"
+ self.parent.update_theory(data_id=self.data_id, theory=new_plot)
+ #Put this call in plottables/guitools
+ wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot,
+ title="Sphere P(r)"))
+
+ def get_npts(self):
+ """
+ Returns the number of points in the I(q) data
+ """
+ try:
+ return len(self.pr.x)
+ except:
+ return 0
+
+ def show_iq(self, out, pr, q=None):
+ """
+ Display computed I(q)
+ """
+ qtemp = pr.x
+ if q is not None:
+ qtemp = q
+
+ # Make a plot
+ maxq = -1
+ for q_i in qtemp:
+ if q_i > maxq:
+ maxq = q_i
+
+ minq = 0.001
+
+ # Check for user min/max
+ if pr.q_min is not None:
+ minq = pr.q_min
+ if pr.q_max is not None:
+ maxq = pr.q_max
+
+ x = pylab.arange(minq, maxq, maxq / 301.0)
+ y = np.zeros(len(x))
+ err = np.zeros(len(x))
+ for i in range(len(x)):
+ value = pr.iq(out, x[i])
+ y[i] = value
+ try:
+ err[i] = math.sqrt(math.fabs(value))
+ except:
+ err[i] = 1.0
+ print("Error getting error", value, x[i])
+
+ new_plot = Data1D(x, y)
+ new_plot.symbol = GUIFRAME_ID.CURVE_SYMBOL_NUM
+ new_plot.name = IQ_FIT_LABEL
+ new_plot.xaxis("\\rm{Q}", 'A^{-1}')
+ new_plot.yaxis("\\rm{Intensity} ", "cm^{-1}")
+ title = "I(q)"
+ new_plot.title = title
+
+ # If we have a group ID, use it
+ if 'plot_group_id' in pr.info:
+ new_plot.group_id = pr.info["plot_group_id"]
+ new_plot.id = IQ_FIT_LABEL
+ self.parent.update_theory(data_id=self.data_id, theory=new_plot)
+
+ wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title=title))
+
+ # If we have used slit smearing, plot the smeared I(q) too
+ if pr.slit_width > 0 or pr.slit_height > 0:
+ x = pylab.arange(minq, maxq, maxq / 301.0)
+ y = np.zeros(len(x))
+ err = np.zeros(len(x))
+ for i in range(len(x)):
+ value = pr.iq_smeared(out, x[i])
+ y[i] = value
+ try:
+ err[i] = math.sqrt(math.fabs(value))
+ except:
+ err[i] = 1.0
+ print("Error getting error", value, x[i])
+
+ new_plot = Data1D(x, y)
+ new_plot.symbol = GUIFRAME_ID.CURVE_SYMBOL_NUM
+ new_plot.name = IQ_SMEARED_LABEL
+ new_plot.xaxis("\\rm{Q}", 'A^{-1}')
+ new_plot.yaxis("\\rm{Intensity} ", "cm^{-1}")
+ # If we have a group ID, use it
+ if 'plot_group_id' in pr.info:
+ new_plot.group_id = pr.info["plot_group_id"]
+ new_plot.id = IQ_SMEARED_LABEL
+ new_plot.title = title
+ self.parent.update_theory(data_id=self.data_id, theory=new_plot)
+ wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title=title))
+
+ def _on_pr_npts(self, evt):
+ """
+ Redisplay P(r) with a different number of points
+ """
+ from inversion_panel import PrDistDialog
+ dialog = PrDistDialog(None, -1)
+ dialog.set_content(self._pr_npts)
+ if dialog.ShowModal() == wx.ID_OK:
+ self._pr_npts = dialog.get_content()
+ dialog.Destroy()
+ self.show_pr(self._last_out, self._last_pr, self._last_cov)
+ else:
+ dialog.Destroy()
+
+
+ def show_pr(self, out, pr, cov=None):
+ """
+ """
+ # Show P(r)
+ x = pylab.arange(0.0, pr.d_max, pr.d_max / self._pr_npts)
+
+ y = np.zeros(len(x))
+ dy = np.zeros(len(x))
+ y_true = np.zeros(len(x))
+
+ total = 0.0
+ pmax = 0.0
+ cov2 = np.ascontiguousarray(cov)
+
+ for i in range(len(x)):
+ if cov2 is None:
+ value = pr.pr(out, x[i])
+ else:
+ (value, dy[i]) = pr.pr_err(out, cov2, x[i])
+ total += value * pr.d_max / len(x)
+
+ # keep track of the maximum P(r) value
+ if value > pmax:
+ pmax = value
+
+ y[i] = value
+
+ if self._normalize_output == True:
+ y = y / total
+ dy = dy / total
+ elif self._scale_output_unity == True:
+ y = y / pmax
+ dy = dy / pmax
+
+ if cov2 is None:
+ new_plot = Data1D(x, y)
+ new_plot.symbol = GUIFRAME_ID.CURVE_SYMBOL_NUM
+ else:
+ new_plot = Data1D(x, y, dy=dy)
+ new_plot.name = PR_FIT_LABEL
+ new_plot.xaxis("\\rm{r}", 'A')
+ new_plot.yaxis("\\rm{P(r)} ", "cm^{-3}")
+ new_plot.title = "P(r) fit"
+ new_plot.id = PR_FIT_LABEL
+ # Make sure that the plot is linear
+ new_plot.xtransform = "x"
+ new_plot.ytransform = "y"
+ new_plot.group_id = GROUP_ID_PR_FIT
+ self.parent.update_theory(data_id=self.data_id, theory=new_plot)
+ wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title="P(r) fit"))
+ return x, pr.d_max
+
+ def load(self, data):
+ """
+ Load data. This will eventually be replaced
+ by our standard DataLoader class.
+ """
+ class FileData(object):
+ x = None
+ y = None
+ err = None
+ path = None
+
+ def __init__(self, path):
+ self.path = path
+
+ self._current_file_data = FileData(data.path)
+
+ # Use data loader to load file
+ dataread = data
+ # Notify the user if we could not read the file
+ if dataread is None:
+ raise RuntimeError, "Invalid data"
+
+ x = None
+ y = None
+ err = None
+ if dataread.__class__.__name__ == 'Data1D':
+ x = dataread.x
+ y = dataread.y
+ err = dataread.dy
+ else:
+ if isinstance(dataread, list) and len(dataread) > 0:
+ x = dataread[0].x
+ y = dataread[0].y
+ err = dataread[0].dy
+ msg = "PrView only allows a single data set at a time. "
+ msg += "Only the first data set was loaded."
+ wx.PostEvent(self.parent, StatusEvent(status=msg))
+ else:
+ if dataread is None:
+ return x, y, err
+ raise RuntimeError, "This tool can only read 1D data"
+
+ self._current_file_data.x = x
+ self._current_file_data.y = y
+ self._current_file_data.err = err
+ return x, y, err
+
+ def load_columns(self, path="sphere_60_q0_2.txt"):
+ """
+ Load 2- or 3- column ascii
+ """
+ # Read the data from the data file
+ data_x = np.zeros(0)
+ data_y = np.zeros(0)
+ data_err = np.zeros(0)
+ scale = None
+ min_err = 0.0
+ if path is not None:
+ input_f = open(path, 'r')
+ buff = input_f.read()
+ lines = buff.split('\n')
+ for line in lines:
+ try:
+ toks = line.split()
+ x = float(toks[0])
+ y = float(toks[1])
+ if len(toks) > 2:
+ err = float(toks[2])
+ else:
+ if scale is None:
+ scale = 0.05 * math.sqrt(y)
+ #scale = 0.05/math.sqrt(y)
+ min_err = 0.01 * y
+ err = scale * math.sqrt(y) + min_err
+ #err = 0
+
+ data_x = np.append(data_x, x)
+ data_y = np.append(data_y, y)
+ data_err = np.append(data_err, err)
+ except:
+ logger.error(sys.exc_value)
+
+ if scale is not None:
+ message = "The loaded file had no error bars, statistical errors are assumed."
+ wx.PostEvent(self.parent, StatusEvent(status=message))
+ else:
+ wx.PostEvent(self.parent, StatusEvent(status=''))
+
+ return data_x, data_y, data_err
+
+ def load_abs(self, path):
+ """
+ Load an IGOR .ABS reduced file
+
+ :param path: file path
+
+ :return: x, y, err vectors
+
+ """
+ # Read the data from the data file
+ data_x = np.zeros(0)
+ data_y = np.zeros(0)
+ data_err = np.zeros(0)
+ scale = None
+ min_err = 0.0
+
+ data_started = False
+ if path is not None:
+ input_f = open(path, 'r')
+ buff = input_f.read()
+ lines = buff.split('\n')
+ for line in lines:
+ if data_started == True:
+ try:
+ toks = line.split()
+ x = float(toks[0])
+ y = float(toks[1])
+ if len(toks) > 2:
+ err = float(toks[2])
+ else:
+ if scale is None:
+ scale = 0.05 * math.sqrt(y)
+ #scale = 0.05/math.sqrt(y)
+ min_err = 0.01 * y
+ err = scale * math.sqrt(y) + min_err
+ #err = 0
+
+ data_x = np.append(data_x, x)
+ data_y = np.append(data_y, y)
+ data_err = np.append(data_err, err)
+ except:
+ logger.error(sys.exc_value)
+ elif line.find("The 6 columns") >= 0:
+ data_started = True
+
+ if scale is not None:
+ message = "The loaded file had no error bars, statistical errors are assumed."
+ wx.PostEvent(self.parent, StatusEvent(status=message))
+ else:
+ wx.PostEvent(self.parent, StatusEvent(status=''))
+
+ return data_x, data_y, data_err
+
+ def pr_theory(self, r, R):
+ """
+ Return P(r) of a sphere for a given R
+ For test purposes
+ """
+ if r <= 2 * R:
+ return 12.0 * ((0.5 * r / R) ** 2) * ((1.0 - 0.5 * r / R) ** 2) * (2.0 + 0.5 * r / R)
+ else:
+ return 0.0
+
+ def get_context_menu(self, plotpanel=None):
+ """
+ Get the context menu items available for P(r)
+
+ :param graph: the Graph object to which we attach the context menu
+
+ :return: a list of menu items with call-back function
+
+ """
+ graph = plotpanel.graph
+ # Look whether this Graph contains P(r) data
+ if graph.selected_plottable not in plotpanel.plots:
+ return []
+ item = plotpanel.plots[graph.selected_plottable]
+ if item.id == PR_FIT_LABEL:
+ #add_data_hint = "Load a data file and display it on this plot"
+ #["Add P(r) data",add_data_hint , self._on_add_data],
+ change_n_hint = "Change the number of"
+ change_n_hint += " points on the P(r) output"
+ change_n_label = "Change number of P(r) points"
+ m_list = [[change_n_label, change_n_hint, self._on_pr_npts]]
+
+ if self._scale_output_unity or self._normalize_output:
+ hint = "Let the output P(r) keep the scale of the data"
+ m_list.append(["Disable P(r) scaling", hint,
+ self._on_disable_scaling])
+ if not self._scale_output_unity:
+ m_list.append(["Scale P_max(r) to unity",
+ "Scale P(r) so that its maximum is 1",
+ self._on_scale_unity])
+ if not self._normalize_output:
+ m_list.append(["Normalize P(r) to unity",
+ "Normalize the integral of P(r) to 1",
+ self._on_normalize])
+
+ return m_list
+
+ elif item.id in [PR_LOADED_LABEL, IQ_DATA_LABEL, IQ_FIT_LABEL, IQ_SMEARED_LABEL]:
+ return []
+ elif item.id == graph.selected_plottable:
+ if issubclass(item.__class__, Data1D):
+ return [["Compute P(r)",
+ "Compute P(r) from distribution",
+ self._on_context_inversion]]
+ return []
+
+ def _on_disable_scaling(self, evt):
+ """
+ Disable P(r) scaling
+
+ :param evt: Menu event
+
+ """
+ self._normalize_output = False
+ self._scale_output_unity = False
+ self.show_pr(self._last_out, self._last_pr, self._last_cov)
+
+ # Now replot the original added data
+ for plot in self._added_plots:
+ self._added_plots[plot].y = np.copy(self._default_Iq[plot])
+ wx.PostEvent(self.parent,
+ NewPlotEvent(plot=self._added_plots[plot],
+ title=self._added_plots[plot].name,
+ update=True))
+
+ # Need the update flag in the NewPlotEvent to protect against
+ # the plot no longer being there...
+
+ def _on_normalize(self, evt):
+ """
+ Normalize the area under the P(r) curve to 1.
+ This operation is done for all displayed plots.
+
+ :param evt: Menu event
+
+ """
+ self._normalize_output = True
+ self._scale_output_unity = False
+
+ self.show_pr(self._last_out, self._last_pr, self._last_cov)
+
+ # Now scale the added plots too
+ for plot in self._added_plots:
+ total = np.sum(self._added_plots[plot].y)
+ npts = len(self._added_plots[plot].x)
+ total *= self._added_plots[plot].x[npts - 1] / npts
+ y = self._added_plots[plot].y / total
+
+ new_plot = Data1D(self._added_plots[plot].x, y)
+ new_plot.symbol = GUIFRAME_ID.CURVE_SYMBOL_NUM
+ new_plot.group_id = self._added_plots[plot].group_id
+ new_plot.id = self._added_plots[plot].id
+ new_plot.title = self._added_plots[plot].title
+ new_plot.name = self._added_plots[plot].name
+ new_plot.xaxis("\\rm{r}", 'A')
+ new_plot.yaxis("\\rm{P(r)} ", "cm^{-3}")
+ self.parent.update_theory(data_id=self.data_id, theory=new_plot)
+ wx.PostEvent(self.parent,
+ NewPlotEvent(plot=new_plot, update=True,
+ title=self._added_plots[plot].name))
+
+ def _on_scale_unity(self, evt):
+ """
+ Scale the maximum P(r) value on each displayed plot to 1.
+
+ :param evt: Menu event
+
+ """
+ self._scale_output_unity = True
+ self._normalize_output = False
+
+ self.show_pr(self._last_out, self._last_pr, self._last_cov)
+
+ # Now scale the added plots too
+ for plot in self._added_plots:
+ _max = 0
+ for y in self._added_plots[plot].y:
+ if y > _max:
+ _max = y
+ y = self._added_plots[plot].y / _max
+
+ new_plot = Data1D(self._added_plots[plot].x, y)
+ new_plot.symbol = GUIFRAME_ID.CURVE_SYMBOL_NUM
+ new_plot.name = self._added_plots[plot].name
+ new_plot.xaxis("\\rm{r}", 'A')
+ new_plot.yaxis("\\rm{P(r)} ", "cm^{-3}")
+ self.parent.update_theory(data_id=self.data_id, theory=new_plot)
+ wx.PostEvent(self.parent,
+ NewPlotEvent(plot=new_plot, update=True,
+ title=self._added_plots[plot].name))
+
+ def start_thread(self):
+ """
+ Start a calculation thread
+ """
+ from pr_thread import CalcPr
+
+ # If a thread is already started, stop it
+ if self.calc_thread is not None and self.calc_thread.isrunning():
+ self.calc_thread.stop()
+ ## stop just raises the flag -- the thread is supposed to
+ ## then kill itself. In August 2014 it was shown that this is
+ ## incorrectly handled by fitting.py and a fix implemented.
+ ## It is not clear whether it is properly used here, but the
+ ## "fix" of waiting for the previous thread to end breaks the
+ ## pr perspective completely as it causes an infinite loop.
+ ## Thus it is likely the threading is bing properly handled.
+ ## While the "fix" is no longer implemented the comment is
+ ## left here till somebody ascertains that in fact the threads
+ ## are being properly handled.
+ ##
+ ## -PDB January 25, 2015
+
+ pr = self.pr.clone()
+ self.calc_thread = CalcPr(pr, self.nfunc,
+ error_func=self._thread_error,
+ completefn=self._completed, updatefn=None)
+ self.calc_thread.queue()
+ self.calc_thread.ready(2.5)
+
+ def _thread_error(self, error):
+ """
+ Call-back method for calculation errors
+ """
+ wx.PostEvent(self.parent, StatusEvent(status=error))
+
+ def _estimate_completed(self, alpha, message, elapsed):
+ """
+ Parameter estimation completed,
+ display the results to the user
+
+ :param alpha: estimated best alpha
+ :param elapsed: computation time
+
+ """
+ # Save useful info
+ self.elapsed = elapsed
+ self.control_panel.alpha_estimate = alpha
+ if message is not None:
+ wx.PostEvent(self.parent, StatusEvent(status=str(message)))
+ self.perform_estimateNT()
+
+ def _estimateNT_completed(self, nterms, alpha, message, elapsed):
+ """
+ Parameter estimation completed,
+ display the results to the user
+
+ :param alpha: estimated best alpha
+ :param nterms: estimated number of terms
+ :param elapsed: computation time
+
+ """
+ # Save useful info
+ self.elapsed = elapsed
+ self.control_panel.nterms_estimate = nterms
+ self.control_panel.alpha_estimate = alpha
+ if message is not None:
+ wx.PostEvent(self.parent, StatusEvent(status=str(message)))
+
+ def _completed(self, out, cov, pr, elapsed):
+ """
+ wxCallAfter Method called with the results when the inversion
+ is done
+
+ :param out: output coefficient for the base functions
+ :param cov: covariance matrix
+ :param pr: Invertor instance
+ :param elapsed: time spent computing
+ """
+ # Ensure hat you have all inputs are ready at the time call happens:
+ # Without CallAfter, it will freeze with wx >= 2.9.
+ wx.CallAfter(self._completed_call, out, cov, pr, elapsed)
+
+ def _completed_call(self, out, cov, pr, elapsed):
+ """
+ Method called with the results when the inversion
+ is done
+
+ :param out: output coefficient for the base functions
+ :param cov: covariance matrix
+ :param pr: Invertor instance
+ :param elapsed: time spent computing
+
+ """
+ # Save useful info
+ self.elapsed = elapsed
+ # Keep a copy of the last result
+ self._last_pr = pr.clone()
+ self._last_out = out
+ self._last_cov = cov
+
+ # Save Pr invertor
+ self.pr = pr
+ cov = np.ascontiguousarray(cov)
+
+ # Show result on control panel
+ self.control_panel.chi2 = pr.chi2
+ self.control_panel.elapsed = elapsed
+ self.control_panel.oscillation = pr.oscillations(out)
+ self.control_panel.positive = pr.get_positive(out)
+ self.control_panel.pos_err = pr.get_pos_err(out, cov)
+ self.control_panel.rg = pr.rg(out)
+ self.control_panel.iq0 = pr.iq0(out)
+ self.control_panel.bck = pr.background
+ self.control_panel.bck_input.SetValue("{:.2g}".format(pr.background))
+
+ # Show I(q) fit
+ self.show_iq(out, self.pr)
+
+ # Show P(r) fit
+ self.show_pr(out, self.pr, cov)
+
+ def show_data(self, path=None, data=None, reset=False):
+ """
+ Show data read from a file
+
+ :param path: file path
+ :param reset: if True all other plottables will be cleared
+
+ """
+ #if path is not None:
+ if data is not None:
+ try:
+ pr = self._create_file_pr(data)
+ except:
+ status = "Problem reading data: %s" % sys.exc_value
+ wx.PostEvent(self.parent, StatusEvent(status=status))
+ raise RuntimeError, status
+
+ # If the file contains nothing, just return
+ if pr is None:
+ raise RuntimeError, "Loaded data is invalid"
+
+ self.pr = pr
+
+ # Make a plot of I(q) data
+ if self.pr.err is None:
+ new_plot = Data1D(self.pr.x, self.pr.y)
+ new_plot.symbol = GUIFRAME_ID.CURVE_SYMBOL_NUM
+ else:
+ new_plot = Data1D(self.pr.x, self.pr.y, dy=self.pr.err)
+ new_plot.name = IQ_DATA_LABEL
+ new_plot.xaxis("\\rm{Q}", 'A^{-1}')
+ new_plot.yaxis("\\rm{Intensity} ", "cm^{-1}")
+ new_plot.interactive = True
+ new_plot.group_id = GROUP_ID_IQ_DATA
+ new_plot.id = self.data_id
+ new_plot.title = "I(q)"
+ wx.PostEvent(self.parent,
+ NewPlotEvent(plot=new_plot, title="I(q)", reset=reset))
+
+ self.current_plottable = new_plot
+ # Get Q range
+ self.control_panel.q_min = min(self.pr.x)
+ self.control_panel.q_max = max(self.pr.x)
+
+ def save_data(self, filepath, prstate=None):
+ """
+ Save data in provided state object.
+
+ :TODO: move the state code away from inversion_panel and move it here.
+ Then remove the "prstate" input and make this method private.
+
+ :param filepath: path of file to write to
+ :param prstate: P(r) inversion state
+
+ """
+ #TODO: do we need this or can we use DataLoader.loader.save directly?
+
+ # Add output data and coefficients to state
+ prstate.coefficients = self._last_out
+ prstate.covariance = self._last_cov
+
+ # Write the output to file
+ # First, check that the data is of the right type
+ if issubclass(self.current_plottable.__class__,
+ sas.sascalc.dataloader.data_info.Data1D):
+ self.state_reader.write(filepath, self.current_plottable, prstate)
+ else:
+ msg = "pr.save_data: the data being saved is not a"
+ msg += " sas.data_info.Data1D object"
+ raise RuntimeError, msg
+
+ def setup_plot_inversion(self, alpha, nfunc, d_max, q_min=None, q_max=None,
+ est_bck=False, bck_val=0, height=0, width=0):
+ """
+ Set up inversion from plotted data
+ """
+ self.alpha = alpha
+ self.nfunc = nfunc
+ self.max_length = d_max
+ self.q_min = q_min
+ self.q_max = q_max
+ self.est_bck = est_bck
+ self.bck_val = bck_val
+ self.slit_height = height
+ self.slit_width = width
+
+ try:
+ pr = self._create_plot_pr()
+ if pr is not None:
+ self.pr = pr
+ self.perform_inversion()
+ except:
+ wx.PostEvent(self.parent, StatusEvent(status=sys.exc_value))
+
+ def estimate_plot_inversion(self, alpha, nfunc, d_max,
+ q_min=None, q_max=None,
+ est_bck=False, bck_val=0, height=0, width=0):
+ """
+ Estimate parameters from plotted data
+ """
+ self.alpha = alpha
+ self.nfunc = nfunc
+ self.max_length = d_max
+ self.q_min = q_min
+ self.q_max = q_max
+ self.est_bck = est_bck
+ self.bck_val = bck_val
+ self.slit_height = height
+ self.slit_width = width
+
+ try:
+ pr = self._create_plot_pr()
+ if pr is not None:
+ self.pr = pr
+ self.perform_estimate()
+ except:
+ wx.PostEvent(self.parent, StatusEvent(status=sys.exc_value))
+
+ def _create_plot_pr(self, estimate=False):
+ """
+ Create and prepare invertor instance from
+ a plottable data set.
+
+ :param path: path of the file to read in
+
+ """
+ # Sanity check
+ if self.current_plottable is None:
+ msg = "Please load a valid data set before proceeding."
+ wx.PostEvent(self.parent, StatusEvent(status=msg))
+ return None
+
+ # Get the data from the chosen data set and perform inversion
+ pr = Invertor()
+ pr.d_max = self.max_length
+ pr.alpha = self.alpha
+ pr.q_min = self.q_min
+ pr.q_max = self.q_max
+ pr.x = self.current_plottable.x
+ pr.y = self.current_plottable.y
+ pr.est_bck = self.est_bck
+ pr.slit_height = self.slit_height
+ pr.slit_width = self.slit_width
+ pr.background = self.bck_val
+
+ # Keep track of the plot window title to ensure that
+ # we can overlay the plots
+ pr.info["plot_group_id"] = self.current_plottable.group_id
+
+ # Fill in errors if none were provided
+ err = self.current_plottable.dy
+ all_zeros = True
+ if err is None:
+ err = np.zeros(len(pr.y))
+ else:
+ for i in range(len(err)):
+ if err[i] > 0:
+ all_zeros = False
+
+ if all_zeros:
+ scale = None
+ min_err = 0.0
+ for i in range(len(pr.y)):
+ # Scale the error so that we can fit over several decades of Q
+ if scale is None:
+ scale = 0.05 * math.sqrt(pr.y[i])
+ min_err = 0.01 * pr.y[i]
+ err[i] = scale * math.sqrt(math.fabs(pr.y[i])) + min_err
+ message = "The loaded file had no error bars, "
+ message += "statistical errors are assumed."
+ wx.PostEvent(self.parent, StatusEvent(status=message))
+
+ pr.err = err
+
+ return pr
+
+ def setup_file_inversion(self, alpha, nfunc, d_max, data,
+ path=None, q_min=None, q_max=None,
+ bck=False, height=0, width=0):
+ """
+ Set up inversion
+ """
+ self.alpha = alpha
+ self.nfunc = nfunc
+ self.max_length = d_max
+ self.q_min = q_min
+ self.q_max = q_max
+ self.est_bck = bck
+ self.slit_height = height
+ self.slit_width = width
+
+ try:
+ pr = self._create_file_pr(data)
+ if pr is not None:
+ self.pr = pr
+ self.perform_inversion()
+ except:
+ wx.PostEvent(self.parent, StatusEvent(status=sys.exc_value))
+
+ def estimate_file_inversion(self, alpha, nfunc, d_max, data,
+ path=None, q_min=None, q_max=None,
+ bck=False, height=0, width=0):
+ """
+ Estimate parameters for inversion
+ """
+ self.alpha = alpha
+ self.nfunc = nfunc
+ self.max_length = d_max
+ self.q_min = q_min
+ self.q_max = q_max
+ self.est_bck = bck
+ self.slit_height = height
+ self.slit_width = width
+
+ try:
+ pr = self._create_file_pr(data)
+ if pr is not None:
+ self.pr = pr
+ self.perform_estimate()
+ except:
+ wx.PostEvent(self.parent, StatusEvent(status=sys.exc_value))
+
+ def _create_file_pr(self, data):
+ """
+ Create and prepare invertor instance from
+ a file data set.
+
+ :param path: path of the file to read in
+
+ """
+ # Reset the status bar so that we don't get mixed up
+ # with old messages.
+ #TODO: refactor this into a proper status handling
+ wx.PostEvent(self.parent, StatusEvent(status=''))
+ try:
+ class FileData(object):
+ x = None
+ y = None
+ err = None
+ path = None
+ def __init__(self, path):
+ self.path = path
+
+ self._current_file_data = FileData(data.path)
+ self._current_file_data.x = data.x
+ self._current_file_data.y = data.y
+ self._current_file_data.err = data.dy
+ x, y, err = data.x, data.y, data.dy
+ except:
+ load_error(sys.exc_value)
+ return None
+
+ # If the file contains no data, just return
+ if x is None or len(x) == 0:
+ load_error("The loaded file contains no data")
+ return None
+
+ # If we have not errors, add statistical errors
+ if y is not None:
+ if err is None or np.all(err) == 0:
+ err = np.zeros(len(y))
+ scale = None
+ min_err = 0.0
+ for i in range(len(y)):
+ # Scale the error so that we can fit over several decades of Q
+ if scale is None:
+ scale = 0.05 * math.sqrt(y[i])
+ min_err = 0.01 * y[i]
+ err[i] = scale * math.sqrt(math.fabs(y[i])) + min_err
+ message = "The loaded file had no error bars, "
+ message += "statistical errors are assumed."
+ wx.PostEvent(self.parent, StatusEvent(status=message))
+
+ try:
+ # Get the data from the chosen data set and perform inversion
+ pr = Invertor()
+ pr.d_max = self.max_length
+ pr.alpha = self.alpha
+ pr.q_min = self.q_min
+ pr.q_max = self.q_max
+ pr.x = x
+ pr.y = y
+ pr.err = err
+ pr.est_bck = self.est_bck
+ pr.slit_height = self.slit_height
+ pr.slit_width = self.slit_width
+ return pr
+ except:
+ load_error(sys.exc_value)
+ return None
+
+ def perform_estimate(self):
+ """
+ Perform parameter estimation
+ """
+ from pr_thread import EstimatePr
+
+ # If a thread is already started, stop it
+ if self.estimation_thread is not None and \
+ self.estimation_thread.isrunning():
+ self.estimation_thread.stop()
+ ## stop just raises the flag -- the thread is supposed to
+ ## then kill itself. In August 2014 it was shown that this is
+ ## incorrectly handled by fitting.py and a fix implemented.
+ ## It is not clear whether it is properly used here, but the
+ ## "fix" of waiting for the previous thread to end breaks the
+ ## pr perspective completely as it causes an infinite loop.
+ ## Thus it is likely the threading is bing properly handled.
+ ## While the "fix" is no longer implemented the comment is
+ ## left here till somebody ascertains that in fact the threads
+ ## are being properly handled.
+ ##
+ ## -PDB January 25, 2015
+ pr = self.pr.clone()
+ self.estimation_thread = EstimatePr(pr, self.nfunc,
+ error_func=self._thread_error,
+ completefn=self._estimate_completed,
+ updatefn=None)
+ self.estimation_thread.queue()
+ self.estimation_thread.ready(2.5)
+
+ def perform_estimateNT(self):
+ """
+ Perform parameter estimation
+ """
+ from pr_thread import EstimateNT
+
+ # If a thread is already started, stop it
+ if self.estimation_thread is not None and self.estimation_thread.isrunning():
+ self.estimation_thread.stop()
+ ## stop just raises the flag -- the thread is supposed to
+ ## then kill itself. In August 2014 it was shown that this is
+ ## incorrectly handled by fitting.py and a fix implemented.
+ ## It is not clear whether it is properly used here, but the
+ ## "fix" of waiting for the previous thread to end breaks the
+ ## pr perspective completely as it causes an infinite loop.
+ ## Thus it is likely the threading is bing properly handled.
+ ## While the "fix" is no longer implemented the comment is
+ ## left here till somebody ascertains that in fact the threads
+ ## are being properly handled.
+ ##
+ ## -PDB January 25, 2015
+ pr = self.pr.clone()
+ # Skip the slit settings for the estimation
+ # It slows down the application and it doesn't change the estimates
+ pr.slit_height = 0.0
+ pr.slit_width = 0.0
+ self.estimation_thread = EstimateNT(pr, self.nfunc,
+ error_func=self._thread_error,
+ completefn=self._estimateNT_completed,
+ updatefn=None)
+ self.estimation_thread.queue()
+ self.estimation_thread.ready(2.5)
+
+ def perform_inversion(self):
+ """
+ Perform inversion
+ """
+ self.start_thread()
+
+ def _on_context_inversion(self, event):
+ """
+ Call-back method for plot context menu
+ """
+ panel = event.GetEventObject()
+ Plugin.on_perspective(self, event=event)
+
+ # If we have more than one displayed plot, make the user choose
+ if len(panel.plots) >= 1 and \
+ panel.graph.selected_plottable in panel.plots:
+ dataset = panel.plots[panel.graph.selected_plottable].name
+ else:
+ logger.info("Prview Error: No data is available")
+ return
+
+ # Store a reference to the current plottable
+ # If we have a suggested value, use it.
+ try:
+ estimate = float(self.control_panel.alpha_estimate)
+ self.control_panel.alpha = estimate
+ except:
+ self.control_panel.alpha = self.alpha
+ logger.info("Prview :Alpha Not estimate yet")
+ try:
+ estimate = int(self.control_panel.nterms_estimate)
+ self.control_panel.nfunc = estimate
+ except:
+ self.control_panel.nfunc = self.nfunc
+ logger.info("Prview : ntemrs Not estimate yet")
+
+ self.current_plottable = panel.plots[panel.graph.selected_plottable]
+ self.set_data([self.current_plottable])
+ self.control_panel.plotname = dataset
+ #self.control_panel.nfunc = self.nfunc
+ self.control_panel.d_max = self.max_length
+ #self.parent.set_perspective(self.perspective)
+ self.control_panel._on_invert(None)
+
+ def get_panels(self, parent):
+ """
+ Create and return a list of panel objects
+ """
+ from inversion_panel import InversionControl
+
+ self.parent = parent
+ self.frame = MDIFrame(self.parent, None, 'None', (100, 200))
+ self.control_panel = InversionControl(self.frame, -1,
+ style=wx.RAISED_BORDER)
+ self.frame.set_panel(self.control_panel)
+ self._frame_set_helper()
+ self.control_panel.set_manager(self)
+ self.control_panel.nfunc = self.nfunc
+ self.control_panel.d_max = self.max_length
+ self.control_panel.alpha = self.alpha
+ self.perspective = []
+ self.perspective.append(self.control_panel.window_name)
+
+ return [self.control_panel]
+
+ def set_data(self, data_list=None):
+ """
+ receive a list of data to compute pr
+ """
+ if data_list is None:
+ data_list = []
+ if len(data_list) >= 1:
+ if len(data_list) == 1:
+ data = data_list[0]
+ else:
+ data_1d_list = []
+ data_2d_list = []
+ error_msg = ""
+ # separate data into data1d and data2d list
+ for data in data_list:
+ if data is not None:
+ if issubclass(data.__class__, Data1D):
+ data_1d_list.append(data)
+ else:
+ error_msg += " %s type %s \n" % (str(data.name),
+ str(data.__class__.__name__))
+ data_2d_list.append(data)
+ if len(data_2d_list) > 0:
+ msg = "PrView does not support the following data types:\n"
+ msg += error_msg
+ if len(data_1d_list) == 0:
+ wx.PostEvent(self.parent, StatusEvent(status=msg, info='error'))
+ return
+ msg = "Prview does not allow multiple data!\n"
+ msg += "Please select one.\n"
+ if len(data_list) > 1:
+ from pr_widgets import DataDialog
+ dlg = DataDialog(data_list=data_1d_list, text=msg)
+ if dlg.ShowModal() == wx.ID_OK:
+ data = dlg.get_data()
+ else:
+ data = None
+ dlg.Destroy()
+ if data is None:
+ msg += "PrView receives no data. \n"
+ wx.PostEvent(self.parent, StatusEvent(status=msg, info='error'))
+ return
+ if issubclass(data.__class__, Data1D):
+ try:
+ wx.PostEvent(self.parent,
+ NewPlotEvent(action='remove',
+ group_id=GROUP_ID_IQ_DATA,
+ id=self.data_id))
+ self.data_id = data.id
+ self.control_panel._change_file(evt=None, data=data)
+ except:
+ msg = "Prview Set_data: " + str(sys.exc_value)
+ wx.PostEvent(self.parent, StatusEvent(status=msg, info="error"))
+ else:
+ msg = "Pr cannot be computed for data of "
+ msg += "type %s" % (data_list[0].__class__.__name__)
+ wx.PostEvent(self.parent, StatusEvent(status=msg, info='error'))
+ else:
+ msg = "Pr contain no data"
+ wx.PostEvent(self.parent, StatusEvent(status=msg, info='warning'))
+
+ def post_init(self):
+ """
+ Post initialization call back to close the loose ends
+ [Somehow openGL needs this call]
+ """
+ pass
diff --git a/src/sas/sasgui/perspectives/pr/pr_thread.py b/src/sas/sasgui/perspectives/pr/pr_thread.py
index 16d25b6..75119f8 100644
--- a/src/sas/sasgui/perspectives/pr/pr_thread.py
+++ b/src/sas/sasgui/perspectives/pr/pr_thread.py
@@ -1,113 +1,113 @@
-
-################################################################################
-#This software was developed by the University of Tennessee as part of the
-#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
-#project funded by the US National Science Foundation.
-#
-#See the license text in license.txt
-#
-#copyright 2009, University of Tennessee
-################################################################################
-
-import sys
-import time
-from sas.sascalc.data_util.calcthread import CalcThread
-
-class CalcPr(CalcThread):
- """
- Compute P(r)
- """
-
- def __init__(self, pr, nfunc=5, error_func=None, completefn=None,
- updatefn=None, yieldtime=0.01, worktime=0.01):
- """
- """
- CalcThread.__init__(self, completefn, updatefn, yieldtime, worktime)
- self.pr = pr
- self.nfunc = nfunc
- self.error_func = error_func
- self.starttime = 0
-
- def compute(self):
- """
- Perform P(r) inversion
- """
- try:
- self.starttime = time.time()
- out, cov = self.pr.invert(self.nfunc)
- elapsed = time.time() - self.starttime
- self.complete(out=out, cov=cov, pr=self.pr, elapsed=elapsed)
- except KeyboardInterrupt:
- # Thread was interrupted, just proceed
- pass
- except:
- if not self.error_func == None:
- self.error_func("CalcPr.compute: %s" % sys.exc_value)
-
-class EstimatePr(CalcThread):
- """
- Estimate P(r)
- """
-
- def __init__(self, pr, nfunc=5, error_func=None, completefn=None,
- updatefn=None, yieldtime=0.01, worktime=0.01):
- CalcThread.__init__(self, completefn, updatefn, yieldtime, worktime)
- self.pr = pr
- self.nfunc = nfunc
- self.error_func = error_func
- self.starttime = 0
-
- def compute(self):
- """
- Calculates the estimate
- """
- try:
- alpha, message, elapsed = self.pr.estimate_alpha(self.nfunc)
- self.isquit()
- self.complete(alpha=alpha, message=message, elapsed=elapsed)
- except KeyboardInterrupt:
- # Thread was interrupted, just proceed
- pass
- except:
- if not self.error_func == None:
- self.error_func("EstimatePr.compute: %s" % sys.exc_value)
-
-class EstimateNT(CalcThread):
- """
- """
- def __init__(self, pr, nfunc=5, error_func=None, completefn=None,
- updatefn=None, yieldtime=0.01, worktime=0.01):
- CalcThread.__init__(self, completefn, updatefn, yieldtime, worktime)
- self.pr = pr
- self.nfunc = nfunc
- self.error_func = error_func
- self.starttime = 0
- self._time_for_sleep = 0
- self._sleep_delay = 1.0
-
-
- def isquit(self):
- """
- """
- CalcThread.isquit(self)
- if time.time() > self._time_for_sleep + self._sleep_delay:
- time.sleep(.2)
- self._time_for_sleep = time.time()
-
- def compute(self):
- """
- Calculates the estimate
- """
- try:
- t_0 = time.time()
- self._time_for_sleep = t_0
- nterms, alpha, message = self.pr.estimate_numterms(self.isquit)
- t_1 = time.time() - t_0
- self.isquit()
- self.complete(nterms=nterms, alpha=alpha, message=message, elapsed=t_1)
- except KeyboardInterrupt:
- # Thread was interrupted, just proceed
- pass
- except:
- if not self.error_func == None:
- self.error_func("EstimatePr2.compute: %s" % sys.exc_value)
+
+################################################################################
+#This software was developed by the University of Tennessee as part of the
+#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
+#project funded by the US National Science Foundation.
+#
+#See the license text in license.txt
+#
+#copyright 2009, University of Tennessee
+################################################################################
+
+import sys
+import time
+from sas.sascalc.data_util.calcthread import CalcThread
+
+class CalcPr(CalcThread):
+ """
+ Compute P(r)
+ """
+
+ def __init__(self, pr, nfunc=5, error_func=None, completefn=None,
+ updatefn=None, yieldtime=0.01, worktime=0.01):
+ """
+ """
+ CalcThread.__init__(self, completefn, updatefn, yieldtime, worktime)
+ self.pr = pr
+ self.nfunc = nfunc
+ self.error_func = error_func
+ self.starttime = 0
+
+ def compute(self):
+ """
+ Perform P(r) inversion
+ """
+ try:
+ self.starttime = time.time()
+ out, cov = self.pr.invert(self.nfunc)
+ elapsed = time.time() - self.starttime
+ self.complete(out=out, cov=cov, pr=self.pr, elapsed=elapsed)
+ except KeyboardInterrupt:
+ # Thread was interrupted, just proceed
+ pass
+ except:
+ if self.error_func is not None:
+ self.error_func("CalcPr.compute: %s" % sys.exc_value)
+
+class EstimatePr(CalcThread):
+ """
+ Estimate P(r)
+ """
+
+ def __init__(self, pr, nfunc=5, error_func=None, completefn=None,
+ updatefn=None, yieldtime=0.01, worktime=0.01):
+ CalcThread.__init__(self, completefn, updatefn, yieldtime, worktime)
+ self.pr = pr
+ self.nfunc = nfunc
+ self.error_func = error_func
+ self.starttime = 0
+
+ def compute(self):
+ """
+ Calculates the estimate
+ """
+ try:
+ alpha, message, elapsed = self.pr.estimate_alpha(self.nfunc)
+ self.isquit()
+ self.complete(alpha=alpha, message=message, elapsed=elapsed)
+ except KeyboardInterrupt:
+ # Thread was interrupted, just proceed
+ pass
+ except:
+ if self.error_func is not None:
+ self.error_func("EstimatePr.compute: %s" % sys.exc_value)
+
+class EstimateNT(CalcThread):
+ """
+ """
+ def __init__(self, pr, nfunc=5, error_func=None, completefn=None,
+ updatefn=None, yieldtime=0.01, worktime=0.01):
+ CalcThread.__init__(self, completefn, updatefn, yieldtime, worktime)
+ self.pr = pr
+ self.nfunc = nfunc
+ self.error_func = error_func
+ self.starttime = 0
+ self._time_for_sleep = 0
+ self._sleep_delay = 1.0
+
+
+ def isquit(self):
+ """
+ """
+ CalcThread.isquit(self)
+ if time.time() > self._time_for_sleep + self._sleep_delay:
+ time.sleep(.2)
+ self._time_for_sleep = time.time()
+
+ def compute(self):
+ """
+ Calculates the estimate
+ """
+ try:
+ t_0 = time.time()
+ self._time_for_sleep = t_0
+ nterms, alpha, message = self.pr.estimate_numterms(self.isquit)
+ t_1 = time.time() - t_0
+ self.isquit()
+ self.complete(nterms=nterms, alpha=alpha, message=message, elapsed=t_1)
+ except KeyboardInterrupt:
+ # Thread was interrupted, just proceed
+ pass
+ except:
+ if self.error_func is not None:
+ self.error_func("EstimatePr2.compute: %s" % sys.exc_value)
diff --git a/src/sas/sasgui/perspectives/pr/pr_widgets.py b/src/sas/sasgui/perspectives/pr/pr_widgets.py
index 21492ab..ef1c752 100644
--- a/src/sas/sasgui/perspectives/pr/pr_widgets.py
+++ b/src/sas/sasgui/perspectives/pr/pr_widgets.py
@@ -1,223 +1,223 @@
-
-################################################################################
-#This software was developed by the University of Tennessee as part of the
-#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
-#project funded by the US National Science Foundation.
-#
-#See the license text in license.txt
-#
-#copyright 2009, University of Tennessee
-################################################################################
-
-"""
-Text controls for input/output of the main PrView panel
-"""
-
-import wx
-import os
-from wx.lib.scrolledpanel import ScrolledPanel
-
-WIDTH = 400
-HEIGHT = 350
-
-
-class DialogPanel(ScrolledPanel):
- def __init__(self, *args, **kwds):
- ScrolledPanel.__init__(self, *args, **kwds)
- self.SetupScrolling()
-
-
-class PrTextCtrl(wx.TextCtrl):
- """
- Text control for model and fit parameters.
- Binds the appropriate events for user interactions.
- """
- def __init__(self, *args, **kwds):
-
- wx.TextCtrl.__init__(self, *args, **kwds)
-
- ## Set to True when the mouse is clicked while the whole string is selected
- self.full_selection = False
- ## Call back for EVT_SET_FOCUS events
- _on_set_focus_callback = None
- # Bind appropriate events
- self.Bind(wx.EVT_LEFT_UP, self._highlight_text)
- self.Bind(wx.EVT_SET_FOCUS, self._on_set_focus)
-
- def _on_set_focus(self, event):
- """
- Catch when the text control is set in focus to highlight the whole
- text if necessary
-
- :param event: mouse event
-
- """
- event.Skip()
- self.full_selection = True
-
- def _highlight_text(self, event):
- """
- Highlight text of a TextCtrl only of no text has be selected
-
- :param event: mouse event
-
- """
- # Make sure the mouse event is available to other listeners
- event.Skip()
- control = event.GetEventObject()
- if self.full_selection:
- self.full_selection = False
- # Check that we have a TextCtrl
- if issubclass(control.__class__, wx.TextCtrl):
- # Check whether text has been selected,
- # if not, select the whole string
- (start, end) = control.GetSelection()
- if start == end:
- control.SetSelection(-1, -1)
-
-class OutputTextCtrl(wx.TextCtrl):
- """
- Text control used to display outputs.
- No editing allowed. The background is
- grayed out. User can't select text.
- """
- def __init__(self, *args, **kwds):
- """
- """
- wx.TextCtrl.__init__(self, *args, **kwds)
- self.SetEditable(False)
- self.SetBackgroundColour(self.GetParent().GetBackgroundColour())
-
- # Bind to mouse event to avoid text highlighting
- # The event will be skipped once the call-back
- # is called.
- self.Bind(wx.EVT_MOUSE_EVENTS, self._click)
-
- def _click(self, event):
- """
- Prevent further handling of the mouse event
- by not calling Skip().
- """
- pass
-
-
-class DataFileTextCtrl(OutputTextCtrl):
- """
- Text control used to display only the file name
- given a full path.
-
- :TODO: now that we no longer choose the data file from the panel,
- it's no longer necessary to pass around the file path. That code
- should be refactored away and simplified.
- """
- def __init__(self, *args, **kwds):
- """
- """
- OutputTextCtrl.__init__(self, *args, **kwds)
- self._complete_path = None
-
- def SetValue(self, value):
- """
- Sets the file name given a path
- """
- self._complete_path = str(value)
- file_path = os.path.basename(self._complete_path)
- OutputTextCtrl.SetValue(self, file_path)
-
- def GetValue(self):
- """
- Return the full path
- """
- return self._complete_path
-
-
-def load_error(error=None):
- """
- Pop up an error message.
-
- :param error: details error message to be displayed
- """
- message = "The data file you selected could not be loaded.\n"
- message += "Make sure the content of your file is properly formatted.\n\n"
-
- if error is not None:
- message += "When contacting the DANSE team, mention the"
- message += " following:\n%s" % str(error)
-
- dial = wx.MessageDialog(None, message, 'Error Loading File',
- wx.OK | wx.ICON_EXCLAMATION)
- dial.ShowModal()
-
-
-class DataDialog(wx.Dialog):
- """
- Allow file selection at loading time
- """
- def __init__(self, data_list, parent=None, text='', *args, **kwds):
- kwds['size'] = (WIDTH, HEIGHT)
- kwds['title'] = "Data Selection"
- wx.Dialog.__init__(self, parent, *args, **kwds)
- self.list_of_ctrl = []
- self._sizer_main = wx.BoxSizer(wx.VERTICAL)
- self._sizer_txt = wx.BoxSizer(wx.VERTICAL)
- self._sizer_button = wx.BoxSizer(wx.HORIZONTAL)
- self._choice_sizer = wx.GridBagSizer(5, 5)
- self._panel = DialogPanel(self, style=wx.RAISED_BORDER,
- size=(WIDTH - 20, HEIGHT / 3))
-
- self.__do_layout(data_list, text=text)
-
- def __do_layout(self, data_list, text=''):
- """
- layout the dialog
- """
- #add text
- if text.strip() == "":
- text = "This Perspective does not allow multiple data !\n"
- text += "Please select only one Data.\n"
- text_ctrl = wx.TextCtrl(self, -1, str(text), style=wx.TE_MULTILINE,
- size=(-1, HEIGHT / 3))
- text_ctrl.SetEditable(False)
- self._sizer_txt.Add(text_ctrl, 1, wx.EXPAND | wx.ALL, 10)
- iy = 0
- ix = 0
- rbox = wx.RadioButton(self._panel, -1, str(data_list[0].name),
- (10, 10), style=wx.RB_GROUP)
- rbox.SetValue(True)
- self.list_of_ctrl.append((rbox, data_list[0]))
- self._choice_sizer.Add(rbox, (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- for i in range(1, len(data_list)):
- iy += 1
- rbox = wx.RadioButton(self._panel, -1,
- str(data_list[i].name), (10, 10))
- rbox.SetValue(False)
- self.list_of_ctrl.append((rbox, data_list[i]))
- self._choice_sizer.Add(rbox, (iy, ix),
- (1, 1), wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- self._panel.SetSizer(self._choice_sizer)
- #add sizer
- self._sizer_button.Add((20, 20), 1, wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- button_cancel = wx.Button(self, wx.ID_CANCEL, "Cancel")
- self._sizer_button.Add(button_cancel, 0,
- wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 10)
- button_ok = wx.Button(self, wx.ID_OK, "Ok")
- button_ok.SetFocus()
- self._sizer_button.Add(button_ok, 0,
- wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 10)
- static_line = wx.StaticLine(self, -1)
-
- self._sizer_txt.Add(self._panel, 0, wx.EXPAND | wx.ALL, 5)
- self._sizer_main.Add(self._sizer_txt, 0, wx.EXPAND | wx.ALL, 5)
- self._sizer_main.Add(static_line, 0, wx.EXPAND, 0)
- self._sizer_main.Add(self._sizer_button, 0, wx.EXPAND | wx.ALL, 10)
- self.SetSizer(self._sizer_main)
-
- def get_data(self):
- """
- return the selected data
- """
- for item in self.list_of_ctrl:
- rbox, data = item
- if rbox.GetValue():
- return data
+
+################################################################################
+#This software was developed by the University of Tennessee as part of the
+#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
+#project funded by the US National Science Foundation.
+#
+#See the license text in license.txt
+#
+#copyright 2009, University of Tennessee
+################################################################################
+
+"""
+Text controls for input/output of the main PrView panel
+"""
+
+import wx
+import os
+from wx.lib.scrolledpanel import ScrolledPanel
+
+WIDTH = 400
+HEIGHT = 350
+
+
+class DialogPanel(ScrolledPanel):
+ def __init__(self, *args, **kwds):
+ ScrolledPanel.__init__(self, *args, **kwds)
+ self.SetupScrolling()
+
+
+class PrTextCtrl(wx.TextCtrl):
+ """
+ Text control for model and fit parameters.
+ Binds the appropriate events for user interactions.
+ """
+ def __init__(self, *args, **kwds):
+
+ wx.TextCtrl.__init__(self, *args, **kwds)
+
+ ## Set to True when the mouse is clicked while the whole string is selected
+ self.full_selection = False
+ ## Call back for EVT_SET_FOCUS events
+ _on_set_focus_callback = None
+ # Bind appropriate events
+ self.Bind(wx.EVT_LEFT_UP, self._highlight_text)
+ self.Bind(wx.EVT_SET_FOCUS, self._on_set_focus)
+
+ def _on_set_focus(self, event):
+ """
+ Catch when the text control is set in focus to highlight the whole
+ text if necessary
+
+ :param event: mouse event
+
+ """
+ event.Skip()
+ self.full_selection = True
+
+ def _highlight_text(self, event):
+ """
+ Highlight text of a TextCtrl only of no text has be selected
+
+ :param event: mouse event
+
+ """
+ # Make sure the mouse event is available to other listeners
+ event.Skip()
+ control = event.GetEventObject()
+ if self.full_selection:
+ self.full_selection = False
+ # Check that we have a TextCtrl
+ if issubclass(control.__class__, wx.TextCtrl):
+ # Check whether text has been selected,
+ # if not, select the whole string
+ (start, end) = control.GetSelection()
+ if start == end:
+ control.SetSelection(-1, -1)
+
+class OutputTextCtrl(wx.TextCtrl):
+ """
+ Text control used to display outputs.
+ No editing allowed. The background is
+ grayed out. User can't select text.
+ """
+ def __init__(self, *args, **kwds):
+ """
+ """
+ wx.TextCtrl.__init__(self, *args, **kwds)
+ self.SetEditable(False)
+ self.SetBackgroundColour(self.GetParent().GetBackgroundColour())
+
+ # Bind to mouse event to avoid text highlighting
+ # The event will be skipped once the call-back
+ # is called.
+ self.Bind(wx.EVT_MOUSE_EVENTS, self._click)
+
+ def _click(self, event):
+ """
+ Prevent further handling of the mouse event
+ by not calling Skip().
+ """
+ pass
+
+
+class DataFileTextCtrl(OutputTextCtrl):
+ """
+ Text control used to display only the file name
+ given a full path.
+
+ :TODO: now that we no longer choose the data file from the panel,
+ it's no longer necessary to pass around the file path. That code
+ should be refactored away and simplified.
+ """
+ def __init__(self, *args, **kwds):
+ """
+ """
+ OutputTextCtrl.__init__(self, *args, **kwds)
+ self._complete_path = None
+
+ def SetValue(self, value):
+ """
+ Sets the file name given a path
+ """
+ self._complete_path = str(value)
+ file_path = os.path.basename(self._complete_path)
+ OutputTextCtrl.SetValue(self, file_path)
+
+ def GetValue(self):
+ """
+ Return the full path
+ """
+ return self._complete_path
+
+
+def load_error(error=None):
+ """
+ Pop up an error message.
+
+ :param error: details error message to be displayed
+ """
+ message = "The data file you selected could not be loaded.\n"
+ message += "Make sure the content of your file is properly formatted.\n\n"
+
+ if error is not None:
+ message += "When contacting the DANSE team, mention the"
+ message += " following:\n%s" % str(error)
+
+ dial = wx.MessageDialog(None, message, 'Error Loading File',
+ wx.OK | wx.ICON_EXCLAMATION)
+ dial.ShowModal()
+
+
+class DataDialog(wx.Dialog):
+ """
+ Allow file selection at loading time
+ """
+ def __init__(self, data_list, parent=None, text='', *args, **kwds):
+ kwds['size'] = (WIDTH, HEIGHT)
+ kwds['title'] = "Data Selection"
+ wx.Dialog.__init__(self, parent, *args, **kwds)
+ self.list_of_ctrl = []
+ self._sizer_main = wx.BoxSizer(wx.VERTICAL)
+ self._sizer_txt = wx.BoxSizer(wx.VERTICAL)
+ self._sizer_button = wx.BoxSizer(wx.HORIZONTAL)
+ self._choice_sizer = wx.GridBagSizer(5, 5)
+ self._panel = DialogPanel(self, style=wx.RAISED_BORDER,
+ size=(WIDTH - 20, HEIGHT / 3))
+
+ self.__do_layout(data_list, text=text)
+
+ def __do_layout(self, data_list, text=''):
+ """
+ layout the dialog
+ """
+ #add text
+ if text.strip() == "":
+ text = "This Perspective does not allow multiple data !\n"
+ text += "Please select only one Data.\n"
+ text_ctrl = wx.TextCtrl(self, -1, str(text), style=wx.TE_MULTILINE,
+ size=(-1, HEIGHT / 3))
+ text_ctrl.SetEditable(False)
+ self._sizer_txt.Add(text_ctrl, 1, wx.EXPAND | wx.ALL, 10)
+ iy = 0
+ ix = 0
+ rbox = wx.RadioButton(self._panel, -1, str(data_list[0].name),
+ (10, 10), style=wx.RB_GROUP)
+ rbox.SetValue(True)
+ self.list_of_ctrl.append((rbox, data_list[0]))
+ self._choice_sizer.Add(rbox, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ for i in range(1, len(data_list)):
+ iy += 1
+ rbox = wx.RadioButton(self._panel, -1,
+ str(data_list[i].name), (10, 10))
+ rbox.SetValue(False)
+ self.list_of_ctrl.append((rbox, data_list[i]))
+ self._choice_sizer.Add(rbox, (iy, ix),
+ (1, 1), wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ self._panel.SetSizer(self._choice_sizer)
+ #add sizer
+ self._sizer_button.Add((20, 20), 1, wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ button_cancel = wx.Button(self, wx.ID_CANCEL, "Cancel")
+ self._sizer_button.Add(button_cancel, 0,
+ wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 10)
+ button_ok = wx.Button(self, wx.ID_OK, "Ok")
+ button_ok.SetFocus()
+ self._sizer_button.Add(button_ok, 0,
+ wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 10)
+ static_line = wx.StaticLine(self, -1)
+
+ self._sizer_txt.Add(self._panel, 0, wx.EXPAND | wx.ALL, 5)
+ self._sizer_main.Add(self._sizer_txt, 0, wx.EXPAND | wx.ALL, 5)
+ self._sizer_main.Add(static_line, 0, wx.EXPAND, 0)
+ self._sizer_main.Add(self._sizer_button, 0, wx.EXPAND | wx.ALL, 10)
+ self.SetSizer(self._sizer_main)
+
+ def get_data(self):
+ """
+ return the selected data
+ """
+ for item in self.list_of_ctrl:
+ rbox, data = item
+ if rbox.GetValue():
+ return data
diff --git a/src/sas/sasgui/perspectives/simulation/ShapeAdapter.py b/src/sas/sasgui/perspectives/simulation/ShapeAdapter.py
index a25635a..fbb3f28 100644
--- a/src/sas/sasgui/perspectives/simulation/ShapeAdapter.py
+++ b/src/sas/sasgui/perspectives/simulation/ShapeAdapter.py
@@ -1,133 +1,133 @@
-"""
-This software was developed by the University of Tennessee as part of the
-Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
-project funded by the US National Science Foundation.
-
-See the license text in license.txt
-
-copyright 2009, University of Tennessee
-"""
-import sas.sascalc.realspace.VolumeCanvas as VolumeCanvas
-
-class ShapeVisitor:
- """
- The shape visitor process a GUI object representing
- a shape and returns a shape description that can be
- processed by the VolumeCanvas.
- """
-
- def __init__(self):
- """
- Initialize visitor
- """
- ## Place holder for the simulation canvas
- self.sim_canvas = None
-
- def fromCylinder(self, cyl):
- """
- Create a simulation cylinder descriptor (computation)
- from the information produced by the GUI
- @param cyl: Cylinder object from the GUI canvas
- @return: VolumeCanvas.CylinderDescriptor object
- """
- from sas.sascalc.realspace.VolumeCanvas import CylinderDescriptor
- desc = CylinderDescriptor()
-
- desc.params["center"] = [cyl.x, cyl.y, cyl.z]
- # Orientation are angular offsets in degrees with respect to X, Y, Z
- desc.params["orientation"] = [cyl.theta_x, cyl.theta_y, cyl.theta_z]
- desc.params["order"] = cyl.params["order"]
-
-
- # Length of the cylinder
- desc.params["length"] = cyl.params["length"]
- # Radius of the cylinder
- desc.params["radius"] = cyl.params["radius"]
- # Constrast parameter
- desc.params["contrast"] = cyl.params["contrast"]
-
- return desc
-
- def fromSphere(self, sph):
- """
- Create a simulation sphere descriptor (computation)
- from the information produced by the GUI
- @param sph: Sphere object from the GUI canvas
- @return: VolumeCanvas.SphereDescriptor object
- """
- from sas.sascalc.realspace.VolumeCanvas import SphereDescriptor
- desc = SphereDescriptor()
-
- desc.params["center"] = [sph.x, sph.y, sph.z]
- desc.params["order"] = sph.params["order"]
- # Radius of the sphere
- desc.params["radius"] = sph.params["radius"]
- # Constrast parameter
- desc.params["contrast"] = sph.params["contrast"]
-
- return desc
-
- def update_sphere(self, sph):
- """
- Update a shape description in the simulation canvas (computation)
- according to the new parameters of the GUI canvas.
- @param sph: Sphere object from the GUI canvas
- """
- # Check class
- if self.sim_canvas.shapes[sph.name].__class__.__name__=="SphereDescriptor":
- desc = self.sim_canvas.shapes[sph.name]
-
- desc.params["center"] = [sph.x, sph.y, sph.z]
- desc.params["order"] = sph.params["order"]
- # Radius of the sphere
- desc.params["radius"] = sph.params["radius"]
- # Constrast parameter
- desc.params["contrast"] = sph.params["contrast"]
-
- self.sim_canvas._model_changed()
- else:
- raise ValueError, "SimShapeVisitor: Wrong class for visited object"
-
-
-
- def update_cylinder(self, cyl):
- """
- Update a shape description in the simulation canvas (computation)
- according to the new parameters of the GUI canvas.
- @param cyl: Cylinder object from the GUI canvas
- """
- # Check class
- if self.sim_canvas.shapes[cyl.name].__class__.__name__=="CylinderDescriptor":
- desc = self.sim_canvas.shapes[cyl.name]
-
- desc.params["center"] = [cyl.x, cyl.y, cyl.z]
- # Orientation are angular offsets in degrees with respect to X, Y, Z
- desc.params["orientation"] = [cyl.theta_x, cyl.theta_y, cyl.theta_z]
- desc.params["order"] = cyl.params["order"]
-
- # Length of the cylinder
- desc.params["length"] = cyl.params["length"]
- # Radius of the cylinder
- desc.params["radius"] = cyl.params["radius"]
- # Constrast parameter
- desc.params["contrast"] = cyl.params["contrast"]
-
- self.sim_canvas._model_changed()
- else:
- raise ValueError, "SimShapeVisitor: Wrong class for visited object"
-
-
- def update(self, volCanvas, shape):
- """
- Update the shape descriptor in the VolumeCanvas
- corresponding to the given 'shape' parameter
-
- @param volCanvas: VolumeCanvas object
- @param shape: SimCanvas.BaseShape object
- """
- if shape.name in volCanvas.getShapeList():
- self.sim_canvas = volCanvas
- shape.accept_update(self)
- else:
- raise ValueError, "ShapeAdapter: Shape [%s] not in list" % shape.name
-
+"""
+This software was developed by the University of Tennessee as part of the
+Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
+project funded by the US National Science Foundation.
+
+See the license text in license.txt
+
+copyright 2009, University of Tennessee
+"""
+import sas.sascalc.realspace.VolumeCanvas as VolumeCanvas
+
+class ShapeVisitor:
+ """
+ The shape visitor process a GUI object representing
+ a shape and returns a shape description that can be
+ processed by the VolumeCanvas.
+ """
+
+ def __init__(self):
+ """
+ Initialize visitor
+ """
+ ## Place holder for the simulation canvas
+ self.sim_canvas = None
+
+ def fromCylinder(self, cyl):
+ """
+ Create a simulation cylinder descriptor (computation)
+ from the information produced by the GUI
+ @param cyl: Cylinder object from the GUI canvas
+ @return: VolumeCanvas.CylinderDescriptor object
+ """
+ from sas.sascalc.realspace.VolumeCanvas import CylinderDescriptor
+ desc = CylinderDescriptor()
+
+ desc.params["center"] = [cyl.x, cyl.y, cyl.z]
+ # Orientation are angular offsets in degrees with respect to X, Y, Z
+ desc.params["orientation"] = [cyl.theta_x, cyl.theta_y, cyl.theta_z]
+ desc.params["order"] = cyl.params["order"]
+
+
+ # Length of the cylinder
+ desc.params["length"] = cyl.params["length"]
+ # Radius of the cylinder
+ desc.params["radius"] = cyl.params["radius"]
+ # Constrast parameter
+ desc.params["contrast"] = cyl.params["contrast"]
+
+ return desc
+
+ def fromSphere(self, sph):
+ """
+ Create a simulation sphere descriptor (computation)
+ from the information produced by the GUI
+ @param sph: Sphere object from the GUI canvas
+ @return: VolumeCanvas.SphereDescriptor object
+ """
+ from sas.sascalc.realspace.VolumeCanvas import SphereDescriptor
+ desc = SphereDescriptor()
+
+ desc.params["center"] = [sph.x, sph.y, sph.z]
+ desc.params["order"] = sph.params["order"]
+ # Radius of the sphere
+ desc.params["radius"] = sph.params["radius"]
+ # Constrast parameter
+ desc.params["contrast"] = sph.params["contrast"]
+
+ return desc
+
+ def update_sphere(self, sph):
+ """
+ Update a shape description in the simulation canvas (computation)
+ according to the new parameters of the GUI canvas.
+ @param sph: Sphere object from the GUI canvas
+ """
+ # Check class
+ if self.sim_canvas.shapes[sph.name].__class__.__name__=="SphereDescriptor":
+ desc = self.sim_canvas.shapes[sph.name]
+
+ desc.params["center"] = [sph.x, sph.y, sph.z]
+ desc.params["order"] = sph.params["order"]
+ # Radius of the sphere
+ desc.params["radius"] = sph.params["radius"]
+ # Constrast parameter
+ desc.params["contrast"] = sph.params["contrast"]
+
+ self.sim_canvas._model_changed()
+ else:
+ raise ValueError, "SimShapeVisitor: Wrong class for visited object"
+
+
+
+ def update_cylinder(self, cyl):
+ """
+ Update a shape description in the simulation canvas (computation)
+ according to the new parameters of the GUI canvas.
+ @param cyl: Cylinder object from the GUI canvas
+ """
+ # Check class
+ if self.sim_canvas.shapes[cyl.name].__class__.__name__=="CylinderDescriptor":
+ desc = self.sim_canvas.shapes[cyl.name]
+
+ desc.params["center"] = [cyl.x, cyl.y, cyl.z]
+ # Orientation are angular offsets in degrees with respect to X, Y, Z
+ desc.params["orientation"] = [cyl.theta_x, cyl.theta_y, cyl.theta_z]
+ desc.params["order"] = cyl.params["order"]
+
+ # Length of the cylinder
+ desc.params["length"] = cyl.params["length"]
+ # Radius of the cylinder
+ desc.params["radius"] = cyl.params["radius"]
+ # Constrast parameter
+ desc.params["contrast"] = cyl.params["contrast"]
+
+ self.sim_canvas._model_changed()
+ else:
+ raise ValueError, "SimShapeVisitor: Wrong class for visited object"
+
+
+ def update(self, volCanvas, shape):
+ """
+ Update the shape descriptor in the VolumeCanvas
+ corresponding to the given 'shape' parameter
+
+ @param volCanvas: VolumeCanvas object
+ @param shape: SimCanvas.BaseShape object
+ """
+ if shape.name in volCanvas.getShapeList():
+ self.sim_canvas = volCanvas
+ shape.accept_update(self)
+ else:
+ raise ValueError, "ShapeAdapter: Shape [%s] not in list" % shape.name
+
diff --git a/src/sas/sasgui/perspectives/simulation/ShapeParameters.py b/src/sas/sasgui/perspectives/simulation/ShapeParameters.py
index f90c68e..79352e3 100644
--- a/src/sas/sasgui/perspectives/simulation/ShapeParameters.py
+++ b/src/sas/sasgui/perspectives/simulation/ShapeParameters.py
@@ -7,6 +7,8 @@ See the license text in license.txt
copyright 2009, University of Tennessee
"""
+from __future__ import print_function
+
import wx
import sys
import wx.lib.newevent
@@ -311,7 +313,7 @@ class ShapeParameterPanel(wx.Panel):
try:
self.parent.GetSizer().Layout()
except:
- print "TODO: move the Layout call of editShape up to the caller"
+ print("TODO: move the Layout call of editShape up to the caller")
def _readCtrlFloat(self, ctrl):
"""
@@ -391,8 +393,8 @@ class ShapeParameterPanel(wx.Panel):
if not tmp==None:
self.current_shape.params[item[0]] = tmp
except:
- print "Could not create"
- print sys.exc_value
+ print("Could not create")
+ print(sys.exc_value)
def _onCreate(self, evt):
"""
@@ -484,6 +486,6 @@ class ShapeParameterPanel(wx.Panel):
"""
indices = self.shape_listbox.GetSelections()
if len(indices)>0:
- print "NOT YET IMPLMENTED"
- print "renaming", self.shape_listbox.GetString(indices[0])
+ print("NOT YET IMPLMENTED")
+ print("renaming", self.shape_listbox.GetString(indices[0]))
\ No newline at end of file
diff --git a/src/sas/sasgui/perspectives/simulation/SimCanvas.py b/src/sas/sasgui/perspectives/simulation/SimCanvas.py
index 12e4e71..c6a2b8e 100644
--- a/src/sas/sasgui/perspectives/simulation/SimCanvas.py
+++ b/src/sas/sasgui/perspectives/simulation/SimCanvas.py
@@ -1,660 +1,660 @@
-"""
-This software was developed by the University of Tennessee as part of the
-Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
-project funded by the US National Science Foundation.
-
-See the license text in license.txt
-
-copyright 2009, University of Tennessee
-"""
-import wx
-import math
-
-try:
- import OpenGL
-except:
- import sys, os
- sys.path.insert(1,os.path.dirname(sys.executable))
-
-import OpenGL.GL
-try:
- from wx import glcanvas
- haveGLCanvas = True
-except ImportError:
- haveGLCanvas = False
-try:
- # The Python OpenGL package can be found at
- # http://PyOpenGL.sourceforge.net/
- from OpenGL.GL import *
- from OpenGL.GLU import *
- from OpenGL.GLUT import *
- haveOpenGL = True
-except ImportError:
- haveOpenGL = False
-
-# Color set
-DEFAULT_COLOR = [1.0, 1.0, 0.0, .2]
-COLOR_RED = [1.0, 0.0, 0.0, .2]
-COLOR_GREEN = [0.0, 1.0, 0.0, .2]
-COLOR_BLUE = [0.0, 0.0, 1.0, .2]
-COLOR_YELLOW = [1.0, 1.0, 0.0, .2]
-COLOR_HIGHLIGHT = [.2, .2, .8, .5]
-
-# List of shapes
-SHAPE_LIST = []
-
-import ShapeParameters
-
-class SimPanel(wx.Panel):
- """
- 3D viewer to support real-space simulation.
- """
- window_name = "3dview"
- window_caption = "3D viewer"
-
- def __init__(self, parent, id = -1, plots = None, standalone=False, **kwargs):
- wx.Panel.__init__(self, parent, id = id, **kwargs)
- self.parent = parent
-
- #Add a sizer
- mainSizer = wx.BoxSizer(wx.VERTICAL)
- sliderSizer = wx.BoxSizer(wx.HORIZONTAL)
-
- self.canvas = CanvasBase(self)
- self.canvas.SetMinSize((200,2100))
-
- #Add the model to it's sizer
- mainSizer.Add(self.canvas, 1, wx.EXPAND)
-
- #Add the Subsizers to mainsizer
- mainSizer.Add(sliderSizer, 0, wx.EXPAND)
-
- self.SetSizer(mainSizer)
- self.Bind(wx.EVT_CONTEXT_MENU, self._on_context_menu)
-
-
- def _on_context_menu(self, event):
- """
- Default context menu for a plot panel
- """
- # Slicer plot popup menu
- id = wx.NewId()
- slicerpop = wx.Menu()
- slicerpop.Append(id, '&Reset 3D View')
- wx.EVT_MENU(self, id, self.canvas.resetView)
-
- pos = event.GetPosition()
- pos = self.ScreenToClient(pos)
- self.PopupMenu(slicerpop, pos)
-
-class CanvasBase(glcanvas.GLCanvas):
- """
- 3D canvas to display OpenGL 3D shapes
- """
- window_name = "Simulation"
- window_caption = "Simulation"
-
- def __init__(self, parent):
- glcanvas.GLCanvas.__init__(self, parent, -1)
- self.init = False
- # initial mouse position
- self.lastx = self.x = 30
- self.lasty = self.y = 30
- self.tr_lastx = self.tr_x = 30
- self.tr_lasty = self.tr_y = 30
- self.size = None
- self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
- self.Bind(wx.EVT_SIZE, self.OnSize)
- self.Bind(wx.EVT_PAINT, self.OnPaint)
- self.Bind(wx.EVT_LEFT_DOWN, self.OnMouseDown)
- self.Bind(wx.EVT_RIGHT_DOWN, self.OnMouseDown)
- self.Bind(wx.EVT_LEFT_UP, self.OnMouseUp)
- self.Bind(wx.EVT_RIGHT_UP, self.OnRightUp)
- self.Bind(wx.EVT_MOTION, self.OnMouseMotion)
- self.Bind(wx.EVT_MOUSEWHEEL, self._onMouseWheel)
-
- self.initialized = False
- self.shapes = []
- self.parent = parent
-
- # Reference vectors
- self.x_vec = [1,0,0]
- self.y_vec = [0,1,0]
-
- self.mouse_down = False
- self.scale = 1.0
- self.zoom = 1.0
- self.translation = [0,0,0]
-
- # Bind to Edit events
- self.parent.Bind(ShapeParameters.EVT_EDIT_SHAPE, self._onEditShape)
-
- def resetView(self, evt=None):
- """
- Resets zooming, translation and rotation.
- """
- self.zoom = 1.0
- self.scale = 1.0
- self.x_vec = [1,0,0]
- self.y_vec = [0,1,0]
- glLoadIdentity()
- self.Refresh()
-
- def _onEditShape(self, evt):
- evt.Skip()
- evt.shape.highlight(True)
- for item in self.shapes:
- if not item == evt.shape:
- item.highlight(False)
- self.Refresh(False)
-
- def OnEraseBackground(self, event):
- pass # Do nothing, to avoid flashing on MSW.
-
- def OnSize(self, event):
- size = self.size = self.GetClientSize()
- if self.GetContext():
- glViewport(0, 0, size.width, size.height)
- event.Skip()
-
- def OnPaint(self, event):
- size = self.GetClientSize()
- side = size.width
- if size.height<size.width:
- side = size.height
-
- if self.GetContext():
- glViewport(0, 0, side, side)
- self.SetMinSize((side,side))
-
- dc = wx.PaintDC(self)
- self.SetCurrent()
- if not self.init:
- self.InitGL()
- self.init = True
- self.OnDraw()
- event.Skip()
-
- def _onMouseWheel(self, evt):
- # Initialize mouse position so we don't have unwanted rotation
- self.x, self.y = self.lastx, self.lasty = evt.GetPosition()
- self.tr_x, self.tr_y = self.tr_lastx, self.tr_lasty = evt.GetPosition()
-
- scale = 1.15
- if evt.GetWheelRotation()<0:
- scale = 1.0/scale
-
- self.zoom *= scale
-
- glScale(scale, scale, scale)
- self.Refresh(False)
-
- def OnMouseDown(self, evt):
- self.SetFocus()
- self.CaptureMouse()
- self.x, self.y = self.lastx, self.lasty = evt.GetPosition()
- self.tr_x, self.tr_y = self.tr_lastx, self.tr_lasty = self.x, self.y
- self.mouse_down = True
-
- def OnMouseUp(self, evt):
- self.ReleaseMouse()
- self.mouse_down = False
-
- def OnRightUp(self, evt):
- self.OnMouseUp(evt)
- if self.x==self.tr_lastx and self.y==self.tr_lasty:
- self._on_context_menu(evt)
-
- def _on_context_menu(self, event):
- """
- Default context menu for a plot panel
- """
- id = wx.NewId()
- slicerpop = wx.Menu()
- slicerpop.Append(id, '&Reset 3D View')
- wx.EVT_MENU(self, id, self.resetView)
-
- pos = event.GetPosition()
- #pos = self.ScreenToClient(pos)
- self.PopupMenu(slicerpop, pos)
-
- def OnMouseMotion(self, evt):
- if evt.Dragging() and evt.LeftIsDown():
- self.tr_lastx, self.tr_lasty = self.tr_x, self.tr_y
- x, y = evt.GetPosition()
-
- # Min distance to do anything
- if math.fabs(self.lastx-x)>10 or math.fabs(self.lasty-y)>10:
-
- self.lastx, self.lasty = self.x, self.y
-
-
- if math.fabs(self.lastx-x)>math.fabs(self.lasty-y):
- self.x = x
- else:
- self.y = y
-
- #self.x, self.y = evt.GetPosition()
- self.Refresh(False)
-
- elif evt.Dragging() and evt.RightIsDown():
- self.lastx, self.lasty = self.x, self.y
- self.tr_lastx, self.tr_lasty = self.tr_x, self.tr_y
- self.tr_x, self.tr_y = evt.GetPosition()
- self.Refresh(False)
-
- def InitGL( self ):
- glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGBA)
- #glShadeModel(GL_FLAT);
-
- glMatrixMode(GL_PROJECTION)
-
- glLight(GL_LIGHT0, GL_AMBIENT, [.2, .2, .2, 0])
-
- # Object color
- #glLight(GL_LIGHT0, GL_DIFFUSE, COLOR_BLUE)
-
- glLight(GL_LIGHT0, GL_POSITION, [1.0, 1.0, -1.0, 0.0])
-
-
- glLightModelfv(GL_LIGHT_MODEL_AMBIENT, [1, 1, 1, 0])
- glEnable(GL_LIGHTING)
- glEnable(GL_LIGHT0)
- glEnable(GL_BLEND)
- glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
- glEnable ( GL_ALPHA_TEST ) ;
- glAlphaFunc ( GL_GREATER, 0 ) ;
- glPixelStorei(GL_PACK_ALIGNMENT, 1)
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
-
- glEnable(GL_NORMALIZE)
- glDepthFunc(GL_LESS)
- glEnable(GL_DEPTH_TEST)
- glDepthMask(GL_TRUE);
- glClearColor (1.0, 1.0, 1.0, 0.0);
- #glClear (GL_COLOR_BUFFER_BIT);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
-
-
- gluPerspective(0, 1.0, 0.1, 60.0);
-
- glMatrixMode(GL_MODELVIEW)
-
- def getMaxSize(self):
- max_size = 0.0
- # Ready to draw shapes
- for item in self.shapes:
- item.draw()
- l = item.get_length()
- if l>max_size:
- max_size = l
- return max_size
-
- def OnDraw(self):
- # clear color and depth buffers
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
- # use a fresh transformation matrix
-
- # get the max object size to re-scale
- max_size = 1.0
- # Ready to draw shapes
- for item in self.shapes:
- item.draw()
- l = item.get_length()
- if l>max_size:
- max_size = l
-
- max_size *= 1.05
- scale = self.scale/max_size
- glScale(scale, scale, scale)
- self.scale = max_size
-
- self.drawAxes()
-
- if self.mouse_down:
- if math.fabs((self.x - self.lastx))>math.fabs((self.y - self.lasty)):
- angle = 10.0*(self.x - self.lastx) / math.fabs(self.x - self.lastx)
- glRotate(angle, self.y_vec[0], self.y_vec[1], self.y_vec[2]);
- self._rot_y(angle)
- elif math.fabs(self.y - self.lasty)>0:
- angle = 10.0*(self.y - self.lasty) / math.fabs(self.y - self.lasty)
- glRotate(angle, self.x_vec[0], self.x_vec[1], self.x_vec[2]);
- self._rot_x(angle)
-
- self.lasty = self.y
- self.lastx = self.x
-
- w,h = self.GetVirtualSizeTuple()
-
- # Translate in the x-y plane
- vx = self.x_vec[0] * 2.0*float(self.tr_x - self.tr_lastx)/w \
- + self.y_vec[0] * 2.0*float(self.tr_lasty - self.tr_y)/h
- vy = self.x_vec[1] * 2.0*float(self.tr_x - self.tr_lastx)/w \
- + self.y_vec[1] * 2.0*float(self.tr_lasty - self.tr_y)/h
- vz = self.x_vec[2] * 2.0*float(self.tr_x - self.tr_lastx)/w \
- + self.y_vec[2] * 2.0*float(self.tr_lasty - self.tr_y)/h
-
- glTranslate(self.scale*vx/self.zoom, self.scale*vy/self.zoom, self.scale*vz/self.zoom)
-
- # push into visible buffer
- self.SwapBuffers()
-
- def _matrix_mult(self, v, axis, angle):
- c = math.cos(angle)
- s = math.sin(angle)
- x = axis[0]
- y = axis[1]
- z = axis[2]
- vx = v[0]*(x*x*(1-c)+c) + v[1]*(x*y*(1-c)-z*s) + v[2]*(x*z*(1-c)+y*s)
- vy = v[0]*(y*x*(1-c)+z*s) + v[1]*(y*y*(1-c)+c) + v[2]*(y*z*(1-c)-x*s)
- vz = v[0]*(x*z*(1-c)-y*s) + v[1]*(y*z*(1-c)+x*s) + v[2]*(z*z*(1-c)+c)
- return [vx, vy, vz]
-
- def _rot_y(self, theta):
- """
- Rotate the view by theta around the y-axis
- """
- angle = theta/180.0*math.pi
- axis = self.y_vec
- self.x_vec = self._matrix_mult(self.x_vec, self.y_vec, -angle)
-
- def _rot_x(self, theta):
- """
- Rotate the view by theta around the x-axis
- """
- angle = theta/180.0*math.pi
- self.y_vec = self._matrix_mult(self.y_vec, self.x_vec, -angle)
-
-
- def addShape(self, shape, name=None):
- """
- Add a shape to the list of displayed shapes
- @param shape: BaseShape object
- @param name: name given to the shape
- """
- if not name==None:
- shape.name = name
- shape.params['order']=len(self.shapes)
- self.shapes.append(shape)
- self.Refresh(False)
-
- def delShape(self, name):
- """
- Delete a shape by name
- @param name: name of the shape to be deleted
- """
- for i in range(len(self.shapes)):
- if self.shapes[i].name == name:
- del self.shapes[i]
- break
- self.Refresh(False)
-
- def getMaxVolume(self):
- """
- Returns the maximum volume of the combination of all shapes.
- The maximum volume is the simple sum of the volumes of all the shapes.
- @return: sum of the volumes of all the shapes [float]
- """
- sum = 0
- for item in self.shapes:
- sum += item.get_volume()
- return sum
-
- def drawAxes(self):
- """
- Draw 3D axes
- """
- pos = self.scale * 0.7
-
- # Z-axis is red
- zaxis= Arrow(x=pos, y=-pos, z=0, r_cyl=self.scale*0.005, r_cone=self.scale*0.01,
- l_cyl=self.scale*0.1, l_cone=self.scale*0.05)
- zaxis.color = COLOR_RED
- zaxis.draw()
-
- # Y-axis is yellow
- yaxis= Arrow(x=pos, y=-pos, z=0, r_cyl=self.scale*0.005, r_cone=self.scale*0.01,
- l_cyl=self.scale*0.1, l_cone=self.scale*0.05)
- yaxis.color = COLOR_YELLOW
- yaxis.rotate(-90,0,0)
- yaxis.draw()
-
- # X-axis is green
- xaxis= Arrow(x=pos, y=-pos, z=0, r_cyl=self.scale*0.005, r_cone=self.scale*0.01,
- l_cyl=self.scale*0.1, l_cone=self.scale*0.05)
- xaxis.color = COLOR_GREEN
- xaxis.rotate(0,-90,0)
- xaxis.draw()
-
- glLight(GL_LIGHT0, GL_DIFFUSE, DEFAULT_COLOR)
-
-
-class BaseShape:
- """
- Basic shape functionality
- """
- def __init__(self, x=0, y=0, z=0):
- self.name = ''
- ## Position
- self.x = x
- self.y = y
- self.z = z
- ## Orientation
- self.theta_x = 0
- self.theta_y = 0
- self.theta_z = 0
-
- # Params
- self.params = {}
- self.params['contrast'] = 1.0
- self.params['order'] = 0
- self.details = {}
- self.details['contrast'] = 'A-2'
- self.details['order'] = ' '
-
- self.highlighted = False
- self.color = DEFAULT_COLOR
-
- def get_volume(self):
- return 0
-
- def get_length(self):
- return 1.0
-
- def highlight(self, value=False):
- self.highlighted = value
-
- def rotate(self, alpha, beta, gamma):
- """
- Set the rotation angles of the shape
- @param alpha: angle around the x-axis [degrees]
- @param beta: angle around the y-axis [degrees]
- @param gamma: angle around the z-axis [degrees]
- """
- self.theta_x = alpha
- self.theta_y = beta
- self.theta_z = gamma
-
- def _rotate(self):
- """
- Perform the OpenGL rotation
-
- Note that the rotation order is reversed.
- We do Y, X, Z do be compatible with simulation...
- """
-
- glRotated(self.theta_z, 0, 0, 1)
- glRotated(self.theta_x, 1, 0, 0)
- glRotated(self.theta_y, 0, 1, 0)
-
- def _pre_draw(self):
- if self.highlighted:
- glLight(GL_LIGHT0, GL_DIFFUSE, COLOR_HIGHLIGHT)
- else:
- glLight(GL_LIGHT0, GL_DIFFUSE, self.color)
-
-
-class Arrow(BaseShape):
- """
- Arrow shape used to show the three axes
- """
- def __init__(self, x=0, y=0, z=0, r_cyl=0.01, r_cone=0.02, l_cyl=0.3, l_cone=0.1):
- BaseShape.__init__(self, x, y, z)
- self.r_cyl = r_cyl
- self.r_cone = r_cone
- self.l_cyl = l_cyl
- self.l_cone = l_cone
-
- def draw(self):
- self._pre_draw()
- glPushMatrix()
- glTranslate(self.x, self.y, self.z)
-
- # Perform rotation
- glRotate(self.theta_x, 1, 0, 0)
- glRotate(self.theta_y, 0, 1, 0)
- glRotate(self.theta_z, 0, 0, 1)
-
- # Draw axis cylinder
- qobj = gluNewQuadric();
- gluCylinder(qobj, self.r_cyl, self.r_cyl, self.l_cyl, 15, 5);
-
- glTranslate(0, 0, self.z+self.l_cyl)
-
- # Draw cone of the arrow
- glutSolidCone(self.r_cone, self.l_cone, 30, 5)
-
- # Translate back to original position
- glTranslate(-self.x, -self.y, -self.z)
- glPopMatrix()
-
-class Cone(BaseShape):
- """
- Conical shape
- """
- def __init__(self, x=0, y=0, z=0, radius=0.5, height=1):
- BaseShape.__init__(self, x, y, z)
- self.radius = radius
- self.height = height
-
- def draw(self):
- glPushMatrix()
- glTranslate(self.x, self.y, self.z)
- glutSolidCone(self.radius, self.height, 30, 5)
- self._rotate()
- glTranslate(-self.x, -self.y, -self.z)
- glPopMatrix()
-
-class Sphere(BaseShape):
- """
- Spherical shape
- """
- def __init__(self, x=0, y=0, z=0, radius=10.0):
- BaseShape.__init__(self, x, y, z)
- self.name = 'sphere'
- self.params['radius'] = radius
- self.details['radius'] = 'A'
-
- def get_volume(self):
- return 4.0/3.0*math.pi*self.params['radius']*self.params['radius']*self.params['radius']
-
- def get_length(self):
- return 2.0*self.params['radius']
-
- def draw(self):
- self._pre_draw()
- glPushMatrix()
- glTranslate(self.x, self.y, self.z)
- #glutSolidSphere(self.params['radius'], 30, 30)
- qobj = gluNewQuadric();
- #gluQuadricDrawStyle(qobj,GLU_SILHOUETTE)
- gluSphere(qobj,self.params['radius'], 30, 30)
- glTranslate(-self.x, -self.y, -self.z)
- glPopMatrix()
- glLight(GL_LIGHT0, GL_DIFFUSE, DEFAULT_COLOR)
-
- def accept(self, visitor):
- return visitor.fromSphere(self)
-
- def accept_update(self, visitor):
- return visitor.update_sphere(self)
-
-class Cylinder(BaseShape):
- """
- Cylinder shape, by default the cylinder is oriented along
- the z-axis.
-
- The reference point of the cylinder is the center of the
- bottom circle.
- """
- def __init__(self, x=0, y=0, z=0, radius=10.0, length=100.0):
- BaseShape.__init__(self, x, y, z)
- self.name = 'cylinder'
- self.params['radius'] = radius
- self.params['length'] = length
- self.details['radius'] = 'A'
- self.details['length'] = 'A'
-
- def get_volume(self):
- return math.pi*self.params['radius']*self.params['radius']*self.params['length']
-
- def get_length(self):
- if self.params['length']>2.0*self.params['radius']:
- return self.params['length']
- else:
- return 2.0*self.params['radius']
-
- def draw(self):
- self._pre_draw()
- glPushMatrix()
-
- glTranslate(self.x, self.y, self.z)
- self._rotate()
- qobj = gluNewQuadric();
- # gluCylinder(qobj, r_base, r_top, L, div around z, div along z)
- gluCylinder(qobj, self.params['radius'], self.params['radius'], self.params['length'], 15, 5);
-
- glTranslate(-self.x, -self.y, -self.z)
- glPopMatrix()
- glLight(GL_LIGHT0, GL_DIFFUSE, DEFAULT_COLOR)
-
- def accept(self, visitor):
- return visitor.fromCylinder(self)
-
- def accept_update(self, visitor):
- return visitor.update_cylinder(self)
-
-# Fill the shape list
-SHAPE_LIST.append(dict(name='Sphere', id=wx.NewId(), cl=Sphere))
-SHAPE_LIST.append(dict(name='Cylinder', id=wx.NewId(), cl=Cylinder))
-
-def getShapes():
- """
- Returns a list of all available shapes
- """
- return SHAPE_LIST
-
-def getShapeClass(id):
- """
- Returns a child class of BaseShape corresponding
- to the supplied shape ID.
- @param id: shape ID number
- """
- def f(s): return s['id']==id
- if SHAPE_LIST is not None:
- shape = filter(f, SHAPE_LIST)
- return shape[0]['cl']
- return None
-
-def getShapeClassByName(name):
- """
- Returns a child class of BaseShape corresponding
- to the supplied shape name.
- @param name: shape name
- """
- def f(s): return s['name']==name
- if SHAPE_LIST is not None:
- shape = filter(f, SHAPE_LIST)
- return shape[0]['cl']
- return None
+"""
+This software was developed by the University of Tennessee as part of the
+Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
+project funded by the US National Science Foundation.
+
+See the license text in license.txt
+
+copyright 2009, University of Tennessee
+"""
+import wx
+import math
+
+try:
+ import OpenGL
+except:
+ import sys, os
+ sys.path.insert(1,os.path.dirname(sys.executable))
+
+import OpenGL.GL
+try:
+ from wx import glcanvas
+ haveGLCanvas = True
+except ImportError:
+ haveGLCanvas = False
+try:
+ # The Python OpenGL package can be found at
+ # http://PyOpenGL.sourceforge.net/
+ from OpenGL.GL import *
+ from OpenGL.GLU import *
+ from OpenGL.GLUT import *
+ haveOpenGL = True
+except ImportError:
+ haveOpenGL = False
+
+# Color set
+DEFAULT_COLOR = [1.0, 1.0, 0.0, .2]
+COLOR_RED = [1.0, 0.0, 0.0, .2]
+COLOR_GREEN = [0.0, 1.0, 0.0, .2]
+COLOR_BLUE = [0.0, 0.0, 1.0, .2]
+COLOR_YELLOW = [1.0, 1.0, 0.0, .2]
+COLOR_HIGHLIGHT = [.2, .2, .8, .5]
+
+# List of shapes
+SHAPE_LIST = []
+
+import ShapeParameters
+
+class SimPanel(wx.Panel):
+ """
+ 3D viewer to support real-space simulation.
+ """
+ window_name = "3dview"
+ window_caption = "3D viewer"
+
+ def __init__(self, parent, id = -1, plots = None, standalone=False, **kwargs):
+ wx.Panel.__init__(self, parent, id = id, **kwargs)
+ self.parent = parent
+
+ #Add a sizer
+ mainSizer = wx.BoxSizer(wx.VERTICAL)
+ sliderSizer = wx.BoxSizer(wx.HORIZONTAL)
+
+ self.canvas = CanvasBase(self)
+ self.canvas.SetMinSize((200,2100))
+
+ #Add the model to it's sizer
+ mainSizer.Add(self.canvas, 1, wx.EXPAND)
+
+ #Add the Subsizers to mainsizer
+ mainSizer.Add(sliderSizer, 0, wx.EXPAND)
+
+ self.SetSizer(mainSizer)
+ self.Bind(wx.EVT_CONTEXT_MENU, self._on_context_menu)
+
+
+ def _on_context_menu(self, event):
+ """
+ Default context menu for a plot panel
+ """
+ # Slicer plot popup menu
+ id = wx.NewId()
+ slicerpop = wx.Menu()
+ slicerpop.Append(id, '&Reset 3D View')
+ wx.EVT_MENU(self, id, self.canvas.resetView)
+
+ pos = event.GetPosition()
+ pos = self.ScreenToClient(pos)
+ self.PopupMenu(slicerpop, pos)
+
+class CanvasBase(glcanvas.GLCanvas):
+ """
+ 3D canvas to display OpenGL 3D shapes
+ """
+ window_name = "Simulation"
+ window_caption = "Simulation"
+
+ def __init__(self, parent):
+ glcanvas.GLCanvas.__init__(self, parent, -1)
+ self.init = False
+ # initial mouse position
+ self.lastx = self.x = 30
+ self.lasty = self.y = 30
+ self.tr_lastx = self.tr_x = 30
+ self.tr_lasty = self.tr_y = 30
+ self.size = None
+ self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
+ self.Bind(wx.EVT_SIZE, self.OnSize)
+ self.Bind(wx.EVT_PAINT, self.OnPaint)
+ self.Bind(wx.EVT_LEFT_DOWN, self.OnMouseDown)
+ self.Bind(wx.EVT_RIGHT_DOWN, self.OnMouseDown)
+ self.Bind(wx.EVT_LEFT_UP, self.OnMouseUp)
+ self.Bind(wx.EVT_RIGHT_UP, self.OnRightUp)
+ self.Bind(wx.EVT_MOTION, self.OnMouseMotion)
+ self.Bind(wx.EVT_MOUSEWHEEL, self._onMouseWheel)
+
+ self.initialized = False
+ self.shapes = []
+ self.parent = parent
+
+ # Reference vectors
+ self.x_vec = [1,0,0]
+ self.y_vec = [0,1,0]
+
+ self.mouse_down = False
+ self.scale = 1.0
+ self.zoom = 1.0
+ self.translation = [0,0,0]
+
+ # Bind to Edit events
+ self.parent.Bind(ShapeParameters.EVT_EDIT_SHAPE, self._onEditShape)
+
+ def resetView(self, evt=None):
+ """
+ Resets zooming, translation and rotation.
+ """
+ self.zoom = 1.0
+ self.scale = 1.0
+ self.x_vec = [1,0,0]
+ self.y_vec = [0,1,0]
+ glLoadIdentity()
+ self.Refresh()
+
+ def _onEditShape(self, evt):
+ evt.Skip()
+ evt.shape.highlight(True)
+ for item in self.shapes:
+ if not item == evt.shape:
+ item.highlight(False)
+ self.Refresh(False)
+
+ def OnEraseBackground(self, event):
+ pass # Do nothing, to avoid flashing on MSW.
+
+ def OnSize(self, event):
+ size = self.size = self.GetClientSize()
+ if self.GetContext():
+ glViewport(0, 0, size.width, size.height)
+ event.Skip()
+
+ def OnPaint(self, event):
+ size = self.GetClientSize()
+ side = size.width
+ if size.height<size.width:
+ side = size.height
+
+ if self.GetContext():
+ glViewport(0, 0, side, side)
+ self.SetMinSize((side,side))
+
+ dc = wx.PaintDC(self)
+ self.SetCurrent()
+ if not self.init:
+ self.InitGL()
+ self.init = True
+ self.OnDraw()
+ event.Skip()
+
+ def _onMouseWheel(self, evt):
+ # Initialize mouse position so we don't have unwanted rotation
+ self.x, self.y = self.lastx, self.lasty = evt.GetPosition()
+ self.tr_x, self.tr_y = self.tr_lastx, self.tr_lasty = evt.GetPosition()
+
+ scale = 1.15
+ if evt.GetWheelRotation()<0:
+ scale = 1.0/scale
+
+ self.zoom *= scale
+
+ glScale(scale, scale, scale)
+ self.Refresh(False)
+
+ def OnMouseDown(self, evt):
+ self.SetFocus()
+ self.CaptureMouse()
+ self.x, self.y = self.lastx, self.lasty = evt.GetPosition()
+ self.tr_x, self.tr_y = self.tr_lastx, self.tr_lasty = self.x, self.y
+ self.mouse_down = True
+
+ def OnMouseUp(self, evt):
+ self.ReleaseMouse()
+ self.mouse_down = False
+
+ def OnRightUp(self, evt):
+ self.OnMouseUp(evt)
+ if self.x==self.tr_lastx and self.y==self.tr_lasty:
+ self._on_context_menu(evt)
+
+ def _on_context_menu(self, event):
+ """
+ Default context menu for a plot panel
+ """
+ id = wx.NewId()
+ slicerpop = wx.Menu()
+ slicerpop.Append(id, '&Reset 3D View')
+ wx.EVT_MENU(self, id, self.resetView)
+
+ pos = event.GetPosition()
+ #pos = self.ScreenToClient(pos)
+ self.PopupMenu(slicerpop, pos)
+
+ def OnMouseMotion(self, evt):
+ if evt.Dragging() and evt.LeftIsDown():
+ self.tr_lastx, self.tr_lasty = self.tr_x, self.tr_y
+ x, y = evt.GetPosition()
+
+ # Min distance to do anything
+ if math.fabs(self.lastx-x)>10 or math.fabs(self.lasty-y)>10:
+
+ self.lastx, self.lasty = self.x, self.y
+
+
+ if math.fabs(self.lastx-x)>math.fabs(self.lasty-y):
+ self.x = x
+ else:
+ self.y = y
+
+ #self.x, self.y = evt.GetPosition()
+ self.Refresh(False)
+
+ elif evt.Dragging() and evt.RightIsDown():
+ self.lastx, self.lasty = self.x, self.y
+ self.tr_lastx, self.tr_lasty = self.tr_x, self.tr_y
+ self.tr_x, self.tr_y = evt.GetPosition()
+ self.Refresh(False)
+
+ def InitGL( self ):
+ glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGBA)
+ #glShadeModel(GL_FLAT);
+
+ glMatrixMode(GL_PROJECTION)
+
+ glLight(GL_LIGHT0, GL_AMBIENT, [.2, .2, .2, 0])
+
+ # Object color
+ #glLight(GL_LIGHT0, GL_DIFFUSE, COLOR_BLUE)
+
+ glLight(GL_LIGHT0, GL_POSITION, [1.0, 1.0, -1.0, 0.0])
+
+
+ glLightModelfv(GL_LIGHT_MODEL_AMBIENT, [1, 1, 1, 0])
+ glEnable(GL_LIGHTING)
+ glEnable(GL_LIGHT0)
+ glEnable(GL_BLEND)
+ glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ glEnable ( GL_ALPHA_TEST ) ;
+ glAlphaFunc ( GL_GREATER, 0 ) ;
+ glPixelStorei(GL_PACK_ALIGNMENT, 1)
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
+
+ glEnable(GL_NORMALIZE)
+ glDepthFunc(GL_LESS)
+ glEnable(GL_DEPTH_TEST)
+ glDepthMask(GL_TRUE);
+ glClearColor (1.0, 1.0, 1.0, 0.0);
+ #glClear (GL_COLOR_BUFFER_BIT);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
+
+
+ gluPerspective(0, 1.0, 0.1, 60.0);
+
+ glMatrixMode(GL_MODELVIEW)
+
+ def getMaxSize(self):
+ max_size = 0.0
+ # Ready to draw shapes
+ for item in self.shapes:
+ item.draw()
+ l = item.get_length()
+ if l>max_size:
+ max_size = l
+ return max_size
+
+ def OnDraw(self):
+ # clear color and depth buffers
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
+ # use a fresh transformation matrix
+
+ # get the max object size to re-scale
+ max_size = 1.0
+ # Ready to draw shapes
+ for item in self.shapes:
+ item.draw()
+ l = item.get_length()
+ if l>max_size:
+ max_size = l
+
+ max_size *= 1.05
+ scale = self.scale/max_size
+ glScale(scale, scale, scale)
+ self.scale = max_size
+
+ self.drawAxes()
+
+ if self.mouse_down:
+ if math.fabs((self.x - self.lastx))>math.fabs((self.y - self.lasty)):
+ angle = 10.0*(self.x - self.lastx) / math.fabs(self.x - self.lastx)
+ glRotate(angle, self.y_vec[0], self.y_vec[1], self.y_vec[2]);
+ self._rot_y(angle)
+ elif math.fabs(self.y - self.lasty)>0:
+ angle = 10.0*(self.y - self.lasty) / math.fabs(self.y - self.lasty)
+ glRotate(angle, self.x_vec[0], self.x_vec[1], self.x_vec[2]);
+ self._rot_x(angle)
+
+ self.lasty = self.y
+ self.lastx = self.x
+
+ w,h = self.GetVirtualSizeTuple()
+
+ # Translate in the x-y plane
+ vx = self.x_vec[0] * 2.0*float(self.tr_x - self.tr_lastx)/w \
+ + self.y_vec[0] * 2.0*float(self.tr_lasty - self.tr_y)/h
+ vy = self.x_vec[1] * 2.0*float(self.tr_x - self.tr_lastx)/w \
+ + self.y_vec[1] * 2.0*float(self.tr_lasty - self.tr_y)/h
+ vz = self.x_vec[2] * 2.0*float(self.tr_x - self.tr_lastx)/w \
+ + self.y_vec[2] * 2.0*float(self.tr_lasty - self.tr_y)/h
+
+ glTranslate(self.scale*vx/self.zoom, self.scale*vy/self.zoom, self.scale*vz/self.zoom)
+
+ # push into visible buffer
+ self.SwapBuffers()
+
+ def _matrix_mult(self, v, axis, angle):
+ c = math.cos(angle)
+ s = math.sin(angle)
+ x = axis[0]
+ y = axis[1]
+ z = axis[2]
+ vx = v[0]*(x*x*(1-c)+c) + v[1]*(x*y*(1-c)-z*s) + v[2]*(x*z*(1-c)+y*s)
+ vy = v[0]*(y*x*(1-c)+z*s) + v[1]*(y*y*(1-c)+c) + v[2]*(y*z*(1-c)-x*s)
+ vz = v[0]*(x*z*(1-c)-y*s) + v[1]*(y*z*(1-c)+x*s) + v[2]*(z*z*(1-c)+c)
+ return [vx, vy, vz]
+
+ def _rot_y(self, theta):
+ """
+ Rotate the view by theta around the y-axis
+ """
+ angle = theta/180.0*math.pi
+ axis = self.y_vec
+ self.x_vec = self._matrix_mult(self.x_vec, self.y_vec, -angle)
+
+ def _rot_x(self, theta):
+ """
+ Rotate the view by theta around the x-axis
+ """
+ angle = theta/180.0*math.pi
+ self.y_vec = self._matrix_mult(self.y_vec, self.x_vec, -angle)
+
+
+ def addShape(self, shape, name=None):
+ """
+ Add a shape to the list of displayed shapes
+ @param shape: BaseShape object
+ @param name: name given to the shape
+ """
+ if not name==None:
+ shape.name = name
+ shape.params['order']=len(self.shapes)
+ self.shapes.append(shape)
+ self.Refresh(False)
+
+ def delShape(self, name):
+ """
+ Delete a shape by name
+ @param name: name of the shape to be deleted
+ """
+ for i in range(len(self.shapes)):
+ if self.shapes[i].name == name:
+ del self.shapes[i]
+ break
+ self.Refresh(False)
+
+ def getMaxVolume(self):
+ """
+ Returns the maximum volume of the combination of all shapes.
+ The maximum volume is the simple sum of the volumes of all the shapes.
+ @return: sum of the volumes of all the shapes [float]
+ """
+ sum = 0
+ for item in self.shapes:
+ sum += item.get_volume()
+ return sum
+
+ def drawAxes(self):
+ """
+ Draw 3D axes
+ """
+ pos = self.scale * 0.7
+
+ # Z-axis is red
+ zaxis= Arrow(x=pos, y=-pos, z=0, r_cyl=self.scale*0.005, r_cone=self.scale*0.01,
+ l_cyl=self.scale*0.1, l_cone=self.scale*0.05)
+ zaxis.color = COLOR_RED
+ zaxis.draw()
+
+ # Y-axis is yellow
+ yaxis= Arrow(x=pos, y=-pos, z=0, r_cyl=self.scale*0.005, r_cone=self.scale*0.01,
+ l_cyl=self.scale*0.1, l_cone=self.scale*0.05)
+ yaxis.color = COLOR_YELLOW
+ yaxis.rotate(-90,0,0)
+ yaxis.draw()
+
+ # X-axis is green
+ xaxis= Arrow(x=pos, y=-pos, z=0, r_cyl=self.scale*0.005, r_cone=self.scale*0.01,
+ l_cyl=self.scale*0.1, l_cone=self.scale*0.05)
+ xaxis.color = COLOR_GREEN
+ xaxis.rotate(0,-90,0)
+ xaxis.draw()
+
+ glLight(GL_LIGHT0, GL_DIFFUSE, DEFAULT_COLOR)
+
+
+class BaseShape:
+ """
+ Basic shape functionality
+ """
+ def __init__(self, x=0, y=0, z=0):
+ self.name = ''
+ ## Position
+ self.x = x
+ self.y = y
+ self.z = z
+ ## Orientation
+ self.theta_x = 0
+ self.theta_y = 0
+ self.theta_z = 0
+
+ # Params
+ self.params = {}
+ self.params['contrast'] = 1.0
+ self.params['order'] = 0
+ self.details = {}
+ self.details['contrast'] = 'A-2'
+ self.details['order'] = ' '
+
+ self.highlighted = False
+ self.color = DEFAULT_COLOR
+
+ def get_volume(self):
+ return 0
+
+ def get_length(self):
+ return 1.0
+
+ def highlight(self, value=False):
+ self.highlighted = value
+
+ def rotate(self, alpha, beta, gamma):
+ """
+ Set the rotation angles of the shape
+ @param alpha: angle around the x-axis [degrees]
+ @param beta: angle around the y-axis [degrees]
+ @param gamma: angle around the z-axis [degrees]
+ """
+ self.theta_x = alpha
+ self.theta_y = beta
+ self.theta_z = gamma
+
+ def _rotate(self):
+ """
+ Perform the OpenGL rotation
+
+ Note that the rotation order is reversed.
+ We do Y, X, Z do be compatible with simulation...
+ """
+
+ glRotated(self.theta_z, 0, 0, 1)
+ glRotated(self.theta_x, 1, 0, 0)
+ glRotated(self.theta_y, 0, 1, 0)
+
+ def _pre_draw(self):
+ if self.highlighted:
+ glLight(GL_LIGHT0, GL_DIFFUSE, COLOR_HIGHLIGHT)
+ else:
+ glLight(GL_LIGHT0, GL_DIFFUSE, self.color)
+
+
+class Arrow(BaseShape):
+ """
+ Arrow shape used to show the three axes
+ """
+ def __init__(self, x=0, y=0, z=0, r_cyl=0.01, r_cone=0.02, l_cyl=0.3, l_cone=0.1):
+ BaseShape.__init__(self, x, y, z)
+ self.r_cyl = r_cyl
+ self.r_cone = r_cone
+ self.l_cyl = l_cyl
+ self.l_cone = l_cone
+
+ def draw(self):
+ self._pre_draw()
+ glPushMatrix()
+ glTranslate(self.x, self.y, self.z)
+
+ # Perform rotation
+ glRotate(self.theta_x, 1, 0, 0)
+ glRotate(self.theta_y, 0, 1, 0)
+ glRotate(self.theta_z, 0, 0, 1)
+
+ # Draw axis cylinder
+ qobj = gluNewQuadric();
+ gluCylinder(qobj, self.r_cyl, self.r_cyl, self.l_cyl, 15, 5);
+
+ glTranslate(0, 0, self.z+self.l_cyl)
+
+ # Draw cone of the arrow
+ glutSolidCone(self.r_cone, self.l_cone, 30, 5)
+
+ # Translate back to original position
+ glTranslate(-self.x, -self.y, -self.z)
+ glPopMatrix()
+
+class Cone(BaseShape):
+ """
+ Conical shape
+ """
+ def __init__(self, x=0, y=0, z=0, radius=0.5, height=1):
+ BaseShape.__init__(self, x, y, z)
+ self.radius = radius
+ self.height = height
+
+ def draw(self):
+ glPushMatrix()
+ glTranslate(self.x, self.y, self.z)
+ glutSolidCone(self.radius, self.height, 30, 5)
+ self._rotate()
+ glTranslate(-self.x, -self.y, -self.z)
+ glPopMatrix()
+
+class Sphere(BaseShape):
+ """
+ Spherical shape
+ """
+ def __init__(self, x=0, y=0, z=0, radius=10.0):
+ BaseShape.__init__(self, x, y, z)
+ self.name = 'sphere'
+ self.params['radius'] = radius
+ self.details['radius'] = 'A'
+
+ def get_volume(self):
+ return 4.0/3.0*math.pi*self.params['radius']*self.params['radius']*self.params['radius']
+
+ def get_length(self):
+ return 2.0*self.params['radius']
+
+ def draw(self):
+ self._pre_draw()
+ glPushMatrix()
+ glTranslate(self.x, self.y, self.z)
+ #glutSolidSphere(self.params['radius'], 30, 30)
+ qobj = gluNewQuadric();
+ #gluQuadricDrawStyle(qobj,GLU_SILHOUETTE)
+ gluSphere(qobj,self.params['radius'], 30, 30)
+ glTranslate(-self.x, -self.y, -self.z)
+ glPopMatrix()
+ glLight(GL_LIGHT0, GL_DIFFUSE, DEFAULT_COLOR)
+
+ def accept(self, visitor):
+ return visitor.fromSphere(self)
+
+ def accept_update(self, visitor):
+ return visitor.update_sphere(self)
+
+class Cylinder(BaseShape):
+ """
+ Cylinder shape, by default the cylinder is oriented along
+ the z-axis.
+
+ The reference point of the cylinder is the center of the
+ bottom circle.
+ """
+ def __init__(self, x=0, y=0, z=0, radius=10.0, length=100.0):
+ BaseShape.__init__(self, x, y, z)
+ self.name = 'cylinder'
+ self.params['radius'] = radius
+ self.params['length'] = length
+ self.details['radius'] = 'A'
+ self.details['length'] = 'A'
+
+ def get_volume(self):
+ return math.pi*self.params['radius']*self.params['radius']*self.params['length']
+
+ def get_length(self):
+ if self.params['length']>2.0*self.params['radius']:
+ return self.params['length']
+ else:
+ return 2.0*self.params['radius']
+
+ def draw(self):
+ self._pre_draw()
+ glPushMatrix()
+
+ glTranslate(self.x, self.y, self.z)
+ self._rotate()
+ qobj = gluNewQuadric();
+ # gluCylinder(qobj, r_base, r_top, L, div around z, div along z)
+ gluCylinder(qobj, self.params['radius'], self.params['radius'], self.params['length'], 15, 5);
+
+ glTranslate(-self.x, -self.y, -self.z)
+ glPopMatrix()
+ glLight(GL_LIGHT0, GL_DIFFUSE, DEFAULT_COLOR)
+
+ def accept(self, visitor):
+ return visitor.fromCylinder(self)
+
+ def accept_update(self, visitor):
+ return visitor.update_cylinder(self)
+
+# Fill the shape list
+SHAPE_LIST.append(dict(name='Sphere', id=wx.NewId(), cl=Sphere))
+SHAPE_LIST.append(dict(name='Cylinder', id=wx.NewId(), cl=Cylinder))
+
+def getShapes():
+ """
+ Returns a list of all available shapes
+ """
+ return SHAPE_LIST
+
+def getShapeClass(id):
+ """
+ Returns a child class of BaseShape corresponding
+ to the supplied shape ID.
+ @param id: shape ID number
+ """
+ def f(s): return s['id']==id
+ if SHAPE_LIST is not None:
+ shape = filter(f, SHAPE_LIST)
+ return shape[0]['cl']
+ return None
+
+def getShapeClassByName(name):
+ """
+ Returns a child class of BaseShape corresponding
+ to the supplied shape name.
+ @param name: shape name
+ """
+ def f(s): return s['name']==name
+ if SHAPE_LIST is not None:
+ shape = filter(f, SHAPE_LIST)
+ return shape[0]['cl']
+ return None
diff --git a/src/sas/sasgui/perspectives/simulation/__init__.py b/src/sas/sasgui/perspectives/simulation/__init__.py
index 74f2d7b..77c981e 100644
--- a/src/sas/sasgui/perspectives/simulation/__init__.py
+++ b/src/sas/sasgui/perspectives/simulation/__init__.py
@@ -1,2 +1,2 @@
-PLUGIN_ID = "Simulation plug-in 1.0"
+PLUGIN_ID = "Simulation plug-in 1.0"
from simulation import *
\ No newline at end of file
diff --git a/src/sas/sasgui/perspectives/simulation/simulation.py b/src/sas/sasgui/perspectives/simulation/simulation.py
index 781a40c..0509764 100644
--- a/src/sas/sasgui/perspectives/simulation/simulation.py
+++ b/src/sas/sasgui/perspectives/simulation/simulation.py
@@ -1,332 +1,334 @@
-"""
-This software was developed by the University of Tennessee as part of the
-Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
-project funded by the US National Science Foundation.
-
-See the license text in license.txt
-
-copyright 2009, University of Tennessee
-"""
-import wx
-import os
-import numpy
-import time
-import logging
-
-# Application imports
-import SimCanvas
-import ShapeParameters
-import ShapeAdapter
-from sas.sasgui.guiframe.dataFitting import Data1D
-# Real-space simulation import
-import sas.sascalc.realspace.VolumeCanvas as VolumeCanvas
-
-from sas.sascalc.data_util.calcthread import CalcThread
-from sas.guicomm.events import NewPlotEvent, StatusEvent
-
-class Calc1D(CalcThread):
- """
- Thread object to simulate I(q)
- """
-
- def __init__(self, x, model,
- completefn = None,
- updatefn = None,
- yieldtime = 0.01,
- worktime = 0.01
- ):
- CalcThread.__init__(self,completefn,
- updatefn,
- yieldtime,
- worktime)
- self.x = x
- self.model = model
- self.starttime = 0
-
- def compute(self):
- x = self.x
- output = numpy.zeros(len(x))
- error = numpy.zeros(len(x))
-
- self.starttime = time.time()
-
- for i_x in range(len(self.x)):
- # Check whether we need to bail out
- self.isquit()
- self.update(output=output, error=error)
-
- value, err = self.model.getIqError(float(self.x[i_x]))
- output[i_x] = value
- error[i_x] = err
-
- elapsed = time.time()-self.starttime
- self.complete(output=output, error=error, elapsed=elapsed)
-
-## Default minimum q-value for simulation output
-DEFAULT_Q_MIN = 0.01
-## Default maximum q-value for simulation output
-DEFAULT_Q_MAX = 0.4
-## Default number of q point for simulation output
-DEFAULT_Q_NPTS = 10
-## Default number of real-space points per Angstrom cube
-DEFAULT_PT_DENSITY = 0.1
-
-class Plugin:
- """
- Real-space simulation plug-in for guiframe
- """
- ## Minimum q-value for simulation output
- q_min = DEFAULT_Q_MIN
- ## Maximum q-value for simulation output
- q_max = DEFAULT_Q_MAX
- ## Number of q point for simulation output
- q_npts = DEFAULT_Q_NPTS
-
- def __init__(self):
- ## Plug-in name
- self.sub_menu = "Simulation"
- ## Reference to the parent window
- self.parent = None
- ## List of panels for the simulation perspective (names)
- self.perspective = []
- # Default save location
- self._default_save_location = os.getcwd()
- # Log startup
- logging.info("Simulation plug-in started")
-
- def get_panels(self, parent):
- """
- Create and return a list of panel objects
- """
- self.parent = parent
-
- # 3D viewer
- self.plotPanel = SimCanvas.SimPanel(self.parent, -1, style=wx.RAISED_BORDER)
-
- # Central simulation panel
- self.paramPanel = ShapeParameters.ShapeParameterPanel(self.parent,
- q_min = self.q_min,
- q_max = self.q_max,
- q_npts = self.q_npts,
- pt_density = DEFAULT_PT_DENSITY,
- style=wx.RAISED_BORDER)
-
- # Simulation
- self.volCanvas = VolumeCanvas.VolumeCanvas()
- self.volCanvas.setParam('lores_density', DEFAULT_PT_DENSITY)
- self.adapter = ShapeAdapter.ShapeVisitor()
- self._data_1D = None
- self.calc_thread_1D = None
- self.speedCheck = False
- self.speed = 3.0e-7
-
- # Q-values for plotting simulated I(Q)
- step = (self.q_max-self.q_min)/(self.q_npts-1)
- self.x = numpy.arange(self.q_min, self.q_max+step*0.01, step)
-
- # Set the list of panels that are part of the simulation perspective
- self.perspective = []
- self.perspective.append(self.plotPanel.window_name)
- self.perspective.append(self.paramPanel.window_name)
-
- # Bind state events
- self.parent.Bind(ShapeParameters.EVT_ADD_SHAPE, self._onAddShape)
- self.parent.Bind(ShapeParameters.EVT_DEL_SHAPE, self._onDelShape)
- self.parent.Bind(ShapeParameters.EVT_Q_RANGE, self._on_q_range_changed)
- self.parent.Bind(ShapeParameters.EVT_PT_DENSITY, self._on_pt_density_changed)
-
- return [self.plotPanel, self.paramPanel]
-
- def _onAddShape(self, evt):
- """
- Process a user event to add a newly created
- or modified shape to the canvas
- """
- evt.Skip()
-
- # Give the new shape to the canvas
- if evt.new:
- shape = evt.shape.accept(self.adapter)
- id = self.volCanvas.addObject(shape)
- self.plotPanel.canvas.addShape(evt.shape, id)
- else:
- self.adapter.update(self.volCanvas, evt.shape)
-
- # Compute the simulated I(Q)
- self._simulate_Iq()
-
- # Refresh the 3D viewer
- self._refresh_3D_viewer()
-
- def _onDelShape(self, evt):
- """
- Remove a shape from the simulation
- """
- # Notify the simulation canvas
- self.volCanvas.delete(evt.id)
- # Notify the UI canvas
- self.plotPanel.canvas.delShape(evt.id)
-
- # Compute the simulated I(Q)
- self._simulate_Iq()
-
- # Refresh the 3D viewer
- self._refresh_3D_viewer()
-
- def _on_q_range_changed(self, evt):
- """
- Modify the Q range of the simulation output
- """
- if evt.q_min is not None:
- self.q_min = evt.q_min
- if evt.q_max is not None:
- self.q_max = evt.q_max
- if evt.npts is not None:
- self.q_npts = evt.npts
-
- # Q-values for plotting simulated I(Q)
- step = (self.q_max-self.q_min)/(self.q_npts-1)
- self.x = numpy.arange(self.q_min, self.q_max+step*0.01, step)
-
- # Compute the simulated I(Q)
- self._simulate_Iq()
-
- def _on_pt_density_changed(self, evt):
- """
- Modify the Q range of the simulation output
- """
- if evt.npts is not None:
- self.volCanvas.setParam('lores_density', evt.npts)
-
- # Compute the simulated I(Q)
- self._simulate_Iq()
-
- def _simulate_Iq(self):
- """
- Simulate I(q) using the current VolumeCanvas object.
- """
- # Check that the VolumeCanvas object exists
- if not isinstance(self.volCanvas, VolumeCanvas.VolumeCanvas):
- return
-
- # If a computation thread is running, stop it
- if self.calc_thread_1D != None and self.calc_thread_1D.isrunning():
- self.calc_thread_1D.stop()
- ## stop just raises the flag -- the thread is supposed to
- ## then kill itself. In August 2014 it was shown that this is
- ## incorrectly handled by fitting.py and a fix implemented.
- ## It is not clear that it is improperly used here so no fix
- ## is being added here.
- ##
- ## -PDB January 25, 2015
-
- # Create a computation thread
- self.calc_thread_1D = Calc1D(self.x, self.volCanvas,
- completefn=self._simulation_completed_1D,
- updatefn=None)
- self.calc_thread_1D.queue()
- self.calc_thread_1D.ready(2.5)
-
- # Evaluate maximum number of points on the canvas and the
- # maximum computation time
-
- # TODO: the getMaxVolume should be a call to the VolumeCanvas object.
- # Since the VolumeCanvas doesn't currently have that functionality, and
- # since the simulation panel holds the list of graphical representations
- # for the shapes, we will take the information from there until VolumeCanvas
- # is updated.
- npts = self.plotPanel.canvas.getMaxVolume() * self.volCanvas.params['lores_density']
-
- est = self.speed * npts * npts
- self.parent.SetStatusText("Calculation started: this might take a moment... [up to %d secs, %g points]" % (int(est), int(npts)))
-
-
- def _simulation_completed_1D(self, output, elapsed, error=None):
- """
- Called by the computation thread when the simulation is complete.
- This method processes the simulation output, plots it, and updates
- the simulation time estimate.
-
- @param output: simulated distribution I(q)
- @param elapsed: simulation time, in seconds
- @param error: standard deviation on the I(q) points
- """
- # Create the plotting event to pop up the I(Q) plot.
- new_plot = Data1D(x=self.x, y=output, dy=error)
- new_plot.name = "I(Q) Simulation"
- new_plot.group_id = "simulation_output"
- new_plot.xaxis("\\rm{Q}", 'A^{-1}')
- new_plot.yaxis("\\rm{Intensity} ","cm^{-1}")
- wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title="Simulation I(Q)"))
-
- # Create the plotting event to pop up the P(r) plot.
- r, pr = self.volCanvas.getPrData()
- new_plot = Data1D(x=r, y=pr, dy=[0]*len(r))
- new_plot.name = "P(r) Simulation"
- new_plot.group_id = "simulated_pr"
- new_plot.xaxis("\\rm{r}", 'A')
- new_plot.yaxis("\\rm{P(r)} ","cm^{-3}")
-
- wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title="Simulated P(r)"))
-
-
- # Notify the user of the simlation time and update the basic
- # simulation estimate that will allow us to estimate simulation time
- # next time we are asked to simulate.
- msg = "Calculation completed in %g secs! [%g points]" % (elapsed, self.volCanvas.npts)
- wx.PostEvent(self.parent, StatusEvent(status=msg))
- if self.volCanvas.npts>0:
- self.speed = elapsed/self.volCanvas.npts**2
-
-
- def get_perspective(self):
- """
- Get the list of panel names for this perspective
- """
- return self.perspective
-
- def populate_menu(self, id, owner):
- """
- Create a menu for the plug-in
- """
- return []
-
- def _change_point_density(self, point_density):
- """
- Placeholder for changing the simulation point density
- TODO: refactor this away by writing a single update method for the simulation parameters
- """
- self.volCanvas.setParam('lores_density', point_density)
-
- def help(self, evt):
- """
- Provide help for the simulation
- """
- pass
-
- def on_perspective(self, event):
- """
- Call back function for the perspective menu item.
- We notify the parent window that the perspective
- has changed.
- """
- self.parent.set_perspective(self.perspective)
-
- def post_init(self):
- """
- Post initialization call back to close the loose ends
- [Somehow openGL needs this call]
- """
- self.parent.set_perspective(self.perspective)
- self.parent._mgr.Update()
-
- def _refresh_3D_viewer(self):
- """
- Refresh the 3D viewer window
- #TODO: don't access data member directly
- """
- self.plotPanel.canvas.Refresh(False)
- # Give focus back to 3D canvas so that the
- # zooming works
- #self.plotPanel.canvas.SetFocus()
- #self.plotPanel.SetFocus()
+"""
+This software was developed by the University of Tennessee as part of the
+Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
+project funded by the US National Science Foundation.
+
+See the license text in license.txt
+
+copyright 2009, University of Tennessee
+"""
+import wx
+import os
+import numpy as np
+import time
+import logging
+
+# Application imports
+import SimCanvas
+import ShapeParameters
+import ShapeAdapter
+from sas.sasgui.guiframe.dataFitting import Data1D
+# Real-space simulation import
+import sas.sascalc.realspace.VolumeCanvas as VolumeCanvas
+
+from sas.sascalc.data_util.calcthread import CalcThread
+from sas.guicomm.events import NewPlotEvent, StatusEvent
+
+logger = logging.getLogger(__name__)
+
+class Calc1D(CalcThread):
+ """
+ Thread object to simulate I(q)
+ """
+
+ def __init__(self, x, model,
+ completefn = None,
+ updatefn = None,
+ yieldtime = 0.01,
+ worktime = 0.01
+ ):
+ CalcThread.__init__(self,completefn,
+ updatefn,
+ yieldtime,
+ worktime)
+ self.x = x
+ self.model = model
+ self.starttime = 0
+
+ def compute(self):
+ x = self.x
+ output = np.zeros(len(x))
+ error = np.zeros(len(x))
+
+ self.starttime = time.time()
+
+ for i_x in range(len(self.x)):
+ # Check whether we need to bail out
+ self.isquit()
+ self.update(output=output, error=error)
+
+ value, err = self.model.getIqError(float(self.x[i_x]))
+ output[i_x] = value
+ error[i_x] = err
+
+ elapsed = time.time()-self.starttime
+ self.complete(output=output, error=error, elapsed=elapsed)
+
+## Default minimum q-value for simulation output
+DEFAULT_Q_MIN = 0.01
+## Default maximum q-value for simulation output
+DEFAULT_Q_MAX = 0.4
+## Default number of q point for simulation output
+DEFAULT_Q_NPTS = 10
+## Default number of real-space points per Angstrom cube
+DEFAULT_PT_DENSITY = 0.1
+
+class Plugin:
+ """
+ Real-space simulation plug-in for guiframe
+ """
+ ## Minimum q-value for simulation output
+ q_min = DEFAULT_Q_MIN
+ ## Maximum q-value for simulation output
+ q_max = DEFAULT_Q_MAX
+ ## Number of q point for simulation output
+ q_npts = DEFAULT_Q_NPTS
+
+ def __init__(self):
+ ## Plug-in name
+ self.sub_menu = "Simulation"
+ ## Reference to the parent window
+ self.parent = None
+ ## List of panels for the simulation perspective (names)
+ self.perspective = []
+ # Default save location
+ self._default_save_location = os.getcwd()
+ # Log startup
+ logger.info("Simulation plug-in started")
+
+ def get_panels(self, parent):
+ """
+ Create and return a list of panel objects
+ """
+ self.parent = parent
+
+ # 3D viewer
+ self.plotPanel = SimCanvas.SimPanel(self.parent, -1, style=wx.RAISED_BORDER)
+
+ # Central simulation panel
+ self.paramPanel = ShapeParameters.ShapeParameterPanel(self.parent,
+ q_min = self.q_min,
+ q_max = self.q_max,
+ q_npts = self.q_npts,
+ pt_density = DEFAULT_PT_DENSITY,
+ style=wx.RAISED_BORDER)
+
+ # Simulation
+ self.volCanvas = VolumeCanvas.VolumeCanvas()
+ self.volCanvas.setParam('lores_density', DEFAULT_PT_DENSITY)
+ self.adapter = ShapeAdapter.ShapeVisitor()
+ self._data_1D = None
+ self.calc_thread_1D = None
+ self.speedCheck = False
+ self.speed = 3.0e-7
+
+ # Q-values for plotting simulated I(Q)
+ step = (self.q_max-self.q_min)/(self.q_npts-1)
+ self.x = np.arange(self.q_min, self.q_max+step*0.01, step)
+
+ # Set the list of panels that are part of the simulation perspective
+ self.perspective = []
+ self.perspective.append(self.plotPanel.window_name)
+ self.perspective.append(self.paramPanel.window_name)
+
+ # Bind state events
+ self.parent.Bind(ShapeParameters.EVT_ADD_SHAPE, self._onAddShape)
+ self.parent.Bind(ShapeParameters.EVT_DEL_SHAPE, self._onDelShape)
+ self.parent.Bind(ShapeParameters.EVT_Q_RANGE, self._on_q_range_changed)
+ self.parent.Bind(ShapeParameters.EVT_PT_DENSITY, self._on_pt_density_changed)
+
+ return [self.plotPanel, self.paramPanel]
+
+ def _onAddShape(self, evt):
+ """
+ Process a user event to add a newly created
+ or modified shape to the canvas
+ """
+ evt.Skip()
+
+ # Give the new shape to the canvas
+ if evt.new:
+ shape = evt.shape.accept(self.adapter)
+ id = self.volCanvas.addObject(shape)
+ self.plotPanel.canvas.addShape(evt.shape, id)
+ else:
+ self.adapter.update(self.volCanvas, evt.shape)
+
+ # Compute the simulated I(Q)
+ self._simulate_Iq()
+
+ # Refresh the 3D viewer
+ self._refresh_3D_viewer()
+
+ def _onDelShape(self, evt):
+ """
+ Remove a shape from the simulation
+ """
+ # Notify the simulation canvas
+ self.volCanvas.delete(evt.id)
+ # Notify the UI canvas
+ self.plotPanel.canvas.delShape(evt.id)
+
+ # Compute the simulated I(Q)
+ self._simulate_Iq()
+
+ # Refresh the 3D viewer
+ self._refresh_3D_viewer()
+
+ def _on_q_range_changed(self, evt):
+ """
+ Modify the Q range of the simulation output
+ """
+ if evt.q_min is not None:
+ self.q_min = evt.q_min
+ if evt.q_max is not None:
+ self.q_max = evt.q_max
+ if evt.npts is not None:
+ self.q_npts = evt.npts
+
+ # Q-values for plotting simulated I(Q)
+ step = (self.q_max-self.q_min)/(self.q_npts-1)
+ self.x = np.arange(self.q_min, self.q_max+step*0.01, step)
+
+ # Compute the simulated I(Q)
+ self._simulate_Iq()
+
+ def _on_pt_density_changed(self, evt):
+ """
+ Modify the Q range of the simulation output
+ """
+ if evt.npts is not None:
+ self.volCanvas.setParam('lores_density', evt.npts)
+
+ # Compute the simulated I(Q)
+ self._simulate_Iq()
+
+ def _simulate_Iq(self):
+ """
+ Simulate I(q) using the current VolumeCanvas object.
+ """
+ # Check that the VolumeCanvas object exists
+ if not isinstance(self.volCanvas, VolumeCanvas.VolumeCanvas):
+ return
+
+ # If a computation thread is running, stop it
+ if self.calc_thread_1D is not None and self.calc_thread_1D.isrunning():
+ self.calc_thread_1D.stop()
+ ## stop just raises the flag -- the thread is supposed to
+ ## then kill itself. In August 2014 it was shown that this is
+ ## incorrectly handled by fitting.py and a fix implemented.
+ ## It is not clear that it is improperly used here so no fix
+ ## is being added here.
+ ##
+ ## -PDB January 25, 2015
+
+ # Create a computation thread
+ self.calc_thread_1D = Calc1D(self.x, self.volCanvas,
+ completefn=self._simulation_completed_1D,
+ updatefn=None)
+ self.calc_thread_1D.queue()
+ self.calc_thread_1D.ready(2.5)
+
+ # Evaluate maximum number of points on the canvas and the
+ # maximum computation time
+
+ # TODO: the getMaxVolume should be a call to the VolumeCanvas object.
+ # Since the VolumeCanvas doesn't currently have that functionality, and
+ # since the simulation panel holds the list of graphical representations
+ # for the shapes, we will take the information from there until VolumeCanvas
+ # is updated.
+ npts = self.plotPanel.canvas.getMaxVolume() * self.volCanvas.params['lores_density']
+
+ est = self.speed * npts * npts
+ self.parent.SetStatusText("Calculation started: this might take a moment... [up to %d secs, %g points]" % (int(est), int(npts)))
+
+
+ def _simulation_completed_1D(self, output, elapsed, error=None):
+ """
+ Called by the computation thread when the simulation is complete.
+ This method processes the simulation output, plots it, and updates
+ the simulation time estimate.
+
+ @param output: simulated distribution I(q)
+ @param elapsed: simulation time, in seconds
+ @param error: standard deviation on the I(q) points
+ """
+ # Create the plotting event to pop up the I(Q) plot.
+ new_plot = Data1D(x=self.x, y=output, dy=error)
+ new_plot.name = "I(Q) Simulation"
+ new_plot.group_id = "simulation_output"
+ new_plot.xaxis("\\rm{Q}", 'A^{-1}')
+ new_plot.yaxis("\\rm{Intensity} ","cm^{-1}")
+ wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title="Simulation I(Q)"))
+
+ # Create the plotting event to pop up the P(r) plot.
+ r, pr = self.volCanvas.getPrData()
+ new_plot = Data1D(x=r, y=pr, dy=[0]*len(r))
+ new_plot.name = "P(r) Simulation"
+ new_plot.group_id = "simulated_pr"
+ new_plot.xaxis("\\rm{r}", 'A')
+ new_plot.yaxis("\\rm{P(r)} ","cm^{-3}")
+
+ wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title="Simulated P(r)"))
+
+
+ # Notify the user of the simlation time and update the basic
+ # simulation estimate that will allow us to estimate simulation time
+ # next time we are asked to simulate.
+ msg = "Calculation completed in %g secs! [%g points]" % (elapsed, self.volCanvas.npts)
+ wx.PostEvent(self.parent, StatusEvent(status=msg))
+ if self.volCanvas.npts>0:
+ self.speed = elapsed/self.volCanvas.npts**2
+
+
+ def get_perspective(self):
+ """
+ Get the list of panel names for this perspective
+ """
+ return self.perspective
+
+ def populate_menu(self, id, owner):
+ """
+ Create a menu for the plug-in
+ """
+ return []
+
+ def _change_point_density(self, point_density):
+ """
+ Placeholder for changing the simulation point density
+ TODO: refactor this away by writing a single update method for the simulation parameters
+ """
+ self.volCanvas.setParam('lores_density', point_density)
+
+ def help(self, evt):
+ """
+ Provide help for the simulation
+ """
+ pass
+
+ def on_perspective(self, event):
+ """
+ Call back function for the perspective menu item.
+ We notify the parent window that the perspective
+ has changed.
+ """
+ self.parent.set_perspective(self.perspective)
+
+ def post_init(self):
+ """
+ Post initialization call back to close the loose ends
+ [Somehow openGL needs this call]
+ """
+ self.parent.set_perspective(self.perspective)
+ self.parent._mgr.Update()
+
+ def _refresh_3D_viewer(self):
+ """
+ Refresh the 3D viewer window
+ #TODO: don't access data member directly
+ """
+ self.plotPanel.canvas.Refresh(False)
+ # Give focus back to 3D canvas so that the
+ # zooming works
+ #self.plotPanel.canvas.SetFocus()
+ #self.plotPanel.SetFocus()
diff --git a/src/sas/sasgui/plottools/BaseInteractor.py b/src/sas/sasgui/plottools/BaseInteractor.py
index 6c139ec..f325e31 100644
--- a/src/sas/sasgui/plottools/BaseInteractor.py
+++ b/src/sas/sasgui/plottools/BaseInteractor.py
@@ -1,179 +1,179 @@
-interface_color = 'black'
-disable_color = 'gray'
-active_color = 'red'
-rho_color = 'black'
-mu_color = 'green'
-P_color = 'blue'
-theta_color = 'orange'
-profile_colors = [rho_color, mu_color, P_color, theta_color]
-
-
-class _BaseInteractor(object):
- """
- Share some functions between the interface interactor and various layer
- interactors.
-
- Individual interactors need the following functions:
-
- save(ev) - save the current state for later restore
- restore() - restore the old state
- move(x,y,ev) - move the interactor to position x,y
- moveend(ev) - end the drag event
- update() - draw the interactors
-
- The following are provided by the base class:
-
- connect_markers(markers) - register callbacks for all markers
- clear_markers() - remove all items in self.markers
- onHilite(ev) - enter/leave event processing
- onLeave(ev) - enter/leave event processing
- onClick(ev) - mouse click: calls save()
- onRelease(ev) - mouse click ends: calls moveend()
- onDrag(ev) - mouse move: calls move() or restore()
- onKey(ev) - keyboard move: calls move() or restore()
-
- Interactor attributes:
-
- base - model we are operating on
- axes - axes holding the interactor
- color - color of the interactor in non-active state
- markers - list of handles for the interactor
-
- """
- def __init__(self, base, axes, color='black'):
- """
- """
- self.base = base
- self.axes = axes
- self.color = color
- self.markers = []
-
- def clear_markers(self):
- '''
- Clear old markers and interfaces.
- '''
- for h in self.markers:
- h.remove()
- if self.markers:
- self.base.connect.clear(*self.markers)
- self.markers = []
-
- def save(self, ev):
- """
- """
- pass
-
- def restore(self, ev):
- """
- """
- pass
-
- def move(self, x, y, ev):
- """
- """
- pass
-
- def moveend(self, ev):
- """
- """
- pass
-
- def connect_markers(self, markers):
- """
- Connect markers to callbacks
- """
- for h in markers:
- connect = self.base.connect
- connect('enter', h, self.onHilite)
- connect('leave', h, self.onLeave)
- connect('click', h, self.onClick)
- connect('release', h, self.onRelease)
- connect('drag', h, self.onDrag)
- connect('key', h, self.onKey)
-
- def onHilite(self, ev):
- """
- Hilite the artist reporting the event, indicating that it is
- ready to receive a click.
- """
- ev.artist.set_color(active_color)
- self.base.draw()
- return True
-
- def onLeave(self, ev):
- """
- Restore the artist to the original colour when the cursor leaves.
- """
- ev.artist.set_color(self.color)
- self.base.draw()
- return True
-
- def onClick(self, ev):
- """
- Prepare to move the artist. Calls save() to preserve the state for
- later restore().
- """
- self.clickx, self.clicky = ev.xdata, ev.ydata
- self.save(ev)
- return True
-
- def onRelease(self, ev):
- """
- """
- self.moveend(ev)
- return True
-
- def onDrag(self, ev):
- """
- Move the artist. Calls move() to update the state, or restore() if
- the mouse leaves the window.
- """
- inside, _ = self.axes.contains(ev)
- if inside:
- self.clickx, self.clicky = ev.xdata, ev.ydata
- self.move(ev.xdata, ev.ydata, ev)
- else:
- self.restore()
- self.base.update()
- return True
-
- def onKey(self, ev):
- """
- Respond to keyboard events. Arrow keys move the widget. Escape
- restores it to the position before the last click.
-
- Calls move() to update the state. Calls restore() on escape.
- """
- if ev.key == 'escape':
- self.restore()
- elif ev.key in ['up', 'down', 'right', 'left']:
- dx, dy = self.dpixel(self.clickx, self.clicky, nudge=ev.control)
- if ev.key == 'up':
- self.clicky += dy
- elif ev.key == 'down':
- self.clicky -= dy
- elif ev.key == 'right':
- self.clickx += dx
- else:
- self.clickx -= dx
- self.move(self.clickx, self.clicky, ev)
- else:
- return False
- self.base.update()
- return True
-
- def dpixel(self, x, y, nudge=False):
- """
- Return the step size in data coordinates for a small
- step in screen coordinates. If nudge is False (default)
- the step size is one pixel. If nudge is True, the step
- size is 0.2 pixels.
- """
- ax = self.axes
- px, py = ax.transData.inverse_xy_tup((x, y))
- if nudge:
- nx, ny = ax.transData.xy_tup((px + 0.2, py + 0.2))
- else:
- nx, ny = ax.transData.xy_tup((px + 1., py + 1.))
- dx, dy = nx - x, ny - y
- return dx, dy
+interface_color = 'black'
+disable_color = 'gray'
+active_color = 'red'
+rho_color = 'black'
+mu_color = 'green'
+P_color = 'blue'
+theta_color = 'orange'
+profile_colors = [rho_color, mu_color, P_color, theta_color]
+
+
+class _BaseInteractor(object):
+ """
+ Share some functions between the interface interactor and various layer
+ interactors.
+
+ Individual interactors need the following functions:
+
+ save(ev) - save the current state for later restore
+ restore() - restore the old state
+ move(x,y,ev) - move the interactor to position x,y
+ moveend(ev) - end the drag event
+ update() - draw the interactors
+
+ The following are provided by the base class:
+
+ connect_markers(markers) - register callbacks for all markers
+ clear_markers() - remove all items in self.markers
+ onHilite(ev) - enter/leave event processing
+ onLeave(ev) - enter/leave event processing
+ onClick(ev) - mouse click: calls save()
+ onRelease(ev) - mouse click ends: calls moveend()
+ onDrag(ev) - mouse move: calls move() or restore()
+ onKey(ev) - keyboard move: calls move() or restore()
+
+ Interactor attributes:
+
+ base - model we are operating on
+ axes - axes holding the interactor
+ color - color of the interactor in non-active state
+ markers - list of handles for the interactor
+
+ """
+ def __init__(self, base, axes, color='black'):
+ """
+ """
+ self.base = base
+ self.axes = axes
+ self.color = color
+ self.markers = []
+
+ def clear_markers(self):
+ '''
+ Clear old markers and interfaces.
+ '''
+ for h in self.markers:
+ h.remove()
+ if self.markers:
+ self.base.connect.clear(*self.markers)
+ self.markers = []
+
+ def save(self, ev):
+ """
+ """
+ pass
+
+ def restore(self, ev):
+ """
+ """
+ pass
+
+ def move(self, x, y, ev):
+ """
+ """
+ pass
+
+ def moveend(self, ev):
+ """
+ """
+ pass
+
+ def connect_markers(self, markers):
+ """
+ Connect markers to callbacks
+ """
+ for h in markers:
+ connect = self.base.connect
+ connect('enter', h, self.onHilite)
+ connect('leave', h, self.onLeave)
+ connect('click', h, self.onClick)
+ connect('release', h, self.onRelease)
+ connect('drag', h, self.onDrag)
+ connect('key', h, self.onKey)
+
+ def onHilite(self, ev):
+ """
+ Hilite the artist reporting the event, indicating that it is
+ ready to receive a click.
+ """
+ ev.artist.set_color(active_color)
+ self.base.draw()
+ return True
+
+ def onLeave(self, ev):
+ """
+ Restore the artist to the original colour when the cursor leaves.
+ """
+ ev.artist.set_color(self.color)
+ self.base.draw()
+ return True
+
+ def onClick(self, ev):
+ """
+ Prepare to move the artist. Calls save() to preserve the state for
+ later restore().
+ """
+ self.clickx, self.clicky = ev.xdata, ev.ydata
+ self.save(ev)
+ return True
+
+ def onRelease(self, ev):
+ """
+ """
+ self.moveend(ev)
+ return True
+
+ def onDrag(self, ev):
+ """
+ Move the artist. Calls move() to update the state, or restore() if
+ the mouse leaves the window.
+ """
+ inside, _ = self.axes.contains(ev)
+ if inside:
+ self.clickx, self.clicky = ev.xdata, ev.ydata
+ self.move(ev.xdata, ev.ydata, ev)
+ else:
+ self.restore()
+ self.base.update()
+ return True
+
+ def onKey(self, ev):
+ """
+ Respond to keyboard events. Arrow keys move the widget. Escape
+ restores it to the position before the last click.
+
+ Calls move() to update the state. Calls restore() on escape.
+ """
+ if ev.key == 'escape':
+ self.restore()
+ elif ev.key in ['up', 'down', 'right', 'left']:
+ dx, dy = self.dpixel(self.clickx, self.clicky, nudge=ev.control)
+ if ev.key == 'up':
+ self.clicky += dy
+ elif ev.key == 'down':
+ self.clicky -= dy
+ elif ev.key == 'right':
+ self.clickx += dx
+ else:
+ self.clickx -= dx
+ self.move(self.clickx, self.clicky, ev)
+ else:
+ return False
+ self.base.update()
+ return True
+
+ def dpixel(self, x, y, nudge=False):
+ """
+ Return the step size in data coordinates for a small
+ step in screen coordinates. If nudge is False (default)
+ the step size is one pixel. If nudge is True, the step
+ size is 0.2 pixels.
+ """
+ ax = self.axes
+ px, py = ax.transData.inverse_xy_tup((x, y))
+ if nudge:
+ nx, ny = ax.transData.xy_tup((px + 0.2, py + 0.2))
+ else:
+ nx, ny = ax.transData.xy_tup((px + 1., py + 1.))
+ dx, dy = nx - x, ny - y
+ return dx, dy
diff --git a/src/sas/sasgui/plottools/LabelDialog.py b/src/sas/sasgui/plottools/LabelDialog.py
index cb4b30a..54081af 100644
--- a/src/sas/sasgui/plottools/LabelDialog.py
+++ b/src/sas/sasgui/plottools/LabelDialog.py
@@ -1,43 +1,43 @@
-import wx
-import sys
-if sys.platform.count("win32") > 0:
- FONT_VARIANT = 0
- PNL_WIDTH = 270
-else:
- FONT_VARIANT = 1
- PNL_WIDTH = 300
-
-class LabelDialog(wx.Dialog):
- def __init__(self, parent, id, title, label):
- wx.Dialog.__init__(self, parent, id, title, size=(PNL_WIDTH, 150))
-
- # Font
- self.SetWindowVariant(variant=FONT_VARIANT)
- mainbox = wx.BoxSizer(wx.VERTICAL)
- vbox = wx.BoxSizer(wx.VERTICAL)
- textbox = wx.BoxSizer(wx.HORIZONTAL)
-
- text1 = "Enter a new title/label:"
- msg = wx.StaticText(self, -1, text1, (30, 15), style=wx.ALIGN_LEFT)
- msg.SetLabel(text1)
- self.label_ctrl = wx.TextCtrl(self, -1, '', (200, 30))
- self.label_ctrl.SetValue(str(label))
- textbox.Add(self.label_ctrl, flag=wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE,
- border=10, proportion=2)
- vbox.Add(msg, flag=wx.ALL, border=10, proportion=1)
- vbox.Add(textbox, flag=wx.EXPAND | wx.TOP | wx.BOTTOM | wx.ADJUST_MINSIZE, border=5)
- hbox = wx.BoxSizer(wx.HORIZONTAL)
- ok_button = wx.Button(self, wx.ID_OK, 'OK', size=(70, 25))
- close_button = wx.Button(self, wx.ID_CANCEL, 'Cancel', size=(70, 25))
-
- hbox.Add(ok_button, wx.LEFT, 10)
- hbox.Add((20, 20))
- hbox.Add(close_button, wx.LEFT, 10)
-
- mainbox.Add(vbox, flag=wx.LEFT, border=5)
- mainbox.Add(wx.StaticLine(self), 0, wx.ALL | wx.EXPAND, 5)
- mainbox.Add(hbox, flag=wx.CENTER, border=20)
- self.SetSizer(mainbox)
-
- def getText(self):
- return self.label_ctrl.GetValue()
+import wx
+import sys
+if sys.platform.count("win32") > 0:
+ FONT_VARIANT = 0
+ PNL_WIDTH = 270
+else:
+ FONT_VARIANT = 1
+ PNL_WIDTH = 300
+
+class LabelDialog(wx.Dialog):
+ def __init__(self, parent, id, title, label):
+ wx.Dialog.__init__(self, parent, id, title, size=(PNL_WIDTH, 150))
+
+ # Font
+ self.SetWindowVariant(variant=FONT_VARIANT)
+ mainbox = wx.BoxSizer(wx.VERTICAL)
+ vbox = wx.BoxSizer(wx.VERTICAL)
+ textbox = wx.BoxSizer(wx.HORIZONTAL)
+
+ text1 = "Enter a new title/label:"
+ msg = wx.StaticText(self, -1, text1, (30, 15), style=wx.ALIGN_LEFT)
+ msg.SetLabel(text1)
+ self.label_ctrl = wx.TextCtrl(self, -1, '', (200, 30))
+ self.label_ctrl.SetValue(str(label))
+ textbox.Add(self.label_ctrl, flag=wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE,
+ border=10, proportion=2)
+ vbox.Add(msg, flag=wx.ALL, border=10, proportion=1)
+ vbox.Add(textbox, flag=wx.EXPAND | wx.TOP | wx.BOTTOM | wx.ADJUST_MINSIZE, border=5)
+ hbox = wx.BoxSizer(wx.HORIZONTAL)
+ ok_button = wx.Button(self, wx.ID_OK, 'OK', size=(70, 25))
+ close_button = wx.Button(self, wx.ID_CANCEL, 'Cancel', size=(70, 25))
+
+ hbox.Add(ok_button, wx.LEFT, 10)
+ hbox.Add((20, 20))
+ hbox.Add(close_button, wx.LEFT, 10)
+
+ mainbox.Add(vbox, flag=wx.LEFT, border=5)
+ mainbox.Add(wx.StaticLine(self), 0, wx.ALL | wx.EXPAND, 5)
+ mainbox.Add(hbox, flag=wx.CENTER, border=20)
+ self.SetSizer(mainbox)
+
+ def getText(self):
+ return self.label_ctrl.GetValue()
diff --git a/src/sas/sasgui/plottools/LineModel.py b/src/sas/sasgui/plottools/LineModel.py
index 4a6f0ed..d5366a9 100644
--- a/src/sas/sasgui/plottools/LineModel.py
+++ b/src/sas/sasgui/plottools/LineModel.py
@@ -1,107 +1,109 @@
-#!/usr/bin/env python
-"""
-Provide Line function (y= Ax + B). Until July 10, 2016 this function provided
-(y= A + Bx). This however was contrary to all the other code using it which
-assumed (y= mx+b) or in this nomenclature (y=Ax + B). This lead to some
-contortions in the code and worse incorrect calculations until now for at least
-some of the functions. This seemed the easiest to fix particularly since this
-function should disappear in a future iteration (see notes in fitDialog)
-
- -PDB July 10, 2016
-"""
-
-import math
-
-class LineModel(object):
- """
- Class that evaluates a linear model.
-
- f(x) = Ax + B
-
- List of default parameters:
- A = 1.0
- B = 1.0
- """
-
- def __init__(self):
- """ Initialization """
- # # Name of the model
- self.name = "LineModel"
-
- # # Define parameters
- self.params = {}
- self.params['A'] = 1.0
- self.params['B'] = 1.0
-
- # # Parameter details [units, min, max]
- self.details = {}
- self.details['A'] = ['', None, None]
- self.details['B'] = ['', None, None]
-
- def getParam(self, name):
- """
- Return parameter value
- """
- return self.params[name.upper()]
-
- def setParam(self, name, value):
- """
- Set parameter value
- """
- self.params[name.upper()] = value
-
- def _line(self, x):
- """
- Evaluate the function
-
- :param x: x-value
-
- :return: function value
-
- """
- return (self.params['A'] * x) + self.params['B']
-
- def run(self, x=0.0):
- """
- Evaluate the model
-
- :note: This is the function called by fitDialog to calculate the
- the y(xmin) and y(xmax), but the only difference between this and
- runXY is when the if statement is true. I however cannot see what that
- function is for. It needs to be documented here or removed.
- -PDB 7/10/16
-
- :param x: simple value
-
- :return: (Line value)
- """
- if x.__class__.__name__ == 'list':
- return self._line(x[0] * math.cos(x[1])) * \
- self._line(x[0] * math.sin(x[1]))
- elif x.__class__.__name__ == 'tuple':
- msg = "Tuples are not allowed as input to BaseComponent models"
- raise ValueError, msg
- else:
- return self._line(x)
-
- def runXY(self, x=0.0):
- """
- Evaluate the model.
-
- :note: This is to be what is called by fitDialog for the actual fit
- but the only difference between this and run is when the if
- statement is true. I however cannot see what that function
- is for. It needs to be documented here or removed. -PDB 7/10/16
-
- :param x: simple value
-
- :return: Line value
-
- """
- if x.__class__.__name__ == 'list':
- return self._line(x[0]) * self._line(x[1])
- elif x.__class__.__name__ == 'tuple':
- msg = "Tuples are not allowed as input to BaseComponent models"
- raise ValueError, msg
- else:
- return self._line(x)
+#!/usr/bin/env python
+"""
+Provide Line function (y= Ax + B). Until July 10, 2016 this function provided
+(y= A + Bx). This however was contrary to all the other code using it which
+assumed (y= mx+b) or in this nomenclature (y=Ax + B). This lead to some
+contortions in the code and worse incorrect calculations until now for at least
+some of the functions. This seemed the easiest to fix particularly since this
+function should disappear in a future iteration (see notes in fitDialog)
+
+PDB July 10, 2016
+
+"""
+
+import math
+
+class LineModel(object):
+ """
+ Class that evaluates a linear model.
+
+ f(x) = Ax + B
+
+ List of default parameters:
+ A = 1.0
+ B = 1.0
+ """
+
+ def __init__(self):
+ """ Initialization """
+ # # Name of the model
+ self.name = "LineModel"
+
+ # # Define parameters
+ self.params = {}
+ self.params['A'] = 1.0
+ self.params['B'] = 1.0
+
+ # # Parameter details [units, min, max]
+ self.details = {}
+ self.details['A'] = ['', None, None]
+ self.details['B'] = ['', None, None]
+
+ def getParam(self, name):
+ """
+ Return parameter value
+ """
+ return self.params[name.upper()]
+
+ def setParam(self, name, value):
+ """
+ Set parameter value
+ """
+ self.params[name.upper()] = value
+
+ def _line(self, x):
+ """
+ Evaluate the function
+
+ :param x: x-value
+
+ :return: function value
+
+ """
+ return (self.params['A'] * x) + self.params['B']
+
+ def run(self, x=0.0):
+ """
+ Evaluate the model
+
+ :param x: simple value
+
+ :return: (Line value)
+
+ .. note::
+ This is the function called by fitDialog to calculate the
+ the y(xmin) and y(xmax), but the only difference between this and
+ runXY is when the if statement is true. I however cannot see what
+ that function is for. It needs to be documented here or removed.
+ PDB 7/10/16
+ """
+ if x.__class__.__name__ == 'list':
+ return self._line(x[0] * math.cos(x[1])) * \
+ self._line(x[0] * math.sin(x[1]))
+ elif x.__class__.__name__ == 'tuple':
+ msg = "Tuples are not allowed as input to BaseComponent models"
+ raise ValueError, msg
+ else:
+ return self._line(x)
+
+ def runXY(self, x=0.0):
+ """
+ Evaluate the model.
+
+ :param x: simple value
+
+ :return: Line value
+
+ .. note::
+ This is to be what is called by fitDialog for the actual fit
+ the only difference between this and run is when the if
+ statement is true. I however cannot see what that function
+ is for. It needs to be documented here or removed. PDB 7/10/16
+ """
+ if x.__class__.__name__ == 'list':
+ return self._line(x[0]) * self._line(x[1])
+ elif x.__class__.__name__ == 'tuple':
+ msg = "Tuples are not allowed as input to BaseComponent models"
+ raise ValueError, msg
+ else:
+ return self._line(x)
diff --git a/src/sas/sasgui/plottools/PlotPanel.py b/src/sas/sasgui/plottools/PlotPanel.py
index 45d0d4d..f3cce69 100644
--- a/src/sas/sasgui/plottools/PlotPanel.py
+++ b/src/sas/sasgui/plottools/PlotPanel.py
@@ -1,2041 +1,2045 @@
-"""
- Plot panel.
-"""
-import logging
-import traceback
-import wx
-# Try a normal import first
-# If it fails, try specifying a version
-import matplotlib
-matplotlib.interactive(False)
-#Use the WxAgg back end. The Wx one takes too long to render
-matplotlib.use('WXAgg')
-from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg
-from matplotlib.figure import Figure
-import os
-import transform
-#TODO: make the plottables interactive
-from binder import BindArtist
-from matplotlib.font_manager import FontProperties
-DEBUG = False
-
-from plottables import Graph
-from TextDialog import TextDialog
-from LabelDialog import LabelDialog
-import operator
-
-import math
-import pylab
-DEFAULT_CMAP = pylab.cm.jet
-import copy
-import numpy
-
-from sas.sasgui.guiframe.events import StatusEvent
-from .toolbar import NavigationToolBar, PlotPrintout, bind
-
-def show_tree(obj, d=0):
- """Handy function for displaying a tree of graph objects"""
- print "%s%s" % ("-"*d, obj.__class__.__name__)
- if 'get_children' in dir(obj):
- for a in obj.get_children(): show_tree(a, d + 1)
-
-from convert_units import convert_unit
-
-
-def _rescale(lo, hi, step, pt=None, bal=None, scale='linear'):
- """
- Rescale (lo,hi) by step, returning the new (lo,hi)
- The scaling is centered on pt, with positive values of step
- driving lo/hi away from pt and negative values pulling them in.
- If bal is given instead of point, it is already in [0,1] coordinates.
-
- This is a helper function for step-based zooming.
-
- """
- # Convert values into the correct scale for a linear transformation
- # TODO: use proper scale transformers
- loprev = lo
- hiprev = hi
- if scale == 'log':
- assert lo > 0
- if lo > 0:
- lo = math.log10(lo)
- if hi > 0:
- hi = math.log10(hi)
- if pt is not None:
- pt = math.log10(pt)
-
- # Compute delta from axis range * %, or 1-% if persent is negative
- if step > 0:
- delta = float(hi - lo) * step / 100
- else:
- delta = float(hi - lo) * step / (100 - step)
-
- # Add scale factor proportionally to the lo and hi values,
- # preserving the
- # point under the mouse
- if bal is None:
- bal = float(pt - lo) / (hi - lo)
- lo = lo - (bal * delta)
- hi = hi + (1 - bal) * delta
-
- # Convert transformed values back to the original scale
- if scale == 'log':
- if (lo <= -250) or (hi >= 250):
- lo = loprev
- hi = hiprev
- else:
- lo, hi = math.pow(10., lo), math.pow(10., hi)
- return (lo, hi)
-
-
-class PlotPanel(wx.Panel):
- """
- The PlotPanel has a Figure and a Canvas. OnSize events simply set a
- flag, and the actually redrawing of the
- figure is triggered by an Idle event.
- """
- def __init__(self, parent, id=-1, xtransform=None,
- ytransform=None, scale='log_{10}',
- color=None, dpi=None, **kwargs):
- """
- """
- wx.Panel.__init__(self, parent, id=id, **kwargs)
- self.parent = parent
- if hasattr(parent, "parent"):
- self.parent = self.parent.parent
- self.dimension = 1
- self.gotLegend = 0 # to begin, legend is not picked.
- self.legend_pos_loc = None
- self.legend = None
- self.line_collections_list = []
- self.figure = Figure(None, dpi, linewidth=2.0)
- self.color = '#b3b3b3'
- from canvas import FigureCanvas
- self.canvas = FigureCanvas(self, -1, self.figure)
- self.SetColor(color)
- self._resizeflag = True
- self._SetSize()
- self.subplot = self.figure.add_subplot(111)
- self.figure.subplots_adjust(left=0.2, bottom=.2)
- self.yscale = 'linear'
- self.xscale = 'linear'
- self.sizer = wx.BoxSizer(wx.VERTICAL)
- self.sizer.Add(self.canvas, 1, wx.EXPAND)
- #add toolbar
- self.enable_toolbar = True
- self.toolbar = None
- self.add_toolbar()
- self.SetSizer(self.sizer)
-
- # Graph object to manage the plottables
- self.graph = Graph()
-
- #Boolean value to keep track of whether current legend is
- #visible or not
- self.legend_on = True
- self.grid_on = False
- #Location of legend, default is 0 or 'best'
- self.legendLoc = 0
- self.position = None
- self._loc_labels = self.get_loc_label()
-
- self.Bind(wx.EVT_CONTEXT_MENU, self.onContextMenu)
-
- # Define some constants
- self.colorlist = ['b', 'g', 'r', 'c', 'm', 'y', 'k']
- self.symbollist = ['o', 'x', '^', 'v', '<', '>', '+',
- 's', 'd', 'D', 'h', 'H', 'p', '-']
-
- #List of texts currently on the plot
- self.textList = []
- self.selectedText = None
- #User scale
- if xtransform != None:
- self.xLabel = xtransform
- else:
- self.xLabel = "log10(x)"
- if ytransform != None:
- self.yLabel = ytransform
- else:
- self.yLabel = "log10(y)"
- self.viewModel = "--"
- # keep track if the previous transformation of x
- # and y in Property dialog
- self.prevXtrans = "log10(x)"
- self.prevYtrans = "log10(y)"
- self.scroll_id = self.canvas.mpl_connect('scroll_event', self.onWheel)
- #taking care of dragging
- self.motion_id = self.canvas.mpl_connect('motion_notify_event',
- self.onMouseMotion)
- self.press_id = self.canvas.mpl_connect('button_press_event',
- self.onLeftDown)
- self.pick_id = self.canvas.mpl_connect('pick_event', self.onPick)
- self.release_id = self.canvas.mpl_connect('button_release_event',
- self.onLeftUp)
-
- wx.EVT_RIGHT_DOWN(self, self.onLeftDown)
- # to turn axis off whenn resizing the panel
- self.resizing = False
-
- self.leftdown = False
- self.leftup = False
- self.mousemotion = False
- self.axes = [self.subplot]
- ## Fit dialog
- self._fit_dialog = None
- # Interactor
- self.connect = BindArtist(self.subplot.figure)
- #self.selected_plottable = None
-
- # new data for the fit
- from sas.sasgui.guiframe.dataFitting import Data1D
- self.fit_result = Data1D(x=[], y=[], dy=None)
- self.fit_result.symbol = 13
- #self.fit_result = Data1D(x=[], y=[],dx=None, dy=None)
- self.fit_result.name = "Fit"
- # For fit Dialog initial display
- self.xmin = 0.0
- self.xmax = 0.0
- self.xminView = 0.0
- self.xmaxView = 0.0
- self._scale_xlo = None
- self._scale_xhi = None
- self._scale_ylo = None
- self._scale_yhi = None
- self.Avalue = None
- self.Bvalue = None
- self.ErrAvalue = None
- self.ErrBvalue = None
- self.Chivalue = None
-
- # for 2D scale
- if scale != 'linear':
- scale = 'log_{10}'
- self.scale = scale
- self.data = None
- self.qx_data = None
- self.qy_data = None
- self.xmin_2D = None
- self.xmax_2D = None
- self.ymin_2D = None
- self.ymax_2D = None
- ## store reference to the current plotted vmin and vmax of plotted image
- ##z range in linear scale
- self.zmin_2D = None
- self.zmax_2D = None
-
- #index array
- self.index_x = None
- self.index_y = None
-
- #number of bins
- self.x_bins = None
- self.y_bins = None
-
- ## default color map
- self.cmap = DEFAULT_CMAP
-
- # Dragging info
- self.begDrag = False
- self.xInit = None
- self.yInit = None
- self.xFinal = None
- self.yFinal = None
-
- #axes properties
- self.xaxis_font = None
- self.xaxis_label = None
- self.xaxis_unit = None
- self.xaxis_color = 'black'
- self.xaxis_tick = None
- self.yaxis_font = None
- self.yaxis_label = None
- self.yaxis_unit = None
- self.yaxis_color = 'black'
- self.yaxis_tick = None
-
- # check if zoomed.
- self.is_zoomed = False
- # Plottables
- self.plots = {}
-
- # Default locations
- self._default_save_location = os.getcwd()
- # let canvas know about axes
- self.canvas.set_panel(self)
- self.ly = None
- self.q_ctrl = None
- #Bind focus to change the border color
- self.canvas.Bind(wx.EVT_SET_FOCUS, self.on_set_focus)
- self.canvas.Bind(wx.EVT_KILL_FOCUS, self.on_kill_focus)
-
- def _SetInitialSize(self,):
- """
- """
- pixels = self.parent.GetClientSize()
- self.canvas.SetSize(pixels)
- self.figure.set_size_inches(pixels[0] / self.figure.get_dpi(),
- pixels[1] / self.figure.get_dpi(), forward=True)
-
- def On_Paint(self, event):
- """
- """
- self.canvas.SetBackgroundColour(self.color)
-
- def on_set_focus(self, event):
- """
- Send to the parenet the current panel on focus
- """
- # light blue
- self.color = '#0099f7'
- self.figure.set_edgecolor(self.color)
- if self.parent and self.window_caption:
- self.parent.send_focus_to_datapanel(self.window_caption)
- self.draw()
-
- def on_kill_focus(self, event):
- """
- Reset the panel color
- """
- # light grey
- self.color = '#b3b3b3'
- self.figure.set_edgecolor(self.color)
- self.draw()
-
- def set_resizing(self, resizing=False):
- """
- Set the resizing (True/False)
- """
- pass # Not implemented
-
- def schedule_full_draw(self, func='append'):
- """
- Put self in schedule to full redraw list
- """
- pass # Not implemented
-
- def add_toolbar(self):
- """
- add toolbar
- """
- self.enable_toolbar = True
- self.toolbar = NavigationToolBar(parent=self, canvas=self.canvas)
- bind(self.toolbar, wx.EVT_TOOL, self.onResetGraph, id=self.toolbar._NTB2_RESET)
- bind(self.toolbar, wx.EVT_TOOL, self.onContextMenu, id=self.toolbar._NTB2_HOME)
- self.toolbar.Realize()
- ## The 'SetToolBar()' is not working on MAC: JHC
- #if IS_MAC:
- # Mac platform (OSX 10.3, MacPython) does not seem to cope with
- # having a toolbar in a sizer. This work-around gets the buttons
- # back, but at the expense of having the toolbar at the top
- #self.SetToolBar(self.toolbar)
- #else:
- # On Windows platform, default window size is incorrect, so set
- # toolbar width to figure width.
- tw, th = self.toolbar.GetSizeTuple()
- fw, fh = self.canvas.GetSizeTuple()
- # By adding toolbar in sizer, we are able to put it at the bottom
- # of the frame - so appearance is closer to GTK version.
- # As noted above, doesn't work for Mac.
- self.toolbar.SetSize(wx.Size(fw, th))
- self.sizer.Add(self.toolbar, 0, wx.LEFT | wx.EXPAND)
-
- # update the axes menu on the toolbar
- self.toolbar.update()
-
- def onLeftDown(self, event):
- """
- left button down and ready to drag
- """
- # Check that the LEFT button was pressed
- if event.button == 1:
- self.leftdown = True
- ax = event.inaxes
- for text in self.textList:
- if text.contains(event)[0]: # If user has clicked on text
- self.selectedText = text
- return
-
- if ax != None:
- self.xInit, self.yInit = event.xdata, event.ydata
- try:
- pos_x = float(event.xdata) # / size_x
- pos_y = float(event.ydata) # / size_y
- pos_x = "%8.3g" % pos_x
- pos_y = "%8.3g" % pos_y
- self.position = str(pos_x), str(pos_y)
- wx.PostEvent(self.parent, StatusEvent(status=self.position))
- except:
- self.position = None
-
- def onLeftUp(self, event):
- """
- Dragging is done
- """
- # Check that the LEFT button was released
- if event.button == 1:
- self.leftdown = False
- self.mousemotion = False
- self.leftup = True
- self.selectedText = None
-
- #release the legend
- if self.gotLegend == 1:
- self.gotLegend = 0
- self.set_legend_alpha(1)
-
- def set_legend_alpha(self, alpha=1):
- """
- Set legend alpha
- """
- if self.legend != None:
- self.legend.legendPatch.set_alpha(alpha)
-
- def onPick(self, event):
- """
- On pick legend
- """
- legend = self.legend
- if event.artist == legend:
- #gets the box of the legend.
- bbox = self.legend.get_window_extent()
- #get mouse coordinates at time of pick.
- self.mouse_x = event.mouseevent.x
- self.mouse_y = event.mouseevent.y
- #get legend coordinates at time of pick.
- self.legend_x = bbox.xmin
- self.legend_y = bbox.ymin
- #indicates we picked up the legend.
- self.gotLegend = 1
- self.set_legend_alpha(0.5)
-
- def _on_legend_motion(self, event):
- """
- On legend in motion
- """
- ax = event.inaxes
- if ax == None:
- return
- # Event occurred inside a plotting area
- lo_x, hi_x = ax.get_xlim()
- lo_y, hi_y = ax.get_ylim()
- # How much the mouse moved.
- x = mouse_diff_x = self.mouse_x - event.x
- y = mouse_diff_y = self.mouse_y - event.y
- # Put back inside
- if x < lo_x:
- x = lo_x
- if x > hi_x:
- x = hi_x
- if y < lo_y:
- y = lo_y
- if y > hi_y:
- y = hi_y
- # Move the legend from its previous location by that same amount
- loc_in_canvas = self.legend_x - mouse_diff_x, \
- self.legend_y - mouse_diff_y
- # Transform into legend coordinate system
- trans_axes = self.legend.parent.transAxes.inverted()
- loc_in_norm_axes = trans_axes.transform_point(loc_in_canvas)
- self.legend_pos_loc = tuple(loc_in_norm_axes)
- self.legend._loc = self.legend_pos_loc
- self.resizing = True
- self.canvas.set_resizing(self.resizing)
- self.canvas.draw()
-
- def onMouseMotion(self, event):
- """
- check if the left button is press and the mouse in moving.
- computer delta for x and y coordinates and then calls draghelper
- to perform the drag
- """
- self.cusor_line(event)
- if self.gotLegend == 1 and self.leftdown:
- self._on_legend_motion(event)
- return
-
- if self.leftdown and self.selectedText is not None:
- # User has clicked on text and is dragging
- ax = event.inaxes
- if ax != None:
- # Only move text if mouse is within axes
- self.selectedText.set_position((event.xdata, event.ydata))
- self._dragHelper(0, 0)
- else:
- # User has dragged outside of axes
- self.selectedText = None
- return
-
- if self.enable_toolbar:
- #Disable dragging without the toolbar to allow zooming with toolbar
- return
- self.mousemotion = True
- if self.leftdown == True and self.mousemotion == True:
- ax = event.inaxes
- if ax != None: # the dragging is perform inside the figure
- self.xFinal, self.yFinal = event.xdata, event.ydata
- # Check whether this is the first point
- if self.xInit == None:
- self.xInit = self.xFinal
- self.yInit = self.yFinal
-
- xdelta = self.xFinal - self.xInit
- ydelta = self.yFinal - self.yInit
-
- if self.xscale == 'log':
- xdelta = math.log10(self.xFinal) - math.log10(self.xInit)
- if self.yscale == 'log':
- ydelta = math.log10(self.yFinal) - math.log10(self.yInit)
- self._dragHelper(xdelta, ydelta)
- else: # no dragging is perform elsewhere
- self._dragHelper(0, 0)
-
- def cusor_line(self, event):
- """
- """
- pass
-
- def _offset_graph(self):
- """
- Zoom and offset the graph to the last known settings
- """
- for ax in self.axes:
- if self._scale_xhi is not None and self._scale_xlo is not None:
- ax.set_xlim(self._scale_xlo, self._scale_xhi)
- if self._scale_yhi is not None and self._scale_ylo is not None:
- ax.set_ylim(self._scale_ylo, self._scale_yhi)
-
- def _dragHelper(self, xdelta, ydelta):
- """
- dragging occurs here
- """
- # Event occurred inside a plotting area
- for ax in self.axes:
- lo, hi = ax.get_xlim()
- newlo, newhi = lo - xdelta, hi - xdelta
- if self.xscale == 'log':
- if lo > 0:
- newlo = math.log10(lo) - xdelta
- if hi > 0:
- newhi = math.log10(hi) - xdelta
- if self.xscale == 'log':
- self._scale_xlo = math.pow(10, newlo)
- self._scale_xhi = math.pow(10, newhi)
- ax.set_xlim(math.pow(10, newlo), math.pow(10, newhi))
- else:
- self._scale_xlo = newlo
- self._scale_xhi = newhi
- ax.set_xlim(newlo, newhi)
-
- lo, hi = ax.get_ylim()
- newlo, newhi = lo - ydelta, hi - ydelta
- if self.yscale == 'log':
- if lo > 0:
- newlo = math.log10(lo) - ydelta
- if hi > 0:
- newhi = math.log10(hi) - ydelta
- if self.yscale == 'log':
- self._scale_ylo = math.pow(10, newlo)
- self._scale_yhi = math.pow(10, newhi)
- ax.set_ylim(math.pow(10, newlo), math.pow(10, newhi))
- else:
- self._scale_ylo = newlo
- self._scale_yhi = newhi
- ax.set_ylim(newlo, newhi)
- self.canvas.draw_idle()
-
- def resetFitView(self):
- """
- For fit Dialog initial display
- """
- self.xmin = 0.0
- self.xmax = 0.0
- self.xminView = 0.0
- self.xmaxView = 0.0
- self._scale_xlo = None
- self._scale_xhi = None
- self._scale_ylo = None
- self._scale_yhi = None
- self.Avalue = None
- self.Bvalue = None
- self.ErrAvalue = None
- self.ErrBvalue = None
- self.Chivalue = None
-
- def onWheel(self, event):
- """
- Process mouse wheel as zoom events
-
- :param event: Wheel event
-
- """
- ax = event.inaxes
- step = event.step
-
- if ax != None:
- # Event occurred inside a plotting area
- lo, hi = ax.get_xlim()
- lo, hi = _rescale(lo, hi, step,
- pt=event.xdata, scale=ax.get_xscale())
- if not self.xscale == 'log' or lo > 0:
- self._scale_xlo = lo
- self._scale_xhi = hi
- ax.set_xlim((lo, hi))
-
- lo, hi = ax.get_ylim()
- lo, hi = _rescale(lo, hi, step, pt=event.ydata,
- scale=ax.get_yscale())
- if not self.yscale == 'log' or lo > 0:
- self._scale_ylo = lo
- self._scale_yhi = hi
- ax.set_ylim((lo, hi))
- else:
- # Check if zoom happens in the axes
- xdata, ydata = None, None
- x, y = event.x, event.y
-
- for ax in self.axes:
- insidex, _ = ax.xaxis.contains(event)
- if insidex:
- xdata, _ = ax.transAxes.inverted().transform_point((x, y))
- insidey, _ = ax.yaxis.contains(event)
- if insidey:
- _, ydata = ax.transAxes.inverted().transform_point((x, y))
- if xdata is not None:
- lo, hi = ax.get_xlim()
- lo, hi = _rescale(lo, hi, step,
- bal=xdata, scale=ax.get_xscale())
- if not self.xscale == 'log' or lo > 0:
- self._scale_xlo = lo
- self._scale_xhi = hi
- ax.set_xlim((lo, hi))
- if ydata is not None:
- lo, hi = ax.get_ylim()
- lo, hi = _rescale(lo, hi, step, bal=ydata,
- scale=ax.get_yscale())
- if not self.yscale == 'log' or lo > 0:
- self._scale_ylo = lo
- self._scale_yhi = hi
- ax.set_ylim((lo, hi))
- self.canvas.draw_idle()
-
- def returnTrans(self):
- """
- Return values and labels used by Fit Dialog
- """
- return self.xLabel, self.yLabel, self.Avalue, self.Bvalue, \
- self.ErrAvalue, self.ErrBvalue, self.Chivalue
-
- def setTrans(self, xtrans, ytrans):
- """
-
- :param xtrans: set x transformation on Property dialog
- :param ytrans: set y transformation on Property dialog
-
- """
- self.prevXtrans = xtrans
- self.prevYtrans = ytrans
-
- def onFitting(self, event):
- """
- when clicking on linear Fit on context menu , display Fitting Dialog
- """
- plot_dict = {}
- menu = event.GetEventObject()
- event_id = event.GetId()
- self.set_selected_from_menu(menu, event_id)
- plotlist = self.graph.returnPlottable()
- if self.graph.selected_plottable is not None:
- for item in plotlist:
- if item.id == self.graph.selected_plottable:
- plot_dict[item] = plotlist[item]
- else:
- plot_dict = plotlist
- from fitDialog import LinearFit
-
- if len(plot_dict.keys()) > 0:
- first_item = plot_dict.keys()[0]
- dlg = LinearFit(parent=None, plottable=first_item,
- push_data=self.onFitDisplay,
- transform=self.returnTrans,
- title='Linear Fit')
-
- if (self.xmin != 0.0)and (self.xmax != 0.0)\
- and(self.xminView != 0.0)and (self.xmaxView != 0.0):
- dlg.setFitRange(self.xminView, self.xmaxView,
- self.xmin, self.xmax)
- else:
- xlim = self.subplot.get_xlim()
- ylim = self.subplot.get_ylim()
- dlg.setFitRange(xlim[0], xlim[1], ylim[0], ylim[1])
- # It would be nice for this to NOT be modal (i.e. Show).
- # Not sure about other ramifications - for example
- # if a second linear fit is started before the first is closed.
- # consider for future - being able to work on the plot while
- # seing the fit values would be very nice -- PDB 7/10/16
- dlg.ShowModal()
-
- def set_selected_from_menu(self, menu, id):
- """
- Set selected_plottable from context menu selection
-
- :param menu: context menu item
- :param id: menu item id
- """
- if len(self.plots) < 1:
- return
- name = menu.GetHelpString(id)
- for plot in self.plots.values():
- if plot.name == name:
- self.graph.selected_plottable = plot.id
- break
-
- def linear_plottable_fit(self, plot):
- """
- when clicking on linear Fit on context menu, display Fitting Dialog
-
- :param plot: PlotPanel owning the graph
-
- """
- from fitDialog import LinearFit
- if self._fit_dialog is not None:
- return
- self._fit_dialog = LinearFit(None, plot, self.onFitDisplay,
- self.returnTrans, -1, 'Linear Fit')
- # Set the zoom area
- if self._scale_xhi is not None and self._scale_xlo is not None:
- self._fit_dialog.set_fit_region(self._scale_xlo, self._scale_xhi)
- # Register the close event
- self._fit_dialog.register_close(self._linear_fit_close)
- # Show a non-model dialog
- self._fit_dialog.Show()
-
- def _linear_fit_close(self):
- """
- A fit dialog was closed
- """
- self._fit_dialog = None
-
- def _onProperties(self, event):
- """
- when clicking on Properties on context menu ,
- The Property dialog is displayed
- The user selects a transformation for x or y value and
- a new plot is displayed
- """
- if self._fit_dialog is not None:
- self._fit_dialog.Destroy()
- self._fit_dialog = None
- plot_list = self.graph.returnPlottable()
- if len(plot_list.keys()) > 0:
- first_item = plot_list.keys()[0]
- if first_item.x != []:
- from PropertyDialog import Properties
- dial = Properties(self, -1, 'Properties')
- dial.setValues(self.prevXtrans, self.prevYtrans, self.viewModel)
- if dial.ShowModal() == wx.ID_OK:
- self.xLabel, self.yLabel, self.viewModel = dial.getValues()
- self._onEVT_FUNC_PROPERTY()
- dial.Destroy()
-
- def set_yscale(self, scale='linear'):
- """
- Set the scale on Y-axis
-
- :param scale: the scale of y-axis
-
- """
- self.subplot.set_yscale(scale, nonposy='clip')
- self.yscale = scale
-
- def get_yscale(self):
- """
-
- :return: Y-axis scale
-
- """
- return self.yscale
-
- def set_xscale(self, scale='linear'):
- """
- Set the scale on x-axis
-
- :param scale: the scale of x-axis
-
- """
- self.subplot.set_xscale(scale)
- self.xscale = scale
-
- def get_xscale(self):
- """
-
- :return: x-axis scale
-
- """
- return self.xscale
-
- def SetColor(self, rgbtuple):
- """
- Set figure and canvas colours to be the same
-
- """
- if not rgbtuple:
- rgbtuple = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE).Get()
- col = [c / 255.0 for c in rgbtuple]
- self.figure.set_facecolor(col)
- self.figure.set_edgecolor(self.color)
- self.canvas.SetBackgroundColour(wx.Colour(*rgbtuple))
-
- def _onSize(self, event):
- """
- """
- self._resizeflag = True
-
- def _onIdle(self, evt):
- """
- """
- if self._resizeflag:
- self._resizeflag = False
- self._SetSize()
- self.draw()
-
- def _SetSize(self, pixels=None):
- """
- This method can be called to force the Plot to be a desired size,
- which defaults to the ClientSize of the panel
-
- """
- if not pixels:
- pixels = tuple(self.GetClientSize())
- self.canvas.SetSize(pixels)
- self.figure.set_size_inches(float(pixels[0]) / self.figure.get_dpi(),
- float(pixels[1]) / self.figure.get_dpi())
-
- def draw(self):
- """
- Where the actual drawing happens
-
- """
- self.figure.canvas.draw_idle()
-
- def legend_picker(self, legend, event):
- """
- Pick up the legend patch
- """
- return self.legend.legendPatch.contains(event)
-
- def get_loc_label(self):
- """
- Associates label to a specific legend location
- """
- _labels = {}
- i = 0
- _labels['best'] = i
- i += 1
- _labels['upper right'] = i
- i += 1
- _labels['upper left'] = i
- i += 1
- _labels['lower left'] = i
- i += 1
- _labels['lower right'] = i
- i += 1
- _labels['right'] = i
- i += 1
- _labels['center left'] = i
- i += 1
- _labels['center right'] = i
- i += 1
- _labels['lower center'] = i
- i += 1
- _labels['upper center'] = i
- i += 1
- _labels['center'] = i
- return _labels
-
- def onSaveImage(self, evt):
- """
- Implement save image
- """
- self.toolbar.save_figure(evt)
-
- def onContextMenu(self, event):
- """
- Default context menu for a plot panel
-
- """
- # Slicer plot popup menu
- wx_id = wx.NewId()
- slicerpop = wx.Menu()
- slicerpop.Append(wx_id, '&Save image', 'Save image as PNG')
- wx.EVT_MENU(self, wx_id, self.onSaveImage)
-
- wx_id = wx.NewId()
- slicerpop.Append(wx_id, '&Printer setup', 'Set image size')
- wx.EVT_MENU(self, wx_id, self.onPrinterSetup)
-
- wx_id = wx.NewId()
- slicerpop.Append(wx_id, '&Print image', 'Print image ')
- wx.EVT_MENU(self, wx_id, self.onPrint)
-
- wx_id = wx.NewId()
- slicerpop.Append(wx_id, '&Copy', 'Copy to the clipboard')
- wx.EVT_MENU(self, wx_id, self.OnCopyFigureMenu)
-
- wx_id = wx.NewId()
- slicerpop.AppendSeparator()
- slicerpop.Append(wx_id, '&Properties')
- wx.EVT_MENU(self, wx_id, self._onProperties)
-
- wx_id = wx.NewId()
- slicerpop.AppendSeparator()
- slicerpop.Append(wx_id, '&Linear Fit')
- wx.EVT_MENU(self, wx_id, self.onFitting)
-
- wx_id = wx.NewId()
- slicerpop.AppendSeparator()
- slicerpop.Append(wx_id, '&Toggle Legend On/Off', 'Toggle Legend On/Off')
- wx.EVT_MENU(self, wx_id, self.onLegend)
-
- loc_menu = wx.Menu()
- for label in self._loc_labels:
- wx_id = wx.NewId()
- loc_menu.Append(wx_id, str(label), str(label))
- wx.EVT_MENU(self, wx_id, self.onChangeLegendLoc)
- wx_id = wx.NewId()
- slicerpop.AppendMenu(wx_id, '&Modify Legend Location', loc_menu)
-
- wx_id = wx.NewId()
- slicerpop.Append(wx_id, '&Modify Y Axis Label')
- wx.EVT_MENU(self, wx_id, self._on_yaxis_label)
- wx_id = wx.NewId()
- slicerpop.Append(wx_id, '&Modify X Axis Label')
- wx.EVT_MENU(self, wx_id, self._on_xaxis_label)
-
- try:
- # mouse event
- pos_evt = event.GetPosition()
- pos = self.ScreenToClient(pos_evt)
- except:
- # toolbar event
- pos_x, pos_y = self.toolbar.GetPositionTuple()
- pos = (pos_x, pos_y + 5)
-
- self.PopupMenu(slicerpop, pos)
-
- def onToolContextMenu(self, event):
- """
- ContextMenu from toolbar
-
- :param event: toolbar event
- """
- # reset postion
- self.position = None
- if self.graph.selected_plottable != None:
- self.graph.selected_plottable = None
-
- self.onContextMenu(event)
-
-# modified kieranrcampbell ILL june2012
- def onLegend(self, legOnOff):
- """
- Toggles whether legend is visible/not visible
- """
- self.legend_on = legOnOff
- if not self.legend_on:
- for ax in self.axes:
- self.remove_legend(ax)
- else:
- # sort them by labels
- handles, labels = self.subplot.get_legend_handles_labels()
- hl = sorted(zip(handles, labels),
- key=operator.itemgetter(1))
- handles2, labels2 = zip(*hl)
- self.line_collections_list = handles2
- self.legend = self.subplot.legend(handles2, labels2,
- prop=FontProperties(size=10),
- loc=self.legendLoc)
- if self.legend != None:
- self.legend.set_picker(self.legend_picker)
- self.legend.set_axes(self.subplot)
- self.legend.set_zorder(20)
-
- self.subplot.figure.canvas.draw_idle()
-
- def onChangeLegendLoc(self, event):
- """
- Changes legend loc based on user input
- """
- menu = event.GetEventObject()
- label = menu.GetLabel(event.GetId())
- self.ChangeLegendLoc(label)
-
- def ChangeLegendLoc(self, label):
- """
- Changes legend loc based on user input
- """
- self.legendLoc = label
- self.legend_pos_loc = None
- # sort them by labels
- handles, labels = self.subplot.get_legend_handles_labels()
- hl = sorted(zip(handles, labels),
- key=operator.itemgetter(1))
- handles2, labels2 = zip(*hl)
- self.line_collections_list = handles2
- self.legend = self.subplot.legend(handles2, labels2,
- prop=FontProperties(size=10),
- loc=self.legendLoc)
- if self.legend != None:
- self.legend.set_picker(self.legend_picker)
- self.legend.set_axes(self.subplot)
- self.legend.set_zorder(20)
- self.subplot.figure.canvas.draw_idle()
-
- def remove_legend(self, ax=None):
- """
- Remove legend for ax or the current axes.
- """
- from pylab import gca
- if ax is None:
- ax = gca()
- ax.legend_ = None
-
- def _on_addtext(self, event):
- """
- Allows you to add text to the plot
- """
- pos_x = 0
- pos_y = 0
- if self.position != None:
- pos_x, pos_y = self.position
- else:
- pos_x, pos_y = 0.01, 1.00
-
- textdial = TextDialog(None, -1, 'Add Custom Text')
- if textdial.ShowModal() == wx.ID_OK:
- try:
- FONT = FontProperties()
- label = textdial.getText()
- xpos = pos_x
- ypos = pos_y
- font = FONT.copy()
- font.set_size(textdial.getSize())
- font.set_family(textdial.getFamily())
- font.set_style(textdial.getStyle())
- font.set_weight(textdial.getWeight())
- colour = textdial.getColor()
- if len(label) > 0 and xpos > 0 and ypos > 0:
- new_text = self.subplot.text(str(xpos), str(ypos), label,
- fontproperties=font,
- color=colour)
- self.textList.append(new_text)
- self.subplot.figure.canvas.draw_idle()
- except:
- if self.parent != None:
- msg = "Add Text: Error. Check your property values..."
- wx.PostEvent(self.parent, StatusEvent(status=msg))
- else:
- raise
- textdial.Destroy()
- #Have a pop up box come up for user to type in the
- #text that they want to add...then create text Plottable
- #based on this and plot it at user designated coordinates
-
- def onGridOnOff(self, gridon_off):
- """
- Allows ON/OFF Grid
- """
- self.grid_on = gridon_off
-
- self.subplot.figure.canvas.draw_idle()
-
- def _on_xaxis_label(self, event):
- """
- Allows you to add text to the plot
- """
- xaxis_label, xaxis_unit, xaxis_font, xaxis_color, \
- is_ok, is_tick = self._on_axis_label(axis='x')
- if not is_ok:
- return
-
- self.xaxis_label = xaxis_label
- self.xaxis_unit = xaxis_unit
- self.xaxis_font = xaxis_font
- self.xaxis_color = xaxis_color
- if is_tick:
- self.xaxis_tick = xaxis_font
-
- if self.data != None:
- # 2D
- self.xaxis(self.xaxis_label, self.xaxis_unit, \
- self.xaxis_font, self.xaxis_color, self.xaxis_tick)
- self.subplot.figure.canvas.draw_idle()
- else:
- # 1D
- self._check_zoom_plot()
-
- def _check_zoom_plot(self):
- """
- Check the zoom range and plot (1D only)
- """
- xlo, xhi = self.subplot.get_xlim()
- ylo, yhi = self.subplot.get_ylim()
- ## Set the view scale for all plots
- self._onEVT_FUNC_PROPERTY(False)
- if self.is_zoomed:
- # Recover the x,y limits
- self.subplot.set_xlim((xlo, xhi))
- self.subplot.set_ylim((ylo, yhi))
-
- @property
- def is_zoomed(self):
- toolbar_zoomed = self.toolbar.GetToolEnabled(self.toolbar.wx_ids['Back'])
- return self._is_zoomed or toolbar_zoomed
-
- @is_zoomed.setter
- def is_zoomed(self, value):
- self._is_zoomed = value
-
- def _on_yaxis_label(self, event):
- """
- Allows you to add text to the plot
- """
- yaxis_label, yaxis_unit, yaxis_font, yaxis_color, \
- is_ok, is_tick = self._on_axis_label(axis='y')
- if not is_ok:
- return
-
- self.yaxis_label = yaxis_label
- self.yaxis_unit = yaxis_unit
- self.yaxis_font = yaxis_font
- self.yaxis_color = yaxis_color
- if is_tick:
- self.yaxis_tick = yaxis_font
-
- if self.data != None:
- # 2D
- self.yaxis(self.yaxis_label, self.yaxis_unit, \
- self.yaxis_font, self.yaxis_color, self.yaxis_tick)
- self.subplot.figure.canvas.draw_idle()
- else:
- # 1D
- self._check_zoom_plot()
-
- def _on_axis_label(self, axis='x'):
- """
- Modify axes labels
-
- :param axis: x or y axis [string]
- """
- is_ok = True
- title = 'Modify %s axis label' % axis
- font = 'serif'
- colour = 'black'
- if axis == 'x':
- label = self.xaxis_label
- unit = self.xaxis_unit
- else:
- label = self.yaxis_label
- unit = self.yaxis_unit
- textdial = TextDialog(None, -1, title, label, unit)
- if textdial.ShowModal() == wx.ID_OK:
- try:
- FONT = FontProperties()
- font = FONT.copy()
- font.set_size(textdial.getSize())
- font.set_family(textdial.getFamily())
- font.set_style(textdial.getStyle())
- font.set_weight(textdial.getWeight())
- unit = textdial.getUnit()
- colour = textdial.getColor()
- is_tick = textdial.getTickLabel()
- label_temp = textdial.getText()
- if label_temp.count("\%s" % "\\") > 0:
- if self.parent != None:
- msg = "Add Label: Error. Can not use double '\\' "
- msg += "characters..."
- wx.PostEvent(self.parent, StatusEvent(status=msg))
- else:
- label = label_temp
- except:
- if self.parent != None:
- msg = "Add Label: Error. Check your property values..."
- wx.PostEvent(self.parent, StatusEvent(status=msg))
- else:
- pass
- else:
- is_ok = False
- is_tick = True
- textdial.Destroy()
- return label, unit, font, colour, is_ok, is_tick
-
- def _on_removetext(self, event):
- """
- Removes all text from the plot.
- Eventually, add option to remove specific text boxes
- """
- num_text = len(self.textList)
- if num_text < 1:
- if self.parent != None:
- msg = "Remove Text: Nothing to remove. "
- wx.PostEvent(self.parent, StatusEvent(status=msg))
- else:
- raise
- return
- txt = self.textList[num_text - 1]
- try:
- text_remove = txt.get_text()
- txt.remove()
- if self.parent != None:
- msg = "Removed Text: '%s'. " % text_remove
- wx.PostEvent(self.parent, StatusEvent(status=msg))
- except:
- if self.parent != None:
- msg = "Remove Text: Error occurred. "
- wx.PostEvent(self.parent, StatusEvent(status=msg))
- else:
- raise
- self.textList.remove(txt)
-
- self.subplot.figure.canvas.draw_idle()
-
- def properties(self, prop):
- """
- Set some properties of the graph.
- The set of properties is not yet determined.
-
- """
- # The particulars of how they are stored and manipulated (e.g., do
- # we want an inventory internally) is not settled. I've used a
- # property dictionary for now.
- #
- # How these properties interact with a user defined style file is
- # even less clear.
-
- # Properties defined by plot
-
- # Ricardo:
- # A empty label "$$" will prevent the panel from displaying!
- if prop["xlabel"]:
- self.subplot.set_xlabel(r"$%s$"%prop["xlabel"])
- if prop["ylabel"]:
- self.subplot.set_ylabel(r"$%s$"%prop["ylabel"])
- self.subplot.set_title(prop["title"])
-
-
- def clear(self):
- """Reset the plot"""
- # TODO: Redraw is brutal. Render to a backing store and swap in
- # TODO: rather than redrawing on the fly.
- self.subplot.clear()
- self.subplot.hold(True)
-
- def render(self):
- """Commit the plot after all objects are drawn"""
- # TODO: this is when the backing store should be swapped in.
- if self.legend_on:
- ax = self.subplot
- ax.texts = self.textList
- try:
- handles, labels = ax.get_legend_handles_labels()
- # sort them by labels
- hl = sorted(zip(handles, labels),
- key=operator.itemgetter(1))
- handles2, labels2 = zip(*hl)
- self.line_collections_list = handles2
- self.legend = ax.legend(handles2, labels2,
- prop=FontProperties(size=10),
- loc=self.legendLoc)
- if self.legend != None:
- self.legend.set_picker(self.legend_picker)
- self.legend.set_axes(self.subplot)
- self.legend.set_zorder(20)
-
- except:
- self.legend = ax.legend(prop=FontProperties(size=10),
- loc=self.legendLoc)
-
- def xaxis(self, label, units, font=None, color='black', t_font=None):
- """xaxis label and units.
-
- Axis labels know about units.
-
- We need to do this so that we can detect when axes are not
- commesurate. Currently this is ignored other than for formatting
- purposes.
-
- """
-
- self.xcolor = color
- if units.count("{") > 0 and units.count("$") < 2:
- units = '$' + units + '$'
- if label.count("{") > 0 and label.count("$") < 2:
- label = '$' + label + '$'
- if units != "":
- label = label + " (" + units + ")"
- if font:
- self.subplot.set_xlabel(label, fontproperties=font, color=color)
- if t_font != None:
- for tick in self.subplot.xaxis.get_major_ticks():
- tick.label.set_fontproperties(t_font)
- for line in self.subplot.xaxis.get_ticklines():
- size = t_font.get_size()
- line.set_markersize(size / 3)
- else:
- self.subplot.set_xlabel(label, color=color)
- pass
-
- def yaxis(self, label, units, font=None, color='black', t_font=None):
- """yaxis label and units."""
- self.ycolor = color
- if units.count("{") > 0 and units.count("$") < 2:
- units = '$' + units + '$'
- if label.count("{") > 0 and label.count("$") < 2:
- label = '$' + label + '$'
- if units != "":
- label = label + " (" + units + ")"
- if font:
- self.subplot.set_ylabel(label, fontproperties=font, color=color)
- if t_font != None:
- for tick_label in self.subplot.get_yticklabels():
- tick_label.set_fontproperties(t_font)
- for line in self.subplot.yaxis.get_ticklines():
- size = t_font.get_size()
- line.set_markersize(size / 3)
- else:
- self.subplot.set_ylabel(label, color=color)
- pass
-
- def _connect_to_xlim(self, callback):
- """Bind the xlim change notification to the callback"""
- def process_xlim(axes):
- lo, hi = subplot.get_xlim()
- callback(lo, hi)
- self.subplot.callbacks.connect('xlim_changed', process_xlim)
-
- def interactive_points(self, x, y, dx=None, dy=None, name='', color=0,
- symbol=0, markersize=5, zorder=1, id=None,
- label=None, hide_error=False):
- """Draw markers with error bars"""
- self.subplot.set_yscale('linear')
- self.subplot.set_xscale('linear')
- if id is None:
- id = name
- from plottable_interactor import PointInteractor
- p = PointInteractor(self, self.subplot, zorder=zorder, id=id)
- if p.markersize != None:
- markersize = p.markersize
- p.points(x, y, dx=dx, dy=dy, color=color, symbol=symbol, zorder=zorder,
- markersize=markersize, label=label, hide_error=hide_error)
-
- self.subplot.set_yscale(self.yscale, nonposy='clip')
- self.subplot.set_xscale(self.xscale)
-
- def interactive_curve(self, x, y, dy=None, name='', color=0,
- symbol=0, zorder=1, id=None, label=None):
- """Draw markers with error bars"""
- self.subplot.set_yscale('linear')
- self.subplot.set_xscale('linear')
- if id is None:
- id = name
- from plottable_interactor import PointInteractor
- p = PointInteractor(self, self.subplot, zorder=zorder, id=id)
- p.curve(x, y, dy=dy, color=color, symbol=symbol, zorder=zorder,
- label=label)
-
- self.subplot.set_yscale(self.yscale, nonposy='clip')
- self.subplot.set_xscale(self.xscale)
-
- def plottable_selected(self, id):
- """
- Called to register a plottable as selected
- """
- #TODO: check that it really is in the list of plottables
- self.graph.selected_plottable = id
-
- def points(self, x, y, dx=None, dy=None,
- color=0, symbol=0, marker_size=5, label=None,
- id=None, hide_error=False):
- """Draw markers with error bars"""
-
- # Convert tuple (lo,hi) to array [(x-lo),(hi-x)]
- if dx != None and type(dx) == type(()):
- dx = nx.vstack((x - dx[0], dx[1] - x)).transpose()
- if dy != None and type(dy) == type(()):
- dy = nx.vstack((y - dy[0], dy[1] - y)).transpose()
- if dx == None and dy == None:
- self.subplot.plot(x, y, color=self._color(color),
- marker=self._symbol(symbol),
- markersize=marker_size,
- linestyle='',
- label=label)
- else:
- col = self._color(color)
- if hide_error:
- self.subplot.plot(x, y, color=col,
- marker=self._symbol(symbol),
- markersize=marker_size,
- linestyle='',
- label=label)
- else:
- self.subplot.errorbar(x, y, yerr=dy, xerr=None,
- ecolor=col, capsize=2, linestyle='',
- barsabove=False,
- mec=col, mfc=col,
- marker=self._symbol(symbol),
- markersize=marker_size,
- lolims=False, uplims=False,
- xlolims=False, xuplims=False, label=label)
-
- self.subplot.set_yscale(self.yscale, nonposy='clip')
- self.subplot.set_xscale(self.xscale)
-
- def _onToggleScale(self, event):
- """
- toggle axis and replot image
-
- """
- zmin_2D_temp = self.zmin_2D
- zmax_2D_temp = self.zmax_2D
- if self.scale == 'log_{10}':
- self.scale = 'linear'
- if not self.zmin_2D is None:
- zmin_2D_temp = math.pow(10, self.zmin_2D)
- if not self.zmax_2D is None:
- zmax_2D_temp = math.pow(10, self.zmax_2D)
- else:
- self.scale = 'log_{10}'
- if not self.zmin_2D is None:
- # min log value: no log(negative)
- if self.zmin_2D <= 0:
- zmin_2D_temp = -32
- else:
- zmin_2D_temp = math.log10(self.zmin_2D)
- if not self.zmax_2D is None:
- zmax_2D_temp = math.log10(self.zmax_2D)
-
- self.image(data=self.data, qx_data=self.qx_data,
- qy_data=self.qy_data, xmin=self.xmin_2D,
- xmax=self.xmax_2D,
- ymin=self.ymin_2D, ymax=self.ymax_2D,
- cmap=self.cmap, zmin=zmin_2D_temp,
- zmax=zmax_2D_temp)
-
- def image(self, data, qx_data, qy_data, xmin, xmax, ymin, ymax,
- zmin, zmax, color=0, symbol=0, markersize=0,
- label='data2D', cmap=DEFAULT_CMAP):
- """
- Render the current data
-
- """
- self.data = data
- self.qx_data = qx_data
- self.qy_data = qy_data
- self.xmin_2D = xmin
- self.xmax_2D = xmax
- self.ymin_2D = ymin
- self.ymax_2D = ymax
- self.zmin_2D = zmin
- self.zmax_2D = zmax
- c = self._color(color)
- # If we don't have any data, skip.
- if self.data == None:
- return
- if self.data.ndim == 1:
- output = self._build_matrix()
- else:
- output = copy.deepcopy(self.data)
- # check scale
- if self.scale == 'log_{10}':
- try:
- if self.zmin_2D <= 0 and len(output[output > 0]) > 0:
- zmin_temp = self.zmin_2D
- output[output > 0] = numpy.log10(output[output > 0])
- #In log scale Negative values are not correct in general
- #output[output<=0] = math.log(numpy.min(output[output>0]))
- elif self.zmin_2D <= 0:
- zmin_temp = self.zmin_2D
- output[output > 0] = numpy.zeros(len(output))
- output[output <= 0] = -32
- else:
- zmin_temp = self.zmin_2D
- output[output > 0] = numpy.log10(output[output > 0])
- #In log scale Negative values are not correct in general
- #output[output<=0] = math.log(numpy.min(output[output>0]))
- except:
- #Too many problems in 2D plot with scale
- pass
-
- else:
- zmin_temp = self.zmin_2D
- self.cmap = cmap
- if self.dimension != 3:
- #Re-adjust colorbar
- self.subplot.figure.subplots_adjust(left=0.2, right=.8, bottom=.2)
-
- im = self.subplot.imshow(output, interpolation='nearest',
- origin='lower',
- vmin=zmin_temp, vmax=self.zmax_2D,
- cmap=self.cmap,
- extent=(self.xmin_2D, self.xmax_2D,
- self.ymin_2D, self.ymax_2D))
-
- cbax = self.subplot.figure.add_axes([0.84, 0.2, 0.02, 0.7])
- else:
- # clear the previous 2D from memory
- # mpl is not clf, so we do
- self.subplot.figure.clear()
-
- self.subplot.figure.subplots_adjust(left=0.1, right=.8, bottom=.1)
-
- X = self.x_bins[0:-1]
- Y = self.y_bins[0:-1]
- X, Y = numpy.meshgrid(X, Y)
-
- try:
- # mpl >= 1.0.0
- ax = self.subplot.figure.gca(projection='3d')
- #ax.disable_mouse_rotation()
- cbax = self.subplot.figure.add_axes([0.84, 0.1, 0.02, 0.8])
- if len(X) > 60:
- ax.disable_mouse_rotation()
- except:
- # mpl < 1.0.0
- try:
- from mpl_toolkits.mplot3d import Axes3D
- except:
- logging.error("PlotPanel could not import Axes3D")
- self.subplot.figure.clear()
- ax = Axes3D(self.subplot.figure)
- if len(X) > 60:
- ax.cla()
- cbax = None
- self.subplot.figure.canvas.resizing = False
- im = ax.plot_surface(X, Y, output, rstride=1, cstride=1, cmap=cmap,
- linewidth=0, antialiased=False)
- self.subplot.set_axis_off()
-
- if cbax == None:
- ax.set_frame_on(False)
- cb = self.subplot.figure.colorbar(im, shrink=0.8, aspect=20)
- else:
- cb = self.subplot.figure.colorbar(im, cax=cbax)
- cb.update_bruteforce(im)
- cb.set_label('$' + self.scale + '$')
- if self.dimension != 3:
- self.figure.canvas.draw_idle()
- else:
- self.figure.canvas.draw()
-
- def _build_matrix(self):
- """
- Build a matrix for 2d plot from a vector
- Returns a matrix (image) with ~ square binning
- Requirement: need 1d array formats of
- self.data, self.qx_data, and self.qy_data
- where each one corresponds to z, x, or y axis values
-
- """
- # No qx or qy given in a vector format
- if self.qx_data == None or self.qy_data == None \
- or self.qx_data.ndim != 1 or self.qy_data.ndim != 1:
- # do we need deepcopy here?
- return copy.deepcopy(self.data)
-
- # maximum # of loops to fillup_pixels
- # otherwise, loop could never stop depending on data
- max_loop = 1
- # get the x and y_bin arrays.
- self._get_bins()
- # set zero to None
-
- #Note: Can not use scipy.interpolate.Rbf:
- # 'cause too many data points (>10000)<=JHC.
- # 1d array to use for weighting the data point averaging
- #when they fall into a same bin.
- weights_data = numpy.ones([self.data.size])
- # get histogram of ones w/len(data); this will provide
- #the weights of data on each bins
- weights, xedges, yedges = numpy.histogram2d(x=self.qy_data,
- y=self.qx_data,
- bins=[self.y_bins, self.x_bins],
- weights=weights_data)
- # get histogram of data, all points into a bin in a way of summing
- image, xedges, yedges = numpy.histogram2d(x=self.qy_data,
- y=self.qx_data,
- bins=[self.y_bins, self.x_bins],
- weights=self.data)
- # Now, normalize the image by weights only for weights>1:
- # If weight == 1, there is only one data point in the bin so
- # that no normalization is required.
- image[weights > 1] = image[weights > 1] / weights[weights > 1]
- # Set image bins w/o a data point (weight==0) as None (was set to zero
- # by histogram2d.)
- image[weights == 0] = None
-
- # Fill empty bins with 8 nearest neighbors only when at least
- #one None point exists
- loop = 0
-
- # do while loop until all vacant bins are filled up up
- #to loop = max_loop
- while not(numpy.isfinite(image[weights == 0])).all():
- if loop >= max_loop: # this protects never-ending loop
- break
- image = self._fillup_pixels(image=image, weights=weights)
- loop += 1
-
- return image
-
- def _get_bins(self):
- """
- get bins
- set x_bins and y_bins into self, 1d arrays of the index with
- ~ square binning
- Requirement: need 1d array formats of
- self.qx_data, and self.qy_data
- where each one corresponds to x, or y axis values
- """
- # No qx or qy given in a vector format
- if self.qx_data == None or self.qy_data == None \
- or self.qx_data.ndim != 1 or self.qy_data.ndim != 1:
- # do we need deepcopy here?
- return copy.deepcopy(self.data)
-
- # find max and min values of qx and qy
- xmax = self.qx_data.max()
- xmin = self.qx_data.min()
- ymax = self.qy_data.max()
- ymin = self.qy_data.min()
-
- # calculate the range of qx and qy: this way, it is a little
- # more independent
- x_size = xmax - xmin
- y_size = ymax - ymin
-
- # estimate the # of pixels on each axes
- npix_y = int(math.floor(math.sqrt(len(self.qy_data))))
- npix_x = int(math.floor(len(self.qy_data) / npix_y))
-
- # bin size: x- & y-directions
- xstep = x_size / (npix_x - 1)
- ystep = y_size / (npix_y - 1)
-
- # max and min taking account of the bin sizes
- xmax = xmax + xstep / 2.0
- xmin = xmin - xstep / 2.0
- ymax = ymax + ystep / 2.0
- ymin = ymin - ystep / 2.0
-
- # store x and y bin centers in q space
- x_bins = numpy.linspace(xmin, xmax, npix_x)
- y_bins = numpy.linspace(ymin, ymax, npix_y)
-
- #set x_bins and y_bins
- self.x_bins = x_bins
- self.y_bins = y_bins
-
- def _fillup_pixels(self, image=None, weights=None):
- """
- Fill z values of the empty cells of 2d image matrix
- with the average over up-to next nearest neighbor points
-
- :param image: (2d matrix with some zi = None)
-
- :return: image (2d array )
-
- :TODO: Find better way to do for-loop below
-
- """
- # No image matrix given
- if image == None or numpy.ndim(image) != 2 \
- or numpy.isfinite(image).all() \
- or weights == None:
- return image
- # Get bin size in y and x directions
- len_y = len(image)
- len_x = len(image[1])
- temp_image = numpy.zeros([len_y, len_x])
- weit = numpy.zeros([len_y, len_x])
- # do for-loop for all pixels
- for n_y in range(len(image)):
- for n_x in range(len(image[1])):
- # find only null pixels
- if weights[n_y][n_x] > 0 or numpy.isfinite(image[n_y][n_x]):
- continue
- else:
- # find 4 nearest neighbors
- # check where or not it is at the corner
- if n_y != 0 and numpy.isfinite(image[n_y - 1][n_x]):
- temp_image[n_y][n_x] += image[n_y - 1][n_x]
- weit[n_y][n_x] += 1
- if n_x != 0 and numpy.isfinite(image[n_y][n_x - 1]):
- temp_image[n_y][n_x] += image[n_y][n_x - 1]
- weit[n_y][n_x] += 1
- if n_y != len_y - 1 and numpy.isfinite(image[n_y + 1][n_x]):
- temp_image[n_y][n_x] += image[n_y + 1][n_x]
- weit[n_y][n_x] += 1
- if n_x != len_x - 1 and numpy.isfinite(image[n_y][n_x + 1]):
- temp_image[n_y][n_x] += image[n_y][n_x + 1]
- weit[n_y][n_x] += 1
- # go 4 next nearest neighbors when no non-zero
- # neighbor exists
- if n_y != 0 and n_x != 0 and\
- numpy.isfinite(image[n_y - 1][n_x - 1]):
- temp_image[n_y][n_x] += image[n_y - 1][n_x - 1]
- weit[n_y][n_x] += 1
- if n_y != len_y - 1 and n_x != 0 and \
- numpy.isfinite(image[n_y + 1][n_x - 1]):
- temp_image[n_y][n_x] += image[n_y + 1][n_x - 1]
- weit[n_y][n_x] += 1
- if n_y != len_y and n_x != len_x - 1 and \
- numpy.isfinite(image[n_y - 1][n_x + 1]):
- temp_image[n_y][n_x] += image[n_y - 1][n_x + 1]
- weit[n_y][n_x] += 1
- if n_y != len_y - 1 and n_x != len_x - 1 and \
- numpy.isfinite(image[n_y + 1][n_x + 1]):
- temp_image[n_y][n_x] += image[n_y + 1][n_x + 1]
- weit[n_y][n_x] += 1
-
- # get it normalized
- ind = (weit > 0)
- image[ind] = temp_image[ind] / weit[ind]
-
- return image
-
- def curve(self, x, y, dy=None, color=0, symbol=0, label=None):
- """Draw a line on a graph, possibly with confidence intervals."""
- c = self._color(color)
- self.subplot.set_yscale('linear')
- self.subplot.set_xscale('linear')
-
- self.subplot.plot(x, y, color=c, marker='',
- linestyle='-', label=label)
- self.subplot.set_yscale(self.yscale)
- self.subplot.set_xscale(self.xscale)
-
- def _color(self, c):
- """Return a particular colour"""
- return self.colorlist[c % len(self.colorlist)]
-
- def _symbol(self, s):
- """Return a particular symbol"""
- return self.symbollist[s % len(self.symbollist)]
-
- def _replot(self, remove_fit=False):
- """
- Rescale the plottables according to the latest
- user selection and update the plot
-
- :param remove_fit: Fit line will be removed if True
-
- """
- self.graph.reset_scale()
- self._onEVT_FUNC_PROPERTY(remove_fit=remove_fit)
- #TODO: Why do we have to have the following line?
- self.fit_result.reset_view()
- self.graph.render(self)
- self.subplot.figure.canvas.draw_idle()
-
- def _onEVT_FUNC_PROPERTY(self, remove_fit=True, show=True):
- """
- Receive the x and y transformation from myDialog,
- Transforms x and y in View
- and set the scale
- """
- # The logic should be in the right order
- # Delete first, and then get the whole list...
- if remove_fit:
- self.graph.delete(self.fit_result)
- if hasattr(self, 'plots'):
- if 'fit' in self.plots.keys():
- del self.plots['fit']
- self.ly = None
- self.q_ctrl = None
- list = self.graph.returnPlottable()
- # Changing the scale might be incompatible with
- # currently displayed data (for instance, going
- # from ln to log when all plotted values have
- # negative natural logs).
- # Go linear and only change the scale at the end.
- self.set_xscale("linear")
- self.set_yscale("linear")
- _xscale = 'linear'
- _yscale = 'linear'
- for item in list:
- if item.id == 'fit':
- continue
- item.setLabel(self.xLabel, self.yLabel)
- # control axis labels from the panel itself
- yname, yunits = item.get_yaxis()
- if self.yaxis_label != None:
- yname = self.yaxis_label
- yunits = self.yaxis_unit
- else:
- self.yaxis_label = yname
- self.yaxis_unit = yunits
- xname, xunits = item.get_xaxis()
- if self.xaxis_label != None:
- xname = self.xaxis_label
- xunits = self.xaxis_unit
- else:
- self.xaxis_label = xname
- self.xaxis_unit = xunits
- # Goes through all possible scales
- if self.xLabel == "x":
- item.transformX(transform.toX, transform.errToX)
- self.graph._xaxis_transformed("%s" % xname, "%s" % xunits)
- if self.xLabel == "x^(2)":
- item.transformX(transform.toX2, transform.errToX2)
- xunits = convert_unit(2, xunits)
- self.graph._xaxis_transformed("%s^{2}" % xname, "%s" % xunits)
- if self.xLabel == "x^(4)":
- item.transformX(transform.toX4, transform.errToX4)
- xunits = convert_unit(4, xunits)
- self.graph._xaxis_transformed("%s^{4}" % xname, "%s" % xunits)
- if self.xLabel == "ln(x)":
- item.transformX(transform.toLogX, transform.errToLogX)
- self.graph._xaxis_transformed("\ln{(%s)}" % xname, "%s" % xunits)
- if self.xLabel == "log10(x)":
- item.transformX(transform.toX_pos, transform.errToX_pos)
- _xscale = 'log'
- self.graph._xaxis_transformed("%s" % xname, "%s" % xunits)
- if self.xLabel == "log10(x^(4))":
- item.transformX(transform.toX4, transform.errToX4)
- xunits = convert_unit(4, xunits)
- self.graph._xaxis_transformed("%s^{4}" % xname, "%s" % xunits)
- _xscale = 'log'
- if self.yLabel == "ln(y)":
- item.transformY(transform.toLogX, transform.errToLogX)
- self.graph._yaxis_transformed("\ln{(%s)}" % yname, "%s" % yunits)
- if self.yLabel == "y":
- item.transformY(transform.toX, transform.errToX)
- self.graph._yaxis_transformed("%s" % yname, "%s" % yunits)
- if self.yLabel == "log10(y)":
- item.transformY(transform.toX_pos, transform.errToX_pos)
- _yscale = 'log'
- self.graph._yaxis_transformed("%s" % yname, "%s" % yunits)
- if self.yLabel == "y^(2)":
- item.transformY(transform.toX2, transform.errToX2)
- yunits = convert_unit(2, yunits)
- self.graph._yaxis_transformed("%s^{2}" % yname, "%s" % yunits)
- if self.yLabel == "1/y":
- item.transformY(transform.toOneOverX, transform.errOneOverX)
- yunits = convert_unit(-1, yunits)
- self.graph._yaxis_transformed("1/%s" % yname, "%s" % yunits)
- if self.yLabel == "y*x^(2)":
- item.transformY(transform.toYX2, transform.errToYX2)
- xunits = convert_unit(2, self.xaxis_unit)
- self.graph._yaxis_transformed("%s \ \ %s^{2}" % (yname, xname),
- "%s%s" % (yunits, xunits))
- if self.yLabel == "y*x^(4)":
- item.transformY(transform.toYX4, transform.errToYX4)
- xunits = convert_unit(4, self.xaxis_unit)
- self.graph._yaxis_transformed("%s \ \ %s^{4}" % (yname, xname),
- "%s%s" % (yunits, xunits))
- if self.yLabel == "1/sqrt(y)":
- item.transformY(transform.toOneOverSqrtX,
- transform.errOneOverSqrtX)
- yunits = convert_unit(-0.5, yunits)
- self.graph._yaxis_transformed("1/\sqrt{%s}" % yname,
- "%s" % yunits)
- if self.yLabel == "ln(y*x)":
- item.transformY(transform.toLogXY, transform.errToLogXY)
- self.graph._yaxis_transformed("\ln{(%s \ \ %s)}" % (yname, xname),
- "%s%s" % (yunits, self.xaxis_unit))
- if self.yLabel == "ln(y*x^(2))":
- item.transformY(transform.toLogYX2, transform.errToLogYX2)
- xunits = convert_unit(2, self.xaxis_unit)
- self.graph._yaxis_transformed("\ln (%s \ \ %s^{2})" % (yname, xname),
- "%s%s" % (yunits, xunits))
- if self.yLabel == "ln(y*x^(4))":
- item.transformY(transform.toLogYX4, transform.errToLogYX4)
- xunits = convert_unit(4, self.xaxis_unit)
- self.graph._yaxis_transformed("\ln (%s \ \ %s^{4})" % (yname, xname),
- "%s%s" % (yunits, xunits))
- if self.yLabel == "log10(y*x^(4))":
- item.transformY(transform.toYX4, transform.errToYX4)
- xunits = convert_unit(4, self.xaxis_unit)
- _yscale = 'log'
- self.graph._yaxis_transformed("%s \ \ %s^{4}" % (yname, xname),
- "%s%s" % (yunits, xunits))
- item.transformView()
-
- # set new label and units
- yname = self.graph.prop["ylabel"]
- yunits = ''
- xname = self.graph.prop["xlabel"]
- xunits = ''
-
- self.resetFitView()
- self.prevXtrans = self.xLabel
- self.prevYtrans = self.yLabel
- self.graph.render(self)
- self.set_xscale(_xscale)
- self.set_yscale(_yscale)
-
- self.xaxis(xname, xunits, self.xaxis_font,
- self.xaxis_color, self.xaxis_tick)
- self.yaxis(yname, yunits, self.yaxis_font,
- self.yaxis_color, self.yaxis_tick)
- self.subplot.texts = self.textList
- if show:
- self.subplot.figure.canvas.draw_idle()
-
- def onFitDisplay(self, tempx, tempy, xminView,
- xmaxView, xmin, xmax, func):
- """
- Add a new plottable into the graph .In this case this plottable
- will be used to fit some data
-
- :param tempx: The x data of fit line
- :param tempy: The y data of fit line
- :param xminView: the lower bound of fitting range
- :param xminView: the upper bound of fitting range
- :param xmin: the lowest value of data to fit to the line
- :param xmax: the highest value of data to fit to the line
-
- """
- xlim = self.subplot.get_xlim()
- ylim = self.subplot.get_ylim()
-
- # Saving value to redisplay in Fit Dialog when it is opened again
- self.Avalue, self.Bvalue, self.ErrAvalue, \
- self.ErrBvalue, self.Chivalue = func
- self.xminView = xminView
- self.xmaxView = xmaxView
- self.xmin = xmin
- self.xmax = xmax
- #In case need to change the range of data plotted
- for item in self.graph.returnPlottable():
- item.onFitRange(None, None)
- # Create new data plottable with result
- self.fit_result.x = []
- self.fit_result.y = []
- self.fit_result.x = tempx
- self.fit_result.y = tempy
- self.fit_result.dx = None
- self.fit_result.dy = None
- #Load the view with the new values
- self.fit_result.reset_view()
- # Add the new plottable to the graph
- self.graph.add(self.fit_result)
- self.graph.render(self)
- self._offset_graph()
- if hasattr(self, 'plots'):
- # Used by Plotter1D
- fit_id = 'fit'
- self.fit_result.id = fit_id
- self.fit_result.title = 'Fit'
- self.fit_result.name = 'Fit'
- self.plots[fit_id] = self.fit_result
- self.subplot.set_xlim(xlim)
- self.subplot.set_ylim(ylim)
- self.subplot.figure.canvas.draw_idle()
-
- def onChangeCaption(self, event):
- """
- """
- if self.parent == None:
- return
- # get current caption
- old_caption = self.window_caption
- # Get new caption dialog
- dial = LabelDialog(None, -1, 'Modify Window Title', old_caption)
- if dial.ShowModal() == wx.ID_OK:
- new_caption = dial.getText()
-
- # send to guiframe to change the panel caption
- caption = self.parent.on_change_caption(self.window_name,
- old_caption, new_caption)
-
- # also set new caption in plot_panels list
- self.parent.plot_panels[self.uid].window_caption = caption
- # set new caption
- self.window_caption = caption
-
- dial.Destroy()
-
- def onResetGraph(self, event):
- """
- Reset the graph by plotting the full range of data
- """
- for item in self.graph.returnPlottable():
- item.onReset()
- self.graph.render(self)
- self._onEVT_FUNC_PROPERTY(False)
- self.is_zoomed = False
- self.toolbar.update()
-
- def onPrint(self, event=None):
- self.toolbar.print_figure(event)
-
- def onPrinterSetup(self, event=None):
- """
- """
- self.canvas.Printer_Setup(event=event)
- self.Update()
-
- def onPrinterPreview(self, event=None):
- """
- Matplotlib camvas can no longer print itself. Thus need to do
- everything ourselves: need to create a printpreview frame to to
- see the preview but needs a parent frame object. Also needs a
- printout object (just as any printing task).
- """
- try:
- #check if parent is a frame. If not keep getting the higher
- #parent till we find a frame
- _plot = self
- while not isinstance(_plot, wx.Frame):
- _plot = _plot.GetParent()
- assert _plot is not None
-
- #now create the printpeview object
- _preview = wx.PrintPreview(PlotPrintout(self.canvas),
- PlotPrintout(self.canvas))
- #and tie it to a printpreview frame then show it
- _frame = wx.PreviewFrame(_preview, _plot, "Print Preview", wx.Point(100, 100), wx.Size(600, 650))
- _frame.Centre(wx.BOTH)
- _frame.Initialize()
- _frame.Show(True)
- except:
- traceback.print_exc()
- pass
-
- def OnCopyFigureMenu(self, evt):
- """
- Copy the current figure to clipboard
- """
- try:
- self.toolbar.copy_figure(self.canvas)
- except:
- print "Error in copy Image"
-
-
-#---------------------------------------------------------------
-class NoRepaintCanvas(FigureCanvasWxAgg):
- """
- We subclass FigureCanvasWxAgg, overriding the _onPaint method, so that
- the draw method is only called for the first two paint events. After that,
- the canvas will only be redrawn when it is resized.
-
- """
- def __init__(self, *args, **kwargs):
- """
- """
- FigureCanvasWxAgg.__init__(self, *args, **kwargs)
- self._drawn = 0
-
- def _onPaint(self, evt):
- """
- Called when wxPaintEvt is generated
-
- """
- if not self._isRealized:
- self.realize()
- if self._drawn < 2:
- self.draw(repaint=False)
- self._drawn += 1
- self.gui_repaint(drawDC=wx.PaintDC(self))
+"""
+ Plot panel.
+"""
+from __future__ import print_function
+
+import logging
+import traceback
+import wx
+# Try a normal import first
+# If it fails, try specifying a version
+import matplotlib
+matplotlib.interactive(False)
+#Use the WxAgg back end. The Wx one takes too long to render
+matplotlib.use('WXAgg')
+from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg
+from matplotlib.figure import Figure
+import os
+import transform
+#TODO: make the plottables interactive
+from binder import BindArtist
+from matplotlib.font_manager import FontProperties
+DEBUG = False
+
+from plottables import Graph
+from TextDialog import TextDialog
+from LabelDialog import LabelDialog
+import operator
+
+import math
+import pylab
+DEFAULT_CMAP = pylab.cm.jet
+import copy
+import numpy as np
+
+from sas.sasgui.guiframe.events import StatusEvent
+from .toolbar import NavigationToolBar, PlotPrintout, bind
+
+logger = logging.getLogger(__name__)
+
+def show_tree(obj, d=0):
+ """Handy function for displaying a tree of graph objects"""
+ print("%s%s" % ("-"*d, obj.__class__.__name__))
+ if 'get_children' in dir(obj):
+ for a in obj.get_children(): show_tree(a, d + 1)
+
+from convert_units import convert_unit
+
+
+def _rescale(lo, hi, step, pt=None, bal=None, scale='linear'):
+ """
+ Rescale (lo,hi) by step, returning the new (lo,hi)
+ The scaling is centered on pt, with positive values of step
+ driving lo/hi away from pt and negative values pulling them in.
+ If bal is given instead of point, it is already in [0,1] coordinates.
+
+ This is a helper function for step-based zooming.
+
+ """
+ # Convert values into the correct scale for a linear transformation
+ # TODO: use proper scale transformers
+ loprev = lo
+ hiprev = hi
+ if scale == 'log':
+ assert lo > 0
+ if lo > 0:
+ lo = math.log10(lo)
+ if hi > 0:
+ hi = math.log10(hi)
+ if pt is not None:
+ pt = math.log10(pt)
+
+ # Compute delta from axis range * %, or 1-% if persent is negative
+ if step > 0:
+ delta = float(hi - lo) * step / 100
+ else:
+ delta = float(hi - lo) * step / (100 - step)
+
+ # Add scale factor proportionally to the lo and hi values,
+ # preserving the
+ # point under the mouse
+ if bal is None:
+ bal = float(pt - lo) / (hi - lo)
+ lo = lo - (bal * delta)
+ hi = hi + (1 - bal) * delta
+
+ # Convert transformed values back to the original scale
+ if scale == 'log':
+ if (lo <= -250) or (hi >= 250):
+ lo = loprev
+ hi = hiprev
+ else:
+ lo, hi = math.pow(10., lo), math.pow(10., hi)
+ return (lo, hi)
+
+
+class PlotPanel(wx.Panel):
+ """
+ The PlotPanel has a Figure and a Canvas. OnSize events simply set a
+ flag, and the actually redrawing of the
+ figure is triggered by an Idle event.
+ """
+ def __init__(self, parent, id=-1, xtransform=None,
+ ytransform=None, scale='log_{10}',
+ color=None, dpi=None, **kwargs):
+ """
+ """
+ wx.Panel.__init__(self, parent, id=id, **kwargs)
+ self.parent = parent
+ if hasattr(parent, "parent"):
+ self.parent = self.parent.parent
+ self.dimension = 1
+ self.gotLegend = 0 # to begin, legend is not picked.
+ self.legend_pos_loc = None
+ self.legend = None
+ self.line_collections_list = []
+ self.figure = Figure(None, dpi, linewidth=2.0)
+ self.color = '#b3b3b3'
+ from canvas import FigureCanvas
+ self.canvas = FigureCanvas(self, -1, self.figure)
+ self.SetColor(color)
+ self._resizeflag = True
+ self._SetSize()
+ self.subplot = self.figure.add_subplot(111)
+ self.figure.subplots_adjust(left=0.2, bottom=.2)
+ self.yscale = 'linear'
+ self.xscale = 'linear'
+ self.sizer = wx.BoxSizer(wx.VERTICAL)
+ self.sizer.Add(self.canvas, 1, wx.EXPAND)
+ #add toolbar
+ self.enable_toolbar = True
+ self.toolbar = None
+ self.add_toolbar()
+ self.SetSizer(self.sizer)
+
+ # Graph object to manage the plottables
+ self.graph = Graph()
+
+ #Boolean value to keep track of whether current legend is
+ #visible or not
+ self.legend_on = True
+ self.grid_on = False
+ #Location of legend, default is 0 or 'best'
+ self.legendLoc = 0
+ self.position = None
+ self._loc_labels = self.get_loc_label()
+
+ self.Bind(wx.EVT_CONTEXT_MENU, self.onContextMenu)
+
+ # Define some constants
+ self.colorlist = ['b', 'g', 'r', 'c', 'm', 'y', 'k']
+ self.symbollist = ['o', 'x', '^', 'v', '<', '>', '+',
+ 's', 'd', 'D', 'h', 'H', 'p', '-']
+
+ #List of texts currently on the plot
+ self.textList = []
+ self.selectedText = None
+ #User scale
+ if xtransform is not None:
+ self.xLabel = xtransform
+ else:
+ self.xLabel = "log10(x)"
+ if ytransform is not None:
+ self.yLabel = ytransform
+ else:
+ self.yLabel = "log10(y)"
+ self.viewModel = "--"
+ # keep track if the previous transformation of x
+ # and y in Property dialog
+ self.prevXtrans = "log10(x)"
+ self.prevYtrans = "log10(y)"
+ self.scroll_id = self.canvas.mpl_connect('scroll_event', self.onWheel)
+ #taking care of dragging
+ self.motion_id = self.canvas.mpl_connect('motion_notify_event',
+ self.onMouseMotion)
+ self.press_id = self.canvas.mpl_connect('button_press_event',
+ self.onLeftDown)
+ self.pick_id = self.canvas.mpl_connect('pick_event', self.onPick)
+ self.release_id = self.canvas.mpl_connect('button_release_event',
+ self.onLeftUp)
+
+ wx.EVT_RIGHT_DOWN(self, self.onLeftDown)
+ # to turn axis off whenn resizing the panel
+ self.resizing = False
+
+ self.leftdown = False
+ self.leftup = False
+ self.mousemotion = False
+ self.axes = [self.subplot]
+ ## Fit dialog
+ self._fit_dialog = None
+ # Interactor
+ self.connect = BindArtist(self.subplot.figure)
+ #self.selected_plottable = None
+
+ # new data for the fit
+ from sas.sasgui.guiframe.dataFitting import Data1D
+ self.fit_result = Data1D(x=[], y=[], dy=None)
+ self.fit_result.symbol = 13
+ #self.fit_result = Data1D(x=[], y=[],dx=None, dy=None)
+ self.fit_result.name = "Fit"
+ # For fit Dialog initial display
+ self.xmin = 0.0
+ self.xmax = 0.0
+ self.xminView = 0.0
+ self.xmaxView = 0.0
+ self._scale_xlo = None
+ self._scale_xhi = None
+ self._scale_ylo = None
+ self._scale_yhi = None
+ self.Avalue = None
+ self.Bvalue = None
+ self.ErrAvalue = None
+ self.ErrBvalue = None
+ self.Chivalue = None
+
+ # for 2D scale
+ if scale != 'linear':
+ scale = 'log_{10}'
+ self.scale = scale
+ self.data = None
+ self.qx_data = None
+ self.qy_data = None
+ self.xmin_2D = None
+ self.xmax_2D = None
+ self.ymin_2D = None
+ self.ymax_2D = None
+ ## store reference to the current plotted vmin and vmax of plotted image
+ ##z range in linear scale
+ self.zmin_2D = None
+ self.zmax_2D = None
+
+ #index array
+ self.index_x = None
+ self.index_y = None
+
+ #number of bins
+ self.x_bins = None
+ self.y_bins = None
+
+ ## default color map
+ self.cmap = DEFAULT_CMAP
+
+ # Dragging info
+ self.begDrag = False
+ self.xInit = None
+ self.yInit = None
+ self.xFinal = None
+ self.yFinal = None
+
+ #axes properties
+ self.xaxis_font = None
+ self.xaxis_label = None
+ self.xaxis_unit = None
+ self.xaxis_color = 'black'
+ self.xaxis_tick = None
+ self.yaxis_font = None
+ self.yaxis_label = None
+ self.yaxis_unit = None
+ self.yaxis_color = 'black'
+ self.yaxis_tick = None
+
+ # check if zoomed.
+ self.is_zoomed = False
+ # Plottables
+ self.plots = {}
+
+ # Default locations
+ self._default_save_location = os.getcwd()
+ # let canvas know about axes
+ self.canvas.set_panel(self)
+ self.ly = None
+ self.q_ctrl = None
+ #Bind focus to change the border color
+ self.canvas.Bind(wx.EVT_SET_FOCUS, self.on_set_focus)
+ self.canvas.Bind(wx.EVT_KILL_FOCUS, self.on_kill_focus)
+
+ def _SetInitialSize(self,):
+ """
+ """
+ pixels = self.parent.GetClientSize()
+ self.canvas.SetSize(pixels)
+ self.figure.set_size_inches(pixels[0] / self.figure.get_dpi(),
+ pixels[1] / self.figure.get_dpi(), forward=True)
+
+ def On_Paint(self, event):
+ """
+ """
+ self.canvas.SetBackgroundColour(self.color)
+
+ def on_set_focus(self, event):
+ """
+ Send to the parenet the current panel on focus
+ """
+ # light blue
+ self.color = '#0099f7'
+ self.figure.set_edgecolor(self.color)
+ if self.parent and self.window_caption:
+ self.parent.send_focus_to_datapanel(self.window_caption)
+ self.draw()
+
+ def on_kill_focus(self, event):
+ """
+ Reset the panel color
+ """
+ # light grey
+ self.color = '#b3b3b3'
+ self.figure.set_edgecolor(self.color)
+ self.draw()
+
+ def set_resizing(self, resizing=False):
+ """
+ Set the resizing (True/False)
+ """
+ pass # Not implemented
+
+ def schedule_full_draw(self, func='append'):
+ """
+ Put self in schedule to full redraw list
+ """
+ pass # Not implemented
+
+ def add_toolbar(self):
+ """
+ add toolbar
+ """
+ self.enable_toolbar = True
+ self.toolbar = NavigationToolBar(parent=self, canvas=self.canvas)
+ bind(self.toolbar, wx.EVT_TOOL, self.onResetGraph, id=self.toolbar._NTB2_RESET)
+ bind(self.toolbar, wx.EVT_TOOL, self.onContextMenu, id=self.toolbar._NTB2_HOME)
+ self.toolbar.Realize()
+ ## The 'SetToolBar()' is not working on MAC: JHC
+ #if IS_MAC:
+ # Mac platform (OSX 10.3, MacPython) does not seem to cope with
+ # having a toolbar in a sizer. This work-around gets the buttons
+ # back, but at the expense of having the toolbar at the top
+ #self.SetToolBar(self.toolbar)
+ #else:
+ # On Windows platform, default window size is incorrect, so set
+ # toolbar width to figure width.
+ tw, th = self.toolbar.GetSizeTuple()
+ fw, fh = self.canvas.GetSizeTuple()
+ # By adding toolbar in sizer, we are able to put it at the bottom
+ # of the frame - so appearance is closer to GTK version.
+ # As noted above, doesn't work for Mac.
+ self.toolbar.SetSize(wx.Size(fw, th))
+ self.sizer.Add(self.toolbar, 0, wx.LEFT | wx.EXPAND)
+
+ # update the axes menu on the toolbar
+ self.toolbar.update()
+
+ def onLeftDown(self, event):
+ """
+ left button down and ready to drag
+ """
+ # Check that the LEFT button was pressed
+ if event.button == 1:
+ self.leftdown = True
+ ax = event.inaxes
+ for text in self.textList:
+ if text.contains(event)[0]: # If user has clicked on text
+ self.selectedText = text
+ return
+
+ if ax is not None:
+ self.xInit, self.yInit = event.xdata, event.ydata
+ try:
+ pos_x = float(event.xdata) # / size_x
+ pos_y = float(event.ydata) # / size_y
+ pos_x = "%8.3g" % pos_x
+ pos_y = "%8.3g" % pos_y
+ self.position = str(pos_x), str(pos_y)
+ wx.PostEvent(self.parent, StatusEvent(status=self.position))
+ except:
+ self.position = None
+
+ def onLeftUp(self, event):
+ """
+ Dragging is done
+ """
+ # Check that the LEFT button was released
+ if event.button == 1:
+ self.leftdown = False
+ self.mousemotion = False
+ self.leftup = True
+ self.selectedText = None
+
+ #release the legend
+ if self.gotLegend == 1:
+ self.gotLegend = 0
+ self.set_legend_alpha(1)
+
+ def set_legend_alpha(self, alpha=1):
+ """
+ Set legend alpha
+ """
+ if self.legend is not None:
+ self.legend.legendPatch.set_alpha(alpha)
+
+ def onPick(self, event):
+ """
+ On pick legend
+ """
+ legend = self.legend
+ if event.artist == legend:
+ #gets the box of the legend.
+ bbox = self.legend.get_window_extent()
+ #get mouse coordinates at time of pick.
+ self.mouse_x = event.mouseevent.x
+ self.mouse_y = event.mouseevent.y
+ #get legend coordinates at time of pick.
+ self.legend_x = bbox.xmin
+ self.legend_y = bbox.ymin
+ #indicates we picked up the legend.
+ self.gotLegend = 1
+ self.set_legend_alpha(0.5)
+
+ def _on_legend_motion(self, event):
+ """
+ On legend in motion
+ """
+ ax = event.inaxes
+ if ax is None:
+ return
+ # Event occurred inside a plotting area
+ lo_x, hi_x = ax.get_xlim()
+ lo_y, hi_y = ax.get_ylim()
+ # How much the mouse moved.
+ x = mouse_diff_x = self.mouse_x - event.x
+ y = mouse_diff_y = self.mouse_y - event.y
+ # Put back inside
+ if x < lo_x:
+ x = lo_x
+ if x > hi_x:
+ x = hi_x
+ if y < lo_y:
+ y = lo_y
+ if y > hi_y:
+ y = hi_y
+ # Move the legend from its previous location by that same amount
+ loc_in_canvas = self.legend_x - mouse_diff_x, \
+ self.legend_y - mouse_diff_y
+ # Transform into legend coordinate system
+ trans_axes = self.legend.parent.transAxes.inverted()
+ loc_in_norm_axes = trans_axes.transform_point(loc_in_canvas)
+ self.legend_pos_loc = tuple(loc_in_norm_axes)
+ self.legend._loc = self.legend_pos_loc
+ self.resizing = True
+ self.canvas.set_resizing(self.resizing)
+ self.canvas.draw()
+
+ def onMouseMotion(self, event):
+ """
+ check if the left button is press and the mouse in moving.
+ computer delta for x and y coordinates and then calls draghelper
+ to perform the drag
+ """
+ self.cusor_line(event)
+ if self.gotLegend == 1 and self.leftdown:
+ self._on_legend_motion(event)
+ return
+
+ if self.leftdown and self.selectedText is not None:
+ # User has clicked on text and is dragging
+ ax = event.inaxes
+ if ax is not None:
+ # Only move text if mouse is within axes
+ self.selectedText.set_position((event.xdata, event.ydata))
+ self._dragHelper(0, 0)
+ else:
+ # User has dragged outside of axes
+ self.selectedText = None
+ return
+
+ if self.enable_toolbar:
+ #Disable dragging without the toolbar to allow zooming with toolbar
+ return
+ self.mousemotion = True
+ if self.leftdown == True and self.mousemotion == True:
+ ax = event.inaxes
+ if ax is not None: # the dragging is perform inside the figure
+ self.xFinal, self.yFinal = event.xdata, event.ydata
+ # Check whether this is the first point
+ if self.xInit is None:
+ self.xInit = self.xFinal
+ self.yInit = self.yFinal
+
+ xdelta = self.xFinal - self.xInit
+ ydelta = self.yFinal - self.yInit
+
+ if self.xscale == 'log':
+ xdelta = math.log10(self.xFinal) - math.log10(self.xInit)
+ if self.yscale == 'log':
+ ydelta = math.log10(self.yFinal) - math.log10(self.yInit)
+ self._dragHelper(xdelta, ydelta)
+ else: # no dragging is perform elsewhere
+ self._dragHelper(0, 0)
+
+ def cusor_line(self, event):
+ """
+ """
+ pass
+
+ def _offset_graph(self):
+ """
+ Zoom and offset the graph to the last known settings
+ """
+ for ax in self.axes:
+ if self._scale_xhi is not None and self._scale_xlo is not None:
+ ax.set_xlim(self._scale_xlo, self._scale_xhi)
+ if self._scale_yhi is not None and self._scale_ylo is not None:
+ ax.set_ylim(self._scale_ylo, self._scale_yhi)
+
+ def _dragHelper(self, xdelta, ydelta):
+ """
+ dragging occurs here
+ """
+ # Event occurred inside a plotting area
+ for ax in self.axes:
+ lo, hi = ax.get_xlim()
+ newlo, newhi = lo - xdelta, hi - xdelta
+ if self.xscale == 'log':
+ if lo > 0:
+ newlo = math.log10(lo) - xdelta
+ if hi > 0:
+ newhi = math.log10(hi) - xdelta
+ if self.xscale == 'log':
+ self._scale_xlo = math.pow(10, newlo)
+ self._scale_xhi = math.pow(10, newhi)
+ ax.set_xlim(math.pow(10, newlo), math.pow(10, newhi))
+ else:
+ self._scale_xlo = newlo
+ self._scale_xhi = newhi
+ ax.set_xlim(newlo, newhi)
+
+ lo, hi = ax.get_ylim()
+ newlo, newhi = lo - ydelta, hi - ydelta
+ if self.yscale == 'log':
+ if lo > 0:
+ newlo = math.log10(lo) - ydelta
+ if hi > 0:
+ newhi = math.log10(hi) - ydelta
+ if self.yscale == 'log':
+ self._scale_ylo = math.pow(10, newlo)
+ self._scale_yhi = math.pow(10, newhi)
+ ax.set_ylim(math.pow(10, newlo), math.pow(10, newhi))
+ else:
+ self._scale_ylo = newlo
+ self._scale_yhi = newhi
+ ax.set_ylim(newlo, newhi)
+ self.canvas.draw_idle()
+
+ def resetFitView(self):
+ """
+ For fit Dialog initial display
+ """
+ self.xmin = 0.0
+ self.xmax = 0.0
+ self.xminView = 0.0
+ self.xmaxView = 0.0
+ self._scale_xlo = None
+ self._scale_xhi = None
+ self._scale_ylo = None
+ self._scale_yhi = None
+ self.Avalue = None
+ self.Bvalue = None
+ self.ErrAvalue = None
+ self.ErrBvalue = None
+ self.Chivalue = None
+
+ def onWheel(self, event):
+ """
+ Process mouse wheel as zoom events
+
+ :param event: Wheel event
+
+ """
+ ax = event.inaxes
+ step = event.step
+
+ if ax is not None:
+ # Event occurred inside a plotting area
+ lo, hi = ax.get_xlim()
+ lo, hi = _rescale(lo, hi, step,
+ pt=event.xdata, scale=ax.get_xscale())
+ if not self.xscale == 'log' or lo > 0:
+ self._scale_xlo = lo
+ self._scale_xhi = hi
+ ax.set_xlim((lo, hi))
+
+ lo, hi = ax.get_ylim()
+ lo, hi = _rescale(lo, hi, step, pt=event.ydata,
+ scale=ax.get_yscale())
+ if not self.yscale == 'log' or lo > 0:
+ self._scale_ylo = lo
+ self._scale_yhi = hi
+ ax.set_ylim((lo, hi))
+ else:
+ # Check if zoom happens in the axes
+ xdata, ydata = None, None
+ x, y = event.x, event.y
+
+ for ax in self.axes:
+ insidex, _ = ax.xaxis.contains(event)
+ if insidex:
+ xdata, _ = ax.transAxes.inverted().transform_point((x, y))
+ insidey, _ = ax.yaxis.contains(event)
+ if insidey:
+ _, ydata = ax.transAxes.inverted().transform_point((x, y))
+ if xdata is not None:
+ lo, hi = ax.get_xlim()
+ lo, hi = _rescale(lo, hi, step,
+ bal=xdata, scale=ax.get_xscale())
+ if not self.xscale == 'log' or lo > 0:
+ self._scale_xlo = lo
+ self._scale_xhi = hi
+ ax.set_xlim((lo, hi))
+ if ydata is not None:
+ lo, hi = ax.get_ylim()
+ lo, hi = _rescale(lo, hi, step, bal=ydata,
+ scale=ax.get_yscale())
+ if not self.yscale == 'log' or lo > 0:
+ self._scale_ylo = lo
+ self._scale_yhi = hi
+ ax.set_ylim((lo, hi))
+ self.canvas.draw_idle()
+
+ def returnTrans(self):
+ """
+ Return values and labels used by Fit Dialog
+ """
+ return self.xLabel, self.yLabel, self.Avalue, self.Bvalue, \
+ self.ErrAvalue, self.ErrBvalue, self.Chivalue
+
+ def setTrans(self, xtrans, ytrans):
+ """
+
+ :param xtrans: set x transformation on Property dialog
+ :param ytrans: set y transformation on Property dialog
+
+ """
+ self.prevXtrans = xtrans
+ self.prevYtrans = ytrans
+
+ def onFitting(self, event):
+ """
+ when clicking on linear Fit on context menu , display Fitting Dialog
+ """
+ plot_dict = {}
+ menu = event.GetEventObject()
+ event_id = event.GetId()
+ self.set_selected_from_menu(menu, event_id)
+ plotlist = self.graph.returnPlottable()
+ if self.graph.selected_plottable is not None:
+ for item in plotlist:
+ if item.id == self.graph.selected_plottable:
+ plot_dict[item] = plotlist[item]
+ else:
+ plot_dict = plotlist
+ from fitDialog import LinearFit
+
+ if len(plot_dict.keys()) > 0:
+ first_item = plot_dict.keys()[0]
+ dlg = LinearFit(parent=None, plottable=first_item,
+ push_data=self.onFitDisplay,
+ transform=self.returnTrans,
+ title='Linear Fit')
+
+ if (self.xmin != 0.0)and (self.xmax != 0.0)\
+ and(self.xminView != 0.0)and (self.xmaxView != 0.0):
+ dlg.setFitRange(self.xminView, self.xmaxView,
+ self.xmin, self.xmax)
+ else:
+ xlim = self.subplot.get_xlim()
+ ylim = self.subplot.get_ylim()
+ dlg.setFitRange(xlim[0], xlim[1], ylim[0], ylim[1])
+ # It would be nice for this to NOT be modal (i.e. Show).
+ # Not sure about other ramifications - for example
+ # if a second linear fit is started before the first is closed.
+ # consider for future - being able to work on the plot while
+ # seing the fit values would be very nice -- PDB 7/10/16
+ dlg.ShowModal()
+
+ def set_selected_from_menu(self, menu, id):
+ """
+ Set selected_plottable from context menu selection
+
+ :param menu: context menu item
+ :param id: menu item id
+ """
+ if len(self.plots) < 1:
+ return
+ name = menu.GetHelpString(id)
+ for plot in self.plots.values():
+ if plot.name == name:
+ self.graph.selected_plottable = plot.id
+ break
+
+ def linear_plottable_fit(self, plot):
+ """
+ when clicking on linear Fit on context menu, display Fitting Dialog
+
+ :param plot: PlotPanel owning the graph
+
+ """
+ from fitDialog import LinearFit
+ if self._fit_dialog is not None:
+ return
+ self._fit_dialog = LinearFit(None, plot, self.onFitDisplay,
+ self.returnTrans, -1, 'Linear Fit')
+ # Set the zoom area
+ if self._scale_xhi is not None and self._scale_xlo is not None:
+ self._fit_dialog.set_fit_region(self._scale_xlo, self._scale_xhi)
+ # Register the close event
+ self._fit_dialog.register_close(self._linear_fit_close)
+ # Show a non-model dialog
+ self._fit_dialog.Show()
+
+ def _linear_fit_close(self):
+ """
+ A fit dialog was closed
+ """
+ self._fit_dialog = None
+
+ def _onProperties(self, event):
+ """
+ when clicking on Properties on context menu ,
+ The Property dialog is displayed
+ The user selects a transformation for x or y value and
+ a new plot is displayed
+ """
+ if self._fit_dialog is not None:
+ self._fit_dialog.Destroy()
+ self._fit_dialog = None
+ plot_list = self.graph.returnPlottable()
+ if len(plot_list.keys()) > 0:
+ first_item = plot_list.keys()[0]
+ if first_item.x != []:
+ from PropertyDialog import Properties
+ dial = Properties(self, -1, 'Properties')
+ dial.setValues(self.prevXtrans, self.prevYtrans, self.viewModel)
+ if dial.ShowModal() == wx.ID_OK:
+ self.xLabel, self.yLabel, self.viewModel = dial.getValues()
+ self._onEVT_FUNC_PROPERTY()
+ dial.Destroy()
+
+ def set_yscale(self, scale='linear'):
+ """
+ Set the scale on Y-axis
+
+ :param scale: the scale of y-axis
+
+ """
+ self.subplot.set_yscale(scale, nonposy='clip')
+ self.yscale = scale
+
+ def get_yscale(self):
+ """
+
+ :return: Y-axis scale
+
+ """
+ return self.yscale
+
+ def set_xscale(self, scale='linear'):
+ """
+ Set the scale on x-axis
+
+ :param scale: the scale of x-axis
+
+ """
+ self.subplot.set_xscale(scale)
+ self.xscale = scale
+
+ def get_xscale(self):
+ """
+
+ :return: x-axis scale
+
+ """
+ return self.xscale
+
+ def SetColor(self, rgbtuple):
+ """
+ Set figure and canvas colours to be the same
+
+ """
+ if not rgbtuple:
+ rgbtuple = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE).Get()
+ col = [c / 255.0 for c in rgbtuple]
+ self.figure.set_facecolor(col)
+ self.figure.set_edgecolor(self.color)
+ self.canvas.SetBackgroundColour(wx.Colour(*rgbtuple))
+
+ def _onSize(self, event):
+ """
+ """
+ self._resizeflag = True
+
+ def _onIdle(self, evt):
+ """
+ """
+ if self._resizeflag:
+ self._resizeflag = False
+ self._SetSize()
+ self.draw()
+
+ def _SetSize(self, pixels=None):
+ """
+ This method can be called to force the Plot to be a desired size,
+ which defaults to the ClientSize of the panel
+
+ """
+ if not pixels:
+ pixels = tuple(self.GetClientSize())
+ self.canvas.SetSize(pixels)
+ self.figure.set_size_inches(float(pixels[0]) / self.figure.get_dpi(),
+ float(pixels[1]) / self.figure.get_dpi())
+
+ def draw(self):
+ """
+ Where the actual drawing happens
+
+ """
+ self.figure.canvas.draw_idle()
+
+ def legend_picker(self, legend, event):
+ """
+ Pick up the legend patch
+ """
+ return self.legend.legendPatch.contains(event)
+
+ def get_loc_label(self):
+ """
+ Associates label to a specific legend location
+ """
+ _labels = {}
+ i = 0
+ _labels['best'] = i
+ i += 1
+ _labels['upper right'] = i
+ i += 1
+ _labels['upper left'] = i
+ i += 1
+ _labels['lower left'] = i
+ i += 1
+ _labels['lower right'] = i
+ i += 1
+ _labels['right'] = i
+ i += 1
+ _labels['center left'] = i
+ i += 1
+ _labels['center right'] = i
+ i += 1
+ _labels['lower center'] = i
+ i += 1
+ _labels['upper center'] = i
+ i += 1
+ _labels['center'] = i
+ return _labels
+
+ def onSaveImage(self, evt):
+ """
+ Implement save image
+ """
+ self.toolbar.save_figure(evt)
+
+ def onContextMenu(self, event):
+ """
+ Default context menu for a plot panel
+
+ """
+ # Slicer plot popup menu
+ wx_id = wx.NewId()
+ slicerpop = wx.Menu()
+ slicerpop.Append(wx_id, '&Save image', 'Save image as PNG')
+ wx.EVT_MENU(self, wx_id, self.onSaveImage)
+
+ wx_id = wx.NewId()
+ slicerpop.Append(wx_id, '&Printer setup', 'Set image size')
+ wx.EVT_MENU(self, wx_id, self.onPrinterSetup)
+
+ wx_id = wx.NewId()
+ slicerpop.Append(wx_id, '&Print image', 'Print image ')
+ wx.EVT_MENU(self, wx_id, self.onPrint)
+
+ wx_id = wx.NewId()
+ slicerpop.Append(wx_id, '&Copy', 'Copy to the clipboard')
+ wx.EVT_MENU(self, wx_id, self.OnCopyFigureMenu)
+
+ wx_id = wx.NewId()
+ slicerpop.AppendSeparator()
+ slicerpop.Append(wx_id, '&Properties')
+ wx.EVT_MENU(self, wx_id, self._onProperties)
+
+ wx_id = wx.NewId()
+ slicerpop.AppendSeparator()
+ slicerpop.Append(wx_id, '&Linear Fit')
+ wx.EVT_MENU(self, wx_id, self.onFitting)
+
+ wx_id = wx.NewId()
+ slicerpop.AppendSeparator()
+ slicerpop.Append(wx_id, '&Toggle Legend On/Off', 'Toggle Legend On/Off')
+ wx.EVT_MENU(self, wx_id, self.onLegend)
+
+ loc_menu = wx.Menu()
+ for label in self._loc_labels:
+ wx_id = wx.NewId()
+ loc_menu.Append(wx_id, str(label), str(label))
+ wx.EVT_MENU(self, wx_id, self.onChangeLegendLoc)
+ wx_id = wx.NewId()
+ slicerpop.AppendMenu(wx_id, '&Modify Legend Location', loc_menu)
+
+ wx_id = wx.NewId()
+ slicerpop.Append(wx_id, '&Modify Y Axis Label')
+ wx.EVT_MENU(self, wx_id, self._on_yaxis_label)
+ wx_id = wx.NewId()
+ slicerpop.Append(wx_id, '&Modify X Axis Label')
+ wx.EVT_MENU(self, wx_id, self._on_xaxis_label)
+
+ try:
+ # mouse event
+ pos_evt = event.GetPosition()
+ pos = self.ScreenToClient(pos_evt)
+ except:
+ # toolbar event
+ pos_x, pos_y = self.toolbar.GetPositionTuple()
+ pos = (pos_x, pos_y + 5)
+
+ self.PopupMenu(slicerpop, pos)
+
+ def onToolContextMenu(self, event):
+ """
+ ContextMenu from toolbar
+
+ :param event: toolbar event
+ """
+ # reset postion
+ self.position = None
+ if self.graph.selected_plottable is not None:
+ self.graph.selected_plottable = None
+
+ self.onContextMenu(event)
+
+# modified kieranrcampbell ILL june2012
+ def onLegend(self, legOnOff):
+ """
+ Toggles whether legend is visible/not visible
+ """
+ self.legend_on = legOnOff
+ if not self.legend_on:
+ for ax in self.axes:
+ self.remove_legend(ax)
+ else:
+ # sort them by labels
+ handles, labels = self.subplot.get_legend_handles_labels()
+ hl = sorted(zip(handles, labels),
+ key=operator.itemgetter(1))
+ handles2, labels2 = zip(*hl)
+ self.line_collections_list = handles2
+ self.legend = self.subplot.legend(handles2, labels2,
+ prop=FontProperties(size=10),
+ loc=self.legendLoc)
+ if self.legend is not None:
+ self.legend.set_picker(self.legend_picker)
+ self.legend.set_axes(self.subplot)
+ self.legend.set_zorder(20)
+
+ self.subplot.figure.canvas.draw_idle()
+
+ def onChangeLegendLoc(self, event):
+ """
+ Changes legend loc based on user input
+ """
+ menu = event.GetEventObject()
+ label = menu.GetLabel(event.GetId())
+ self.ChangeLegendLoc(label)
+
+ def ChangeLegendLoc(self, label):
+ """
+ Changes legend loc based on user input
+ """
+ self.legendLoc = label
+ self.legend_pos_loc = None
+ # sort them by labels
+ handles, labels = self.subplot.get_legend_handles_labels()
+ hl = sorted(zip(handles, labels),
+ key=operator.itemgetter(1))
+ handles2, labels2 = zip(*hl)
+ self.line_collections_list = handles2
+ self.legend = self.subplot.legend(handles2, labels2,
+ prop=FontProperties(size=10),
+ loc=self.legendLoc)
+ if self.legend is not None:
+ self.legend.set_picker(self.legend_picker)
+ self.legend.set_axes(self.subplot)
+ self.legend.set_zorder(20)
+ self.subplot.figure.canvas.draw_idle()
+
+ def remove_legend(self, ax=None):
+ """
+ Remove legend for ax or the current axes.
+ """
+ from pylab import gca
+ if ax is None:
+ ax = gca()
+ ax.legend_ = None
+
+ def _on_addtext(self, event):
+ """
+ Allows you to add text to the plot
+ """
+ pos_x = 0
+ pos_y = 0
+ if self.position is not None:
+ pos_x, pos_y = self.position
+ else:
+ pos_x, pos_y = 0.01, 1.00
+
+ textdial = TextDialog(None, -1, 'Add Custom Text')
+ if textdial.ShowModal() == wx.ID_OK:
+ try:
+ FONT = FontProperties()
+ label = textdial.getText()
+ xpos = pos_x
+ ypos = pos_y
+ font = FONT.copy()
+ font.set_size(textdial.getSize())
+ font.set_family(textdial.getFamily())
+ font.set_style(textdial.getStyle())
+ font.set_weight(textdial.getWeight())
+ colour = textdial.getColor()
+ if len(label) > 0 and xpos > 0 and ypos > 0:
+ new_text = self.subplot.text(str(xpos), str(ypos), label,
+ fontproperties=font,
+ color=colour)
+ self.textList.append(new_text)
+ self.subplot.figure.canvas.draw_idle()
+ except:
+ if self.parent is not None:
+ msg = "Add Text: Error. Check your property values..."
+ wx.PostEvent(self.parent, StatusEvent(status=msg))
+ else:
+ raise
+ textdial.Destroy()
+ #Have a pop up box come up for user to type in the
+ #text that they want to add...then create text Plottable
+ #based on this and plot it at user designated coordinates
+
+ def onGridOnOff(self, gridon_off):
+ """
+ Allows ON/OFF Grid
+ """
+ self.grid_on = gridon_off
+
+ self.subplot.figure.canvas.draw_idle()
+
+ def _on_xaxis_label(self, event):
+ """
+ Allows you to add text to the plot
+ """
+ xaxis_label, xaxis_unit, xaxis_font, xaxis_color, \
+ is_ok, is_tick = self._on_axis_label(axis='x')
+ if not is_ok:
+ return
+
+ self.xaxis_label = xaxis_label
+ self.xaxis_unit = xaxis_unit
+ self.xaxis_font = xaxis_font
+ self.xaxis_color = xaxis_color
+ if is_tick:
+ self.xaxis_tick = xaxis_font
+
+ if self.data is not None:
+ # 2D
+ self.xaxis(self.xaxis_label, self.xaxis_unit, \
+ self.xaxis_font, self.xaxis_color, self.xaxis_tick)
+ self.subplot.figure.canvas.draw_idle()
+ else:
+ # 1D
+ self._check_zoom_plot()
+
+ def _check_zoom_plot(self):
+ """
+ Check the zoom range and plot (1D only)
+ """
+ xlo, xhi = self.subplot.get_xlim()
+ ylo, yhi = self.subplot.get_ylim()
+ ## Set the view scale for all plots
+ self._onEVT_FUNC_PROPERTY(False)
+ if self.is_zoomed:
+ # Recover the x,y limits
+ self.subplot.set_xlim((xlo, xhi))
+ self.subplot.set_ylim((ylo, yhi))
+
+ @property
+ def is_zoomed(self):
+ toolbar_zoomed = self.toolbar.GetToolEnabled(self.toolbar.wx_ids['Back'])
+ return self._is_zoomed or toolbar_zoomed
+
+ @is_zoomed.setter
+ def is_zoomed(self, value):
+ self._is_zoomed = value
+
+ def _on_yaxis_label(self, event):
+ """
+ Allows you to add text to the plot
+ """
+ yaxis_label, yaxis_unit, yaxis_font, yaxis_color, \
+ is_ok, is_tick = self._on_axis_label(axis='y')
+ if not is_ok:
+ return
+
+ self.yaxis_label = yaxis_label
+ self.yaxis_unit = yaxis_unit
+ self.yaxis_font = yaxis_font
+ self.yaxis_color = yaxis_color
+ if is_tick:
+ self.yaxis_tick = yaxis_font
+
+ if self.data is not None:
+ # 2D
+ self.yaxis(self.yaxis_label, self.yaxis_unit, \
+ self.yaxis_font, self.yaxis_color, self.yaxis_tick)
+ self.subplot.figure.canvas.draw_idle()
+ else:
+ # 1D
+ self._check_zoom_plot()
+
+ def _on_axis_label(self, axis='x'):
+ """
+ Modify axes labels
+
+ :param axis: x or y axis [string]
+ """
+ is_ok = True
+ title = 'Modify %s axis label' % axis
+ font = 'serif'
+ colour = 'black'
+ if axis == 'x':
+ label = self.xaxis_label
+ unit = self.xaxis_unit
+ else:
+ label = self.yaxis_label
+ unit = self.yaxis_unit
+ textdial = TextDialog(None, -1, title, label, unit)
+ if textdial.ShowModal() == wx.ID_OK:
+ try:
+ FONT = FontProperties()
+ font = FONT.copy()
+ font.set_size(textdial.getSize())
+ font.set_family(textdial.getFamily())
+ font.set_style(textdial.getStyle())
+ font.set_weight(textdial.getWeight())
+ unit = textdial.getUnit()
+ colour = textdial.getColor()
+ is_tick = textdial.getTickLabel()
+ label_temp = textdial.getText()
+ if label_temp.count("\%s" % "\\") > 0:
+ if self.parent is not None:
+ msg = "Add Label: Error. Can not use double '\\' "
+ msg += "characters..."
+ wx.PostEvent(self.parent, StatusEvent(status=msg))
+ else:
+ label = label_temp
+ except:
+ if self.parent is not None:
+ msg = "Add Label: Error. Check your property values..."
+ wx.PostEvent(self.parent, StatusEvent(status=msg))
+ else:
+ pass
+ else:
+ is_ok = False
+ is_tick = True
+ textdial.Destroy()
+ return label, unit, font, colour, is_ok, is_tick
+
+ def _on_removetext(self, event):
+ """
+ Removes all text from the plot.
+ Eventually, add option to remove specific text boxes
+ """
+ num_text = len(self.textList)
+ if num_text < 1:
+ if self.parent is not None:
+ msg = "Remove Text: Nothing to remove. "
+ wx.PostEvent(self.parent, StatusEvent(status=msg))
+ else:
+ raise
+ return
+ txt = self.textList[num_text - 1]
+ try:
+ text_remove = txt.get_text()
+ txt.remove()
+ if self.parent is not None:
+ msg = "Removed Text: '%s'. " % text_remove
+ wx.PostEvent(self.parent, StatusEvent(status=msg))
+ except:
+ if self.parent is not None:
+ msg = "Remove Text: Error occurred. "
+ wx.PostEvent(self.parent, StatusEvent(status=msg))
+ else:
+ raise
+ self.textList.remove(txt)
+
+ self.subplot.figure.canvas.draw_idle()
+
+ def properties(self, prop):
+ """
+ Set some properties of the graph.
+ The set of properties is not yet determined.
+
+ """
+ # The particulars of how they are stored and manipulated (e.g., do
+ # we want an inventory internally) is not settled. I've used a
+ # property dictionary for now.
+ #
+ # How these properties interact with a user defined style file is
+ # even less clear.
+
+ # Properties defined by plot
+
+ # Ricardo:
+ # A empty label "$$" will prevent the panel from displaying!
+ if prop["xlabel"]:
+ self.subplot.set_xlabel(r"$%s$"%prop["xlabel"])
+ if prop["ylabel"]:
+ self.subplot.set_ylabel(r"$%s$"%prop["ylabel"])
+ self.subplot.set_title(prop["title"])
+
+
+ def clear(self):
+ """Reset the plot"""
+ # TODO: Redraw is brutal. Render to a backing store and swap in
+ # TODO: rather than redrawing on the fly.
+ self.subplot.clear()
+ self.subplot.hold(True)
+
+ def render(self):
+ """Commit the plot after all objects are drawn"""
+ # TODO: this is when the backing store should be swapped in.
+ if self.legend_on:
+ ax = self.subplot
+ ax.texts = self.textList
+ try:
+ handles, labels = ax.get_legend_handles_labels()
+ # sort them by labels
+ hl = sorted(zip(handles, labels),
+ key=operator.itemgetter(1))
+ handles2, labels2 = zip(*hl)
+ self.line_collections_list = handles2
+ self.legend = ax.legend(handles2, labels2,
+ prop=FontProperties(size=10),
+ loc=self.legendLoc)
+ if self.legend is not None:
+ self.legend.set_picker(self.legend_picker)
+ self.legend.set_axes(self.subplot)
+ self.legend.set_zorder(20)
+
+ except:
+ self.legend = ax.legend(prop=FontProperties(size=10),
+ loc=self.legendLoc)
+
+ def xaxis(self, label, units, font=None, color='black', t_font=None):
+ """xaxis label and units.
+
+ Axis labels know about units.
+
+ We need to do this so that we can detect when axes are not
+ commesurate. Currently this is ignored other than for formatting
+ purposes.
+
+ """
+
+ self.xcolor = color
+ if units.count("{") > 0 and units.count("$") < 2:
+ units = '$' + units + '$'
+ if label.count("{") > 0 and label.count("$") < 2:
+ label = '$' + label + '$'
+ if units != "":
+ label = label + " (" + units + ")"
+ if font:
+ self.subplot.set_xlabel(label, fontproperties=font, color=color)
+ if t_font is not None:
+ for tick in self.subplot.xaxis.get_major_ticks():
+ tick.label.set_fontproperties(t_font)
+ for line in self.subplot.xaxis.get_ticklines():
+ size = t_font.get_size()
+ line.set_markersize(size / 3)
+ else:
+ self.subplot.set_xlabel(label, color=color)
+ pass
+
+ def yaxis(self, label, units, font=None, color='black', t_font=None):
+ """yaxis label and units."""
+ self.ycolor = color
+ if units.count("{") > 0 and units.count("$") < 2:
+ units = '$' + units + '$'
+ if label.count("{") > 0 and label.count("$") < 2:
+ label = '$' + label + '$'
+ if units != "":
+ label = label + " (" + units + ")"
+ if font:
+ self.subplot.set_ylabel(label, fontproperties=font, color=color)
+ if t_font is not None:
+ for tick_label in self.subplot.get_yticklabels():
+ tick_label.set_fontproperties(t_font)
+ for line in self.subplot.yaxis.get_ticklines():
+ size = t_font.get_size()
+ line.set_markersize(size / 3)
+ else:
+ self.subplot.set_ylabel(label, color=color)
+ pass
+
+ def _connect_to_xlim(self, callback):
+ """Bind the xlim change notification to the callback"""
+ def process_xlim(axes):
+ lo, hi = subplot.get_xlim()
+ callback(lo, hi)
+ self.subplot.callbacks.connect('xlim_changed', process_xlim)
+
+ def interactive_points(self, x, y, dx=None, dy=None, name='', color=0,
+ symbol=0, markersize=5, zorder=1, id=None,
+ label=None, hide_error=False):
+ """Draw markers with error bars"""
+ self.subplot.set_yscale('linear')
+ self.subplot.set_xscale('linear')
+ if id is None:
+ id = name
+ from plottable_interactor import PointInteractor
+ p = PointInteractor(self, self.subplot, zorder=zorder, id=id)
+ if p.markersize is not None:
+ markersize = p.markersize
+ p.points(x, y, dx=dx, dy=dy, color=color, symbol=symbol, zorder=zorder,
+ markersize=markersize, label=label, hide_error=hide_error)
+
+ self.subplot.set_yscale(self.yscale, nonposy='clip')
+ self.subplot.set_xscale(self.xscale)
+
+ def interactive_curve(self, x, y, dy=None, name='', color=0,
+ symbol=0, zorder=1, id=None, label=None):
+ """Draw markers with error bars"""
+ self.subplot.set_yscale('linear')
+ self.subplot.set_xscale('linear')
+ if id is None:
+ id = name
+ from plottable_interactor import PointInteractor
+ p = PointInteractor(self, self.subplot, zorder=zorder, id=id)
+ p.curve(x, y, dy=dy, color=color, symbol=symbol, zorder=zorder,
+ label=label)
+
+ self.subplot.set_yscale(self.yscale, nonposy='clip')
+ self.subplot.set_xscale(self.xscale)
+
+ def plottable_selected(self, id):
+ """
+ Called to register a plottable as selected
+ """
+ #TODO: check that it really is in the list of plottables
+ self.graph.selected_plottable = id
+
+ def points(self, x, y, dx=None, dy=None,
+ color=0, symbol=0, marker_size=5, label=None,
+ id=None, hide_error=False):
+ """Draw markers with error bars"""
+
+ # Convert tuple (lo,hi) to array [(x-lo),(hi-x)]
+ if dx is not None and type(dx) == type(()):
+ dx = nx.vstack((x - dx[0], dx[1] - x)).transpose()
+ if dy is not None and type(dy) == type(()):
+ dy = nx.vstack((y - dy[0], dy[1] - y)).transpose()
+ if dx is None and dy is None:
+ self.subplot.plot(x, y, color=self._color(color),
+ marker=self._symbol(symbol),
+ markersize=marker_size,
+ linestyle='',
+ label=label)
+ else:
+ col = self._color(color)
+ if hide_error:
+ self.subplot.plot(x, y, color=col,
+ marker=self._symbol(symbol),
+ markersize=marker_size,
+ linestyle='',
+ label=label)
+ else:
+ self.subplot.errorbar(x, y, yerr=dy, xerr=None,
+ ecolor=col, capsize=2, linestyle='',
+ barsabove=False,
+ mec=col, mfc=col,
+ marker=self._symbol(symbol),
+ markersize=marker_size,
+ lolims=False, uplims=False,
+ xlolims=False, xuplims=False, label=label)
+
+ self.subplot.set_yscale(self.yscale, nonposy='clip')
+ self.subplot.set_xscale(self.xscale)
+
+ def _onToggleScale(self, event):
+ """
+ toggle axis and replot image
+
+ """
+ zmin_2D_temp = self.zmin_2D
+ zmax_2D_temp = self.zmax_2D
+ if self.scale == 'log_{10}':
+ self.scale = 'linear'
+ if self.zmin_2D is not None:
+ zmin_2D_temp = math.pow(10, self.zmin_2D)
+ if self.zmax_2D is not None:
+ zmax_2D_temp = math.pow(10, self.zmax_2D)
+ else:
+ self.scale = 'log_{10}'
+ if self.zmin_2D is not None:
+ # min log value: no log(negative)
+ if self.zmin_2D <= 0:
+ zmin_2D_temp = -32
+ else:
+ zmin_2D_temp = math.log10(self.zmin_2D)
+ if self.zmax_2D is not None:
+ zmax_2D_temp = math.log10(self.zmax_2D)
+
+ self.image(data=self.data, qx_data=self.qx_data,
+ qy_data=self.qy_data, xmin=self.xmin_2D,
+ xmax=self.xmax_2D,
+ ymin=self.ymin_2D, ymax=self.ymax_2D,
+ cmap=self.cmap, zmin=zmin_2D_temp,
+ zmax=zmax_2D_temp)
+
+ def image(self, data, qx_data, qy_data, xmin, xmax, ymin, ymax,
+ zmin, zmax, color=0, symbol=0, markersize=0,
+ label='data2D', cmap=DEFAULT_CMAP):
+ """
+ Render the current data
+
+ """
+ self.data = data
+ self.qx_data = qx_data
+ self.qy_data = qy_data
+ self.xmin_2D = xmin
+ self.xmax_2D = xmax
+ self.ymin_2D = ymin
+ self.ymax_2D = ymax
+ self.zmin_2D = zmin
+ self.zmax_2D = zmax
+ c = self._color(color)
+ # If we don't have any data, skip.
+ if self.data is None:
+ return
+ if self.data.ndim == 1:
+ output = self._build_matrix()
+ else:
+ output = copy.deepcopy(self.data)
+ # check scale
+ if self.scale == 'log_{10}':
+ try:
+ if self.zmin_2D <= 0 and len(output[output > 0]) > 0:
+ zmin_temp = self.zmin_2D
+ output[output > 0] = np.log10(output[output > 0])
+ #In log scale Negative values are not correct in general
+ #output[output<=0] = math.log(np.min(output[output>0]))
+ elif self.zmin_2D <= 0:
+ zmin_temp = self.zmin_2D
+ output[output > 0] = np.zeros(len(output))
+ output[output <= 0] = -32
+ else:
+ zmin_temp = self.zmin_2D
+ output[output > 0] = np.log10(output[output > 0])
+ #In log scale Negative values are not correct in general
+ #output[output<=0] = math.log(np.min(output[output>0]))
+ except:
+ #Too many problems in 2D plot with scale
+ pass
+
+ else:
+ zmin_temp = self.zmin_2D
+ self.cmap = cmap
+ if self.dimension != 3:
+ #Re-adjust colorbar
+ self.subplot.figure.subplots_adjust(left=0.2, right=.8, bottom=.2)
+
+ im = self.subplot.imshow(output, interpolation='nearest',
+ origin='lower',
+ vmin=zmin_temp, vmax=self.zmax_2D,
+ cmap=self.cmap,
+ extent=(self.xmin_2D, self.xmax_2D,
+ self.ymin_2D, self.ymax_2D))
+
+ cbax = self.subplot.figure.add_axes([0.84, 0.2, 0.02, 0.7])
+ else:
+ # clear the previous 2D from memory
+ # mpl is not clf, so we do
+ self.subplot.figure.clear()
+
+ self.subplot.figure.subplots_adjust(left=0.1, right=.8, bottom=.1)
+
+ X = self.x_bins[0:-1]
+ Y = self.y_bins[0:-1]
+ X, Y = np.meshgrid(X, Y)
+
+ try:
+ # mpl >= 1.0.0
+ ax = self.subplot.figure.gca(projection='3d')
+ #ax.disable_mouse_rotation()
+ cbax = self.subplot.figure.add_axes([0.84, 0.1, 0.02, 0.8])
+ if len(X) > 60:
+ ax.disable_mouse_rotation()
+ except:
+ # mpl < 1.0.0
+ try:
+ from mpl_toolkits.mplot3d import Axes3D
+ except:
+ logger.error("PlotPanel could not import Axes3D")
+ self.subplot.figure.clear()
+ ax = Axes3D(self.subplot.figure)
+ if len(X) > 60:
+ ax.cla()
+ cbax = None
+ self.subplot.figure.canvas.resizing = False
+ im = ax.plot_surface(X, Y, output, rstride=1, cstride=1, cmap=cmap,
+ linewidth=0, antialiased=False)
+ self.subplot.set_axis_off()
+
+ if cbax is None:
+ ax.set_frame_on(False)
+ cb = self.subplot.figure.colorbar(im, shrink=0.8, aspect=20)
+ else:
+ cb = self.subplot.figure.colorbar(im, cax=cbax)
+ cb.update_bruteforce(im)
+ cb.set_label('$' + self.scale + '$')
+ if self.dimension != 3:
+ self.figure.canvas.draw_idle()
+ else:
+ self.figure.canvas.draw()
+
+ def _build_matrix(self):
+ """
+ Build a matrix for 2d plot from a vector
+ Returns a matrix (image) with ~ square binning
+ Requirement: need 1d array formats of
+ self.data, self.qx_data, and self.qy_data
+ where each one corresponds to z, x, or y axis values
+
+ """
+ # No qx or qy given in a vector format
+ if self.qx_data is None or self.qy_data is None \
+ or self.qx_data.ndim != 1 or self.qy_data.ndim != 1:
+ # do we need deepcopy here?
+ return copy.deepcopy(self.data)
+
+ # maximum # of loops to fillup_pixels
+ # otherwise, loop could never stop depending on data
+ max_loop = 1
+ # get the x and y_bin arrays.
+ self._get_bins()
+ # set zero to None
+
+ #Note: Can not use scipy.interpolate.Rbf:
+ # 'cause too many data points (>10000)<=JHC.
+ # 1d array to use for weighting the data point averaging
+ #when they fall into a same bin.
+ weights_data = np.ones([self.data.size])
+ # get histogram of ones w/len(data); this will provide
+ #the weights of data on each bins
+ weights, xedges, yedges = np.histogram2d(x=self.qy_data,
+ y=self.qx_data,
+ bins=[self.y_bins, self.x_bins],
+ weights=weights_data)
+ # get histogram of data, all points into a bin in a way of summing
+ image, xedges, yedges = np.histogram2d(x=self.qy_data,
+ y=self.qx_data,
+ bins=[self.y_bins, self.x_bins],
+ weights=self.data)
+ # Now, normalize the image by weights only for weights>1:
+ # If weight == 1, there is only one data point in the bin so
+ # that no normalization is required.
+ image[weights > 1] = image[weights > 1] / weights[weights > 1]
+ # Set image bins w/o a data point (weight==0) as None (was set to zero
+ # by histogram2d.)
+ image[weights == 0] = None
+
+ # Fill empty bins with 8 nearest neighbors only when at least
+ #one None point exists
+ loop = 0
+
+ # do while loop until all vacant bins are filled up up
+ #to loop = max_loop
+ while not(np.isfinite(image[weights == 0])).all():
+ if loop >= max_loop: # this protects never-ending loop
+ break
+ image = self._fillup_pixels(image=image, weights=weights)
+ loop += 1
+
+ return image
+
+ def _get_bins(self):
+ """
+ get bins
+ set x_bins and y_bins into self, 1d arrays of the index with
+ ~ square binning
+ Requirement: need 1d array formats of
+ self.qx_data, and self.qy_data
+ where each one corresponds to x, or y axis values
+ """
+ # No qx or qy given in a vector format
+ if self.qx_data is None or self.qy_data is None \
+ or self.qx_data.ndim != 1 or self.qy_data.ndim != 1:
+ # do we need deepcopy here?
+ return copy.deepcopy(self.data)
+
+ # find max and min values of qx and qy
+ xmax = self.qx_data.max()
+ xmin = self.qx_data.min()
+ ymax = self.qy_data.max()
+ ymin = self.qy_data.min()
+
+ # calculate the range of qx and qy: this way, it is a little
+ # more independent
+ x_size = xmax - xmin
+ y_size = ymax - ymin
+
+ # estimate the # of pixels on each axes
+ npix_y = int(math.floor(math.sqrt(len(self.qy_data))))
+ npix_x = int(math.floor(len(self.qy_data) / npix_y))
+
+ # bin size: x- & y-directions
+ xstep = x_size / (npix_x - 1)
+ ystep = y_size / (npix_y - 1)
+
+ # max and min taking account of the bin sizes
+ xmax = xmax + xstep / 2.0
+ xmin = xmin - xstep / 2.0
+ ymax = ymax + ystep / 2.0
+ ymin = ymin - ystep / 2.0
+
+ # store x and y bin centers in q space
+ x_bins = np.linspace(xmin, xmax, npix_x)
+ y_bins = np.linspace(ymin, ymax, npix_y)
+
+ #set x_bins and y_bins
+ self.x_bins = x_bins
+ self.y_bins = y_bins
+
+ def _fillup_pixels(self, image=None, weights=None):
+ """
+ Fill z values of the empty cells of 2d image matrix
+ with the average over up-to next nearest neighbor points
+
+ :param image: (2d matrix with some zi = None)
+
+ :return: image (2d array )
+
+ :TODO: Find better way to do for-loop below
+
+ """
+ # No image matrix given
+ if image is None or np.ndim(image) != 2 \
+ or np.isfinite(image).all() \
+ or weights is None:
+ return image
+ # Get bin size in y and x directions
+ len_y = len(image)
+ len_x = len(image[1])
+ temp_image = np.zeros([len_y, len_x])
+ weit = np.zeros([len_y, len_x])
+ # do for-loop for all pixels
+ for n_y in range(len(image)):
+ for n_x in range(len(image[1])):
+ # find only null pixels
+ if weights[n_y][n_x] > 0 or np.isfinite(image[n_y][n_x]):
+ continue
+ else:
+ # find 4 nearest neighbors
+ # check where or not it is at the corner
+ if n_y != 0 and np.isfinite(image[n_y - 1][n_x]):
+ temp_image[n_y][n_x] += image[n_y - 1][n_x]
+ weit[n_y][n_x] += 1
+ if n_x != 0 and np.isfinite(image[n_y][n_x - 1]):
+ temp_image[n_y][n_x] += image[n_y][n_x - 1]
+ weit[n_y][n_x] += 1
+ if n_y != len_y - 1 and np.isfinite(image[n_y + 1][n_x]):
+ temp_image[n_y][n_x] += image[n_y + 1][n_x]
+ weit[n_y][n_x] += 1
+ if n_x != len_x - 1 and np.isfinite(image[n_y][n_x + 1]):
+ temp_image[n_y][n_x] += image[n_y][n_x + 1]
+ weit[n_y][n_x] += 1
+ # go 4 next nearest neighbors when no non-zero
+ # neighbor exists
+ if n_y != 0 and n_x != 0 and \
+ np.isfinite(image[n_y - 1][n_x - 1]):
+ temp_image[n_y][n_x] += image[n_y - 1][n_x - 1]
+ weit[n_y][n_x] += 1
+ if n_y != len_y - 1 and n_x != 0 and \
+ np.isfinite(image[n_y + 1][n_x - 1]):
+ temp_image[n_y][n_x] += image[n_y + 1][n_x - 1]
+ weit[n_y][n_x] += 1
+ if n_y != len_y and n_x != len_x - 1 and \
+ np.isfinite(image[n_y - 1][n_x + 1]):
+ temp_image[n_y][n_x] += image[n_y - 1][n_x + 1]
+ weit[n_y][n_x] += 1
+ if n_y != len_y - 1 and n_x != len_x - 1 and \
+ np.isfinite(image[n_y + 1][n_x + 1]):
+ temp_image[n_y][n_x] += image[n_y + 1][n_x + 1]
+ weit[n_y][n_x] += 1
+
+ # get it normalized
+ ind = (weit > 0)
+ image[ind] = temp_image[ind] / weit[ind]
+
+ return image
+
+ def curve(self, x, y, dy=None, color=0, symbol=0, label=None):
+ """Draw a line on a graph, possibly with confidence intervals."""
+ c = self._color(color)
+ self.subplot.set_yscale('linear')
+ self.subplot.set_xscale('linear')
+
+ self.subplot.plot(x, y, color=c, marker='',
+ linestyle='-', label=label)
+ self.subplot.set_yscale(self.yscale)
+ self.subplot.set_xscale(self.xscale)
+
+ def _color(self, c):
+ """Return a particular colour"""
+ return self.colorlist[c % len(self.colorlist)]
+
+ def _symbol(self, s):
+ """Return a particular symbol"""
+ return self.symbollist[s % len(self.symbollist)]
+
+ def _replot(self, remove_fit=False):
+ """
+ Rescale the plottables according to the latest
+ user selection and update the plot
+
+ :param remove_fit: Fit line will be removed if True
+
+ """
+ self.graph.reset_scale()
+ self._onEVT_FUNC_PROPERTY(remove_fit=remove_fit)
+ #TODO: Why do we have to have the following line?
+ self.fit_result.reset_view()
+ self.graph.render(self)
+ self.subplot.figure.canvas.draw_idle()
+
+ def _onEVT_FUNC_PROPERTY(self, remove_fit=True, show=True):
+ """
+ Receive the x and y transformation from myDialog,
+ Transforms x and y in View
+ and set the scale
+ """
+ # The logic should be in the right order
+ # Delete first, and then get the whole list...
+ if remove_fit:
+ self.graph.delete(self.fit_result)
+ if hasattr(self, 'plots'):
+ if 'fit' in self.plots.keys():
+ del self.plots['fit']
+ self.ly = None
+ self.q_ctrl = None
+ list = self.graph.returnPlottable()
+ # Changing the scale might be incompatible with
+ # currently displayed data (for instance, going
+ # from ln to log when all plotted values have
+ # negative natural logs).
+ # Go linear and only change the scale at the end.
+ self.set_xscale("linear")
+ self.set_yscale("linear")
+ _xscale = 'linear'
+ _yscale = 'linear'
+ for item in list:
+ if item.id == 'fit':
+ continue
+ item.setLabel(self.xLabel, self.yLabel)
+ # control axis labels from the panel itself
+ yname, yunits = item.get_yaxis()
+ if self.yaxis_label is not None:
+ yname = self.yaxis_label
+ yunits = self.yaxis_unit
+ else:
+ self.yaxis_label = yname
+ self.yaxis_unit = yunits
+ xname, xunits = item.get_xaxis()
+ if self.xaxis_label is not None:
+ xname = self.xaxis_label
+ xunits = self.xaxis_unit
+ else:
+ self.xaxis_label = xname
+ self.xaxis_unit = xunits
+ # Goes through all possible scales
+ if self.xLabel == "x":
+ item.transformX(transform.toX, transform.errToX)
+ self.graph._xaxis_transformed("%s" % xname, "%s" % xunits)
+ if self.xLabel == "x^(2)":
+ item.transformX(transform.toX2, transform.errToX2)
+ xunits = convert_unit(2, xunits)
+ self.graph._xaxis_transformed("%s^{2}" % xname, "%s" % xunits)
+ if self.xLabel == "x^(4)":
+ item.transformX(transform.toX4, transform.errToX4)
+ xunits = convert_unit(4, xunits)
+ self.graph._xaxis_transformed("%s^{4}" % xname, "%s" % xunits)
+ if self.xLabel == "ln(x)":
+ item.transformX(transform.toLogX, transform.errToLogX)
+ self.graph._xaxis_transformed("\ln{(%s)}" % xname, "%s" % xunits)
+ if self.xLabel == "log10(x)":
+ item.transformX(transform.toX_pos, transform.errToX_pos)
+ _xscale = 'log'
+ self.graph._xaxis_transformed("%s" % xname, "%s" % xunits)
+ if self.xLabel == "log10(x^(4))":
+ item.transformX(transform.toX4, transform.errToX4)
+ xunits = convert_unit(4, xunits)
+ self.graph._xaxis_transformed("%s^{4}" % xname, "%s" % xunits)
+ _xscale = 'log'
+ if self.yLabel == "ln(y)":
+ item.transformY(transform.toLogX, transform.errToLogX)
+ self.graph._yaxis_transformed("\ln{(%s)}" % yname, "%s" % yunits)
+ if self.yLabel == "y":
+ item.transformY(transform.toX, transform.errToX)
+ self.graph._yaxis_transformed("%s" % yname, "%s" % yunits)
+ if self.yLabel == "log10(y)":
+ item.transformY(transform.toX_pos, transform.errToX_pos)
+ _yscale = 'log'
+ self.graph._yaxis_transformed("%s" % yname, "%s" % yunits)
+ if self.yLabel == "y^(2)":
+ item.transformY(transform.toX2, transform.errToX2)
+ yunits = convert_unit(2, yunits)
+ self.graph._yaxis_transformed("%s^{2}" % yname, "%s" % yunits)
+ if self.yLabel == "1/y":
+ item.transformY(transform.toOneOverX, transform.errOneOverX)
+ yunits = convert_unit(-1, yunits)
+ self.graph._yaxis_transformed("1/%s" % yname, "%s" % yunits)
+ if self.yLabel == "y*x^(2)":
+ item.transformY(transform.toYX2, transform.errToYX2)
+ xunits = convert_unit(2, self.xaxis_unit)
+ self.graph._yaxis_transformed("%s \ \ %s^{2}" % (yname, xname),
+ "%s%s" % (yunits, xunits))
+ if self.yLabel == "y*x^(4)":
+ item.transformY(transform.toYX4, transform.errToYX4)
+ xunits = convert_unit(4, self.xaxis_unit)
+ self.graph._yaxis_transformed("%s \ \ %s^{4}" % (yname, xname),
+ "%s%s" % (yunits, xunits))
+ if self.yLabel == "1/sqrt(y)":
+ item.transformY(transform.toOneOverSqrtX,
+ transform.errOneOverSqrtX)
+ yunits = convert_unit(-0.5, yunits)
+ self.graph._yaxis_transformed("1/\sqrt{%s}" % yname,
+ "%s" % yunits)
+ if self.yLabel == "ln(y*x)":
+ item.transformY(transform.toLogXY, transform.errToLogXY)
+ self.graph._yaxis_transformed("\ln{(%s \ \ %s)}" % (yname, xname),
+ "%s%s" % (yunits, self.xaxis_unit))
+ if self.yLabel == "ln(y*x^(2))":
+ item.transformY(transform.toLogYX2, transform.errToLogYX2)
+ xunits = convert_unit(2, self.xaxis_unit)
+ self.graph._yaxis_transformed("\ln (%s \ \ %s^{2})" % (yname, xname),
+ "%s%s" % (yunits, xunits))
+ if self.yLabel == "ln(y*x^(4))":
+ item.transformY(transform.toLogYX4, transform.errToLogYX4)
+ xunits = convert_unit(4, self.xaxis_unit)
+ self.graph._yaxis_transformed("\ln (%s \ \ %s^{4})" % (yname, xname),
+ "%s%s" % (yunits, xunits))
+ if self.yLabel == "log10(y*x^(4))":
+ item.transformY(transform.toYX4, transform.errToYX4)
+ xunits = convert_unit(4, self.xaxis_unit)
+ _yscale = 'log'
+ self.graph._yaxis_transformed("%s \ \ %s^{4}" % (yname, xname),
+ "%s%s" % (yunits, xunits))
+ item.transformView()
+
+ # set new label and units
+ yname = self.graph.prop["ylabel"]
+ yunits = ''
+ xname = self.graph.prop["xlabel"]
+ xunits = ''
+
+ self.resetFitView()
+ self.prevXtrans = self.xLabel
+ self.prevYtrans = self.yLabel
+ self.graph.render(self)
+ self.set_xscale(_xscale)
+ self.set_yscale(_yscale)
+
+ self.xaxis(xname, xunits, self.xaxis_font,
+ self.xaxis_color, self.xaxis_tick)
+ self.yaxis(yname, yunits, self.yaxis_font,
+ self.yaxis_color, self.yaxis_tick)
+ self.subplot.texts = self.textList
+ if show:
+ self.subplot.figure.canvas.draw_idle()
+
+ def onFitDisplay(self, tempx, tempy, xminView,
+ xmaxView, xmin, xmax, func):
+ """
+ Add a new plottable into the graph .In this case this plottable
+ will be used to fit some data
+
+ :param tempx: The x data of fit line
+ :param tempy: The y data of fit line
+ :param xminView: the lower bound of fitting range
+ :param xminView: the upper bound of fitting range
+ :param xmin: the lowest value of data to fit to the line
+ :param xmax: the highest value of data to fit to the line
+
+ """
+ xlim = self.subplot.get_xlim()
+ ylim = self.subplot.get_ylim()
+
+ # Saving value to redisplay in Fit Dialog when it is opened again
+ self.Avalue, self.Bvalue, self.ErrAvalue, \
+ self.ErrBvalue, self.Chivalue = func
+ self.xminView = xminView
+ self.xmaxView = xmaxView
+ self.xmin = xmin
+ self.xmax = xmax
+ #In case need to change the range of data plotted
+ for item in self.graph.returnPlottable():
+ item.onFitRange(None, None)
+ # Create new data plottable with result
+ self.fit_result.x = []
+ self.fit_result.y = []
+ self.fit_result.x = tempx
+ self.fit_result.y = tempy
+ self.fit_result.dx = None
+ self.fit_result.dy = None
+ #Load the view with the new values
+ self.fit_result.reset_view()
+ # Add the new plottable to the graph
+ self.graph.add(self.fit_result)
+ self.graph.render(self)
+ self._offset_graph()
+ if hasattr(self, 'plots'):
+ # Used by Plotter1D
+ fit_id = 'fit'
+ self.fit_result.id = fit_id
+ self.fit_result.title = 'Fit'
+ self.fit_result.name = 'Fit'
+ self.plots[fit_id] = self.fit_result
+ self.subplot.set_xlim(xlim)
+ self.subplot.set_ylim(ylim)
+ self.subplot.figure.canvas.draw_idle()
+
+ def onChangeCaption(self, event):
+ """
+ """
+ if self.parent is None:
+ return
+ # get current caption
+ old_caption = self.window_caption
+ # Get new caption dialog
+ dial = LabelDialog(None, -1, 'Modify Window Title', old_caption)
+ if dial.ShowModal() == wx.ID_OK:
+ new_caption = dial.getText()
+
+ # send to guiframe to change the panel caption
+ caption = self.parent.on_change_caption(self.window_name,
+ old_caption, new_caption)
+
+ # also set new caption in plot_panels list
+ self.parent.plot_panels[self.uid].window_caption = caption
+ # set new caption
+ self.window_caption = caption
+
+ dial.Destroy()
+
+ def onResetGraph(self, event):
+ """
+ Reset the graph by plotting the full range of data
+ """
+ for item in self.graph.returnPlottable():
+ item.onReset()
+ self.graph.render(self)
+ self._onEVT_FUNC_PROPERTY(False)
+ self.is_zoomed = False
+ self.toolbar.update()
+
+ def onPrint(self, event=None):
+ self.toolbar.print_figure(event)
+
+ def onPrinterSetup(self, event=None):
+ """
+ """
+ self.canvas.Printer_Setup(event=event)
+ self.Update()
+
+ def onPrinterPreview(self, event=None):
+ """
+ Matplotlib camvas can no longer print itself. Thus need to do
+ everything ourselves: need to create a printpreview frame to to
+ see the preview but needs a parent frame object. Also needs a
+ printout object (just as any printing task).
+ """
+ try:
+ #check if parent is a frame. If not keep getting the higher
+ #parent till we find a frame
+ _plot = self
+ while not isinstance(_plot, wx.Frame):
+ _plot = _plot.GetParent()
+ assert _plot is not None
+
+ #now create the printpeview object
+ _preview = wx.PrintPreview(PlotPrintout(self.canvas),
+ PlotPrintout(self.canvas))
+ #and tie it to a printpreview frame then show it
+ _frame = wx.PreviewFrame(_preview, _plot, "Print Preview", wx.Point(100, 100), wx.Size(600, 650))
+ _frame.Centre(wx.BOTH)
+ _frame.Initialize()
+ _frame.Show(True)
+ except:
+ traceback.print_exc()
+ pass
+
+ def OnCopyFigureMenu(self, evt):
+ """
+ Copy the current figure to clipboard
+ """
+ try:
+ self.toolbar.copy_figure(self.canvas)
+ except:
+ print("Error in copy Image")
+
+
+#---------------------------------------------------------------
+class NoRepaintCanvas(FigureCanvasWxAgg):
+ """
+ We subclass FigureCanvasWxAgg, overriding the _onPaint method, so that
+ the draw method is only called for the first two paint events. After that,
+ the canvas will only be redrawn when it is resized.
+
+ """
+ def __init__(self, *args, **kwargs):
+ """
+ """
+ FigureCanvasWxAgg.__init__(self, *args, **kwargs)
+ self._drawn = 0
+
+ def _onPaint(self, evt):
+ """
+ Called when wxPaintEvt is generated
+
+ """
+ if not self._isRealized:
+ self.realize()
+ if self._drawn < 2:
+ self.draw(repaint=False)
+ self._drawn += 1
+ self.gui_repaint(drawDC=wx.PaintDC(self))
diff --git a/src/sas/sasgui/plottools/PropertyDialog.py b/src/sas/sasgui/plottools/PropertyDialog.py
index 27833f4..2f0fc4e 100644
--- a/src/sas/sasgui/plottools/PropertyDialog.py
+++ b/src/sas/sasgui/plottools/PropertyDialog.py
@@ -1,116 +1,116 @@
-"""
-"""
-import wx
-
-class Properties(wx.Dialog):
- """
- """
- def __init__(self, parent, id=-1, title="Select the scale of the graph"):
- wx.Dialog.__init__(self, parent, id, title)
- self.parent = parent
- vbox = wx.BoxSizer(wx.VERTICAL)
- sizer = wx.GridBagSizer(5, 5)
-
- x_size = 70
-
- ix = 1
- iy = 1
- sizer.Add(wx.StaticText(self, -1, 'X'), (iy, ix))
- ix += 2
- sizer.Add(wx.StaticText(self, -1, 'Y'), (iy, ix))
- ix += 2
- sizer.Add(wx.StaticText(self, -1, 'View'), (iy, ix))
- iy += 1
- ix = 1
- self.xvalue = wx.ComboBox(self, -1, style=wx.CB_READONLY)
- x_size += self.xvalue.GetSize()[0]
- sizer.Add(self.xvalue, (iy, ix), (1, 1), wx.ADJUST_MINSIZE, 0)
-
- ix += 2
- self.yvalue = wx.ComboBox(self, -1, style=wx.CB_READONLY)
- x_size += self.yvalue.GetSize()[0]
- sizer.Add(self.yvalue, (iy, ix), (1, 1), wx.ADJUST_MINSIZE, 0)
-
- ix += 2
- self.view = wx.ComboBox(self, -1, style=wx.CB_READONLY)
- self.view.Bind(wx.EVT_COMBOBOX, self.viewChanged)
- x_size += self.view.GetSize()[0]
- self.view.SetMinSize((160, 30))
- sizer.Add(self.view, (iy, ix), (1, 1),
- wx.EXPAND | wx.RIGHT | wx.ADJUST_MINSIZE, 10)
- self.SetMinSize((x_size, 50))
- vbox.Add(sizer, 0, wx.EXPAND | wx.ADJUST_MINSIZE, 0)
-
- cancel_button = wx.Button(self, wx.ID_CANCEL, 'Cancel')
- ok_button = wx.Button(self, wx.ID_OK, "OK")
- sizer_button = wx.BoxSizer(wx.HORIZONTAL)
- sizer_button.Add((20, 20), 1, wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- sizer_button.Add(ok_button, 0, wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 10)
- sizer_button.Add(cancel_button, 0, wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 10)
- vbox.Add(sizer_button, 0,
- wx.EXPAND | wx.TOP | wx.BOTTOM | wx.ADJUST_MINSIZE, 10)
- # scale value for x
- self.xvalue.SetValue("ln(x)")
- self.xvalue.Insert("x", 0)
- self.xvalue.Insert("x^(2)", 1)
- self.xvalue.Insert("x^(4)", 2)
- self.xvalue.Insert("ln(x)", 3)
- self.xvalue.Insert("log10(x)", 4)
- self.xvalue.Insert("log10(x^(4))", 5)
-
- # scale value for y
- self.yvalue.SetValue("ln(y)")
- self.yvalue.Insert("y", 0)
- self.yvalue.Insert("1/y", 1)
- self.yvalue.Insert("ln(y)", 2)
- self.yvalue.Insert("y^(2)", 3)
- self.yvalue.Insert("y*x^(2)", 4)
- self.yvalue.Insert("y*x^(4)", 5)
- self.yvalue.Insert("1/sqrt(y)", 6)
- self.yvalue.Insert("log10(y)", 7)
- self.yvalue.Insert("ln(y*x)", 8)
- self.yvalue.Insert("ln(y*x^(2))", 9)
- self.yvalue.Insert("ln(y*x^(4))", 10)
- self.yvalue.Insert("log10(y*x^(4))", 11)
- # type of view or model used
- self.view.SetValue("--")
- self.view.Insert("--", 0)
- self.view.Insert("Linear y vs x", 1)
- self.view.Insert("Guinier lny vs x^(2)", 2)
- self.view.Insert("XS Guinier ln(y*x) vs x^(2)", 3)
- self.view.Insert("Porod y*x^(4) vs x^(4)", 4)
- self.view.Insert("Kratky y*x^(2) vs x", 5)
- self.SetSizer(vbox)
- self.Fit()
- self.Centre()
-
- def viewChanged(self, event):
- event.Skip()
- view = self.view.GetValue()
- if view == "Linear y vs x":
- self.xvalue.SetValue("x")
- self.yvalue.SetValue("y")
- elif view == "Guinier lny vs x^(2)":
- self.xvalue.SetValue("x^(2)")
- self.yvalue.SetValue("ln(y)")
- elif view == "XS Guinier ln(y*x) vs x^(2)":
- self.xvalue.SetValue("x^(2)")
- self.yvalue.SetValue("ln(y*x)")
- elif view == "Porod y*x^(4) vs x^(4)":
- self.xvalue.SetValue("x^(4)")
- self.yvalue.SetValue("y*x^(4)")
- elif view == "Kratky y*x^(2) vs x":
- self.xvalue.SetValue("x")
- self.yvalue.SetValue("y*x^(2)")
-
- def setValues(self, x, y, view):
- """
- """
- return self.xvalue.SetValue(x), self.yvalue.SetValue(y), \
- self.view.SetValue(view)
-
- def getValues(self):
- """
- """
- return self.xvalue.GetValue(), self.yvalue.GetValue(), \
- self.view.GetValue()
+"""
+"""
+import wx
+
+class Properties(wx.Dialog):
+ """
+ """
+ def __init__(self, parent, id=-1, title="Select the scale of the graph"):
+ wx.Dialog.__init__(self, parent, id, title)
+ self.parent = parent
+ vbox = wx.BoxSizer(wx.VERTICAL)
+ sizer = wx.GridBagSizer(5, 5)
+
+ x_size = 70
+
+ ix = 1
+ iy = 1
+ sizer.Add(wx.StaticText(self, -1, 'X'), (iy, ix))
+ ix += 2
+ sizer.Add(wx.StaticText(self, -1, 'Y'), (iy, ix))
+ ix += 2
+ sizer.Add(wx.StaticText(self, -1, 'View'), (iy, ix))
+ iy += 1
+ ix = 1
+ self.xvalue = wx.ComboBox(self, -1, style=wx.CB_READONLY)
+ x_size += self.xvalue.GetSize()[0]
+ sizer.Add(self.xvalue, (iy, ix), (1, 1), wx.ADJUST_MINSIZE, 0)
+
+ ix += 2
+ self.yvalue = wx.ComboBox(self, -1, style=wx.CB_READONLY)
+ x_size += self.yvalue.GetSize()[0]
+ sizer.Add(self.yvalue, (iy, ix), (1, 1), wx.ADJUST_MINSIZE, 0)
+
+ ix += 2
+ self.view = wx.ComboBox(self, -1, style=wx.CB_READONLY)
+ self.view.Bind(wx.EVT_COMBOBOX, self.viewChanged)
+ x_size += self.view.GetSize()[0]
+ self.view.SetMinSize((160, 30))
+ sizer.Add(self.view, (iy, ix), (1, 1),
+ wx.EXPAND | wx.RIGHT | wx.ADJUST_MINSIZE, 10)
+ self.SetMinSize((x_size, 50))
+ vbox.Add(sizer, 0, wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+
+ cancel_button = wx.Button(self, wx.ID_CANCEL, 'Cancel')
+ ok_button = wx.Button(self, wx.ID_OK, "OK")
+ sizer_button = wx.BoxSizer(wx.HORIZONTAL)
+ sizer_button.Add((20, 20), 1, wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ sizer_button.Add(ok_button, 0, wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 10)
+ sizer_button.Add(cancel_button, 0, wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 10)
+ vbox.Add(sizer_button, 0,
+ wx.EXPAND | wx.TOP | wx.BOTTOM | wx.ADJUST_MINSIZE, 10)
+ # scale value for x
+ self.xvalue.SetValue("ln(x)")
+ self.xvalue.Insert("x", 0)
+ self.xvalue.Insert("x^(2)", 1)
+ self.xvalue.Insert("x^(4)", 2)
+ self.xvalue.Insert("ln(x)", 3)
+ self.xvalue.Insert("log10(x)", 4)
+ self.xvalue.Insert("log10(x^(4))", 5)
+
+ # scale value for y
+ self.yvalue.SetValue("ln(y)")
+ self.yvalue.Insert("y", 0)
+ self.yvalue.Insert("1/y", 1)
+ self.yvalue.Insert("ln(y)", 2)
+ self.yvalue.Insert("y^(2)", 3)
+ self.yvalue.Insert("y*x^(2)", 4)
+ self.yvalue.Insert("y*x^(4)", 5)
+ self.yvalue.Insert("1/sqrt(y)", 6)
+ self.yvalue.Insert("log10(y)", 7)
+ self.yvalue.Insert("ln(y*x)", 8)
+ self.yvalue.Insert("ln(y*x^(2))", 9)
+ self.yvalue.Insert("ln(y*x^(4))", 10)
+ self.yvalue.Insert("log10(y*x^(4))", 11)
+ # type of view or model used
+ self.view.SetValue("--")
+ self.view.Insert("--", 0)
+ self.view.Insert("Linear y vs x", 1)
+ self.view.Insert("Guinier lny vs x^(2)", 2)
+ self.view.Insert("XS Guinier ln(y*x) vs x^(2)", 3)
+ self.view.Insert("Porod y*x^(4) vs x^(4)", 4)
+ self.view.Insert("Kratky y*x^(2) vs x", 5)
+ self.SetSizer(vbox)
+ self.Fit()
+ self.Centre()
+
+ def viewChanged(self, event):
+ event.Skip()
+ view = self.view.GetValue()
+ if view == "Linear y vs x":
+ self.xvalue.SetValue("x")
+ self.yvalue.SetValue("y")
+ elif view == "Guinier lny vs x^(2)":
+ self.xvalue.SetValue("x^(2)")
+ self.yvalue.SetValue("ln(y)")
+ elif view == "XS Guinier ln(y*x) vs x^(2)":
+ self.xvalue.SetValue("x^(2)")
+ self.yvalue.SetValue("ln(y*x)")
+ elif view == "Porod y*x^(4) vs x^(4)":
+ self.xvalue.SetValue("x^(4)")
+ self.yvalue.SetValue("y*x^(4)")
+ elif view == "Kratky y*x^(2) vs x":
+ self.xvalue.SetValue("x")
+ self.yvalue.SetValue("y*x^(2)")
+
+ def setValues(self, x, y, view):
+ """
+ """
+ return self.xvalue.SetValue(x), self.yvalue.SetValue(y), \
+ self.view.SetValue(view)
+
+ def getValues(self):
+ """
+ """
+ return self.xvalue.GetValue(), self.yvalue.GetValue(), \
+ self.view.GetValue()
diff --git a/src/sas/sasgui/plottools/SizeDialog.py b/src/sas/sasgui/plottools/SizeDialog.py
index 3828d4c..56dc9ea 100644
--- a/src/sas/sasgui/plottools/SizeDialog.py
+++ b/src/sas/sasgui/plottools/SizeDialog.py
@@ -1,38 +1,38 @@
-import wx
-
-
-class SizeDialog(wx.Dialog):
- def __init__(self, parent, id, title):
- wx.Dialog.__init__(self, parent, id, title, size=(300, 175))
-
- mainbox = wx.BoxSizer(wx.VERTICAL)
- vbox = wx.BoxSizer(wx.VERTICAL)
- textbox = wx.BoxSizer(wx.HORIZONTAL)
- hbox = wx.BoxSizer(wx.HORIZONTAL)
- text1 = "Enter in a custom size (> 0 accepted)"
- msg = wx.StaticText(self, -1, text1, (30, 15), style=wx.ALIGN_CENTRE)
- msg.SetLabel(text1)
- self.text_ctrl = wx.TextCtrl(self, -1, '', (100, 50))
-
- textbox.Add(self.text_ctrl, flag=wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, border=10)
- vbox.Add(msg, flag=wx.ALL, border=10, proportion=1)
- vbox.Add(textbox, flag=wx.EXPAND | wx.TOP | wx.BOTTOM | wx.ADJUST_MINSIZE, border=10)
- self.text_ctrl.SetValue(str(5))
-
- ok_button = wx.Button(self, wx.ID_OK, 'OK', size=(70, 25))
- close_button = wx.Button(self, wx.ID_CANCEL, 'Cancel', size=(70, 25))
-
- hbox.Add(ok_button)
- hbox.Add((20, 20))
- hbox.Add(close_button)
-
- mainbox.Add(vbox, flag=wx.ALL, border=10)
- mainbox.Add(wx.StaticLine(self), 0, wx.ALL | wx.EXPAND, 5)
- mainbox.Add(hbox, flag=wx.CENTER, border=10)
- self.SetSizer(mainbox)
-
- def getText(self):
- """
- Get text typed
- """
- return self.text_ctrl.GetValue()
+import wx
+
+
+class SizeDialog(wx.Dialog):
+ def __init__(self, parent, id, title):
+ wx.Dialog.__init__(self, parent, id, title, size=(300, 175))
+
+ mainbox = wx.BoxSizer(wx.VERTICAL)
+ vbox = wx.BoxSizer(wx.VERTICAL)
+ textbox = wx.BoxSizer(wx.HORIZONTAL)
+ hbox = wx.BoxSizer(wx.HORIZONTAL)
+ text1 = "Enter in a custom size (> 0 accepted)"
+ msg = wx.StaticText(self, -1, text1, (30, 15), style=wx.ALIGN_CENTRE)
+ msg.SetLabel(text1)
+ self.text_ctrl = wx.TextCtrl(self, -1, '', (100, 50))
+
+ textbox.Add(self.text_ctrl, flag=wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, border=10)
+ vbox.Add(msg, flag=wx.ALL, border=10, proportion=1)
+ vbox.Add(textbox, flag=wx.EXPAND | wx.TOP | wx.BOTTOM | wx.ADJUST_MINSIZE, border=10)
+ self.text_ctrl.SetValue(str(5))
+
+ ok_button = wx.Button(self, wx.ID_OK, 'OK', size=(70, 25))
+ close_button = wx.Button(self, wx.ID_CANCEL, 'Cancel', size=(70, 25))
+
+ hbox.Add(ok_button)
+ hbox.Add((20, 20))
+ hbox.Add(close_button)
+
+ mainbox.Add(vbox, flag=wx.ALL, border=10)
+ mainbox.Add(wx.StaticLine(self), 0, wx.ALL | wx.EXPAND, 5)
+ mainbox.Add(hbox, flag=wx.CENTER, border=10)
+ self.SetSizer(mainbox)
+
+ def getText(self):
+ """
+ Get text typed
+ """
+ return self.text_ctrl.GetValue()
diff --git a/src/sas/sasgui/plottools/TextDialog.py b/src/sas/sasgui/plottools/TextDialog.py
index 6812cc0..8d3f37f 100644
--- a/src/sas/sasgui/plottools/TextDialog.py
+++ b/src/sas/sasgui/plottools/TextDialog.py
@@ -1,307 +1,307 @@
-import wx
-import sys
-
-if sys.platform.count("win32") > 0:
- FONT_VARIANT = 0
- PNL_WIDTH = 460
-else:
- FONT_VARIANT = 1
- PNL_WIDTH = 500
-FAMILY = ['serif', 'sans-serif', 'fantasy', 'monospace']
-SIZE = [8, 9, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 36, 48, 72]
-STYLE = ['normal', 'italic']
-WEIGHT = ['light', 'normal', 'bold']
-COLOR = ['black', 'blue', 'green', 'red', 'cyan', 'magenta', 'yellow']
-
-
-class TextDialog(wx.Dialog):
- def __init__(self, parent, id, title, label='', unit=None):
- """
- Dialog window pops- up when selecting 'Add Text' on the toolbar
- """
- wx.Dialog.__init__(self, parent, id, title, size=(PNL_WIDTH, 300))
- self.parent = parent
- # Font
- self.SetWindowVariant(variant=FONT_VARIANT)
- # default
- self.family = FAMILY[1]
- self.size = SIZE[3]
- self.style = STYLE[0]
- self.weight = WEIGHT[1]
- self.color = COLOR[0]
- self.tick_label = False
- # Dialog interface
- vbox = wx.BoxSizer(wx.VERTICAL)
- text_box = wx.BoxSizer(wx.HORIZONTAL)
- sizer = wx.GridBagSizer(1, 3)
- _BOX_WIDTH = 70
- font_description = wx.StaticBox(self, -1, 'Font')
- font_box = wx.StaticBoxSizer(font_description, wx.VERTICAL)
- family_box = wx.BoxSizer(wx.HORIZONTAL)
- style_box = wx.BoxSizer(wx.HORIZONTAL)
- # tcA
- if unit != None:
- styles = wx.TAB_TRAVERSAL
- height = -1
- unit_text = wx.StaticText(self, -1, 'Unit :')
- unit_text.SetToolTipString("Unit of the axis.")
- self.unit_ctrl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, -1))
- self.unit_ctrl.SetValue(str(unit))
- unit_box = wx.BoxSizer(wx.HORIZONTAL)
- tick_label_text = wx.StaticText(self, -1, 'Tick label')
- tick_label_text.SetToolTipString("Apply to tick label too.")
- self.tick_label_check = wx.CheckBox(self, -1, '', (10, 10))
- self.tick_label_check.SetValue(False)
- self.tick_label_check.SetToolTipString("Apply to tick label too.")
- wx.EVT_CHECKBOX(self, self.tick_label_check.GetId(),
- self.on_tick_label)
- enter_text = 'Enter text:'
- else:
- styles = wx.TAB_TRAVERSAL | wx.TE_MULTILINE | wx.TE_LINEWRAP | \
- wx.TE_PROCESS_ENTER | wx.SUNKEN_BORDER | wx.HSCROLL
- height = 60
- unit_text = None
- self.unit_ctrl = None
- unit_box = None
- tick_label_text = None
- self.tick_label_check = None
- enter_text = 'Enter text'
- if len(label) > 0:
- enter_text += " (this text won't be auto-updated if modified.):"
- else:
- enter_text += ":"
- self.text_string = wx.TextCtrl(self, -1, size=(PNL_WIDTH - 30, height), style=styles)
- self.text_string.SetValue(str(label))
- self.text_string.SetToolTipString("The text that will be displayed.")
- # font family
- self.font_family = wx.ComboBox(self, -1, style=wx.CB_READONLY)
- wx.EVT_COMBOBOX(self.font_family, -1, self.on_family)
- self.font_family.SetMinSize((_BOX_WIDTH, -1))
- self._set_family_list()
- self.font_family.SetSelection(1)
- self.font_family.SetToolTipString("Font family of the text.")
- # font weight
- self.font_weight = wx.ComboBox(self, -1, style=wx.CB_READONLY)
- wx.EVT_COMBOBOX(self.font_weight, -1, self.on_weight)
- self.font_weight.SetMinSize((_BOX_WIDTH, -1))
- self._set_weight_list()
- self.font_weight.SetSelection(1)
- self.font_weight.SetToolTipString("Font weight of the text.")
- # font family
- self.font_size = wx.ComboBox(self, -1, style=wx.CB_READONLY)
- wx.EVT_COMBOBOX(self.font_size, -1, self.on_size)
- self.font_size.SetMinSize((_BOX_WIDTH, -1))
- self._set_size_list()
- self.font_size.SetSelection(5)
- self.font_size.SetToolTipString("Font size of the text.")
- # font style
- self.font_style = wx.ComboBox(self, -1, style=wx.CB_READONLY)
- wx.EVT_COMBOBOX(self.font_style, -1, self.on_style)
- self.font_style.SetMinSize((_BOX_WIDTH, -1))
- self._set_style_list()
- self.font_style.SetSelection(0)
- self.font_style.SetToolTipString("Font style of the text.")
- # font color
- self.font_color = wx.ComboBox(self, -1, style = wx.CB_READONLY)
- wx.EVT_COMBOBOX(self.font_color, -1, self.on_color)
- self.font_color.SetMinSize((_BOX_WIDTH, -1))
- self._set_color_list()
- self.font_color.SetSelection(0)
- self.font_color.SetToolTipString("Font color of the text.")
- # Buttons on the bottom
- self.static_line_1 = wx.StaticLine(self, -1)
- self.ok_button = wx.Button(self, wx.ID_OK, 'OK',
- size = (_BOX_WIDTH, 25))
- self.close_button = wx.Button(self, wx.ID_CANCEL, 'Cancel',
- size = (_BOX_WIDTH, 25))
-
- # Intro
- explanation = "Select font properties :"
- vbox.Add(sizer)
- ix = 0
- iy = 1
- sizer.Add(wx.StaticText(self, -1, explanation), (iy, ix),
- (1, 1), wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- family_box.Add(wx.StaticText(self, -1, 'Family :', size = (50, -1)),
- 0, wx.TOP, 5)
- family_box.Add(self.font_family, 0, 0)
- family_box.Add((_BOX_WIDTH / 2, -1))
- family_box.Add(wx.StaticText(self, -1, 'Size :', size = (50, -1)),
- 0, wx.TOP, 5)
- family_box.Add(self.font_size, 0, 0)
- if unit_box != None:
- family_box.Add((_BOX_WIDTH / 2, -1))
- family_box.Add(tick_label_text, 0, 0)
- family_box.Add(self.tick_label_check, 0, 0)
- style_box.Add(wx.StaticText(self, -1, 'Style :', size = (50, -1)),
- 0, wx.TOP, 5)
- style_box.Add(self.font_style, 0, 0)
- style_box.Add((_BOX_WIDTH / 2, -1))
- style_box.Add(wx.StaticText(self, -1, 'Weight :', size = (50, -1)),
- 0, wx.TOP, 5)
- style_box.Add(self.font_weight, 0, 0)
- style_box.Add((_BOX_WIDTH / 2, -1))
- style_box.Add(wx.StaticText(self, -1, 'Color :', size = (45, -1)),
- 0, wx.TOP, 5)
- style_box.Add(self.font_color, 0, 0)
- font_box.Add(family_box, 0, 10)
- font_box.Add((0,5))
- font_box.Add(style_box, 0, 10)
- iy += 1
- ix = 0
- sizer.Add(font_box, (iy, ix),
- (1, 1), wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- iy += 2
- ix = 0
- sizer.Add(wx.StaticText(self, -1, enter_text), (iy, ix),
- (1, 1), wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- text_box.Add((15, 10))
- text_box.Add(self.text_string)
- vbox.Add(text_box, 0, wx.EXPAND, 15)
- if unit_box != None:
- unit_box.Add(unit_text, 0, 0)
- unit_box.Add(self.unit_ctrl, 0, 0)
- vbox.Add((5, 5))
- vbox.Add(unit_box, 0, wx.LEFT, 15)
-
- vbox.Add((10, 10))
- vbox.Add(self.static_line_1, 0, wx.EXPAND, 10)
- sizer_button = wx.BoxSizer(wx.HORIZONTAL)
- sizer_button.Add((20, 20), 1, wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- sizer_button.Add(self.ok_button, 0,
- wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 10)
- sizer_button.Add(self.close_button, 0,
- wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 10)
- vbox.Add(sizer_button, 0, wx.EXPAND | wx.BOTTOM | wx.TOP, 10)
- self.SetSizer(vbox)
- self.Centre()
-
- def _set_family_list(self):
- """
- Set the list of font family
- """
- # list of family choices
- for idx in range(len(FAMILY)):
- self.font_family.Append(FAMILY[idx], idx)
-
- def _set_size_list(self):
- """
- Set the list of font size
- """
- # list of size choices
- for idx in range(len(SIZE)):
- self.font_size.Append(str(SIZE[idx]), idx)
-
- def _set_weight_list(self):
- """
- Set the list of font weight
- """
- # list of weight choices
- for idx in range(len(WEIGHT)):
- self.font_weight.Append(WEIGHT[idx], idx)
-
- def _set_style_list(self):
- """
- Set the list of font style
- """
- # list of style choices
- for idx in range(len(STYLE)):
- self.font_style.Append(STYLE[idx], idx)
-
- def _set_color_list(self):
- """
- Set the list of font color
- """
- # list of tyle choices
- for idx in range(len(COLOR)):
- self.font_color.Append(COLOR[idx], idx)
-
- def on_tick_label(self, event):
- """
- Set the font for tick label
- """
- event.Skip()
- self.tick_label = self.tick_label_check.GetValue()
-
- def on_family(self, event):
- """
- Set the family
- """
- event.Skip()
- self.family = self.font_family.GetValue()
-
- def on_style(self, event):
- """
- Set the style
- """
- event.Skip()
- self.style = self.font_style.GetValue()
-
- def on_weight(self, event):
- """
- Set the weight
- """
- event.Skip()
- self.weight = self.font_weight.GetValue()
-
- def on_size(self, event):
- """
- Set the size
- """
- event.Skip()
- self.size = self.font_size.GetValue()
-
- def on_color(self, event):
- """
- Set the color
- """
- event.Skip()
- self.color = self.font_color.GetValue()
-
- def getText(self):
- """
- Returns text string as input by user.
- """
- return self.text_string.GetValue()
-
- def getUnit(self):
- """
- Returns unit string as input by user.
- """
- return self.unit_ctrl.GetValue()
-
- def getFamily(self):
- """
- Returns font family for the text box
- """
- return str(self.family)
-
- def getStyle(self):
- """
- Returns font tyle for the text box
- """
- return str(self.style)
-
- def getWeight(self):
- """
- Returns font weight for the text box
- """
- return str(self.weight)
-
- def getSize(self):
- """
- Returns font size for the text box
- """
- return int(self.size)
-
- def getColor(self):
- """
- Returns font size for the text box
- """
- return str(self.color)
-
- def getTickLabel(self):
- """
- Bool for use on tick label
- """
- return self.tick_label
+import wx
+import sys
+
+if sys.platform.count("win32") > 0:
+ FONT_VARIANT = 0
+ PNL_WIDTH = 460
+else:
+ FONT_VARIANT = 1
+ PNL_WIDTH = 500
+FAMILY = ['serif', 'sans-serif', 'fantasy', 'monospace']
+SIZE = [8, 9, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 36, 48, 72]
+STYLE = ['normal', 'italic']
+WEIGHT = ['light', 'normal', 'bold']
+COLOR = ['black', 'blue', 'green', 'red', 'cyan', 'magenta', 'yellow']
+
+
+class TextDialog(wx.Dialog):
+ def __init__(self, parent, id, title, label='', unit=None):
+ """
+ Dialog window pops- up when selecting 'Add Text' on the toolbar
+ """
+ wx.Dialog.__init__(self, parent, id, title, size=(PNL_WIDTH, 300))
+ self.parent = parent
+ # Font
+ self.SetWindowVariant(variant=FONT_VARIANT)
+ # default
+ self.family = FAMILY[1]
+ self.size = SIZE[3]
+ self.style = STYLE[0]
+ self.weight = WEIGHT[1]
+ self.color = COLOR[0]
+ self.tick_label = False
+ # Dialog interface
+ vbox = wx.BoxSizer(wx.VERTICAL)
+ text_box = wx.BoxSizer(wx.HORIZONTAL)
+ sizer = wx.GridBagSizer(1, 3)
+ _BOX_WIDTH = 70
+ font_description = wx.StaticBox(self, -1, 'Font')
+ font_box = wx.StaticBoxSizer(font_description, wx.VERTICAL)
+ family_box = wx.BoxSizer(wx.HORIZONTAL)
+ style_box = wx.BoxSizer(wx.HORIZONTAL)
+ # tcA
+ if unit is not None:
+ styles = wx.TAB_TRAVERSAL
+ height = -1
+ unit_text = wx.StaticText(self, -1, 'Unit :')
+ unit_text.SetToolTipString("Unit of the axis.")
+ self.unit_ctrl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, -1))
+ self.unit_ctrl.SetValue(str(unit))
+ unit_box = wx.BoxSizer(wx.HORIZONTAL)
+ tick_label_text = wx.StaticText(self, -1, 'Tick label')
+ tick_label_text.SetToolTipString("Apply to tick label too.")
+ self.tick_label_check = wx.CheckBox(self, -1, '', (10, 10))
+ self.tick_label_check.SetValue(False)
+ self.tick_label_check.SetToolTipString("Apply to tick label too.")
+ wx.EVT_CHECKBOX(self, self.tick_label_check.GetId(),
+ self.on_tick_label)
+ enter_text = 'Enter text:'
+ else:
+ styles = wx.TAB_TRAVERSAL | wx.TE_MULTILINE | wx.TE_LINEWRAP | \
+ wx.TE_PROCESS_ENTER | wx.SUNKEN_BORDER | wx.HSCROLL
+ height = 60
+ unit_text = None
+ self.unit_ctrl = None
+ unit_box = None
+ tick_label_text = None
+ self.tick_label_check = None
+ enter_text = 'Enter text'
+ if len(label) > 0:
+ enter_text += " (this text won't be auto-updated if modified.):"
+ else:
+ enter_text += ":"
+ self.text_string = wx.TextCtrl(self, -1, size=(PNL_WIDTH - 30, height), style=styles)
+ self.text_string.SetValue(str(label))
+ self.text_string.SetToolTipString("The text that will be displayed.")
+ # font family
+ self.font_family = wx.ComboBox(self, -1, style=wx.CB_READONLY)
+ wx.EVT_COMBOBOX(self.font_family, -1, self.on_family)
+ self.font_family.SetMinSize((_BOX_WIDTH, -1))
+ self._set_family_list()
+ self.font_family.SetSelection(1)
+ self.font_family.SetToolTipString("Font family of the text.")
+ # font weight
+ self.font_weight = wx.ComboBox(self, -1, style=wx.CB_READONLY)
+ wx.EVT_COMBOBOX(self.font_weight, -1, self.on_weight)
+ self.font_weight.SetMinSize((_BOX_WIDTH, -1))
+ self._set_weight_list()
+ self.font_weight.SetSelection(1)
+ self.font_weight.SetToolTipString("Font weight of the text.")
+ # font family
+ self.font_size = wx.ComboBox(self, -1, style=wx.CB_READONLY)
+ wx.EVT_COMBOBOX(self.font_size, -1, self.on_size)
+ self.font_size.SetMinSize((_BOX_WIDTH, -1))
+ self._set_size_list()
+ self.font_size.SetSelection(5)
+ self.font_size.SetToolTipString("Font size of the text.")
+ # font style
+ self.font_style = wx.ComboBox(self, -1, style=wx.CB_READONLY)
+ wx.EVT_COMBOBOX(self.font_style, -1, self.on_style)
+ self.font_style.SetMinSize((_BOX_WIDTH, -1))
+ self._set_style_list()
+ self.font_style.SetSelection(0)
+ self.font_style.SetToolTipString("Font style of the text.")
+ # font color
+ self.font_color = wx.ComboBox(self, -1, style = wx.CB_READONLY)
+ wx.EVT_COMBOBOX(self.font_color, -1, self.on_color)
+ self.font_color.SetMinSize((_BOX_WIDTH, -1))
+ self._set_color_list()
+ self.font_color.SetSelection(0)
+ self.font_color.SetToolTipString("Font color of the text.")
+ # Buttons on the bottom
+ self.static_line_1 = wx.StaticLine(self, -1)
+ self.ok_button = wx.Button(self, wx.ID_OK, 'OK',
+ size = (_BOX_WIDTH, 25))
+ self.close_button = wx.Button(self, wx.ID_CANCEL, 'Cancel',
+ size = (_BOX_WIDTH, 25))
+
+ # Intro
+ explanation = "Select font properties :"
+ vbox.Add(sizer)
+ ix = 0
+ iy = 1
+ sizer.Add(wx.StaticText(self, -1, explanation), (iy, ix),
+ (1, 1), wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ family_box.Add(wx.StaticText(self, -1, 'Family :', size = (50, -1)),
+ 0, wx.TOP, 5)
+ family_box.Add(self.font_family, 0, 0)
+ family_box.Add((_BOX_WIDTH / 2, -1))
+ family_box.Add(wx.StaticText(self, -1, 'Size :', size = (50, -1)),
+ 0, wx.TOP, 5)
+ family_box.Add(self.font_size, 0, 0)
+ if unit_box is not None:
+ family_box.Add((_BOX_WIDTH / 2, -1))
+ family_box.Add(tick_label_text, 0, 0)
+ family_box.Add(self.tick_label_check, 0, 0)
+ style_box.Add(wx.StaticText(self, -1, 'Style :', size = (50, -1)),
+ 0, wx.TOP, 5)
+ style_box.Add(self.font_style, 0, 0)
+ style_box.Add((_BOX_WIDTH / 2, -1))
+ style_box.Add(wx.StaticText(self, -1, 'Weight :', size = (50, -1)),
+ 0, wx.TOP, 5)
+ style_box.Add(self.font_weight, 0, 0)
+ style_box.Add((_BOX_WIDTH / 2, -1))
+ style_box.Add(wx.StaticText(self, -1, 'Color :', size = (45, -1)),
+ 0, wx.TOP, 5)
+ style_box.Add(self.font_color, 0, 0)
+ font_box.Add(family_box, 0, 10)
+ font_box.Add((0,5))
+ font_box.Add(style_box, 0, 10)
+ iy += 1
+ ix = 0
+ sizer.Add(font_box, (iy, ix),
+ (1, 1), wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ iy += 2
+ ix = 0
+ sizer.Add(wx.StaticText(self, -1, enter_text), (iy, ix),
+ (1, 1), wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ text_box.Add((15, 10))
+ text_box.Add(self.text_string)
+ vbox.Add(text_box, 0, wx.EXPAND, 15)
+ if unit_box is not None:
+ unit_box.Add(unit_text, 0, 0)
+ unit_box.Add(self.unit_ctrl, 0, 0)
+ vbox.Add((5, 5))
+ vbox.Add(unit_box, 0, wx.LEFT, 15)
+
+ vbox.Add((10, 10))
+ vbox.Add(self.static_line_1, 0, wx.EXPAND, 10)
+ sizer_button = wx.BoxSizer(wx.HORIZONTAL)
+ sizer_button.Add((20, 20), 1, wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ sizer_button.Add(self.ok_button, 0,
+ wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 10)
+ sizer_button.Add(self.close_button, 0,
+ wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 10)
+ vbox.Add(sizer_button, 0, wx.EXPAND | wx.BOTTOM | wx.TOP, 10)
+ self.SetSizer(vbox)
+ self.Centre()
+
+ def _set_family_list(self):
+ """
+ Set the list of font family
+ """
+ # list of family choices
+ for idx in range(len(FAMILY)):
+ self.font_family.Append(FAMILY[idx], idx)
+
+ def _set_size_list(self):
+ """
+ Set the list of font size
+ """
+ # list of size choices
+ for idx in range(len(SIZE)):
+ self.font_size.Append(str(SIZE[idx]), idx)
+
+ def _set_weight_list(self):
+ """
+ Set the list of font weight
+ """
+ # list of weight choices
+ for idx in range(len(WEIGHT)):
+ self.font_weight.Append(WEIGHT[idx], idx)
+
+ def _set_style_list(self):
+ """
+ Set the list of font style
+ """
+ # list of style choices
+ for idx in range(len(STYLE)):
+ self.font_style.Append(STYLE[idx], idx)
+
+ def _set_color_list(self):
+ """
+ Set the list of font color
+ """
+ # list of tyle choices
+ for idx in range(len(COLOR)):
+ self.font_color.Append(COLOR[idx], idx)
+
+ def on_tick_label(self, event):
+ """
+ Set the font for tick label
+ """
+ event.Skip()
+ self.tick_label = self.tick_label_check.GetValue()
+
+ def on_family(self, event):
+ """
+ Set the family
+ """
+ event.Skip()
+ self.family = self.font_family.GetValue()
+
+ def on_style(self, event):
+ """
+ Set the style
+ """
+ event.Skip()
+ self.style = self.font_style.GetValue()
+
+ def on_weight(self, event):
+ """
+ Set the weight
+ """
+ event.Skip()
+ self.weight = self.font_weight.GetValue()
+
+ def on_size(self, event):
+ """
+ Set the size
+ """
+ event.Skip()
+ self.size = self.font_size.GetValue()
+
+ def on_color(self, event):
+ """
+ Set the color
+ """
+ event.Skip()
+ self.color = self.font_color.GetValue()
+
+ def getText(self):
+ """
+ Returns text string as input by user.
+ """
+ return self.text_string.GetValue()
+
+ def getUnit(self):
+ """
+ Returns unit string as input by user.
+ """
+ return self.unit_ctrl.GetValue()
+
+ def getFamily(self):
+ """
+ Returns font family for the text box
+ """
+ return str(self.family)
+
+ def getStyle(self):
+ """
+ Returns font tyle for the text box
+ """
+ return str(self.style)
+
+ def getWeight(self):
+ """
+ Returns font weight for the text box
+ """
+ return str(self.weight)
+
+ def getSize(self):
+ """
+ Returns font size for the text box
+ """
+ return int(self.size)
+
+ def getColor(self):
+ """
+ Returns font size for the text box
+ """
+ return str(self.color)
+
+ def getTickLabel(self):
+ """
+ Bool for use on tick label
+ """
+ return self.tick_label
diff --git a/src/sas/sasgui/plottools/__init__.py b/src/sas/sasgui/plottools/__init__.py
index 1f23601..f00c452 100644
--- a/src/sas/sasgui/plottools/__init__.py
+++ b/src/sas/sasgui/plottools/__init__.py
@@ -1,3 +1,2 @@
-import config
from PlotPanel import PlotPanel
from plottables import Data1D, Theory1D
diff --git a/src/sas/sasgui/plottools/arrow3d.py b/src/sas/sasgui/plottools/arrow3d.py
index f3c5708..17ee94a 100644
--- a/src/sas/sasgui/plottools/arrow3d.py
+++ b/src/sas/sasgui/plottools/arrow3d.py
@@ -1,67 +1,67 @@
-"""
-Module that draws multiple arrows in 3D coordinates
-"""
-
-from matplotlib.patches import FancyArrowPatch
-from mpl_toolkits.mplot3d import proj3d
-import time
-# from matplotlib.artist import allow_rasterization
-class Arrow3D(FancyArrowPatch):
- """
- Draw 3D arrow
- """
-
- def __init__(self, base, xs, ys, zs, colors, *args, **kwargs):
- """
- Init
-
- :Params xs: [[x0, x0+dx0], [x1, x1+dx1], ...]
- :Params ys: [[y0, y0+dy0], [y1, y1+dy1], ...]
- :Params zs: [[z0, z0+dz0], [z1, z1+dz1], ...]
- :Params colors: [[R0, G0, B0], [R1, G1, B1], ...]
- where R, G, B ranges (0,1)
- """
- FancyArrowPatch.__init__(self, (0, 0), (0, 0), *args, **kwargs)
- self.leftdown = False
- self.t_click = 0
- self._verts3d = xs, ys, zs
- self.colors = colors
- self.base = base
-
- if base != None:
- # To turn the updating off during dragging
- base.canvas.mpl_connect('button_press_event', self.on_left_down)
- base.canvas.mpl_connect('button_release_event', self.on_left_up)
-
- def on_left_down(self, event):
- """
- Mouse left-down event
- """
- self.leftdown = True
- self.t_click = time.time()
-
- def on_left_up(self, event):
- """
- Mouse left up event
- """
- t_up = time.time() - self.t_click
- # Avoid just clicking
- if t_up > 0.1:
- self.leftdown = False
- self.base.canvas.draw()
-
- def draw(self, renderer, rasterized=True):
- """
- Drawing actually happens here
- """
- # Draws only when the dragging finished
- if self.leftdown:
- return
- xs3d, ys3d, zs3d = self._verts3d
- for i in xrange(len(xs3d)):
- xs, ys, _ = proj3d.proj_transform(xs3d[i], ys3d[i], zs3d[i], renderer.M)
- self.set_positions((xs[0], ys[0]), (xs[1], ys[1]))
- self.set_color(self.colors[i])
- FancyArrowPatch.draw(self, renderer)
-
- self.leftdown = False
+"""
+Module that draws multiple arrows in 3D coordinates
+"""
+
+from matplotlib.patches import FancyArrowPatch
+from mpl_toolkits.mplot3d import proj3d
+import time
+# from matplotlib.artist import allow_rasterization
+class Arrow3D(FancyArrowPatch):
+ """
+ Draw 3D arrow
+ """
+
+ def __init__(self, base, xs, ys, zs, colors, *args, **kwargs):
+ """
+ Init
+
+ :Params xs: [[x0, x0+dx0], [x1, x1+dx1], ...]
+ :Params ys: [[y0, y0+dy0], [y1, y1+dy1], ...]
+ :Params zs: [[z0, z0+dz0], [z1, z1+dz1], ...]
+ :Params colors: [[R0, G0, B0], [R1, G1, B1], ...]
+ where R, G, B ranges (0,1)
+ """
+ FancyArrowPatch.__init__(self, (0, 0), (0, 0), *args, **kwargs)
+ self.leftdown = False
+ self.t_click = 0
+ self._verts3d = xs, ys, zs
+ self.colors = colors
+ self.base = base
+
+ if base is not None:
+ # To turn the updating off during dragging
+ base.canvas.mpl_connect('button_press_event', self.on_left_down)
+ base.canvas.mpl_connect('button_release_event', self.on_left_up)
+
+ def on_left_down(self, event):
+ """
+ Mouse left-down event
+ """
+ self.leftdown = True
+ self.t_click = time.time()
+
+ def on_left_up(self, event):
+ """
+ Mouse left up event
+ """
+ t_up = time.time() - self.t_click
+ # Avoid just clicking
+ if t_up > 0.1:
+ self.leftdown = False
+ self.base.canvas.draw()
+
+ def draw(self, renderer, rasterized=True):
+ """
+ Drawing actually happens here
+ """
+ # Draws only when the dragging finished
+ if self.leftdown:
+ return
+ xs3d, ys3d, zs3d = self._verts3d
+ for i in xrange(len(xs3d)):
+ xs, ys, _ = proj3d.proj_transform(xs3d[i], ys3d[i], zs3d[i], renderer.M)
+ self.set_positions((xs[0], ys[0]), (xs[1], ys[1]))
+ self.set_color(self.colors[i])
+ FancyArrowPatch.draw(self, renderer)
+
+ self.leftdown = False
diff --git a/src/sas/sasgui/plottools/binder.py b/src/sas/sasgui/plottools/binder.py
index b5ea1f0..c24f2e0 100644
--- a/src/sas/sasgui/plottools/binder.py
+++ b/src/sas/sasgui/plottools/binder.py
@@ -1,9 +1,13 @@
"""
Extension to MPL to support the binding of artists to key/mouse events.
"""
+from __future__ import print_function
+
import sys
import logging
+logger = logging.getLogger(__name__)
+
class Selection(object):
"""
Store and compare selections.
@@ -60,7 +64,7 @@ class BindArtist(object):
canvas.mpl_connect('scroll_event', self._onScroll)
]
except:
- print "bypassing scroll_event: wrong matplotlib version"
+ print("bypassing scroll_event: wrong matplotlib version")
self._connections = [
canvas.mpl_connect('motion_notify_event', self._onMotion),
canvas.mpl_connect('button_press_event', self._onClick),
@@ -120,7 +124,7 @@ class BindArtist(object):
try:
for cid in self._connections: self.canvas.mpl_disconnect(cid)
except:
- logging.error("Error disconnection canvas: %s" % sys.exc_value)
+ logger.error("Error disconnection canvas: %s" % sys.exc_value)
self._connections = []
def __del__(self):
diff --git a/src/sas/sasgui/plottools/canvas.py b/src/sas/sasgui/plottools/canvas.py
index 3ef31cb..6349411 100644
--- a/src/sas/sasgui/plottools/canvas.py
+++ b/src/sas/sasgui/plottools/canvas.py
@@ -10,6 +10,8 @@ from matplotlib.backend_bases import MouseEvent, RendererBase
from matplotlib.backends.backend_wx import GraphicsContextWx, PrintoutWx
from matplotlib.backends.backend_wx import RendererWx
+logger = logging.getLogger(__name__)
+
def draw_image(self, x, y, im, bbox, clippath=None, clippath_trans=None):
"""
@@ -95,7 +97,7 @@ def OnPrintPage(self, page):
try:
dc.DrawBitmap(self.canvas.bitmap, (0, 0))
except:
- logging.error(sys.exc_value)
+ logger.error(sys.exc_value)
# restore original figure resolution
self.canvas.figure.set_facecolor(bgcolor)
@@ -150,7 +152,7 @@ class FigureCanvas(FigureCanvasWxAgg):
Render after a delay if no other render requests have been made.
"""
self.panel.subplot.grid(self.panel.grid_on)
- if self.panel.legend != None and self.panel.legend_pos_loc:
+ if self.panel.legend is not None and self.panel.legend_pos_loc:
self.panel.legend._loc = self.panel.legend_pos_loc
self.idletimer.Restart(5, *args, **kwargs) # Delay by 5 ms
@@ -206,7 +208,7 @@ class FigureCanvas(FigureCanvasWxAgg):
try:
fig.draw(self)
except ValueError:
- logging.error(sys.exc_value)
+ logger.error(sys.exc_value)
else:
self._isRendered = False
if self.ndraw <= 1:
diff --git a/src/sas/sasgui/plottools/config.py b/src/sas/sasgui/plottools/config.py
index 51c2a66..e9d1b79 100644
--- a/src/sas/sasgui/plottools/config.py
+++ b/src/sas/sasgui/plottools/config.py
@@ -37,7 +37,7 @@ import matplotlib
try:
import pkg_resources
pkg_resources.require("matplotlib>=" + plot_version)
-except:
+except ImportError:
from distutils.version import LooseVersion as Version
if Version(matplotlib.__version__) < Version(plot_version):
msg = "Matplotlib version must be %s or newer" % (plot_version, )
diff --git a/src/sas/sasgui/plottools/convert_units.py b/src/sas/sasgui/plottools/convert_units.py
index e105ee7..af89f87 100644
--- a/src/sas/sasgui/plottools/convert_units.py
+++ b/src/sas/sasgui/plottools/convert_units.py
@@ -1,78 +1,80 @@
-"""
- Convert units to strings that can be displayed
- This is a cleaned up version of unitConverter.py
-"""
-import re
-import string
-
-def convert_unit(power, unit):
- """
- Convert units to strings that can be displayed
- """
- if power != 0:
- if string.find(unit, "^") != -1: # if the unit contains a powerer ^
- toks = re.split("\^", unit)
- if string.find(toks[0], "/") != -1 or \
- string.find(toks[0], "-") != -1:
- if power == 1:
- unit = unit
- else:
- unit = "(" + unit + ")" + "^{" + str(power) + "}"
- else:
- if string.find(toks[1], "{") != -1: # if found a {
- find_power_toks = re.split("{", toks[1])
- if string.find(find_power_toks[1], "}") != -1: # found }
- unit_toks = re.split("}", find_power_toks[1])
- if string.find(unit_toks[0], ".") != -1:
- powerer = float(unit_toks[0]) * power
- elif string.find(unit_toks[0], "/") != -1:
- power_toks = re.split("/", unit_toks[0])
- powerer = power * int(power_toks[0])\
- / int(power_toks[1])
- else:
- powerer = int(unit_toks[0]) * power
-
- if powerer == 1.0:
- unit = toks[0]
- elif powerer == 0.5:
- unit = toks[0] + "^{1/2}"
- elif powerer == -0.5:
- unit = toks[0] + "^{-1/2}"
- else:
- unit = toks[0] + "^{" + str(powerer) + "}"
- else:
- raise ValueError, "missing } in unit expression"
- else: # no powerer
- if power != 1:
- unit = "(" + unit + ")" + "^{" + str(power) + "}"
- else:
- raise ValueError, "empty unit ,enter a powerer different from zero"
- return unit
-
-
-if __name__ == "__main__":
- # pylint: disable=invalid-name
- # Input -> new scale -> Output
- unit1 = "A^{-1} " # x A^{-1}
- unit2 = "A" # x A
- unit3 = "A" # x^2 A^{2}
- unit4 = "A " # 1/x A^{-1}
- unit5 = "A^{0.5} " # x^2 A
- unit9 = "m^{1/2}" # x^2 m
-
- # If you don't recognize the pattern, give up
- # and just put some parentheses around the unit and write the transoformation:
-
- unit6 = "m/s" # x^2 (m/s)^{2}
- unit7 = "m/s^{2}" # 1/x (m/s^{2})^{-1}
- unit8 = "m/s^{4}" # x^2 (m/s^{4})^{2}
-
- print "this unit1 %s ,its powerer %s , and value %s" % (unit1, 1, convert_unit(1, unit1))
- print "this unit2 %s ,its powerer %s , and value %s" % (unit2, 1, convert_unit(1, unit2))
- print "this unit3 %s ,its powerer %s , and value %s" % (unit3, 2, convert_unit(2, unit3))
- print "this unit4 %s ,its powerer %s , and value %s" % (unit4, -1, convert_unit(-1, unit4))
- print "this unit5 %s ,its powerer %s , and value %s" % (unit5, 2, convert_unit(2, unit5))
- print "this unit6 %s ,its powerer %s , and value %s" % (unit6, 2, convert_unit(2, unit6))
- print "this unit7 %s ,its powerer %s , and value %s" % (unit7, -1, convert_unit(-1, unit7))
- print "this unit8 %s ,its powerer %s , and value %s" % (unit8, 2, convert_unit(2, unit8))
- print "this unit9 %s ,its powerer %s , and value %s" % (unit9, 2, convert_unit(2, unit9))
+"""
+ Convert units to strings that can be displayed
+ This is a cleaned up version of unitConverter.py
+"""
+from __future__ import print_function
+
+import re
+import string
+
+def convert_unit(power, unit):
+ """
+ Convert units to strings that can be displayed
+ """
+ if power != 0:
+ if string.find(unit, "^") != -1: # if the unit contains a powerer ^
+ toks = re.split("\^", unit)
+ if string.find(toks[0], "/") != -1 or \
+ string.find(toks[0], "-") != -1:
+ if power == 1:
+ unit = unit
+ else:
+ unit = "(" + unit + ")" + "^{" + str(power) + "}"
+ else:
+ if string.find(toks[1], "{") != -1: # if found a {
+ find_power_toks = re.split("{", toks[1])
+ if string.find(find_power_toks[1], "}") != -1: # found }
+ unit_toks = re.split("}", find_power_toks[1])
+ if string.find(unit_toks[0], ".") != -1:
+ powerer = float(unit_toks[0]) * power
+ elif string.find(unit_toks[0], "/") != -1:
+ power_toks = re.split("/", unit_toks[0])
+ powerer = power * int(power_toks[0])\
+ / int(power_toks[1])
+ else:
+ powerer = int(unit_toks[0]) * power
+
+ if powerer == 1.0:
+ unit = toks[0]
+ elif powerer == 0.5:
+ unit = toks[0] + "^{1/2}"
+ elif powerer == -0.5:
+ unit = toks[0] + "^{-1/2}"
+ else:
+ unit = toks[0] + "^{" + str(powerer) + "}"
+ else:
+ raise ValueError, "missing } in unit expression"
+ else: # no powerer
+ if power != 1:
+ unit = "(" + unit + ")" + "^{" + str(power) + "}"
+ else:
+ raise ValueError, "empty unit ,enter a powerer different from zero"
+ return unit
+
+
+if __name__ == "__main__":
+ # pylint: disable=invalid-name
+ # Input -> new scale -> Output
+ unit1 = "A^{-1} " # x A^{-1}
+ unit2 = "A" # x A
+ unit3 = "A" # x^2 A^{2}
+ unit4 = "A " # 1/x A^{-1}
+ unit5 = "A^{0.5} " # x^2 A
+ unit9 = "m^{1/2}" # x^2 m
+
+ # If you don't recognize the pattern, give up
+ # and just put some parentheses around the unit and write the transoformation:
+
+ unit6 = "m/s" # x^2 (m/s)^{2}
+ unit7 = "m/s^{2}" # 1/x (m/s^{2})^{-1}
+ unit8 = "m/s^{4}" # x^2 (m/s^{4})^{2}
+
+ print("this unit1 %s ,its powerer %s , and value %s" % (unit1, 1, convert_unit(1, unit1)))
+ print("this unit2 %s ,its powerer %s , and value %s" % (unit2, 1, convert_unit(1, unit2)))
+ print("this unit3 %s ,its powerer %s , and value %s" % (unit3, 2, convert_unit(2, unit3)))
+ print("this unit4 %s ,its powerer %s , and value %s" % (unit4, -1, convert_unit(-1, unit4)))
+ print("this unit5 %s ,its powerer %s , and value %s" % (unit5, 2, convert_unit(2, unit5)))
+ print("this unit6 %s ,its powerer %s , and value %s" % (unit6, 2, convert_unit(2, unit6)))
+ print("this unit7 %s ,its powerer %s , and value %s" % (unit7, -1, convert_unit(-1, unit7)))
+ print("this unit8 %s ,its powerer %s , and value %s" % (unit8, 2, convert_unit(2, unit8)))
+ print("this unit9 %s ,its powerer %s , and value %s" % (unit9, 2, convert_unit(2, unit9)))
diff --git a/src/sas/sasgui/plottools/fitDialog.py b/src/sas/sasgui/plottools/fitDialog.py
index c0a7af1..112354a 100644
--- a/src/sas/sasgui/plottools/fitDialog.py
+++ b/src/sas/sasgui/plottools/fitDialog.py
@@ -1,770 +1,770 @@
-import wx
-from plottables import Theory1D
-import math
-import numpy
-import fittings
-import transform
-import sys
-
-# Linear fit panel size
-if sys.platform.count("win32") > 0:
- FONT_VARIANT = 0
- PNL_WIDTH = 450
- PNL_HEIGHT = 500
-else:
- FONT_VARIANT = 1
- PNL_WIDTH = 500
- PNL_HEIGHT = 500
-RG_ON = True
-
-def format_number(value, high=False):
- """
- Return a float in a standardized, human-readable formatted string.
- This is used to output readable (e.g. x.xxxe-y) values to the panel.
- """
- try:
- value = float(value)
- except:
- output = "NaN"
- return output.lstrip().rstrip()
-
- if high:
- output = "%-6.4g" % value
-
- else:
- output = "%-5.3g" % value
- return output.lstrip().rstrip()
-
-
-class LinearFit(wx.Dialog):
- def __init__(self, parent, plottable, push_data, transform, title):
- """
- Dialog window pops- up when select Linear fit on Context menu
- Displays fitting parameters. This class handles the linearized
- fitting and derives and displays specialized output parameters based
- on the scale choice of the plot calling it.
-
- :note1: The fitting is currently a bit convoluted as besides using
- plottools.transform.py to handle all the conversions, it uses
- LineModel to define a linear model and calculate a number of
- things like residuals etc as well as the function itself given an x
- value. It also uses fittings.py to set up the defined LineModel for
- fitting and then send it to the SciPy NLLSQ method. As these are by
- definition "linear nodels" it would make more sense to just call
- a linear solver such as scipy.stats.linregress or bumps.wsolve directly.
- This would considerably simplify the code and remove the need I think
- for LineModel.py and possibly fittins.py altogether. -PDB 7/10/16
-
- :note2: The linearized fits do not take resolution into account. This
- means that for poor resolution such as slit smearing the answers will
- be completely wrong --- Rg would be OK but I0 would be orders of
- magnitude off. Eventually we should fix this to account properly for
- resolution. -PDB 7/10/16
- """
- wx.Dialog.__init__(self, parent, title=title,
- size=(PNL_WIDTH, 350))
- self.parent = parent
- self.transform = transform
- # Font
- self.SetWindowVariant(variant=FONT_VARIANT)
- # Registered owner for close event
- self._registered_close = None
- # dialog panel self call function to plot the fitting function
- # calls the calling PlotPanel method onFitDisplay
- self.push_data = push_data
- # dialog self plottable - basically the plot we are working with
- # passed in by the caller
- self.plottable = plottable
- # is this a Guinier fit
- self.rg_on = False
- # Receive transformations of x and y - basically transform is passed
- # as caller method that returns its current value for these
- self.xLabel, self.yLabel, self.Avalue, self.Bvalue, \
- self.ErrAvalue, self.ErrBvalue, self.Chivalue = self.transform()
-
- # Now set up the dialog interface
- self.layout()
- # Receives the type of model for the fitting
- from LineModel import LineModel
- self.model = LineModel()
- # Display the fittings values
- self.default_A = self.model.getParam('A')
- self.default_B = self.model.getParam('B')
- self.cstA = fittings.Parameter(self.model, 'A', self.default_A)
- self.cstB = fittings.Parameter(self.model, 'B', self.default_B)
-
- # Set default value of parameter in the dialog panel
- if self.Avalue == None:
- self.tcA.SetValue(format_number(self.default_A))
- else:
- self.tcA.SetLabel(format_number(self.Avalue))
- if self.Bvalue == None:
- self.tcB.SetValue(format_number(self.default_B))
- else:
- self.tcB.SetLabel(format_number(self.Bvalue))
- if self.ErrAvalue == None:
- self.tcErrA.SetLabel(format_number(0.0))
- else:
- self.tcErrA.SetLabel(format_number(self.ErrAvalue))
- if self.ErrBvalue == None:
- self.tcErrB.SetLabel(format_number(0.0))
- else:
- self.tcErrB.SetLabel(format_number(self.ErrBvalue))
- if self.Chivalue == None:
- self.tcChi.SetLabel(format_number(0.0))
- else:
- self.tcChi.SetLabel(format_number(self.Chivalue))
- if self.plottable.x != []:
- # store the values of View in self.x,self.y,self.dx,self.dy
- self.x, self.y, self.dx, \
- self.dy = self.plottable.returnValuesOfView()
- try:
- self.mini = self.floatForwardTransform(min(self.x))
- except:
- self.mini = "Invalid"
- try:
- self.maxi = self.floatForwardTransform(max(self.x))
- except:
- self.maxi = "Invalid"
-
- self.initXmin.SetValue(format_number(min(self.plottable.x)))
- self.initXmax.SetValue(format_number(max(self.plottable.x)))
- self.mini = min(self.x)
- self.maxi = max(self.x)
- self.xminFit.SetValue(format_number(self.mini))
- self.xmaxFit.SetValue(format_number(self.maxi))
-
- def layout(self):
- """
- Sets up the panel layout for the linear fit including all the
- labels, text entry boxes, and buttons.
-
- """
-
- # set up sizers first.
- # vbox is the panel sizer and is a vertical sizer
- # The first element of the panel is sizer which is a gridbagsizer
- # and contains most of the text fields
- # this is followed by a line separator added to vbox
- # and finally the sizer_button (a horizontal sizer) adds the buttons
- vbox = wx.BoxSizer(wx.VERTICAL)
- sizer = wx.GridBagSizer(5, 5)
- sizer_button = wx.BoxSizer(wx.HORIZONTAL)
-
- #size of string boxes in pixels
- _BOX_WIDTH = 100
- _BOX_HEIGHT = 20
- #now set up all the text fields
- self.tcA = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, _BOX_HEIGHT))
- self.tcA.SetToolTipString("Fit value for the slope parameter.")
- self.tcErrA = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, _BOX_HEIGHT))
- self.tcErrA.SetToolTipString("Error on the slope parameter.")
- self.tcB = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, _BOX_HEIGHT))
- self.tcA.SetToolTipString("Fit value for the constant parameter.")
- self.tcErrB = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, _BOX_HEIGHT))
- self.tcErrB.SetToolTipString("Error on the constant parameter.")
- self.tcChi = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, _BOX_HEIGHT))
- self.tcChi.SetToolTipString("Chi^2 over degrees of freedom.")
- self.xminFit = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, _BOX_HEIGHT))
- msg = "Enter the minimum value on "
- msg += "the x-axis to be included in the fit."
- self.xminFit.SetToolTipString(msg)
- self.xmaxFit = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, _BOX_HEIGHT))
- msg = "Enter the maximum value on "
- msg += " the x-axis to be included in the fit."
- self.xmaxFit.SetToolTipString(msg)
- self.initXmin = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, _BOX_HEIGHT))
- msg = "Minimum value on the x-axis for the plotted data."
- self.initXmin.SetToolTipString(msg)
- self.initXmax = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, _BOX_HEIGHT))
- msg = "Maximum value on the x-axis for the plotted data."
- self.initXmax.SetToolTipString(msg)
-
- # Make the info box not editable
- # _BACKGROUND_COLOR = '#ffdf85'
- _BACKGROUND_COLOR = self.GetBackgroundColour()
- self.initXmin.SetEditable(False)
- self.initXmin.SetBackgroundColour(_BACKGROUND_COLOR)
- self.initXmax.SetEditable(False)
- self.initXmax.SetBackgroundColour(_BACKGROUND_COLOR)
-
- #set some flags for specific types of fits like Guinier (Rg) and
- #Porod (bg) -- this will determine WHAT boxes show up in the
- #sizer layout and depends on the active axis transform
- self.bg_on = False
- if RG_ON:
- if (self.yLabel == "ln(y)" or self.yLabel == "ln(y*x)") and \
- (self.xLabel == "x^(2)"):
- self.rg_on = True
- if (self.xLabel == "x^(4)") and (self.yLabel == "y*x^(4)"):
- self.bg_on = True
-
- # Finally set up static text strings
- warning = "WARNING! Resolution is NOT accounted for. \n"
- warning += "Thus slit smeared data will give very wrong answers!"
- self.textwarn = wx.StaticText(self, -1, warning)
- self.textwarn.SetForegroundColour(wx.RED)
- explanation = "Perform fit for y(x) = ax + b \n"
- if self.bg_on:
- param_a = 'Background (= Parameter a)'
- else:
- param_a = 'Parameter a'
-
-
- #Now set this all up in the GridBagSizer sizer
- ix = 0
- iy = 0
- sizer.Add(self.textwarn, (iy, ix),
- (2, 3), wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- iy += 2
- sizer.Add(wx.StaticText(self, -1, explanation), (iy, ix),
- (1, 1), wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- iy += 1
- sizer.Add(wx.StaticText(self, -1, param_a), (iy, ix),
- (1, 1), wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- ix += 1
- sizer.Add(self.tcA, (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 1
- sizer.Add(wx.StaticText(self, -1, '+/-'),
- (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 1
- sizer.Add(self.tcErrA, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- iy += 1
- ix = 0
- sizer.Add(wx.StaticText(self, -1, 'Parameter b'), (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- ix += 1
- sizer.Add(self.tcB, (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 1
- sizer.Add(wx.StaticText(self, -1, '+/-'), (iy, ix),
- (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 1
- sizer.Add(self.tcErrB, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- iy += 1
- ix = 0
- sizer.Add(wx.StaticText(self, -1, 'Chi2/dof'), (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- ix += 1
- sizer.Add(self.tcChi, (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- iy += 2
- ix = 1
- sizer.Add(wx.StaticText(self, -1, 'Min'), (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 2
- sizer.Add(wx.StaticText(self, -1, 'Max'), (iy, ix),
- (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
-
- iy += 1
- ix = 0
- sizer.Add(wx.StaticText(self, -1, 'Maximum range (linear scale)'),
- (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- ix += 1
- sizer.Add(self.initXmin, (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 2
- sizer.Add(self.initXmax, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
-
- iy += 1
- ix = 0
- sizer.Add(wx.StaticText(self, -1, 'Fit range of ' + self.xLabel),
- (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- ix += 1
- sizer.Add(self.xminFit, (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 2
- sizer.Add(self.xmaxFit, (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- if self.rg_on:
- self.SetSize((PNL_WIDTH, PNL_HEIGHT))
- I0_stxt = wx.StaticText(self, -1, 'I(q=0)')
- self.I0_tctr = wx.TextCtrl(self, -1, '')
- self.I0_tctr.SetEditable(False)
- self.I0_tctr.SetBackgroundColour(_BACKGROUND_COLOR)
- self.I0err_tctr = wx.TextCtrl(self, -1, '')
- self.I0err_tctr.SetEditable(False)
- self.I0err_tctr.SetBackgroundColour(_BACKGROUND_COLOR)
- Rg_stxt = wx.StaticText(self, -1, 'Rg [A]')
- Rg_stxt.Show(self.yLabel == "ln(y)")
- self.Rg_tctr = wx.TextCtrl(self, -1, '')
- self.Rg_tctr.SetEditable(False)
- self.Rg_tctr.SetBackgroundColour(_BACKGROUND_COLOR)
- self.Rg_tctr.Show(self.yLabel == "ln(y)")
- self.Rgerr_tctr = wx.TextCtrl(self, -1, '')
- self.Rgerr_tctr.SetEditable(False)
- self.Rgerr_tctr.SetBackgroundColour(_BACKGROUND_COLOR)
- self.Rgerr_tctr.Show(self.yLabel == "ln(y)")
- self.Rgerr_pm = wx.StaticText(self, -1, '+/-')
- self.Rgerr_pm.Show(self.yLabel == "ln(y)")
- Diameter_stxt = wx.StaticText(self, -1, 'Rod Diameter [A]')
- Diameter_stxt.Show(self.yLabel == "ln(y*x)")
- self.Diameter_tctr = wx.TextCtrl(self, -1, '')
- self.Diameter_tctr.SetEditable(False)
- self.Diameter_tctr.SetBackgroundColour(_BACKGROUND_COLOR)
- self.Diameter_tctr.Show(self.yLabel == "ln(y*x)")
- self.Diameter_pm = wx.StaticText(self, -1, '+/-')
- self.Diameter_pm.Show(self.yLabel == "ln(y*x)")
- self.Diametererr_tctr = wx.TextCtrl(self, -1, '')
- self.Diametererr_tctr.SetEditable(False)
- self.Diametererr_tctr.SetBackgroundColour(_BACKGROUND_COLOR)
- self.Diametererr_tctr.Show(self.yLabel == "ln(y*x)")
- RgQmin_stxt = wx.StaticText(self, -1, 'Rg*Qmin')
- self.RgQmin_tctr = wx.TextCtrl(self, -1, '')
- self.RgQmin_tctr.SetEditable(False)
- self.RgQmin_tctr.SetBackgroundColour(_BACKGROUND_COLOR)
- RgQmax_stxt = wx.StaticText(self, -1, 'Rg*Qmax')
- self.RgQmax_tctr = wx.TextCtrl(self, -1, '')
- self.RgQmax_tctr.SetEditable(False)
- self.RgQmax_tctr.SetBackgroundColour(_BACKGROUND_COLOR)
-
- iy += 2
- ix = 0
- sizer.Add(I0_stxt, (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- ix += 1
- sizer.Add(self.I0_tctr, (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 1
- sizer.Add(wx.StaticText(self, -1, '+/-'), (iy, ix),
- (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 1
- sizer.Add(self.I0err_tctr, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
-
- iy += 1
- ix = 0
- sizer.Add(Rg_stxt, (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- ix += 1
- sizer.Add(self.Rg_tctr, (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 0)
-
- ix += 1
- sizer.Add(self.Rgerr_pm, (iy, ix),
- (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 1
- sizer.Add(self.Rgerr_tctr, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- iy += 1
- ix = 0
- sizer.Add(Diameter_stxt, (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- ix += 1
- sizer.Add(self.Diameter_tctr, (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 0)
-
- ix += 1
- sizer.Add(self.Diameter_pm, (iy, ix),
- (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- ix += 1
- sizer.Add(self.Diametererr_tctr, (iy, ix), (1, 1),
- wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- iy += 1
- ix = 0
- sizer.Add(RgQmin_stxt, (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- ix += 1
- sizer.Add(self.RgQmin_tctr, (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- iy += 1
- ix = 0
- sizer.Add(RgQmax_stxt, (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- ix += 1
- sizer.Add(self.RgQmax_tctr, (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 0)
-
- #Now add some space before the separation line
- iy += 1
- ix = 0
- sizer.Add((20,20), (iy, ix), (1, 1),
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 0)
-
- # Buttons on the bottom
- self.btFit = wx.Button(self, -1, 'Fit')
- self.btFit.Bind(wx.EVT_BUTTON, self._onFit)
- self.btFit.SetToolTipString("Perform fit.")
- self.btClose = wx.Button(self, wx.ID_CANCEL, 'Close')
- self.btClose.Bind(wx.EVT_BUTTON, self._on_close)
- sizer_button.Add((20, 20), 1, wx.EXPAND | wx.ADJUST_MINSIZE, 0)
- sizer_button.Add(self.btFit, 0,
- wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 10)
- sizer_button.Add(self.btClose, 0,
- wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 10)
-
- vbox.Add(sizer)
- self.static_line_1 = wx.StaticLine(self, -1)
- vbox.Add(self.static_line_1, 0, wx.EXPAND, 0)
- vbox.Add(sizer_button, 0, wx.EXPAND | wx.BOTTOM | wx.TOP, 10)
-
- # panel.SetSizer(sizer)
- self.SetSizer(vbox)
- self.Centre()
-
- def register_close(self, owner):
- """
- Method to register the close event to a parent
- window that needs notification when the dialog
- is closed
-
- :param owner: parent window
-
- """
- self._registered_close = owner
-
- def _on_close(self, event):
- """
- Close event.
- Notify registered owner if available.
- """
- event.Skip()
- if self._registered_close is not None:
- self._registered_close()
-
- def _onFit(self, event):
- """
- Performs the fit. Receive an event when clicking on
- the button Fit.Computes chisqr ,
- A and B parameters of the best linear fit y=Ax +B
- Push a plottable to the caller
- """
- tempx = []
- tempy = []
- tempdy = []
-
- # Check if View contains a x array .we online fit when x exits
- # makes transformation for y as a line to fit
- if self.x != []:
- if self.checkFitValues(self.xminFit) == True:
- # Check if the field of Fit Dialog contain values
- # and use the x max and min of the user
- if not self._checkVal(self.xminFit, self.xmaxFit):
- return
- xminView = float(self.xminFit.GetValue())
- xmaxView = float(self.xmaxFit.GetValue())
- xmin = xminView
- xmax = xmaxView
- # Set the qmin and qmax in the panel that matches the
- # transformed min and max
- self.initXmin.SetValue(format_number(self.floatInvTransform(xmin)))
- self.initXmax.SetValue(format_number(self.floatInvTransform(xmax)))
- # Store the transformed values of view x, y,dy
- # in variables before the fit
- if self.yLabel.lower() == "log10(y)":
- if self.xLabel.lower() == "log10(x)":
- for i in range(len(self.x)):
- if self.x[i] >= math.log10(xmin):
- tempy.append(math.log10(self.y[i]))
- tempdy.append(transform.errToLogX(self.y[i], 0, self.dy[i], 0))
- else:
- for i in range(len(self.y)):
- tempy.append(math.log10(self.y[i]))
- tempdy.append(transform.errToLogX(self.y[i], 0, self.dy[i], 0))
- else:
- tempy = self.y
- tempdy = self.dy
-
- if self.xLabel.lower() == "log10(x)":
- for x_i in self.x:
- if x_i >= math.log10(xmin):
- tempx.append(math.log10(x_i))
- else:
- tempx = self.x
-
- # Find the fitting parameters
- # Always use the same defaults, so that fit history
- # doesn't play a role!
- self.cstA = fittings.Parameter(self.model, 'A', self.default_A)
- self.cstB = fittings.Parameter(self.model, 'B', self.default_B)
-
- if self.xLabel.lower() == "log10(x)":
- tempdy = numpy.asarray(tempdy)
- tempdy[tempdy == 0] = 1
- chisqr, out, cov = fittings.sasfit(self.model,
- [self.cstA, self.cstB],
- tempx, tempy,
- tempdy,
- math.log10(xmin),
- math.log10(xmax))
- else:
- tempdy = numpy.asarray(tempdy)
- tempdy[tempdy == 0] = 1
- chisqr, out, cov = fittings.sasfit(self.model,
- [self.cstA, self.cstB],
- tempx, tempy, tempdy,
- xminView, xmaxView)
- # Use chi2/dof
- if len(tempx) > 0:
- chisqr = chisqr / len(tempx)
-
- # Check that cov and out are iterable before displaying them
- if cov == None:
- errA = 0.0
- errB = 0.0
- else:
- errA = math.sqrt(cov[0][0])
- errB = math.sqrt(cov[1][1])
- if out == None:
- cstA = 0.0
- cstB = 0.0
- else:
- cstA = out[0]
- cstB = out[1]
- # Reset model with the right values of A and B
- self.model.setParam('A', float(cstA))
- self.model.setParam('B', float(cstB))
-
- tempx = []
- tempy = []
- y_model = 0.0
- # load tempy with the minimum transformation
-
- if self.xLabel == "log10(x)":
- y_model = self.model.run(math.log10(xmin))
- tempx.append(xmin)
- else:
- y_model = self.model.run(xminView)
- tempx.append(xminView)
-
- if self.yLabel == "log10(y)":
- tempy.append(math.pow(10, y_model))
- else:
- tempy.append(y_model)
-
- # load tempy with the maximum transformation
- if self.xLabel == "log10(x)":
- y_model = self.model.run(math.log10(xmax))
- tempx.append(xmax)
- else:
- y_model = self.model.run(xmaxView)
- tempx.append(xmaxView)
-
- if self.yLabel == "log10(y)":
- tempy.append(math.pow(10, y_model))
- else:
- tempy.append(y_model)
- # Set the fit parameter display when FitDialog is opened again
- self.Avalue = cstA
- self.Bvalue = cstB
- self.ErrAvalue = errA
- self.ErrBvalue = errB
- self.Chivalue = chisqr
- self.push_data(tempx, tempy, xminView, xmaxView,
- xmin, xmax, self._ongetValues())
-
- # Display the fitting value on the Fit Dialog
- self._onsetValues(cstA, cstB, errA, errB, chisqr)
-
- def _onsetValues(self, cstA, cstB, errA, errB, Chi):
- """
- Display the value on fit Dialog
- """
- rg = None
- _diam = None
- self.tcA.SetValue(format_number(cstA))
- self.tcB.SetValue(format_number(cstB))
- self.tcErrA.SetValue(format_number(errA))
- self.tcErrB.SetValue(format_number(errB))
- self.tcChi.SetValue(format_number(Chi))
- if self.rg_on:
- if self.Rg_tctr.IsShown():
- rg = numpy.sqrt(-3 * float(cstA))
- value = format_number(rg)
- self.Rg_tctr.SetValue(value)
- if self.I0_tctr.IsShown():
- val = numpy.exp(cstB)
- self.I0_tctr.SetValue(format_number(val))
- if self.Rgerr_tctr.IsShown():
- if rg != None and rg != 0:
- value = format_number(3 * float(errA) / (2 * rg))
- else:
- value = ''
- self.Rgerr_tctr.SetValue(value)
- if self.I0err_tctr.IsShown():
- val = numpy.abs(numpy.exp(cstB) * errB)
- self.I0err_tctr.SetValue(format_number(val))
- if self.Diameter_tctr.IsShown():
- rg = numpy.sqrt(-2 * float(cstA))
- _diam = 4 * numpy.sqrt(-float(cstA))
- value = format_number(_diam)
- self.Diameter_tctr.SetValue(value)
- if self.Diametererr_tctr.IsShown():
- if rg != None and rg != 0:
- value = format_number(8 * float(errA) / _diam)
- else:
- value = ''
- self.Diametererr_tctr.SetValue(value)
- if self.RgQmin_tctr.IsShown():
- value = format_number(rg * self.floatInvTransform(self.mini))
- self.RgQmin_tctr.SetValue(value)
- if self.RgQmax_tctr.IsShown():
- value = format_number(rg * self.floatInvTransform(self.maxi))
- self.RgQmax_tctr.SetValue(value)
-
- def _ongetValues(self):
- """
- Display the value on fit Dialog
- """
- return self.Avalue, self.Bvalue, self.ErrAvalue, \
- self.ErrBvalue, self.Chivalue
-
- def _checkVal(self, usermin, usermax):
- """
- Ensure that fields parameter contains a min and a max value
- within x min and x max range
- """
- self.mini = float(self.xminFit.GetValue())
- self.maxi = float(self.xmaxFit.GetValue())
- flag = True
- try:
- mini = float(usermin.GetValue())
- maxi = float(usermax.GetValue())
- if mini < maxi:
- usermin.SetBackgroundColour(wx.WHITE)
- usermin.Refresh()
- else:
- flag = False
- usermin.SetBackgroundColour("pink")
- usermin.Refresh()
- except:
- # Check for possible values entered
- flag = False
- usermin.SetBackgroundColour("pink")
- usermin.Refresh()
-
- return flag
-
- def floatForwardTransform(self, x):
- """
- transform a float.
- """
- # TODO: refactor this with proper object-oriented design
- # This code stinks.
- if self.xLabel == "x":
- return transform.toX(x)
- if self.xLabel == "x^(2)":
- return transform.toX2(x)
- if self.xLabel == "ln(x)":
- return transform.toLogX(x)
- if self.xLabel == "log10(x)":
- return math.log10(x)
-
- def floatTransform(self, x):
- """
- transform a float.It is use to determine the x.
- View min and x.View max for values
- not in x
- """
- # TODO: refactor this with proper object-oriented design
- # This code stinks.
- if self.xLabel == "x":
- return transform.toX(x)
- if self.xLabel == "x^(2)":
- return transform.toX2(x)
- if self.xLabel == "ln(x)":
- return transform.toLogX(x)
- if self.xLabel == "log10(x)":
- if x > 0:
- return x
- else:
- raise ValueError, "cannot compute log of a negative number"
-
- def floatInvTransform(self, x):
- """
- transform a float.It is used to determine the x.View min and x.View
- max for values not in x. Also used to properly calculate RgQmin,
- RgQmax and to update qmin and qmax in the linear range boxes on the
- panel.
-
- """
- # TODO: refactor this. This is just a hack to make the
- # functionality work without rewritting the whole code
- # with good design (which really should be done...).
- if self.xLabel == "x":
- return x
- elif self.xLabel == "x^(2)":
- return math.sqrt(x)
- elif self.xLabel == "x^(4)":
- return math.sqrt(math.sqrt(x))
- elif self.xLabel == "log10(x)":
- return math.pow(10, x)
- elif self.xLabel == "ln(x)":
- return math.exp(x)
- elif self.xLabel == "log10(x^(4))":
- return math.sqrt(math.sqrt(math.pow(10, x)))
- return x
-
- def checkFitValues(self, item):
- """
- Check the validity of input values
- """
- flag = True
- value = item.GetValue()
- # Check for possible values entered
- if self.xLabel == "log10(x)":
- if float(value) > 0:
- item.SetBackgroundColour(wx.WHITE)
- item.Refresh()
- else:
- flag = False
- item.SetBackgroundColour("pink")
- item.Refresh()
- return flag
-
- def setFitRange(self, xmin, xmax, xminTrans, xmaxTrans):
- """
- Set fit parameters
- """
- self.xminFit.SetValue(format_number(xmin))
- self.xmaxFit.SetValue(format_number(xmax))
-
- def set_fit_region(self, xmin, xmax):
- """
- Set the fit region
- :param xmin: minimum x-value to be included in fit
- :param xmax: maximum x-value to be included in fit
- """
- # Check values
- try:
- float(xmin)
- float(xmax)
- except:
- msg = "LinearFit.set_fit_region: fit range must be floats"
- raise ValueError, msg
- self.xminFit.SetValue(format_number(xmin))
- self.xmaxFit.SetValue(format_number(xmax))
-
-
-class MyApp(wx.App):
- """
- Test application
- """
- def OnInit(self):
- """
- Test application initialization
- """
- wx.InitAllImageHandlers()
- plot = Theory1D([], [])
- dialog = LinearFit(parent=None, plottable=plot,
- push_data=self.onFitDisplay,
- transform=self.returnTrans,
- title='Linear Fit')
- if dialog.ShowModal() == wx.ID_OK:
- pass
- dialog.Destroy()
- return 1
-
- def onFitDisplay(self, tempx, tempy, xminView, xmaxView, xmin, xmax, func):
- """
- Test application dummy method
- """
- pass
-
- def returnTrans(self):
- """
- Test application dummy method
- """
- return '', '', 0, 0, 0, 0, 0
+import wx
+from plottables import Theory1D
+import math
+import numpy as np
+import fittings
+import transform
+import sys
+
+# Linear fit panel size
+if sys.platform.count("win32") > 0:
+ FONT_VARIANT = 0
+ PNL_WIDTH = 450
+ PNL_HEIGHT = 500
+else:
+ FONT_VARIANT = 1
+ PNL_WIDTH = 500
+ PNL_HEIGHT = 500
+RG_ON = True
+
+def format_number(value, high=False):
+ """
+ Return a float in a standardized, human-readable formatted string.
+ This is used to output readable (e.g. x.xxxe-y) values to the panel.
+ """
+ try:
+ value = float(value)
+ except:
+ output = "NaN"
+ return output.lstrip().rstrip()
+
+ if high:
+ output = "%-6.4g" % value
+
+ else:
+ output = "%-5.3g" % value
+ return output.lstrip().rstrip()
+
+
+class LinearFit(wx.Dialog):
+ def __init__(self, parent, plottable, push_data, transform, title):
+ """
+ Dialog window pops- up when select Linear fit on Context menu
+ Displays fitting parameters. This class handles the linearized
+ fitting and derives and displays specialized output parameters based
+ on the scale choice of the plot calling it.
+
+ :note1: The fitting is currently a bit convoluted as besides using
+ plottools.transform.py to handle all the conversions, it uses
+ LineModel to define a linear model and calculate a number of
+ things like residuals etc as well as the function itself given an x
+ value. It also uses fittings.py to set up the defined LineModel for
+ fitting and then send it to the SciPy NLLSQ method. As these are by
+ definition "linear nodels" it would make more sense to just call
+ a linear solver such as scipy.stats.linregress or bumps.wsolve directly.
+ This would considerably simplify the code and remove the need I think
+ for LineModel.py and possibly fittins.py altogether. -PDB 7/10/16
+
+ :note2: The linearized fits do not take resolution into account. This
+ means that for poor resolution such as slit smearing the answers will
+ be completely wrong --- Rg would be OK but I0 would be orders of
+ magnitude off. Eventually we should fix this to account properly for
+ resolution. -PDB 7/10/16
+ """
+ wx.Dialog.__init__(self, parent, title=title,
+ size=(PNL_WIDTH, 350))
+ self.parent = parent
+ self.transform = transform
+ # Font
+ self.SetWindowVariant(variant=FONT_VARIANT)
+ # Registered owner for close event
+ self._registered_close = None
+ # dialog panel self call function to plot the fitting function
+ # calls the calling PlotPanel method onFitDisplay
+ self.push_data = push_data
+ # dialog self plottable - basically the plot we are working with
+ # passed in by the caller
+ self.plottable = plottable
+ # is this a Guinier fit
+ self.rg_on = False
+ # Receive transformations of x and y - basically transform is passed
+ # as caller method that returns its current value for these
+ self.xLabel, self.yLabel, self.Avalue, self.Bvalue, \
+ self.ErrAvalue, self.ErrBvalue, self.Chivalue = self.transform()
+
+ # Now set up the dialog interface
+ self.layout()
+ # Receives the type of model for the fitting
+ from LineModel import LineModel
+ self.model = LineModel()
+ # Display the fittings values
+ self.default_A = self.model.getParam('A')
+ self.default_B = self.model.getParam('B')
+ self.cstA = fittings.Parameter(self.model, 'A', self.default_A)
+ self.cstB = fittings.Parameter(self.model, 'B', self.default_B)
+
+ # Set default value of parameter in the dialog panel
+ if self.Avalue is None:
+ self.tcA.SetValue(format_number(self.default_A))
+ else:
+ self.tcA.SetLabel(format_number(self.Avalue))
+ if self.Bvalue is None:
+ self.tcB.SetValue(format_number(self.default_B))
+ else:
+ self.tcB.SetLabel(format_number(self.Bvalue))
+ if self.ErrAvalue is None:
+ self.tcErrA.SetLabel(format_number(0.0))
+ else:
+ self.tcErrA.SetLabel(format_number(self.ErrAvalue))
+ if self.ErrBvalue is None:
+ self.tcErrB.SetLabel(format_number(0.0))
+ else:
+ self.tcErrB.SetLabel(format_number(self.ErrBvalue))
+ if self.Chivalue is None:
+ self.tcChi.SetLabel(format_number(0.0))
+ else:
+ self.tcChi.SetLabel(format_number(self.Chivalue))
+ if self.plottable.x != []:
+ # store the values of View in self.x,self.y,self.dx,self.dy
+ self.x, self.y, self.dx, \
+ self.dy = self.plottable.returnValuesOfView()
+ try:
+ self.mini = self.floatForwardTransform(min(self.x))
+ except:
+ self.mini = "Invalid"
+ try:
+ self.maxi = self.floatForwardTransform(max(self.x))
+ except:
+ self.maxi = "Invalid"
+
+ self.initXmin.SetValue(format_number(min(self.plottable.x)))
+ self.initXmax.SetValue(format_number(max(self.plottable.x)))
+ self.mini = min(self.x)
+ self.maxi = max(self.x)
+ self.xminFit.SetValue(format_number(self.mini))
+ self.xmaxFit.SetValue(format_number(self.maxi))
+
+ def layout(self):
+ """
+ Sets up the panel layout for the linear fit including all the
+ labels, text entry boxes, and buttons.
+
+ """
+
+ # set up sizers first.
+ # vbox is the panel sizer and is a vertical sizer
+ # The first element of the panel is sizer which is a gridbagsizer
+ # and contains most of the text fields
+ # this is followed by a line separator added to vbox
+ # and finally the sizer_button (a horizontal sizer) adds the buttons
+ vbox = wx.BoxSizer(wx.VERTICAL)
+ sizer = wx.GridBagSizer(5, 5)
+ sizer_button = wx.BoxSizer(wx.HORIZONTAL)
+
+ #size of string boxes in pixels
+ _BOX_WIDTH = 100
+ _BOX_HEIGHT = 20
+ #now set up all the text fields
+ self.tcA = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, _BOX_HEIGHT))
+ self.tcA.SetToolTipString("Fit value for the slope parameter.")
+ self.tcErrA = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, _BOX_HEIGHT))
+ self.tcErrA.SetToolTipString("Error on the slope parameter.")
+ self.tcB = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, _BOX_HEIGHT))
+ self.tcA.SetToolTipString("Fit value for the constant parameter.")
+ self.tcErrB = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, _BOX_HEIGHT))
+ self.tcErrB.SetToolTipString("Error on the constant parameter.")
+ self.tcChi = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, _BOX_HEIGHT))
+ self.tcChi.SetToolTipString("Chi^2 over degrees of freedom.")
+ self.xminFit = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, _BOX_HEIGHT))
+ msg = "Enter the minimum value on "
+ msg += "the x-axis to be included in the fit."
+ self.xminFit.SetToolTipString(msg)
+ self.xmaxFit = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, _BOX_HEIGHT))
+ msg = "Enter the maximum value on "
+ msg += " the x-axis to be included in the fit."
+ self.xmaxFit.SetToolTipString(msg)
+ self.initXmin = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, _BOX_HEIGHT))
+ msg = "Minimum value on the x-axis for the plotted data."
+ self.initXmin.SetToolTipString(msg)
+ self.initXmax = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, _BOX_HEIGHT))
+ msg = "Maximum value on the x-axis for the plotted data."
+ self.initXmax.SetToolTipString(msg)
+
+ # Make the info box not editable
+ # _BACKGROUND_COLOR = '#ffdf85'
+ _BACKGROUND_COLOR = self.GetBackgroundColour()
+ self.initXmin.SetEditable(False)
+ self.initXmin.SetBackgroundColour(_BACKGROUND_COLOR)
+ self.initXmax.SetEditable(False)
+ self.initXmax.SetBackgroundColour(_BACKGROUND_COLOR)
+
+ #set some flags for specific types of fits like Guinier (Rg) and
+ #Porod (bg) -- this will determine WHAT boxes show up in the
+ #sizer layout and depends on the active axis transform
+ self.bg_on = False
+ if RG_ON:
+ if (self.yLabel == "ln(y)" or self.yLabel == "ln(y*x)") and \
+ (self.xLabel == "x^(2)"):
+ self.rg_on = True
+ if (self.xLabel == "x^(4)") and (self.yLabel == "y*x^(4)"):
+ self.bg_on = True
+
+ # Finally set up static text strings
+ warning = "WARNING! Resolution is NOT accounted for. \n"
+ warning += "Thus slit smeared data will give very wrong answers!"
+ self.textwarn = wx.StaticText(self, -1, warning)
+ self.textwarn.SetForegroundColour(wx.RED)
+ explanation = "Perform fit for y(x) = ax + b \n"
+ if self.bg_on:
+ param_a = 'Background (= Parameter a)'
+ else:
+ param_a = 'Parameter a'
+
+
+ #Now set this all up in the GridBagSizer sizer
+ ix = 0
+ iy = 0
+ sizer.Add(self.textwarn, (iy, ix),
+ (2, 3), wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ iy += 2
+ sizer.Add(wx.StaticText(self, -1, explanation), (iy, ix),
+ (1, 1), wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ iy += 1
+ sizer.Add(wx.StaticText(self, -1, param_a), (iy, ix),
+ (1, 1), wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ ix += 1
+ sizer.Add(self.tcA, (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix += 1
+ sizer.Add(wx.StaticText(self, -1, '+/-'),
+ (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix += 1
+ sizer.Add(self.tcErrA, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ iy += 1
+ ix = 0
+ sizer.Add(wx.StaticText(self, -1, 'Parameter b'), (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ ix += 1
+ sizer.Add(self.tcB, (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix += 1
+ sizer.Add(wx.StaticText(self, -1, '+/-'), (iy, ix),
+ (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix += 1
+ sizer.Add(self.tcErrB, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ iy += 1
+ ix = 0
+ sizer.Add(wx.StaticText(self, -1, 'Chi2/dof'), (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ ix += 1
+ sizer.Add(self.tcChi, (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ iy += 2
+ ix = 1
+ sizer.Add(wx.StaticText(self, -1, 'Min'), (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix += 2
+ sizer.Add(wx.StaticText(self, -1, 'Max'), (iy, ix),
+ (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+
+ iy += 1
+ ix = 0
+ sizer.Add(wx.StaticText(self, -1, 'Maximum range (linear scale)'),
+ (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ ix += 1
+ sizer.Add(self.initXmin, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix += 2
+ sizer.Add(self.initXmax, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+
+ iy += 1
+ ix = 0
+ sizer.Add(wx.StaticText(self, -1, 'Fit range of ' + self.xLabel),
+ (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ ix += 1
+ sizer.Add(self.xminFit, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix += 2
+ sizer.Add(self.xmaxFit, (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ if self.rg_on:
+ self.SetSize((PNL_WIDTH, PNL_HEIGHT))
+ I0_stxt = wx.StaticText(self, -1, 'I(q=0)')
+ self.I0_tctr = wx.TextCtrl(self, -1, '')
+ self.I0_tctr.SetEditable(False)
+ self.I0_tctr.SetBackgroundColour(_BACKGROUND_COLOR)
+ self.I0err_tctr = wx.TextCtrl(self, -1, '')
+ self.I0err_tctr.SetEditable(False)
+ self.I0err_tctr.SetBackgroundColour(_BACKGROUND_COLOR)
+ Rg_stxt = wx.StaticText(self, -1, 'Rg [A]')
+ Rg_stxt.Show(self.yLabel == "ln(y)")
+ self.Rg_tctr = wx.TextCtrl(self, -1, '')
+ self.Rg_tctr.SetEditable(False)
+ self.Rg_tctr.SetBackgroundColour(_BACKGROUND_COLOR)
+ self.Rg_tctr.Show(self.yLabel == "ln(y)")
+ self.Rgerr_tctr = wx.TextCtrl(self, -1, '')
+ self.Rgerr_tctr.SetEditable(False)
+ self.Rgerr_tctr.SetBackgroundColour(_BACKGROUND_COLOR)
+ self.Rgerr_tctr.Show(self.yLabel == "ln(y)")
+ self.Rgerr_pm = wx.StaticText(self, -1, '+/-')
+ self.Rgerr_pm.Show(self.yLabel == "ln(y)")
+ Diameter_stxt = wx.StaticText(self, -1, 'Rod Diameter [A]')
+ Diameter_stxt.Show(self.yLabel == "ln(y*x)")
+ self.Diameter_tctr = wx.TextCtrl(self, -1, '')
+ self.Diameter_tctr.SetEditable(False)
+ self.Diameter_tctr.SetBackgroundColour(_BACKGROUND_COLOR)
+ self.Diameter_tctr.Show(self.yLabel == "ln(y*x)")
+ self.Diameter_pm = wx.StaticText(self, -1, '+/-')
+ self.Diameter_pm.Show(self.yLabel == "ln(y*x)")
+ self.Diametererr_tctr = wx.TextCtrl(self, -1, '')
+ self.Diametererr_tctr.SetEditable(False)
+ self.Diametererr_tctr.SetBackgroundColour(_BACKGROUND_COLOR)
+ self.Diametererr_tctr.Show(self.yLabel == "ln(y*x)")
+ RgQmin_stxt = wx.StaticText(self, -1, 'Rg*Qmin')
+ self.RgQmin_tctr = wx.TextCtrl(self, -1, '')
+ self.RgQmin_tctr.SetEditable(False)
+ self.RgQmin_tctr.SetBackgroundColour(_BACKGROUND_COLOR)
+ RgQmax_stxt = wx.StaticText(self, -1, 'Rg*Qmax')
+ self.RgQmax_tctr = wx.TextCtrl(self, -1, '')
+ self.RgQmax_tctr.SetEditable(False)
+ self.RgQmax_tctr.SetBackgroundColour(_BACKGROUND_COLOR)
+
+ iy += 2
+ ix = 0
+ sizer.Add(I0_stxt, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ ix += 1
+ sizer.Add(self.I0_tctr, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix += 1
+ sizer.Add(wx.StaticText(self, -1, '+/-'), (iy, ix),
+ (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix += 1
+ sizer.Add(self.I0err_tctr, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+
+ iy += 1
+ ix = 0
+ sizer.Add(Rg_stxt, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ ix += 1
+ sizer.Add(self.Rg_tctr, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+
+ ix += 1
+ sizer.Add(self.Rgerr_pm, (iy, ix),
+ (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix += 1
+ sizer.Add(self.Rgerr_tctr, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ iy += 1
+ ix = 0
+ sizer.Add(Diameter_stxt, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ ix += 1
+ sizer.Add(self.Diameter_tctr, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+
+ ix += 1
+ sizer.Add(self.Diameter_pm, (iy, ix),
+ (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ ix += 1
+ sizer.Add(self.Diametererr_tctr, (iy, ix), (1, 1),
+ wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ iy += 1
+ ix = 0
+ sizer.Add(RgQmin_stxt, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ ix += 1
+ sizer.Add(self.RgQmin_tctr, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ iy += 1
+ ix = 0
+ sizer.Add(RgQmax_stxt, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ ix += 1
+ sizer.Add(self.RgQmax_tctr, (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+
+ #Now add some space before the separation line
+ iy += 1
+ ix = 0
+ sizer.Add((20,20), (iy, ix), (1, 1),
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+
+ # Buttons on the bottom
+ self.btFit = wx.Button(self, -1, 'Fit')
+ self.btFit.Bind(wx.EVT_BUTTON, self._onFit)
+ self.btFit.SetToolTipString("Perform fit.")
+ self.btClose = wx.Button(self, wx.ID_CANCEL, 'Close')
+ self.btClose.Bind(wx.EVT_BUTTON, self._on_close)
+ sizer_button.Add((20, 20), 1, wx.EXPAND | wx.ADJUST_MINSIZE, 0)
+ sizer_button.Add(self.btFit, 0,
+ wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 10)
+ sizer_button.Add(self.btClose, 0,
+ wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 10)
+
+ vbox.Add(sizer)
+ self.static_line_1 = wx.StaticLine(self, -1)
+ vbox.Add(self.static_line_1, 0, wx.EXPAND, 0)
+ vbox.Add(sizer_button, 0, wx.EXPAND | wx.BOTTOM | wx.TOP, 10)
+
+ # panel.SetSizer(sizer)
+ self.SetSizer(vbox)
+ self.Centre()
+
+ def register_close(self, owner):
+ """
+ Method to register the close event to a parent
+ window that needs notification when the dialog
+ is closed
+
+ :param owner: parent window
+
+ """
+ self._registered_close = owner
+
+ def _on_close(self, event):
+ """
+ Close event.
+ Notify registered owner if available.
+ """
+ event.Skip()
+ if self._registered_close is not None:
+ self._registered_close()
+
+ def _onFit(self, event):
+ """
+ Performs the fit. Receive an event when clicking on
+ the button Fit.Computes chisqr ,
+ A and B parameters of the best linear fit y=Ax +B
+ Push a plottable to the caller
+ """
+ tempx = []
+ tempy = []
+ tempdy = []
+
+ # Check if View contains a x array .we online fit when x exits
+ # makes transformation for y as a line to fit
+ if self.x != []:
+ if self.checkFitValues(self.xminFit) == True:
+ # Check if the field of Fit Dialog contain values
+ # and use the x max and min of the user
+ if not self._checkVal(self.xminFit, self.xmaxFit):
+ return
+ xminView = float(self.xminFit.GetValue())
+ xmaxView = float(self.xmaxFit.GetValue())
+ xmin = xminView
+ xmax = xmaxView
+ # Set the qmin and qmax in the panel that matches the
+ # transformed min and max
+ self.initXmin.SetValue(format_number(self.floatInvTransform(xmin)))
+ self.initXmax.SetValue(format_number(self.floatInvTransform(xmax)))
+ # Store the transformed values of view x, y,dy
+ # in variables before the fit
+ if self.yLabel.lower() == "log10(y)":
+ if self.xLabel.lower() == "log10(x)":
+ for i in range(len(self.x)):
+ if self.x[i] >= math.log10(xmin):
+ tempy.append(math.log10(self.y[i]))
+ tempdy.append(transform.errToLogX(self.y[i], 0, self.dy[i], 0))
+ else:
+ for i in range(len(self.y)):
+ tempy.append(math.log10(self.y[i]))
+ tempdy.append(transform.errToLogX(self.y[i], 0, self.dy[i], 0))
+ else:
+ tempy = self.y
+ tempdy = self.dy
+
+ if self.xLabel.lower() == "log10(x)":
+ for x_i in self.x:
+ if x_i >= math.log10(xmin):
+ tempx.append(math.log10(x_i))
+ else:
+ tempx = self.x
+
+ # Find the fitting parameters
+ # Always use the same defaults, so that fit history
+ # doesn't play a role!
+ self.cstA = fittings.Parameter(self.model, 'A', self.default_A)
+ self.cstB = fittings.Parameter(self.model, 'B', self.default_B)
+
+ if self.xLabel.lower() == "log10(x)":
+ tempdy = np.asarray(tempdy)
+ tempdy[tempdy == 0] = 1
+ chisqr, out, cov = fittings.sasfit(self.model,
+ [self.cstA, self.cstB],
+ tempx, tempy,
+ tempdy,
+ math.log10(xmin),
+ math.log10(xmax))
+ else:
+ tempdy = np.asarray(tempdy)
+ tempdy[tempdy == 0] = 1
+ chisqr, out, cov = fittings.sasfit(self.model,
+ [self.cstA, self.cstB],
+ tempx, tempy, tempdy,
+ xminView, xmaxView)
+ # Use chi2/dof
+ if len(tempx) > 0:
+ chisqr = chisqr / len(tempx)
+
+ # Check that cov and out are iterable before displaying them
+ if cov is None:
+ errA = 0.0
+ errB = 0.0
+ else:
+ errA = math.sqrt(cov[0][0])
+ errB = math.sqrt(cov[1][1])
+ if out is None:
+ cstA = 0.0
+ cstB = 0.0
+ else:
+ cstA = out[0]
+ cstB = out[1]
+ # Reset model with the right values of A and B
+ self.model.setParam('A', float(cstA))
+ self.model.setParam('B', float(cstB))
+
+ tempx = []
+ tempy = []
+ y_model = 0.0
+ # load tempy with the minimum transformation
+
+ if self.xLabel == "log10(x)":
+ y_model = self.model.run(math.log10(xmin))
+ tempx.append(xmin)
+ else:
+ y_model = self.model.run(xminView)
+ tempx.append(xminView)
+
+ if self.yLabel == "log10(y)":
+ tempy.append(math.pow(10, y_model))
+ else:
+ tempy.append(y_model)
+
+ # load tempy with the maximum transformation
+ if self.xLabel == "log10(x)":
+ y_model = self.model.run(math.log10(xmax))
+ tempx.append(xmax)
+ else:
+ y_model = self.model.run(xmaxView)
+ tempx.append(xmaxView)
+
+ if self.yLabel == "log10(y)":
+ tempy.append(math.pow(10, y_model))
+ else:
+ tempy.append(y_model)
+ # Set the fit parameter display when FitDialog is opened again
+ self.Avalue = cstA
+ self.Bvalue = cstB
+ self.ErrAvalue = errA
+ self.ErrBvalue = errB
+ self.Chivalue = chisqr
+ self.push_data(tempx, tempy, xminView, xmaxView,
+ xmin, xmax, self._ongetValues())
+
+ # Display the fitting value on the Fit Dialog
+ self._onsetValues(cstA, cstB, errA, errB, chisqr)
+
+ def _onsetValues(self, cstA, cstB, errA, errB, Chi):
+ """
+ Display the value on fit Dialog
+ """
+ rg = None
+ _diam = None
+ self.tcA.SetValue(format_number(cstA))
+ self.tcB.SetValue(format_number(cstB))
+ self.tcErrA.SetValue(format_number(errA))
+ self.tcErrB.SetValue(format_number(errB))
+ self.tcChi.SetValue(format_number(Chi))
+ if self.rg_on:
+ if self.Rg_tctr.IsShown():
+ rg = np.sqrt(-3 * float(cstA))
+ value = format_number(rg)
+ self.Rg_tctr.SetValue(value)
+ if self.I0_tctr.IsShown():
+ val = np.exp(cstB)
+ self.I0_tctr.SetValue(format_number(val))
+ if self.Rgerr_tctr.IsShown():
+ if rg is not None and rg != 0:
+ value = format_number(3 * float(errA) / (2 * rg))
+ else:
+ value = ''
+ self.Rgerr_tctr.SetValue(value)
+ if self.I0err_tctr.IsShown():
+ val = np.abs(np.exp(cstB) * errB)
+ self.I0err_tctr.SetValue(format_number(val))
+ if self.Diameter_tctr.IsShown():
+ rg = np.sqrt(-2 * float(cstA))
+ _diam = 4 * np.sqrt(-float(cstA))
+ value = format_number(_diam)
+ self.Diameter_tctr.SetValue(value)
+ if self.Diametererr_tctr.IsShown():
+ if rg is not None and rg != 0:
+ value = format_number(8 * float(errA) / _diam)
+ else:
+ value = ''
+ self.Diametererr_tctr.SetValue(value)
+ if self.RgQmin_tctr.IsShown():
+ value = format_number(rg * self.floatInvTransform(self.mini))
+ self.RgQmin_tctr.SetValue(value)
+ if self.RgQmax_tctr.IsShown():
+ value = format_number(rg * self.floatInvTransform(self.maxi))
+ self.RgQmax_tctr.SetValue(value)
+
+ def _ongetValues(self):
+ """
+ Display the value on fit Dialog
+ """
+ return self.Avalue, self.Bvalue, self.ErrAvalue, \
+ self.ErrBvalue, self.Chivalue
+
+ def _checkVal(self, usermin, usermax):
+ """
+ Ensure that fields parameter contains a min and a max value
+ within x min and x max range
+ """
+ self.mini = float(self.xminFit.GetValue())
+ self.maxi = float(self.xmaxFit.GetValue())
+ flag = True
+ try:
+ mini = float(usermin.GetValue())
+ maxi = float(usermax.GetValue())
+ if mini < maxi:
+ usermin.SetBackgroundColour(wx.WHITE)
+ usermin.Refresh()
+ else:
+ flag = False
+ usermin.SetBackgroundColour("pink")
+ usermin.Refresh()
+ except:
+ # Check for possible values entered
+ flag = False
+ usermin.SetBackgroundColour("pink")
+ usermin.Refresh()
+
+ return flag
+
+ def floatForwardTransform(self, x):
+ """
+ transform a float.
+ """
+ # TODO: refactor this with proper object-oriented design
+ # This code stinks.
+ if self.xLabel == "x":
+ return transform.toX(x)
+ if self.xLabel == "x^(2)":
+ return transform.toX2(x)
+ if self.xLabel == "ln(x)":
+ return transform.toLogX(x)
+ if self.xLabel == "log10(x)":
+ return math.log10(x)
+
+ def floatTransform(self, x):
+ """
+ transform a float.It is use to determine the x.
+ View min and x.View max for values
+ not in x
+ """
+ # TODO: refactor this with proper object-oriented design
+ # This code stinks.
+ if self.xLabel == "x":
+ return transform.toX(x)
+ if self.xLabel == "x^(2)":
+ return transform.toX2(x)
+ if self.xLabel == "ln(x)":
+ return transform.toLogX(x)
+ if self.xLabel == "log10(x)":
+ if x > 0:
+ return x
+ else:
+ raise ValueError, "cannot compute log of a negative number"
+
+ def floatInvTransform(self, x):
+ """
+ transform a float.It is used to determine the x.View min and x.View
+ max for values not in x. Also used to properly calculate RgQmin,
+ RgQmax and to update qmin and qmax in the linear range boxes on the
+ panel.
+
+ """
+ # TODO: refactor this. This is just a hack to make the
+ # functionality work without rewritting the whole code
+ # with good design (which really should be done...).
+ if self.xLabel == "x":
+ return x
+ elif self.xLabel == "x^(2)":
+ return math.sqrt(x)
+ elif self.xLabel == "x^(4)":
+ return math.sqrt(math.sqrt(x))
+ elif self.xLabel == "log10(x)":
+ return math.pow(10, x)
+ elif self.xLabel == "ln(x)":
+ return math.exp(x)
+ elif self.xLabel == "log10(x^(4))":
+ return math.sqrt(math.sqrt(math.pow(10, x)))
+ return x
+
+ def checkFitValues(self, item):
+ """
+ Check the validity of input values
+ """
+ flag = True
+ value = item.GetValue()
+ # Check for possible values entered
+ if self.xLabel == "log10(x)":
+ if float(value) > 0:
+ item.SetBackgroundColour(wx.WHITE)
+ item.Refresh()
+ else:
+ flag = False
+ item.SetBackgroundColour("pink")
+ item.Refresh()
+ return flag
+
+ def setFitRange(self, xmin, xmax, xminTrans, xmaxTrans):
+ """
+ Set fit parameters
+ """
+ self.xminFit.SetValue(format_number(xmin))
+ self.xmaxFit.SetValue(format_number(xmax))
+
+ def set_fit_region(self, xmin, xmax):
+ """
+ Set the fit region
+ :param xmin: minimum x-value to be included in fit
+ :param xmax: maximum x-value to be included in fit
+ """
+ # Check values
+ try:
+ float(xmin)
+ float(xmax)
+ except:
+ msg = "LinearFit.set_fit_region: fit range must be floats"
+ raise ValueError, msg
+ self.xminFit.SetValue(format_number(xmin))
+ self.xmaxFit.SetValue(format_number(xmax))
+
+
+class MyApp(wx.App):
+ """
+ Test application
+ """
+ def OnInit(self):
+ """
+ Test application initialization
+ """
+ wx.InitAllImageHandlers()
+ plot = Theory1D([], [])
+ dialog = LinearFit(parent=None, plottable=plot,
+ push_data=self.onFitDisplay,
+ transform=self.returnTrans,
+ title='Linear Fit')
+ if dialog.ShowModal() == wx.ID_OK:
+ pass
+ dialog.Destroy()
+ return 1
+
+ def onFitDisplay(self, tempx, tempy, xminView, xmaxView, xmin, xmax, func):
+ """
+ Test application dummy method
+ """
+ pass
+
+ def returnTrans(self):
+ """
+ Test application dummy method
+ """
+ return '', '', 0, 0, 0, 0, 0
diff --git a/src/sas/sasgui/plottools/fittings.py b/src/sas/sasgui/plottools/fittings.py
index 2ccc404..79d1225 100644
--- a/src/sas/sasgui/plottools/fittings.py
+++ b/src/sas/sasgui/plottools/fittings.py
@@ -1,109 +1,111 @@
-"""
-This module is used to fit a set of x,y data to a model passed to it. It is
-used to calculate the slope and intercepts for the linearized fits. Two things
-should be noted:
-
-First, this fitting module uses the NLLSQ module of SciPy rather than a linear
-fit. This along with a few other modules could probably be removed if we
-move to a linear regression approach.
-
-Second, this infrastructure does not allow for resolution smearing of the
-the models. Hence the results are not that accurate even for pinhole
-collimation of SANS but may be good for SAXS. It is completely wrong for
-slit smeared data.
-
-"""
-from scipy import optimize
-
-
-class Parameter(object):
- """
- Class to handle model parameters - sets the parameters and their
- initial value from the model based to it.
- """
- def __init__(self, model, name, value=None):
- self.model = model
- self.name = name
- if not value == None:
- self.model.setParam(self.name, value)
-
- def set(self, value):
- """
- Set the value of the parameter
- """
- self.model.setParam(self.name, value)
-
- def __call__(self):
- """
- Return the current value of the parameter
- """
- return self.model.getParam(self.name)
-
-
-def sasfit(model, pars, x, y, err_y, qmin=None, qmax=None):
- """
- Fit function
-
- :param model: sas model object
- :param pars: list of parameters
- :param x: vector of x data
- :param y: vector of y data
- :param err_y: vector of y errors
- """
- def f(params):
- """
- Calculates the vector of residuals for each point
- in y for a given set of input parameters.
-
- :param params: list of parameter values
- :return: vector of residuals
- """
- i = 0
- for p in pars:
- p.set(params[i])
- i += 1
-
- residuals = []
- for j in range(len(x)):
- if x[j] >= qmin and x[j] <= qmax:
- residuals.append((y[j] - model.runXY(x[j])) / err_y[j])
- return residuals
-
- def chi2(params):
- """
- Calculates chi^2
-
- :param params: list of parameter values
-
- :return: chi^2
-
- """
- sum = 0
- res = f(params)
- for item in res:
- sum += item * item
- return sum
-
- p = [param() for param in pars]
- out, cov_x, info, mesg, success = optimize.leastsq(f, p, full_output=1)
- # Calculate chi squared
- if len(pars) > 1:
- chisqr = chi2(out)
- elif len(pars) == 1:
- chisqr = chi2([out])
-
- return chisqr, out, cov_x
-
-
-def calcCommandline(event):
- # Testing implementation
- # Fit a Line model
- from LineModel import LineModel
- line = LineModel()
- cstA = Parameter(line, 'A', event.cstA)
- cstB = Parameter(line, 'B', event.cstB)
- y = line.run()
- chisqr, out, cov = sasfit(line, [cstA, cstB], event.x, y, 0)
- # print "Output parameters:", out
- print "The right answer is [70.0, 1.0]"
- print chisqr, out, cov
+"""
+This module is used to fit a set of x,y data to a model passed to it. It is
+used to calculate the slope and intercepts for the linearized fits. Two things
+should be noted:
+
+First, this fitting module uses the NLLSQ module of SciPy rather than a linear
+fit. This along with a few other modules could probably be removed if we
+move to a linear regression approach.
+
+Second, this infrastructure does not allow for resolution smearing of the
+the models. Hence the results are not that accurate even for pinhole
+collimation of SANS but may be good for SAXS. It is completely wrong for
+slit smeared data.
+
+"""
+from __future__ import print_function
+
+from scipy import optimize
+
+
+class Parameter(object):
+ """
+ Class to handle model parameters - sets the parameters and their
+ initial value from the model based to it.
+ """
+ def __init__(self, model, name, value=None):
+ self.model = model
+ self.name = name
+ if value is not None:
+ self.model.setParam(self.name, value)
+
+ def set(self, value):
+ """
+ Set the value of the parameter
+ """
+ self.model.setParam(self.name, value)
+
+ def __call__(self):
+ """
+ Return the current value of the parameter
+ """
+ return self.model.getParam(self.name)
+
+
+def sasfit(model, pars, x, y, err_y, qmin=None, qmax=None):
+ """
+ Fit function
+
+ :param model: sas model object
+ :param pars: list of parameters
+ :param x: vector of x data
+ :param y: vector of y data
+ :param err_y: vector of y errors
+ """
+ def f(params):
+ """
+ Calculates the vector of residuals for each point
+ in y for a given set of input parameters.
+
+ :param params: list of parameter values
+ :return: vector of residuals
+ """
+ i = 0
+ for p in pars:
+ p.set(params[i])
+ i += 1
+
+ residuals = []
+ for j in range(len(x)):
+ if x[j] >= qmin and x[j] <= qmax:
+ residuals.append((y[j] - model.runXY(x[j])) / err_y[j])
+ return residuals
+
+ def chi2(params):
+ """
+ Calculates chi^2
+
+ :param params: list of parameter values
+
+ :return: chi^2
+
+ """
+ sum = 0
+ res = f(params)
+ for item in res:
+ sum += item * item
+ return sum
+
+ p = [param() for param in pars]
+ out, cov_x, info, mesg, success = optimize.leastsq(f, p, full_output=1)
+ # Calculate chi squared
+ if len(pars) > 1:
+ chisqr = chi2(out)
+ elif len(pars) == 1:
+ chisqr = chi2([out])
+
+ return chisqr, out, cov_x
+
+
+def calcCommandline(event):
+ # Testing implementation
+ # Fit a Line model
+ from LineModel import LineModel
+ line = LineModel()
+ cstA = Parameter(line, 'A', event.cstA)
+ cstB = Parameter(line, 'B', event.cstB)
+ y = line.run()
+ chisqr, out, cov = sasfit(line, [cstA, cstB], event.x, y, 0)
+ # print "Output parameters:", out
+ print("The right answer is [70.0, 1.0]")
+ print(chisqr, out, cov)
diff --git a/src/sas/sasgui/plottools/plottable_interactor.py b/src/sas/sasgui/plottools/plottable_interactor.py
index 1f00f01..e0388a6 100644
--- a/src/sas/sasgui/plottools/plottable_interactor.py
+++ b/src/sas/sasgui/plottools/plottable_interactor.py
@@ -1,231 +1,234 @@
-"""
- This module allows more interaction with the plot
-"""
-from BaseInteractor import _BaseInteractor
-
-class PointInteractor(_BaseInteractor):
- """
- """
- def __init__(self, base, axes, color='black', zorder=3, id=''):
- """
- """
- _BaseInteractor.__init__(self, base, axes, color=color)
- self.zorder = zorder
- self.id = id
- self.color = color
- self.colorlist = ['b', 'g', 'r', 'c', 'm', 'y', 'k']
- self.symbollist = ['o', 'x', '^', 'v', '<', '>',
- '+', 's', 'd', 'D', 'h', 'H', 'p', '-', '--',
- 'vline', 'step']
- self.markersize = None
- self.marker = None
- self.marker2 = None
- self._button_down = False
- self._context_menu = False
- self._dragged = False
- self.connect_markers([self.axes])
-
- def _color(self, c):
- """Return a particular colour"""
- return self.colorlist[c % len(self.colorlist)]
-
- def _symbol(self, s):
- """Return a particular symbol"""
- return self.symbollist[s % len(self.symbollist)]
-
- def points(self, x, y, dx=None, dy=None, color=0, symbol=0, zorder=1,
- markersize=5, label=None, hide_error=False):
- """
- """
- # Draw curve
- if self._symbol(symbol) == '-' or self._symbol(symbol) == '--':
- l_width = markersize * 0.4
- return self.curve(x=x, y=y, color=color, symbol=symbol,
- label=label, width=l_width)
- # return
- if self._symbol(symbol) == 'vline':
- l_width = markersize * 0.4
- return self.vline(x=x, y=y, color=color, label=label, width=l_width)
- if self._symbol(symbol) == 'step':
- l_width = markersize * 0.4
- return self.step(x=x, y=y, color=color, label=label, width=l_width)
- if not self.marker == None:
- self.base.connect.clear([self.marker])
- self.color = self._color(color)
- if self.markersize != None:
- markersize = self.markersize
- # Convert tuple (lo,hi) to array [(x-lo),(hi-x)]
- if dx != None and type(dx) == type(()):
- dx = nx.vstack((x - dx[0], dx[1] - x)).transpose()
- if dy != None and type(dy) == type(()):
- dy = nx.vstack((y - dy[0], dy[1] - y)).transpose()
-
- if dx == None and dy == None:
- # zorder = 1
- self.marker = self.axes.plot(x, y, color=self.color,
- marker=self._symbol(symbol),
- markersize=markersize,
- linestyle='', label=label,
- zorder=zorder)[0]
- else:
-
- if hide_error:
- # zorder = 1
- self.marker = self.axes.plot(x, y, color=self.color,
- marker=self._symbol(symbol),
- markersize=markersize,
- linestyle='', label=label,
- zorder=1)[0]
- else:
- # zorder = 2
- self.marker = self.axes.errorbar(x, y, yerr=dy,
- xerr=None,
- ecolor=self.color,
- color=self.color,
- capsize=2,
- linestyle='',
- barsabove=False,
- marker=self._symbol(symbol),
- markersize=markersize,
- lolims=False, uplims=False,
- xlolims=False, xuplims=False,
- label=label,
- zorder=1)[0]
-
- self.connect_markers([self.marker])
- self.update()
-
- def curve(self, x, y, dy=None, color=0, symbol=0, zorder=10,
- label=None, width=2.0):
- """
- """
- if not self.marker == None:
- self.base.connect.clear([self.marker])
- self.color = self._color(color)
- self.marker = self.axes.plot(x, y, color=self.color, lw=width,
- marker='', linestyle=self._symbol(symbol),
- label=label, zorder=zorder)[0]
-
- self.connect_markers([self.marker])
- self.update()
-
-
- def vline(self, x, y, dy=None, color=0, symbol=0, zorder=1,
- label=None, width=2.0):
- """
- """
- if not self.marker == None:
- self.base.connect.clear([self.marker])
- self.color = self._color(color)
- if min(y) < 0:
- y_min = 0.0
- else:
- y_min = min(y) * 9 / 10
- self.marker = self.axes.vlines(x=x, ymin=y_min, ymax=y,
- color=self.color,
- linestyle='-', label=label,
- lw=width, zorder=zorder)
- self.connect_markers([self.marker])
- self.update()
-
- def step(self, x, y, dy=None, color=0, symbol=0, zorder=1,
- label=None, width=2.0):
- """
- """
- if not self.marker == None:
- self.base.connect.clear([self.marker])
- self.color = self._color(color)
- self.marker = self.axes.step(x, y, color=self.color,
- marker='',
- linestyle='-', label=label,
- lw=width, zorder=zorder)[0]
- self.connect_markers([self.marker])
- self.update()
-
- def connect_markers(self, markers):
- """
- Connect markers to callbacks
- """
- for h in markers:
- connect = self.base.connect
- connect('enter', h, self._on_enter)
- connect('leave', h, self._on_leave)
- connect('click', h, self._on_click)
- connect('release', h, self._on_release)
- connect('key', h, self.onKey)
-
- def clear(self):
- print "plottable_interactor.clear()"
-
- def _on_click(self, evt):
- """
- Called when a mouse button is clicked
- from within the boundaries of an artist.
- """
- if self._context_menu == True:
- self._context_menu = False
- evt.artist = self.marker
- self._on_leave(evt)
-
- def _on_release(self, evt):
- """
- Called when a mouse button is released
- within the boundaries of an artist
- """
- # Check to see whether we are about to pop
- # the context menu up
- if evt.button == 3:
- self._context_menu = True
-
- def _on_enter(self, evt):
- """
- Called when we are entering the boundaries
- of an artist.
- """
- if not evt.artist.__class__.__name__ == "AxesSubplot":
- self.base.plottable_selected(self.id)
-
- if evt.artist.get_color() == 'y':
- try:
- evt.artist.set_color('b')
- except:
- evt.artist.set_color_cycle('b')
- if hasattr(evt.artist, "set_facecolor"):
- evt.artist.set_facecolor('b')
- if hasattr(evt.artist, "set_edgecolor"):
- evt.artist.set_edgecolor('b')
- else:
- try:
- evt.artist.set_color('y')
- except:
- evt.artist.set_color_cycle('y')
- if hasattr(evt.artist, "set_facecolor"):
- evt.artist.set_facecolor('y')
- if hasattr(evt.artist, "set_edgecolor"):
- evt.artist.set_edgecolor('y')
-
- self.axes.figure.canvas.draw_idle()
-
- def _on_leave(self, evt):
- """
- Called when we are leaving the boundaries
- of an artist.
- """
- if not evt.artist.__class__.__name__ == "AxesSubplot":
- if self._context_menu == False:
- self.base.plottable_selected(None)
- try:
- evt.artist.set_color(self.color)
- except:
- evt.artist.set_color_cycle(self.color)
- if hasattr(evt.artist, "set_facecolor"):
- evt.artist.set_facecolor(self.color)
- if hasattr(evt.artist, "set_edgecolor"):
- evt.artist.set_edgecolor(self.color)
- self.axes.figure.canvas.draw_idle()
-
- def update(self):
- """
- Update
- """
- pass
+"""
+ This module allows more interaction with the plot
+"""
+from __future__ import print_function
+
+from BaseInteractor import _BaseInteractor
+
+
+class PointInteractor(_BaseInteractor):
+ """
+ """
+ def __init__(self, base, axes, color='black', zorder=3, id=''):
+ """
+ """
+ _BaseInteractor.__init__(self, base, axes, color=color)
+ self.zorder = zorder
+ self.id = id
+ self.color = color
+ self.colorlist = ['b', 'g', 'r', 'c', 'm', 'y', 'k']
+ self.symbollist = ['o', 'x', '^', 'v', '<', '>',
+ '+', 's', 'd', 'D', 'h', 'H', 'p', '-', '--',
+ 'vline', 'step']
+ self.markersize = None
+ self.marker = None
+ self.marker2 = None
+ self._button_down = False
+ self._context_menu = False
+ self._dragged = False
+ self.connect_markers([self.axes])
+
+ def _color(self, c):
+ """Return a particular colour"""
+ return self.colorlist[c % len(self.colorlist)]
+
+ def _symbol(self, s):
+ """Return a particular symbol"""
+ return self.symbollist[s % len(self.symbollist)]
+
+ def points(self, x, y, dx=None, dy=None, color=0, symbol=0, zorder=1,
+ markersize=5, label=None, hide_error=False):
+ """
+ """
+ # Draw curve
+ if self._symbol(symbol) == '-' or self._symbol(symbol) == '--':
+ l_width = markersize * 0.4
+ return self.curve(x=x, y=y, color=color, symbol=symbol,
+ label=label, width=l_width)
+ # return
+ if self._symbol(symbol) == 'vline':
+ l_width = markersize * 0.4
+ return self.vline(x=x, y=y, color=color, label=label, width=l_width)
+ if self._symbol(symbol) == 'step':
+ l_width = markersize * 0.4
+ return self.step(x=x, y=y, color=color, label=label, width=l_width)
+ if self.marker is not None:
+ self.base.connect.clear([self.marker])
+ self.color = self._color(color)
+ if self.markersize is not None:
+ markersize = self.markersize
+ # Convert tuple (lo,hi) to array [(x-lo),(hi-x)]
+ if dx is not None and type(dx) == type(()):
+ dx = nx.vstack((x - dx[0], dx[1] - x)).transpose()
+ if dy is not None and type(dy) == type(()):
+ dy = nx.vstack((y - dy[0], dy[1] - y)).transpose()
+
+ if dx is None and dy is None:
+ # zorder = 1
+ self.marker = self.axes.plot(x, y, color=self.color,
+ marker=self._symbol(symbol),
+ markersize=markersize,
+ linestyle='', label=label,
+ zorder=zorder)[0]
+ else:
+
+ if hide_error:
+ # zorder = 1
+ self.marker = self.axes.plot(x, y, color=self.color,
+ marker=self._symbol(symbol),
+ markersize=markersize,
+ linestyle='', label=label,
+ zorder=1)[0]
+ else:
+ # zorder = 2
+ self.marker = self.axes.errorbar(x, y, yerr=dy,
+ xerr=None,
+ ecolor=self.color,
+ color=self.color,
+ capsize=2,
+ linestyle='',
+ barsabove=False,
+ marker=self._symbol(symbol),
+ markersize=markersize,
+ lolims=False, uplims=False,
+ xlolims=False, xuplims=False,
+ label=label,
+ zorder=1)[0]
+
+ self.connect_markers([self.marker])
+ self.update()
+
+ def curve(self, x, y, dy=None, color=0, symbol=0, zorder=10,
+ label=None, width=2.0):
+ """
+ """
+ if self.marker is not None:
+ self.base.connect.clear([self.marker])
+ self.color = self._color(color)
+ self.marker = self.axes.plot(x, y, color=self.color, lw=width,
+ marker='', linestyle=self._symbol(symbol),
+ label=label, zorder=zorder)[0]
+
+ self.connect_markers([self.marker])
+ self.update()
+
+
+ def vline(self, x, y, dy=None, color=0, symbol=0, zorder=1,
+ label=None, width=2.0):
+ """
+ """
+ if self.marker is not None:
+ self.base.connect.clear([self.marker])
+ self.color = self._color(color)
+ if min(y) < 0:
+ y_min = 0.0
+ else:
+ y_min = min(y) * 9 / 10
+ self.marker = self.axes.vlines(x=x, ymin=y_min, ymax=y,
+ color=self.color,
+ linestyle='-', label=label,
+ lw=width, zorder=zorder)
+ self.connect_markers([self.marker])
+ self.update()
+
+ def step(self, x, y, dy=None, color=0, symbol=0, zorder=1,
+ label=None, width=2.0):
+ """
+ """
+ if self.marker is not None:
+ self.base.connect.clear([self.marker])
+ self.color = self._color(color)
+ self.marker = self.axes.step(x, y, color=self.color,
+ marker='',
+ linestyle='-', label=label,
+ lw=width, zorder=zorder)[0]
+ self.connect_markers([self.marker])
+ self.update()
+
+ def connect_markers(self, markers):
+ """
+ Connect markers to callbacks
+ """
+ for h in markers:
+ connect = self.base.connect
+ connect('enter', h, self._on_enter)
+ connect('leave', h, self._on_leave)
+ connect('click', h, self._on_click)
+ connect('release', h, self._on_release)
+ connect('key', h, self.onKey)
+
+ def clear(self):
+ print("plottable_interactor.clear()")
+
+ def _on_click(self, evt):
+ """
+ Called when a mouse button is clicked
+ from within the boundaries of an artist.
+ """
+ if self._context_menu == True:
+ self._context_menu = False
+ evt.artist = self.marker
+ self._on_leave(evt)
+
+ def _on_release(self, evt):
+ """
+ Called when a mouse button is released
+ within the boundaries of an artist
+ """
+ # Check to see whether we are about to pop
+ # the context menu up
+ if evt.button == 3:
+ self._context_menu = True
+
+ def _on_enter(self, evt):
+ """
+ Called when we are entering the boundaries
+ of an artist.
+ """
+ if not evt.artist.__class__.__name__ == "AxesSubplot":
+ self.base.plottable_selected(self.id)
+
+ if evt.artist.get_color() == 'y':
+ try:
+ evt.artist.set_color('b')
+ except:
+ evt.artist.set_color_cycle('b')
+ if hasattr(evt.artist, "set_facecolor"):
+ evt.artist.set_facecolor('b')
+ if hasattr(evt.artist, "set_edgecolor"):
+ evt.artist.set_edgecolor('b')
+ else:
+ try:
+ evt.artist.set_color('y')
+ except:
+ evt.artist.set_color_cycle('y')
+ if hasattr(evt.artist, "set_facecolor"):
+ evt.artist.set_facecolor('y')
+ if hasattr(evt.artist, "set_edgecolor"):
+ evt.artist.set_edgecolor('y')
+
+ self.axes.figure.canvas.draw_idle()
+
+ def _on_leave(self, evt):
+ """
+ Called when we are leaving the boundaries
+ of an artist.
+ """
+ if not evt.artist.__class__.__name__ == "AxesSubplot":
+ if self._context_menu == False:
+ self.base.plottable_selected(None)
+ try:
+ evt.artist.set_color(self.color)
+ except:
+ evt.artist.set_color_cycle(self.color)
+ if hasattr(evt.artist, "set_facecolor"):
+ evt.artist.set_facecolor(self.color)
+ if hasattr(evt.artist, "set_edgecolor"):
+ evt.artist.set_edgecolor(self.color)
+ self.axes.figure.canvas.draw_idle()
+
+ def update(self):
+ """
+ Update
+ """
+ pass
diff --git a/src/sas/sasgui/plottools/plottables.py b/src/sas/sasgui/plottools/plottables.py
index 756a16a..7e35d8d 100644
--- a/src/sas/sasgui/plottools/plottables.py
+++ b/src/sas/sasgui/plottools/plottables.py
@@ -42,10 +42,12 @@ distinctiveness rather than a simple colour number.
# Support for ancient python versions
import copy
-import numpy
+import numpy as np
import sys
import logging
+logger = logging.getLogger(__name__)
+
if 'any' not in dir(__builtins__):
def any(L):
for cond in L:
@@ -226,25 +228,28 @@ class Graph(object):
for p in self.plottables:
if p.hidden == True:
continue
- if not p.x == None:
+ if p.x is not None:
for x_i in p.x:
- if min_value == None or x_i < min_value:
+ if min_value is None or x_i < min_value:
min_value = x_i
- if max_value == None or x_i > max_value:
+ if max_value is None or x_i > max_value:
max_value = x_i
return min_value, max_value
def replace(self, plottable):
"""Replace an existing plottable from the graph"""
- selected_color = None
+ # If the user has set a custom color, ensure the new plot is the same color
+ selected_color = plottable.custom_color
selected_plottable = None
for p in self.plottables.keys():
if plottable.id == p.id:
selected_plottable = p
- selected_color = self.plottables[p]
+ if selected_color is None:
+ selected_color = self.plottables[p]
break
- if selected_plottable is not None and selected_color is not None:
+ if selected_plottable is not None and selected_color is not None:
del self.plottables[selected_plottable]
+ plottable.custom_color = selected_color
self.plottables[plottable] = selected_color
def delete(self, plottable):
@@ -559,8 +564,8 @@ class Plottable(object):
"""
Returns True if there is no data stored in the plottable
"""
- if not self.x == None and len(self.x) == 0 \
- and not self.y == None and len(self.y) == 0:
+ if (self.x is not None and len(self.x) == 0
+ and self.y is not None and len(self.y) == 0):
return True
return False
@@ -676,11 +681,11 @@ class View(object):
"""
# Sanity check
# Do the transofrmation only when x and y are empty
- has_err_x = not (dx == None or len(dx) == 0)
- has_err_y = not (dy == None or len(dy) == 0)
+ has_err_x = not (dx is None or len(dx) == 0)
+ has_err_y = not (dy is None or len(dy) == 0)
- if(x != None) and (y != None):
- if not dx == None and not len(dx) == 0 and not len(x) == len(dx):
+ if(x is not None) and (y is not None):
+ if dx is not None and not len(dx) == 0 and not len(x) == len(dx):
msg = "Plottable.View: Given x and dx are not"
msg += " of the same length"
raise ValueError, msg
@@ -690,7 +695,7 @@ class View(object):
msg += "and x are not of the same length"
raise ValueError, msg
- if not dy == None and not len(dy) == 0 and not len(y) == len(dy):
+ if dy is not None and not len(dy) == 0 and not len(y) == len(dy):
msg = "Plottable.View: Given y and dy are not of the same "
msg += "length: len(y)=%s, len(dy)=%s" % (len(y), len(dy))
raise ValueError, msg
@@ -705,9 +710,9 @@ class View(object):
else:
self.dy = None
if not has_err_x:
- dx = numpy.zeros(len(x))
+ dx = np.zeros(len(x))
if not has_err_y:
- dy = numpy.zeros(len(y))
+ dy = np.zeros(len(y))
for i in range(len(x)):
try:
tempx = self.funcx(x[i], y[i])
@@ -794,10 +799,10 @@ class View(object):
tempdx = []
tempy = []
tempdy = []
- if self.dx == None:
- self.dx = numpy.zeros(len(self.x))
- if self.dy == None:
- self.dy = numpy.zeros(len(self.y))
+ if self.dx is None:
+ self.dx = np.zeros(len(self.x))
+ if self.dy is None:
+ self.dy = np.zeros(len(self.y))
if self.xLabel == "log10(x)":
for i in range(len(self.x)):
try:
@@ -807,8 +812,8 @@ class View(object):
tempy.append(self.y[i])
tempdy.append(self.dy[i])
except:
- logging.error("check_data_logX: skipping point x %g", self.x[i])
- logging.error(sys.exc_value)
+ logger.error("check_data_logX: skipping point x %g", self.x[i])
+ logger.error(sys.exc_value)
self.x = tempx
self.y = tempy
self.dx = tempdx
@@ -824,10 +829,10 @@ class View(object):
tempdx = []
tempy = []
tempdy = []
- if self.dx == None:
- self.dx = numpy.zeros(len(self.x))
- if self.dy == None:
- self.dy = numpy.zeros(len(self.y))
+ if self.dx is None:
+ self.dx = np.zeros(len(self.x))
+ if self.dy is None:
+ self.dy = np.zeros(len(self.y))
if self.yLabel == "log10(y)":
for i in range(len(self.x)):
try:
@@ -837,8 +842,8 @@ class View(object):
tempy.append(self.y[i])
tempdy.append(self.dy[i])
except:
- logging.error("check_data_logY: skipping point %g", self.y[i])
- logging.error(sys.exc_value)
+ logger.error("check_data_logY: skipping point %g", self.y[i])
+ logger.error(sys.exc_value)
self.x = tempx
self.y = tempy
@@ -857,11 +862,11 @@ class View(object):
tempdx = []
tempy = []
tempdy = []
- if self.dx == None:
- self.dx = numpy.zeros(len(self.x))
- if self.dy == None:
- self.dy = numpy.zeros(len(self.y))
- if xmin != None and xmax != None:
+ if self.dx is None:
+ self.dx = np.zeros(len(self.x))
+ if self.dy is None:
+ self.dy = np.zeros(len(self.y))
+ if xmin is not None and xmax is not None:
for i in range(len(self.x)):
if self.x[i] >= xmin and self.x[i] <= xmax:
tempx.append(self.x[i])
@@ -1203,7 +1208,7 @@ class Chisq(Plottable):
def render(self, plot, **kw):
"""
"""
- if self._chisq == None:
+ if self._chisq is None:
chisqTxt = r'$\chi^2=$'
else:
chisqTxt = r'$\chi^2=%g$' % (float(self._chisq))
@@ -1227,17 +1232,17 @@ class Chisq(Plottable):
######################################################
def sample_graph():
- import numpy as nx
+ import numpy as np
# Construct a simple graph
if False:
- x = nx.array([1, 2, 3, 4, 5, 6], 'd')
- y = nx.array([4, 5, 6, 5, 4, 5], 'd')
- dy = nx.array([0.2, 0.3, 0.1, 0.2, 0.9, 0.3])
+ x = np.array([1, 2, 3, 4, 5, 6], 'd')
+ y = np.array([4, 5, 6, 5, 4, 5], 'd')
+ dy = np.array([0.2, 0.3, 0.1, 0.2, 0.9, 0.3])
else:
- x = nx.linspace(0, 1., 10000)
- y = nx.sin(2 * nx.pi * x * 2.8)
- dy = nx.sqrt(100 * nx.abs(y)) / 100
+ x = np.linspace(0, 1., 10000)
+ y = np.sin(2 * np.pi * x * 2.8)
+ dy = np.sqrt(100 * np.abs(y)) / 100
data = Data1D(x, y, dy=dy)
data.xaxis('distance', 'm')
data.yaxis('time', 's')
diff --git a/src/sas/sasgui/plottools/toolbar.py b/src/sas/sasgui/plottools/toolbar.py
index 0bd40e6..c68681d 100644
--- a/src/sas/sasgui/plottools/toolbar.py
+++ b/src/sas/sasgui/plottools/toolbar.py
@@ -1,172 +1,174 @@
-"""
- This module overwrites matplotlib toolbar
-"""
-import wx
-from matplotlib.backends.backend_wxagg import NavigationToolbar2WxAgg
-from matplotlib.backends.backend_wx import _load_bitmap
-import logging
-
-# Event binding code changed after version 2.5
-if wx.VERSION_STRING >= '2.5':
- def bind(actor, event, action, **kw):
- actor.Bind(event, action, **kw)
-else:
- def bind(actor, event, action, id=None):
- if id is not None:
- event(actor, id, action)
- else:
- event(actor, action)
-
-class NavigationToolBar(NavigationToolbar2WxAgg):
- _NTB2_HOME = wx.NewId()
- _NTB2_BACK = wx.NewId()
- _NTB2_FORWARD = wx.NewId()
- _NTB2_PAN = wx.NewId()
- _NTB2_ZOOM = wx.NewId()
- _NTB2_SAVE = wx.NewId()
- _NTB2_PRINT = wx.NewId()
- _NTB2_RESET = wx.NewId()
- _NTB2_COPY = wx.NewId()
- """
- Overwrite matplotlib toolbar
- """
- def __init__(self, canvas, parent=None):
- NavigationToolbar2WxAgg.__init__(self, canvas)
-
- # CRUFT: mpl 1.1 uses save rather than save_figure
- try: save_figure = NavigationToolbar2WxAgg.save
- except AttributeError: pass
-
- def _init_toolbar(self):
- self._parent = self.canvas.GetParent()
-
- # for mpl 1.2+ compatibility
- self.wx_ids = {}
- self.wx_ids['Back'] = self._NTB2_BACK
- self.wx_ids['Forward'] = self._NTB2_FORWARD
- self.wx_ids['Pan'] = self._NTB2_PAN
- self.wx_ids['Zoom'] = self._NTB2_ZOOM
-
- self.SetToolBitmapSize(wx.Size(24, 24))
-
- context_tip = 'Graph Menu: \n'
- context_tip += ' For more menu options, \n'
- context_tip += ' right-click the data symbols.'
- context = wx.ArtProvider.GetBitmap(wx.ART_LIST_VIEW, wx.ART_TOOLBAR)
- self.AddSimpleTool(self._NTB2_HOME, context, context_tip, context_tip)
-
- self.InsertSeparator(1)
-
- self.AddSimpleTool(self._NTB2_BACK, _load_bitmap('back.png'),
- 'Back', 'Back navigation view')
- self.AddSimpleTool(self._NTB2_FORWARD, _load_bitmap('forward.png'),
- 'Forward', 'Forward navigation view')
- # todo: get new bitmap
- self.AddCheckTool(self._NTB2_PAN, _load_bitmap('move.png'),
- shortHelp='Pan',
- longHelp='Pan with left, zoom with right')
- self.AddCheckTool(self._NTB2_ZOOM, _load_bitmap('zoom_to_rect.png'),
- shortHelp='Zoom', longHelp='Zoom to rectangle')
-
- self.AddSeparator()
- self.AddSimpleTool(self._NTB2_SAVE, _load_bitmap('filesave.png'),
- 'Save', 'Save plot contents to file')
-
- print_bmp = wx.ArtProvider.GetBitmap(wx.ART_PRINT, wx.ART_TOOLBAR)
- self.AddSimpleTool(self._NTB2_PRINT, print_bmp, 'Print', 'Print plot')
-
- reset_bmp = wx.ArtProvider.GetBitmap(wx.ART_GO_HOME, wx.ART_TOOLBAR)
- self.AddSimpleTool(self._NTB2_RESET, reset_bmp, 'Reset', 'Reset graph range')
-
- bind(self, wx.EVT_TOOL, self.context_menu, id=self._NTB2_HOME)
- bind(self, wx.EVT_TOOL, self.forward, id=self._NTB2_FORWARD)
- bind(self, wx.EVT_TOOL, self.back, id=self._NTB2_BACK)
- bind(self, wx.EVT_TOOL, self.zoom, id=self._NTB2_ZOOM)
- bind(self, wx.EVT_TOOL, self.pan, id=self._NTB2_PAN)
- bind(self, wx.EVT_TOOL, self.save_figure, id=self._NTB2_SAVE)
- bind(self, wx.EVT_TOOL, self.print_figure, id=self._NTB2_PRINT)
- bind(self, wx.EVT_TOOL, self.home, id=self._NTB2_RESET)
-
- self.Realize()
-
- def on_menu(self, event):
- try:
- self._parent.onToolContextMenu(event=event)
- except:
- logging.error("Plot toolbar could not show menu")
-
- def context_menu(self, event):
- """
- Default context menu for a plot panel
-
- """
- # Slicer plot popup menu
- popup = wx.Menu()
- popup.Append(self._NTB2_SAVE, '&Save image', 'Save image as PNG')
- wx.EVT_MENU(self, self._NTB2_SAVE, self.save_figure)
-
- popup.Append(self._NTB2_PRINT, '&Print image', 'Print image ')
- wx.EVT_MENU(self, self._NTB2_PRINT, self.print_figure)
-
- popup.Append(self._NTB2_COPY, '&Copy to Clipboard', 'Copy image to the clipboard')
- wx.EVT_MENU(self, self._NTB2_COPY, self.copy_figure)
-
- # Show the popup menu relative to the location of the toolbar
- self.PopupMenu(popup, (0,0))
-
-
- def print_figure(self, event):
- try:
- _printer = wx.Printer()
- _printer.Print(self.canvas, PlotPrintout(self.canvas), True)
- except:
- import traceback
- logging.error(traceback.format_exc())
-
- def copy_figure(self, event):
- copy_image_to_clipboard(self.canvas)
-
-class PlotPrintout(wx.Printout):
- """
- Create the wx.Printout object for matplotlib figure from the PlotPanel.
- Provides the required OnPrintPage and HasPage overrides. Other methods
- may be added/overriden in the future.
- :TODO: this needs LOTS of TLC .. but fixes immediate problem
- """
- def __init__(self, canvas):
- """
- Initialize wx.Printout and get passed figure object
- """
- wx.Printout.__init__(self)
- self.canvas = canvas
-
- def OnPrintPage(self, page):
- """
- Most rudimentry OnPrintPage overide. instatiates a dc object, gets
- its size, gets the size of the figure object, scales it to the dc
- canvas size keeping the aspect ratio intact, then prints as bitmap
- """
- _dc = self.GetDC()
- (_dcX, _dcY) = _dc.GetSizeTuple()
- (_bmpX,_bmpY) = self.canvas.GetSize()
- _scale = min(_dcX/_bmpX, _dcY/_bmpY)
- _dc.SetUserScale(_scale, _scale)
- _dc.DrawBitmap(self.canvas.bitmap, 0, 0, False,)
- return True
-
- def GetPageInfo(self):
- """
- just sets the page to 1 - no flexibility for now
- """
- return (1, 1, 1, 1)
-
-
-def copy_image_to_clipboard(canvas):
- bmp = wx.BitmapDataObject()
- bmp.SetBitmap(canvas.bitmap)
-
- wx.TheClipboard.Open()
- wx.TheClipboard.SetData(bmp)
- wx.TheClipboard.Close()
-
-
+"""
+ This module overwrites matplotlib toolbar
+"""
+import wx
+from matplotlib.backends.backend_wxagg import NavigationToolbar2WxAgg
+from matplotlib.backends.backend_wx import _load_bitmap
+import logging
+
+logger = logging.getLogger(__name__)
+
+# Event binding code changed after version 2.5
+if wx.VERSION_STRING >= '2.5':
+ def bind(actor, event, action, **kw):
+ actor.Bind(event, action, **kw)
+else:
+ def bind(actor, event, action, id=None):
+ if id is not None:
+ event(actor, id, action)
+ else:
+ event(actor, action)
+
+class NavigationToolBar(NavigationToolbar2WxAgg):
+ _NTB2_HOME = wx.NewId()
+ _NTB2_BACK = wx.NewId()
+ _NTB2_FORWARD = wx.NewId()
+ _NTB2_PAN = wx.NewId()
+ _NTB2_ZOOM = wx.NewId()
+ _NTB2_SAVE = wx.NewId()
+ _NTB2_PRINT = wx.NewId()
+ _NTB2_RESET = wx.NewId()
+ _NTB2_COPY = wx.NewId()
+ """
+ Overwrite matplotlib toolbar
+ """
+ def __init__(self, canvas, parent=None):
+ NavigationToolbar2WxAgg.__init__(self, canvas)
+
+ # CRUFT: mpl 1.1 uses save rather than save_figure
+ try: save_figure = NavigationToolbar2WxAgg.save
+ except AttributeError: pass
+
+ def _init_toolbar(self):
+ self._parent = self.canvas.GetParent()
+
+ # for mpl 1.2+ compatibility
+ self.wx_ids = {}
+ self.wx_ids['Back'] = self._NTB2_BACK
+ self.wx_ids['Forward'] = self._NTB2_FORWARD
+ self.wx_ids['Pan'] = self._NTB2_PAN
+ self.wx_ids['Zoom'] = self._NTB2_ZOOM
+
+ self.SetToolBitmapSize(wx.Size(24, 24))
+
+ context_tip = 'Graph Menu: \n'
+ context_tip += ' For more menu options, \n'
+ context_tip += ' right-click the data symbols.'
+ context = wx.ArtProvider.GetBitmap(wx.ART_LIST_VIEW, wx.ART_TOOLBAR)
+ self.AddSimpleTool(self._NTB2_HOME, context, context_tip, context_tip)
+
+ self.InsertSeparator(1)
+
+ self.AddSimpleTool(self._NTB2_BACK, _load_bitmap('back.png'),
+ 'Back', 'Back navigation view')
+ self.AddSimpleTool(self._NTB2_FORWARD, _load_bitmap('forward.png'),
+ 'Forward', 'Forward navigation view')
+ # todo: get new bitmap
+ self.AddCheckTool(self._NTB2_PAN, _load_bitmap('move.png'),
+ shortHelp='Pan',
+ longHelp='Pan with left, zoom with right')
+ self.AddCheckTool(self._NTB2_ZOOM, _load_bitmap('zoom_to_rect.png'),
+ shortHelp='Zoom', longHelp='Zoom to rectangle')
+
+ self.AddSeparator()
+ self.AddSimpleTool(self._NTB2_SAVE, _load_bitmap('filesave.png'),
+ 'Save', 'Save plot contents to file')
+
+ print_bmp = wx.ArtProvider.GetBitmap(wx.ART_PRINT, wx.ART_TOOLBAR)
+ self.AddSimpleTool(self._NTB2_PRINT, print_bmp, 'Print', 'Print plot')
+
+ reset_bmp = wx.ArtProvider.GetBitmap(wx.ART_GO_HOME, wx.ART_TOOLBAR)
+ self.AddSimpleTool(self._NTB2_RESET, reset_bmp, 'Reset', 'Reset graph range')
+
+ bind(self, wx.EVT_TOOL, self.context_menu, id=self._NTB2_HOME)
+ bind(self, wx.EVT_TOOL, self.forward, id=self._NTB2_FORWARD)
+ bind(self, wx.EVT_TOOL, self.back, id=self._NTB2_BACK)
+ bind(self, wx.EVT_TOOL, self.zoom, id=self._NTB2_ZOOM)
+ bind(self, wx.EVT_TOOL, self.pan, id=self._NTB2_PAN)
+ bind(self, wx.EVT_TOOL, self.save_figure, id=self._NTB2_SAVE)
+ bind(self, wx.EVT_TOOL, self.print_figure, id=self._NTB2_PRINT)
+ bind(self, wx.EVT_TOOL, self.home, id=self._NTB2_RESET)
+
+ self.Realize()
+
+ def on_menu(self, event):
+ try:
+ self._parent.onToolContextMenu(event=event)
+ except:
+ logger.error("Plot toolbar could not show menu")
+
+ def context_menu(self, event):
+ """
+ Default context menu for a plot panel
+
+ """
+ # Slicer plot popup menu
+ popup = wx.Menu()
+ popup.Append(self._NTB2_SAVE, '&Save image', 'Save image as PNG')
+ wx.EVT_MENU(self, self._NTB2_SAVE, self.save_figure)
+
+ popup.Append(self._NTB2_PRINT, '&Print image', 'Print image ')
+ wx.EVT_MENU(self, self._NTB2_PRINT, self.print_figure)
+
+ popup.Append(self._NTB2_COPY, '&Copy to Clipboard', 'Copy image to the clipboard')
+ wx.EVT_MENU(self, self._NTB2_COPY, self.copy_figure)
+
+ # Show the popup menu relative to the location of the toolbar
+ self.PopupMenu(popup, (0,0))
+
+
+ def print_figure(self, event):
+ try:
+ _printer = wx.Printer()
+ _printer.Print(self.canvas, PlotPrintout(self.canvas), True)
+ except:
+ import traceback
+ logger.error(traceback.format_exc())
+
+ def copy_figure(self, event):
+ copy_image_to_clipboard(self.canvas)
+
+class PlotPrintout(wx.Printout):
+ """
+ Create the wx.Printout object for matplotlib figure from the PlotPanel.
+ Provides the required OnPrintPage and HasPage overrides. Other methods
+ may be added/overriden in the future.
+ :TODO: this needs LOTS of TLC .. but fixes immediate problem
+ """
+ def __init__(self, canvas):
+ """
+ Initialize wx.Printout and get passed figure object
+ """
+ wx.Printout.__init__(self)
+ self.canvas = canvas
+
+ def OnPrintPage(self, page):
+ """
+ Most rudimentry OnPrintPage overide. instatiates a dc object, gets
+ its size, gets the size of the figure object, scales it to the dc
+ canvas size keeping the aspect ratio intact, then prints as bitmap
+ """
+ _dc = self.GetDC()
+ (_dcX, _dcY) = _dc.GetSizeTuple()
+ (_bmpX,_bmpY) = self.canvas.GetSize()
+ _scale = min(_dcX/_bmpX, _dcY/_bmpY)
+ _dc.SetUserScale(_scale, _scale)
+ _dc.DrawBitmap(self.canvas.bitmap, 0, 0, False,)
+ return True
+
+ def GetPageInfo(self):
+ """
+ just sets the page to 1 - no flexibility for now
+ """
+ return (1, 1, 1, 1)
+
+
+def copy_image_to_clipboard(canvas):
+ bmp = wx.BitmapDataObject()
+ bmp.SetBitmap(canvas.bitmap)
+
+ wx.TheClipboard.Open()
+ wx.TheClipboard.SetData(bmp)
+ wx.TheClipboard.Close()
+
+
diff --git a/src/sas/sasgui/plottools/transform.py b/src/sas/sasgui/plottools/transform.py
index 112a5a8..00028a8 100644
--- a/src/sas/sasgui/plottools/transform.py
+++ b/src/sas/sasgui/plottools/transform.py
@@ -1,413 +1,413 @@
-import math
-
-
-def toX(x, y=None):
- """
- This function is used to load value on Plottable.View
-
- :param x: Float value
-
- :return: x
-
- """
- return x
-
-
-def toX_pos(x, y=None):
- """
- This function is used to load value on Plottable.View
-
- :param x: Float value
-
- :return: x
-
- """
- if not x > 0:
- raise ValueError, "Transformation only accepts positive values."
- else:
- return x
-
-
-def toX2(x, y=None):
- """
- This function is used to load value on Plottable.View
-
- Calculate x^(2)
-
- :param x: float value
-
- """
- return x * x
-
-
-def fromX2(x, y=None):
- """
- This function is used to load value on Plottable.View
- Calculate square root of x
-
- :param x: float value
-
- """
- if not x >= 0:
- raise ValueError, "square root of a negative value "
- else:
- return math.sqrt(x)
-
-
-def toX4(x, y=None):
- """
- This function is used to load value on Plottable.View
-
- Calculate x^(4)
-
- :param x: float value
-
- """
- return x * x * x * x
-
-
-def fromX4(x, y=None):
- """
- This function is used to load value on Plottable.View
- Calculate square root of x
-
- :param x: float value
-
- """
- if not x >= 0:
- raise ValueError, "double square root of a negative value "
- else:
- return math.sqrt(math.sqrt(x))
-
-
-def toLogX(x, y=None):
- """
- This function is used to load value on Plottable.View
- calculate log x
-
- :param x: float value
-
- """
- if not x > 0:
- raise ValueError, "Log(x)of a negative value "
- else:
- return math.log(x)
-
-def toOneOverX(x, y=None):
- """
- """
- if x != 0:
- return 1 / x
- else:
- raise ValueError, "cannot divide by zero"
-
-
-def toOneOverSqrtX(y, x=None):
- """
- """
- if y > 0:
- return 1 / math.sqrt(y)
- else:
- raise ValueError, "transform.toOneOverSqrtX: cannot be computed"
-
-
-def toLogYX2(y, x):
- """
- """
- if (y * (x ** 2)) > 0:
- return math.log(y * (x ** 2))
- else:
- raise ValueError, "transform.toLogYX2: cannot be computed"
-
-
-def toLogYX4(y, x):
- """
- """
- if (math.pow(x, 4) * y) > 0:
- return math.log(math.pow(x, 4) * y)
- else:
- raise ValueError, "transform.toLogYX4: input error"
-
-
-def toYX4(y, x):
- """
- """
- return math.pow(x, 4) * y
-
-def toYX2(y, x):
- """
- """
- return math.pow(x, 2) * y
-
-def toLogXY(y, x):
- """
- This function is used to load value on Plottable.View
- calculate log x
-
- :param x: float value
-
- """
- if not (x * y) > 0:
- raise ValueError, "Log(X*Y)of a negative value "
- else:
- return math.log(x * y)
-
-
-def errToX(x, y=None, dx=None, dy=None):
- """
- calculate error of x**2
-
- :param x: float value
- :param dx: float value
-
- """
- if dx == None:
- dx = 0
- return dx
-
-
-def errToX_pos(x, y=None, dx=None, dy=None):
- """
- calculate error of x**2
-
- :param x: float value
- :param dx: float value
-
- """
- if dx == None:
- dx = 0
- return dx
-
-
-def errToX2(x, y=None, dx=None, dy=None):
- """
- calculate error of x**2
-
- :param x: float value
- :param dx: float value
-
- """
- if dx != None:
- err = 2 * x * dx
- return math.fabs(err)
- else:
- return 0.0
-
-
-def errFromX2(x, y=None, dx=None, dy=None):
- """
- calculate error of sqrt(x)
-
- :param x: float value
- :param dx: float value
-
- """
- if x > 0:
- if dx != None:
- err = dx / (2 * math.sqrt(x))
- else:
- err = 0
- return math.fabs(err)
- else:
- msg = "transform.errFromX2: can't compute error of negative x"
- raise ValueError, msg
-
-
-def errToX4(x, y=None, dx=None, dy=None):
- """
- calculate error of x**4
-
- :param x: float value
- :param dx: float value
-
- """
- if dx != None:
- err = 4 * math.pow(x, 3) * dx
- return math.fabs(err)
- else:
- return 0.0
-
-
-def errFromX4(x, y=None, dx=None, dy=None):
- """
- calculate error of x^1/4
-
- :param x: float value
- :param dx: float value
-
- """
- if x > 0:
- if dx != None:
- err = dx / (4 * math.pow(x, 3 / 4))
- else:
- err = 0
- return math.fabs(err)
- else:
- msg = "transform.errFromX4: can't compute error of negative x"
- raise ValueError, msg
-
-
-def errToLog10X(x, y=None, dx=None, dy=None):
- """
- calculate error of Log(x)
-
- :param x: float value
- :param dx: float value
-
- """
- if dx == None:
- dx = 0
-
- # Check that the point on the graph is positive
- # within errors
- if not (x - dx) > 0:
- msg = "Transformation does not accept"
- msg += " point that are consistent with zero."
- raise ValueError, msg
- if x != 0:
- dx = dx / (x * math.log(10))
- else:
- raise ValueError, "errToLogX: divide by zero"
- return dx
-
-
-def errToLogX(x, y=None, dx=None, dy=None):
- """
- calculate error of Log(x)
-
- :param x: float value
- :param dx: float value
-
- """
- if dx == None:
- dx = 0
-
- # Check that the x point on the graph is zero
- if x != 0:
- dx = dx / x
- else:
- raise ValueError, "errToLogX: divide by zero"
- return dx
-
-
-def errToYX2(y, x, dy=None, dx=None):
- """
- """
- if dx == None:
- dx = 0
- if dy == None:
- dy = 0
- err = math.sqrt((2 * x * y * dx) ** 2 + ((x ** 2) * dy) ** 2)
- return err
-
-
-def errToLogXY(x, y, dx=None, dy=None):
- """
- calculate error of Log(xy)
-
- """
- # Check that the point on the graph is positive
- # within errors
- if not (x - dx) > 0 or not (y - dy) > 0:
- msg = "Transformation does not accept point "
- msg += " that are consistent with zero."
- raise ValueError, msg
- if x != 0 and y != 0:
- if dx == None:
- dx = 0
- if dy == None:
- dy = 0
- err = (dx / x) ** 2 + (dy / y) ** 2
- else:
- raise ValueError, "cannot compute this error"
-
- return math.sqrt(math.fabs(err))
-
-
-def errToLogYX2(y, x, dy=None, dx=None):
- """
- calculate error of Log(yx**2)
-
- """
- # Check that the point on the graph is positive
- # within errors
- if not (x - dx) > 0 or not (y - dy) > 0:
- msg = "Transformation does not accept point"
- msg += " that are consistent with zero."
- raise ValueError, msg
- if x > 0 and y > 0:
- if dx == None:
- dx = 0
- if dy == None:
- dy = 0
- err = (2.0 * dx / x) ** 2 + (dy / y) ** 2
- else:
- raise ValueError, "cannot compute this error"
- return math.sqrt(math.fabs(err))
-
-
-def errOneOverX(x, y=None, dx=None, dy=None):
- """
- calculate error on 1/x
-
- """
- if x != 0:
- if dx == None:
- dx = 0
- err = dx / x ** 2
- else:
- raise ValueError, "Cannot compute this error"
- return math.fabs(err)
-
-
-def errOneOverSqrtX(x, y=None, dx=None, dy=None):
- """
- Calculate error on 1/sqrt(x)
-
- """
- if x > 0:
- if dx == None:
- dx = 0
- err = -1 / 2 * math.pow(x, -3.0 / 2.0) * dx
- else:
- raise ValueError, "Cannot compute this error"
- return math.fabs(err)
-
-
-def errToLogYX4(y, x, dy=None, dx=None):
- """
- error for ln(y*x^(4))
-
- :param x: float value
-
- """
- # Check that the point on the graph is positive
- # within errors
- if (not (x - dx) > 0) or (not (y - dy) > 0):
- msg = "Transformation does not accept point "
- msg += " that are consistent with zero."
- raise ValueError, msg
- if dx == None:
- dx = 0
- if dy == None:
- dy = 0
- err = math.sqrt((4.0 * dx / x) ** 2 + (dy / y) ** 2)
- return err
-
-
-def errToYX4(y, x, dy=None, dx=None):
- """
- error for (y*x^(4))
-
- :param x: float value
-
- """
- # Check that the point on the graph is positive
- # within errors
-
- if dx == None:
- dx = 0
- if dy == None:
- dy = 0
- err = math.sqrt((dy * pow(x, 4)) ** 2 + (4 * y * dx * math.pow(x, 3)) ** 2)
- return err
+import math
+
+
+def toX(x, y=None):
+ """
+ This function is used to load value on Plottable.View
+
+ :param x: Float value
+
+ :return: x
+
+ """
+ return x
+
+
+def toX_pos(x, y=None):
+ """
+ This function is used to load value on Plottable.View
+
+ :param x: Float value
+
+ :return: x
+
+ """
+ if not x > 0:
+ raise ValueError, "Transformation only accepts positive values."
+ else:
+ return x
+
+
+def toX2(x, y=None):
+ """
+ This function is used to load value on Plottable.View
+
+ Calculate x^(2)
+
+ :param x: float value
+
+ """
+ return x * x
+
+
+def fromX2(x, y=None):
+ """
+ This function is used to load value on Plottable.View
+ Calculate square root of x
+
+ :param x: float value
+
+ """
+ if not x >= 0:
+ raise ValueError, "square root of a negative value "
+ else:
+ return math.sqrt(x)
+
+
+def toX4(x, y=None):
+ """
+ This function is used to load value on Plottable.View
+
+ Calculate x^(4)
+
+ :param x: float value
+
+ """
+ return x * x * x * x
+
+
+def fromX4(x, y=None):
+ """
+ This function is used to load value on Plottable.View
+ Calculate square root of x
+
+ :param x: float value
+
+ """
+ if not x >= 0:
+ raise ValueError, "double square root of a negative value "
+ else:
+ return math.sqrt(math.sqrt(x))
+
+
+def toLogX(x, y=None):
+ """
+ This function is used to load value on Plottable.View
+ calculate log x
+
+ :param x: float value
+
+ """
+ if not x > 0:
+ raise ValueError, "Log(x)of a negative value "
+ else:
+ return math.log(x)
+
+def toOneOverX(x, y=None):
+ """
+ """
+ if x != 0:
+ return 1 / x
+ else:
+ raise ValueError, "cannot divide by zero"
+
+
+def toOneOverSqrtX(y, x=None):
+ """
+ """
+ if y > 0:
+ return 1 / math.sqrt(y)
+ else:
+ raise ValueError, "transform.toOneOverSqrtX: cannot be computed"
+
+
+def toLogYX2(y, x):
+ """
+ """
+ if (y * (x ** 2)) > 0:
+ return math.log(y * (x ** 2))
+ else:
+ raise ValueError, "transform.toLogYX2: cannot be computed"
+
+
+def toLogYX4(y, x):
+ """
+ """
+ if (math.pow(x, 4) * y) > 0:
+ return math.log(math.pow(x, 4) * y)
+ else:
+ raise ValueError, "transform.toLogYX4: input error"
+
+
+def toYX4(y, x):
+ """
+ """
+ return math.pow(x, 4) * y
+
+def toYX2(y, x):
+ """
+ """
+ return math.pow(x, 2) * y
+
+def toLogXY(y, x):
+ """
+ This function is used to load value on Plottable.View
+ calculate log x
+
+ :param x: float value
+
+ """
+ if not (x * y) > 0:
+ raise ValueError, "Log(X*Y)of a negative value "
+ else:
+ return math.log(x * y)
+
+
+def errToX(x, y=None, dx=None, dy=None):
+ """
+ calculate error of x**2
+
+ :param x: float value
+ :param dx: float value
+
+ """
+ if dx is None:
+ dx = 0
+ return dx
+
+
+def errToX_pos(x, y=None, dx=None, dy=None):
+ """
+ calculate error of x**2
+
+ :param x: float value
+ :param dx: float value
+
+ """
+ if dx is None:
+ dx = 0
+ return dx
+
+
+def errToX2(x, y=None, dx=None, dy=None):
+ """
+ calculate error of x**2
+
+ :param x: float value
+ :param dx: float value
+
+ """
+ if dx is not None:
+ err = 2 * x * dx
+ return math.fabs(err)
+ else:
+ return 0.0
+
+
+def errFromX2(x, y=None, dx=None, dy=None):
+ """
+ calculate error of sqrt(x)
+
+ :param x: float value
+ :param dx: float value
+
+ """
+ if x > 0:
+ if dx is not None:
+ err = dx / (2 * math.sqrt(x))
+ else:
+ err = 0
+ return math.fabs(err)
+ else:
+ msg = "transform.errFromX2: can't compute error of negative x"
+ raise ValueError, msg
+
+
+def errToX4(x, y=None, dx=None, dy=None):
+ """
+ calculate error of x**4
+
+ :param x: float value
+ :param dx: float value
+
+ """
+ if dx is not None:
+ err = 4 * math.pow(x, 3) * dx
+ return math.fabs(err)
+ else:
+ return 0.0
+
+
+def errFromX4(x, y=None, dx=None, dy=None):
+ """
+ calculate error of x^1/4
+
+ :param x: float value
+ :param dx: float value
+
+ """
+ if x > 0:
+ if dx is not None:
+ err = dx / (4 * math.pow(x, 3 / 4))
+ else:
+ err = 0
+ return math.fabs(err)
+ else:
+ msg = "transform.errFromX4: can't compute error of negative x"
+ raise ValueError, msg
+
+
+def errToLog10X(x, y=None, dx=None, dy=None):
+ """
+ calculate error of Log(x)
+
+ :param x: float value
+ :param dx: float value
+
+ """
+ if dx is None:
+ dx = 0
+
+ # Check that the point on the graph is positive
+ # within errors
+ if not (x - dx) > 0:
+ msg = "Transformation does not accept"
+ msg += " point that are consistent with zero."
+ raise ValueError, msg
+ if x != 0:
+ dx = dx / (x * math.log(10))
+ else:
+ raise ValueError, "errToLogX: divide by zero"
+ return dx
+
+
+def errToLogX(x, y=None, dx=None, dy=None):
+ """
+ calculate error of Log(x)
+
+ :param x: float value
+ :param dx: float value
+
+ """
+ if dx is None:
+ dx = 0
+
+ # Check that the x point on the graph is zero
+ if x != 0:
+ dx = dx / x
+ else:
+ raise ValueError, "errToLogX: divide by zero"
+ return dx
+
+
+def errToYX2(y, x, dy=None, dx=None):
+ """
+ """
+ if dx is None:
+ dx = 0
+ if dy is None:
+ dy = 0
+ err = math.sqrt((2 * x * y * dx) ** 2 + ((x ** 2) * dy) ** 2)
+ return err
+
+
+def errToLogXY(x, y, dx=None, dy=None):
+ """
+ calculate error of Log(xy)
+
+ """
+ # Check that the point on the graph is positive
+ # within errors
+ if not (x - dx) > 0 or not (y - dy) > 0:
+ msg = "Transformation does not accept point "
+ msg += " that are consistent with zero."
+ raise ValueError, msg
+ if x != 0 and y != 0:
+ if dx is None:
+ dx = 0
+ if dy is None:
+ dy = 0
+ err = (dx / x) ** 2 + (dy / y) ** 2
+ else:
+ raise ValueError, "cannot compute this error"
+
+ return math.sqrt(math.fabs(err))
+
+
+def errToLogYX2(y, x, dy=None, dx=None):
+ """
+ calculate error of Log(yx**2)
+
+ """
+ # Check that the point on the graph is positive
+ # within errors
+ if not (x - dx) > 0 or not (y - dy) > 0:
+ msg = "Transformation does not accept point"
+ msg += " that are consistent with zero."
+ raise ValueError, msg
+ if x > 0 and y > 0:
+ if dx is None:
+ dx = 0
+ if dy is None:
+ dy = 0
+ err = (2.0 * dx / x) ** 2 + (dy / y) ** 2
+ else:
+ raise ValueError, "cannot compute this error"
+ return math.sqrt(math.fabs(err))
+
+
+def errOneOverX(x, y=None, dx=None, dy=None):
+ """
+ calculate error on 1/x
+
+ """
+ if x != 0:
+ if dx is None:
+ dx = 0
+ err = dx / x ** 2
+ else:
+ raise ValueError, "Cannot compute this error"
+ return math.fabs(err)
+
+
+def errOneOverSqrtX(x, y=None, dx=None, dy=None):
+ """
+ Calculate error on 1/sqrt(x)
+
+ """
+ if x > 0:
+ if dx is None:
+ dx = 0
+ err = -1 / 2 * math.pow(x, -3.0 / 2.0) * dx
+ else:
+ raise ValueError, "Cannot compute this error"
+ return math.fabs(err)
+
+
+def errToLogYX4(y, x, dy=None, dx=None):
+ """
+ error for ln(y*x^(4))
+
+ :param x: float value
+
+ """
+ # Check that the point on the graph is positive
+ # within errors
+ if (not (x - dx) > 0) or (not (y - dy) > 0):
+ msg = "Transformation does not accept point "
+ msg += " that are consistent with zero."
+ raise ValueError, msg
+ if dx is None:
+ dx = 0
+ if dy is None:
+ dy = 0
+ err = math.sqrt((4.0 * dx / x) ** 2 + (dy / y) ** 2)
+ return err
+
+
+def errToYX4(y, x, dy=None, dx=None):
+ """
+ error for (y*x^(4))
+
+ :param x: float value
+
+ """
+ # Check that the point on the graph is positive
+ # within errors
+
+ if dx is None:
+ dx = 0
+ if dy is None:
+ dy = 0
+ err = math.sqrt((dy * pow(x, 4)) ** 2 + (4 * y * dx * math.pow(x, 3)) ** 2)
+ return err
diff --git a/src/sas/sasview/__init__.py b/src/sas/sasview/__init__.py
new file mode 100644
index 0000000..f47b871
--- /dev/null
+++ b/src/sas/sasview/__init__.py
@@ -0,0 +1,2 @@
+__version__ = "4.2.0"
+__build__ = "GIT_COMMIT"
\ No newline at end of file
diff --git a/sasview/custom_config.py b/src/sas/sasview/custom_config.py
similarity index 77%
rename from sasview/custom_config.py
rename to src/sas/sasview/custom_config.py
index ecf5133..61b03f9 100644
--- a/sasview/custom_config.py
+++ b/src/sas/sasview/custom_config.py
@@ -1,17 +1,17 @@
-"""
- Application appearance custom configuration
-"""
-DATAPANEL_WIDTH = -1
-CLEANUP_PLOT = False
-FIXED_PANEL = True
-PLOPANEL_WIDTH = -1
-DATALOADER_SHOW = True
-GUIFRAME_HEIGHT = -1
-GUIFRAME_WIDTH = -1
-CONTROL_WIDTH = -1
-CONTROL_HEIGHT = -1
-DEFAULT_OPEN_FOLDER = None
-WELCOME_PANEL_SHOW = False
-TOOLBAR_SHOW = True
-DEFAULT_PERSPECTIVE = "Fitting"
-SAS_OPENCL = "None"
+"""
+Application appearance custom configuration
+"""
+DATAPANEL_WIDTH = -1
+CLEANUP_PLOT = False
+FIXED_PANEL = True
+PLOPANEL_WIDTH = -1
+DATALOADER_SHOW = True
+GUIFRAME_HEIGHT = -1
+GUIFRAME_WIDTH = -1
+CONTROL_WIDTH = -1
+CONTROL_HEIGHT = -1
+DEFAULT_OPEN_FOLDER = None
+WELCOME_PANEL_SHOW = False
+TOOLBAR_SHOW = True
+DEFAULT_PERSPECTIVE = "Fitting"
+SAS_OPENCL = "None"
diff --git a/sasview/images/SVwelcome.png b/src/sas/sasview/images/SVwelcome.png
similarity index 100%
rename from sasview/images/SVwelcome.png
rename to src/sas/sasview/images/SVwelcome.png
diff --git a/sasview/images/SVwelcome_mini.png b/src/sas/sasview/images/SVwelcome_mini.png
similarity index 100%
rename from sasview/images/SVwelcome_mini.png
rename to src/sas/sasview/images/SVwelcome_mini.png
diff --git a/sasview/images/angles.png b/src/sas/sasview/images/angles.png
similarity index 100%
rename from sasview/images/angles.png
rename to src/sas/sasview/images/angles.png
diff --git a/sasview/images/angles_flat.png b/src/sas/sasview/images/angles_flat.png
similarity index 100%
rename from sasview/images/angles_flat.png
rename to src/sas/sasview/images/angles_flat.png
diff --git a/sasview/images/ansto_logo.png b/src/sas/sasview/images/ansto_logo.png
similarity index 100%
rename from sasview/images/ansto_logo.png
rename to src/sas/sasview/images/ansto_logo.png
diff --git a/sasview/images/ball.icns b/src/sas/sasview/images/ball.icns
similarity index 100%
rename from sasview/images/ball.icns
rename to src/sas/sasview/images/ball.icns
diff --git a/sasview/images/ball.ico b/src/sas/sasview/images/ball.ico
similarity index 100%
rename from sasview/images/ball.ico
rename to src/sas/sasview/images/ball.ico
diff --git a/sasview/images/danse_logo.png b/src/sas/sasview/images/danse_logo.png
similarity index 100%
rename from sasview/images/danse_logo.png
rename to src/sas/sasview/images/danse_logo.png
diff --git a/src/sas/sasview/images/dls_logo.png b/src/sas/sasview/images/dls_logo.png
new file mode 100755
index 0000000..da4aa66
Binary files /dev/null and b/src/sas/sasview/images/dls_logo.png differ
diff --git a/sasview/images/ess_logo.png b/src/sas/sasview/images/ess_logo.png
similarity index 100%
rename from sasview/images/ess_logo.png
rename to src/sas/sasview/images/ess_logo.png
diff --git a/sasview/images/ill_logo.png b/src/sas/sasview/images/ill_logo.png
similarity index 100%
rename from sasview/images/ill_logo.png
rename to src/sas/sasview/images/ill_logo.png
diff --git a/sasview/images/isis_logo.png b/src/sas/sasview/images/isis_logo.png
similarity index 100%
rename from sasview/images/isis_logo.png
rename to src/sas/sasview/images/isis_logo.png
diff --git a/sasview/images/nist_logo.png b/src/sas/sasview/images/nist_logo.png
similarity index 100%
rename from sasview/images/nist_logo.png
rename to src/sas/sasview/images/nist_logo.png
diff --git a/sasview/images/nsf_logo.png b/src/sas/sasview/images/nsf_logo.png
similarity index 100%
rename from sasview/images/nsf_logo.png
rename to src/sas/sasview/images/nsf_logo.png
diff --git a/sasview/images/ornl_logo.png b/src/sas/sasview/images/ornl_logo.png
similarity index 100%
rename from sasview/images/ornl_logo.png
rename to src/sas/sasview/images/ornl_logo.png
diff --git a/sasview/images/sns_logo.png b/src/sas/sasview/images/sns_logo.png
similarity index 100%
rename from sasview/images/sns_logo.png
rename to src/sas/sasview/images/sns_logo.png
diff --git a/sasview/images/tudelft_logo.png b/src/sas/sasview/images/tudelft_logo.png
similarity index 100%
rename from sasview/images/tudelft_logo.png
rename to src/sas/sasview/images/tudelft_logo.png
diff --git a/sasview/images/umd_logo.png b/src/sas/sasview/images/umd_logo.png
similarity index 100%
rename from sasview/images/umd_logo.png
rename to src/sas/sasview/images/umd_logo.png
diff --git a/sasview/images/utlogo.gif b/src/sas/sasview/images/utlogo.gif
similarity index 100%
rename from sasview/images/utlogo.gif
rename to src/sas/sasview/images/utlogo.gif
diff --git a/sasview/local_config.py b/src/sas/sasview/local_config.py
similarity index 89%
rename from sasview/local_config.py
rename to src/sas/sasview/local_config.py
index bc10603..f2afad1 100644
--- a/sasview/local_config.py
+++ b/src/sas/sasview/local_config.py
@@ -1,11 +1,16 @@
"""
- Application settings
+Application settings
"""
+from __future__ import print_function
+
import time
import os
+import logging
+
from sas.sasgui.guiframe.gui_style import GUIFRAME
import sas.sasview
-import logging
+
+logger = logging.getLogger(__name__)
# Version of the application
__appname__ = "SasView"
@@ -45,7 +50,7 @@ _acknowledgement_citation = \
'''M. Doucet et al. SasView Version 4.1.2, Zenodo, 10.5281/zenodo.825675'''
_acknowledgement = \
-'''This work was originally developed as part of the DANSE project funded by the US NSF under Award DMR-0520547,\n but is currently maintained by a collaboration between UTK, UMD, NIST, ORNL, ISIS, ESS, ILL, ANSTO and TU Delft and the scattering community.\n\n SasView also contains code developed with funding from the EU Horizon 2020 programme under the SINE2020 project (Grant No 654000).\nA list of individual contributors can be found at: https://github.com/orgs/SasView/people
+'''This work was originally developed as part of the DANSE project funded by the US NSF under Award DMR-0520547,\n but is currently maintained by a collaboration between UTK, UMD, NIST, ORNL, ISIS, ESS, ILL, ANSTO, TU Delft, DLS, and the scattering community.\n\n SasView also contains code developed with funding from the EU Horizon 2020 programme under the SINE2020 project (Grant No 654000).\nA list of individual contributors can be found at: http://www.sasview.org/contact.html
'''
_homepage = "http://www.sasview.org"
@@ -56,7 +61,7 @@ _license = "mailto:help at sasview.org"
icon_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "images"))
-logging.info("icon path: %s" % icon_path)
+logger.info("icon path: %s" % icon_path)
media_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "media"))
test_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "test"))
@@ -69,6 +74,7 @@ _ess_logo = os.path.join(icon_path, "ess_logo.png")
_ill_logo = os.path.join(icon_path, "ill_logo.png")
_ansto_logo = os.path.join(icon_path, "ansto_logo.png")
_tudelft_logo = os.path.join(icon_path, "tudelft_logo.png")
+_dls_logo = os.path.join(icon_path, "dls_logo.png")
_nsf_logo = os.path.join(icon_path, "nsf_logo.png")
_danse_logo = os.path.join(icon_path, "danse_logo.png")
_inst_logo = os.path.join(icon_path, "utlogo.gif")
@@ -82,11 +88,12 @@ _ess_url = "http://ess-scandinavia.eu/"
_ill_url = "http://www.ill.eu/"
_ansto_url = "http://www.ansto.gov.au/"
_tudelft_url = "http://www.tnw.tudelft.nl/en/cooperation/facilities/reactor-instituut-delft/"
+_dls_url = "http://www.diamond.ac.uk/"
_danse_url = "http://www.cacr.caltech.edu/projects/danse/release/index.html"
_inst_url = "http://www.utk.edu"
_corner_image = os.path.join(icon_path, "angles_flat.png")
_welcome_image = os.path.join(icon_path, "SVwelcome.png")
-_copyright = "(c) 2009 - 2017, UTK, UMD, NIST, ORNL, ISIS, ESS, ILL, ANSTO and TU Delft"
+_copyright = "(c) 2009 - 2017, UTK, UMD, NIST, ORNL, ISIS, ESS, ILL, ANSTO, TU Delft, and DLS"
marketplace_url = "http://marketplace.sasview.org/"
#edit the list of file state your plugin can read
@@ -137,15 +144,15 @@ DEFAULT_PERSPECTIVE = 'None'
# Time out for updating sasview
UPDATE_TIMEOUT = 2
-#OpenCL option
-SAS_OPENCL = None
+# Time out for updating sasview
+UPDATE_TIMEOUT = 2
def printEVT(message):
if __EVT_DEBUG__:
"""
:TODO - Need method doc string
"""
- print "%g: %s" % (time.clock(), message)
+ print("%g: %s" % (time.clock(), message))
if __EVT_DEBUG_2_FILE__:
out = open(__EVT_DEBUG_FILENAME__, 'a')
diff --git a/sasview/media/README.txt b/src/sas/sasview/media/README.txt
similarity index 100%
rename from sasview/media/README.txt
rename to src/sas/sasview/media/README.txt
diff --git a/sasview/media/Tutorial.pdf b/src/sas/sasview/media/Tutorial.pdf
similarity index 100%
rename from sasview/media/Tutorial.pdf
rename to src/sas/sasview/media/Tutorial.pdf
diff --git a/sasview/media/getting_started_with_sasview.pdf b/src/sas/sasview/media/getting_started_with_sasview.pdf
similarity index 100%
rename from sasview/media/getting_started_with_sasview.pdf
rename to src/sas/sasview/media/getting_started_with_sasview.pdf
diff --git a/src/sas/sasview/sasview.py b/src/sas/sasview/sasview.py
new file mode 100644
index 0000000..68ccad7
--- /dev/null
+++ b/src/sas/sasview/sasview.py
@@ -0,0 +1,254 @@
+# -*- coding: utf-8 -*-
+"""
+Base module for loading and running the main SasView application.
+"""
+################################################################################
+# This software was developed by the University of Tennessee as part of the
+# Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
+# project funded by the US National Science Foundation.
+#
+# See the license text in license.txt
+#
+# copyright 2009, University of Tennessee
+################################################################################
+import os
+import os.path
+import sys
+import traceback
+import logging
+
+try:
+ reload(sys)
+ sys.setdefaultencoding("iso-8859-1")
+except NameError:
+ # On python 3 sys.setdefaultencoding does nothing, so pass.
+ # We know we are in python 3 at this point since reload is no longer in
+ # builtins, but instead has been moved to importlib, hence the NameError.
+ pass
+
+import sas
+
+APP_NAME = 'SasView'
+PLUGIN_MODEL_DIR = 'plugin_models'
+
+class SasView(object):
+ """
+ Main class for running the SasView application
+ """
+ def __init__(self):
+ """
+ """
+ logger = logging.getLogger(__name__)
+
+ from sas.sasgui.guiframe.gui_manager import SasViewApp
+ self.gui = SasViewApp(0)
+ # Set the application manager for the GUI
+ self.gui.set_manager(self)
+ # Add perspectives to the basic application
+ # Additional perspectives can still be loaded
+ # dynamically
+ # Note: py2exe can't find dynamically loaded
+ # modules. We load the fitting module here
+ # to ensure a complete Windows executable build.
+
+ # Rebuild .sasview/categories.json. This triggers a load of sasmodels
+ # and all the plugins.
+ try:
+ from sas.sascalc.fit.models import ModelManager
+ from sas.sasgui.guiframe.CategoryInstaller import CategoryInstaller
+ model_list = ModelManager().cat_model_list()
+ CategoryInstaller.check_install(model_list=model_list)
+ except Exception:
+ logger.error("%s: could not load SasView models")
+ logger.error(traceback.format_exc())
+
+ # Fitting perspective
+ try:
+ import sas.sasgui.perspectives.fitting as module
+ fitting_plug = module.Plugin()
+ self.gui.add_perspective(fitting_plug)
+ except Exception:
+ logger.error("%s: could not find Fitting plug-in module", APP_NAME)
+ logger.error(traceback.format_exc())
+
+ # P(r) perspective
+ try:
+ import sas.sasgui.perspectives.pr as module
+ pr_plug = module.Plugin()
+ self.gui.add_perspective(pr_plug)
+ except Exception:
+ logger.error("%s: could not find P(r) plug-in module", APP_NAME)
+ logger.error(traceback.format_exc())
+
+ # Invariant perspective
+ try:
+ import sas.sasgui.perspectives.invariant as module
+ invariant_plug = module.Plugin()
+ self.gui.add_perspective(invariant_plug)
+ except Exception:
+ logger.error("%s: could not find Invariant plug-in module",
+ APP_NAME)
+ logger.error(traceback.format_exc())
+
+ # Corfunc perspective
+ try:
+ import sas.sasgui.perspectives.corfunc as module
+ corfunc_plug = module.Plugin()
+ self.gui.add_perspective(corfunc_plug)
+ except Exception:
+ logger.error("Unable to load corfunc module")
+
+ # Calculator perspective
+ try:
+ import sas.sasgui.perspectives.calculator as module
+ calculator_plug = module.Plugin()
+ self.gui.add_perspective(calculator_plug)
+ except Exception:
+ logger.error("%s: could not find Calculator plug-in module",
+ APP_NAME)
+ logger.error(traceback.format_exc())
+
+ # File converter tool
+ try:
+ import sas.sasgui.perspectives.file_converter as module
+ converter_plug = module.Plugin()
+ self.gui.add_perspective(converter_plug)
+ except Exception:
+ logger.error("%s: could not find File Converter plug-in module",
+ APP_NAME)
+ logger.error(traceback.format_exc())
+
+ # Add welcome page
+ from .welcome_panel import WelcomePanel
+ self.gui.set_welcome_panel(WelcomePanel)
+
+ # Build the GUI
+ self.gui.build_gui()
+ # delete unused model folder
+ self.gui.clean_plugin_models(PLUGIN_MODEL_DIR)
+ # Start the main loop
+ self.gui.MainLoop()
+
+
+def setup_logging():
+ from sas.logger_config import SetupLogger
+
+ logger = SetupLogger(__name__).config_production()
+ # Log the start of the session
+ logger.info(" --- SasView session started ---")
+ # Log the python version
+ logger.info("Python: %s" % sys.version)
+ return logger
+
+
+def setup_wx():
+ # Allow the dynamic selection of wxPython via an environment variable, when devs
+ # who have multiple versions of the module installed want to pick between them.
+ # This variable does not have to be set of course, and through normal usage will
+ # probably not be, but this can make things a little easier when upgrading to a
+ # new version of wx.
+ logger = logging.getLogger(__name__)
+ WX_ENV_VAR = "SASVIEW_WX_VERSION"
+ if WX_ENV_VAR in os.environ:
+ logger.info("You have set the %s environment variable to %s.",
+ WX_ENV_VAR, os.environ[WX_ENV_VAR])
+ import wxversion
+ if wxversion.checkInstalled(os.environ[WX_ENV_VAR]):
+ logger.info("Version %s of wxPython is installed, so using that version.",
+ os.environ[WX_ENV_VAR])
+ wxversion.select(os.environ[WX_ENV_VAR])
+ else:
+ logger.error("Version %s of wxPython is not installed, so using default version.",
+ os.environ[WX_ENV_VAR])
+ else:
+ logger.info("You have not set the %s environment variable, so using default version of wxPython.",
+ WX_ENV_VAR)
+
+ import wx
+
+ try:
+ logger.info("Wx version: %s", wx.__version__)
+ except AttributeError:
+ logger.error("Wx version: error reading version")
+
+ from . import wxcruft
+ wxcruft.call_later_fix()
+ #wxcruft.trace_new_id()
+ #Always use private .matplotlib setup to avoid conflicts with other
+ #uses of matplotlib
+
+
+def setup_mpl(backend=None):
+ # Always use private .matplotlib setup to avoid conflicts with other
+ mplconfigdir = os.path.join(sas.get_user_dir(), '.matplotlib')
+ if not os.path.exists(mplconfigdir):
+ os.mkdir(mplconfigdir)
+ os.environ['MPLCONFIGDIR'] = mplconfigdir
+ # Set backend to WXAgg; this overrides matplotlibrc, but shouldn't override
+ # mpl.use(). Note: Don't import matplotlib here since the script that
+ # we are running may not actually need it; also, putting as little on the
+ # path as we can
+ if backend:
+ os.environ['MPLBACKEND'] = backend
+
+ # TODO: ... so much for not importing matplotlib unless we need it...
+ from matplotlib import backend_bases
+ backend_bases.FigureCanvasBase.filetypes.pop('pgf', None)
+
+def setup_sasmodels():
+ """
+ Prepare sasmodels for running within sasview.
+ """
+ # Set SAS_MODELPATH so sasmodels can find our custom models
+ plugin_dir = os.path.join(sas.get_user_dir(), PLUGIN_MODEL_DIR)
+ os.environ['SAS_MODELPATH'] = plugin_dir
+ #Initiliaze enviromental variable with custom setting but only if variable not set
+ SAS_OPENCL = sas.get_custom_config().SAS_OPENCL
+ if SAS_OPENCL and "SAS_OPENCL" not in os.environ:
+ os.environ["SAS_OPENCL"] = SAS_OPENCL
+
+def run_gui():
+ """
+ __main__ method for loading and running SasView
+ """
+ from multiprocessing import freeze_support
+ freeze_support()
+ setup_logging()
+ setup_mpl(backend='WXAgg')
+ setup_sasmodels()
+ setup_wx()
+ SasView()
+
+
+def run_cli():
+ from multiprocessing import freeze_support
+ freeze_support()
+ setup_logging()
+ # Use default matplotlib backend on mac/linux, but wx on windows.
+ # The problem on mac is that the wx backend requires pythonw. On windows
+ # we are sure to wx since it is the shipped with the app.
+ setup_mpl(backend='WXAgg' if os.name == 'nt' else None)
+ setup_sasmodels()
+ if len(sys.argv) == 1 or sys.argv[1] == '-i':
+ # Run sasview as an interactive python interpreter
+ try:
+ from IPython import start_ipython
+ sys.argv = ["ipython", "--pylab"]
+ sys.exit(start_ipython())
+ except ImportError:
+ import code
+ code.interact(local={'exit': sys.exit})
+ elif sys.argv[1] == '-c':
+ exec(sys.argv[2])
+ else:
+ thing_to_run = sys.argv[1]
+ sys.argv = sys.argv[1:]
+ import runpy
+ if os.path.exists(thing_to_run):
+ runpy.run_path(thing_to_run, run_name="__main__")
+ else:
+ runpy.run_module(thing_to_run, run_name="__main__")
+
+
+if __name__ == "__main__":
+ run_gui()
diff --git a/sasview/test/1d_data/ testdata_line1.txt b/src/sas/sasview/test/1d_data/ testdata_line1.txt
similarity index 100%
rename from sasview/test/1d_data/ testdata_line1.txt
rename to src/sas/sasview/test/1d_data/ testdata_line1.txt
diff --git a/sasview/test/1d_data/1000A_sphere_dsm.xml b/src/sas/sasview/test/1d_data/1000A_sphere_dsm.xml
similarity index 100%
rename from sasview/test/1d_data/1000A_sphere_dsm.xml
rename to src/sas/sasview/test/1d_data/1000A_sphere_dsm.xml
diff --git a/sasview/test/1d_data/10wtAOT_Reline_120_reduced.pdh b/src/sas/sasview/test/1d_data/10wtAOT_Reline_120_reduced.pdh
similarity index 100%
rename from sasview/test/1d_data/10wtAOT_Reline_120_reduced.pdh
rename to src/sas/sasview/test/1d_data/10wtAOT_Reline_120_reduced.pdh
diff --git a/sasview/test/1d_data/33837rear_1D_1.75_16.5_CanSAS1D.xml b/src/sas/sasview/test/1d_data/33837rear_1D_1.75_16.5_CanSAS1D.xml
similarity index 100%
rename from sasview/test/1d_data/33837rear_1D_1.75_16.5_CanSAS1D.xml
rename to src/sas/sasview/test/1d_data/33837rear_1D_1.75_16.5_CanSAS1D.xml
diff --git a/sasview/test/1d_data/33837rear_1D_1.75_16.5_NXcanSAS.h5 b/src/sas/sasview/test/1d_data/33837rear_1D_1.75_16.5_NXcanSAS.h5
similarity index 100%
rename from sasview/test/1d_data/33837rear_1D_1.75_16.5_NXcanSAS.h5
rename to src/sas/sasview/test/1d_data/33837rear_1D_1.75_16.5_NXcanSAS.h5
diff --git a/sasview/test/1d_data/33837rear_1D_1.75_16.5_NXcanSAS_v3.h5 b/src/sas/sasview/test/1d_data/33837rear_1D_1.75_16.5_NXcanSAS_v3.h5
similarity index 100%
rename from sasview/test/1d_data/33837rear_1D_1.75_16.5_NXcanSAS_v3.h5
rename to src/sas/sasview/test/1d_data/33837rear_1D_1.75_16.5_NXcanSAS_v3.h5
diff --git a/sasview/test/1d_data/AOT_Microemulsion-Core_Contrast.xml b/src/sas/sasview/test/1d_data/AOT_Microemulsion-Core_Contrast.xml
similarity index 100%
rename from sasview/test/1d_data/AOT_Microemulsion-Core_Contrast.xml
rename to src/sas/sasview/test/1d_data/AOT_Microemulsion-Core_Contrast.xml
diff --git a/sasview/test/1d_data/AOT_Microemulsion-Drop_Contrast.xml b/src/sas/sasview/test/1d_data/AOT_Microemulsion-Drop_Contrast.xml
similarity index 100%
rename from sasview/test/1d_data/AOT_Microemulsion-Drop_Contrast.xml
rename to src/sas/sasview/test/1d_data/AOT_Microemulsion-Drop_Contrast.xml
diff --git a/sasview/test/1d_data/AOT_Microemulsion-Shell_Contrast.xml b/src/sas/sasview/test/1d_data/AOT_Microemulsion-Shell_Contrast.xml
similarity index 100%
rename from sasview/test/1d_data/AOT_Microemulsion-Shell_Contrast.xml
rename to src/sas/sasview/test/1d_data/AOT_Microemulsion-Shell_Contrast.xml
diff --git a/sasview/test/1d_data/APS_DND-CAT.TXT b/src/sas/sasview/test/1d_data/APS_DND-CAT.TXT
similarity index 100%
rename from sasview/test/1d_data/APS_DND-CAT.TXT
rename to src/sas/sasview/test/1d_data/APS_DND-CAT.TXT
diff --git a/sasview/test/1d_data/Anton-Paar.pdh b/src/sas/sasview/test/1d_data/Anton-Paar.pdh
similarity index 100%
rename from sasview/test/1d_data/Anton-Paar.pdh
rename to src/sas/sasview/test/1d_data/Anton-Paar.pdh
diff --git a/sasview/test/1d_data/CoreXY_ShellZ.txt b/src/sas/sasview/test/1d_data/CoreXY_ShellZ.txt
similarity index 100%
rename from sasview/test/1d_data/CoreXY_ShellZ.txt
rename to src/sas/sasview/test/1d_data/CoreXY_ShellZ.txt
diff --git a/sasview/test/1d_data/ISIS_83404.TXT b/src/sas/sasview/test/1d_data/ISIS_83404.TXT
similarity index 100%
rename from sasview/test/1d_data/ISIS_83404.TXT
rename to src/sas/sasview/test/1d_data/ISIS_83404.TXT
diff --git a/sasview/test/1d_data/ISIS_98929.TXT b/src/sas/sasview/test/1d_data/ISIS_98929.TXT
similarity index 100%
rename from sasview/test/1d_data/ISIS_98929.TXT
rename to src/sas/sasview/test/1d_data/ISIS_98929.TXT
diff --git a/sasview/test/1d_data/ISIS_Polymer_Blend_TK49.xml b/src/sas/sasview/test/1d_data/ISIS_Polymer_Blend_TK49.xml
similarity index 100%
copy from sasview/test/1d_data/ISIS_Polymer_Blend_TK49.xml
copy to src/sas/sasview/test/1d_data/ISIS_Polymer_Blend_TK49.xml
diff --git a/sasview/test/1d_data/P123_D2O_10_percent.xml b/src/sas/sasview/test/1d_data/P123_D2O_10_percent.xml
similarity index 100%
rename from sasview/test/1d_data/P123_D2O_10_percent.xml
rename to src/sas/sasview/test/1d_data/P123_D2O_10_percent.xml
diff --git a/sasview/test/1d_data/P123_D2O_30_percent.xml b/src/sas/sasview/test/1d_data/P123_D2O_30_percent.xml
similarity index 100%
rename from sasview/test/1d_data/P123_D2O_30_percent.xml
rename to src/sas/sasview/test/1d_data/P123_D2O_30_percent.xml
diff --git a/sasview/test/1d_data/P123_D2O_40_percent.xml b/src/sas/sasview/test/1d_data/P123_D2O_40_percent.xml
similarity index 100%
rename from sasview/test/1d_data/P123_D2O_40_percent.xml
rename to src/sas/sasview/test/1d_data/P123_D2O_40_percent.xml
diff --git a/sasview/test/1d_data/PolySpheres.txt b/src/sas/sasview/test/1d_data/PolySpheres.txt
similarity index 100%
rename from sasview/test/1d_data/PolySpheres.txt
rename to src/sas/sasview/test/1d_data/PolySpheres.txt
diff --git a/sasview/test/1d_data/beam profile.DAT b/src/sas/sasview/test/1d_data/beam profile.DAT
similarity index 100%
rename from sasview/test/1d_data/beam profile.DAT
rename to src/sas/sasview/test/1d_data/beam profile.DAT
diff --git a/sasview/test/1d_data/circular_test.txt b/src/sas/sasview/test/1d_data/circular_test.txt
similarity index 100%
rename from sasview/test/1d_data/circular_test.txt
rename to src/sas/sasview/test/1d_data/circular_test.txt
diff --git a/sasview/test/1d_data/cyl_400_20.txt b/src/sas/sasview/test/1d_data/cyl_400_20.txt
similarity index 100%
rename from sasview/test/1d_data/cyl_400_20.txt
rename to src/sas/sasview/test/1d_data/cyl_400_20.txt
diff --git a/sasview/test/1d_data/cyl_400_40.txt b/src/sas/sasview/test/1d_data/cyl_400_40.txt
similarity index 100%
rename from sasview/test/1d_data/cyl_400_40.txt
rename to src/sas/sasview/test/1d_data/cyl_400_40.txt
diff --git a/sasview/test/1d_data/cyl_testdata.txt b/src/sas/sasview/test/1d_data/cyl_testdata.txt
similarity index 100%
rename from sasview/test/1d_data/cyl_testdata.txt
rename to src/sas/sasview/test/1d_data/cyl_testdata.txt
diff --git a/sasview/test/1d_data/cyl_testdata1.txt b/src/sas/sasview/test/1d_data/cyl_testdata1.txt
similarity index 100%
rename from sasview/test/1d_data/cyl_testdata1.txt
rename to src/sas/sasview/test/1d_data/cyl_testdata1.txt
diff --git a/sasview/test/1d_data/cyl_testdata2.txt b/src/sas/sasview/test/1d_data/cyl_testdata2.txt
similarity index 100%
rename from sasview/test/1d_data/cyl_testdata2.txt
rename to src/sas/sasview/test/1d_data/cyl_testdata2.txt
diff --git a/sasview/test/1d_data/hSDS_D2O_0p5_percent.xml b/src/sas/sasview/test/1d_data/hSDS_D2O_0p5_percent.xml
similarity index 100%
rename from sasview/test/1d_data/hSDS_D2O_0p5_percent.xml
rename to src/sas/sasview/test/1d_data/hSDS_D2O_0p5_percent.xml
diff --git a/sasview/test/1d_data/hSDS_D2O_2p0_percent.xml b/src/sas/sasview/test/1d_data/hSDS_D2O_2p0_percent.xml
similarity index 100%
rename from sasview/test/1d_data/hSDS_D2O_2p0_percent.xml
rename to src/sas/sasview/test/1d_data/hSDS_D2O_2p0_percent.xml
diff --git a/sasview/test/1d_data/hSDS_D2O_2p0_percent_0p2M_NaCl.xml b/src/sas/sasview/test/1d_data/hSDS_D2O_2p0_percent_0p2M_NaCl.xml
similarity index 100%
rename from sasview/test/1d_data/hSDS_D2O_2p0_percent_0p2M_NaCl.xml
rename to src/sas/sasview/test/1d_data/hSDS_D2O_2p0_percent_0p2M_NaCl.xml
diff --git a/sasview/test/1d_data/latex_smeared.xml b/src/sas/sasview/test/1d_data/latex_smeared.xml
similarity index 100%
rename from sasview/test/1d_data/latex_smeared.xml
rename to src/sas/sasview/test/1d_data/latex_smeared.xml
diff --git a/sasview/test/1d_data/rpa_igor.txt b/src/sas/sasview/test/1d_data/rpa_igor.txt
similarity index 100%
rename from sasview/test/1d_data/rpa_igor.txt
rename to src/sas/sasview/test/1d_data/rpa_igor.txt
diff --git a/sasview/test/1d_data/saxess_example.pdh b/src/sas/sasview/test/1d_data/saxess_example.pdh
similarity index 100%
rename from sasview/test/1d_data/saxess_example.pdh
rename to src/sas/sasview/test/1d_data/saxess_example.pdh
diff --git a/sasview/test/1d_data/sphere_60_q0_2.txt b/src/sas/sasview/test/1d_data/sphere_60_q0_2.txt
similarity index 100%
rename from sasview/test/1d_data/sphere_60_q0_2.txt
rename to src/sas/sasview/test/1d_data/sphere_60_q0_2.txt
diff --git a/sasview/test/1d_data/sphere_80.txt b/src/sas/sasview/test/1d_data/sphere_80.txt
similarity index 100%
rename from sasview/test/1d_data/sphere_80.txt
rename to src/sas/sasview/test/1d_data/sphere_80.txt
diff --git a/sasview/test/1d_data/testdata_line.txt b/src/sas/sasview/test/1d_data/testdata_line.txt
similarity index 100%
rename from sasview/test/1d_data/testdata_line.txt
rename to src/sas/sasview/test/1d_data/testdata_line.txt
diff --git a/sasview/test/1d_data/testdata_line3.txt b/src/sas/sasview/test/1d_data/testdata_line3.txt
similarity index 100%
rename from sasview/test/1d_data/testdata_line3.txt
rename to src/sas/sasview/test/1d_data/testdata_line3.txt
diff --git a/sasview/test/2d_data/14250_2D_NoDetInfo_NXcanSAS_v3.h5 b/src/sas/sasview/test/2d_data/14250_2D_NoDetInfo_NXcanSAS_v3.h5
similarity index 100%
rename from sasview/test/2d_data/14250_2D_NoDetInfo_NXcanSAS_v3.h5
rename to src/sas/sasview/test/2d_data/14250_2D_NoDetInfo_NXcanSAS_v3.h5
diff --git a/sasview/test/2d_data/2P_New.sans b/src/sas/sasview/test/2d_data/2P_New.sans
similarity index 100%
rename from sasview/test/2d_data/2P_New.sans
rename to src/sas/sasview/test/2d_data/2P_New.sans
diff --git a/sasview/test/2d_data/33837rear_2D_1.75_16.5_NIST.dat b/src/sas/sasview/test/2d_data/33837rear_2D_1.75_16.5_NIST.dat
similarity index 100%
rename from sasview/test/2d_data/33837rear_2D_1.75_16.5_NIST.dat
rename to src/sas/sasview/test/2d_data/33837rear_2D_1.75_16.5_NIST.dat
diff --git a/sasview/test/2d_data/33837rear_2D_1.75_16.5_NXcanSAS.h5 b/src/sas/sasview/test/2d_data/33837rear_2D_1.75_16.5_NXcanSAS.h5
similarity index 100%
rename from sasview/test/2d_data/33837rear_2D_1.75_16.5_NXcanSAS.h5
rename to src/sas/sasview/test/2d_data/33837rear_2D_1.75_16.5_NXcanSAS.h5
diff --git a/sasview/test/2d_data/33837rear_2D_1.75_16.5_NXcanSAS_v3.h5 b/src/sas/sasview/test/2d_data/33837rear_2D_1.75_16.5_NXcanSAS_v3.h5
similarity index 100%
rename from sasview/test/2d_data/33837rear_2D_1.75_16.5_NXcanSAS_v3.h5
rename to src/sas/sasview/test/2d_data/33837rear_2D_1.75_16.5_NXcanSAS_v3.h5
diff --git a/sasview/test/2d_data/P123_D2O_10_percent.dat b/src/sas/sasview/test/2d_data/P123_D2O_10_percent.dat
similarity index 100%
rename from sasview/test/2d_data/P123_D2O_10_percent.dat
rename to src/sas/sasview/test/2d_data/P123_D2O_10_percent.dat
diff --git a/sasview/test/2d_data/P123_D2O_30_percent.dat b/src/sas/sasview/test/2d_data/P123_D2O_30_percent.dat
similarity index 100%
rename from sasview/test/2d_data/P123_D2O_30_percent.dat
rename to src/sas/sasview/test/2d_data/P123_D2O_30_percent.dat
diff --git a/sasview/test/2d_data/P123_D2O_40_percent.dat b/src/sas/sasview/test/2d_data/P123_D2O_40_percent.dat
similarity index 100%
rename from sasview/test/2d_data/P123_D2O_40_percent.dat
rename to src/sas/sasview/test/2d_data/P123_D2O_40_percent.dat
diff --git a/sasview/test/2d_data/P_New.sans b/src/sas/sasview/test/2d_data/P_New.sans
similarity index 100%
rename from sasview/test/2d_data/P_New.sans
rename to src/sas/sasview/test/2d_data/P_New.sans
diff --git a/sasview/test/2d_data/SILIC010.DAT b/src/sas/sasview/test/2d_data/SILIC010.DAT
similarity index 100%
rename from sasview/test/2d_data/SILIC010.DAT
rename to src/sas/sasview/test/2d_data/SILIC010.DAT
diff --git a/sasview/test/2d_data/SILIC010_noheader.DAT b/src/sas/sasview/test/2d_data/SILIC010_noheader.DAT
similarity index 100%
rename from sasview/test/2d_data/SILIC010_noheader.DAT
rename to src/sas/sasview/test/2d_data/SILIC010_noheader.DAT
diff --git a/sasview/test/2d_data/SILIC010_noheader_3col.DAT b/src/sas/sasview/test/2d_data/SILIC010_noheader_3col.DAT
similarity index 100%
rename from sasview/test/2d_data/SILIC010_noheader_3col.DAT
rename to src/sas/sasview/test/2d_data/SILIC010_noheader_3col.DAT
diff --git a/sasview/test/2d_data/exp18_14_igor_2dqxqy.dat b/src/sas/sasview/test/2d_data/exp18_14_igor_2dqxqy.dat
similarity index 100%
rename from sasview/test/2d_data/exp18_14_igor_2dqxqy.dat
rename to src/sas/sasview/test/2d_data/exp18_14_igor_2dqxqy.dat
diff --git a/sasview/test/README.txt b/src/sas/sasview/test/README.txt
similarity index 100%
rename from sasview/test/README.txt
rename to src/sas/sasview/test/README.txt
diff --git a/sasview/test/convertible_files/APS_X.TXT b/src/sas/sasview/test/convertible_files/APS_X.TXT
similarity index 100%
rename from sasview/test/convertible_files/APS_X.TXT
rename to src/sas/sasview/test/convertible_files/APS_X.TXT
diff --git a/sasview/test/convertible_files/APS_Y.TXT b/src/sas/sasview/test/convertible_files/APS_Y.TXT
similarity index 100%
rename from sasview/test/convertible_files/APS_Y.TXT
rename to src/sas/sasview/test/convertible_files/APS_Y.TXT
diff --git a/sasview/test/convertible_files/FIT2D_I.TXT b/src/sas/sasview/test/convertible_files/FIT2D_I.TXT
similarity index 100%
rename from sasview/test/convertible_files/FIT2D_I.TXT
rename to src/sas/sasview/test/convertible_files/FIT2D_I.TXT
diff --git a/sasview/test/convertible_files/FIT2D_Q.TXT b/src/sas/sasview/test/convertible_files/FIT2D_Q.TXT
similarity index 100%
rename from sasview/test/convertible_files/FIT2D_Q.TXT
rename to src/sas/sasview/test/convertible_files/FIT2D_Q.TXT
diff --git a/src/sas/sasview/test/convertible_files/SANS2D_100254_merged_ISIS2D.txt b/src/sas/sasview/test/convertible_files/SANS2D_100254_merged_ISIS2D.txt
new file mode 100644
index 0000000..67782fe
--- /dev/null
+++ b/src/sas/sasview/test/convertible_files/SANS2D_100254_merged_ISIS2D.txt
@@ -0,0 +1,2536 @@
+ LOQ Wed 31-MAY-2017 16:13 Workspace: shirin100254_merged_cloned_temp
+ 6 q (Angstrom^-1)
+ 6 q (Angstrom^-1)
+ 0 I(q) (cm-1)
+ 1
+ 4H_35oC_10%_CH_R_SANS
+ 101
+ -4.000000e-01 -3.920000e-01 -3.840000e-01 -3.760000e-01 -3.680000e-01 -3.600000e-01 -3.520000e-01 -3.440000e-01
+ -3.360000e-01 -3.280000e-01 -3.200000e-01 -3.120000e-01 -3.040000e-01 -2.960000e-01 -2.880000e-01 -2.800000e-01
+ -2.720000e-01 -2.640000e-01 -2.560000e-01 -2.480000e-01 -2.400000e-01 -2.320000e-01 -2.240000e-01 -2.160000e-01
+ -2.080000e-01 -2.000000e-01 -1.920000e-01 -1.840000e-01 -1.760000e-01 -1.680000e-01 -1.600000e-01 -1.520000e-01
+ -1.440000e-01 -1.360000e-01 -1.280000e-01 -1.200000e-01 -1.120000e-01 -1.040000e-01 -9.600000e-02 -8.800000e-02
+ -8.000000e-02 -7.200000e-02 -6.400000e-02 -5.600000e-02 -4.800000e-02 -4.000000e-02 -3.200000e-02 -2.400000e-02
+ -1.600000e-02 -8.000000e-03 0.000000e+00 8.000000e-03 1.600000e-02 2.400000e-02 3.200000e-02 4.000000e-02
+ 4.800000e-02 5.600000e-02 6.400000e-02 7.200000e-02 8.000000e-02 8.800000e-02 9.600000e-02 1.040000e-01
+ 1.120000e-01 1.200000e-01 1.280000e-01 1.360000e-01 1.440000e-01 1.520000e-01 1.600000e-01 1.680000e-01
+ 1.760000e-01 1.840000e-01 1.920000e-01 2.000000e-01 2.080000e-01 2.160000e-01 2.240000e-01 2.320000e-01
+ 2.400000e-01 2.480000e-01 2.560000e-01 2.640000e-01 2.720000e-01 2.800000e-01 2.880000e-01 2.960000e-01
+ 3.040000e-01 3.120000e-01 3.200000e-01 3.280000e-01 3.360000e-01 3.440000e-01 3.520000e-01 3.600000e-01
+ 3.680000e-01 3.760000e-01 3.840000e-01 3.920000e-01 4.000000e-01
+ 100
+ -4.000000e-01 -3.920000e-01 -3.840000e-01 -3.760000e-01 -3.680000e-01 -3.600000e-01 -3.520000e-01 -3.440000e-01
+ -3.360000e-01 -3.280000e-01 -3.200000e-01 -3.120000e-01 -3.040000e-01 -2.960000e-01 -2.880000e-01 -2.800000e-01
+ -2.720000e-01 -2.640000e-01 -2.560000e-01 -2.480000e-01 -2.400000e-01 -2.320000e-01 -2.240000e-01 -2.160000e-01
+ -2.080000e-01 -2.000000e-01 -1.920000e-01 -1.840000e-01 -1.760000e-01 -1.680000e-01 -1.600000e-01 -1.520000e-01
+ -1.440000e-01 -1.360000e-01 -1.280000e-01 -1.200000e-01 -1.120000e-01 -1.040000e-01 -9.600000e-02 -8.800000e-02
+ -8.000000e-02 -7.200000e-02 -6.400000e-02 -5.600000e-02 -4.800000e-02 -4.000000e-02 -3.200000e-02 -2.400000e-02
+ -1.600000e-02 -8.000000e-03 0.000000e+00 8.000000e-03 1.600000e-02 2.400000e-02 3.200000e-02 4.000000e-02
+ 4.800000e-02 5.600000e-02 6.400000e-02 7.200000e-02 8.000000e-02 8.800000e-02 9.600000e-02 1.040000e-01
+ 1.120000e-01 1.200000e-01 1.280000e-01 1.360000e-01 1.440000e-01 1.520000e-01 1.600000e-01 1.680000e-01
+ 1.760000e-01 1.840000e-01 1.920000e-01 2.000000e-01 2.080000e-01 2.160000e-01 2.240000e-01 2.320000e-01
+ 2.400000e-01 2.480000e-01 2.560000e-01 2.640000e-01 2.720000e-01 2.800000e-01 2.880000e-01 2.960000e-01
+ 3.040000e-01 3.120000e-01 3.200000e-01 3.280000e-01 3.360000e-01 3.440000e-01 3.520000e-01 3.600000e-01
+ 3.680000e-01 3.760000e-01 3.840000e-01 3.920000e-01
+ 100 100 1.000000000000e+00
+ 3(8E12.4)
+ -nan(ind) -1.0525e-01 5.3607e-02 -nan(ind) 3.9454e-02 1.4885e-01 1.5108e-01 9.9900e-02
+ 1.3403e-01 4.2078e-02 6.8270e-02 -3.6101e-02 7.0154e-02 -3.4934e-02 8.0033e-02 6.2179e-02
+ -3.8732e-02 1.5814e-02 -1.8266e-03 4.6180e-02 3.6422e-02 1.2568e-01 3.2525e-02 4.9334e-02
+ -nan(ind) 1.0793e-01 -nan(ind) 8.9821e-02 1.4231e-01 5.2486e-02 1.0637e-02 4.2594e-03
+ 1.9238e-02 1.6338e-01 7.2472e-02 5.4136e-02 1.0557e-01 4.8344e-02 2.1668e-02 3.7989e-02
+ 5.1146e-02 1.0497e-01 4.3021e-02 2.1228e-03 8.3914e-02 -3.4819e-02 -3.2711e-02 1.9757e-02
+ 6.8603e-02 -nan(ind) -nan(ind) 2.2801e-02 7.7157e-02 6.0645e-02 8.9023e-02 2.5131e-02
+ 7.3107e-02 -1.6954e-02 3.9819e-02 2.5651e-02 4.9684e-03 5.1803e-02 9.6730e-02 1.8206e-02
+ 4.7966e-02 -2.5755e-02 3.3369e-02 -7.7763e-03 5.4264e-02 2.8716e-02 1.9280e-01 5.6106e-02
+ 1.5318e-02 -nan(ind) -4.2374e-04 9.5753e-02 1.7750e-01 9.5618e-02 1.5884e-01 1.7463e-01
+ 5.5122e-02 1.3482e-01 4.6359e-02 -1.4194e-02 4.4475e-02 5.1021e-02 2.1995e-02 3.6241e-02
+ 5.2519e-02 6.7380e-02 -2.7038e-02 1.0800e-01 4.5542e-02 -nan(ind) 1.0950e-01 3.6368e-02
+ 2.0734e-01 -1.7062e-02 6.6028e-02 1.9050e-01 3.7065e-02 -nan(ind) -nan(ind) 4.2969e-02
+ 1.6267e-01 1.6100e-03 3.9701e-02 3.7933e-02 1.6678e-01 -1.9933e-02 -2.1710e-02 3.0543e-03
+ 4.4295e-02 -2.0693e-02 2.2099e-01 -1.2266e-04 -1.9783e-02 -9.0749e-02 -4.1148e-02 -3.2467e-02
+ -nan(ind) 4.2323e-02 1.0833e-01 4.6421e-02 3.1483e-02 7.5865e-02 -nan(ind) 3.0220e-02
+ 4.3001e-02 4.2737e-04 6.7884e-02 8.1966e-03 -1.9023e-01 -1.8863e-03 -6.7377e-03 -nan(ind)
+ 1.3797e-01 -2.5427e-03 1.8941e-01 -3.9566e-03 3.7473e-02 3.8241e-02 -1.9006e-02 9.9039e-02
+ 1.2009e-01 1.1343e-01 -1.8961e-02 1.0829e-01 2.0974e-03 -nan(ind) -nan(ind) 4.4130e-02
+ -3.6635e-02 8.3068e-02 -1.6576e-02 7.9953e-02 7.5209e-02 -nan(ind) 1.2942e-01 1.8080e-02
+ -2.1576e-02 6.5966e-02 6.9974e-02 -2.0994e-02 -nan(ind) 1.3177e-01 6.1811e-02 4.1733e-02
+ 6.8319e-02 1.1415e-02 5.6416e-02 2.2133e-01 1.0652e-02 4.8750e-02 -2.9026e-02 4.9601e-02
+ 5.6739e-03 1.2854e-01 6.9937e-02 -nan(ind) 1.6099e-01 -5.7955e-03 1.2356e-01 5.7804e-02
+ 1.7093e-02 -4.4861e-02 2.5516e-03 -2.3429e-02 2.4602e-02 4.7411e-02 1.2204e-01 -2.8762e-02
+ 7.2634e-02 6.6155e-02 2.5183e-02 7.3518e-02 7.6321e-02 -nan(ind) -nan(ind) 5.7794e-02
+ 1.2690e-01 1.1018e-01 -nan(ind) -6.6913e-02 1.7995e-02 2.9867e-02 2.5404e-02 -5.9859e-03
+ 7.3091e-02 1.2638e-01 -1.7867e-02 1.0881e-02 1.5369e-01 1.2281e-01 -4.5223e-02 2.7124e-02
+ -3.0940e-02 -4.3570e-02 -nan(ind) -2.8975e-02 3.4576e-02 2.6902e-02 1.0108e-01 -9.3490e-03
+ 7.5623e-02 -2.4298e-03 4.8663e-02 -1.1718e-01 5.7652e-02 7.1712e-02 -9.8116e-03 -nan(ind)
+ 1.4233e-01 6.1138e-03 1.6783e-01 5.3313e-02 5.6982e-02 -3.2477e-02 1.1219e-01 2.3134e-02
+ 8.5924e-02 1.1619e-01 1.0377e-01 -5.3248e-02 -1.0134e-01 1.4659e-01 -2.8172e-01 -2.2994e-02
+ 6.8704e-02 -nan(ind) -nan(ind) 5.7729e-02 7.3184e-02 1.6849e-01 -5.8621e-02 8.3149e-02
+ 1.2524e-01 4.4969e-02 -3.7354e-02 -1.2641e-02 3.9154e-02 1.4862e-01 4.8236e-02 -8.2758e-04
+ 8.2049e-02 1.6774e-01 7.5753e-02 1.0404e-01 5.2222e-02 1.2990e-01 -1.4302e-02 9.9629e-03
+ -1.7712e-02 8.3543e-02 2.0072e-02 4.1279e-02 -1.9428e-02 1.7351e-01 1.7977e-01 9.0465e-03
+ 2.8267e-03 5.0260e-02 -2.4212e-02 4.9677e-02 1.5767e-01 3.2892e-02 7.1650e-02 1.4790e-01
+ 2.6109e-01 3.0975e-02 4.4608e-02 5.4250e-02 8.4806e-02 -3.5203e-02 1.7679e-02 -4.4677e-02
+ 5.3700e-02 1.0455e-01 -1.1854e-02 9.8913e-02 -nan(ind) 7.8427e-02 1.1572e-02 7.9635e-02
+ -5.3672e-02 1.0890e-01 1.4559e-01 -5.5341e-02 -8.5723e-02 1.2961e-01 6.4912e-02 6.3307e-02
+ 2.9198e-02 -4.7224e-02 -nan(ind) 7.3382e-04 1.1815e-01 -5.3883e-02 -1.6360e-02 4.7676e-04
+ -3.9281e-02 7.5479e-02 4.0818e-02 1.0726e-01 -3.4141e-02 4.7958e-02 -nan(ind) 7.4502e-02
+ -8.9350e-03 2.3773e-02 2.8429e-02 1.3012e-02 9.3985e-03 9.6396e-02 4.4804e-02 -6.6491e-02
+ 5.8886e-02 1.1382e-02 2.4035e-02 1.8436e-01 -1.0654e-02 4.2762e-02 4.8649e-02 4.9389e-02
+ 1.1593e-01 3.9946e-02 1.0202e-01 1.3341e-01 -1.8518e-03 -nan(ind) -nan(ind) 4.7445e-02
+ 2.6661e-02 9.9812e-02 -8.2566e-03 8.9175e-03 4.9915e-02 7.9925e-03 2.7326e-02 1.0044e-01
+ 1.3786e-02 1.8974e-03 2.1404e-02 1.6999e-01 4.6865e-02 5.7738e-02 1.2999e-01 5.3744e-02
+ 1.6652e-01 3.1783e-02 1.7646e-02 8.1407e-04 8.7677e-02 -nan(ind) 8.5914e-02 -3.6650e-03
+ 2.6118e-02 7.0212e-02 1.4928e-01 -2.1209e-02 4.9784e-02 -2.0209e-02 5.2085e-02 9.0221e-02
+ -2.8681e-02 1.0666e-02 9.8063e-02 6.7675e-02 1.3525e-01 9.2873e-02 -1.6222e-01 2.9391e-02
+ 1.3759e-02 2.9074e-02 6.0143e-02 6.0044e-02 -7.8331e-02 7.0003e-02 2.9479e-03 -7.2614e-02
+ 1.1446e-01 1.0687e-01 6.1962e-02 -4.9304e-03 -nan(ind) -1.8232e-02 4.7368e-02 -9.1356e-02
+ 1.9286e-02 7.0840e-02 1.6422e-01 5.6202e-02 6.9414e-02 4.8259e-02 1.8709e-02 6.6031e-02
+ -2.4125e-02 8.3695e-02 4.4705e-02 6.6256e-02 4.1017e-02 3.3924e-03 7.5265e-04 7.8518e-02
+ -nan(ind) -nan(ind) 4.2834e-02 5.0312e-02 1.0038e-01 -nan(ind) -nan(ind) 9.3690e-02
+ 8.8057e-02 2.4295e-01 -2.9206e-02 1.2324e-01 -4.1395e-02 3.0913e-02 6.2539e-02 -2.5777e-02
+ -7.3811e-03 -1.0458e-01 -1.4835e-02 3.9537e-02 1.0337e-01 8.2623e-02 -1.7670e-01 9.7622e-02
+ 7.0866e-03 -nan(ind) -nan(ind) -1.3517e-02 -nan(ind) 3.6238e-02 1.0188e-01 1.0070e-01
+ 1.4776e-01 9.8573e-02 1.9802e-01 -2.6932e-02 1.4095e-02 1.0946e-02 4.7210e-03 -1.7055e-01
+ 7.9334e-02 1.4969e-01 7.4391e-02 -nan(ind) 5.5892e-03 -nan(ind) -nan(ind) 3.9915e-02
+ 2.4626e-01 -1.0773e-01 -nan(ind) 6.0126e-02 5.3855e-02 9.1038e-02 4.5513e-02 6.6055e-03
+ 1.6199e-02 1.1595e-01 3.8978e-02 4.6781e-02 3.0932e-02 4.6115e-02 2.6480e-02 9.7301e-02
+ 6.1460e-02 7.6514e-02 -1.6583e-02 2.9066e-01 -1.5440e-02 1.4699e-02 -1.3583e-01 9.2275e-02
+ 4.5953e-02 -nan(ind) 9.2212e-02 5.7230e-02 -nan(ind) 7.2853e-02 8.0810e-02 9.2601e-02
+ 7.8193e-02 5.9278e-02 -4.9314e-03 6.5360e-02 9.6639e-02 2.7527e-02 -nan(ind) -2.7409e-03
+ 7.8586e-02 -nan(ind) -1.3906e-02 6.8593e-02 -9.6609e-02 1.1611e-01 1.3705e-01 1.0468e-01
+ 2.0975e-02 1.8204e-01 3.8348e-02 5.4421e-03 -7.0664e-03 1.8360e-02 -1.3953e-02 -1.6804e-02
+ -nan(ind) 3.0057e-03 1.9775e-02 1.0047e-01 1.7658e-02 7.7949e-02 7.6762e-02 4.2155e-02
+ 9.5742e-02 4.7743e-02 6.7483e-02 2.0728e-02 7.6998e-02 3.2972e-02 7.8225e-02 6.7808e-02
+ 1.3471e-01 8.7665e-02 1.6303e-01 7.9568e-02 9.2503e-02 -nan(ind) -nan(ind) 3.9671e-02
+ 7.4042e-02 -6.2968e-02 4.6741e-02 4.1245e-02 6.0290e-02 1.6756e-01 8.7522e-02 -2.4108e-04
+ -2.1461e-02 1.3015e-01 4.4760e-02 1.0332e-01 1.2132e-01 1.0467e-01 1.2193e-01 -6.7466e-03
+ -4.0257e-03 -6.6438e-02 5.7166e-02 1.8653e-02 1.1257e-01 7.8666e-02 5.8401e-02 2.2492e-02
+ 5.1131e-02 2.3619e-02 2.4071e-02 1.0765e-01 3.9634e-02 1.5020e-01 7.5506e-03 9.1675e-02
+ 7.5657e-02 2.1238e-02 1.0503e-01 2.5233e-02 -2.2262e-02 7.2462e-02 6.6828e-02 -2.1326e-02
+ 3.2008e-02 1.3782e-01 -1.3642e-04 2.2626e-02 1.4605e-01 1.3477e-01 3.5080e-02 -7.6104e-02
+ -4.0577e-02 1.2342e-01 4.9626e-02 6.1635e-03 1.2115e-02 3.1466e-02 -nan(ind) -4.9714e-02
+ 5.7990e-02 1.0978e-01 -8.8962e-02 9.4179e-02 1.1118e-01 1.1234e-01 1.8259e-01 -7.2983e-02
+ 1.6508e-02 -5.0503e-02 5.2510e-02 -5.0384e-02 -1.8558e-02 3.9612e-03 3.2676e-02 7.5387e-03
+ 5.8150e-02 4.9135e-02 -2.3378e-02 -1.6840e-02 6.6049e-02 -nan(ind) 1.2628e-02 8.0725e-02
+ -nan(ind) 6.2596e-02 5.1429e-02 6.8447e-02 4.6348e-03 1.1877e-01 1.1621e-01 3.6762e-02
+ 2.3849e-02 4.9152e-02 1.1281e-01 1.6051e-01 1.2023e-01 6.5693e-02 7.5346e-02 3.5738e-02
+ 3.9090e-02 -nan(ind) -nan(ind) 5.8824e-02 -nan(ind) 5.5804e-02 6.1810e-02 -3.8217e-03
+ -7.5136e-02 -1.4995e-02 6.8934e-03 -3.6057e-02 3.0579e-03 -6.4184e-03 2.9091e-02 2.7177e-02
+ -4.3186e-02 5.0465e-02 5.0637e-02 1.3789e-01 7.0421e-02 1.1797e-01 -nan(ind) 8.0742e-02
+ 1.2073e-02 -1.2889e-03 7.7244e-02 4.2174e-02 9.7218e-02 1.2196e-01 -4.0096e-02 5.6121e-02
+ 4.6419e-02 -nan(ind) 1.3051e-01 8.8896e-02 1.2449e-01 9.9826e-02 1.0420e-01 -3.6115e-02
+ -7.2001e-03 1.0636e-01 3.6771e-02 6.4663e-02 -nan(ind) -nan(ind) 5.1781e-02 1.1104e-01
+ -8.3824e-03 -1.2497e-02 1.1109e-01 1.1517e-01 2.4892e-02 -9.2155e-03 4.9810e-02 8.3885e-02
+ 1.3680e-01 -2.9459e-02 3.5667e-02 9.5711e-02 1.2960e-01 5.5657e-02 8.0261e-02 2.3435e-02
+ 3.3207e-02 -2.4773e-02 4.6518e-02 1.8301e-01 6.9014e-02 3.6533e-03 1.0175e-02 1.8506e-01
+ -1.4763e-02 1.1077e-01 5.1801e-02 -6.1667e-02 -nan(ind) 8.3882e-02 -1.1425e-02 4.2610e-02
+ 1.8139e-02 -nan(ind) 5.6765e-02 -nan(ind) 5.1240e-02 2.9475e-02 4.9599e-02 9.1488e-02
+ 1.1725e-01 -nan(ind) 4.1773e-02 -1.3884e-01 5.5843e-02 1.4415e-01 -6.7286e-02 2.5793e-02
+ 8.6988e-02 3.1758e-02 1.2779e-01 -7.0663e-02 9.2292e-02 -nan(ind) 1.2390e-01 5.6971e-02
+ -4.8079e-02 1.0268e-01 1.1546e-01 4.0869e-02 5.6441e-02 4.8803e-02 -3.7806e-02 3.0199e-02
+ 2.5211e-02 1.3378e-01 1.3365e-01 9.3753e-04 -6.3667e-02 8.0584e-02 -nan(ind) 5.6953e-02
+ -nan(ind) 3.5527e-02 1.1084e-01 -1.0822e-02 9.8865e-02 1.3690e-01 8.7096e-02 -nan(ind)
+ 5.5699e-02 -2.0687e-02 1.1002e-02 2.5625e-02 1.8063e-01 -1.9591e-02 1.8765e-01 8.0341e-02
+ 6.2704e-02 3.3068e-02 -1.9234e-03 3.1874e-02 -4.2063e-03 4.9710e-04 4.4074e-02 1.4734e-01
+ 5.3497e-02 8.0070e-02 -nan(ind) 4.1445e-02 -6.7516e-02 -1.1560e-03 6.2721e-02 4.6500e-02
+ -4.5174e-02 7.2446e-02 1.4766e-01 3.2158e-02 9.4764e-02 7.8054e-02 3.8117e-02 1.3333e-02
+ -1.2816e-01 -nan(ind) 5.8244e-02 1.5603e-01 6.5592e-02 5.0558e-02 7.5187e-02 -4.0263e-02
+ 9.9513e-02 5.3945e-02 5.0777e-03 1.0688e-01 -nan(ind) 8.7093e-02 8.6449e-02 8.1618e-02
+ 4.9791e-02 -nan(ind) 1.5917e-02 5.6838e-03 -nan(ind) 3.4540e-02 -6.0527e-02 -1.2964e-02
+ 6.3142e-02 -4.6369e-02 1.4051e-01 2.0735e-02 9.4275e-02 4.6529e-02 5.5529e-02 1.2427e-01
+ 2.0367e-02 -3.7301e-03 1.3018e-02 7.8663e-02 1.3394e-01 -3.6570e-03 2.0344e-02 -7.4822e-02
+ 1.2114e-01 -nan(ind) -1.0352e-01 4.4135e-02 1.7866e-02 6.0710e-02 1.1664e-01 7.4683e-02
+ 7.7064e-02 -7.8953e-02 7.1525e-02 1.0077e-01 1.6332e-02 3.4513e-02 -7.7457e-04 -1.7775e-02
+ 7.3789e-02 -2.1569e-02 -3.2563e-02 3.6635e-02 8.5718e-02 2.8223e-01 9.2211e-02 1.3846e-02
+ 3.0288e-02 2.2739e-01 5.7442e-02 2.9851e-02 4.3708e-02 9.9468e-03 9.2140e-02 5.3385e-03
+ -1.0652e-02 2.3296e-01 -5.0992e-02 1.7392e-01 2.0732e-02 -4.1460e-02 1.2137e-01 -2.5044e-03
+ 1.2399e-01 2.0476e-01 -nan(ind) 5.9463e-03 1.1352e-02 -nan(ind) 1.0414e-01 -1.0158e-01
+ 3.6006e-02 -6.2890e-02 6.0619e-02 2.5707e-02 8.1004e-02 7.2233e-03 -2.4242e-02 1.5576e-02
+ 7.0706e-02 -4.7906e-02 9.3848e-02 2.0058e-02 2.5253e-02 -nan(ind) 7.0441e-02 2.8131e-02
+ 1.0347e-01 1.7359e-01 -nan(ind) -4.8810e-02 1.7311e-02 -nan(ind) 1.1946e-01 -nan(ind)
+ 6.0215e-02 3.2809e-01 2.5346e-02 6.4675e-02 3.9910e-02 5.9755e-02 9.5657e-02 1.5165e-01
+ 9.6937e-02 -2.2946e-02 -4.2585e-02 7.9746e-02 3.3297e-03 2.3414e-01 3.8861e-02 2.8930e-02
+ -4.7083e-03 9.7304e-02 1.3863e-01 1.1479e-01 -9.8707e-02 9.3190e-02 -5.1196e-02 1.5072e-02
+ 1.8894e-01 8.7434e-02 -1.4304e-02 3.6611e-02 1.8218e-02 -nan(ind) -5.0242e-02 5.4901e-02
+ 2.8758e-01 2.2308e-01 -1.3758e-02 -8.4238e-02 1.1454e-01 3.8486e-02 2.3743e-01 9.1776e-02
+ 1.1027e-01 8.7741e-02 9.6443e-02 7.7710e-02 -2.4359e-03 -1.1716e-02 9.4364e-02 1.5222e-01
+ 1.8183e-02 3.5960e-02 2.9888e-02 -6.9751e-03 7.9859e-02 5.2645e-02 -2.4900e-02 -1.1062e-02
+ 1.8940e-02 -6.1566e-02 1.0231e-01 1.2278e-01 4.4915e-02 8.9611e-02 -nan(ind) 1.3642e-01
+ 1.0448e-01 -nan(ind) 1.5083e-02 1.4784e-01 4.6698e-02 -9.9797e-02 -nan(ind) 8.0170e-02
+ -nan(ind) 1.3448e-01 5.6904e-02 4.5220e-02 8.4383e-02 9.4774e-03 1.6302e-02 2.3600e-02
+ 4.5391e-02 6.9801e-02 -2.6092e-02 5.5459e-03 9.4295e-02 -4.5734e-02 1.2247e-01 -7.8070e-02
+ 3.4591e-02 4.0839e-02 1.1346e-01 -1.1901e-01 8.0852e-02 3.2972e-02 1.4458e-01 1.3105e-01
+ 4.3474e-02 2.6116e-02 -7.4107e-04 1.8255e-02 3.1166e-02 5.5748e-03 1.4134e-01 -9.9482e-02
+ 4.3048e-02 -nan(ind) 8.6341e-04 -1.9183e-03 -3.0245e-02 2.1126e-01 2.6452e-02 9.8717e-02
+ 4.4433e-02 7.7956e-02 -3.3276e-02 -3.4179e-03 4.5898e-03 5.8418e-02 6.6820e-02 1.9180e-02
+ -2.2548e-03 -4.4364e-02 4.4002e-03 2.0108e-01 1.0889e-01 2.6282e-02 1.0080e-01 -nan(ind)
+ 3.6869e-02 -nan(ind) 1.4736e-02 6.6103e-02 1.6058e-01 -3.5677e-02 4.3292e-02 6.7468e-02
+ 1.2604e-01 2.2596e-02 9.3971e-02 1.2138e-01 -1.0014e-02 9.8869e-02 1.3633e-01 5.9776e-02
+ 1.5733e-02 1.1082e-01 6.3653e-02 2.7056e-02 -3.9833e-02 5.8910e-02 6.4964e-02 1.9149e-01
+ 2.3199e-02 6.1555e-02 2.0902e-01 1.2734e-01 -6.7567e-02 -1.4014e-02 -nan(ind) 7.8978e-02
+ 6.3517e-02 5.7748e-02 2.7141e-02 6.4042e-02 -6.2421e-03 1.7560e-01 -5.1194e-02 9.4365e-02
+ 7.6826e-02 7.1203e-02 7.4240e-02 -nan(ind) 4.7215e-04 2.9226e-02 -1.3107e-02 9.4253e-03
+ 8.0077e-03 1.7759e-01 7.9555e-02 7.2640e-02 9.0016e-02 3.3672e-02 3.6638e-01 8.9025e-02
+ 2.9882e-02 4.3241e-02 4.4397e-02 1.9070e-02 -5.1031e-02 5.4030e-02 2.4044e-02 -nan(ind)
+ 1.9095e-01 1.2063e-03 1.1839e-02 2.2242e-02 3.7702e-03 -nan(ind) 6.0294e-02 -4.7302e-03
+ 2.2377e-01 1.1829e-01 9.8610e-02 1.2233e-01 8.2955e-02 1.5398e-01 9.6588e-02 5.1923e-02
+ -6.3650e-02 4.0410e-02 4.7239e-02 2.7274e-02 1.9859e-02 -3.1143e-02 8.3410e-02 -2.6736e-02
+ 4.3219e-02 6.4070e-02 1.5668e-02 9.9034e-02 6.6617e-03 -2.2398e-02 -nan(ind) -2.6350e-02
+ 2.6225e-02 6.5554e-02 3.7846e-01 8.0079e-02 3.1940e-02 -1.0553e-01 2.5128e-02 3.9334e-02
+ 2.2070e-01 1.2479e-01 5.5473e-02 8.6900e-02 2.2331e-01 3.1704e-02 2.5984e-02 2.0738e-02
+ -1.7301e-01 1.3778e-01 2.8914e-03 9.3004e-02 1.5349e-02 1.3454e-01 4.5927e-02 1.3757e-01
+ 7.2480e-02 3.5670e-02 5.7682e-02 9.6367e-02 -3.5346e-02 2.1107e-02 4.2380e-02 4.8673e-02
+ 1.1300e-02 8.3878e-02 9.6972e-02 4.5586e-02 1.5905e-01 1.0746e-01 8.3908e-02 3.5075e-02
+ 3.3617e-02 5.2261e-02 1.1961e-01 3.4953e-02 1.0601e-01 4.1786e-02 -nan(ind) 6.7157e-02
+ -8.9043e-03 1.0803e-02 6.1399e-02 5.2485e-02 9.7579e-02 7.9392e-02 8.5943e-02 1.1620e-01
+ -7.6404e-02 8.0541e-02 1.6795e-01 2.4150e-02 1.2823e-01 5.5150e-02 9.2740e-02 7.1229e-02
+ -4.5273e-02 -2.4942e-02 2.1413e-02 3.6063e-02 -nan(ind) 1.0449e-03 6.0363e-03 7.2124e-02
+ 1.6458e-01 8.9720e-02 1.0561e-02 -7.1515e-02 5.5224e-02 5.0450e-02 9.6193e-02 -3.8724e-02
+ 1.0675e-01 -6.8063e-03 3.5844e-02 -1.0799e-01 1.1628e-01 4.9818e-03 2.9883e-02 4.4852e-02
+ 6.1998e-02 3.5057e-02 2.5882e-02 -4.0892e-02 4.9061e-03 1.2817e-01 7.4555e-02 2.7852e-02
+ 4.2247e-02 2.6088e-02 6.1680e-02 8.4374e-02 -1.3233e-02 1.0085e-02 1.5526e-01 8.2685e-02
+ 8.2560e-02 7.5868e-02 -1.6045e-02 -2.8241e-03 -1.0345e-02 1.1502e-01 2.7293e-02 6.3412e-02
+ 1.0840e-01 5.7786e-02 8.4278e-02 1.0084e-01 -2.2057e-02 3.9206e-02 7.0917e-02 9.4086e-03
+ 1.3546e-01 -3.1553e-03 9.5187e-02 4.5461e-03 3.8794e-02 8.8068e-02 -6.4771e-03 -7.8915e-02
+ 7.7066e-02 6.4291e-02 1.2455e-01 6.2147e-02 1.0382e-01 3.5282e-02 8.2952e-02 3.5168e-02
+ 1.3722e-01 7.5416e-02 4.2563e-04 -7.6846e-02 7.2084e-04 4.6241e-02 6.8155e-02 -3.4180e-02
+ 1.3872e-01 5.8735e-02 6.1650e-02 4.6887e-02 -4.3662e-02 6.0754e-02 8.4531e-02 1.8911e-02
+ 1.2839e-01 3.5275e-02 1.0749e-01 9.6105e-02 6.8388e-03 2.4999e-02 5.4768e-02 1.2316e-01
+ -1.1695e-01 -1.7913e-02 6.1629e-02 8.1965e-02 1.2927e-01 3.1913e-02 -1.0493e-01 2.0063e-01
+ 2.5360e-02 1.9050e-01 1.3465e-02 4.7232e-02 -1.0256e-01 1.4940e-01 7.7751e-02 5.5204e-02
+ 5.6515e-02 3.0143e-02 1.3731e-01 5.2999e-02 -1.1285e-02 1.2455e-01 -2.9037e-02 3.0630e-02
+ 1.7405e-02 -7.9776e-02 1.7455e-02 1.0963e-01 1.6472e-01 6.0291e-02 6.1726e-02 -2.7741e-03
+ 5.3176e-02 7.4615e-02 1.2609e-01 1.0244e-01 8.3636e-02 5.2072e-02 1.3213e-01 -1.5769e-02
+ 9.2031e-02 2.4219e-01 4.4251e-02 -2.6718e-03 8.4997e-02 2.5883e-01 8.7597e-02 1.1145e-02
+ 1.9867e-01 -8.2446e-02 2.6448e-02 3.0218e-02 -2.9414e-02 1.6219e-01 -2.9118e-02 2.1184e-02
+ 4.6914e-02 -8.6136e-02 2.3636e-02 7.9942e-02 1.1492e-01 -4.9167e-02 1.0438e-01 3.5635e-02
+ 3.2896e-02 5.5844e-02 2.3387e-03 4.4010e-02 6.7730e-02 1.3326e-01 1.3382e-01 -7.7372e-03
+ 5.5240e-02 9.9105e-02 1.4630e-02 -1.4035e-02 -6.6348e-02 8.6849e-02 1.9506e-02 7.1917e-02
+ 8.3869e-02 1.4557e-02 -6.2573e-04 5.8611e-02 1.0471e-01 -1.7022e-02 7.4394e-02 -5.4470e-02
+ -1.2764e-02 1.6698e-02 -1.7547e-02 1.0734e-01 1.2451e-01 3.6625e-02 1.2991e-01 -3.2708e-02
+ 8.5763e-02 1.0284e-01 -1.5749e-02 5.3160e-02 1.3862e-01 7.5645e-02 7.3278e-02 1.7426e-02
+ 1.1269e-01 6.4882e-02 -2.0347e-02 -1.9169e-02 1.0450e-01 9.8367e-02 2.1322e-01 9.0141e-03
+ 2.1654e-02 5.8175e-02 -1.8199e-02 4.5726e-02 -3.9292e-02 -5.8910e-02 9.0361e-02 1.4415e-01
+ 1.9549e-02 1.7832e-02 8.9229e-02 -5.0950e-02 1.6301e-02 2.3163e-02 1.1098e-01 -6.6027e-02
+ 9.8523e-02 8.0465e-02 5.5053e-02 7.3474e-02 1.2980e-01 9.1391e-02 1.1050e-01 6.8685e-02
+ 1.0453e-01 6.2426e-02 -2.9730e-02 1.2179e-02 -1.9348e-02 5.3427e-02 7.2115e-02 -2.3120e-02
+ 9.1527e-02 5.4780e-02 4.3171e-02 6.6180e-02 3.7520e-02 6.5443e-03 -2.6516e-03 4.3797e-02
+ 5.8804e-02 3.2616e-02 1.1814e-01 9.7284e-02 1.7051e-01 8.0497e-02 -7.0889e-02 2.2508e-01
+ 8.5100e-02 1.2353e-01 9.5388e-02 4.9159e-02 -9.5047e-02 1.0095e-01 6.0013e-02 6.9878e-02
+ 2.9205e-02 8.0505e-02 4.6162e-02 -1.8701e-02 6.7532e-02 -1.2506e-02 8.1247e-02 7.7755e-02
+ 6.3951e-03 3.6489e-02 1.1704e-01 5.7580e-02 5.2052e-02 3.2811e-02 4.8639e-02 -nan(ind)
+ 1.4599e-01 9.4875e-02 -2.1141e-02 2.0446e-02 -nan(ind) -4.4294e-02 -3.2553e-02 1.4550e-01
+ 6.6510e-02 1.3031e-01 1.0141e-01 -3.8468e-02 1.8044e-01 7.6865e-02 4.5408e-02 -2.0087e-02
+ 1.4006e-01 1.1919e-01 -4.7204e-02 5.2209e-02 -nan(ind) 1.2697e-01 -9.2727e-03 4.6139e-02
+ -8.5639e-02 1.0281e-01 1.1149e-01 5.9331e-02 4.2651e-02 7.0005e-02 7.0441e-02 -2.1206e-02
+ 2.4893e-02 -3.8140e-02 8.3021e-02 1.1913e-01 2.7250e-02 1.8369e-01 1.2750e-01 6.6501e-04
+ 8.2995e-02 7.0718e-02 4.2271e-02 4.6458e-02 3.8328e-02 -4.0139e-02 4.8390e-02 7.1551e-02
+ 2.1078e-01 4.3977e-02 -7.1099e-03 -9.8629e-03 1.2403e-01 6.6281e-02 1.8097e-02 1.0137e-01
+ 1.5666e-01 7.1129e-02 5.3544e-02 6.5044e-03 2.8224e-03 8.1845e-02 4.8914e-02 6.4850e-02
+ -5.7252e-02 2.2214e-02 3.8208e-02 6.6325e-02 9.3062e-02 8.6717e-02 7.0009e-02 2.9138e-02
+ 1.3681e-01 6.3050e-03 1.0050e-01 1.4130e-01 1.8170e-01 2.7427e-01 6.5160e-02 6.1990e-02
+ 1.3524e-02 -3.2882e-02 1.0908e-01 1.5539e-01 6.4074e-02 7.8475e-02 -2.6803e-02 3.7265e-02
+ 1.1973e-02 1.2958e-01 6.1401e-02 2.8675e-02 5.6310e-04 6.6147e-02 2.1067e-02 7.6074e-02
+ 6.4983e-02 2.7266e-02 4.7381e-02 4.7285e-02 1.2953e-01 3.1111e-02 8.0539e-02 -nan(ind)
+ 2.5593e-02 -8.8642e-02 9.9949e-02 1.2729e-01 5.8800e-03 1.1916e-01 -2.3584e-02 8.4831e-03
+ 1.9243e-03 1.8842e-01 1.1328e-01 2.0007e-02 6.1491e-02 3.4169e-03 6.3559e-02 1.2883e-01
+ -2.5884e-02 4.3704e-02 -nan(ind) 5.3330e-02 8.7674e-02 -1.4582e-04 1.9766e-01 6.4675e-02
+ -8.8968e-02 -2.2820e-02 8.7353e-02 1.2443e-01 1.3207e-01 6.8960e-02 2.0124e-02 8.7222e-02
+ 2.4461e-01 1.2042e-01 -1.5609e-01 6.4216e-02 1.9332e-02 1.3243e-01 1.0401e-01 2.6416e-02
+ -3.9281e-02 8.3215e-02 -1.2703e-02 -nan(ind) 1.1035e-01 2.6271e-02 1.6953e-01 -2.8163e-03
+ 1.7682e-01 9.9519e-02 7.4059e-03 2.2918e-02 6.9069e-02 4.4104e-02 1.4584e-01 1.3795e-01
+ 3.4530e-02 1.4393e-01 5.5813e-02 6.9853e-02 1.7671e-01 2.8296e-02 2.4714e-02 1.9887e-01
+ 5.9778e-04 4.5350e-02 3.4988e-02 1.1024e-01 1.4410e-01 1.4936e-01 7.9615e-02 1.1369e-03
+ 6.4156e-02 1.3828e-01 5.1102e-02 5.7297e-03 5.5896e-02 -5.5092e-03 1.0802e-01 -3.5020e-02
+ 8.8323e-02 1.1466e-01 5.9762e-02 -7.2968e-03 1.0403e-02 5.3337e-02 -7.6401e-03 3.9035e-02
+ 1.8066e-01 7.4885e-02 -7.5832e-02 1.6601e-01 1.2094e-01 3.5578e-04 4.3808e-02 1.1410e-01
+ 6.5113e-02 -nan(ind) 9.1397e-02 1.1937e-01 -1.1320e-01 1.0870e-01 3.1207e-02 2.3925e-02
+ -1.1680e-02 -1.7998e-02 -2.2316e-02 5.8436e-02 3.4037e-02 7.9530e-02 3.9102e-02 1.5079e-01
+ 4.1067e-02 2.3027e-01 4.9646e-02 1.0121e-01 -3.1047e-02 7.5604e-02 6.9564e-02 2.0091e-04
+ 1.7069e-01 4.0726e-02 5.5514e-03 1.3574e-02 4.2710e-03 -2.4259e-01 1.1630e-01 1.0065e-01
+ 1.4233e-01 2.2952e-01 1.6601e-02 8.5443e-02 2.0869e-02 -2.9599e-02 8.1828e-02 -2.1400e-01
+ 1.5558e-01 1.1569e-01 -7.6636e-02 3.8789e-02 3.7764e-02 -3.6773e-03 6.7483e-02 9.2294e-02
+ 6.4739e-04 3.3764e-02 2.9176e-02 8.5685e-02 1.3407e-01 1.4301e-01 1.7824e-03 1.5028e-01
+ 7.1131e-02 3.8823e-02 3.4648e-02 2.6572e-01 6.0355e-03 5.0545e-02 -1.6092e-02 7.9444e-02
+ 5.2048e-02 8.9769e-03 1.4585e-01 2.6303e-01 1.5222e-02 3.9031e-02 1.0978e-01 7.8157e-02
+ 9.2384e-02 1.9071e-02 2.7057e-03 6.4987e-02 6.0255e-02 1.1725e-01 1.4510e-01 8.8259e-02
+ 9.4815e-02 1.2894e-01 1.1022e-01 4.2321e-02 -1.0045e-01 5.0592e-02 7.8219e-02 9.1712e-03
+ 1.1897e-01 2.9755e-04 4.7140e-03 -3.0634e-02 3.3977e-02 2.5143e-02 1.3504e-01 -2.5315e-03
+ 1.1825e-01 1.1280e-01 9.8630e-02 5.6408e-02 6.4113e-02 -6.5766e-03 5.0070e-02 5.9426e-02
+ 8.8736e-03 7.7886e-03 2.2519e-01 4.3484e-02 5.0350e-02 -1.7033e-02 -nan(ind) 4.9988e-02
+ 3.4339e-02 4.9529e-02 -9.2535e-03 8.6717e-02 3.0230e-02 1.8113e-01 9.5414e-02 1.4428e-02
+ 9.0546e-02 1.0341e-01 9.3971e-03 1.0096e-01 -1.7252e-02 1.2804e-01 7.2764e-02 4.7265e-02
+ 1.1045e-01 3.6653e-02 9.5634e-02 1.7674e-01 8.5387e-02 2.1347e-01 7.3182e-02 2.3686e-01
+ 1.3255e-01 9.9992e-02 1.0672e-02 5.6672e-02 1.2345e-01 6.1229e-02 1.6367e-01 1.4047e-02
+ 1.0037e-01 9.7247e-02 7.7715e-02 1.0341e-01 1.0249e-01 7.4586e-02 -6.5485e-02 1.0732e-01
+ 1.5029e-01 9.5410e-02 1.2247e-01 1.1012e-01 -1.3925e-01 5.8994e-02 1.2102e-01 5.7078e-02
+ 8.2301e-03 1.8475e-01 1.9245e-03 3.7443e-03 1.1330e-01 -7.5252e-02 9.6960e-02 3.0397e-01
+ 1.4009e-01 -6.0843e-03 -3.4819e-02 3.3362e-02 1.0919e-01 -1.2491e-03 -9.3791e-03 6.1014e-04
+ 7.5924e-02 2.9082e-02 5.3382e-03 1.4868e-01 1.0408e-01 6.0881e-02 4.2823e-02 -2.4583e-02
+ -3.9375e-02 -4.3749e-03 4.1420e-02 1.4856e-01 9.9875e-02 3.1429e-02 6.1852e-02 9.0892e-02
+ 8.4569e-02 9.5811e-02 3.4037e-02 1.2614e-01 -7.6252e-02 5.5391e-02 -nan(ind) 2.1251e-02
+ 6.5763e-02 1.4776e-01 2.7647e-03 6.9006e-02 6.1420e-02 7.3916e-02 6.4678e-02 3.2426e-02
+ -3.1728e-02 2.0249e-02 2.7938e-02 1.1859e-01 -4.5123e-02 3.2152e-02 2.1469e-02 2.7043e-02
+ -4.6496e-02 -1.7191e-02 5.1743e-02 -2.8218e-02 6.2953e-02 4.3706e-02 4.7767e-02 -4.7247e-02
+ 1.5647e-01 4.4615e-02 1.7456e-01 1.0970e-01 -3.3689e-02 5.1441e-02 4.3561e-02 2.2851e-02
+ 1.4077e-01 6.8695e-02 1.9227e-01 9.6929e-02 -6.9228e-02 1.3588e-01 -1.1903e-01 1.2463e-01
+ 3.4456e-01 1.3367e-01 3.2525e-02 2.7260e-02 1.0502e-01 1.0347e-02 4.0016e-03 -2.7686e-02
+ 4.9811e-02 1.0092e-01 1.0787e-01 5.0331e-02 1.5284e-03 1.0521e-01 1.9145e-01 1.0677e-01
+ 8.3444e-02 -1.1459e-02 2.0932e-01 -2.1437e-02 -6.0942e-03 3.5259e-01 8.8871e-03 6.4395e-02
+ 1.0678e-01 8.8256e-02 8.3955e-03 -5.1242e-02 -1.1235e-03 1.2779e-03 7.7643e-02 1.8822e-01
+ 7.1799e-02 4.3620e-03 -3.1766e-02 3.4432e-02 6.4906e-02 5.9797e-02 1.0069e-01 8.5437e-02
+ 1.3283e-01 8.9933e-03 6.0346e-02 1.2752e-02 1.4172e-01 1.5142e-02 8.2119e-02 1.9106e-01
+ 6.3825e-02 -1.0405e-01 1.2696e-01 7.3736e-02 1.2409e-01 1.2289e-01 2.4628e-01 -4.5341e-02
+ 5.3806e-02 -5.0608e-03 1.4724e-02 7.9304e-02 5.9822e-02 7.4032e-02 -4.2000e-02 2.6776e-02
+ -3.3852e-02 1.7985e-02 6.9310e-02 1.1058e-01 2.2516e-02 4.8399e-02 6.9507e-02 -6.4161e-02
+ 1.3392e-01 -nan(ind) 4.2619e-02 1.0872e-01 3.0578e-02 1.1516e-01 -7.0548e-02 3.6178e-02
+ 5.6177e-02 -9.0070e-03 8.6732e-02 3.1869e-02 -2.8677e-02 7.1433e-02 1.4826e-01 -1.4838e-02
+ 8.0843e-02 2.2009e-02 1.0609e-01 3.5348e-02 9.6928e-02 1.5239e-02 6.5875e-02 1.2837e-01
+ 4.3814e-02 5.0709e-02 -5.8812e-02 1.0240e-01 -5.5861e-02 5.6649e-02 -5.2969e-02 9.9201e-02
+ 2.7593e-01 8.2752e-02 -2.2591e-02 1.4559e-01 3.3288e-02 -8.6246e-02 6.7354e-02 -2.2791e-02
+ 1.2176e-01 1.1478e-01 1.3239e-01 3.9057e-02 9.4821e-03 1.3349e-01 1.7656e-01 1.6990e-01
+ 4.1211e-02 7.3474e-02 9.4930e-02 4.3420e-03 2.4658e-02 7.4177e-02 8.4088e-02 -6.3933e-02
+ 1.7554e-01 1.4236e-01 5.5770e-02 -1.8882e-02 6.8408e-02 5.3757e-02 1.1544e-02 1.2040e-01
+ 1.1727e-01 7.8588e-02 7.0539e-03 -1.0101e-01 1.6525e-01 1.4889e-01 2.6013e-02 3.1445e-02
+ 1.4591e-01 -7.3135e-04 6.9669e-02 6.8290e-02 -4.5389e-02 -1.5354e-02 7.1203e-02 2.6516e-01
+ 6.7245e-03 1.6083e-01 2.5606e-02 8.2157e-02 4.5939e-02 -8.3537e-02 3.8366e-02 -6.4933e-03
+ 5.5107e-03 -4.7749e-02 4.6687e-03 2.0429e-02 1.1213e-01 -nan(ind) 4.4471e-02 4.2873e-02
+ 1.1885e-01 -2.4788e-03 6.7302e-03 2.1988e-02 7.0048e-02 1.5932e-02 -4.1787e-02 1.7437e-01
+ 4.3404e-02 1.2178e-01 1.4876e-01 2.5429e-02 -8.1115e-03 2.9481e-02 7.9103e-02 -7.5488e-03
+ 6.2640e-02 9.4838e-02 9.2459e-02 2.3903e-02 2.9765e-02 8.2732e-02 9.5235e-02 1.0431e-01
+ 4.2037e-02 2.2066e-02 9.4297e-02 1.9430e-01 9.0240e-02 1.7903e-01 3.0570e-02 1.5044e-01
+ 1.6342e-02 -9.2102e-03 -2.3916e-02 1.7009e-01 -6.9351e-03 1.1035e-01 8.6007e-02 5.2548e-02
+ 6.9284e-02 -4.6838e-02 3.2591e-02 -2.6152e-02 7.2697e-02 2.9550e-02 1.0081e-01 9.4763e-02
+ -7.0649e-02 8.8993e-02 9.6469e-02 -6.1381e-02 9.6042e-02 2.9644e-01 -2.4507e-02 7.1020e-03
+ 3.0698e-02 6.6378e-02 5.2181e-02 1.6928e-02 5.6403e-02 8.0040e-02 -8.0288e-03 7.4531e-02
+ 3.1427e-02 -1.3960e-02 8.0621e-02 1.0731e-01 6.2174e-02 8.4571e-02 -1.9041e-02 6.1328e-02
+ 3.1770e-02 1.5972e-01 4.4847e-02 7.1026e-04 1.0909e-02 1.5875e-01 3.8847e-02 4.8629e-02
+ -8.1758e-03 9.4056e-02 7.4852e-02 -2.4731e-02 1.2201e-01 6.2002e-02 2.6408e-01 3.6624e-02
+ 2.3349e-02 5.6232e-02 2.1744e-02 -4.4432e-02 -4.4385e-03 1.6795e-03 5.5619e-02 1.4315e-02
+ -3.3397e-02 -2.5980e-03 1.1427e-01 9.4079e-02 -4.8845e-02 5.1868e-02 3.3567e-02 5.7826e-02
+ 1.3247e-01 5.6008e-02 7.5688e-02 -6.5705e-04 -3.3486e-02 4.4842e-02 2.0240e-02 5.3408e-02
+ 6.3840e-02 3.3541e-03 1.6243e-01 2.3915e-02 9.7627e-02 4.0657e-02 6.8358e-02 1.3141e-01
+ 9.3377e-03 -3.8046e-02 8.4645e-02 9.2754e-02 -2.7217e-02 3.8641e-02 1.1215e-01 9.2787e-02
+ -6.6545e-03 -8.1723e-02 1.1940e-01 7.0932e-02 1.4630e-01 5.4857e-02 -6.1572e-02 5.1928e-02
+ 9.2729e-02 0.0000e+00 1.6216e-01 1.9542e-01 2.2253e-02 3.0092e-02 1.0250e-01 5.2329e-02
+ -2.3701e-02 -1.0182e-02 -1.8940e-01 2.0325e-01 1.5531e-01 1.2189e-01 2.3310e-02 1.2353e-01
+ 1.9127e-01 8.1941e-02 5.8952e-02 9.7767e-02 1.6555e-01 1.1782e-02 7.2837e-02 2.0110e-01
+ 1.5235e-02 2.5080e-01 8.9405e-02 7.6469e-02 1.5387e-01 -1.2354e-01 2.6371e-02 2.2567e-02
+ -7.3583e-02 7.1172e-02 6.3120e-02 -1.9913e-02 -5.8449e-03 1.1949e-01 1.1232e-01 1.1608e-01
+ 7.1706e-02 -2.1279e-02 3.4816e-02 -1.2832e-01 3.4504e-02 1.7380e-01 -4.9870e-02 3.7790e-01
+ 2.7025e-02 2.8747e-02 6.7000e-02 1.8875e-02 1.4755e-01 3.0085e-02 2.7015e-02 8.1879e-02
+ -nan(ind) 1.1418e-01 7.4043e-02 6.5277e-02 4.2028e-02 2.3959e-02 4.1452e-04 -5.9407e-02
+ 3.6784e-02 3.5533e-02 3.7546e-02 5.2725e-02 8.4972e-02 3.6341e-02 4.7351e-02 9.4670e-02
+ -3.5688e-02 8.2538e-02 1.4296e-01 5.7758e-02 1.4969e-01 3.7777e-02 -5.0150e-02 1.4090e-01
+ 1.5662e-01 -9.8508e-02 1.4879e-02 5.5492e-02 1.4297e-01 4.7801e-02 1.3415e-01 6.3219e-02
+ 1.5229e-01 1.7769e-01 4.3199e-02 3.3898e-02 8.3198e-02 1.2620e-01 5.2337e-02 1.8845e-01
+ 2.7987e-02 -3.8131e-02 -2.4261e-02 2.3259e-01 -3.1193e-03 9.3826e-02 2.2458e-01 -9.8653e-02
+ -4.4442e-02 1.9643e-03 1.4380e-02 9.2498e-02 1.0507e-01 7.2690e-02 5.1150e-02 4.1872e-02
+ 7.0088e-02 9.8696e-02 2.8733e-02 1.6124e-01 5.8319e-02 -1.1105e-01 6.6932e-02 -1.9442e-02
+ 6.3542e-02 2.7803e-02 -3.9561e-02 3.0028e-02 1.1946e-01 -5.0511e-02 9.1945e-02 1.0807e-01
+ -6.7426e-02 3.7755e-02 8.2961e-02 2.0461e-01 7.2755e-02 -2.0087e-02 1.1740e-01 1.0634e-01
+ -5.2609e-02 9.2925e-02 1.2162e-01 1.4720e-01 1.9108e-01 1.7976e-01 -1.3435e-02 -1.0212e-01
+ 9.1238e-02 1.7777e-01 2.3469e-02 -2.9802e-02 1.4028e-01 6.0826e-02 6.3836e-02 8.3442e-03
+ 1.2497e-02 4.3040e-02 5.2956e-02 1.4628e-01 8.0644e-02 1.1584e-01 2.5756e-02 6.9661e-02
+ 1.6037e-01 -nan(ind) 9.2250e-02 8.3909e-02 -2.6532e-02 2.1496e-02 6.4786e-02 1.2941e-03
+ -nan(ind) 6.9016e-02 -2.9046e-02 7.7623e-02 -1.4601e-02 -5.5365e-02 1.1052e-01 2.0071e-01
+ 1.3846e-01 1.9901e-02 2.7574e-02 2.0961e-02 1.7321e-01 1.2626e-01 -2.4994e-03 1.0543e-01
+ 1.6949e-01 5.5462e-02 8.7487e-03 7.1438e-02 -8.4659e-04 4.4539e-02 8.0944e-02 1.0340e-01
+ 2.9311e-02 4.9558e-02 -3.5656e-02 3.1687e-02 1.2566e-01 -1.1402e-02 5.1236e-02 7.9387e-02
+ 8.1626e-02 4.5757e-02 -2.5593e-01 2.2390e-01 -4.4216e-03 4.4617e-02 5.9654e-02 9.0820e-02
+ 1.2511e-01 5.1342e-02 3.0739e-01 3.0665e-02 6.7692e-02 2.2915e-01 1.6972e-02 1.5883e-01
+ 1.7053e-02 2.1631e-01 7.2049e-02 -1.2272e-02 1.1567e-01 2.6709e-02 1.1849e-01 1.4709e-01
+ 4.9531e-02 1.5871e-01 1.0151e-01 -2.3415e-02 1.4053e-01 9.0157e-02 -2.4276e-02 3.9064e-02
+ 4.3574e-02 7.9998e-02 9.8263e-02 7.8554e-02 8.1597e-02 8.9795e-02 8.3394e-02 3.9529e-02
+ 9.1650e-02 1.0318e-01 2.7383e-02 -9.0087e-02 1.0116e-01 -3.9380e-02 2.6983e-02 4.2381e-02
+ 1.5121e-01 1.3868e-01 -2.8675e-03 -1.1085e-02 5.9067e-02 5.2786e-02 1.1280e-01 4.8353e-02
+ 5.2330e-02 6.2578e-02 7.5632e-02 6.5107e-02 5.7363e-02 -1.8885e-03 -nan(ind) 4.7391e-02
+ 3.8879e-03 5.0329e-02 9.1294e-02 -nan(ind) 1.0771e-01 -nan(ind) -3.8772e-03 1.1163e-02
+ 8.7719e-02 -7.6572e-03 -nan(ind) 7.0260e-02 1.0799e-02 5.4229e-02 1.0836e-01 2.9607e-02
+ 1.5391e-01 -3.4100e-02 4.3188e-02 1.4571e-01 6.9262e-02 -9.8721e-03 8.9295e-02 -3.7852e-02
+ 8.2366e-02 6.9909e-02 1.1094e-01 -5.8027e-02 1.2973e-01 2.7431e-01 8.1319e-02 3.3025e-01
+ 1.1525e-01 -3.2758e-02 6.4553e-02 -6.4530e-02 1.4124e-01 1.3396e-01 7.1374e-02 1.8931e-01
+ 1.4674e-02 2.7627e-02 5.3287e-02 1.3317e-01 2.3492e-01 6.5755e-02 -1.0211e-02 -5.0769e-03
+ 1.1672e-01 1.9907e-01 3.4877e-01 1.0390e-01 1.7046e-01 -4.8384e-02 1.9501e-01 1.1645e-01
+ 5.7397e-02 8.8352e-02 2.1698e-01 1.1885e-01 6.8105e-02 2.3129e-01 6.1835e-02 9.3482e-02
+ 7.7247e-02 2.8493e-01 8.7218e-02 6.4435e-02 7.1941e-02 8.5432e-02 4.3350e-02 1.6985e-01
+ 4.5759e-03 9.5543e-02 7.3656e-02 2.8045e-02 5.1521e-02 -5.6384e-02 2.3354e-01 1.4459e-02
+ -1.9353e-02 -7.7049e-03 -4.0477e-02 8.5952e-02 1.4377e-01 6.1081e-02 5.6240e-02 -5.0919e-02
+ 7.2365e-03 2.6609e-02 4.8177e-02 2.9755e-02 3.2246e-02 7.7208e-02 5.1495e-02 3.1171e-02
+ -8.7018e-03 6.8251e-02 -3.6713e-03 9.2379e-02 1.7956e-01 -nan(ind) 1.0363e-01 1.0274e-01
+ -nan(ind) 4.8577e-02 9.7875e-02 -nan(ind) -5.5496e-03 5.3738e-02 1.6671e-02 4.1568e-02
+ 4.5225e-02 1.0192e-01 4.9058e-02 8.3679e-02 9.9533e-02 1.4008e-01 1.9987e-01 4.4798e-02
+ -8.6904e-02 2.2979e-01 2.2111e-02 7.6995e-02 3.2378e-02 1.3384e-01 1.0148e-01 -8.3259e-02
+ 5.6553e-02 -1.0304e-02 7.9962e-02 1.8624e-01 1.5365e-01 1.3792e-01 1.3696e-01 1.0871e-01
+ -1.9787e-02 1.5142e-01 1.6998e-01 1.3481e-02 4.3982e-02 -7.7863e-03 1.0418e-01 4.2777e-02
+ 5.8647e-02 6.9240e-02 1.3526e-01 9.2995e-02 3.2824e-01 2.6676e-01 5.4809e-02 4.8758e-01
+ 4.7079e-01 2.2449e-01 2.9916e-01 2.3003e-01 1.0567e-01 4.1230e-01 1.4149e-01 1.3274e-01
+ 1.5731e-01 1.9455e-01 1.8164e-02 2.0601e-01 1.1679e-01 7.4851e-02 1.3154e-01 1.2016e-01
+ 7.8319e-02 5.1000e-02 1.6525e-01 -5.6770e-02 6.2808e-02 1.9786e-02 4.4783e-02 1.1787e-01
+ 8.3214e-02 -9.7990e-02 2.6821e-02 1.8744e-01 -1.0221e-01 1.1531e-01 1.2942e-01 2.1557e-02
+ 3.2799e-02 1.0784e-01 1.4421e-03 -1.4755e-01 5.5348e-02 1.1863e-01 1.2172e-01 1.3120e-01
+ 1.7588e-03 6.2398e-03 1.9884e-02 1.2168e-01 5.7979e-02 1.2645e-01 4.4937e-02 2.4289e-01
+ -nan(ind) 4.0846e-02 -nan(ind) -nan(ind) 3.6407e-02 1.3662e-01 6.2976e-02 6.3638e-02
+ 5.1479e-02 9.2807e-02 -nan(ind) -9.1981e-03 5.2127e-02 2.0566e-02 1.0868e-01 8.9024e-02
+ 6.6151e-02 7.6745e-02 3.1708e-02 1.3801e-01 1.4274e-02 6.0904e-02 -3.3377e-02 2.7238e-02
+ 3.2956e-02 4.7912e-02 6.6510e-02 1.9802e-01 1.0176e-01 -1.8975e-01 5.0754e-02 3.7893e-01
+ 2.3493e-02 -7.2630e-02 9.9517e-02 -1.1219e-02 3.0884e-03 8.6524e-02 3.2369e-02 6.1728e-02
+ 7.4904e-02 7.8307e-02 -8.8948e-03 8.2862e-02 5.5197e-02 1.4569e-01 2.6025e-01 3.1279e-01
+ 3.8084e-01 1.3902e-01 1.4805e-01 3.4779e-01 3.6728e-01 2.0272e-01 2.7307e-01 5.7615e-01
+ 3.5667e-01 9.8802e-02 2.2284e-01 2.7537e-01 1.6044e-01 5.9025e-02 8.0710e-02 1.4684e-01
+ 3.6062e-02 9.8060e-02 2.5608e-01 3.3810e-02 1.3203e-01 5.2240e-03 -7.8681e-02 1.6478e-01
+ 2.4362e-01 5.3655e-02 5.6073e-02 9.2731e-02 -6.1723e-02 1.1146e-01 -9.0144e-03 -2.7214e-02
+ 4.8395e-02 7.7683e-02 1.7969e-01 -1.1767e-02 5.4237e-02 -4.5924e-02 -6.3576e-02 -3.5403e-02
+ 7.2164e-02 -2.0765e-02 -1.8990e-03 1.9346e-02 2.2564e-02 5.0646e-02 -nan(ind) 1.6657e-01
+ -3.3808e-02 -nan(ind) 9.5602e-02 4.9085e-02 7.5337e-02 -1.7025e-02 4.3781e-02 -nan(ind)
+ 1.7921e-01 2.4720e-02 2.4809e-02 -3.3858e-02 -8.1242e-02 8.8643e-02 1.0801e-01 6.5335e-02
+ -5.5594e-02 9.0233e-02 -2.1652e-02 3.7720e-02 3.4647e-02 -2.5874e-02 7.5665e-02 1.0829e-01
+ 7.1112e-03 1.2161e-01 -5.7302e-02 9.2241e-02 8.2069e-02 7.1832e-02 6.9624e-02 1.1254e-01
+ -3.6657e-02 5.6915e-02 2.4559e-01 6.0634e-03 2.5446e-01 9.3787e-02 -2.1606e-02 1.2188e-01
+ 9.9337e-02 6.9614e-02 1.7514e-01 1.3144e-01 2.1499e-01 1.5708e-01 -5.4547e-03 1.0954e-01
+ 1.9018e-01 3.7983e-01 4.8491e-01 2.4455e-01 1.6453e-01 3.2079e-01 -7.1755e-02 -1.3274e-02
+ 4.0539e-01 4.2120e-02 2.0625e-01 3.3862e-01 2.6312e-01 4.1876e-02 2.2809e-01 1.5197e-01
+ 3.7210e-01 1.6166e-01 1.2710e-01 1.3638e-01 1.9043e-01 2.4825e-01 2.6042e-01 1.3107e-01
+ -2.4403e-02 -7.0897e-02 4.8746e-02 1.0786e-01 4.8592e-02 5.0057e-02 1.0645e-02 1.2808e-01
+ -2.9029e-02 1.1993e-01 3.4729e-02 1.5920e-01 1.8170e-01 6.8350e-02 6.5087e-02 1.5821e-02
+ 9.9299e-02 8.0277e-03 4.8023e-02 7.8091e-02 1.3595e-02 7.3142e-02 -1.4330e-02 -5.2564e-02
+ 6.4867e-02 1.7527e-02 5.2652e-03 2.0004e-01 -2.3056e-02 6.0052e-02 1.5428e-01 9.6102e-02
+ 9.5455e-02 8.3692e-02 1.5408e-02 1.4065e-01 7.5226e-02 3.0500e-02 5.5275e-02 1.1671e-01
+ -1.4891e-02 8.2358e-02 9.3441e-02 -nan(ind) 1.6434e-01 -nan(ind) -3.4730e-02 1.0161e-01
+ 1.0435e-01 -nan(ind) 1.4449e-01 1.3091e-01 4.3514e-02 1.1205e-01 9.7997e-02 6.4315e-02
+ 1.6138e-05 -8.1184e-03 -2.6629e-02 5.1903e-02 8.6754e-03 2.0315e-01 1.1597e-01 1.7065e-01
+ 8.5307e-02 2.3479e-01 2.8574e-02 1.2760e-01 6.0096e-02 9.7316e-02 1.9450e-01 1.5087e-01
+ 2.4525e-01 1.8407e-01 7.6006e-03 5.3937e-02 3.2460e-01 4.6421e-01 1.0573e-01 -1.1870e-02
+ 2.0327e-01 9.1875e-02 6.6909e-02 2.7589e-01 1.3010e-01 5.0445e-02 7.1798e-02 3.7908e-01
+ 1.6413e-01 1.0905e-01 5.8164e-02 1.6832e-01 1.2887e-01 1.3485e-01 8.4679e-02 -4.0967e-02
+ 7.2277e-02 1.8362e-01 4.2920e-01 2.0308e-01 1.3881e-01 2.9049e-01 -2.4557e-02 -6.5556e-03
+ 1.8543e-01 3.1343e-02 6.9721e-03 2.1706e-01 6.4248e-02 2.5683e-02 3.0869e-01 1.5341e-01
+ 8.8865e-02 -1.1905e-02 5.9308e-02 2.3698e-01 4.8737e-02 1.2130e-01 5.3011e-02 1.1102e-01
+ 4.0521e-02 5.1532e-02 -nan(ind) 1.3553e-02 1.0927e-01 1.8873e-01 -4.0891e-02 5.8527e-02
+ -nan(ind) 1.1045e-02 1.3036e-01 1.0762e-01 4.8598e-02 -3.3219e-02 3.4229e-02 -nan(ind)
+ 7.2453e-02 2.1908e-01 9.8732e-02 -nan(ind) 8.5561e-02 1.0652e-01 7.9134e-02 1.1452e-01
+ -1.4576e-01 9.1875e-02 -3.6131e-03 2.7202e-02 1.3142e-01 8.4869e-02 7.5594e-02 9.1300e-02
+ 6.9623e-02 5.7136e-02 -2.5667e-02 -8.8154e-03 -9.5066e-05 4.2456e-03 1.3123e-01 7.6769e-02
+ 9.4634e-02 1.1463e-01 6.6521e-02 -4.4480e-02 -7.0629e-02 1.1186e-01 7.6707e-02 -1.6323e-02
+ 1.0270e-01 3.0446e-01 2.0890e-01 2.6441e-01 1.3301e-02 2.5984e-01 6.4952e-02 1.5010e-01
+ 2.7847e-01 -3.2304e-02 2.1206e-01 1.0384e-01 5.9621e-02 1.1828e-01 1.7015e-01 -1.4685e-02
+ 1.1100e-01 1.0018e-02 1.2672e-01 4.5194e-02 1.2041e-01 1.0463e-01 1.4139e-01 3.4615e-01
+ 1.0621e-01 1.6765e-01 1.0785e-01 6.5069e-02 -8.8863e-02 2.5285e-01 1.6702e-01 -7.7535e-02
+ 2.8810e-01 3.5334e-01 8.5409e-02 2.7444e-01 4.1698e-02 7.6693e-02 1.6825e-01 -1.1345e-03
+ 1.8395e-02 1.2958e-01 7.2091e-02 1.1661e-01 6.6957e-03 -5.9274e-02 8.3495e-02 2.8630e-02
+ 9.1642e-02 1.1209e-01 7.8992e-02 1.3828e-02 6.6506e-02 4.6994e-02 8.6348e-02 1.4671e-01
+ 6.0508e-02 4.6194e-02 -nan(ind) 1.2946e-01 1.7110e-01 2.3997e-02 1.0130e-02 1.7395e-01
+ 2.6885e-02 8.0450e-02 1.5110e-01 6.8674e-02 -2.9057e-02 -2.3155e-02 4.9049e-02 -8.3994e-02
+ 4.1443e-02 2.3357e-02 9.3979e-02 1.1345e-01 1.3294e-01 2.6536e-02 6.4466e-02 3.9219e-02
+ 4.7353e-02 -9.2864e-02 -1.2625e-01 3.0144e-02 -2.6201e-03 5.5229e-02 1.8508e-02 -6.6165e-02
+ 1.3961e-01 1.6341e-02 7.0914e-02 1.8310e-01 5.0502e-02 3.0530e-02 5.5910e-02 -6.0959e-02
+ -6.3552e-02 -4.3867e-02 3.3666e-02 1.3442e-01 2.8051e-01 1.8349e-01 4.3099e-02 1.2185e-01
+ 3.4293e-01 1.8376e-01 2.4988e-01 1.4001e-01 2.1290e-01 -5.3908e-03 2.0385e-01 1.0745e-01
+ 5.7239e-02 1.7636e-03 -1.3500e-01 1.6634e-01 -6.8015e-03 6.6821e-02 6.2858e-02 1.8397e-02
+ 2.2857e-03 -4.1791e-02 1.2990e-01 2.5273e-01 7.7041e-02 1.6567e-01 8.6704e-02 2.3729e-01
+ 2.1608e-01 3.2677e-01 3.1218e-01 3.4261e-01 3.6343e-01 1.1892e-01 1.5841e-01 4.9361e-02
+ 1.4732e-01 9.0666e-02 -5.2682e-02 8.4601e-02 1.4119e-01 9.7511e-02 3.8615e-02 1.3911e-01
+ 1.5200e-01 1.7598e-02 6.6816e-02 4.2895e-02 1.4806e-01 4.2533e-02 -2.2918e-02 1.1683e-01
+ 8.8819e-02 8.6465e-02 -nan(ind) 8.2795e-02 6.7999e-02 1.2587e-01 5.4587e-02 5.8906e-02
+ 1.4600e-02 4.8457e-02 7.7033e-03 1.4422e-02 3.7272e-02 7.2974e-02 2.7857e-02 6.9140e-02
+ 7.9821e-02 9.6601e-02 -5.3765e-02 -5.6441e-03 1.6967e-01 1.3926e-01 2.8753e-01 1.4516e-01
+ -2.3234e-03 5.5990e-02 -1.2214e-02 5.9940e-03 2.3225e-01 -1.1011e-01 3.7785e-02 1.0565e-01
+ 8.4472e-02 -2.8203e-02 6.9177e-02 1.0034e-01 5.7269e-02 5.8739e-02 1.4535e-01 9.2455e-02
+ 1.3001e-01 -1.7719e-02 9.2326e-02 1.7725e-01 2.4815e-01 2.1817e-01 -1.0468e-01 3.1135e-01
+ 3.5226e-01 1.8444e-01 1.1777e-01 2.6199e-01 3.8499e-01 1.1824e-01 1.4750e-01 -1.3276e-02
+ -1.1494e-01 1.6931e-01 3.2108e-01 1.5116e-01 1.4465e-01 1.5959e-02 1.7103e-01 3.6422e-01
+ 5.3404e-02 4.5042e-02 2.0192e-02 3.3276e-01 1.6113e-01 1.9893e-01 2.4555e-01 1.6334e-01
+ 7.1141e-02 8.2929e-02 2.5450e-01 6.0553e-02 -7.0123e-04 3.4397e-01 2.0088e-01 2.1838e-01
+ 4.4256e-01 1.3783e-01 2.1445e-01 1.3860e-01 9.9629e-02 2.6565e-01 3.0401e-02 2.0402e-01
+ -8.8530e-02 -5.8364e-02 1.5213e-01 8.8173e-02 1.0405e-01 1.6140e-02 4.0529e-02 5.7558e-02
+ 7.2833e-02 8.5387e-02 -4.1992e-02 1.2897e-01 9.4379e-02 9.8231e-03 1.5353e-01 8.2919e-02
+ 1.2836e-01 -3.4848e-02 2.2865e-02 3.8058e-02 6.0580e-02 1.3163e-01 8.0340e-02 1.1172e-01
+ 1.4824e-02 -9.2855e-04 1.2269e-01 1.6453e-01 1.8174e-01 -1.5553e-02 4.8824e-03 -nan(ind)
+ 1.3847e-02 2.0389e-01 7.9254e-02 7.0476e-02 1.2930e-01 -nan(ind) 9.9808e-02 9.0413e-02
+ 8.8469e-02 -6.3106e-03 -7.5592e-02 6.5227e-02 -6.5948e-02 8.1379e-02 1.1187e-01 -5.9064e-02
+ 1.0178e-01 6.4193e-02 -7.0963e-02 6.1911e-02 1.3046e-01 1.0159e-01 1.6062e-01 4.2589e-02
+ 1.2045e-01 2.0529e-01 1.1544e-01 3.5390e-02 2.4211e-01 1.4856e-01 3.0886e-01 3.6208e-01
+ 3.4050e-01 1.0812e-01 9.6523e-02 1.4879e-01 6.7987e-02 2.8973e-01 1.8084e-01 1.8174e-01
+ 1.3894e-01 1.1414e-01 1.2354e-02 2.0568e-02 -4.8795e-02 1.6953e-01 2.0501e-01 7.9177e-02
+ 7.5694e-02 1.6320e-01 4.7291e-01 -9.9434e-03 1.0391e-01 1.1627e-01 -5.6596e-02 1.5146e-01
+ 1.0432e-01 1.0512e-01 4.0683e-03 2.2119e-01 4.1508e-01 4.6751e-01 2.8638e-01 1.3305e-01
+ 3.4277e-02 1.8325e-01 1.9355e-01 1.6811e-01 8.0726e-02 4.7320e-02 1.3657e-01 2.5738e-03
+ -4.5433e-04 6.1311e-02 1.3063e-01 2.3193e-02 8.9070e-02 -1.3253e-01 1.0554e-01 -2.4333e-02
+ 7.8271e-02 2.3762e-01 2.7400e-01 9.2452e-02 9.9224e-02 2.6001e-02 -4.0078e-02 9.9368e-02
+ 1.0953e-01 1.9475e-02 9.1997e-02 1.2446e-01 1.0769e-01 6.1316e-02 5.0829e-02 5.7804e-02
+ 1.3237e-01 1.1906e-01 8.1083e-02 6.8803e-02 9.2292e-02 6.2318e-02 5.0527e-02 3.4344e-02
+ 6.2348e-02 1.6392e-01 2.3484e-01 7.3499e-02 6.7459e-02 1.0032e-01 5.3856e-02 3.4840e-02
+ -5.8939e-02 4.1578e-02 1.3118e-01 9.3495e-02 1.5253e-01 6.3143e-02 3.4029e-03 -2.3129e-02
+ 2.8386e-01 1.1466e-01 7.4964e-02 1.4383e-01 1.0383e-01 1.7038e-01 6.8215e-02 6.4388e-02
+ 3.0738e-01 1.1646e-01 2.4916e-01 2.2282e-01 1.0813e-01 1.9129e-01 3.4241e-02 1.9729e-01
+ 1.3298e-01 2.7561e-01 2.2253e-01 8.2058e-02 1.6984e-01 2.3804e-01 4.1867e-01 1.8128e-01
+ 3.0295e-01 4.1887e-01 3.2709e-01 2.7930e-01 4.0127e-01 2.5087e-01 4.3244e-01 8.9420e-02
+ 2.5295e-01 1.0106e-01 6.5755e-03 1.1451e-01 3.0426e-01 3.2044e-01 1.6242e-01 3.1402e-01
+ 4.4264e-01 3.5222e-01 4.0915e-01 1.5367e-01 2.3972e-01 2.9183e-01 1.5771e-01 1.2202e-01
+ -1.1548e-02 1.1370e-01 1.6740e-01 1.8598e-01 1.1692e-01 1.3287e-01 1.2114e-01 1.4586e-01
+ -1.1316e-01 5.4870e-02 1.3316e-01 4.1329e-02 5.7411e-02 7.8436e-02 6.0622e-02 -1.6552e-02
+ -1.1711e-03 7.7879e-02 3.6573e-02 -1.8443e-03 4.6715e-02 9.8474e-02 1.0438e-01 7.0600e-02
+ 1.2391e-01 -4.3203e-02 9.1602e-02 5.0888e-02 7.5088e-02 -nan(ind) 5.1970e-02 9.8928e-02
+ 1.6535e-01 3.0337e-02 1.2946e-02 6.0757e-02 8.7686e-02 1.3346e-01 3.5773e-02 4.0919e-02
+ 4.7163e-02 -2.1599e-02 1.9055e-01 7.1862e-02 1.1840e-01 5.8398e-02 7.9550e-02 3.9536e-02
+ 1.1803e-01 6.3171e-02 1.3064e-01 9.6746e-02 4.5170e-02 8.4631e-02 1.5985e-01 1.0018e-01
+ 2.1718e-01 1.8408e-01 6.2037e-02 1.5244e-01 3.3837e-01 3.9204e-01 6.5251e-02 2.2967e-01
+ 1.0560e-01 3.0945e-01 2.0604e-01 4.8214e-01 3.5481e-01 2.0539e-01 1.1812e-01 1.9750e-01
+ -3.2479e-02 3.5976e-01 4.1786e-01 2.1259e-01 -1.1862e-02 2.4708e-01 2.8296e-01 2.8286e-01
+ 2.2468e-01 3.3867e-01 2.3721e-01 4.1395e-01 2.8550e-01 5.3882e-02 2.7351e-01 7.7365e-02
+ 3.5212e-01 6.5932e-02 2.6375e-01 4.5812e-02 2.3672e-01 2.3289e-01 2.7156e-01 7.2785e-02
+ 1.3751e-02 1.3739e-01 2.2787e-01 1.4146e-01 1.1716e-01 5.6219e-02 8.9897e-02 5.6850e-02
+ 8.8466e-03 7.5477e-02 -7.0826e-02 5.2754e-02 7.6378e-02 2.1228e-03 9.0084e-02 -2.1234e-03
+ -4.5629e-03 -6.1724e-02 1.1324e-01 6.4441e-02 4.8269e-02 3.0942e-02 3.4533e-02 1.3772e-01
+ -8.0554e-02 1.5476e-01 -5.7381e-04 2.7236e-03 8.3563e-02 1.1559e-01 -nan(ind) 3.5340e-02
+ -nan(ind) 8.4797e-02 6.5790e-02 2.7461e-02 -nan(ind) 3.4513e-02 -6.8706e-02 7.3526e-02
+ 5.6119e-02 -1.5115e-02 -1.3437e-01 -6.1591e-03 -7.4929e-03 -3.4536e-03 1.1103e-01 6.7123e-02
+ 3.8301e-02 1.2038e-01 -1.6985e-02 1.0199e-01 2.5086e-01 7.6375e-02 -9.5342e-03 6.8552e-02
+ 6.5089e-02 4.2724e-02 1.5000e-01 3.1668e-01 -1.6060e-02 1.9915e-01 3.4815e-01 4.3630e-01
+ 1.7674e-01 3.1800e-01 4.1658e-02 3.4257e-02 3.1715e-01 2.5667e-01 1.1849e-01 2.5907e-01
+ 8.9470e-02 3.2387e-01 1.5837e-01 8.1542e-02 2.1178e-01 3.3433e-01 4.7722e-01 5.3242e-01
+ 5.4934e-01 3.2407e-01 2.0145e-01 4.8520e-01 2.7360e-01 2.3993e-01 4.3744e-01 5.7790e-02
+ 5.1093e-02 1.1502e-01 1.8491e-01 2.1704e-01 3.1345e-01 1.3521e-03 2.2842e-01 1.9237e-02
+ 1.5778e-01 1.1408e-01 1.0429e-01 1.4516e-01 3.2480e-02 3.8954e-01 2.3426e-01 1.2507e-01
+ 9.9354e-02 8.4359e-02 8.2665e-02 4.0247e-01 1.5046e-02 3.2337e-03 4.5172e-02 1.5150e-01
+ 1.2752e-01 1.4527e-01 2.1870e-02 1.3814e-01 5.8883e-02 1.7565e-01 1.0069e-01 1.0463e-01
+ 1.0542e-01 9.5507e-02 2.9678e-02 5.1489e-02 6.1022e-02 5.7916e-02 1.1912e-01 6.5262e-02
+ 6.1684e-02 6.5095e-02 -6.3845e-02 4.0460e-02 6.2424e-02 2.0080e-02 5.7927e-02 -nan(ind)
+ 9.8510e-02 -1.3440e-01 3.5400e-02 2.3204e-02 8.6443e-03 5.2087e-02 9.7121e-02 1.0185e-02
+ 5.2450e-02 8.7884e-02 3.5387e-02 2.6854e-02 7.5938e-02 1.9763e-02 2.6877e-02 1.2312e-01
+ 1.2436e-01 3.8595e-02 6.5450e-02 1.0569e-01 6.6959e-03 5.5423e-02 8.6255e-02 1.7977e-01
+ 1.2061e-01 2.5216e-01 3.3257e-01 3.3878e-01 3.9181e-01 2.9194e-01 -1.6987e-02 3.4878e-01
+ 3.2334e-02 1.9758e-01 -2.5167e-03 1.9486e-01 1.6522e-01 3.4329e-01 3.6909e-01 1.8723e-01
+ 3.0770e-01 3.1297e-01 4.0650e-01 4.6340e-01 4.9922e-01 5.7435e-01 2.3377e-01 6.7736e-01
+ 3.4779e-01 4.7443e-01 3.6663e-01 3.7261e-01 2.4854e-01 3.0696e-01 3.4021e-02 2.6380e-01
+ 2.1741e-01 1.2964e-01 1.5320e-01 8.1017e-02 1.0248e-01 2.9057e-01 2.7205e-01 2.7962e-01
+ 3.4536e-01 1.8332e-01 1.1622e-01 2.1250e-01 2.8807e-01 1.7171e-01 3.3719e-01 1.5316e-02
+ -2.5236e-02 1.7756e-01 9.1665e-02 5.3313e-02 1.5850e-01 1.9577e-01 2.5223e-02 9.7402e-02
+ 9.5233e-02 1.0826e-01 -5.5059e-02 8.9818e-04 1.0035e-01 7.0819e-02 1.3681e-01 1.3586e-01
+ 7.0411e-02 5.5836e-02 8.2599e-02 7.0461e-02 1.7005e-01 1.2005e-01 5.0337e-02 5.8241e-02
+ 5.5554e-02 -nan(ind) -4.6013e-02 1.0775e-01 1.1627e-01 7.1246e-02 2.9340e-02 2.0766e-02
+ 5.2472e-02 -5.0901e-02 -nan(ind) 1.0574e-01 1.2929e-01 1.4053e-01 9.7152e-02 1.1537e-01
+ 1.7258e-01 5.9783e-02 4.5603e-02 9.6327e-03 8.7481e-02 9.3381e-02 4.4038e-02 3.8430e-02
+ 1.3152e-01 -4.5889e-02 9.7357e-02 -7.3183e-02 1.6769e-01 1.2292e-01 2.0285e-01 3.5493e-01
+ -4.2314e-03 2.6413e-01 2.2461e-01 1.1332e-01 2.3957e-01 2.4481e-01 2.2218e-01 2.0452e-01
+ 8.7153e-02 1.7604e-01 3.1039e-01 2.7856e-01 4.5389e-01 4.1810e-01 3.4678e-01 3.4448e-01
+ 7.6392e-01 5.2714e-01 5.5780e-01 5.0070e-01 3.6863e-01 5.8279e-01 4.9696e-01 3.1009e-01
+ 3.3099e-01 3.9627e-01 1.7940e-01 2.7412e-01 3.5804e-01 2.2812e-01 1.5617e-01 3.2572e-01
+ 2.0700e-01 1.8576e-01 9.3519e-02 2.1081e-01 2.3150e-01 4.9678e-01 3.2745e-01 1.8646e-01
+ 2.2275e-01 2.2008e-01 6.0809e-02 1.5835e-01 3.4908e-02 -4.8421e-02 6.7897e-02 -1.4105e-02
+ 1.3311e-01 1.5880e-01 1.6466e-01 -1.5884e-03 2.9469e-02 1.4189e-01 6.4025e-02 1.4306e-01
+ 5.6222e-02 2.9924e-02 -1.1735e-02 1.0810e-01 7.4029e-02 1.2045e-01 2.0396e-01 1.6633e-01
+ 9.2653e-02 7.6851e-02 -nan(ind) 9.6966e-02 -1.4883e-03 -1.5236e-02 4.1858e-02 3.0125e-02
+ -4.6381e-04 7.1213e-02 7.0476e-02 1.2991e-01 6.2115e-02 8.0728e-02 5.0916e-02 5.2878e-02
+ 1.5032e-01 1.0673e-02 9.1705e-02 2.3142e-02 7.1116e-02 7.2123e-02 1.0127e-01 1.6142e-02
+ -1.1435e-02 4.7067e-02 7.6898e-02 5.4452e-02 2.1183e-02 -6.5734e-03 2.3086e-02 1.8153e-01
+ 5.8860e-02 2.5544e-01 1.6987e-01 1.5073e-01 1.6929e-01 2.9345e-02 2.1398e-01 2.6359e-01
+ 1.8360e-01 2.0291e-01 1.2100e-01 3.1352e-01 3.2215e-01 4.1485e-01 2.1919e-01 2.2337e-01
+ 3.0556e-01 6.1918e-01 6.7873e-01 5.7559e-01 7.3294e-01 7.3449e-01 5.7844e-01 5.7162e-01
+ 5.4568e-01 4.5824e-01 7.6760e-01 4.4224e-01 6.7252e-01 3.5687e-01 2.8920e-01 3.9514e-01
+ 2.0602e-01 3.9810e-01 1.1845e-01 2.6169e-01 2.1756e-01 2.8592e-01 5.7805e-02 4.7095e-02
+ 1.7858e-01 1.9290e-01 2.5295e-01 2.0779e-01 -9.1894e-02 1.7034e-01 9.5418e-02 1.9500e-02
+ 3.3568e-02 2.0087e-01 1.3628e-01 7.9983e-02 4.4006e-02 3.6407e-02 9.3575e-02 -2.7235e-02
+ 1.0867e-01 -nan(ind) 1.3813e-01 -2.9832e-02 2.9287e-02 4.0465e-02 4.2969e-02 2.2838e-04
+ 3.4016e-02 -nan(ind) 1.1894e-01 4.6146e-02 5.6775e-02 8.3074e-02 9.6904e-02 9.8864e-02
+ 1.1568e-01 -7.4029e-02 5.1741e-02 3.5887e-02 1.3271e-01 6.8234e-02 1.5922e-02 -nan(ind)
+ 2.4023e-02 4.7090e-02 1.1880e-01 8.5629e-02 1.5257e-01 -3.8254e-03 1.0198e-01 7.9227e-02
+ -2.5106e-03 1.2317e-01 2.5466e-02 -7.6794e-02 9.7424e-02 7.6672e-02 4.6003e-02 -4.6442e-02
+ 1.5337e-02 -8.8314e-02 1.1951e-01 1.8086e-01 8.4613e-02 1.1512e-01 1.8289e-01 2.3997e-01
+ 2.0701e-01 6.9018e-02 1.1007e-01 3.7491e-01 1.6806e-01 1.5703e-01 4.8825e-01 2.7066e-01
+ 1.7485e-01 3.1393e-01 3.2769e-01 4.5086e-01 6.1369e-01 7.8173e-01 8.8825e-01 7.3295e-01
+ 8.3145e-01 7.3241e-01 9.0785e-01 9.2953e-01 7.4062e-01 4.7236e-01 4.7319e-01 7.6178e-01
+ 3.6270e-01 4.5927e-01 3.7901e-01 3.1983e-01 2.2035e-01 1.9448e-01 3.6406e-01 2.0254e-01
+ -2.7445e-02 1.3521e-01 3.6649e-02 -5.6057e-02 1.1375e-03 1.8991e-01 1.0032e-01 2.3788e-01
+ 4.2358e-01 1.7563e-01 1.3128e-01 1.3388e-01 3.2999e-01 1.0599e-01 1.2344e-01 -8.5487e-02
+ -7.9106e-03 -3.1072e-02 1.5961e-01 -2.4468e-02 7.4460e-02 4.3533e-02 1.5113e-01 9.3112e-03
+ -8.0198e-02 8.3932e-02 6.5473e-02 7.6620e-02 4.1528e-02 -3.9662e-02 -2.5255e-02 -8.8006e-02
+ -nan(ind) 7.1002e-02 4.3666e-02 3.0308e-01 -1.9873e-03 1.2435e-01 -8.3593e-03 6.6071e-02
+ 5.4387e-02 4.4439e-02 1.4051e-02 -4.4163e-03 7.8050e-02 3.7704e-02 8.5579e-02 7.8730e-02
+ -2.9667e-02 -1.3352e-02 7.5399e-02 -3.0631e-02 9.0612e-03 9.5775e-02 1.4516e-01 3.5896e-02
+ 4.9711e-03 -5.0466e-02 1.0945e-01 2.9886e-02 4.1365e-02 1.3265e-01 2.0091e-01 1.4466e-01
+ 1.0083e-01 5.9881e-02 6.5719e-02 1.8317e-01 9.7173e-02 2.3640e-01 8.6773e-02 6.7483e-02
+ 9.3256e-02 1.9919e-01 2.3180e-01 1.5326e-01 2.2587e-01 3.6185e-01 5.2283e-01 5.4162e-01
+ 5.8965e-01 7.9021e-01 9.3567e-01 8.9396e-01 1.2588e+00 1.2136e+00 1.2232e+00 1.1656e+00
+ 1.2708e+00 8.9581e-01 8.4531e-01 8.2265e-01 6.2273e-01 5.5074e-01 3.9737e-01 3.8686e-01
+ 2.3246e-01 3.1423e-01 4.1663e-01 2.1306e-01 1.7615e-01 2.5912e-01 5.8503e-02 7.2946e-02
+ 1.2583e-01 7.4164e-02 3.2285e-01 1.0325e-01 3.2830e-01 1.3551e-01 2.8030e-01 9.0081e-02
+ 1.5830e-01 1.0731e-01 1.8568e-02 1.4694e-01 4.6801e-02 -2.1064e-02 1.2566e-01 -2.2014e-02
+ 2.1028e-02 3.4525e-02 1.1370e-01 1.1319e-01 6.5997e-02 4.1399e-02 -2.4524e-02 1.1517e-01
+ 1.5843e-01 -6.0373e-02 -2.1156e-02 1.0884e-01 4.7362e-02 -2.6261e-02 -9.7785e-02 1.3114e-01
+ -4.5318e-03 -nan(ind) 4.8123e-02 6.8570e-02 3.2285e-02 1.0266e-01 3.0869e-02 4.7316e-02
+ -5.9195e-03 8.1237e-02 6.5138e-02 4.8044e-02 1.3501e-01 7.3422e-02 8.0097e-02 5.8879e-02
+ 2.9105e-02 3.4950e-02 1.2732e-01 1.3618e-01 1.6172e-02 8.8747e-02 8.5272e-02 2.7371e-01
+ 4.1100e-02 8.4367e-02 1.1466e-01 2.4592e-01 4.8834e-01 2.0535e-01 3.3448e-01 1.8382e-01
+ 8.7102e-02 3.2059e-01 3.4867e-01 1.1991e-01 3.1441e-01 2.1753e-01 1.6850e-01 3.4215e-01
+ 3.4285e-01 4.2752e-01 6.5764e-01 7.3453e-01 9.6355e-01 1.1400e+00 1.2166e+00 1.8207e+00
+ 1.7596e+00 2.0166e+00 2.0758e+00 1.8070e+00 1.7569e+00 1.2351e+00 1.1068e+00 9.3193e-01
+ 8.2614e-01 5.4881e-01 4.2469e-01 3.8614e-01 2.2199e-01 2.1273e-01 2.2800e-01 3.0647e-01
+ 1.6890e-01 1.4554e-01 2.2973e-01 1.8701e-01 -1.3022e-01 1.0305e-02 3.2454e-01 3.6999e-01
+ 1.0969e-01 2.0202e-01 6.7309e-02 9.2355e-02 5.7764e-02 1.3712e-01 6.1293e-02 1.5689e-01
+ 3.8482e-02 4.9525e-02 1.4055e-01 7.1511e-02 2.0340e-01 3.9626e-02 4.6633e-02 5.0377e-02
+ 4.2634e-02 -6.2049e-02 1.3065e-01 -1.3810e-02 1.0259e-01 1.2797e-01 7.0923e-02 4.0333e-02
+ -nan(ind) 2.2346e-02 -nan(ind) 7.5870e-03 8.3522e-02 -3.0603e-02 -2.3588e-02 9.7239e-02
+ -7.4535e-02 7.4397e-02 4.0396e-02 -nan(ind) -3.9137e-03 7.8152e-02 3.7096e-02 3.7773e-02
+ 1.1295e-02 -5.2250e-02 2.4719e-02 7.5918e-02 7.7288e-02 9.6784e-02 -4.9525e-03 1.1395e-01
+ 1.4431e-01 1.0709e-01 -5.5437e-02 9.6241e-02 1.3525e-01 1.3676e-02 5.2660e-02 1.5864e-01
+ 1.4422e-01 2.2480e-01 1.4349e-01 1.0031e-01 1.4411e-01 2.1486e-01 3.1634e-01 1.0779e-01
+ 1.6870e-01 3.1938e-01 2.7365e-01 2.3954e-01 5.9575e-01 5.9264e-01 7.3182e-01 9.7629e-01
+ 1.2612e+00 1.6655e+00 2.3051e+00 2.5014e+00 3.1745e+00 3.4920e+00 3.4934e+00 3.1343e+00
+ 2.4465e+00 2.1451e+00 1.6105e+00 1.3491e+00 9.4099e-01 6.3588e-01 5.0691e-01 3.5619e-01
+ 1.1930e-01 4.3312e-01 3.5343e-01 2.4674e-01 5.4433e-02 9.9070e-02 3.2307e-01 1.2148e-01
+ 9.2193e-02 3.7088e-02 1.1322e-01 7.7338e-02 1.7138e-01 1.4437e-01 7.5485e-02 7.9731e-02
+ 1.0145e-01 9.1791e-02 1.4460e-01 4.4634e-02 5.5697e-02 1.4717e-01 5.2858e-02 1.5893e-01
+ 4.0346e-02 1.3825e-01 -1.6934e-03 -1.8033e-02 -8.3143e-03 1.2982e-01 -8.9587e-03 -4.1832e-02
+ -2.1109e-03 -nan(ind) -7.5502e-02 1.0682e-01 2.0721e-01 -3.2371e-02 -8.6519e-03 7.3726e-02
+ 1.0709e-01 -3.6201e-02 5.2664e-02 1.0276e-01 1.0476e-01 1.6129e-02 6.8501e-02 1.9292e-03
+ 4.9276e-02 -1.6795e-02 1.3048e-01 5.9274e-03 -8.6304e-02 1.8360e-01 5.2633e-02 -5.2187e-02
+ 3.9242e-02 5.9076e-02 9.6505e-02 9.1427e-02 2.0546e-01 1.5623e-01 1.0112e-01 -1.1072e-02
+ 1.3710e-01 9.7629e-02 1.8680e-01 4.5877e-01 1.9932e-01 3.9255e-01 9.1755e-03 2.0951e-02
+ 8.1534e-02 1.5631e-01 -3.0961e-02 2.2582e-01 1.3297e-01 2.9926e-01 4.4362e-01 4.8494e-01
+ 6.1971e-01 7.9070e-01 8.5742e-01 1.3261e+00 1.5244e+00 2.2600e+00 3.2716e+00 4.5092e+00
+ 5.7664e+00 6.5616e+00 6.6692e+00 5.7221e+00 4.3121e+00 3.3616e+00 2.4428e+00 1.6852e+00
+ 1.1166e+00 8.8368e-01 8.4658e-01 4.8918e-01 3.6665e-01 3.2393e-01 1.3079e-01 2.2080e-01
+ 9.3704e-02 5.8309e-02 5.1773e-02 4.4173e-02 7.7509e-02 1.8586e-01 1.6220e-01 5.3149e-02
+ 1.6119e-01 2.2236e-01 1.5623e-01 -1.5037e-02 8.7868e-02 7.4751e-02 7.9036e-03 9.4130e-02
+ 9.1481e-02 6.2314e-02 1.5831e-01 2.0605e-01 -5.9300e-02 3.3882e-02 9.6122e-02 4.6942e-02
+ -5.0613e-02 5.4446e-02 -5.9583e-03 1.0315e-01 -9.3691e-04 7.4093e-02 -7.9917e-02 9.5827e-02
+ 2.1539e-02 1.2324e-01 5.6744e-02 6.3512e-02 7.3614e-02 2.0869e-02 7.7102e-02 1.2591e-01
+ -3.7444e-03 1.2311e-02 2.8905e-02 1.0561e-01 5.9774e-02 1.2830e-01 5.5363e-02 1.7893e-01
+ 9.9962e-02 1.1095e-01 5.2292e-02 1.2810e-01 9.6803e-02 6.4178e-02 1.1004e-01 -4.3265e-02
+ 1.1812e-03 1.5090e-01 -5.9126e-02 -2.3163e-02 1.2951e-01 1.4370e-01 8.1627e-02 1.3634e-01
+ 1.1755e-01 3.1927e-02 1.3749e-01 -9.9781e-02 2.3011e-01 6.6938e-02 2.1243e-01 5.6317e-02
+ 1.2940e-01 2.7409e-01 4.8055e-01 4.6259e-01 7.3034e-01 6.5214e-01 1.1059e+00 1.8948e+00
+ 2.2855e+00 3.8339e+00 5.8901e+00 9.1491e+00 1.1769e+01 1.4074e+01 1.3975e+01 1.1938e+01
+ 8.0762e+00 5.5085e+00 3.5701e+00 1.9999e+00 1.5036e+00 1.1634e+00 8.3491e-01 7.3959e-01
+ 5.0329e-01 2.5427e-01 2.3581e-01 1.6899e-01 3.0305e-01 1.1489e-01 2.7925e-01 1.2070e-01
+ 6.7316e-02 5.2788e-02 1.8598e-01 2.0538e-01 1.6455e-01 1.3439e-02 5.7908e-02 8.4582e-02
+ -1.4698e-02 -1.1199e-01 3.3914e-02 7.5533e-02 9.9133e-02 8.0060e-02 -5.1428e-03 1.6570e-01
+ 5.1231e-02 1.0682e-01 1.0467e-01 8.3095e-02 1.5375e-01 -1.2327e-02 2.8634e-02 4.7885e-02
+ 8.3883e-02 1.6824e-01 8.1397e-02 5.5813e-02 7.7595e-02 1.9727e-02 6.8596e-03 -2.9645e-02
+ 1.3849e-01 1.8940e-01 -1.3174e-02 6.9740e-02 7.8491e-02 5.8303e-02 -2.1612e-02 1.1141e-01
+ -4.4843e-02 8.9281e-03 -nan(ind) 1.2831e-01 5.2276e-02 7.9168e-02 6.0731e-02 1.1708e-01
+ 6.1722e-02 7.9676e-02 5.4229e-02 9.1735e-02 4.4652e-02 1.1015e-01 7.8384e-02 4.3439e-04
+ 1.0689e-01 1.6299e-01 1.4251e-01 2.2187e-01 3.1323e-01 2.5799e-01 9.1327e-02 -1.3720e-02
+ 7.6374e-02 2.1448e-01 3.7587e-01 3.7974e-01 2.6008e-01 3.6761e-01 3.3125e-01 6.2019e-01
+ 6.2498e-01 8.9765e-01 1.3212e+00 2.0716e+00 3.4040e+00 5.2981e+00 9.9980e+00 1.8251e+01
+ 3.0787e+01 4.1642e+01 4.0547e+01 2.7977e+01 1.7019e+01 9.3860e+00 5.2992e+00 3.0501e+00
+ 2.1398e+00 1.2741e+00 9.6846e-01 6.7575e-01 6.6802e-01 5.9192e-01 3.2361e-01 2.6274e-01
+ 4.4775e-01 1.4801e-01 4.9843e-03 1.8621e-01 2.0885e-01 2.0864e-01 5.1485e-02 2.7353e-02
+ 2.2399e-01 2.6101e-01 2.0188e-01 2.2244e-01 9.3548e-02 6.8984e-02 1.1324e-01 9.7833e-02
+ 1.1245e-01 3.3743e-02 3.0065e-02 -4.4278e-02 5.4222e-02 5.6897e-02 1.3960e-01 1.3405e-01
+ 8.3341e-02 8.1514e-02 1.2071e-01 2.0122e-02 3.9756e-02 1.8888e-01 2.4369e-02 1.2963e-01
+ 1.9800e-01 6.7183e-02 2.2701e-02 1.5911e-01 4.1346e-02 1.6544e-01 -1.0035e-03 -1.3634e-01
+ 5.3716e-02 1.2283e-01 4.3398e-02 -3.5033e-02 1.1628e-01 5.9889e-02 1.1772e-01 4.1196e-02
+ 1.0071e-01 1.0036e-01 -7.3222e-03 -1.8040e-02 1.0918e-01 5.5134e-02 5.5266e-02 -2.7135e-03
+ 8.8925e-02 1.7052e-01 4.6497e-02 7.4947e-02 1.2495e-01 9.5436e-02 2.2465e-01 2.0715e-01
+ 8.6302e-02 6.1958e-02 8.7570e-02 -8.0803e-03 5.6692e-02 1.8868e-01 1.1424e-01 2.0910e-01
+ 3.9694e-01 4.2960e-01 5.0549e-01 3.9154e-01 8.3171e-01 1.1729e+00 1.8011e+00 2.4983e+00
+ 4.7412e+00 9.1229e+00 1.7674e+01 4.4282e+01 1.0558e+02 1.8497e+02 1.7291e+02 9.2088e+01
+ 3.8296e+01 1.6740e+01 7.8588e+00 3.7757e+00 2.6275e+00 1.3480e+00 1.0568e+00 9.2140e-01
+ 6.1749e-01 3.1577e-01 4.0763e-01 2.2916e-01 4.8090e-01 1.9203e-01 5.6145e-02 9.5465e-02
+ 1.4047e-01 1.9833e-01 1.1512e-01 7.2098e-02 1.8013e-01 1.3334e-01 4.5289e-02 1.8867e-01
+ 7.7043e-02 1.9034e-02 3.8368e-02 -5.9481e-02 1.7143e-01 -6.2496e-03 4.3567e-03 6.7525e-03
+ 8.3777e-02 2.6239e-01 1.0112e-01 7.9016e-03 -1.6197e-02 1.4954e-01 5.7126e-02 1.8877e-01
+ 1.2973e-01 4.5775e-02 1.2042e-01 4.5418e-02 4.1428e-02 3.2808e-02 -nan(ind) 1.8887e-02
+ -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind)
+ -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind) 2.3290e-01 1.2672e-01
+ -nan(ind) -6.6463e-02 -9.3686e-02 -8.9890e-02 6.1393e-02 -1.4740e-01 1.9004e-02 7.7757e-02
+ 2.6411e-01 -3.0177e-02 1.1616e-01 5.0367e-02 9.8570e-02 2.4619e-01 -5.3643e-02 7.0339e-02
+ 2.8796e-01 1.1912e-01 6.3448e-02 3.1687e-01 3.7912e-01 3.2855e-01 2.6607e-01 6.3038e-01
+ 7.5255e-01 1.3912e+00 1.8019e+00 3.3727e+00 5.4823e+00 1.1918e+01 3.0241e+01 9.9884e+01
+ 3.9878e+02 1.1609e+03 1.0831e+03 3.4020e+02 8.3690e+01 2.6214e+01 1.0473e+01 4.7201e+00
+ 2.7284e+00 1.9484e+00 1.2214e+00 8.3993e-01 5.4603e-01 4.4735e-01 4.3566e-01 1.7964e-01
+ 2.3673e-01 1.7717e-01 8.6511e-02 -4.3912e-02 4.6580e-01 2.2357e-01 1.9857e-02 1.0567e-01
+ 6.6108e-02 2.4452e-01 1.3128e-01 1.1124e-02 -5.2590e-02 1.7041e-01 -9.2742e-02 1.8801e-01
+ -1.6548e-01 2.6598e-01 1.1210e-02 -1.1083e-01 -nan(ind) 3.8614e-02 -nan(ind) -nan(ind)
+ -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind)
+ -nan(ind) -nan(ind) -nan(ind) -nan(ind) 5.5573e-02 1.0024e-01 1.9746e-02 1.0853e-01
+ 1.0057e-01 1.3885e-03 1.0377e-01 9.6900e-02 8.3055e-02 1.3902e-01 2.9137e-02 4.3291e-02
+ 1.5796e-02 5.3118e-02 -1.9114e-02 6.6319e-02 4.2855e-02 3.4085e-02 4.3610e-02 5.5079e-02
+ 2.5496e-02 4.6454e-02 8.4061e-02 6.4452e-02 1.0692e-01 5.6226e-02 1.3873e-01 2.8193e-01
+ 3.2571e-01 1.3543e-01 4.6112e-02 1.4566e-01 1.8985e-01 4.0815e-02 2.4408e-01 3.0963e-01
+ 3.1785e-01 3.8189e-01 6.0443e-01 6.3397e-01 8.8366e-01 1.3665e+00 2.1970e+00 3.1086e+00
+ 6.6424e+00 1.4031e+01 4.0483e+01 1.6689e+02 1.0578e+03 4.2365e+03 3.7522e+03 8.9140e+02
+ 1.4062e+02 3.3734e+01 1.2581e+01 5.7495e+00 3.1286e+00 1.9898e+00 1.1712e+00 9.2782e-01
+ 7.8086e-01 6.6772e-01 4.3694e-01 2.8970e-02 1.8913e-01 3.5335e-02 8.5795e-02 2.0931e-01
+ 9.3838e-02 8.8721e-02 7.2873e-02 5.1044e-02 1.9697e-01 2.8869e-01 1.2608e-01 4.9519e-02
+ 2.7134e-02 4.3267e-02 2.0754e-02 1.5908e-02 4.0785e-02 9.8499e-02 6.7620e-02 5.3196e-02
+ 5.3228e-02 7.9494e-02 5.0425e-02 9.2673e-02 5.7527e-02 3.4981e-02 4.5666e-02 1.0172e-01
+ 6.7922e-02 5.7322e-02 5.9475e-02 4.9796e-02 1.2121e-01 1.8106e-02 1.1230e-01 1.3924e-02
+ -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind)
+ -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind)
+ -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind) 5.4718e-01
+ 0.0000e+00 -9.9168e-02 9.7714e-01 -7.4168e-03 -1.3053e-01 6.8576e-01 2.5814e-01 9.5271e-02
+ 1.3679e-01 -1.8830e-02 6.2638e-02 2.5160e-01 2.3015e-01 3.5235e-01 4.2898e-01 3.1661e-01
+ 1.1437e+00 1.1822e+00 1.8231e+00 3.0957e+00 6.1232e+00 1.3438e+01 3.6723e+01 1.3245e+02
+ 6.0173e+02 2.3961e+03 2.7962e+03 7.7249e+02 1.2966e+02 3.4002e+01 1.2393e+01 5.3801e+00
+ 3.3719e+00 1.9433e+00 1.5207e+00 8.5283e-01 6.3640e-01 4.2561e-01 3.8168e-01 1.6393e-01
+ 3.2261e-01 1.2938e-01 3.0440e-01 1.8205e-01 1.3974e-01 1.8222e-01 2.0773e-01 6.7924e-01
+ 7.5718e-01 4.6651e-01 5.0122e-01 2.8057e+00 0.0000e+00 -nan(ind) -nan(ind) -nan(ind)
+ -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind)
+ -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind)
+ -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind) 1.2273e-01 -nan(ind) -nan(ind)
+ -2.1456e-01 -nan(ind) 1.9916e-01 -nan(ind) -3.1965e-02 1.4674e-01 2.6073e-01 2.6283e-01
+ 2.5691e-01 2.2988e-02 8.6498e-02 1.1873e-01 3.6460e-02 2.7645e-02 6.1907e-02 9.5709e-02
+ 8.9081e-02 4.9490e-03 1.0344e-01 2.9284e-02 8.4059e-02 7.9164e-02 2.2804e-01 5.5827e-02
+ 1.7107e-01 2.1190e-01 3.1992e-02 1.8422e-01 1.0603e-01 8.7409e-02 1.0425e-01 2.7853e-01
+ 4.0640e-01 4.4960e-01 6.3567e-01 7.1439e-01 8.4860e-01 1.3980e+00 1.6297e+00 2.7556e+00
+ 5.0316e+00 9.7742e+00 2.0020e+01 5.9954e+01 2.7914e+02 7.9901e+02 7.4808e+02 2.5905e+02
+ 7.2455e+01 2.3507e+01 9.4239e+00 4.8049e+00 2.8670e+00 1.8993e+00 1.2641e+00 1.0650e+00
+ 7.3994e-01 5.0800e-01 2.0828e-01 1.5014e-01 1.3459e-01 3.6318e-01 7.7514e-02 1.1345e-01
+ 2.1455e-02 1.1586e-01 -8.0686e-02 9.8457e-02 4.5463e-01 2.1758e-01 2.0273e-01 1.2181e-01
+ 1.2863e-01 1.3567e-01 3.3552e-02 4.7348e-02 1.2794e-01 2.8254e-02 6.1389e-02 7.1638e-03
+ 9.9819e-02 8.7188e-02 4.1444e-02 1.0661e-01 3.9156e-02 -1.1832e-02 7.5963e-03 -3.6607e-02
+ -nan(ind) 4.9874e-03 -nan(ind) 1.2495e-01 -nan(ind) 5.2090e-03 -nan(ind) -nan(ind)
+ 7.5442e-04 1.1117e-01 6.9668e-02 7.5336e-02 -2.4972e-03 7.7461e-02 1.0310e-01 -2.8807e-02
+ 6.6656e-02 2.9553e-03 7.5440e-02 3.4249e-02 9.0808e-02 4.8920e-02 7.2768e-03 -4.4082e-02
+ 2.2455e-02 1.4339e-02 6.6974e-02 1.1417e-01 1.0566e-01 1.1533e-01 5.4017e-02 -2.8889e-02
+ 4.0817e-02 -1.9946e-02 9.0471e-02 4.6175e-01 4.2986e-01 2.4207e-01 1.5760e-01 5.9776e-02
+ 1.2361e-01 1.2093e-01 1.5317e-01 2.1267e-01 4.2640e-01 1.6724e-01 6.2896e-01 6.0441e-01
+ 7.0351e-01 1.0655e+00 1.5758e+00 2.2825e+00 3.4026e+00 6.3219e+00 1.4836e+01 3.5174e+01
+ 7.8310e+01 1.3087e+02 1.2405e+02 7.1259e+01 3.2659e+01 1.5304e+01 7.1563e+00 3.6470e+00
+ 2.5150e+00 1.5930e+00 8.5223e-01 8.4002e-01 6.1400e-01 5.4447e-01 2.8415e-01 6.3886e-02
+ 3.4136e-01 4.0799e-01 1.0933e-01 1.9434e-01 2.0587e-01 3.3114e-01 2.4043e-01 4.8216e-01
+ -4.4108e-04 1.2893e-01 1.2553e-01 1.5005e-01 1.7335e-02 1.2217e-01 -7.3374e-04 6.3025e-02
+ 1.0983e-01 5.4809e-03 8.5125e-02 8.8340e-02 8.4413e-02 2.1494e-02 1.0140e-01 9.6345e-02
+ 8.0755e-02 6.1913e-02 5.2894e-02 1.2944e-01 7.9489e-02 1.4605e-01 5.0395e-02 1.4916e-01
+ 6.2752e-02 8.4257e-02 -5.5058e-02 1.3513e-01 6.7608e-02 -6.9815e-02 1.2904e-01 -8.9618e-03
+ 1.7539e-02 2.1727e-02 8.5745e-02 -1.4367e-02 9.1654e-02 2.3294e-02 2.0116e-02 9.0828e-02
+ -9.8481e-02 -2.2421e-02 5.6042e-02 9.1518e-02 1.1723e-01 7.3398e-04 1.9471e-01 8.8710e-02
+ 4.4965e-02 -7.1065e-03 1.8540e-03 9.2521e-02 6.3637e-02 1.2312e-01 1.9318e-01 1.8104e-01
+ 1.4115e-01 1.3985e-01 1.3770e-01 1.2495e-01 -4.1857e-02 3.1549e-01 1.5929e-01 2.8016e-01
+ 1.5148e-01 5.2002e-01 4.1743e-01 5.1913e-01 7.1393e-01 1.1408e+00 1.2286e+00 2.0736e+00
+ 3.1767e+00 5.3475e+00 9.0234e+00 1.5323e+01 2.4465e+01 3.3318e+01 3.1672e+01 2.3530e+01
+ 1.4935e+01 9.0904e+00 5.1962e+00 3.0708e+00 2.1613e+00 1.6845e+00 8.3288e-01 4.2095e-01
+ 3.4417e-01 4.6581e-01 2.2786e-01 3.9580e-01 1.0469e-01 1.0952e-01 -4.5644e-02 1.4336e-01
+ 7.6306e-02 -1.2799e-02 1.1413e-01 1.5764e-01 3.9635e-01 1.0170e-01 9.7111e-02 2.0135e-01
+ 1.0583e-01 8.7223e-02 2.8994e-03 1.9088e-01 1.7346e-01 -2.0044e-02 9.6985e-02 -3.6089e-02
+ 2.4779e-02 1.2649e-01 2.1976e-02 7.1348e-03 9.3310e-02 -4.3670e-02 4.6510e-02 7.5088e-02
+ 6.5337e-03 -3.8152e-02 6.7616e-02 9.1479e-02 -1.3513e-02 5.1959e-02 2.4945e-01 5.9173e-02
+ 1.7990e-02 5.0089e-02 -4.3758e-02 -8.7608e-03 1.4743e-01 1.1014e-01 1.1747e-01 -8.2462e-02
+ 3.2139e-02 1.1938e-03 4.6222e-02 -1.3064e-02 -2.3947e-02 5.8896e-02 5.6324e-02 -1.4203e-03
+ 7.5735e-02 9.2105e-02 1.2508e-01 7.8896e-02 1.0712e-01 -2.5421e-02 4.6099e-02 1.2295e-01
+ 1.1953e-01 1.7444e-01 5.3987e-02 1.1124e-01 3.5361e-01 1.5203e-01 2.3372e-01 1.0213e-01
+ 2.5777e-01 2.2115e-01 3.2091e-01 2.0030e-01 1.4516e-01 5.0319e-01 1.3071e-01 4.5821e-01
+ 4.2842e-01 8.2396e-01 7.2379e-01 1.5564e+00 2.4328e+00 3.2485e+00 4.7741e+00 7.1664e+00
+ 1.0311e+01 1.2022e+01 1.2331e+01 9.9566e+00 6.6219e+00 4.9755e+00 3.0069e+00 2.0834e+00
+ 1.6354e+00 1.1213e+00 7.8194e-01 5.1499e-01 5.3885e-01 4.7204e-01 1.9917e-01 1.1091e-01
+ 1.4387e-01 9.0218e-02 1.4241e-01 2.3344e-01 1.9155e-01 4.0378e-01 1.5596e-02 1.9070e-01
+ 2.3779e-01 7.2501e-02 1.0929e-01 1.4855e-01 4.7774e-02 -1.8491e-03 7.3034e-02 5.3317e-03
+ 6.1736e-02 1.5141e-01 1.4515e-01 1.0613e-01 2.6652e-02 2.0400e-01 -5.5066e-02 2.1608e-02
+ -8.3984e-03 2.5913e-02 1.8120e-01 -3.3177e-02 1.3349e-01 8.8822e-02 5.2321e-02 -1.8542e-02
+ -9.6817e-03 1.3987e-01 -2.5561e-03 1.1259e-01 7.2188e-02 5.9228e-02 7.6930e-02 4.4256e-02
+ 4.2801e-02 9.7097e-02 7.2645e-02 1.4047e-01 2.5365e-03 9.1061e-02 1.4796e-02 6.5098e-02
+ 5.8176e-02 4.2375e-02 7.5858e-02 1.7287e-02 9.4558e-02 4.0868e-02 2.7851e-02 7.4524e-02
+ 4.0506e-02 4.0434e-02 7.1422e-02 1.2224e-02 3.3764e-02 1.3574e-01 1.2629e-01 1.5174e-01
+ 1.0476e-01 1.2537e-01 2.3864e-01 9.5010e-02 9.1202e-02 1.8033e-01 9.6589e-02 1.2106e-01
+ 2.3096e-01 2.5025e-01 3.5755e-01 2.1227e-01 2.2596e-01 6.4240e-01 7.5478e-01 1.1059e+00
+ 1.5151e+00 2.2709e+00 3.1453e+00 4.0859e+00 4.6652e+00 5.2655e+00 5.6410e+00 4.8517e+00
+ 4.1099e+00 3.0506e+00 2.0900e+00 1.4923e+00 1.0850e+00 9.7514e-01 7.4416e-01 5.0794e-01
+ 3.9832e-01 3.9163e-01 3.0023e-01 2.2092e-01 1.6551e-01 1.8203e-01 -1.2986e-01 1.5515e-01
+ 4.8547e-02 6.8369e-02 2.4293e-01 3.2375e-01 1.1347e-01 1.8889e-01 1.0534e-01 1.0565e-01
+ 2.3281e-02 5.2224e-02 8.2154e-02 7.2321e-02 8.7025e-02 1.2148e-02 3.7793e-02 1.5756e-02
+ 3.1999e-02 -2.3221e-02 1.0036e-01 1.1004e-01 1.2633e-01 1.0920e-01 2.2932e-02 9.6467e-02
+ 1.2088e-02 -nan(ind) 1.2582e-02 9.6307e-02 7.4607e-02 -5.1922e-02 1.3403e-02 1.8282e-01
+ 6.0178e-02 -nan(ind) 9.9926e-02 9.3833e-03 1.6361e-01 2.1282e-02 3.5482e-02 -5.5439e-03
+ 1.0557e-01 -nan(ind) 8.0833e-02 5.2801e-02 1.0903e-02 1.0203e-01 5.0740e-02 -3.1182e-02
+ 9.8710e-02 1.3044e-01 1.4033e-01 3.6876e-02 9.2229e-02 -3.7283e-02 4.7181e-02 1.3636e-02
+ -3.7028e-02 -3.4517e-02 1.1641e-01 1.6342e-01 3.6527e-01 2.2457e-01 2.6416e-01 2.9271e-01
+ -4.8239e-03 7.2684e-02 3.5770e-01 1.4240e-01 1.8596e-01 2.6655e-01 3.9346e-01 4.4278e-01
+ 3.6165e-01 5.6283e-01 5.6248e-01 8.6319e-01 1.2017e+00 1.7192e+00 1.9167e+00 2.4403e+00
+ 3.0005e+00 3.2781e+00 2.6027e+00 2.8994e+00 2.5893e+00 1.9441e+00 1.8034e+00 1.1284e+00
+ 8.4565e-01 6.8702e-01 5.9350e-01 4.9627e-01 7.0920e-01 2.5862e-01 2.1605e-01 3.5836e-01
+ 2.1120e-01 2.5293e-01 2.0612e-01 1.0533e-01 1.0297e-01 1.5171e-01 2.3590e-01 3.2416e-01
+ 2.9513e-01 1.2396e-01 4.0452e-02 7.7222e-03 1.2805e-01 2.3029e-03 1.2890e-01 1.9273e-01
+ 1.0112e-01 3.8076e-02 4.1747e-02 5.2960e-03 2.8479e-02 -2.5238e-02 1.2405e-01 -5.5600e-02
+ -3.1768e-02 5.4232e-02 -4.6065e-02 1.8991e-01 -5.1093e-03 9.7397e-02 -8.1504e-03 4.9646e-02
+ -nan(ind) 7.9349e-02 -nan(ind) 1.3124e-01 -1.1193e-02 2.2828e-02 9.5575e-02 2.8537e-02
+ -5.8564e-02 1.4972e-01 6.9950e-02 -1.4863e-02 4.3468e-02 5.6351e-02 5.3278e-02 1.1719e-01
+ 1.5913e-02 1.3427e-01 -3.6552e-02 -1.6234e-02 1.0801e-01 4.5687e-02 -5.1659e-02 -2.3742e-02
+ 6.9431e-02 4.7804e-02 9.2899e-02 1.2029e-01 7.0524e-02 7.7059e-02 6.4034e-02 1.7036e-01
+ 2.2011e-01 2.2738e-01 3.1308e-01 6.8423e-02 1.1345e-01 3.3233e-02 1.4468e-01 9.5875e-02
+ -1.5106e-01 3.4035e-01 3.3229e-01 1.4750e-01 6.0414e-01 3.7466e-01 5.5287e-01 6.6720e-01
+ 8.0780e-01 1.0894e+00 1.1833e+00 1.8102e+00 2.0178e+00 2.0160e+00 2.0458e+00 1.7541e+00
+ 1.3864e+00 1.2803e+00 9.2995e-01 9.4995e-01 7.5115e-01 6.8022e-01 3.4295e-01 4.5633e-01
+ 4.1545e-01 3.0899e-01 3.3581e-01 2.3053e-01 1.6846e-01 2.5097e-01 5.9848e-02 2.4547e-01
+ 2.7385e-01 2.0386e-01 2.3661e-01 1.8560e-01 1.0426e-01 1.7907e-01 1.1482e-01 4.5498e-02
+ 1.1747e-01 1.3847e-01 1.3306e-01 9.2920e-02 1.1993e-01 1.8310e-02 9.5635e-02 1.0463e-01
+ 2.6817e-02 6.6566e-02 9.7699e-02 2.3079e-02 9.4800e-02 6.0603e-02 7.8431e-02 9.9629e-02
+ 1.2796e-01 3.3724e-02 -2.4921e-02 1.0316e-01 8.1378e-02 5.2280e-02 1.1549e-01 1.7163e-01
+ 1.0303e-01 1.3074e-01 -9.2197e-03 9.2015e-02 2.7529e-02 4.6778e-02 9.6673e-02 -nan(ind)
+ 3.0589e-02 3.5749e-02 -nan(ind) 4.0173e-03 1.7734e-01 -1.6677e-03 -1.1857e-02 -1.6516e-03
+ -3.0266e-04 8.1057e-02 6.8714e-02 -3.5196e-02 -4.7740e-03 5.0433e-03 9.1741e-02 5.6280e-02
+ 1.1920e-01 1.4405e-01 2.0925e-01 1.4581e-01 7.5867e-02 2.6585e-01 2.8331e-01 2.0654e-01
+ 1.0092e-01 5.1608e-02 1.2263e-01 2.1291e-01 2.1480e-01 2.5854e-01 2.2843e-01 2.7872e-01
+ 2.2980e-01 3.0764e-01 4.5734e-01 3.4655e-01 6.1841e-01 9.4003e-01 1.0514e+00 1.0930e+00
+ 1.1615e+00 1.1169e+00 1.2059e+00 1.1775e+00 1.1076e+00 1.2239e+00 7.6262e-01 7.2453e-01
+ 5.1534e-01 3.5613e-01 3.5025e-01 2.3773e-01 3.3989e-01 -5.2716e-03 1.9451e-01 1.4243e-01
+ 1.1473e-01 9.8310e-02 1.3981e-04 -7.3912e-02 1.0376e-02 2.9803e-01 7.7699e-02 2.8957e-01
+ 2.8814e-02 6.1948e-02 1.1289e-01 -5.2427e-02 1.3860e-01 5.7700e-02 8.7206e-02 1.0939e-01
+ 8.4662e-02 3.8397e-02 1.6770e-01 2.1244e-02 1.6617e-01 -1.6763e-02 -4.1441e-02 -2.0242e-02
+ 2.6362e-02 -nan(ind) 1.3079e-01 -2.8107e-03 6.6160e-02 2.6879e-02 4.9722e-02 1.2697e-01
+ 2.1502e-02 1.3451e-01 2.9544e-02 7.3937e-02 7.3362e-02 6.3302e-02 1.0723e-01 3.7129e-02
+ 9.1189e-02 7.9138e-02 9.0344e-02 1.2078e-01 2.6692e-02 -3.1529e-02 2.2820e-02 9.7385e-02
+ 2.2966e-03 4.1216e-02 1.0349e-01 1.5388e-01 1.0215e-01 9.3486e-02 8.9406e-02 1.2481e-01
+ 8.9002e-02 -2.5538e-02 2.9168e-02 8.0416e-02 -1.8656e-02 1.6074e-01 2.5503e-02 8.3599e-02
+ 1.0093e-01 2.3323e-01 3.1956e-01 1.1695e-01 1.1870e-01 3.3187e-02 7.4998e-02 4.5350e-02
+ 2.2200e-01 2.7318e-01 1.2611e-01 3.6507e-01 5.2794e-01 3.9931e-01 4.8388e-01 4.0408e-01
+ 6.0007e-01 8.4706e-01 5.9954e-01 7.4405e-01 6.5257e-01 8.6036e-01 1.0524e+00 4.2135e-01
+ 6.8988e-01 7.7512e-01 5.0025e-01 5.2971e-01 4.1169e-01 2.0476e-01 4.1716e-01 3.6515e-01
+ 4.9072e-01 2.7346e-01 2.3146e-01 3.1426e-01 2.2842e-01 7.2003e-02 1.0553e-01 2.6545e-01
+ 1.4912e-01 1.7186e-01 1.7032e-01 2.1910e-01 3.5675e-02 1.4707e-01 5.1810e-02 3.0677e-02
+ 6.9150e-02 5.2272e-02 7.1822e-02 1.0732e-01 3.0684e-02 6.1247e-02 -1.0958e-03 5.2309e-02
+ 4.6201e-02 2.0834e-01 9.3048e-02 1.5195e-01 5.2750e-02 3.0205e-03 1.2808e-01 -6.6075e-02
+ 1.6868e-02 -1.7530e-01 -2.0729e-02 5.9163e-02 2.4171e-01 3.8272e-02 -2.6258e-02 -1.1779e-02
+ -1.0046e-01 1.2377e-01 4.6310e-02 4.2166e-02 -7.1083e-03 1.0075e-01 7.6371e-02 3.7999e-02
+ -5.5570e-05 -7.6931e-03 -nan(ind) 6.3530e-02 6.6988e-02 7.1492e-02 2.3146e-01 4.1851e-02
+ 9.1160e-02 8.8889e-02 2.6919e-02 -3.0836e-03 1.1119e-01 1.0342e-01 -1.6963e-02 -3.1356e-02
+ 5.9210e-02 1.7974e-01 3.2222e-03 3.4731e-02 8.4339e-02 1.0196e-01 1.3558e-01 2.0110e-01
+ 1.3564e-01 5.6261e-02 2.0531e-01 1.1009e-01 2.3677e-01 2.3598e-01 2.3968e-01 1.7919e-01
+ 2.1825e-01 4.1446e-01 2.5324e-01 4.3045e-01 3.5009e-01 5.2498e-01 7.9369e-01 5.1122e-01
+ 4.9195e-01 6.3148e-01 5.1591e-01 4.6831e-01 4.7429e-01 4.6248e-01 4.6013e-01 3.1747e-01
+ 1.3910e-01 3.0172e-01 1.4489e-01 2.9744e-01 3.6779e-01 1.5056e-01 2.4160e-01 1.4177e-01
+ 2.2842e-02 1.7221e-01 4.2508e-02 1.6955e-01 2.5537e-01 3.0692e-01 2.0952e-01 4.7080e-02
+ 1.0455e-01 -3.4645e-02 1.6477e-01 -7.5254e-03 -1.0853e-02 1.0512e-01 7.7630e-02 3.2562e-02
+ 1.2529e-01 4.4666e-03 -8.4431e-03 1.3187e-01 1.5873e-01 6.4130e-02 -4.0459e-02 -1.1060e-02
+ 8.2744e-02 1.7146e-01 1.4635e-01 5.2807e-02 4.8194e-02 5.0714e-02 1.1827e-01 5.7718e-02
+ 1.3268e-01 5.8482e-02 9.8078e-03 5.8749e-02 1.1345e-01 1.5401e-01 1.0537e-01 -nan(ind)
+ 2.3445e-02 1.0260e-01 -1.4347e-02 -3.3711e-02 3.3816e-02 6.3374e-02 3.7052e-02 2.8335e-02
+ 8.8786e-03 -1.4218e-02 7.3311e-02 1.7771e-01 1.4347e-01 3.4786e-02 1.2354e-01 5.0907e-02
+ 1.1374e-01 1.2547e-01 8.1943e-02 9.6542e-02 1.4634e-01 1.3908e-01 4.4337e-02 3.1634e-02
+ 1.1176e-01 2.2736e-01 3.5353e-01 2.6919e-01 2.1577e-01 1.1470e-01 -1.3905e-01 1.4896e-01
+ 1.1255e-01 2.7131e-02 4.4086e-02 2.1449e-01 9.9221e-02 1.5584e-01 1.9856e-01 3.4362e-01
+ 4.6167e-01 3.4165e-01 3.9911e-01 3.3259e-01 5.6519e-01 3.3210e-01 3.0158e-01 5.4351e-01
+ 4.0826e-01 3.4220e-01 1.1289e-01 4.4205e-01 2.1069e-01 3.5814e-01 2.4246e-01 1.4811e-01
+ 2.5414e-01 2.0826e-01 1.1470e-01 1.9114e-01 1.9584e-01 2.2404e-01 1.5431e-01 3.8427e-01
+ 2.1243e-01 1.4029e-01 1.8541e-01 1.5492e-01 1.5137e-01 1.5701e-01 1.0807e-01 3.4714e-02
+ 2.1901e-02 -4.9797e-03 8.7255e-02 6.4614e-02 1.2396e-01 -4.2467e-03 1.1163e-01 2.8491e-02
+ 1.1854e-02 5.2013e-02 2.1779e-02 1.1997e-01 3.8683e-02 6.5248e-02 1.2138e-02 6.5854e-02
+ 1.2322e-01 3.5143e-01 7.7191e-02 8.2605e-02 2.0588e-01 6.9599e-02 1.1393e-01 5.9054e-03
+ 4.7015e-02 4.2655e-02 9.0135e-02 1.0344e-01 -nan(ind) 3.2417e-02 -4.2391e-02 -2.9055e-02
+ 7.7491e-02 5.8895e-02 -3.8575e-02 -1.3206e-02 7.8564e-02 2.1897e-03 1.6350e-01 1.1590e-01
+ 4.3194e-02 1.4792e-01 6.4371e-02 -1.4738e-02 8.7108e-02 -5.5261e-02 -1.0336e-02 2.2562e-02
+ 5.6438e-02 1.1587e-01 -6.2253e-02 2.9059e-01 1.6577e-01 3.5923e-02 1.0620e-01 2.4856e-01
+ 2.8526e-01 9.0465e-02 8.6932e-02 1.1278e-01 8.0703e-02 8.9223e-02 1.5097e-01 4.3670e-02
+ 2.0150e-01 3.2378e-01 3.2991e-01 2.8677e-01 3.4415e-01 1.4910e-01 3.4345e-01 2.4646e-01
+ 4.4433e-01 3.9694e-01 5.1221e-01 4.9702e-01 4.2999e-01 2.6248e-01 1.0543e-01 3.1621e-01
+ 4.1223e-01 2.3081e-01 1.5150e-01 1.7742e-01 2.9936e-01 2.0813e-01 1.8887e-01 -2.1434e-02
+ 3.8352e-02 9.8018e-02 3.1794e-01 5.5946e-01 2.4338e-01 3.1254e-01 1.8277e-01 3.2459e-01
+ 1.9422e-01 1.8819e-01 1.4812e-01 9.2561e-02 7.9539e-03 1.5433e-01 1.6420e-01 6.2786e-02
+ -8.7951e-03 6.0482e-02 8.3146e-02 2.4305e-02 4.9427e-03 -8.8576e-03 4.9653e-02 -3.7910e-02
+ -4.2156e-03 6.4791e-02 6.7685e-03 1.0906e-01 2.3689e-02 1.3806e-01 2.4213e-02 6.5018e-02
+ 1.1045e-01 1.1441e-01 -7.2831e-03 -nan(ind) 9.6085e-02 -nan(ind) 5.8238e-02 1.8699e-02
+ 2.5463e-02 -1.5952e-02 -2.6333e-02 5.2841e-04 9.8976e-02 5.1084e-02 1.1558e-02 -3.0189e-02
+ 4.9353e-02 6.3691e-02 -2.2519e-02 8.8323e-02 1.7127e-01 -1.0657e-02 5.6045e-02 -8.8169e-03
+ 5.3881e-02 3.2382e-02 4.8757e-02 -3.0727e-03 1.2514e-01 2.6578e-02 3.4472e-02 7.1039e-02
+ 1.3637e-01 9.1147e-02 9.2820e-02 1.4565e-01 2.2869e-01 3.3097e-01 1.0842e-01 4.0892e-03
+ 2.2249e-01 2.5762e-01 8.6192e-02 2.8525e-02 5.8138e-02 1.7777e-01 1.7902e-01 2.4325e-01
+ 1.8831e-01 7.6591e-02 3.2909e-01 2.6896e-01 3.7816e-01 2.3691e-01 -3.2754e-02 5.2780e-01
+ 2.4701e-01 3.2698e-01 2.6796e-01 4.7745e-01 4.0919e-01 1.1126e-01 2.2161e-01 5.0409e-02
+ 2.6324e-02 3.7653e-01 1.6790e-01 1.8781e-01 2.0437e-01 1.9948e-02 2.6314e-01 1.6938e-01
+ 1.7242e-01 1.9354e-01 -6.3660e-02 3.7631e-02 5.9980e-02 6.1286e-02 5.6540e-03 4.8167e-02
+ 9.9147e-02 7.7708e-02 1.1204e-01 -1.9050e-02 3.3907e-02 1.0513e-01 1.3146e-01 5.7072e-02
+ 4.3531e-02 1.4112e-03 8.5470e-02 -1.8784e-02 4.3348e-02 4.8738e-02 -1.1682e-02 1.4880e-01
+ 1.0106e-01 4.9615e-02 7.3713e-02 4.8900e-02 5.0828e-02 3.6102e-02 -nan(ind) -1.6349e-02
+ 1.0653e-01 1.3667e-01 2.9786e-02 1.2622e-01 3.6617e-02 4.3359e-02 3.3690e-02 5.2564e-02
+ -1.4199e-02 1.3857e-02 1.0075e-01 3.3568e-02 1.6230e-01 8.1029e-02 1.3066e-01 -3.1683e-02
+ 4.6657e-02 -2.5790e-02 1.1592e-01 1.1931e-01 2.0876e-01 -6.1690e-02 8.8157e-02 7.7986e-02
+ 1.6142e-01 1.0706e-01 5.1612e-02 2.8650e-01 2.3643e-01 -5.8427e-04 1.0729e-01 1.2985e-01
+ 5.2319e-01 4.2805e-01 9.7731e-02 1.0513e-01 8.6240e-03 1.2704e-01 2.7607e-01 7.6182e-02
+ 2.0809e-01 3.2205e-02 2.1390e-01 2.6908e-01 8.8808e-02 1.4493e-01 1.8468e-01 5.2270e-01
+ 1.4734e-01 1.9968e-01 1.0396e-01 3.8208e-01 3.3774e-01 2.6642e-01 2.8707e-01 1.3604e-01
+ 3.1215e-02 1.0446e-01 2.6565e-01 1.8233e-01 6.3433e-02 5.9791e-02 1.5746e-01 1.7889e-01
+ 1.5822e-01 2.4373e-01 2.1236e-01 1.1352e-01 3.2317e-01 7.0659e-02 3.5866e-01 1.2036e-01
+ 2.5581e-01 1.0540e-01 6.5763e-03 3.7549e-02 6.7453e-02 -2.6389e-02 1.3915e-01 -4.4191e-02
+ 1.0341e-01 7.1334e-02 9.5531e-02 -2.0628e-02 5.3883e-02 5.4872e-02 -9.3881e-03 -2.8935e-02
+ 5.5921e-02 7.4927e-02 9.3720e-02 4.9263e-02 9.8496e-02 -7.8018e-03 6.3621e-02 6.0473e-02
+ -3.9812e-02 6.5691e-04 9.6763e-02 3.0702e-02 7.7331e-02 1.1207e-01 3.4444e-02 1.5069e-01
+ -9.6769e-03 1.2625e-01 6.3052e-02 6.0871e-02 -2.5186e-02 -nan(ind) 4.2000e-02 -2.7233e-03
+ 7.9542e-02 9.4633e-02 -nan(ind) -2.7255e-02 8.0778e-02 5.4292e-02 2.4627e-02 7.5747e-02
+ 3.5242e-02 1.0773e-01 8.9082e-02 -1.5071e-01 1.2274e-01 2.9283e-02 2.7751e-02 -3.8832e-02
+ 1.9862e-02 8.8868e-04 1.4624e-01 2.1059e-01 4.0106e-02 1.5361e-01 2.3612e-01 2.3119e-01
+ 3.3292e-02 4.7162e-01 8.1690e-03 6.8454e-02 2.9853e-02 1.3064e-01 2.2052e-01 2.6203e-01
+ -7.8762e-02 2.7970e-01 5.9738e-02 1.9661e-01 5.8459e-02 1.1806e-01 5.5674e-02 -5.0508e-02
+ 2.0669e-01 1.7723e-01 2.3695e-01 2.0601e-01 1.3879e-01 3.5447e-02 7.0254e-02 8.3994e-02
+ 2.3821e-01 -8.8510e-03 2.8104e-02 1.2962e-01 3.2160e-01 4.3880e-01 2.6848e-01 9.3419e-03
+ 3.0525e-01 1.4552e-01 1.6775e-01 -2.7117e-02 -5.0458e-02 -3.6240e-02 8.3724e-02 1.1894e-01
+ 9.3160e-02 5.7902e-02 1.1642e-02 1.6226e-01 5.3938e-02 2.9841e-02 1.3674e-01 8.3136e-02
+ -2.8867e-02 5.2373e-02 1.7924e-01 -5.7183e-02 -6.2622e-02 1.5895e-02 -5.5121e-02 5.9391e-02
+ 2.0981e-02 -7.8119e-02 2.7324e-02 6.5999e-02 1.7035e-01 5.0554e-02 1.0695e-01 -8.0490e-02
+ 9.3125e-02 -1.0566e-02 1.1597e-03 6.3520e-02 -2.0340e-02 1.2714e-01 -6.8413e-02 1.2666e-01
+ -2.2536e-02 9.5033e-03 5.7112e-02 1.5881e-02 1.1476e-01 5.7195e-02 2.1049e-01 9.3774e-02
+ 7.1586e-03 1.0791e-02 1.7301e-01 6.7184e-02 5.8046e-02 5.0212e-02 -4.1216e-02 3.6504e-02
+ 1.2228e-01 1.2235e-01 1.2160e-01 3.2743e-01 1.1332e-01 2.1596e-01 -1.7624e-02 1.2431e-01
+ 2.5481e-01 3.0578e-01 2.0558e-01 2.8554e-01 1.7639e-01 1.1295e-01 1.2161e-01 3.1734e-01
+ 1.8143e-01 2.0550e-01 -5.5509e-02 1.7681e-01 5.3796e-01 1.6700e-01 1.3011e-01 -1.3295e-03
+ 1.2292e-01 1.4598e-01 1.0510e-02 -2.9981e-01 2.0716e-01 4.7628e-02 1.6743e-01 3.9293e-02
+ 8.4357e-02 2.2718e-01 2.1110e-02 2.0779e-01 2.2696e-01 3.0314e-01 -1.2425e-01 4.1803e-01
+ 2.5708e-01 3.4533e-01 3.3869e-01 3.2525e-01 1.4775e-01 1.4145e-01 2.4940e-03 2.7253e-02
+ 1.9483e-01 2.2210e-01 9.7152e-02 -2.1943e-02 9.9769e-02 -8.2652e-03 8.3107e-02 1.8007e-02
+ 1.1650e-02 5.7018e-02 7.2328e-02 7.3573e-02 5.3164e-02 -1.3716e-02 -4.7384e-02 1.5627e-01
+ 1.4237e-01 1.1416e-01 -2.8515e-02 5.8978e-02 5.7398e-02 6.0608e-02 7.8417e-02 3.3371e-02
+ 1.2925e-01 -4.4397e-03 7.5359e-02 -5.7276e-04 1.8431e-01 3.9566e-02 1.1187e-01 8.7886e-03
+ 2.3225e-02 2.0428e-02 1.1300e-01 1.3592e-01 1.5065e-02 5.8294e-02 1.4802e-02 6.1713e-02
+ 1.0461e-01 2.7443e-01 9.2272e-02 6.8582e-02 1.3351e-02 6.5926e-03 3.1075e-02 2.1571e-01
+ 1.2192e-01 4.1101e-02 4.6733e-02 1.5252e-01 1.2208e-02 1.1217e-01 5.2821e-02 4.0669e-02
+ 6.9900e-03 -9.1881e-03 2.6714e-01 1.2338e-01 4.0824e-02 3.0729e-01 1.8889e-01 3.8339e-01
+ 4.3745e-01 4.0249e-01 2.9734e-01 1.5220e-01 -4.2559e-04 3.1669e-01 4.4434e-02 1.0813e-01
+ 1.0849e-01 1.6378e-01 9.0984e-02 3.8456e-02 1.9339e-01 5.9353e-02 1.1479e-01 1.1469e-01
+ 8.3696e-02 2.8147e-01 1.4353e-02 1.5122e-02 3.5543e-02 1.6577e-01 6.1712e-02 6.8824e-02
+ 3.1932e-01 1.9919e-01 1.2653e-01 4.1433e-01 1.1781e-02 2.9144e-01 1.5119e-01 1.0404e-01
+ 5.7136e-03 3.5397e-02 1.0772e-01 5.9641e-02 2.1617e-02 -2.8872e-02 1.0784e-01 8.8653e-02
+ 7.9680e-02 4.4178e-02 1.1004e-01 1.2628e-03 1.2802e-01 1.1871e-01 -3.8569e-02 2.0173e-01
+ 6.3388e-02 6.6226e-02 -1.0223e-01 5.6903e-02 8.1884e-02 2.8368e-02 1.5741e-01 -8.7742e-03
+ 9.7805e-03 -2.1384e-02 6.7266e-02 1.1453e-01 6.2040e-02 9.1357e-02 -1.2091e-02 3.3157e-02
+ 6.2638e-02 -2.7538e-02 -1.4213e-02 -5.1904e-02 -1.1528e-02 5.5079e-02 1.7938e-01 1.3599e-01
+ 4.6659e-04 8.2666e-02 2.1075e-01 5.4772e-02 1.6242e-02 3.3195e-02 1.2334e-01 2.6923e-02
+ 1.2368e-01 2.2319e-01 7.7534e-03 9.1328e-02 8.6568e-02 6.2528e-02 -1.4577e-01 -5.4548e-02
+ 1.2602e-02 -2.5249e-02 3.5251e-01 7.4711e-02 8.2228e-03 -3.0876e-02 1.6750e-01 2.2140e-01
+ 1.3634e-01 6.9774e-02 1.7597e-01 3.4455e-01 2.0608e-01 1.2312e-01 3.2749e-01 1.4020e-01
+ 1.4689e-01 3.4214e-01 6.8409e-02 1.2780e-01 1.8076e-01 1.4314e-01 1.7582e-01 3.4842e-02
+ 1.0556e-01 1.9862e-01 5.9653e-02 3.8190e-01 -2.0307e-02 7.3616e-02 7.3229e-02 -5.8523e-03
+ 1.3312e-01 5.5809e-02 2.9805e-01 2.1976e-01 2.9059e-01 2.9544e-01 2.3412e-01 1.7410e-01
+ 2.4356e-01 1.6995e-01 9.9325e-02 1.0284e-01 1.0973e-01 -5.3375e-03 -8.0379e-02 4.6416e-02
+ 1.3650e-01 1.6038e-01 2.1634e-02 5.8889e-02 1.5123e-01 -3.0877e-02 5.3672e-02 3.1893e-02
+ 8.8900e-02 4.2788e-02 5.7329e-02 8.3579e-02 1.3177e-01 7.4542e-02 3.5083e-02 1.7958e-01
+ 1.2311e-01 1.2354e-01 -2.0848e-01 1.6030e-01 2.4807e-02 7.9044e-02 4.0095e-02 3.5993e-02
+ 1.8132e-02 5.9538e-02 4.0704e-02 2.5228e-02 4.8230e-02 3.4224e-02 -3.8758e-02 1.0936e-01
+ 4.4847e-02 1.7741e-01 1.1277e-01 1.5694e-01 1.0587e-01 -nan(ind) -3.8869e-02 6.3875e-02
+ 1.8080e-02 8.7939e-02 1.3716e-01 5.5479e-02 6.9162e-02 -5.3682e-02 1.4400e-02 -3.2133e-02
+ 9.0483e-02 -6.0871e-02 1.8984e-02 -4.3032e-04 3.2099e-02 7.0191e-02 4.0218e-02 -1.8771e-02
+ 1.2061e-01 -4.5150e-03 -6.2269e-02 5.5313e-02 6.6849e-02 -4.6945e-02 1.8420e-01 -7.8583e-02
+ 1.1964e-01 1.9189e-01 1.0816e-01 2.0020e-01 1.6820e-01 3.1829e-01 2.2712e-01 2.7621e-01
+ 1.1872e-01 6.0477e-02 1.1009e-01 9.0039e-02 9.6466e-03 -7.8662e-02 1.0674e-01 4.4711e-01
+ 8.0682e-02 -4.2430e-02 1.5800e-01 9.5741e-02 3.7826e-01 1.4788e-01 4.7600e-01 4.6818e-01
+ 2.8387e-01 2.1101e-01 1.9801e-01 2.6413e-02 1.5863e-01 5.6482e-02 1.1240e-02 4.1850e-02
+ 1.8698e-01 3.7008e-02 1.4022e-01 -2.9201e-02 1.5644e-01 5.7846e-02 3.9106e-03 -2.2068e-02
+ 6.9310e-02 4.5476e-02 1.5989e-01 1.1679e-01 5.1935e-02 2.6989e-02 7.4015e-02 1.1982e-01
+ 2.8320e-02 4.6370e-02 1.8855e-01 1.1645e-01 6.0541e-02 9.3692e-05 2.7090e-01 7.2877e-02
+ 1.1270e-01 4.6933e-02 1.4886e-01 6.0936e-02 1.2809e-01 3.3889e-02 1.7965e-01 2.6599e-01
+ 6.2874e-03 1.7787e-02 7.7297e-02 -nan(ind) 1.9049e-01 -4.9249e-02 4.7840e-02 -6.1597e-02
+ 1.0121e-01 1.5793e-02 2.7190e-01 1.1161e-01 7.3725e-02 8.9637e-02 1.7010e-01 1.2387e-02
+ 1.6861e-01 2.0716e-02 1.7383e-03 2.8104e-01 1.0342e-01 1.8465e-01 3.8177e-02 1.1160e-01
+ 2.1378e-02 1.4151e-02 3.3028e-02 -4.3740e-02 1.1037e-01 1.7456e-01 -2.6948e-03 -3.4144e-02
+ 1.6181e-01 3.8771e-02 1.6545e-01 9.0503e-02 2.2480e-01 9.1892e-02 2.8033e-02 9.5780e-02
+ 1.9617e-01 1.7186e-01 1.6060e-01 2.8040e-01 3.0766e-01 1.8124e-01 3.7208e-02 2.7950e-02
+ 1.2955e-01 1.9671e-01 1.2573e-01 6.3090e-01 9.3788e-02 2.5946e-01 1.9351e-01 3.2762e-01
+ 1.3878e-01 4.3767e-01 3.7991e-01 2.6037e-01 2.1155e-01 1.0016e-01 -1.3068e-02 1.2863e-01
+ 8.2327e-02 1.3475e-01 8.1282e-02 2.1929e-01 2.2666e-01 -2.6738e-02 1.0568e-01 1.1622e-01
+ 1.4744e-01 -4.3814e-02 -4.3156e-03 1.0092e-01 1.0030e-01 3.9105e-02 1.9941e-02 -4.3952e-02
+ 1.1675e-01 2.0530e-01 7.5368e-02 3.4443e-03 3.0144e-02 4.9326e-03 1.0505e-01 3.3396e-02
+ 2.5360e-02 2.2965e-01 1.2152e-01 1.1364e-01 3.4520e-02 4.8948e-02 5.6386e-02 1.0265e-01
+ -3.0535e-02 1.4237e-01 8.9631e-02 1.6055e-01 5.5322e-03 2.1615e-03 8.3857e-02 -9.9603e-02
+ 2.5785e-02 1.1850e-01 8.2053e-02 -2.4454e-02 2.4390e-02 2.1756e-01 1.1780e-01 1.3928e-01
+ -2.9454e-02 5.6759e-02 5.7406e-02 1.2882e-01 -2.1162e-02 1.4681e-01 1.5894e-01 2.2062e-01
+ -4.6511e-02 1.7513e-01 1.1298e-01 3.3520e-02 1.8194e-01 5.7351e-02 7.3712e-02 7.1886e-02
+ -1.0459e-01 1.0498e-01 7.6530e-02 1.3015e-01 1.7795e-01 8.7072e-02 1.9349e-02 2.2853e-01
+ -8.7808e-02 1.1696e-01 2.4953e-01 2.7736e-01 3.7167e-01 1.2571e-01 4.1610e-01 2.9624e-01
+ 3.4866e-01 2.7439e-01 3.2992e-01 8.8817e-02 1.5263e-01 2.9032e-01 2.3210e-01 3.0532e-01
+ 3.2107e-01 3.0477e-01 2.7607e-01 1.7864e-01 1.3727e-01 1.8182e-01 1.4864e-01 2.0778e-03
+ 9.5386e-02 3.5792e-03 1.1500e-01 7.4634e-02 1.8288e-01 1.7302e-02 1.5950e-01 1.4636e-01
+ 1.0597e-01 1.3460e-01 6.8100e-02 5.6913e-02 -2.1371e-02 -2.3682e-02 1.7357e-01 -7.9361e-02
+ -5.9081e-02 7.9112e-02 6.8665e-02 3.6777e-02 8.9182e-02 2.6900e-02 1.7225e-01 1.1138e-01
+ 2.6153e-02 1.3639e-03 1.4545e-01 2.4461e-02 7.3116e-02 1.2984e-02 6.8188e-02 9.0080e-02
+ 5.3882e-02 4.8226e-02 5.9987e-02 9.7973e-02 2.1495e-02 1.1590e-01 9.0939e-02 1.0314e-01
+ 3.4188e-02 6.3510e-02 6.3264e-02 1.6474e-01 5.2752e-02 6.3934e-02 -4.4299e-02 -nan(ind)
+ -2.8828e-02 9.9767e-02 6.0322e-02 7.5655e-02 -3.2859e-02 1.0194e-01 -1.1234e-01 2.8083e-02
+ 4.0220e-04 1.4304e-01 5.6858e-02 -3.9497e-02 3.5412e-02 2.4148e-03 6.8734e-02 -6.7521e-03
+ 1.0377e-01 5.4106e-02 6.2498e-02 -7.8804e-02 5.9177e-03 9.4101e-02 9.6831e-02 9.4562e-02
+ 2.1810e-01 4.9459e-02 2.9614e-01 1.5853e-01 2.2339e-02 4.5934e-02 1.6602e-01 1.5237e-01
+ 1.4505e-01 1.0870e-01 1.0798e-01 2.7949e-01 1.6916e-01 2.9752e-01 2.7376e-01 2.7013e-01
+ 6.7319e-02 1.1578e-01 3.2227e-01 2.2192e-01 3.7534e-01 1.2077e-01 1.7420e-01 1.7458e-01
+ 1.3041e-01 1.2673e-01 2.0169e-01 3.7011e-01 2.3862e-01 1.1758e-01 -4.1048e-02 4.9389e-02
+ 2.9518e-01 1.2305e-01 1.4499e-01 -5.6167e-02 8.9175e-02 -2.4497e-02 2.0263e-02 -1.7059e-02
+ 3.9953e-02 8.4901e-02 1.3015e-01 6.3299e-02 6.4218e-02 1.5221e-01 1.9800e-01 -4.3393e-02
+ -1.5401e-02 7.8023e-02 -2.5238e-02 1.0009e-03 1.2989e-01 -8.7220e-02 1.4099e-02 2.1036e-02
+ 1.0893e-01 1.5507e-02 -nan(ind) 2.9010e-02 -nan(ind) 1.2312e-01 4.9986e-02 -2.9110e-02
+ 1.5459e-01 1.6401e-02 6.2448e-02 5.5517e-02 1.4566e-01 -nan(ind) 1.1394e-01 2.3352e-02
+ 5.1416e-02 -2.3007e-02 -4.6830e-02 6.2382e-02 -3.6035e-02 9.1847e-02 8.7805e-03 6.4020e-02
+ 9.3066e-02 2.2859e-02 2.5743e-01 -1.8870e-02 1.0273e-01 1.3392e-01 1.5761e-01 -7.2820e-03
+ 1.2077e-01 2.0567e-01 7.5403e-02 1.1056e-02 7.9284e-02 -1.0015e-01 2.5851e-02 3.4130e-02
+ 5.2953e-02 1.3877e-02 7.9086e-02 2.4561e-02 7.5485e-02 8.5110e-02 -5.8114e-02 1.6717e-01
+ 1.2665e-01 4.6053e-03 1.4797e-01 2.7963e-01 7.2911e-02 8.7051e-02 2.2591e-01 1.4493e-01
+ 3.2660e-01 2.4597e-01 1.4182e-01 1.4047e-01 2.8385e-01 1.3550e-01 2.0130e-01 1.8659e-02
+ 1.1391e-01 3.6760e-01 1.5116e-01 2.0477e-01 7.4668e-02 1.9568e-01 2.6805e-02 2.8489e-02
+ -1.2760e-02 1.1540e-01 6.3606e-02 2.0643e-01 3.2918e-02 3.1649e-02 1.6552e-01 2.0487e-03
+ 2.1120e-01 4.5238e-02 4.5505e-02 1.3404e-01 1.0939e-01 -2.8810e-02 1.8885e-01 1.8961e-01
+ 5.9896e-03 -3.9629e-04 2.7470e-02 -7.6789e-02 1.3653e-02 -2.4979e-02 2.2674e-02 8.0309e-02
+ 4.7871e-02 8.2671e-02 6.2329e-02 -1.1486e-03 3.9040e-02 1.1624e-01 4.5960e-02 7.3564e-02
+ 7.1279e-02 2.6451e-02 8.2279e-02 -2.1865e-02 5.3877e-02 3.3649e-02 9.9992e-02 -1.9698e-02
+ 4.1748e-02 -2.3395e-02 1.7608e-01 -2.6998e-02 1.6800e-02 1.3431e-02 -3.8756e-02 2.0947e-01
+ 9.9499e-02 2.4734e-02 1.9219e-03 1.8288e-01 -3.0672e-03 1.9000e-02 1.3568e-01 1.5888e-01
+ 1.0217e-01 5.7933e-02 -2.3485e-02 -1.0983e-01 1.5924e-01 5.3333e-02 1.1415e-01 1.3285e-01
+ 1.9290e-01 6.6693e-02 2.1302e-02 1.0822e-01 1.4825e-01 2.2449e-01 1.5806e-02 3.5471e-02
+ 1.4623e-01 1.5351e-01 6.9000e-02 4.6460e-02 9.3141e-02 9.6145e-02 1.2884e-01 3.7914e-02
+ 6.8152e-02 1.7929e-01 3.0197e-02 9.2251e-03 2.9429e-01 8.4495e-02 1.7606e-01 3.1105e-01
+ 1.3268e-01 9.5586e-02 2.6243e-03 1.0782e-01 2.2416e-01 1.7738e-01 6.8811e-02 -4.8865e-03
+ 1.5031e-01 4.7937e-02 9.1903e-02 7.4936e-02 1.2987e-01 4.5053e-02 -1.0070e-02 -4.6559e-03
+ 9.1363e-02 -1.8477e-02 1.3323e-01 -1.7444e-02 1.3255e-01 1.4659e-02 -2.8436e-02 2.8719e-02
+ 5.6894e-02 9.7940e-02 -6.7083e-02 -4.6920e-02 2.7789e-02 -6.9077e-03 1.4497e-02 9.2388e-02
+ -9.5600e-03 1.2863e-01 9.9040e-02 1.7671e-01 6.1865e-02 4.9097e-02 1.0726e-01 9.0817e-02
+ 1.1080e-01 3.9188e-02 -2.2543e-03 1.7851e-01 5.6685e-02 1.2074e-01 1.7137e-02 -4.1180e-03
+ 1.7375e-01 3.6171e-02 1.3551e-01 -nan(ind) 1.2332e-01 -1.6761e-02 1.3855e-01 1.5116e-01
+ 3.1362e-02 -nan(ind) 5.1007e-02 1.5022e-01 9.0510e-02 5.9868e-02 8.9480e-02 2.0103e-02
+ 3.2093e-02 1.1867e-01 6.6199e-02 1.7743e-01 4.0895e-02 -2.7728e-02 6.6319e-04 4.6047e-02
+ -1.0252e-03 2.1772e-02 1.5280e-01 1.0270e-02 2.5072e-01 2.2326e-02 1.6986e-01 6.6842e-02
+ 1.6823e-01 -1.0530e-01 6.8401e-02 6.8534e-02 -3.1146e-02 1.1361e-01 5.5162e-02 8.7319e-02
+ 6.1465e-02 5.6847e-02 5.3146e-02 1.2977e-01 2.0062e-01 1.4979e-01 6.2581e-02 1.3365e-02
+ 2.3347e-01 1.7623e-01 1.3086e-01 1.2120e-01 3.8388e-02 1.5430e-01 5.0393e-02 -9.4020e-03
+ 7.7302e-02 8.1996e-02 1.0665e-01 7.1895e-02 6.4045e-02 1.0615e-01 2.7511e-02 1.0989e-01
+ 2.2556e-02 1.2589e-01 -1.0325e-01 3.1041e-02 1.0260e-01 7.7829e-02 1.8129e-01 8.1259e-02
+ 6.3533e-02 5.7519e-02 2.2100e-01 1.2841e-01 1.0699e-01 1.1136e-01 2.3852e-02 -6.7427e-02
+ -1.3045e-02 3.7022e-02 -6.3604e-02 1.0927e-01 7.3638e-02 6.4205e-02 5.8029e-02 6.9437e-02
+ 8.3157e-02 3.5575e-02 1.4782e-01 8.1163e-02 4.4189e-02 -6.0148e-03 1.0369e-01 -2.3975e-02
+ 7.3931e-02 1.2997e-01 1.0959e-01 8.0343e-02 1.0559e-01 3.7599e-02 2.1822e-02 5.0952e-02
+ 4.0605e-02 2.8023e-02 4.2053e-02 8.2738e-02 -8.4038e-03 6.3498e-02 1.1472e-02 5.9092e-02
+ 3.4307e-02 -6.1680e-02 -1.0420e-01 -nan(ind) 8.6462e-02 8.8006e-02 5.4847e-02 -6.2544e-02
+ 1.1524e-01 2.6109e-01 7.0661e-02 4.4215e-02 3.0661e-03 7.0642e-04 8.4795e-02 1.0605e-02
+ 2.4908e-02 1.4649e-01 -3.7871e-02 1.3183e-01 1.8894e-01 5.5383e-02 -5.5017e-02 1.1535e-01
+ 7.8422e-02 1.1980e-01 6.6203e-02 1.6268e-01 3.7045e-02 1.3254e-01 1.6506e-01 8.6901e-02
+ 6.3852e-02 -8.9742e-02 2.9861e-02 1.1540e-01 1.5560e-01 8.2692e-02 1.8240e-01 9.9897e-02
+ 4.3164e-02 -6.0991e-02 1.0894e-01 2.6980e-02 1.8967e-01 2.5829e-01 8.4643e-02 1.0606e-01
+ 7.3836e-02 1.2085e-01 2.2893e-01 9.1481e-02 6.9361e-02 -1.7578e-02 6.7762e-02 8.5602e-03
+ 1.6755e-01 1.5860e-01 -2.1703e-04 1.1927e-01 1.1697e-02 2.5440e-02 2.2456e-02 1.9029e-02
+ 6.8632e-02 -3.2890e-02 1.2404e-01 6.8446e-02 -7.6578e-02 6.4100e-02 1.0767e-01 2.2149e-02
+ 8.9829e-02 9.1189e-02 8.7643e-02 8.6307e-02 5.5019e-02 5.9804e-02 8.7582e-02 7.7513e-02
+ -nan(ind) 6.8943e-02 -1.8578e-02 -3.1181e-03 1.3467e-01 1.7092e-02 5.5207e-02 1.6004e-01
+ 4.5756e-02 5.5566e-02 8.5310e-02 5.3220e-02 -5.8205e-03 7.1515e-02 -3.9099e-02 8.5198e-02
+ -3.8316e-02 1.1497e-01 -2.9537e-03 9.6731e-02 2.7164e-02 2.9831e-02 7.3971e-02 2.4381e-02
+ 1.1987e-01 1.8060e-02 6.0593e-02 4.6634e-02 5.0861e-02 4.1331e-02 7.9409e-02 1.0640e-02
+ 8.9614e-02 9.0265e-02 3.3761e-02 7.7508e-02 -2.0006e-02 3.1009e-02 5.3493e-02 -7.7898e-02
+ 2.5522e-02 -9.2261e-03 8.5219e-02 9.9668e-02 1.1359e-01 5.7255e-02 4.0672e-03 1.6625e-02
+ 1.0719e-01 2.1558e-01 1.0096e-01 3.1450e-02 6.7339e-02 5.8215e-02 1.1518e-01 4.6886e-02
+ 1.0181e-01 -1.0868e-03 1.7931e-02 5.7249e-02 6.7719e-02 1.5344e-01 2.6821e-02 -2.6236e-02
+ 1.9192e-01 1.8363e-02 8.9572e-02 -7.4153e-02 1.7325e-02 4.7937e-03 -4.7370e-02 3.8745e-02
+ 2.2400e-02 2.5420e-02 1.5265e-02 6.7148e-02 -8.6340e-02 6.0020e-02 1.5208e-01 -1.6281e-02
+ 4.7440e-02 -6.3179e-02 3.2630e-02 -6.4105e-02 -5.5496e-02 1.9401e-02 -2.0849e-02 -3.1300e-02
+ 1.1920e-01 -3.7224e-04 7.1291e-02 1.0061e-01 8.0414e-02 9.2453e-02 -2.4607e-02 1.9514e-04
+ -1.3953e-03 4.8420e-02 -1.3922e-02 1.1325e-01 5.5009e-02 6.6245e-03 1.1182e-01 6.7664e-02
+ 3.3564e-02 4.2125e-02 1.7313e-01 2.1844e-02 9.0405e-02 -5.4050e-02 8.3520e-02 -3.9538e-02
+ 2.2657e-01 9.3891e-02 1.4869e-01 8.6057e-02 7.2939e-04 5.0335e-02 3.3692e-02 3.2060e-02
+ -1.0334e-01 9.6460e-03 1.0131e-01 1.8561e-03 1.3863e-01 8.9526e-02 -4.5889e-02 2.0476e-03
+ 1.3324e-03 9.1721e-02 2.3938e-03 9.8462e-02 6.2157e-02 6.3624e-02 8.9190e-03 2.4353e-01
+ 5.3003e-02 6.7324e-02 -1.0136e-01 1.5612e-01 6.1829e-02 9.0816e-02 -1.7528e-02 1.1671e-01
+ 4.2696e-02 1.2414e-01 5.8780e-02 1.4907e-01 5.9298e-02 1.8483e-01 -2.6255e-02 3.7419e-02
+ 1.0356e-01 1.2410e-01 5.6250e-02 9.5116e-02 1.1830e-01 9.0876e-02 2.1687e-01 1.4250e-01
+ 6.9406e-02 1.0630e-01 1.1696e-01 4.7260e-03 1.7564e-01 6.1014e-02 1.3003e-01 7.6148e-02
+ 9.5228e-02 6.3014e-03 2.8743e-02 5.6785e-02 1.1025e-01 -6.2134e-02 -1.4502e-02 -1.3064e-02
+ 4.5619e-02 -7.5004e-03 1.6066e-02 5.3620e-02 7.2819e-02 6.9577e-02 -5.0854e-02 5.4046e-02
+ 6.1871e-02 1.9826e-01 5.1968e-02 7.6584e-02 -3.3719e-02 -5.5538e-03 3.9250e-03 7.4584e-02
+ -6.5676e-03 9.0651e-03 2.6556e-02 4.0402e-02 3.8760e-02 -5.8907e-02 8.2920e-02 5.8022e-02
+ -7.4782e-03 7.6099e-02 3.8171e-02 6.5200e-02 9.2446e-02 1.0652e-01 7.2187e-02 4.0590e-02
+ 1.1785e-01 2.1985e-02 1.4028e-02 1.4523e-01 2.1656e-02 4.3750e-03 8.7113e-02 8.1303e-03
+ 2.3760e-02 7.4217e-02 9.6876e-02 7.6938e-02 -1.1867e-02 6.4380e-02 -2.2554e-02 -9.4459e-03
+ -1.5212e-02 2.2074e-02 -1.5901e-01 6.9129e-02 1.3477e-01 4.4521e-02 9.8180e-02 9.8823e-02
+ 3.3337e-03 1.1612e-02 2.8359e-02 9.8768e-02 1.4922e-01 1.5033e-01 8.4121e-02 6.9649e-02
+ 8.7289e-02 6.4121e-02 1.7067e-01 6.0413e-02 1.5012e-01 1.3972e-01 4.7602e-02 4.6893e-02
+ 2.3236e-02 1.1488e-01 -6.1371e-03 1.4054e-02 1.3714e-01 4.4544e-02 6.8222e-02 6.7395e-02
+ 6.8113e-02 -4.7764e-02 4.2472e-02 -1.7221e-02 1.5265e-01 2.5831e-02 1.6228e-01 1.2649e-01
+ 1.4827e-01 8.2233e-02 1.1523e-01 2.7966e-02 -5.0159e-02 6.0205e-02 3.6854e-02 -8.6192e-02
+ 1.6238e-01 5.9333e-02 7.6809e-02 3.9265e-02 -8.5171e-02 -4.7919e-03 7.9296e-02 3.5810e-02
+ 4.0308e-02 -1.7903e-02 7.3626e-02 2.1383e-02 7.2740e-02 -4.8880e-02 1.6809e-02 3.7459e-02
+ 1.3527e-01 1.4164e-01 1.0258e-02 3.5861e-02 3.7209e-02 4.9393e-02 3.3258e-01 6.5852e-02
+ 1.2349e-01 -4.5063e-02 9.2523e-02 7.2401e-02 8.9098e-02 -5.4263e-03 9.9592e-02 3.3579e-02
+ -7.9557e-02 1.0407e-01 3.0335e-02 5.4582e-02 4.9387e-02 4.3404e-02 2.5149e-02 3.7094e-02
+ -3.2499e-02 3.3217e-02 -3.7142e-02 -4.1084e-02 1.1823e-01 8.1593e-02 2.5819e-02 1.9460e-02
+ -nan(ind) -2.7718e-02 7.7507e-02 3.1025e-02 -4.6746e-02 -3.1921e-02 5.0961e-02 -8.8924e-03
+ 3.5724e-02 9.1430e-02 -8.8036e-03 -6.5790e-02 1.4821e-01 1.3514e-01 3.0807e-02 3.4821e-02
+ 4.3811e-02 -1.7685e-04 1.4721e-01 5.2885e-02 2.7553e-01 9.7933e-02 1.0889e-01 3.3512e-02
+ 1.6181e-01 4.7163e-02 7.7310e-02 5.0645e-02 8.9830e-02 1.3874e-01 -8.9563e-02 2.1640e-01
+ 2.0801e-02 8.4164e-02 1.1480e-01 2.2910e-03 1.4337e-01 1.9496e-02 2.0139e-02 1.0837e-01
+ 1.6501e-02 -1.9938e-02 -9.2788e-02 3.2452e-02 6.6557e-02 -3.4544e-02 1.0657e-01 5.8559e-02
+ 8.3551e-02 5.4245e-02 9.0409e-02 6.6969e-02 8.2305e-02 1.1853e-02 1.3782e-01 6.3295e-02
+ 8.4518e-02 1.7663e-02 -1.7118e-04 1.3973e-01 6.5251e-02 1.4402e-02 2.3602e-02 9.7669e-02
+ 4.6651e-02 5.9286e-02 -5.8695e-03 1.3068e-01 -2.4223e-02 5.8868e-02 1.4255e-02 6.5801e-03
+ 1.4637e-02 5.7550e-02 -2.0799e-03 1.7132e-01 4.5627e-02 1.1159e-01 -2.1556e-02 2.7980e-02
+ 3.5120e-02 6.3444e-02 8.7112e-02 1.0133e-01 6.5583e-03 1.6439e-02 2.3997e-03 1.0874e-01
+ 5.6384e-02 -2.2425e-02 3.5202e-02 5.0255e-04 -1.2849e-02 -1.6572e-02 1.8339e-01 2.6849e-02
+ 4.6405e-02 4.4984e-02 -5.8145e-02 -1.2788e-02 1.5366e-01 4.2086e-02 1.0119e-01 1.7573e-01
+ 7.4092e-02 8.1689e-02 6.0412e-02 8.1078e-02 8.4403e-02 5.9912e-02 2.4772e-01 3.8294e-02
+ 2.2752e-01 5.8636e-02 7.6155e-02 -1.7497e-02 2.6286e-02 1.2793e-01 7.4111e-02 3.4885e-03
+ 3.7912e-02 1.9326e-02 4.3098e-02 1.7960e-02 1.1860e-01 1.0293e-01 -1.1459e-01 -4.9774e-03
+ 7.7393e-03 3.4318e-02 3.0912e-02 1.7190e-01 1.3836e-02 3.5191e-02 -1.4126e-02 1.8268e-01
+ 5.7556e-02 8.7316e-02 1.4602e-01 3.0948e-01 3.9414e-02 3.0808e-01 2.3397e-01 4.7464e-02
+ 1.6009e-01 1.9116e-01 9.5978e-02 5.0134e-02 7.9026e-02 1.0826e-01 1.2124e-01 -5.5239e-02
+ 2.2033e-01 -1.4990e-02 4.8474e-02 -1.3561e-02 1.9641e-01 9.1705e-02 2.4806e-01 5.2530e-02
+ 2.6034e-02 -5.6278e-03 1.0959e-01 3.7687e-02 -3.5444e-02 6.7144e-02 7.0321e-03 1.0600e-02
+ 1.3176e-02 1.0170e-01 -5.3168e-02 3.9449e-03 3.2918e-02 2.4192e-01 3.2571e-02 7.1039e-02
+ 1.2190e-01 1.5018e-02 6.7506e-02 2.9951e-02 -6.1983e-03 3.0732e-02 -1.1203e-01 1.0103e-01
+ 4.7187e-02 6.2115e-02 9.6136e-02 -6.2386e-02 6.2103e-02 1.8497e-02 -9.1217e-03 1.1397e-01
+ 9.5389e-02 9.0061e-02 1.4362e-01 7.0501e-02 1.2238e-01 1.3018e-03 -1.1320e-02 1.2250e-01
+ -7.8986e-02 7.4019e-02 7.7044e-02 -1.2904e-03 1.4870e-01 7.5405e-02 -4.7422e-02 1.2427e-02
+ 4.4672e-02 2.1575e-01 9.4551e-03 8.0272e-02 6.9121e-02 2.0485e-02 -2.2358e-02 6.2833e-02
+ 6.2478e-02 1.1055e-01 -2.3959e-02 2.4591e-02 3.4462e-02 6.5208e-02 3.9261e-02 6.8676e-02
+ 2.4799e-01 7.5973e-02 4.4771e-02 1.4658e-01 6.3832e-02 -2.6708e-02 5.0137e-02 2.8446e-01
+ 5.3495e-02 1.7953e-02 9.4412e-02 1.2467e-01 2.3383e-01 3.1962e-02 1.6458e-01 1.4993e-01
+ 8.3835e-02 1.6684e-02 1.7345e-01 1.4406e-01 6.5687e-02 -6.0783e-02 5.1628e-03 1.5666e-01
+ 6.2087e-02 2.5781e-02 7.5089e-02 4.6230e-02 7.8549e-02 -6.3112e-02 1.9207e-02 3.6659e-02
+ 4.4348e-02 -1.5811e-02 9.3365e-02 1.0841e-01 1.4273e-01 4.4728e-02 5.1855e-02 -1.0925e-01
+ 5.1903e-02 6.2153e-02 1.5814e-01 4.0512e-01 1.0865e-03 -2.1972e-02 -1.1129e-02 4.9322e-02
+ 1.3009e-01 -2.1045e-02 -nan(ind) 1.4906e-01 4.6510e-02 -7.9324e-02 4.1883e-02 3.8862e-02
+ -7.8586e-02 -5.0455e-02 -3.1461e-03 1.1113e-01 -nan(ind) 1.3666e-01 2.7791e-02 9.4684e-02
+ 1.8270e-02 8.5624e-02 6.8865e-02 3.3196e-02 -nan(ind) -9.4408e-02 1.7151e-01 5.7906e-02
+ 1.2607e-02 -3.0639e-02 7.3381e-02 1.0621e-01 -nan(ind) 6.4087e-02 9.2567e-02 5.6522e-02
+ 5.2699e-02 2.2631e-02 6.0218e-02 2.7002e-02 2.3416e-01 2.3352e-02 -9.9134e-03 1.3700e-01
+ 9.2945e-02 1.1644e-01 1.2176e-01 1.0862e-02 6.0440e-02 3.6620e-02 -6.1135e-02 2.3507e-03
+ 1.2445e-01 9.2754e-02 6.7445e-02 1.0068e-01 5.7303e-02 7.4984e-02 1.4127e-03 3.8636e-02
+ 8.1906e-02 9.7670e-02 -1.0130e-02 3.6924e-02 -2.8410e-02 -1.3654e-02 -3.2973e-02 1.6548e-01
+ 8.8498e-02 1.5535e-02 1.2780e-01 5.6898e-02 3.3090e-02 1.3716e-01 8.9282e-02 4.2186e-02
+ 1.4214e-01 1.2489e-01 6.3316e-02 1.4622e-01 7.3818e-02 7.8169e-03 5.8508e-02 7.9461e-02
+ -1.5616e-02 1.9506e-02 1.4578e-01 4.8843e-02 1.6164e-02 5.8087e-02 1.8503e-01 4.1028e-02
+ 1.8705e-01 -8.3792e-03 1.7384e-02 -4.4522e-03 1.5874e-01 1.2235e-01 1.4077e-01 1.0277e-01
+ 1.6610e-01 -2.6936e-02 8.9604e-02 1.2008e-01 1.3069e-02 -6.2248e-02 3.6592e-02 1.8968e-01
+ 1.0544e-01 3.4172e-02 -9.5895e-02 1.2255e-01 1.0878e-01 1.6420e-02 7.9903e-03 8.1767e-02
+ 1.1201e-01 6.8324e-02 -1.4148e-02 4.2385e-02 1.4320e-01 -3.2574e-02 1.4548e-01 -4.3082e-02
+ 9.8377e-02 4.0308e-02 1.3658e-01 5.3119e-02 4.1522e-03 8.1262e-02 1.5818e-01 -5.5730e-02
+ 2.9350e-02 1.2758e-02 1.2400e-01 9.6575e-02 3.6016e-02 7.6681e-02 -9.1966e-02 4.2580e-02
+ 1.1073e-01 -4.7756e-02 7.5949e-03 4.2035e-02 3.4180e-02 8.6763e-02 -6.1553e-02 7.5196e-02
+ 9.2936e-02 6.3467e-02 4.6824e-02 1.2543e-01 1.3106e-01 1.2397e-01 -4.2257e-03 -7.2080e-02
+ 1.2310e-01 5.1098e-02 1.1286e-01 1.1119e-02 3.4504e-02 4.8931e-02 2.3012e-01 -8.4389e-03
+ 1.2762e-01 3.2073e-02 -2.0940e-02 1.0213e-01 2.7486e-01 9.5793e-02 -1.5424e-01 2.7604e-02
+ 3.8221e-02 1.3914e-01 -8.5273e-02 7.8000e-02 2.2825e-01 8.8872e-02 4.7898e-02 1.2116e-01
+ 6.3211e-02 2.7296e-02 7.4799e-02 1.4978e-01 9.3867e-02 1.0010e-01 -2.1719e-02 -3.1587e-02
+ 9.5385e-02 2.1236e-02 5.8541e-02 1.8410e-01 4.2629e-02 2.3894e-02 1.1380e-01 1.3294e-01
+ 1.6543e-02 4.8543e-02 1.8156e-01 7.9668e-02 1.7808e-01 3.0764e-02 1.0802e-01 8.2176e-02
+ 1.5394e-02 -5.8130e-02 -1.9132e-01 7.9401e-02 4.2219e-02 8.6999e-02 2.0156e-02 3.8168e-02
+ -6.3531e-02 5.6729e-02 4.4781e-02 9.8830e-02 1.0709e-01 1.4875e-01 1.1563e-01 -4.3592e-02
+ 2.0984e-02 1.1147e-01 1.0228e-01 6.8280e-02 7.1518e-02 9.2779e-02 2.0502e-01 1.0668e-01
+ 1.3087e-01 -1.2463e-01 1.8386e-02 6.7686e-02 9.6396e-05 7.0198e-02 7.7226e-03 4.0065e-02
+ 8.9823e-02 7.5239e-02 1.1223e-01 1.1894e-01 -8.2090e-02 -4.1261e-02 7.9232e-02 -nan(ind)
+ 6.7502e-02 -4.1589e-02 1.6184e-01 1.2814e-01 -5.4695e-02 9.3503e-02 1.0459e-01 1.4624e-01
+ 5.4399e-02 1.0819e-01 7.0792e-02 5.1573e-02 1.6192e-01 1.3647e-01 1.1359e-02 1.6775e-02
+ 1.5430e-01 7.9505e-02 5.2916e-02 3.2114e-03 1.0885e-01 1.4569e-01 5.4769e-02 1.6228e-02
+ 2.6628e-02 -3.0560e-03 -2.8511e-02 1.3763e-01 1.2663e-01 2.2581e-01 1.1616e-02 7.8135e-02
+ -8.0934e-02 1.3169e-01 1.5430e-02 -6.3064e-03 1.8658e-02 4.8781e-02 5.0783e-02 9.4972e-02
+ 1.3052e-02 2.0094e-01 2.9735e-02 1.2787e-01 4.7882e-02 2.9540e-02 -3.3532e-02 1.0814e-01
+ 3.2192e-02 -2.4673e-02 1.0925e-01 7.3028e-03 -5.9634e-03 9.8483e-03 8.3582e-02 5.1576e-02
+ -1.6104e-02 4.1480e-02 1.3334e-01 7.9514e-02 9.6194e-02 8.3387e-02 -4.3044e-02 3.4794e-02
+ 9.4856e-02 3.0744e-01 6.2849e-02 -1.6698e-02 7.2555e-02 -5.9229e-02 8.8316e-02 7.1198e-02
+ 3.2389e-02 9.7426e-02 1.0587e-01 9.1640e-02 5.0117e-02 2.4289e-02 -2.2037e-02 8.8434e-02
+ -4.6201e-02 3.2050e-02 5.1413e-02 -3.6451e-02 -5.0261e-02 6.0257e-02 -1.4790e-02 4.8662e-02
+ -2.4581e-02 -2.9035e-02 8.6198e-03 6.2497e-02 -nan(ind) -7.2321e-02 1.1506e-01 4.0681e-02
+ 9.8104e-02 4.8971e-02 -9.8186e-03 1.0774e-01 1.2249e-01 -5.1276e-02 6.5442e-02 6.7232e-02
+ 6.9761e-02 6.1169e-02 1.2327e-01 9.8120e-02 1.1108e-03 1.0142e-01 -9.5576e-02 8.2831e-02
+ 5.3176e-02 1.8044e-01 4.3767e-02 6.8339e-02 1.1479e-01 1.4963e-01 3.4161e-02 7.1485e-02
+ 2.4681e-02 7.8242e-02 1.4213e-01 -5.4796e-02 7.9232e-02 6.5083e-02 -6.5678e-03 8.2470e-02
+ 4.5237e-02 2.8271e-01 -1.3461e-01 1.7849e-02 3.7401e-02 -3.0104e-02 4.9632e-02 7.3673e-02
+ 4.1776e-02 -7.5143e-04 8.0054e-02 3.6493e-02 8.2104e-02 2.2617e-02 1.3436e-01 9.1280e-02
+ 5.1464e-02 -2.4953e-02 9.1502e-03 3.1679e-02 -3.6502e-02 -2.3533e-02 1.2525e-01 3.1916e-03
+ 1.0274e-03 2.4031e-02 -1.7094e-01 1.1327e-01 5.1991e-02 1.7269e-01 1.0550e-01 9.6363e-02
+ 6.4150e-02 -7.0326e-03 1.6211e-01 9.6122e-02 -nan(ind) 1.5592e-01 -nan(ind) 3.0049e-02
+ -1.2331e-02 -1.3140e-01 -1.9852e-02 -nan(ind) 3.4553e-02 4.1787e-02 2.6969e-02 1.3588e-05
+ 4.2260e-02 2.8907e-02 3.5501e-02 2.5876e-02 4.6814e-02 1.9687e-02 4.2408e-02 6.6548e-02
+ -nan(ind) 3.1361e-02 8.0414e-02 5.3675e-03 6.7638e-02 1.2591e-02 4.5117e-02 -2.2005e-01
+ -7.3797e-02 7.8118e-02 2.0223e-01 7.2419e-02 7.5877e-02 7.3093e-03 6.4639e-02 7.9956e-02
+ 5.9870e-02 1.9601e-02 3.9268e-02 4.9619e-02 1.1509e-01 1.6681e-01 9.1445e-02 1.9322e-02
+ 1.1974e-01 -3.0083e-02 8.0846e-02 -nan(ind) -5.5228e-03 -3.7660e-02 9.0598e-02 1.4389e-01
+ -3.4956e-02 2.8098e-02 1.2335e-01 -8.4186e-03 3.2285e-02 3.1644e-02 2.4748e-02 3.3929e-02
+ -4.9605e-02 1.5799e-01 -3.9854e-02 -3.7911e-02 9.8161e-02 -nan(ind) -1.9825e-03 6.0941e-02
+ 2.2567e-03 9.7226e-02 7.5456e-02 6.5242e-03 9.9820e-02 -2.3237e-03 8.7159e-02 2.3794e-02
+ 8.5952e-02 7.6939e-02 1.1522e-02 1.3503e-01 6.1862e-02 4.9461e-02 -nan(ind) 4.0581e-02
+ 1.2495e-01 1.0414e-01 5.7198e-02 -2.3394e-01 1.0412e-01 -1.7314e-02 1.4818e-01 6.8395e-02
+ -1.8429e-02 4.1829e-02 8.9339e-02 8.4135e-02 4.8073e-02 2.1149e-02 1.3665e-01 8.0340e-02
+ 1.3226e-01 7.1253e-02 3.8953e-02 -nan(ind) 1.2131e-01 1.1055e-02 1.3593e-01 1.7931e-01
+ -nan(ind) 2.0960e-01 -5.8680e-02 6.1039e-02 1.5676e-02 1.5184e-02 -nan(ind) 8.2102e-02
+ 1.1178e-01 4.5674e-02 4.6438e-02 -8.8718e-03 -3.6861e-02 3.3178e-02 3.4966e-02 9.3028e-02
+ -2.8984e-02 3.0956e-02 -8.6110e-02 2.2780e-01 7.1916e-02 6.4377e-03 3.2875e-02 1.0795e-01
+ 3.5678e-02 9.3211e-02 -5.4155e-02 5.7648e-02 7.4172e-03 1.0766e-01 4.4185e-02 2.9730e-02
+ 2.0871e-01 1.1637e-01 3.8194e-02 2.1252e-01 3.6849e-02 9.6596e-02 4.1639e-02 4.8356e-03
+ 6.1660e-02 1.8188e-02 1.4374e-02 1.0947e-01 -7.0043e-02 8.9856e-02 4.8319e-02 1.0118e-01
+ 1.2347e-01 -nan(ind) 4.9652e-02 8.2742e-03 5.6509e-02 1.2873e-01 -5.3559e-02 -1.2979e-01
+ 1.5791e-02 -nan(ind) 1.7589e-01 1.4210e-02 -nan(ind) 1.0597e-01 4.2461e-02 2.3938e-01
+ 3.6610e-02 4.5977e-02 7.3587e-02 8.2763e-02 1.3230e-01 7.6321e-02 -1.3883e-02 2.7884e-02
+ 1.5461e-01 -1.7976e-02 2.0984e-02 9.8434e-02 4.9681e-02 1.7218e-02 7.4877e-02 1.2954e-01
+ 8.4415e-02 7.1724e-02 1.4732e-02 6.7964e-02 7.0688e-02 4.2453e-02 3.0371e-02 2.0410e-01
+ -2.1446e-02 6.1326e-02 7.2291e-02 9.9091e-02 5.9948e-02 2.1479e-02 3.7885e-02 9.1519e-02
+ -nan(ind) 5.0343e-02 3.9369e-02 5.8188e-02 1.5969e-01 1.3989e-01 1.0782e-01 4.7404e-02
+ 3.5106e-02 2.9464e-02 4.3836e-02 1.9158e-02 -4.0893e-02 1.2051e-01 -9.1499e-03 3.4003e-02
+ -1.2777e-02 1.1045e-01 -6.2330e-02 6.9533e-02 6.6195e-02 -2.3150e-02 -nan(ind) 6.2084e-02
+ -nan(ind) 4.6873e-02 -nan(ind) 1.5676e-01 1.2209e-02 7.7795e-02 -2.6900e-02 2.4766e-01
+ 4.0519e-02 -1.0170e-02 4.5347e-02 1.1657e-01 1.0365e-01 2.1844e-01 3.9607e-02 1.2594e-01
+ 6.5253e-02 6.0093e-02 8.8258e-02 2.2191e-01 8.2548e-02 1.8288e-01 2.4797e-02 2.7732e-01
+ -5.1325e-03 1.3954e-01 7.8145e-02 6.1579e-02 5.6561e-02 3.5656e-02 2.0662e-02 1.2089e-01
+ -1.6405e-02 9.1550e-02 -1.0038e-01 1.0000e-01 6.3997e-02 -nan(ind) -4.3694e-02 7.4980e-02
+ 2.0212e-02 4.6943e-02 1.3276e-01 1.8625e-01 1.1582e-01 6.4718e-02 6.0853e-02 9.1402e-02
+ 6.9550e-02 9.9337e-02 -2.3392e-02 3.0303e-02 -7.3152e-03 3.7627e-02 -2.7885e-02 6.0364e-02
+ -1.5310e-02 3.3890e-02 1.3600e-01 1.4015e-01 -4.3407e-02 1.3408e-01 9.8662e-03 -nan(ind)
+ -7.9178e-03 1.0671e-01 4.8947e-02 -3.5576e-03 -4.2908e-02 4.0992e-02 2.3334e-02 2.1889e-02
+ 8.2321e-02 -nan(ind) 1.1776e-01 -nan(ind) 5.8595e-02 -nan(ind) -1.3264e-01 4.4745e-02
+ 4.9590e-02 4.8716e-02 7.7106e-03 9.3347e-02 7.3653e-02 7.5539e-02 1.6940e-02 -6.8377e-02
+ -9.6712e-03 2.4013e-02 -8.5537e-02 3.0957e-02 6.3556e-02 -7.7238e-02 3.9475e-01 8.1782e-02
+ -nan(ind) -nan(ind) 9.4692e-02 -nan(ind) -4.7410e-03 1.3076e-01 7.3002e-02 1.3469e-01
+ 7.3382e-02 2.2479e-02 1.7711e-01 7.1577e-02 3.1740e-02 2.5602e-02 3.5255e-02 4.7273e-02
+ 1.2843e-01 5.9553e-02 5.3595e-02 9.8130e-02 1.6809e-01 1.6725e-03 2.4615e-02 5.7341e-02
+ 6.6575e-02 1.2333e-01 4.7431e-02 1.6868e-01 1.5305e-01 2.4249e-02 2.4818e-02 2.2792e-02
+ 9.2485e-02 8.2751e-02 5.7175e-03 5.5108e-02 4.0404e-03 2.3939e-01 -9.6323e-04 4.6614e-02
+ 1.5647e-02 -nan(ind) -9.8504e-02 4.8931e-02 1.2093e-01 9.8991e-02 7.4778e-02 9.3682e-02
+ 5.4812e-02 -1.3769e-02 -1.2918e-02 -4.5391e-03 1.7802e-01 3.0566e-02 1.7488e-01 1.6788e-01
+ -1.0409e-02 6.3776e-02 -1.6751e-02 5.8945e-02 -8.5103e-04 8.0699e-02 1.3444e-02 1.7554e-01
+ 9.9419e-02 6.4745e-02 1.2156e-02 1.4776e-01 1.7348e-02 9.6728e-03 2.1387e-01 9.3515e-02
+ 4.3678e-02 4.1780e-02 4.6456e-02 4.9757e-02 1.3234e-01 -5.1706e-03 9.9484e-02 3.6988e-02
+ 1.8469e-01 1.7302e-02 -nan(ind) -3.6494e-02 -1.1508e-02 1.2049e-02 3.7212e-01 9.3631e-02
+ 1.1318e-01 8.1525e-02 2.1697e-01 1.1120e-01 7.3361e-02 8.8372e-02 -1.7403e-01 5.5225e-02
+ -5.1269e-02 1.2106e-01 1.1643e-02 1.3544e-01 -nan(ind) 2.8518e-02 -1.9350e-02 -9.9228e-02
+ 3.5273e-02 6.8334e-02 6.5205e-02 9.6277e-02 3.8174e-03 -4.1205e-02 7.4451e-02 2.7892e-02
+ 2.2132e-02 -4.9702e-02 -1.2013e-02 9.3726e-02 -6.2258e-02 5.4277e-02 -4.0890e-02 8.7679e-02
+ -2.6388e-02 -2.6224e-02 9.2071e-02 5.6006e-02 6.4424e-02 2.5322e-02 4.4278e-02 2.6871e-02
+ 8.4721e-02 3.9639e-02 -3.5905e-02 3.3211e-02 -5.3408e-03 -1.1965e-02 4.6501e-03 1.5553e-01
+ 6.1147e-02 -1.8911e-02 4.1396e-02 1.0446e-02 1.3016e-01 -nan(ind) -nan(ind) 1.2283e-01
+ 3.3566e-02 1.2195e-01 9.4906e-02 3.4704e-01 1.9534e-02 1.4281e-01 1.6258e-01 1.5312e-01
+ 6.9308e-02 3.2271e-03 -nan(ind) 2.0576e-02 4.4659e-02 -1.9494e-04 5.5321e-03 8.4300e-02
+ 1.6590e-01 1.2163e-01 8.0070e-02 -3.3675e-02 1.9425e-02 7.1541e-02 7.6634e-02 6.8180e-02
+ 6.3173e-02 1.1841e-02 1.2642e-01 9.4394e-02 2.8544e-02 7.0579e-02 4.4743e-02 -2.7222e-03
+ 3.7716e-02 1.0708e-01 -1.0381e-03 2.1757e-02 6.2963e-02 1.8342e-01 6.8501e-02 -nan(ind)
+ 8.7860e-03 2.1036e-02 9.9669e-02 -1.2587e-02 5.6089e-02 1.2104e-01 5.5587e-02 -9.4420e-03
+ 8.8481e-02 1.3638e-01 -2.8972e-02 9.6874e-02 4.4375e-02 8.0779e-02 2.8290e-01 -1.6575e-02
+ 6.2627e-02 -nan(ind) 6.6997e-02 -4.8766e-02 1.3423e-01 1.1991e-01 -nan(ind) 1.1642e-02
+ -2.9375e-02 3.2442e-02 1.5200e-02 2.2978e-02 -2.0448e-02 3.7893e-02 1.6109e-01 1.7714e-01
+ 8.1473e-02 1.2326e-01 -nan(ind) -4.4057e-02 1.1937e-01 -nan(ind) 6.9468e-02 1.0747e-01
+ 1.6417e-01 -3.3505e-02 3.6763e-03 2.0294e-01 1.4152e-02 9.9007e-02 3.4216e-02 7.0151e-02
+ 6.5169e-03 1.9565e-01 3.9816e-02 1.0592e-01 -9.5288e-03 5.6469e-02 4.5208e-02 1.0921e-01
+ 5.9920e-02 -nan(ind) -nan(ind) 1.0590e-01 -nan(ind) 4.9638e-02 3.9866e-02 7.7444e-02
+ 9.8909e-02 5.1560e-02 2.3457e-02 2.7477e-02 -1.0486e-03 5.6308e-02 1.4537e-01 2.2708e-02
+ 3.2326e-02 4.3588e-02 7.2938e-02 1.4485e-02 3.5979e-02 6.8851e-02 -nan(ind) -3.4618e-02
+ 6.8183e-02 1.0156e-01 2.3142e-02 1.5939e-01 9.7138e-02 -nan(ind) 4.3040e-02 -4.2799e-02
+ 1.3671e-01 7.7111e-03 7.7625e-02 1.4907e-01 3.6244e-02 -nan(ind) 2.1454e-02 1.6388e-01
+ 6.5501e-02 4.8333e-02 2.9867e-02 1.0175e-01 -nan(ind) 3.8283e-01 1.3709e-02 1.9284e-02
+ 6.3889e-02 -4.8763e-02 1.6407e-01 1.1360e-01 -nan(ind) 1.0288e-01 1.1893e-01 1.3209e-01
+ 6.8415e-02 -nan(ind) -7.7936e-02 1.3295e-01 -nan(ind) 6.6459e-02 5.4594e-02 3.4293e-03
+ 3.6741e-02 1.2103e-01 7.7891e-02 9.3933e-02 7.0150e-02 1.5258e-01 1.3793e-01 3.3281e-02
+ 7.9362e-03 1.6062e-01 7.8175e-02 7.2817e-03 -2.2976e-02 2.0369e-02 5.0583e-03 6.3072e-02
+ -nan(ind) 4.9916e-03 4.1750e-02 4.2713e-02 -1.3137e-02 6.5508e-02 6.9571e-03 -1.8252e-02
+ 5.1685e-03 5.3547e-02 2.6907e-02 5.5628e-02 -4.0792e-02 2.0523e-02 1.0207e-01 1.1174e-02
+ 1.1893e-01 7.8602e-02 1.2020e-01 -5.0961e-02 4.9752e-02 -nan(ind) -nan(ind) 8.3440e-02
+ 5.0476e-02 5.9004e-02 3.5481e-02 1.2754e-01 1.3045e-01 8.1125e-02 2.3200e-02 1.9705e-01
+ 7.4131e-02 -1.0770e-02 -1.1157e-02 -1.4465e-03 8.9602e-02 5.4644e-02 1.1971e-02 1.1499e-01
+ 2.1655e-01 8.6576e-02 6.4511e-02 -7.2291e-03 2.6868e-03 1.9165e-02 2.1978e-02 -1.9304e-02
+ 1.1962e-01 1.3502e-01 9.9998e-02 3.8192e-02 1.6281e-01 2.6295e-02 1.7493e-02 6.1137e-02
+ 6.7578e-02 -1.4856e-02 -nan(ind) -2.3857e-02 9.0628e-02 7.6257e-02 -8.2541e-02 -nan(ind)
+ 1.3036e-01 -nan(ind) 2.9935e-02 9.5458e-02 7.4482e-02 4.7786e-02 1.0265e-01 3.9328e-02
+ 4.8380e-02 7.8181e-02 1.5415e-01 1.2278e-02 1.9599e-01 -nan(ind) 4.8926e-02 7.3256e-02
+ 9.2250e-02 4.6088e-02 1.1671e-01 6.7272e-02 4.2169e-02 1.1849e-01 4.4661e-02 3.0724e-02
+ 3.8879e-02 4.9675e-02 -5.9709e-02 7.5419e-02 4.4392e-02 3.8031e-02 1.0204e-01 1.0539e-01
+ 1.5985e-01 4.0129e-02 2.2168e-01 5.6231e-02 1.4158e-01 2.9837e-01 8.2017e-02 5.0250e-02
+ 1.1542e-02 -4.5826e-02 5.6463e-02 1.2943e-01 -1.1001e-01 -5.0175e-02 -5.0577e-02 5.2264e-02
+ 4.2378e-02 3.9143e-02 -5.0769e-02 6.4337e-02 -1.0853e-01 6.6951e-02 1.2338e-01 3.8563e-02
+ -1.1950e-02 -nan(ind) -nan(ind) 9.8418e-02 5.2149e-02 -1.9164e-02 -5.5757e-02 9.7772e-02
+ 1.5598e-01 8.4938e-02 3.5190e-01 -2.8744e-02 4.0759e-02 -3.0801e-02 1.2310e-01 -nan(ind)
+ 8.8373e-02 5.4220e-02 5.6945e-02 5.1177e-02 6.3787e-03 1.2133e-01 -2.0249e-02 1.9159e-01
+ 2.3405e-02 -1.5847e-01 7.6269e-02 -nan(ind) 9.1509e-02 4.8097e-03 3.3385e-02 7.6432e-02
+ 3.3768e-02 4.4682e-02 1.4915e-02 4.2666e-02 7.1284e-02 8.9599e-02 9.5923e-02 1.5181e-01
+ -1.8742e-03 6.4361e-02 3.8696e-02 -1.7614e-01 1.4029e-01 1.6957e-02 -nan(ind) 9.0406e-02
+ 8.5227e-02 1.4473e-01 1.8340e-02 1.0820e-01 7.5934e-02 -5.0777e-02 1.5003e-01 5.5604e-02
+ 9.5719e-03 2.8148e-02 1.7408e-01 -4.7225e-02 -3.8462e-02 6.4680e-02 8.5279e-02 2.4860e-02
+ -6.2029e-02 -4.7107e-02 6.8080e-02 4.7365e-02 6.4027e-02 -1.3013e-02 4.4734e-02 -3.2279e-02
+ -5.5758e-03 -3.9778e-02 3.9294e-02 1.8354e-01 5.8013e-02 9.7352e-02 6.1101e-02 8.7862e-02
+ 9.4875e-02 1.0906e-01 1.4441e-01 6.9118e-02 1.4495e-01 8.3138e-02 2.9452e-02 -1.4974e-02
+ -3.3784e-02 -1.1933e-02 8.7179e-02 3.2158e-02 7.5095e-02 1.2661e-01 2.0006e-01 -6.4571e-02
+ 1.6331e-02 1.3293e-01 1.7634e-01 -1.3098e-02 9.1427e-02 -nan(ind) -nan(ind) 5.6122e-02
+ -nan(ind) 1.2007e-01 3.1208e-02 8.9365e-02 5.8192e-02 7.1043e-02 3.0673e-02 1.1139e-01
+ 8.0571e-02 -1.2260e-02 8.2618e-02 -6.4645e-02 1.3124e-01 4.4474e-02 9.6852e-02 2.9435e-02
+ 1.1597e-01 3.4673e-02 4.0543e-02 1.3852e-01 8.4779e-03 8.1160e-02 1.5917e-01 4.1320e-02
+ -3.8620e-02 1.1478e-01 -6.6997e-02 2.2109e-01 1.1553e-01 2.6515e-01 1.0555e-01 9.8530e-02
+ 2.6021e-02 -1.0404e-02 5.3697e-02 -nan(ind) 8.5535e-02 3.3751e-02 7.9909e-03 1.1167e-02
+ 5.0354e-03 1.3813e-03 9.6173e-02 -5.3928e-02 3.9364e-02 1.1837e-01 1.9406e-02 9.7496e-02
+ 1.0823e-01 -2.1819e-02 -nan(ind) -nan(ind) 7.4832e-04 -4.0155e-03 6.7551e-02 2.4251e-02
+ 7.6856e-02 1.1813e-01 -7.3201e-02 9.1040e-02 3.8790e-02 1.6409e-02 -4.1787e-02 -3.3538e-03
+ 3.4699e-02 1.0294e-02 6.0703e-03 5.4019e-02 5.0514e-02 6.8124e-02 5.7536e-02 -5.8422e-02
+ 8.7024e-02 4.1243e-02 1.0163e-02 4.1005e-02 6.6695e-02 1.1747e-01 2.5232e-02 1.0497e-01
+ 6.6354e-02 2.3680e-02 8.0678e-02 7.9666e-02 6.8902e-02 1.3681e-01 3.6026e-02 -2.8539e-02
+ 8.8694e-02 4.3890e-02 -1.0489e-01 5.9417e-02 2.0544e-01 6.1043e-02 2.1915e-01 3.2269e-03
+ 1.0891e-01 -nan(ind) -nan(ind) 2.1460e-02 1.4275e-02 2.6610e-02 -1.1083e-02 8.2653e-02
+ 7.5242e-02 6.7649e-02 7.9329e-02 1.2396e-01 1.3017e-02 4.3685e-02 2.2683e-02 -3.5319e-03
+ 9.1471e-02 1.0507e-02 9.2862e-02 1.3784e-02 3.3112e-03 -6.6300e-03 5.4746e-02 -2.7257e-02
+ -nan(ind) 1.6531e-01 -3.1736e-02 7.4278e-02 2.0672e-01 4.3481e-02 8.0299e-02 1.0504e-01
+ 1.3258e-01 1.2005e-01 4.7470e-03 9.8985e-02 -7.0077e-03 1.0891e-01 8.0824e-03 5.4224e-02
+ 1.5396e-01 -3.0176e-02 2.3088e-02 9.5047e-02 6.9151e-02 8.0370e-02 6.1687e-02 1.2999e-02
+ -nan(ind) -nan(ind) 3.0768e-02 8.3815e-02 3.3993e-02 -4.4472e-02 -nan(ind) -9.6464e-03
+ 4.4629e-02 1.3044e-02 5.8156e-02 1.2740e-02 2.8707e-03 5.9413e-02 8.6011e-02 1.0314e-01
+ -1.9763e-02 4.6400e-02 4.1109e-02 4.7632e-02 6.7096e-02 5.9867e-02 2.9610e-02 1.0589e-02
+ 8.7641e-02 1.0563e-01 4.1742e-02 1.0587e-01 1.1451e-01 9.5229e-02 -3.4989e-03 8.9804e-02
+ 5.8957e-02 1.0690e-01 8.6345e-03 7.3102e-02 4.2795e-02 1.6221e-01 -3.8358e-02 -nan(ind)
+ 6.6190e-02 1.0901e-01 2.0955e-01 -nan(ind) 4.9641e-02 1.0889e-01 -8.8153e-02 9.7346e-02
+ 3.0573e-02 -8.0529e-04 1.6126e-01 6.5760e-04 4.1761e-02 -nan(ind) -nan(ind) 9.1459e-02
+ 5.2044e-02 -7.1724e-02 7.1274e-02 2.0903e-01 8.3337e-02 1.2633e-01 1.6084e-02 1.3212e-01
+ 1.7550e-01 1.3001e-02 6.8260e-02 2.3419e-02 -nan(ind) 6.1953e-02 2.3070e-02 -nan(ind)
+ 6.1263e-02 1.4474e-01 2.1581e-01 4.7195e-02 -4.1252e-02 7.1613e-02 6.9925e-02 5.6046e-02
+ 3.8829e-03 -1.0454e-01 7.4754e-02 5.3704e-02 -1.1016e-02 8.0245e-02 -4.5817e-03 1.7695e-02
+ 9.6031e-02 -4.8031e-02 7.0232e-02 4.4650e-02 6.4161e-02 5.9859e-02 6.5413e-02 1.0781e-01
+ 9.4513e-02 9.5371e-02 1.0288e-01 1.4367e-01 2.9483e-02 -nan(ind) 8.0608e-03 6.8256e-02
+ -2.4106e-02 -nan(ind) 1.8768e-02 -nan(ind) 1.2267e-01 1.8266e-02 -nan(ind) 5.6507e-02
+ 1.8473e-01 1.6594e-01 -1.9004e-02 3.5128e-02 9.9190e-02 -2.2452e-02 4.1064e-02 -3.6905e-02
+ 3.4776e-02 1.1974e-01 -nan(ind) 4.9513e-02 -1.7584e-02 -3.5416e-02 -3.4179e-02 -4.1807e-02
+ -4.9515e-02 1.4601e-02 -4.0830e-02 5.5252e-02 -8.3919e-02 1.4192e-01 -5.4218e-02 5.6527e-02
+ -1.1664e-02 2.0321e-01 -1.7494e-03 7.0178e-02 1.6277e-01 6.6287e-02 1.2543e-01 -2.2134e-03
+ 1.5633e-01 5.9556e-03 2.2377e-02 8.8499e-02 5.0014e-02 -1.6647e-02 -3.1054e-02 2.6960e-02
+ -5.0977e-03 -nan(ind) -nan(ind) 1.9148e-02 -nan(ind) 1.3663e-02 6.2882e-02 7.0805e-02
+ 7.8758e-02 1.6891e-03 2.5207e-02 -4.2755e-02 8.4858e-02 1.5597e-02 1.0818e-01 -3.7828e-02
+ 2.4133e-03 1.0504e-01 8.6804e-02 1.1468e-01 -1.5939e-02 1.8094e-01 -1.7767e-02 9.9433e-02
+ 8.6829e-02 -nan(ind) 4.4721e-02 -nan(ind) 5.1227e-02 -4.6760e-02 1.4499e-01 1.2384e-01
+ -2.2987e-02 1.4581e-01 2.2481e-01 -1.3143e-02 -3.5326e-02 1.0679e-01 2.4236e-02 1.0796e-01
+ 5.6621e-02 8.8015e-02 -nan(ind) -5.0532e-02 3.9107e-02 -nan(ind) 1.3895e-02 -nan(ind)
+ 2.7299e-02 7.5558e-02 -nan(ind) 1.9479e-01 -3.7378e-02 3.5710e-02 -2.4107e-02 2.2044e-01
+ 6.3182e-02 1.0626e-01 8.6463e-03 9.1036e-02 4.7572e-02 1.4643e-02 4.4956e-02 -1.4686e-02
+ 1.8126e-02 -1.8137e-02 -2.5943e-02 -2.9435e-03 8.4748e-02 1.3209e-02 1.4704e-01 9.4069e-02
+ 1.0578e-01 4.2696e-02 1.1889e-01 7.7059e-02 1.3412e-01 -nan(ind) 4.6996e-02 4.1360e-03
+ 1.8029e-01 1.7373e-02 8.4826e-02 5.8296e-02 2.2257e-02 2.5660e-02 -nan(ind) 3.5729e-02
+ -7.9108e-02 3.7110e-02 5.0157e-02 5.1339e-02 -7.5463e-04 5.2418e-02 1.8437e-02 -1.8088e-02
+ -nan(ind) 1.0822e-01 3.5339e-02 1.2760e-01 7.5667e-02 -nan(ind) -nan(ind) 6.2515e-02
+ 5.1742e-02 -5.2727e-02 1.0779e-02 -nan(ind) 2.1569e-02 -3.4901e-03 7.6190e-02 4.6324e-02
+ 1.1157e-01 4.8421e-02 -5.8484e-02 1.8762e-02 -1.7417e-02 3.8777e-02 1.2657e-02 5.5522e-02
+ 1.3865e-01 3.1013e-02 -9.7536e-03 -nan(ind) 7.0308e-02 4.4385e-02 -nan(ind) 2.9248e-03
+ -9.9601e-03 -4.0819e-02 -8.7891e-03 9.0750e-02 -5.2840e-02 1.9477e-02 1.4341e-01 2.0785e-01
+ 1.2279e-01 6.7048e-02 1.5439e-01 1.1923e-01 1.2739e-01 3.0176e-02 4.1604e-02 1.2920e-01
+ 1.1184e-01 1.5389e-02 -1.0914e-02 9.7628e-02 -nan(ind) 8.4495e-02 1.1618e-01 -nan(ind)
+ -nan(ind) 1.0224e-01 4.3140e-02 -nan(ind) 7.3101e-02 7.4344e-02 1.1077e-01 6.9621e-02
+ 9.0012e-02 9.4998e-02 5.8329e-02 5.9226e-02 5.7398e-02 4.4497e-02 4.8559e-02 1.0742e-01
+ 5.1536e-02 1.0789e-01 6.1483e-02 4.9025e-02 7.4978e-02 8.2362e-02 6.1760e-02 4.5350e-02
+ -nan(ind) 5.6460e-02 -nan(ind) 5.3405e-02 7.2193e-02 7.1900e-02 4.4468e-02 7.5482e-02
+ 4.6469e-02 7.7278e-02 8.3270e-02 5.0208e-02 6.8478e-02 5.0603e-02 6.4920e-02 4.6182e-02
+ 7.1016e-02 5.7769e-02 6.2572e-02 6.8077e-02 5.7864e-02 6.5023e-02 1.0835e-01 5.2677e-02
+ 4.4531e-02 -nan(ind) -nan(ind) 3.5875e-02 6.2020e-02 9.3867e-02 7.3541e-02 3.9081e-02
+ 9.3191e-02 4.8600e-02 5.6694e-02 6.2165e-02 5.4417e-02 6.2346e-02 5.0855e-02 5.9160e-02
+ 4.9424e-02 8.7581e-02 4.0077e-02 5.6390e-02 6.3350e-02 5.8527e-02 7.9854e-02 4.4454e-02
+ 7.0876e-02 -nan(ind) 4.5060e-02 1.1730e-01 5.3364e-02 6.9786e-02 8.3421e-02 8.8683e-02
+ 4.5944e-02 5.3660e-02 7.0146e-02 5.8438e-02 1.0689e-01 6.0105e-02 4.6094e-02 1.1044e-01
+ 5.4291e-02 6.3772e-02 7.5050e-02 1.0382e-01 7.1206e-02 -nan(ind) 7.1044e-02 1.0314e-01
+ 1.1896e-01 4.2248e-02 7.7740e-02 1.0668e-01 3.7597e-02 -nan(ind) -nan(ind) 3.7633e-02
+ 8.0256e-02 4.9068e-02 7.4375e-02 5.0582e-02 6.7915e-02 6.1207e-02 5.2051e-02 5.7413e-02
+ 6.0989e-02 1.0777e-01 1.1418e-01 6.0276e-02 5.7888e-02 9.1020e-02 7.0831e-02 6.9271e-02
+ -nan(ind) 4.7631e-02 1.1690e-01 1.0242e-01 7.7083e-02 7.9106e-02 -nan(ind) 6.3669e-02
+ 7.0624e-02 8.3717e-02 6.3153e-02 4.5361e-02 1.3959e-01 5.6478e-02 4.3182e-02 -nan(ind)
+ 8.9005e-02 5.0136e-02 8.2832e-02 1.4734e-01 6.5620e-02 5.7354e-02 8.4118e-02 6.2516e-02
+ 7.5849e-02 1.1854e-01 8.2882e-02 1.0604e-01 3.2266e-02 -nan(ind) -nan(ind) 3.9426e-02
+ 7.5325e-02 7.4569e-02 5.7121e-02 7.4860e-02 6.0055e-02 -nan(ind) 6.7179e-02 6.3157e-02
+ 7.1347e-02 7.5853e-02 6.8034e-02 7.1812e-02 -nan(ind) 5.5819e-02 6.4693e-02 7.0912e-02
+ 4.8941e-02 4.9454e-02 6.5493e-02 1.9399e-01 5.0842e-02 6.5384e-02 1.6044e-01 6.5066e-02
+ 1.1110e-01 1.1056e-01 4.6857e-02 -nan(ind) 9.7057e-02 9.1807e-02 7.6900e-02 6.8214e-02
+ 5.5830e-02 9.4383e-02 4.7650e-02 4.3205e-02 6.0479e-02 4.5916e-02 1.0269e-01 3.7852e-02
+ 4.7294e-02 5.2369e-02 7.8180e-02 5.2326e-02 4.2028e-02 -nan(ind) -nan(ind) 3.9923e-02
+ 6.8047e-02 4.5197e-02 -nan(ind) 6.9430e-02 5.9401e-02 6.4899e-02 8.3288e-02 7.9406e-02
+ 5.9794e-02 5.8790e-02 7.0297e-02 5.2473e-02 5.9452e-02 1.2714e-01 4.1450e-02 5.0676e-02
+ 7.8728e-02 4.1547e-02 -nan(ind) 5.5505e-02 4.7312e-02 1.1205e-01 8.1355e-02 5.8185e-02
+ 4.8175e-02 9.1256e-02 4.2177e-02 7.8126e-02 4.0880e-02 9.6721e-02 5.3891e-02 -nan(ind)
+ 5.7409e-02 6.1576e-02 1.5602e-01 5.6130e-02 6.3610e-02 1.0728e-01 5.5670e-02 6.3840e-02
+ 6.9821e-02 7.4669e-02 5.8915e-02 4.6327e-02 1.5390e-01 6.8381e-02 2.0125e-01 5.5822e-02
+ 4.9104e-02 -nan(ind) -nan(ind) 4.7401e-02 7.2276e-02 1.0391e-01 5.7522e-02 6.8386e-02
+ 5.6881e-02 6.3018e-02 3.8422e-02 5.6980e-02 4.9656e-02 7.0276e-02 1.3580e-01 5.6755e-02
+ 5.7900e-02 1.5591e-01 4.8535e-02 7.2708e-02 5.2649e-02 1.0822e-01 5.9096e-02 4.8394e-02
+ 9.0055e-02 4.7241e-02 7.7079e-02 4.7967e-02 5.4541e-02 7.4396e-02 9.1891e-02 4.5741e-02
+ 4.7994e-02 5.7598e-02 5.9129e-02 1.3509e-01 5.1809e-02 5.1982e-02 9.1032e-02 6.5787e-02
+ 9.4749e-02 5.2966e-02 5.6583e-02 6.0841e-02 8.7835e-02 5.2945e-02 5.0876e-02 5.7520e-02
+ 9.8651e-02 1.2368e-01 4.4419e-02 1.0729e-01 -nan(ind) 5.8218e-02 4.0741e-02 1.0669e-01
+ 6.0146e-02 5.0657e-02 6.6868e-02 5.9866e-02 4.7769e-02 8.8292e-02 6.8945e-02 5.7486e-02
+ 7.9902e-02 9.3264e-02 -nan(ind) 7.3576e-02 9.9349e-02 4.6019e-02 8.1803e-02 4.2187e-02
+ 6.8073e-02 9.7910e-02 4.8192e-02 7.4990e-02 4.8898e-02 5.6757e-02 -nan(ind) 5.1999e-02
+ 7.4189e-02 5.2774e-02 6.0076e-02 6.5107e-02 5.6683e-02 5.3926e-02 7.0322e-02 9.7182e-02
+ 5.9591e-02 5.9785e-02 5.1534e-02 1.0175e-01 6.5043e-02 4.8906e-02 7.1000e-02 4.5083e-02
+ 6.1383e-02 7.5278e-02 9.3047e-02 7.7979e-02 2.9805e-02 -nan(ind) -nan(ind) 3.7685e-02
+ 8.0642e-02 9.2452e-02 5.3845e-02 5.6263e-02 5.1142e-02 9.8358e-02 5.1518e-02 6.7318e-02
+ 6.5703e-02 6.1581e-02 6.3394e-02 6.8765e-02 7.0633e-02 5.4750e-02 7.7718e-02 5.1099e-02
+ 1.2474e-01 5.8659e-02 4.9772e-02 6.4031e-02 4.9152e-02 -nan(ind) 5.1387e-02 7.3194e-02
+ 7.8836e-02 5.8607e-02 9.2570e-02 5.3551e-02 5.1805e-02 7.8805e-02 9.2998e-02 8.7223e-02
+ 5.9083e-02 6.7280e-02 1.1678e-01 1.0174e-01 7.4319e-02 7.9170e-02 6.4618e-02 5.4145e-02
+ 5.7382e-02 9.4596e-02 4.6619e-02 1.8586e-01 7.1201e-02 4.2037e-02 6.0509e-02 8.9402e-02
+ 5.4076e-02 1.1271e-01 6.4099e-02 3.8978e-02 -nan(ind) 5.1815e-02 4.2128e-02 7.0461e-02
+ 5.1872e-02 5.1144e-02 1.0679e-01 5.6879e-02 5.3966e-02 5.6882e-02 7.5770e-02 4.6308e-02
+ 5.3329e-02 6.7397e-02 6.4387e-02 9.2465e-02 5.7048e-02 5.0372e-02 1.0956e-01 4.7023e-02
+ -nan(ind) -nan(ind) 9.3262e-02 9.3137e-02 9.4028e-02 -nan(ind) -nan(ind) 5.8440e-02
+ 8.8581e-02 1.1698e-01 7.8240e-02 7.3735e-02 1.0984e-01 9.8498e-02 7.3378e-02 6.0441e-02
+ 9.8128e-02 1.1550e-01 7.3793e-02 7.1441e-02 9.3929e-02 5.3498e-02 1.2607e-01 8.5801e-02
+ 3.8796e-02 -nan(ind) -nan(ind) 3.9431e-02 -nan(ind) 8.1487e-02 6.3102e-02 6.5476e-02
+ 1.1668e-01 9.4467e-02 1.4317e-01 7.1631e-02 7.2625e-02 7.2900e-02 8.9386e-02 8.9066e-02
+ 7.4999e-02 1.1907e-01 7.7813e-02 -nan(ind) 5.0488e-02 -nan(ind) -nan(ind) 7.0341e-02
+ 1.2095e-01 6.1485e-02 -nan(ind) 1.0230e-01 5.1618e-02 1.3893e-01 5.4459e-02 5.1272e-02
+ 7.0411e-02 5.9088e-02 8.6618e-02 4.8245e-02 5.2229e-02 6.1468e-02 5.9774e-02 5.7958e-02
+ 5.3446e-02 6.5678e-02 4.8025e-02 2.2072e-01 4.8668e-02 4.7752e-02 5.8100e-02 9.9410e-02
+ 4.3127e-02 -nan(ind) 7.6763e-02 4.5300e-02 -nan(ind) 6.8743e-02 7.3331e-02 1.1040e-01
+ 4.5732e-02 8.7199e-02 9.9224e-02 5.8926e-02 6.3353e-02 6.8962e-02 -nan(ind) 3.7465e-02
+ 7.3294e-02 -nan(ind) 5.3663e-02 4.9172e-02 8.7602e-02 5.1597e-02 1.7352e-01 9.6133e-02
+ 6.5152e-02 8.4656e-02 5.4667e-02 1.0478e-01 7.6700e-02 5.2210e-02 4.8165e-02 4.0932e-02
+ -nan(ind) 4.4827e-02 5.2660e-02 7.7724e-02 4.5665e-02 6.7533e-02 4.0368e-02 8.7688e-02
+ 5.5085e-02 5.5781e-02 5.8763e-02 6.1092e-02 7.2792e-02 5.6303e-02 8.9898e-02 5.6301e-02
+ 1.1861e-01 6.7636e-02 1.4294e-01 6.5686e-02 4.7971e-02 -nan(ind) -nan(ind) 4.4354e-02
+ 9.5361e-02 1.2070e-01 6.4407e-02 6.5039e-02 5.2172e-02 7.4988e-02 7.3876e-02 6.0224e-02
+ 4.5284e-02 9.6084e-02 5.8642e-02 6.5857e-02 7.3355e-02 5.5972e-02 6.7680e-02 4.3957e-02
+ 5.1759e-02 4.6524e-02 4.9600e-02 5.4511e-02 7.4822e-02 5.6317e-02 6.6300e-02 7.4238e-02
+ 8.4250e-02 4.5655e-02 5.2900e-02 7.2981e-02 6.5481e-02 1.0785e-01 5.2177e-02 9.1927e-02
+ 5.8799e-02 5.1029e-02 9.3815e-02 4.5717e-02 4.8230e-02 1.0024e-01 8.5933e-02 6.8261e-02
+ 5.4742e-02 1.4972e-01 1.0114e-01 4.8349e-02 1.2780e-01 7.8431e-02 6.9395e-02 1.0073e-01
+ 5.5647e-02 6.3670e-02 5.8978e-02 8.9970e-02 5.4181e-02 4.5541e-02 -nan(ind) 1.0280e-01
+ 4.9773e-02 1.1196e-01 6.9958e-02 7.0114e-02 8.5265e-02 6.4486e-02 1.7560e-01 8.3372e-02
+ 5.5193e-02 8.9512e-02 9.1390e-02 8.6668e-02 1.0350e-01 9.9326e-02 1.0239e-01 1.0901e-01
+ 5.0771e-02 5.6020e-02 1.0845e-01 4.9756e-02 5.9670e-02 -nan(ind) 3.5990e-02 6.7006e-02
+ -nan(ind) 5.8285e-02 9.4026e-02 5.1735e-02 8.1687e-02 6.7424e-02 8.1483e-02 4.9180e-02
+ 8.9578e-02 5.6856e-02 7.4466e-02 7.3846e-02 7.6312e-02 7.2478e-02 1.0249e-01 7.6557e-02
+ 4.2301e-02 -nan(ind) -nan(ind) 3.7558e-02 -nan(ind) 6.7279e-02 5.4592e-02 6.1830e-02
+ 5.3996e-02 5.7417e-02 5.3248e-02 7.6896e-02 6.8468e-02 6.4977e-02 6.7238e-02 7.6269e-02
+ 4.6592e-02 6.4585e-02 6.9883e-02 1.1012e-01 5.1284e-02 7.2682e-02 -nan(ind) 5.8237e-02
+ 7.6025e-02 6.5154e-02 7.4302e-02 4.8730e-02 1.2076e-01 8.2230e-02 9.2551e-02 6.2192e-02
+ 1.0332e-01 -nan(ind) 1.0180e-01 5.0772e-02 1.1148e-01 1.8615e-01 5.5986e-02 1.2453e-01
+ 6.4896e-02 1.0485e-01 9.2810e-02 4.6220e-02 -nan(ind) -nan(ind) 3.8422e-02 1.1635e-01
+ 5.6014e-02 7.3341e-02 4.3040e-02 6.3415e-02 4.7713e-02 5.0988e-02 1.1142e-01 4.4333e-02
+ 9.3741e-02 6.1775e-02 4.1822e-02 1.1120e-01 7.8719e-02 4.4362e-02 6.9349e-02 1.0116e-01
+ 4.6601e-02 5.7747e-02 5.4771e-02 7.1299e-02 7.6300e-02 6.3301e-02 4.6203e-02 1.0170e-01
+ 7.4667e-02 5.6368e-02 6.0366e-02 4.6326e-02 -nan(ind) 5.3062e-02 4.3327e-02 9.0879e-02
+ 5.1517e-02 -nan(ind) 8.4571e-02 -nan(ind) 5.8209e-02 1.2952e-01 7.4540e-02 9.4154e-02
+ 6.7003e-02 -nan(ind) 7.6573e-02 1.1871e-01 6.7212e-02 1.0506e-01 7.2620e-02 6.9835e-02
+ 8.8811e-02 6.5062e-02 1.2716e-01 9.6218e-02 4.8283e-02 -nan(ind) 1.8176e-01 4.4291e-02
+ 1.4982e-01 7.5551e-02 6.9598e-02 6.3996e-02 6.9859e-02 8.5122e-02 5.8773e-02 6.9775e-02
+ 7.8856e-02 9.3035e-02 2.0103e-01 6.0689e-02 1.0758e-01 8.4754e-02 -nan(ind) 5.5676e-02
+ -nan(ind) 7.5999e-02 9.9673e-02 8.6382e-02 5.9648e-02 8.1209e-02 6.0691e-02 -nan(ind)
+ 5.7591e-02 5.4552e-02 5.1064e-02 4.8994e-02 1.1318e-01 4.0479e-02 8.7665e-02 6.7052e-02
+ 5.6941e-02 5.3393e-02 1.0214e-01 4.6456e-02 7.9972e-02 5.6658e-02 4.8895e-02 8.6200e-02
+ 1.1330e-01 4.0263e-02 -nan(ind) 4.5354e-02 5.9181e-02 5.5612e-02 1.0281e-01 4.9106e-02
+ 8.8131e-02 8.9301e-02 6.0473e-02 8.9870e-02 6.8803e-02 7.5869e-02 1.0785e-01 3.9005e-02
+ 8.0413e-02 -nan(ind) 5.2163e-02 1.0958e-01 9.6013e-02 5.6297e-02 6.8930e-02 4.5782e-02
+ 5.6948e-02 4.4924e-02 7.8440e-02 5.0777e-02 -nan(ind) 8.6546e-02 7.1850e-02 7.8824e-02
+ 5.4045e-02 -nan(ind) 5.7769e-02 3.9764e-02 -nan(ind) 5.4989e-02 4.2908e-02 5.0832e-02
+ 7.1340e-02 5.2039e-02 7.4889e-02 4.2455e-02 5.1390e-02 6.3752e-02 6.2397e-02 6.5116e-02
+ 5.6382e-02 5.9852e-02 1.4210e-01 5.2235e-02 7.0114e-02 7.2683e-02 8.4343e-02 7.0798e-02
+ 5.1650e-02 -nan(ind) 9.0963e-02 3.8993e-02 1.0296e-01 7.9137e-02 8.9836e-02 5.7861e-02
+ 5.3166e-02 6.4736e-02 6.5586e-02 7.7859e-02 6.1553e-02 5.2124e-02 5.4717e-02 6.3132e-02
+ 5.6496e-02 5.6909e-02 4.0658e-02 6.5211e-02 4.6918e-02 1.1994e-01 4.9271e-02 5.9058e-02
+ 6.6458e-02 7.1252e-02 9.9446e-02 5.7144e-02 6.3850e-02 8.1232e-02 7.6746e-02 7.6866e-02
+ 3.7505e-02 1.0630e-01 3.9396e-02 9.0762e-02 5.1830e-02 5.0091e-02 8.5872e-02 5.9402e-02
+ 7.3638e-02 7.6506e-02 -nan(ind) 1.1879e-01 4.6326e-02 -nan(ind) 7.6673e-02 7.4380e-02
+ 1.1810e-01 6.9144e-02 9.0824e-02 6.1176e-02 7.4855e-02 6.1033e-02 4.4905e-02 5.1435e-02
+ 5.2171e-02 5.5714e-02 8.1047e-02 6.8463e-02 4.8836e-02 -nan(ind) 6.4777e-02 5.0157e-02
+ 9.1338e-02 7.8442e-02 -nan(ind) 6.1325e-02 4.8381e-02 -nan(ind) 8.6009e-02 -nan(ind)
+ 6.5166e-02 2.2559e-01 8.2439e-02 5.5268e-02 7.4455e-02 5.8927e-02 5.7232e-02 1.1896e-01
+ 5.0176e-02 6.4812e-02 6.1572e-02 5.6578e-02 5.6108e-02 1.0379e-01 6.2819e-02 7.0722e-02
+ 4.2720e-02 7.8236e-02 8.1977e-02 5.4518e-02 8.2127e-02 7.2434e-02 5.4425e-02 5.1672e-02
+ 1.0493e-01 5.3963e-02 9.5278e-02 7.6485e-02 3.6755e-02 -nan(ind) 1.2056e-01 3.9000e-02
+ 2.5620e-01 8.0906e-02 4.1554e-02 6.6300e-02 7.3405e-02 6.7925e-02 8.1633e-02 6.2623e-02
+ 7.3057e-02 7.8654e-02 8.2636e-02 6.3667e-02 6.6032e-02 4.9293e-02 8.8206e-02 6.3025e-02
+ 6.6385e-02 5.3674e-02 1.1220e-01 4.3505e-02 6.8072e-02 6.1324e-02 4.4939e-02 5.2813e-02
+ 5.2821e-02 7.3385e-02 6.3946e-02 9.8007e-02 9.6050e-02 7.4374e-02 -nan(ind) 8.5350e-02
+ 9.0193e-02 -nan(ind) 5.2660e-02 8.7072e-02 4.9039e-02 6.3370e-02 -nan(ind) 4.1137e-02
+ -nan(ind) 7.9440e-02 5.8572e-02 6.2578e-02 5.2556e-02 3.8017e-02 5.4743e-02 6.5577e-02
+ 5.9472e-02 6.9548e-02 5.8110e-02 4.5932e-02 5.9555e-02 9.5101e-02 5.2710e-02 1.3249e-01
+ 6.1495e-02 3.4574e-02 1.9587e-01 8.0297e-02 4.1851e-02 7.2386e-02 6.0131e-02 5.8451e-02
+ 6.6890e-02 4.6758e-02 5.5165e-02 5.6292e-02 5.6129e-02 1.1108e-01 9.3694e-02 6.0280e-02
+ 7.1107e-02 -nan(ind) 4.8073e-02 1.8547e-01 4.1735e-02 1.5492e-01 7.9290e-02 9.2979e-02
+ 7.4663e-02 5.9989e-02 6.0303e-02 6.4526e-02 5.7744e-02 5.1999e-02 9.2877e-02 6.5112e-02
+ 6.3122e-02 6.2875e-02 5.6324e-02 1.0617e-01 8.6888e-02 6.9081e-02 7.5916e-02 -nan(ind)
+ 4.3137e-02 -nan(ind) 1.1342e-01 5.0367e-02 1.9039e-01 9.9100e-02 5.2547e-02 8.6778e-02
+ 6.9123e-02 5.9331e-02 7.1709e-02 9.5097e-02 7.5435e-02 8.6134e-02 6.4374e-02 6.2524e-02
+ 9.1657e-02 5.9086e-02 7.6458e-02 7.4797e-02 8.1877e-02 7.6978e-02 8.7774e-02 2.5895e-01
+ 7.3805e-02 1.0100e-01 1.0483e-01 1.1335e-01 6.8920e-02 5.0221e-02 -nan(ind) 5.1332e-02
+ 6.2892e-02 8.1626e-02 5.5545e-02 5.7897e-02 3.7811e-02 1.6617e-01 5.3177e-02 3.9397e-02
+ 1.5539e-01 6.7951e-02 4.1153e-02 -nan(ind) 5.4938e-02 6.5262e-02 8.9324e-02 4.5241e-02
+ 5.8937e-02 1.1699e-01 6.0216e-02 8.5421e-02 6.0469e-02 6.7656e-02 1.4843e-01 5.9669e-02
+ 1.0194e-01 5.2601e-02 5.6555e-02 5.6364e-02 1.3188e-01 5.8438e-02 4.0728e-02 -nan(ind)
+ 1.4192e-01 4.0840e-02 1.5865e-01 8.1567e-02 4.0460e-02 -nan(ind) 6.6128e-02 5.3741e-02
+ 8.6494e-02 4.8182e-02 1.2048e-01 7.1786e-02 8.0874e-02 6.2611e-02 8.2586e-02 5.3575e-02
+ 5.2594e-02 5.0077e-02 5.2518e-02 5.5058e-02 4.2017e-02 1.1397e-01 9.3090e-02 5.6414e-02
+ 5.3006e-02 7.6637e-02 6.5346e-02 1.0543e-01 4.7037e-02 3.8591e-02 -nan(ind) 7.3466e-02
+ 4.9976e-02 7.0140e-02 1.5107e-01 7.4587e-02 5.5159e-02 1.0364e-01 9.9109e-02 4.1480e-02
+ 1.3410e-01 1.8611e-01 5.8387e-02 5.4677e-02 1.6813e-01 9.3823e-02 4.9698e-02 6.9754e-02
+ 7.3492e-02 5.8346e-02 1.6867e-01 6.7601e-02 6.3301e-02 6.6488e-02 9.1809e-02 4.7912e-02
+ 7.1901e-02 6.8686e-02 4.8668e-02 9.7821e-02 5.0633e-02 5.3390e-02 4.7149e-02 5.7790e-02
+ 5.4668e-02 7.9414e-02 4.8673e-02 6.9913e-02 9.1709e-02 6.6702e-02 6.9123e-02 4.6791e-02
+ 8.6205e-02 7.7717e-02 5.3189e-02 1.1937e-01 1.1169e-01 4.1173e-02 -nan(ind) 6.0450e-02
+ 8.9100e-02 5.3780e-02 4.8391e-02 1.1592e-01 5.3784e-02 8.7968e-02 1.0004e-01 8.1011e-02
+ 8.6406e-02 5.1184e-02 8.5473e-02 8.7126e-02 6.1841e-02 6.7477e-02 9.3217e-02 5.0444e-02
+ 7.5513e-02 6.6729e-02 7.6961e-02 3.7475e-02 -nan(ind) 6.2211e-02 6.2097e-02 7.6903e-02
+ 1.2108e-01 4.8116e-02 1.4214e-01 6.6219e-02 5.4581e-02 9.5629e-02 5.0194e-02 8.6841e-02
+ 6.9937e-02 7.0323e-02 6.5545e-02 5.8738e-02 7.8078e-02 3.1856e-02 1.0790e-01 5.7721e-02
+ 6.2863e-02 6.9280e-02 6.0010e-02 7.0234e-02 4.1412e-02 7.8750e-02 5.8781e-02 5.8619e-02
+ 5.9276e-02 4.4894e-02 5.7657e-02 6.3248e-02 5.0866e-02 5.3391e-02 8.3934e-02 1.3324e-01
+ 3.8496e-02 1.0578e-01 8.4643e-02 3.4005e-02 1.3383e-01 7.3162e-02 4.0984e-02 6.9975e-02
+ 6.9552e-02 5.4840e-02 6.5373e-02 5.5317e-02 6.7688e-02 4.9740e-02 5.8900e-02 5.6183e-02
+ 6.5835e-02 5.4887e-02 5.6490e-02 7.6765e-02 5.9467e-02 5.0461e-02 5.6447e-02 6.9617e-02
+ 5.8096e-02 6.2200e-02 7.5458e-02 5.5185e-02 7.0080e-02 5.3466e-02 9.5161e-02 7.0252e-02
+ 8.6947e-02 6.0207e-02 3.9628e-02 5.6515e-02 6.9954e-02 5.7881e-02 6.4053e-02 1.1519e-01
+ 5.9191e-02 2.1915e-01 6.4915e-02 6.8714e-02 8.1113e-02 7.0445e-02 6.6412e-02 5.7624e-02
+ 1.1523e-01 4.3836e-02 6.9368e-02 6.7809e-02 7.1661e-02 5.0962e-02 5.2355e-02 5.0939e-02
+ 4.6612e-02 8.9309e-02 4.7179e-02 7.3110e-02 7.8496e-02 5.1503e-02 5.2183e-02 2.0536e-01
+ 4.1066e-02 1.4591e-01 4.4364e-02 8.8193e-02 5.3217e-02 8.1431e-02 7.0131e-02 1.1184e-01
+ 9.4271e-02 6.1451e-02 1.8811e-01 4.8188e-02 8.8143e-02 6.4585e-02 5.1673e-02 6.8719e-02
+ 4.6641e-02 6.7448e-02 4.2347e-02 5.7084e-02 1.0877e-01 4.6659e-02 7.1050e-02 8.1152e-02
+ 7.0732e-02 4.9764e-02 9.5723e-02 6.6336e-02 5.2301e-02 1.2395e-01 6.5904e-02 6.6849e-02
+ 6.0399e-02 7.5464e-02 8.6438e-02 9.7038e-02 4.4825e-02 2.8207e-01 9.8134e-02 3.2920e-02
+ 1.2151e-01 6.7032e-02 5.7648e-02 6.2389e-02 4.4376e-02 8.6971e-02 4.4618e-02 7.5654e-02
+ 5.6700e-02 6.4296e-02 5.9997e-02 6.3934e-02 8.8129e-02 4.6691e-02 6.7988e-02 4.9265e-02
+ 6.0952e-02 4.7236e-02 7.8460e-02 5.3299e-02 5.0814e-02 7.5103e-02 6.4807e-02 5.5761e-02
+ 6.7068e-02 7.1818e-02 8.1827e-02 8.2929e-02 8.3464e-02 7.4452e-02 6.3878e-02 1.0979e-01
+ 4.9528e-02 6.0057e-02 9.2812e-02 4.7491e-02 1.6184e-01 8.8311e-02 5.0055e-02 4.9884e-02
+ 4.7200e-02 5.0234e-02 6.2040e-02 7.2585e-02 6.7783e-02 6.7315e-02 6.9500e-02 6.6676e-02
+ 5.5668e-02 8.9965e-02 5.7739e-02 8.6221e-02 1.0588e-01 5.6227e-02 6.5038e-02 9.1759e-02
+ 5.2590e-02 9.2710e-02 5.3449e-02 7.1840e-02 7.2089e-02 4.5914e-02 2.4021e-01 5.0225e-02
+ 4.2887e-02 1.0951e-01 4.1790e-02 7.2211e-02 5.6451e-02 5.8067e-02 1.1452e-01 1.4317e-01
+ 6.1575e-02 4.9436e-02 1.2067e-01 7.0461e-02 1.1256e-01 4.9305e-02 1.0610e-01 6.4026e-02
+ 6.1559e-02 9.2898e-02 4.7506e-02 6.2277e-02 6.4480e-02 6.2068e-02 5.8799e-02 8.9944e-02
+ 8.6115e-02 4.2711e-02 6.7824e-02 6.0768e-02 6.9584e-02 5.0421e-02 9.7046e-02 8.0987e-02
+ 4.2806e-02 1.0572e-01 8.3853e-02 4.4633e-02 9.7406e-02 6.9241e-02 4.4664e-02 5.8854e-02
+ 6.6205e-02 5.1938e-02 7.1478e-02 5.5846e-02 1.2621e-01 4.6711e-02 6.4038e-02 8.6578e-02
+ 5.1348e-02 5.7548e-02 8.9477e-02 5.6987e-02 8.0216e-02 8.5481e-02 5.0321e-02 1.2523e-01
+ 5.9211e-02 6.7148e-02 1.0291e-01 1.0136e-01 7.2385e-02 6.8531e-02 1.1404e-01 5.9503e-02
+ 5.2761e-02 5.9480e-02 1.0992e-01 4.0085e-02 1.2052e-01 8.9785e-02 4.2194e-02 -nan(ind)
+ 9.1900e-02 5.5069e-02 5.2857e-02 5.4415e-02 -nan(ind) 5.0629e-02 5.1948e-02 8.0803e-02
+ 7.3192e-02 7.2560e-02 1.1590e-01 5.4868e-02 1.2336e-01 4.6775e-02 5.4466e-02 6.2901e-02
+ 5.7937e-02 8.5831e-02 5.6208e-02 5.1264e-02 -nan(ind) 5.3793e-02 5.5716e-02 8.9969e-02
+ 5.3014e-02 6.9258e-02 4.2157e-02 1.3251e-01 7.0377e-02 4.6252e-02 8.2269e-02 5.5017e-02
+ 5.0694e-02 7.6498e-02 5.4205e-02 1.2916e-01 4.5704e-02 2.0980e-01 5.6330e-02 5.4469e-02
+ 7.0368e-02 4.7839e-02 6.5043e-02 7.5334e-02 7.4998e-02 1.4192e-01 2.0833e-01 5.6793e-02
+ 9.3164e-02 9.6492e-02 5.7028e-02 4.8137e-02 7.7419e-02 1.1158e-01 5.3514e-02 6.6761e-02
+ 1.5552e-01 7.0099e-02 7.6822e-02 9.3936e-02 5.3952e-02 1.1860e-01 7.1357e-02 5.6055e-02
+ 8.9895e-02 7.1877e-02 6.6494e-02 1.0760e-01 7.4495e-02 7.1991e-02 6.4015e-02 9.4840e-02
+ 7.1222e-02 6.4047e-02 8.5607e-02 7.3266e-02 7.7777e-02 2.3310e-01 6.8925e-02 1.2522e-01
+ 5.0928e-02 6.1850e-02 1.4151e-01 8.1506e-02 6.9550e-02 5.4943e-02 8.2249e-02 4.9022e-02
+ 4.7905e-02 7.3694e-02 6.3526e-02 4.5010e-02 6.4764e-02 5.4565e-02 4.2968e-02 7.6358e-02
+ 7.8245e-02 4.4141e-02 1.0989e-01 5.2103e-02 7.4033e-02 5.3848e-02 5.7223e-02 -nan(ind)
+ 4.9053e-02 8.7818e-02 1.8648e-01 5.1797e-02 1.1689e-01 1.2002e-01 4.0483e-02 9.4312e-02
+ 5.3922e-02 7.1980e-02 1.1309e-01 5.6465e-02 6.3869e-02 6.0455e-02 5.2579e-02 1.0195e-01
+ 6.1758e-02 5.6683e-02 -nan(ind) 4.5696e-02 9.1718e-02 5.8806e-02 1.9508e-01 4.0168e-02
+ 6.5051e-02 8.9403e-02 5.1253e-02 9.3729e-02 8.9420e-02 4.9859e-02 9.4124e-02 5.9557e-02
+ 1.1421e-01 6.4581e-02 1.0552e-01 5.6260e-02 5.4629e-02 7.6299e-02 5.7005e-02 4.6316e-02
+ 1.0035e-01 6.0195e-02 4.0541e-02 -nan(ind) 8.0697e-02 7.4035e-02 7.7862e-02 5.9823e-02
+ 8.8223e-02 6.5172e-02 5.4329e-02 7.7646e-02 7.3723e-02 4.8871e-02 1.0874e-01 9.5337e-02
+ 3.6336e-02 9.0709e-02 6.9618e-02 4.7871e-02 1.0765e-01 7.9662e-02 4.5646e-02 1.1681e-01
+ 6.2887e-02 6.6166e-02 6.0315e-02 7.7755e-02 7.9437e-02 7.8116e-02 7.2381e-02 6.2826e-02
+ 6.6142e-02 6.3204e-02 6.0530e-02 5.4660e-02 7.3977e-02 5.0822e-02 6.6134e-02 5.3079e-02
+ 6.1384e-02 9.0605e-02 5.2464e-02 7.8011e-02 5.0671e-02 6.0908e-02 5.0897e-02 7.7825e-02
+ 1.1234e-01 4.2778e-02 8.7288e-02 1.0540e-01 5.9551e-02 9.9115e-02 5.9220e-02 6.6108e-02
+ 5.0457e-02 -nan(ind) 5.4277e-02 1.1168e-01 8.8085e-02 5.3705e-02 4.9866e-02 9.0096e-02
+ 5.4511e-02 8.3427e-02 4.8584e-02 6.4809e-02 6.4341e-02 1.0978e-01 4.0011e-02 7.7788e-02
+ 7.7761e-02 1.0081e-01 5.8772e-02 7.4895e-02 4.9934e-02 8.8690e-02 5.2907e-02 7.1854e-02
+ 6.6146e-02 5.9818e-02 6.9591e-02 1.3955e-01 3.5575e-02 1.2660e-01 6.8272e-02 5.1900e-02
+ 8.4103e-02 1.1702e-01 7.4921e-02 7.4897e-02 6.6000e-02 4.5121e-02 1.0321e-01 1.3567e-01
+ 6.4809e-02 5.4471e-02 7.6016e-02 5.2880e-02 4.9847e-02 7.5842e-02 7.5358e-02 5.4515e-02
+ 6.7838e-02 7.3883e-02 4.7274e-02 8.1217e-02 8.0157e-02 5.9189e-02 5.7069e-02 9.2338e-02
+ 1.1617e-01 4.5658e-02 1.5536e-01 1.0456e-01 4.2366e-02 9.4414e-02 7.5294e-02 4.9431e-02
+ 8.0740e-02 7.2270e-02 5.4449e-02 2.2424e-01 6.9554e-02 6.2955e-02 7.5095e-02 8.3518e-02
+ 6.1793e-02 5.2713e-02 4.6861e-02 9.7673e-02 5.3763e-02 7.4347e-02 8.3191e-02 5.6975e-02
+ 5.4683e-02 9.2688e-02 6.1962e-02 5.9756e-02 8.7686e-02 5.2727e-02 8.6152e-02 4.6270e-02
+ 1.0955e-01 4.4783e-02 8.0834e-02 6.9179e-02 3.9936e-02 1.0720e-01 7.3934e-02 4.9602e-02
+ 8.7288e-02 9.2912e-02 6.1558e-02 6.6848e-02 9.6788e-02 4.7401e-02 1.4303e-01 5.6573e-02
+ 5.1604e-02 1.0057e-01 7.2909e-02 1.1100e-01 5.9590e-02 4.4235e-02 -nan(ind) 5.2248e-02
+ 1.0775e-01 5.1046e-02 6.6514e-02 6.2437e-02 4.5007e-02 1.2310e-01 1.0213e-01 4.3200e-02
+ 1.1223e-01 6.7888e-02 5.9486e-02 6.9672e-02 7.3532e-02 8.9509e-02 4.6115e-02 1.7892e-01
+ 1.1879e-01 4.2500e-02 1.0770e-01 7.7072e-02 5.4785e-02 1.0695e-01 5.3363e-02 1.5571e-01
+ 8.5642e-02 7.1931e-02 5.7724e-02 6.1153e-02 1.0510e-01 5.0354e-02 8.3417e-02 4.8873e-02
+ 6.0933e-02 8.1119e-02 5.9086e-02 5.7330e-02 8.3990e-02 7.0075e-02 6.9721e-02 5.2375e-02
+ 5.9720e-02 1.0361e-01 5.2384e-02 6.8685e-02 7.1990e-02 4.6868e-02 1.0967e-01 1.0571e-01
+ 4.2217e-02 1.3947e-01 7.4020e-02 4.0908e-02 1.1121e-01 5.7714e-02 4.8342e-02 1.2114e-01
+ 7.0156e-02 5.3896e-02 8.2492e-02 5.1639e-02 5.8234e-02 4.7100e-02 7.0293e-02 4.8104e-02
+ 7.3226e-02 6.5825e-02 4.9103e-02 9.1816e-02 7.1638e-02 7.1585e-02 4.6834e-02 5.5208e-02
+ 5.9204e-02 5.3728e-02 6.1357e-02 9.9717e-02 5.6612e-02 7.3391e-02 9.9157e-02 4.9259e-02
+ 1.0443e-01 9.4033e-02 5.8643e-02 1.1402e-01 1.3068e-01 4.3541e-02 -nan(ind) 6.1625e-02
+ 8.5867e-02 1.1394e-01 5.6605e-02 7.5287e-02 6.3212e-02 8.1939e-02 5.8365e-02 4.4809e-02
+ 1.0596e-01 9.1924e-02 5.4766e-02 6.8515e-02 5.9833e-02 4.8061e-02 6.4024e-02 5.3973e-02
+ 8.3935e-02 5.3171e-02 5.4696e-02 7.1259e-02 8.0822e-02 7.2606e-02 4.7680e-02 6.2807e-02
+ 8.0023e-02 6.4540e-02 1.7694e-01 4.6081e-02 4.4537e-02 8.6905e-02 4.3805e-02 1.0622e-01
+ 6.3673e-02 6.1432e-02 9.4658e-02 6.6236e-02 1.2122e-01 9.0465e-02 5.2631e-02 6.6254e-02
+ 1.8381e-01 9.5104e-02 7.2496e-02 8.6477e-02 8.0637e-02 4.1020e-02 7.1796e-02 7.5931e-02
+ 5.2387e-02 6.4775e-02 9.5841e-02 5.8708e-02 6.4783e-02 8.1569e-02 7.0809e-02 6.2460e-02
+ 1.0634e-01 4.0934e-02 1.0661e-01 1.4001e-01 4.3323e-02 1.8664e-01 7.7711e-02 4.7978e-02
+ 8.9871e-02 7.1100e-02 5.8971e-02 5.7764e-02 6.7863e-02 4.7994e-02 7.8578e-02 7.9413e-02
+ 6.5065e-02 4.4893e-02 7.5881e-02 5.0876e-02 6.8210e-02 8.5162e-02 6.1120e-02 6.6130e-02
+ 6.9936e-02 6.5727e-02 8.2844e-02 7.2233e-02 6.8387e-02 5.5606e-02 1.1538e-01 7.1032e-02
+ 8.6011e-02 7.1041e-02 5.5386e-02 7.7113e-02 1.1920e-01 5.7499e-02 1.4187e-01 6.0402e-02
+ 5.1996e-02 1.4375e-01 5.6595e-02 9.5101e-02 6.6046e-02 5.3131e-02 7.1395e-02 5.7988e-02
+ 1.1365e-01 4.1969e-02 6.8730e-02 1.1366e-01 6.5793e-02 8.2238e-02 5.6136e-02 8.2841e-02
+ 7.6020e-02 -nan(ind) 5.3606e-02 6.1049e-02 6.1845e-02 6.7084e-02 4.7178e-02 4.4319e-02
+ 8.7098e-02 6.9198e-02 9.2493e-02 4.8280e-02 5.5038e-02 6.3317e-02 5.5488e-02 1.1895e-01
+ 5.2973e-02 8.3540e-02 1.3170e-01 4.0930e-02 9.6839e-02 5.8713e-02 5.8507e-02 8.0699e-02
+ 6.7605e-02 1.2816e-01 7.7347e-02 1.0062e-01 5.5102e-02 6.5691e-02 5.2036e-02 6.8827e-02
+ 2.9911e-01 5.6620e-02 8.4456e-02 9.0747e-02 4.6852e-02 1.3382e-01 6.2521e-02 5.8703e-02
+ 8.9651e-02 8.0483e-02 7.2633e-02 6.0007e-02 1.0843e-01 5.3140e-02 1.0056e-01 1.3758e-01
+ 5.5798e-02 8.1354e-02 8.4462e-02 4.8385e-02 8.8367e-02 6.9671e-02 6.8805e-02 6.2403e-02
+ 7.9003e-02 7.5949e-02 8.1964e-02 7.3163e-02 5.6072e-02 6.1782e-02 5.3286e-02 8.2826e-02
+ 7.0573e-02 5.6750e-02 5.8865e-02 1.1110e-01 6.2053e-02 9.8820e-02 6.5866e-02 5.9097e-02
+ 6.8889e-02 7.9302e-02 6.5064e-02 6.8737e-02 6.5040e-02 5.2279e-02 6.1921e-02 9.0433e-02
+ 5.7322e-02 1.0161e-01 5.5273e-02 6.7378e-02 7.4187e-02 4.7850e-02 7.9968e-02 4.4462e-02
+ 6.3522e-02 6.5024e-02 8.9167e-02 9.8378e-02 5.2846e-02 -nan(ind) 6.8716e-02 5.7044e-02
+ 5.5129e-02 8.0354e-02 7.6688e-02 8.3543e-02 9.5256e-02 5.3349e-02 6.6591e-02 1.0570e-01
+ 4.7280e-02 7.2351e-02 1.0168e-01 7.1948e-02 5.0163e-02 6.1780e-02 6.3834e-02 7.0874e-02
+ 6.2121e-02 6.4135e-02 6.0978e-02 5.1817e-02 6.2964e-02 4.5980e-02 7.9402e-02 1.3484e-01
+ 4.4880e-02 1.0971e-01 6.1578e-02 8.4773e-02 9.2478e-02 8.9548e-02 5.7626e-02 1.2695e-01
+ 5.3878e-02 7.6417e-02 6.6217e-02 8.3155e-02 7.4388e-02 8.7608e-02 6.8064e-02 1.0532e-01
+ 7.8953e-02 7.9879e-02 5.9249e-02 8.5487e-02 6.7805e-02 7.8235e-02 5.9374e-02 8.5348e-02
+ 6.9148e-02 6.8278e-02 9.2645e-02 7.7876e-02 7.2949e-02 1.4559e-01 6.6587e-02 6.1287e-02
+ 8.9199e-02 8.7678e-02 6.1435e-02 1.1461e-01 6.2631e-02 1.1798e-01 7.0647e-02 6.6583e-02
+ 8.5269e-02 6.5131e-02 7.1208e-02 7.4005e-02 1.4043e-01 6.9219e-02 7.1949e-02 1.0689e-01
+ 5.3881e-02 8.8040e-02 6.3458e-02 8.0145e-02 7.1290e-02 7.6944e-02 7.1409e-02 9.2380e-02
+ 5.8443e-02 9.7211e-02 6.9690e-02 6.0013e-02 1.0779e-01 5.6876e-02 1.3068e-01 6.5642e-02
+ 6.5968e-02 8.3256e-02 5.7853e-02 4.1857e-02 6.4546e-02 7.5458e-02 5.3373e-02 5.9079e-02
+ 1.1152e-01 6.9624e-02 5.8571e-02 1.0080e-01 6.3044e-02 6.5088e-02 5.2034e-02 9.2998e-02
+ 7.6130e-02 4.9305e-02 5.4729e-02 5.9347e-02 9.9170e-02 5.8550e-02 5.3689e-02 6.7809e-02
+ 6.5566e-02 5.5443e-02 6.5418e-02 7.3988e-02 6.8665e-02 4.6503e-02 6.9088e-02 7.0241e-02
+ 8.6126e-02 5.9323e-02 5.4559e-02 5.8437e-02 5.9035e-02 4.2638e-02 1.2027e-01 7.6417e-02
+ 7.0927e-02 5.7799e-02 7.6912e-02 1.0552e-01 1.2588e-01 6.2085e-02 9.3696e-02 6.3452e-02
+ 6.6581e-02 1.0000e+06 9.1005e-02 9.2178e-02 7.4221e-02 5.5980e-02 8.6665e-02 1.0459e-01
+ 6.5111e-02 7.1033e-02 9.5042e-02 7.3977e-02 1.2668e-01 6.6163e-02 9.4989e-02 1.2405e-01
+ 7.9515e-02 1.0091e-01 6.7448e-02 6.5475e-02 1.0380e-01 5.0949e-02 1.0386e-01 1.4562e-01
+ 7.1571e-02 1.6244e-01 8.2859e-02 7.0794e-02 9.6957e-02 8.9723e-02 7.0865e-02 7.7363e-02
+ 5.0738e-02 7.7617e-02 1.1525e-01 4.7304e-02 4.4678e-02 1.0195e-01 8.0437e-02 8.1150e-02
+ 6.7337e-02 6.4144e-02 9.8748e-02 7.2563e-02 6.8472e-02 7.4534e-02 7.9067e-02 1.5387e-01
+ 6.6551e-02 6.0947e-02 6.6056e-02 7.4080e-02 8.7435e-02 5.4504e-02 5.2190e-02 8.5174e-02
+ -nan(ind) 5.4347e-02 1.3338e-01 6.2723e-02 4.8770e-02 7.2736e-02 7.5180e-02 6.3110e-02
+ 4.9025e-02 6.7617e-02 5.1920e-02 1.0141e-01 6.0068e-02 7.0812e-02 5.1337e-02 7.1617e-02
+ 5.9118e-02 5.6902e-02 1.2352e-01 5.6898e-02 9.7800e-02 5.4568e-02 6.7850e-02 5.6836e-02
+ 8.1236e-02 1.1199e-01 4.4219e-02 6.1236e-02 5.4321e-02 6.6944e-02 9.7028e-02 5.8824e-02
+ 7.1896e-02 1.1619e-01 5.3646e-02 7.2290e-02 6.3273e-02 9.1764e-02 8.4529e-02 1.1814e-01
+ 7.6848e-02 1.1102e-01 4.8617e-02 2.3797e-01 5.8319e-02 1.1562e-01 1.3581e-01 4.4742e-02
+ 7.2879e-02 1.2450e-01 5.6638e-02 1.1742e-01 6.9086e-02 1.3292e-01 8.4319e-02 7.4407e-02
+ 1.1489e-01 6.8650e-02 1.6052e-01 1.3532e-01 7.9955e-02 1.3438e-01 9.0241e-02 7.7361e-02
+ 8.7553e-02 8.7817e-02 1.0640e-01 9.8825e-02 8.7698e-02 8.2352e-02 1.1511e-01 6.8069e-02
+ 9.6715e-02 6.6358e-02 1.2771e-01 1.0328e-01 7.4624e-02 7.6147e-02 8.1452e-02 9.1092e-02
+ 7.9745e-02 5.6563e-02 9.7869e-02 7.4593e-02 1.0660e-01 1.0261e-01 6.4224e-02 5.5068e-02
+ 9.8814e-02 8.1154e-02 1.0696e-01 5.5062e-02 7.0511e-02 6.3016e-02 8.0421e-02 5.3224e-02
+ 5.2058e-02 8.7410e-02 9.5157e-02 7.1501e-02 6.3422e-02 1.8626e-01 4.6222e-02 8.4421e-02
+ 1.3145e-01 -nan(ind) 5.3587e-02 5.2165e-02 6.4870e-02 4.7016e-02 7.6293e-02 6.7316e-02
+ -nan(ind) 4.2099e-02 6.9365e-02 4.9830e-02 6.8049e-02 6.0955e-02 8.2141e-02 7.7433e-02
+ 8.0521e-02 1.1063e-01 5.1839e-02 8.9972e-02 7.0418e-02 5.7154e-02 8.2796e-02 6.0889e-02
+ 6.4299e-02 6.4961e-02 5.5910e-02 9.0860e-02 4.9517e-02 8.1555e-02 8.2116e-02 6.4432e-02
+ 8.3821e-02 7.2004e-02 7.2796e-02 8.5524e-02 1.4955e-01 7.5249e-02 7.9664e-02 7.3977e-02
+ 1.5308e-01 6.4585e-02 1.5323e-01 1.9481e-01 7.3832e-02 8.6561e-02 6.6851e-02 1.0502e-01
+ 1.3483e-01 6.7133e-02 1.4690e-01 6.9159e-02 1.2534e-01 8.6146e-02 7.6604e-02 1.0022e-01
+ 6.8578e-02 1.0896e-01 6.4619e-02 9.0013e-02 9.2448e-02 6.1072e-02 9.1975e-02 1.3774e-01
+ 6.6748e-02 1.1750e-01 7.2886e-02 1.1425e-01 1.2388e-01 6.9623e-02 8.1286e-02 6.6296e-02
+ 1.1676e-01 1.2164e-01 8.1337e-02 9.9406e-02 7.5188e-02 1.3189e-01 1.0002e-01 7.9140e-02
+ 1.0360e-01 8.0971e-02 9.9834e-02 7.8143e-02 8.6504e-02 5.2487e-02 6.7392e-02 5.6010e-02
+ 8.4022e-02 1.3734e-01 5.9253e-02 5.3769e-02 7.6269e-02 6.6370e-02 6.1715e-02 7.6311e-02
+ 5.5862e-02 6.2855e-02 9.2981e-02 1.3026e-01 5.8074e-02 4.5176e-02 -nan(ind) 5.4539e-02
+ 4.9681e-02 8.3609e-02 5.1464e-02 -nan(ind) 4.1902e-02 -nan(ind) 8.9866e-02 5.9588e-02
+ 7.1591e-02 4.1242e-02 -nan(ind) 5.7076e-02 6.0779e-02 7.4149e-02 6.3197e-02 4.9127e-02
+ 6.8720e-02 6.0060e-02 5.1370e-02 7.5733e-02 6.3884e-02 6.7875e-02 5.7760e-02 4.8557e-02
+ 9.9879e-02 5.3787e-02 8.9189e-02 5.2452e-02 6.6896e-02 1.7846e-01 7.3304e-02 2.4659e-01
+ 9.6754e-02 1.2748e-01 8.2068e-02 5.9343e-02 1.3409e-01 1.4474e-01 7.3383e-02 2.2919e-01
+ 6.0098e-02 8.8784e-02 6.6803e-02 1.3161e-01 1.1885e-01 8.4507e-02 9.1674e-02 7.4668e-02
+ 9.9801e-02 1.1967e-01 1.0916e-01 1.0284e-01 9.5967e-02 8.1795e-02 9.0006e-02 1.3808e-01
+ 8.6317e-02 9.5344e-02 1.1985e-01 1.1260e-01 9.6401e-02 1.1396e-01 7.2333e-02 1.1045e-01
+ 7.2322e-02 1.2093e-01 9.7958e-02 8.0796e-02 1.0004e-01 8.4734e-02 1.1519e-01 1.1229e-01
+ 9.6605e-02 9.3368e-02 8.9808e-02 7.6613e-02 1.0035e-01 7.2616e-02 1.1592e-01 9.9738e-02
+ 5.2810e-02 6.0575e-02 4.5873e-02 9.3679e-02 9.2846e-02 6.1216e-02 5.4278e-02 1.0071e-01
+ 6.7890e-02 6.0464e-02 6.7722e-02 6.7599e-02 1.5151e-01 5.3007e-02 8.0111e-02 5.6301e-02
+ 6.8060e-02 7.9723e-02 6.2220e-02 6.9323e-02 7.1864e-02 -nan(ind) 6.1098e-02 6.1230e-02
+ -nan(ind) 7.0233e-02 5.5422e-02 -nan(ind) 4.8204e-02 6.6152e-02 4.5281e-02 7.6391e-02
+ 4.7307e-02 1.0157e-01 6.9201e-02 5.9540e-02 8.6745e-02 7.8629e-02 9.3487e-02 6.3060e-02
+ 7.2090e-02 9.1470e-02 6.4963e-02 6.4706e-02 6.0193e-02 1.3278e-01 5.6744e-02 1.0635e-01
+ 8.2634e-02 5.3802e-02 1.7152e-01 8.8812e-02 1.7509e-01 9.0470e-02 1.0884e-01 9.8398e-02
+ 7.8225e-02 1.2474e-01 1.1691e-01 8.0756e-02 8.1512e-02 5.6664e-02 1.1081e-01 8.8385e-02
+ 9.0277e-02 1.0425e-01 1.4955e-01 1.0703e-01 1.6120e-01 1.2734e-01 1.5886e-01 1.5632e-01
+ 1.6620e-01 1.6165e-01 1.3493e-01 3.0619e-01 1.0366e-01 2.2583e-01 1.1771e-01 1.1688e-01
+ 1.2507e-01 1.1708e-01 1.2001e-01 1.5263e-01 8.2914e-02 1.0207e-01 1.0060e-01 9.5967e-02
+ 7.6466e-02 7.3674e-02 1.1039e-01 6.3255e-02 9.8114e-02 8.2911e-02 7.2154e-02 1.8274e-01
+ 9.0647e-02 1.4250e-01 9.8115e-02 9.0099e-02 1.0264e-01 6.0942e-02 1.3883e-01 8.8292e-02
+ 6.4212e-02 6.5955e-02 6.3535e-02 6.4967e-02 6.2083e-02 9.4365e-02 7.8103e-02 7.7850e-02
+ 6.2456e-02 8.4507e-02 7.8852e-02 8.3447e-02 5.1047e-02 6.3175e-02 7.5007e-02 8.6820e-02
+ -nan(ind) 4.0295e-02 -nan(ind) -nan(ind) 5.6662e-02 7.3304e-02 6.0690e-02 5.4816e-02
+ 6.0498e-02 7.7324e-02 -nan(ind) 4.6665e-02 6.8582e-02 1.0016e-01 5.9479e-02 6.9451e-02
+ 7.7481e-02 8.2426e-02 5.0419e-02 6.9356e-02 5.1398e-02 6.5010e-02 5.1298e-02 5.2346e-02
+ 5.8026e-02 5.7593e-02 8.2490e-02 7.0852e-02 7.7343e-02 1.1417e-01 6.0881e-02 2.1671e-01
+ 6.8006e-02 9.2379e-02 8.4580e-02 1.0754e-01 8.3595e-02 1.6038e-01 1.0483e-01 3.7765e-01
+ 8.7734e-02 8.4460e-02 8.8517e-02 1.0786e-01 8.0781e-02 1.0527e-01 1.0780e-01 1.5358e-01
+ 1.2938e-01 1.1936e-01 1.1857e-01 1.6492e-01 1.3560e-01 1.3222e-01 1.0152e-01 3.5878e-01
+ 1.1736e-01 1.2508e-01 1.2123e-01 1.3239e-01 1.2396e-01 9.2881e-02 1.0434e-01 1.3427e-01
+ 8.7257e-02 7.5897e-02 1.2979e-01 9.3548e-02 1.6464e-01 9.0922e-02 1.0062e-01 8.6227e-02
+ 2.0482e-01 7.3072e-02 8.2825e-02 8.4445e-02 1.4127e-01 9.9230e-02 1.3259e-01 5.9317e-02
+ 5.9880e-02 1.9128e-01 1.1621e-01 6.3068e-02 6.0199e-02 4.6115e-02 6.9915e-02 5.3359e-02
+ 6.4837e-02 5.0159e-02 6.7212e-02 7.5552e-02 7.0017e-02 5.3572e-02 -nan(ind) 9.0242e-02
+ 4.1996e-02 -nan(ind) 9.8011e-02 5.6889e-02 9.1862e-02 8.5612e-02 6.1309e-02 -nan(ind)
+ 5.5085e-02 4.8141e-02 5.5337e-02 8.5740e-02 5.5312e-02 5.2575e-02 6.9259e-02 6.7232e-02
+ 5.6264e-02 5.1831e-02 4.2219e-02 5.5324e-02 6.3276e-02 5.4400e-02 8.1356e-02 7.1200e-02
+ 4.7295e-02 6.6134e-02 5.6305e-02 6.9866e-02 7.4997e-02 6.6537e-02 8.7547e-02 9.0745e-02
+ 7.0078e-02 7.0168e-02 1.4440e-01 7.6128e-02 1.1659e-01 8.5543e-02 1.1401e-01 1.0406e-01
+ 1.6146e-01 1.3815e-01 1.4231e-01 1.2684e-01 1.2277e-01 1.1969e-01 8.2127e-02 1.3874e-01
+ 9.5689e-02 1.3100e-01 1.5538e-01 1.5092e-01 1.2196e-01 1.1180e-01 1.3541e-01 7.9097e-02
+ 1.4045e-01 9.2726e-02 9.2031e-02 2.5202e-01 1.0269e-01 9.7185e-02 1.1218e-01 1.1331e-01
+ 1.4465e-01 1.0448e-01 1.3236e-01 1.0445e-01 1.1536e-01 1.3068e-01 1.2346e-01 9.9942e-02
+ 8.5642e-02 8.9116e-02 1.0489e-01 8.7593e-02 8.7833e-02 8.9124e-02 7.6292e-02 9.1152e-02
+ 1.0511e-01 1.1043e-01 6.0978e-02 1.0080e-01 1.0732e-01 5.6356e-02 6.4247e-02 6.0725e-02
+ 7.6687e-02 6.7979e-02 5.3280e-02 5.8523e-02 5.4047e-02 6.4499e-02 6.0087e-02 6.3804e-02
+ 5.3055e-02 5.5476e-02 4.7146e-02 9.5837e-02 6.2721e-02 7.0659e-02 7.4983e-02 9.3151e-02
+ 6.1093e-02 5.8935e-02 7.7223e-02 5.6760e-02 5.7261e-02 8.2120e-02 1.0705e-01 5.8328e-02
+ 4.7528e-02 7.2723e-02 9.3321e-02 -nan(ind) 5.3504e-02 -nan(ind) 7.6993e-02 5.3250e-02
+ 6.1324e-02 -nan(ind) 6.1736e-02 5.6810e-02 5.1699e-02 8.0453e-02 6.4196e-02 5.8369e-02
+ 7.4150e-02 6.2510e-02 6.1481e-02 6.4178e-02 6.6390e-02 1.3195e-01 7.8565e-02 1.1385e-01
+ 1.1176e-01 1.4574e-01 7.3273e-02 1.5918e-01 1.2014e-01 1.0470e-01 1.2782e-01 1.2091e-01
+ 1.0781e-01 8.9107e-02 7.3726e-02 8.5851e-02 1.0542e-01 2.0817e-01 8.4616e-02 9.1074e-02
+ 9.6674e-02 1.0673e-01 8.2506e-02 1.2480e-01 1.1700e-01 8.9190e-02 6.5780e-02 2.2563e-01
+ 9.3556e-02 1.2142e-01 8.3291e-02 9.9000e-02 1.2506e-01 1.0932e-01 1.1711e-01 7.4263e-02
+ 9.1433e-02 9.3798e-02 1.3129e-01 9.3351e-02 1.0308e-01 1.2423e-01 8.3307e-02 6.8406e-02
+ 1.5095e-01 7.8818e-02 1.0675e-01 1.1371e-01 1.1949e-01 7.2120e-02 1.7790e-01 1.2108e-01
+ 5.8409e-02 6.4170e-02 6.1945e-02 1.4855e-01 6.7627e-02 6.3571e-02 6.0949e-02 7.0407e-02
+ 5.4584e-02 5.8721e-02 -nan(ind) 4.3467e-02 6.7115e-02 9.7018e-02 9.5554e-02 5.1105e-02
+ -nan(ind) 7.9130e-02 7.4948e-02 6.2019e-02 5.3000e-02 7.3606e-02 4.1268e-02 -nan(ind)
+ 5.2182e-02 1.0536e-01 6.2834e-02 -nan(ind) 6.1860e-02 7.6418e-02 7.9595e-02 6.1415e-02
+ 7.4338e-02 6.2280e-02 5.0181e-02 4.9891e-02 1.0448e-01 4.4527e-02 5.4251e-02 7.1565e-02
+ 5.9258e-02 5.1735e-02 7.3391e-02 4.2462e-02 4.7085e-02 6.2060e-02 1.0701e-01 9.1389e-02
+ 6.2010e-02 1.1887e-01 8.6869e-02 1.1316e-01 6.0012e-02 9.4219e-02 1.2309e-01 7.4983e-02
+ 1.3395e-01 1.2573e-01 1.2914e-01 1.5284e-01 1.0264e-01 1.2181e-01 1.0003e-01 9.5317e-02
+ 1.3399e-01 7.2566e-02 1.4299e-01 9.5891e-02 1.3900e-01 9.1133e-02 1.8451e-01 6.7199e-02
+ 1.3806e-01 1.0049e-01 8.1466e-02 1.5778e-01 8.4326e-02 1.2757e-01 7.5441e-02 1.4129e-01
+ 1.1209e-01 1.0365e-01 1.2628e-01 1.0756e-01 9.0540e-02 1.1857e-01 1.2218e-01 7.7955e-02
+ 1.3161e-01 1.7393e-01 9.3306e-02 1.2882e-01 7.4786e-02 1.0256e-01 1.2170e-01 7.7904e-02
+ 1.1030e-01 8.7881e-02 1.1463e-01 6.4624e-02 8.6580e-02 8.5514e-02 8.4431e-02 4.3256e-02
+ 5.3980e-02 7.0646e-02 5.8926e-02 5.4259e-02 5.2914e-02 5.5947e-02 5.2234e-02 1.1089e-01
+ 5.6785e-02 5.3005e-02 -nan(ind) 1.7909e-01 6.4655e-02 7.5023e-02 4.9470e-02 9.0927e-02
+ 1.2232e-01 7.0459e-02 1.0764e-01 5.3311e-02 5.8294e-02 6.6084e-02 5.1203e-02 6.0602e-02
+ 5.7471e-02 5.8690e-02 6.8303e-02 6.1766e-02 5.4460e-02 6.5528e-02 8.8226e-02 9.8812e-02
+ 4.2683e-02 9.7297e-02 6.9784e-02 4.8723e-02 1.0121e-01 6.7142e-02 6.5527e-02 1.2472e-01
+ 7.4485e-02 6.6761e-02 5.9773e-02 1.1748e-01 8.9777e-02 4.6966e-02 9.9583e-02 4.5252e-02
+ 9.6696e-02 9.9930e-02 7.6005e-02 9.6146e-02 1.4358e-01 1.4871e-01 9.9992e-02 1.8092e-01
+ 1.2518e-01 1.1431e-01 1.3801e-01 1.1118e-01 1.2137e-01 8.1721e-02 1.3300e-01 1.0616e-01
+ 1.4452e-01 5.5211e-02 1.3605e-01 8.9937e-02 1.9440e-01 8.3554e-02 6.9317e-02 1.2083e-01
+ 7.7085e-02 1.0801e-01 1.0562e-01 1.2735e-01 7.1372e-02 1.2482e-01 1.2036e-01 1.4129e-01
+ 1.2683e-01 1.4122e-01 1.5485e-01 1.4187e-01 1.7328e-01 8.8343e-02 1.1035e-01 8.9937e-02
+ 1.2149e-01 1.1769e-01 8.1517e-02 1.1711e-01 1.2162e-01 9.0686e-02 5.8345e-02 1.2539e-01
+ 9.7414e-02 6.5163e-02 5.8505e-02 8.3116e-02 1.2192e-01 7.4101e-02 6.7022e-02 6.7435e-02
+ 7.5614e-02 1.7926e-01 -nan(ind) 5.9098e-02 1.0920e-01 7.0848e-02 6.1475e-02 5.3235e-02
+ 6.5715e-02 6.9890e-02 5.6633e-02 5.0864e-02 5.8504e-02 6.4593e-02 5.3631e-02 5.9978e-02
+ 5.7977e-02 7.3911e-02 1.1261e-01 6.9817e-02 1.2200e-01 8.1557e-02 1.3522e-01 8.3470e-02
+ 5.4271e-02 5.7955e-02 5.8513e-02 4.1771e-02 1.0825e-01 6.9697e-02 5.9878e-02 6.3366e-02
+ 6.2703e-02 4.5084e-02 4.7627e-02 6.4283e-02 7.9686e-02 5.5186e-02 6.8217e-02 6.1586e-02
+ 8.3742e-02 7.9156e-02 8.5029e-02 9.9193e-02 1.0763e-01 1.0507e-01 1.1319e-01 1.1583e-01
+ 1.3254e-01 1.0967e-01 1.1077e-01 1.8377e-01 2.0272e-01 1.2272e-01 1.3895e-01 9.2892e-02
+ 8.1922e-02 1.2650e-01 1.3444e-01 1.2036e-01 1.2054e-01 8.9985e-02 1.6353e-01 1.3608e-01
+ 1.5856e-01 9.0321e-02 8.7527e-02 1.7488e-01 1.1459e-01 1.7782e-01 1.2708e-01 1.4958e-01
+ 1.2398e-01 9.2707e-02 1.3728e-01 1.3811e-01 1.0324e-01 1.3061e-01 1.2469e-01 1.4193e-01
+ 1.7892e-01 1.2929e-01 1.3052e-01 1.0732e-01 1.3743e-01 1.6368e-01 9.6364e-02 1.1377e-01
+ 8.9242e-02 9.3277e-02 1.2277e-01 9.2832e-02 7.4767e-02 5.8661e-02 7.9209e-02 6.3398e-02
+ 6.9301e-02 5.3768e-02 5.2756e-02 7.0844e-02 5.7458e-02 5.6639e-02 1.3815e-01 7.0174e-02
+ 6.0223e-02 6.4200e-02 5.3950e-02 7.0099e-02 5.4769e-02 1.1102e-01 7.1958e-02 8.8211e-02
+ 1.0052e-01 8.7481e-02 8.4805e-02 6.7774e-02 7.2699e-02 5.2477e-02 4.8564e-02 -nan(ind)
+ 4.2153e-02 1.2037e-01 8.5519e-02 6.6911e-02 6.7322e-02 -nan(ind) 6.3661e-02 7.5686e-02
+ 6.5924e-02 4.8804e-02 1.2773e-01 8.5733e-02 5.9829e-02 5.6959e-02 6.9194e-02 5.4628e-02
+ 5.5018e-02 9.6637e-02 5.9391e-02 1.0262e-01 7.3822e-02 8.7013e-02 1.1014e-01 9.1811e-02
+ 9.1796e-02 1.1978e-01 9.8741e-02 9.4173e-02 1.2954e-01 1.0369e-01 1.3654e-01 1.6507e-01
+ 1.6087e-01 1.0252e-01 1.2410e-01 1.0484e-01 1.0579e-01 1.3645e-01 1.1458e-01 1.3971e-01
+ 1.1620e-01 1.2607e-01 1.2742e-01 1.1065e-01 1.0178e-01 1.2696e-01 1.2307e-01 1.3369e-01
+ 9.7835e-02 1.2570e-01 1.6589e-01 1.1776e-01 1.5255e-01 1.2651e-01 1.0905e-01 1.2438e-01
+ 1.0564e-01 1.3074e-01 9.3394e-02 1.2838e-01 1.5846e-01 1.4306e-01 1.6555e-01 1.3560e-01
+ 8.5514e-02 1.1753e-01 1.2705e-01 1.1826e-01 1.1144e-01 1.1775e-01 1.0487e-01 5.5340e-02
+ 1.9445e-01 8.0952e-02 9.6872e-02 4.6760e-02 5.3900e-02 1.2277e-01 6.0892e-02 5.4629e-02
+ 1.1764e-01 1.0359e-01 9.7212e-02 8.7158e-02 8.2247e-02 5.4326e-02 1.0127e-01 7.0970e-02
+ 6.5347e-02 8.3299e-02 7.1234e-02 5.9380e-02 1.0052e-01 6.4916e-02 5.3642e-02 5.8407e-02
+ 1.1684e-01 5.7310e-02 6.8067e-02 6.0624e-02 5.7435e-02 5.3565e-02 9.5534e-02 4.7369e-02
+ 7.5161e-02 6.0081e-02 1.3850e-01 4.8332e-02 5.9265e-02 7.1479e-02 6.5452e-02 6.0267e-02
+ 6.1881e-02 7.2413e-02 5.5500e-02 8.2716e-02 1.2201e-01 6.0646e-02 8.3514e-02 7.7937e-02
+ 1.7148e-01 6.8284e-02 9.6613e-02 9.8045e-02 1.0519e-01 1.0805e-01 8.0236e-02 9.7851e-02
+ 1.3971e-01 1.2668e-01 1.3518e-01 1.2430e-01 1.1843e-01 1.4446e-01 9.5706e-02 1.3580e-01
+ 1.1951e-01 1.4579e-01 1.2795e-01 1.3927e-01 1.2630e-01 1.5858e-01 1.5928e-01 1.4567e-01
+ 1.3980e-01 1.5862e-01 1.6106e-01 1.4943e-01 1.7524e-01 1.4301e-01 1.7233e-01 1.2634e-01
+ 1.5267e-01 1.0762e-01 1.2388e-01 1.4248e-01 1.4946e-01 1.3831e-01 1.4027e-01 1.5171e-01
+ 1.7288e-01 1.7160e-01 1.8409e-01 1.0135e-01 1.1720e-01 1.2790e-01 1.5332e-01 1.5898e-01
+ 1.0122e-01 6.4220e-02 1.0589e-01 9.6857e-02 9.3170e-02 1.4190e-01 5.7575e-02 1.6217e-01
+ 1.0613e-01 6.7776e-02 1.1069e-01 8.4604e-02 6.0375e-02 5.6447e-02 6.7614e-02 7.1440e-02
+ 5.1570e-02 5.0240e-02 1.1984e-01 6.7216e-02 5.4480e-02 1.0403e-01 6.0290e-02 7.1593e-02
+ 7.5245e-02 4.5819e-02 7.8140e-02 6.2987e-02 5.4320e-02 -nan(ind) 4.6612e-02 7.1411e-02
+ 9.3117e-02 5.4092e-02 6.2924e-02 6.2623e-02 6.5994e-02 6.9045e-02 5.1491e-02 6.5782e-02
+ 5.3922e-02 5.4992e-02 1.7137e-01 5.9277e-02 8.9257e-02 5.3664e-02 7.3757e-02 5.6585e-02
+ 7.6875e-02 8.4020e-02 6.6386e-02 6.9891e-02 7.4492e-02 1.0524e-01 1.1093e-01 1.0529e-01
+ 1.0136e-01 1.4199e-01 1.2140e-01 9.1970e-02 1.6701e-01 1.3454e-01 1.0478e-01 1.1968e-01
+ 1.2531e-01 1.3689e-01 1.1991e-01 1.4349e-01 1.4324e-01 1.4010e-01 1.2025e-01 1.2773e-01
+ 1.1124e-01 1.4618e-01 1.5516e-01 1.4204e-01 1.1951e-01 1.3144e-01 1.4165e-01 1.3100e-01
+ 1.2842e-01 1.3409e-01 1.1473e-01 1.5103e-01 1.4231e-01 1.2207e-01 1.3205e-01 9.8906e-02
+ 1.5279e-01 1.1642e-01 1.5386e-01 9.8389e-02 1.3664e-01 1.5824e-01 1.1353e-01 1.1260e-01
+ 8.1418e-02 1.2303e-01 1.3187e-01 1.0726e-01 1.0493e-01 1.0231e-01 1.0165e-01 5.7396e-02
+ 6.1438e-02 5.4659e-02 1.9921e-01 7.7017e-02 7.4841e-02 6.7724e-02 6.1820e-02 4.9629e-02
+ 6.0295e-02 7.4087e-02 6.5599e-02 5.8088e-02 7.3750e-02 6.0859e-02 7.9176e-02 7.9951e-02
+ 6.5106e-02 6.4134e-02 4.8433e-02 7.7254e-02 7.8170e-02 5.0188e-02 -nan(ind) 5.0453e-02
+ -nan(ind) 5.8174e-02 8.8549e-02 4.5251e-02 -nan(ind) 5.5503e-02 5.3989e-02 1.0302e-01
+ 5.5096e-02 5.5586e-02 8.6611e-02 4.3855e-02 7.1536e-02 4.8210e-02 7.3331e-02 8.7996e-02
+ 6.0038e-02 7.7688e-02 5.6969e-02 5.8642e-02 1.6593e-01 6.4920e-02 7.5218e-02 7.3219e-02
+ 6.5198e-02 5.4168e-02 1.1689e-01 1.3565e-01 8.5863e-02 9.9087e-02 1.3234e-01 1.4976e-01
+ 1.2176e-01 1.4219e-01 9.2850e-02 1.0919e-01 1.2886e-01 1.1407e-01 9.3063e-02 1.1425e-01
+ 9.7861e-02 1.2879e-01 1.1079e-01 9.7228e-02 1.2200e-01 1.2826e-01 1.3796e-01 1.4369e-01
+ 1.4833e-01 1.2222e-01 1.2719e-01 1.3821e-01 1.1572e-01 1.0873e-01 1.3517e-01 1.2741e-01
+ 1.1257e-01 9.1396e-02 1.0016e-01 1.1942e-01 1.3322e-01 8.9819e-02 1.1719e-01 8.6541e-02
+ 1.3275e-01 1.0651e-01 1.2944e-01 1.1738e-01 9.7648e-02 1.2812e-01 1.4657e-01 1.1313e-01
+ 8.8720e-02 8.2653e-02 7.0999e-02 1.9110e-01 7.3764e-02 8.4198e-02 7.8140e-02 8.5874e-02
+ 6.1797e-02 7.8901e-02 8.7290e-02 6.6923e-02 6.2640e-02 1.2475e-01 7.4353e-02 8.5183e-02
+ 5.5865e-02 7.4383e-02 9.0767e-02 4.9620e-02 9.0941e-02 1.0185e-01 5.9102e-02 5.4431e-02
+ 1.1275e-01 8.8154e-02 4.9452e-02 1.0764e-01 6.0750e-02 9.8705e-02 4.9670e-02 -nan(ind)
+ 5.9998e-02 8.1359e-02 6.0935e-02 5.8832e-02 5.5754e-02 5.8594e-02 6.8514e-02 6.0991e-02
+ 5.7891e-02 5.9298e-02 7.0763e-02 5.3492e-02 5.6231e-02 5.2644e-02 5.6170e-02 6.3426e-02
+ 6.0049e-02 5.1092e-02 6.2856e-02 1.1197e-01 7.3202e-02 1.0237e-01 7.6475e-02 1.2532e-01
+ 1.0179e-01 1.2539e-01 1.0841e-01 1.1387e-01 1.5113e-01 1.2126e-01 1.0479e-01 1.4642e-01
+ 1.0308e-01 1.1701e-01 9.7055e-02 1.0664e-01 1.0092e-01 1.2160e-01 1.1979e-01 1.1128e-01
+ 1.2361e-01 1.2445e-01 1.2880e-01 1.3083e-01 1.4159e-01 1.2875e-01 1.2427e-01 1.4265e-01
+ 1.2794e-01 1.3526e-01 1.2003e-01 1.2486e-01 1.2934e-01 1.0859e-01 1.0882e-01 1.0733e-01
+ 1.1024e-01 8.9379e-02 1.0534e-01 1.0597e-01 1.2030e-01 1.3177e-01 1.2316e-01 1.6406e-01
+ 1.1143e-01 1.0416e-01 1.1226e-01 1.1005e-01 1.1228e-01 9.4838e-02 1.4120e-01 9.4094e-02
+ 8.9979e-02 6.2108e-02 5.3739e-02 6.2674e-02 7.2257e-02 6.2034e-02 5.1198e-02 7.0516e-02
+ 6.0554e-02 6.7805e-02 5.0415e-02 5.4680e-02 7.1334e-02 6.3481e-02 7.4240e-02 6.0643e-02
+ 5.1570e-02 8.0167e-02 9.1532e-02 5.5556e-02 1.0568e-01 5.2927e-02 5.8164e-02 6.1095e-02
+ 5.2652e-02 -nan(ind) 4.7090e-02 8.7037e-02 6.9108e-02 6.8077e-02 1.2280e-01 6.8032e-02
+ 6.1812e-02 9.0273e-02 -nan(ind) 5.7361e-02 6.8276e-02 8.5452e-02 7.8663e-02 6.2550e-02
+ 8.5790e-02 7.0630e-02 6.8862e-02 8.7025e-02 6.4432e-02 8.0747e-02 9.3103e-02 6.3722e-02
+ 7.1797e-02 1.1798e-01 9.7335e-02 1.6010e-01 1.0361e-01 1.0843e-01 1.3085e-01 1.3907e-01
+ 8.0183e-02 1.2261e-01 1.1489e-01 1.1429e-01 1.2330e-01 9.6145e-02 9.2665e-02 9.3719e-02
+ 8.6259e-02 1.0013e-01 1.1152e-01 1.0848e-01 1.3537e-01 1.2075e-01 1.1241e-01 1.1694e-01
+ 1.4849e-01 1.2733e-01 1.3234e-01 1.3849e-01 1.2719e-01 1.2751e-01 1.2650e-01 1.1145e-01
+ 1.1306e-01 1.1810e-01 1.0239e-01 9.9021e-02 1.2226e-01 1.0452e-01 1.0485e-01 1.2663e-01
+ 1.5133e-01 1.0916e-01 8.9372e-02 1.0845e-01 1.0551e-01 1.5132e-01 1.2834e-01 1.2606e-01
+ 1.3495e-01 1.2839e-01 1.3912e-01 7.3519e-02 7.2871e-02 7.9637e-02 8.4960e-02 6.2290e-02
+ 7.4498e-02 1.0512e-01 8.5373e-02 5.2051e-02 9.2287e-02 6.7634e-02 1.1196e-01 6.5016e-02
+ 5.2563e-02 9.3732e-02 1.0031e-01 6.8107e-02 7.2595e-02 7.4531e-02 1.1028e-01 7.8270e-02
+ 8.8447e-02 7.5540e-02 -nan(ind) 5.6458e-02 5.0473e-02 5.6477e-02 6.0993e-02 4.4282e-02
+ 1.0283e-01 5.1172e-02 7.2898e-02 8.2344e-02 8.8294e-02 7.0133e-02 6.0532e-02 5.6096e-02
+ 1.1344e-01 4.4170e-02 6.9380e-02 7.7497e-02 5.7674e-02 5.8768e-02 6.3992e-02 4.4801e-02
+ 8.1766e-02 7.9943e-02 7.3294e-02 6.2610e-02 5.6640e-02 7.1909e-02 6.0381e-02 1.0683e-01
+ 1.1966e-01 1.0335e-01 1.0240e-01 9.4517e-02 1.1516e-01 8.5353e-02 1.0464e-01 1.3726e-01
+ 1.1809e-01 9.9907e-02 9.5921e-02 1.0679e-01 1.0517e-01 1.2127e-01 1.1021e-01 1.0238e-01
+ 1.1261e-01 1.4004e-01 1.3694e-01 1.3208e-01 1.4839e-01 1.4542e-01 1.3224e-01 1.3800e-01
+ 1.2754e-01 1.2313e-01 1.3913e-01 1.2312e-01 1.4302e-01 1.0711e-01 1.0995e-01 1.1229e-01
+ 1.0829e-01 1.1787e-01 1.1052e-01 1.2085e-01 1.2164e-01 1.2969e-01 1.1129e-01 1.2046e-01
+ 1.0666e-01 9.1777e-02 1.1163e-01 1.0913e-01 6.0442e-02 7.2539e-02 8.1083e-02 7.1853e-02
+ 6.1622e-02 7.6849e-02 7.1972e-02 7.3689e-02 5.8533e-02 5.6344e-02 5.6542e-02 5.6460e-02
+ 5.5192e-02 -nan(ind) 4.9320e-02 7.1306e-02 6.4757e-02 5.5833e-02 9.0701e-02 7.3651e-02
+ 5.4477e-02 -nan(ind) 5.8615e-02 4.1481e-02 6.2981e-02 5.4642e-02 7.1367e-02 6.5374e-02
+ 8.7662e-02 6.5741e-02 5.8223e-02 9.7020e-02 8.2262e-02 5.7229e-02 5.5652e-02 -nan(ind)
+ 4.9715e-02 6.5675e-02 1.4251e-01 6.0714e-02 7.1669e-02 7.4907e-02 6.7402e-02 8.8505e-02
+ 7.6562e-02 7.9103e-02 6.6707e-02 6.3146e-02 7.7764e-02 6.1929e-02 6.6532e-02 1.7640e-01
+ 9.4004e-02 1.2554e-01 1.1030e-01 1.3418e-01 1.2461e-01 1.2723e-01 1.4425e-01 1.0922e-01
+ 1.1248e-01 1.2242e-01 1.1513e-01 1.2510e-01 1.2051e-01 1.1054e-01 1.3102e-01 1.0400e-01
+ 9.0959e-02 9.9918e-02 1.0770e-01 1.0640e-01 1.1893e-01 1.3712e-01 1.3905e-01 1.3201e-01
+ 1.3832e-01 1.3176e-01 1.4682e-01 1.3910e-01 1.2769e-01 1.1121e-01 1.0827e-01 1.3375e-01
+ 1.0937e-01 1.1379e-01 1.0303e-01 9.2623e-02 1.1466e-01 1.0333e-01 1.1952e-01 1.1178e-01
+ 9.8556e-02 1.1862e-01 9.3686e-02 1.0291e-01 6.9356e-02 1.3189e-01 1.2481e-01 1.2685e-01
+ 1.4988e-01 1.3535e-01 1.2924e-01 1.2267e-01 2.5295e-01 6.9731e-02 6.6114e-02 4.7380e-02
+ 6.2661e-02 5.7825e-02 8.0947e-02 6.8484e-02 6.8908e-02 5.4304e-02 2.4069e-01 6.4096e-02
+ 4.7163e-02 1.4646e-01 6.5320e-02 5.0099e-02 1.0927e-01 5.8465e-02 5.8674e-02 5.6361e-02
+ -nan(ind) 5.7860e-02 5.8310e-02 1.3694e-01 6.4720e-02 1.0449e-01 4.9219e-02 5.1374e-02
+ 6.7288e-02 9.0320e-02 4.6040e-02 6.1115e-02 7.7676e-02 5.6898e-02 6.4601e-02 6.3065e-02
+ 5.0154e-02 5.4642e-02 5.7129e-02 7.9661e-02 5.5866e-02 6.1424e-02 8.8217e-02 5.7462e-02
+ 5.6902e-02 7.1055e-02 9.7442e-02 5.5531e-02 5.3858e-02 7.7183e-02 1.1332e-01 1.0139e-01
+ 9.1670e-02 9.3591e-02 1.0000e-01 7.4982e-02 1.0928e-01 1.2168e-01 1.0429e-01 1.3953e-01
+ 1.1621e-01 1.0862e-01 1.1371e-01 9.7425e-02 9.3878e-02 9.7974e-02 1.0811e-01 1.0246e-01
+ 1.1477e-01 1.2686e-01 1.3248e-01 1.2853e-01 1.5308e-01 1.3886e-01 1.5484e-01 1.4588e-01
+ 1.4769e-01 1.3363e-01 1.2824e-01 1.2685e-01 1.1647e-01 1.1470e-01 1.1028e-01 1.1021e-01
+ 1.0667e-01 1.1685e-01 1.3480e-01 1.2601e-01 1.2218e-01 1.1832e-01 9.6220e-02 9.6394e-02
+ 8.1691e-02 1.0563e-01 1.2828e-01 1.0144e-01 1.2924e-01 1.0305e-01 7.1571e-02 7.6283e-02
+ 6.4636e-02 7.5801e-02 6.6568e-02 6.5516e-02 5.7620e-02 7.8480e-02 6.7107e-02 5.2866e-02
+ 6.2103e-02 6.6475e-02 6.3293e-02 6.0460e-02 5.0866e-02 6.5822e-02 6.7028e-02 7.0198e-02
+ 7.3523e-02 6.9866e-02 8.4639e-02 5.4933e-02 5.5589e-02 5.3083e-02 9.5303e-02 7.5621e-02
+ 5.2905e-02 -nan(ind) 5.4552e-02 6.2354e-02 7.8754e-02 6.6118e-02 6.5313e-02 7.4171e-02
+ 5.7160e-02 8.9026e-02 7.7241e-02 7.0925e-02 7.1712e-02 6.3281e-02 8.7983e-02 6.3947e-02
+ 7.9870e-02 6.5951e-02 6.7438e-02 1.0843e-01 7.9034e-02 1.1114e-01 1.2258e-01 1.6898e-01
+ 9.8750e-02 1.4829e-01 8.3794e-02 1.4593e-01 1.8330e-01 1.2950e-01 1.4891e-01 1.2736e-01
+ 8.8548e-02 1.2213e-01 1.3888e-01 1.1982e-01 1.2665e-01 1.1170e-01 1.0113e-01 1.0654e-01
+ 1.0374e-01 9.8663e-02 9.9794e-02 1.0943e-01 1.2033e-01 1.3274e-01 1.3219e-01 1.5528e-01
+ 1.5180e-01 1.5565e-01 1.6907e-01 1.5493e-01 1.5155e-01 1.3435e-01 1.2747e-01 1.2377e-01
+ 1.1581e-01 1.0112e-01 1.0641e-01 1.0324e-01 1.0539e-01 1.0633e-01 1.0962e-01 1.3537e-01
+ 1.0687e-01 1.2061e-01 1.2242e-01 1.0183e-01 8.5943e-02 8.6676e-02 1.4711e-01 1.5464e-01
+ 1.3856e-01 9.1378e-02 1.1592e-01 9.4978e-02 1.1786e-01 9.4955e-02 8.4063e-02 1.1272e-01
+ 9.2481e-02 5.6953e-02 7.8136e-02 6.5422e-02 7.5350e-02 9.0750e-02 6.8009e-02 7.0315e-02
+ 6.4342e-02 7.7737e-02 8.9368e-02 6.2779e-02 5.7413e-02 1.7628e-01 6.6762e-02 5.6284e-02
+ -nan(ind) 4.3560e-02 -nan(ind) 4.6976e-02 5.0362e-02 6.3248e-02 6.2216e-02 6.5637e-02
+ 6.7758e-02 6.6076e-02 5.7158e-02 -nan(ind) 5.9652e-02 6.1690e-02 8.9588e-02 5.3373e-02
+ 4.8269e-02 6.7303e-02 6.7785e-02 6.1921e-02 5.6164e-02 5.8015e-02 6.0460e-02 5.7324e-02
+ 6.2722e-02 6.7222e-02 5.7962e-02 6.8697e-02 1.0237e-01 1.1231e-01 9.0483e-02 1.1136e-01
+ 1.1898e-01 9.4027e-02 9.7591e-02 9.7528e-02 1.0223e-01 1.4559e-01 1.1099e-01 1.2059e-01
+ 1.2891e-01 1.1686e-01 1.1228e-01 9.6196e-02 1.1813e-01 1.0429e-01 1.0791e-01 1.1246e-01
+ 1.2515e-01 1.4376e-01 1.6182e-01 1.7194e-01 1.8966e-01 1.9334e-01 2.0036e-01 1.8883e-01
+ 1.6663e-01 1.6071e-01 1.4015e-01 1.3006e-01 1.1300e-01 1.0368e-01 1.0240e-01 1.0071e-01
+ 1.0115e-01 1.1790e-01 1.2265e-01 1.1240e-01 1.0163e-01 1.0413e-01 1.3948e-01 1.2502e-01
+ 9.1012e-02 8.3745e-02 9.5092e-02 9.3611e-02 1.2006e-01 1.0313e-01 9.8182e-02 8.2955e-02
+ 7.3017e-02 7.9262e-02 7.4445e-02 5.3425e-02 5.3064e-02 7.8043e-02 5.3460e-02 6.2701e-02
+ 5.7923e-02 6.8039e-02 6.1904e-02 5.4376e-02 4.5108e-02 8.3592e-02 6.6577e-02 4.7620e-02
+ 5.7345e-02 -nan(ind) 5.6511e-02 6.9355e-02 1.0870e-01 8.6523e-02 5.7010e-02 6.6362e-02
+ 6.0308e-02 5.3243e-02 5.5121e-02 4.9959e-02 7.0411e-02 5.6234e-02 5.3668e-02 4.8913e-02
+ 9.4223e-02 5.7868e-02 9.0008e-02 7.5506e-02 6.9719e-02 7.4907e-02 6.7088e-02 8.9487e-02
+ 6.3333e-02 6.2498e-02 6.4709e-02 7.9172e-02 9.3178e-02 7.3184e-02 7.1369e-02 7.7760e-02
+ 6.0383e-02 7.3866e-02 8.8008e-02 2.0602e-01 1.2802e-01 1.5336e-01 8.4493e-02 1.0125e-01
+ 8.3153e-02 1.1454e-01 1.0811e-01 1.3304e-01 1.1030e-01 1.2712e-01 1.2983e-01 1.2857e-01
+ 1.2249e-01 1.2268e-01 1.1673e-01 1.2876e-01 1.3639e-01 1.6241e-01 1.8527e-01 2.1663e-01
+ 2.4145e-01 2.5307e-01 2.6444e-01 2.4032e-01 2.1041e-01 1.9067e-01 1.6315e-01 1.3964e-01
+ 1.2592e-01 1.2389e-01 1.2334e-01 1.1382e-01 1.1927e-01 1.1215e-01 1.0977e-01 1.3738e-01
+ 1.2540e-01 1.0204e-01 1.0507e-01 7.9960e-02 9.8229e-02 1.2806e-01 1.2383e-01 1.0441e-01
+ 1.0300e-01 1.0421e-01 7.1932e-02 5.9642e-02 8.2975e-02 6.6208e-02 6.1126e-02 7.9712e-02
+ 7.0076e-02 9.2210e-02 7.0581e-02 7.3306e-02 6.1149e-02 1.0501e-01 7.1357e-02 6.5927e-02
+ 7.4315e-02 7.1111e-02 7.3348e-02 5.9651e-02 5.7693e-02 5.7965e-02 3.7972e-02 5.6969e-02
+ 5.3648e-02 4.4711e-02 7.9015e-02 6.2454e-02 6.2536e-02 8.4432e-02 5.6075e-02 1.0071e-01
+ 8.6898e-02 7.3197e-02 6.2907e-02 9.9324e-02 4.9295e-02 6.3378e-02 6.5820e-02 8.6277e-02
+ 6.5445e-02 6.7234e-02 6.2102e-02 7.8315e-02 6.8847e-02 9.1067e-02 1.1445e-01 1.0036e-01
+ 1.0629e-01 1.2557e-01 9.7359e-02 9.4980e-02 1.1938e-01 1.4860e-01 1.0633e-01 1.0276e-01
+ 1.1252e-01 8.2439e-02 7.5041e-02 9.3946e-02 1.2937e-01 1.5389e-01 1.3968e-01 1.0730e-01
+ 1.2296e-01 1.0239e-01 1.2387e-01 1.1943e-01 1.2606e-01 1.1601e-01 1.2536e-01 1.4884e-01
+ 1.6156e-01 2.0515e-01 2.4374e-01 3.0396e-01 3.4313e-01 3.6549e-01 3.7852e-01 3.4347e-01
+ 2.8293e-01 2.4214e-01 1.9229e-01 1.5178e-01 1.4370e-01 1.3483e-01 1.2760e-01 1.3140e-01
+ 1.3966e-01 1.1762e-01 1.1144e-01 1.2379e-01 1.4240e-01 1.1525e-01 1.6353e-01 1.1140e-01
+ 1.0095e-01 9.1626e-02 9.5822e-02 9.4295e-02 1.1567e-01 9.9647e-02 1.2095e-01 1.1388e-01
+ 8.2639e-02 8.0650e-02 1.1416e-01 1.1020e-01 1.1244e-01 1.0030e-01 5.1772e-02 7.8276e-02
+ 8.3646e-02 7.5732e-02 5.6180e-02 6.4671e-02 5.7648e-02 8.7390e-02 4.8451e-02 7.3582e-02
+ 7.1506e-02 1.0985e-01 6.2751e-02 6.2242e-02 1.1634e-01 6.5419e-02 8.1881e-02 6.8249e-02
+ 5.6939e-02 8.2334e-02 5.1855e-02 4.7374e-02 7.1538e-02 5.0432e-02 5.2999e-02 7.7742e-02
+ 3.9237e-02 3.9576e-02 -nan(ind) 5.1831e-02 4.6041e-02 5.4543e-02 4.8460e-02 5.6954e-02
+ 5.0860e-02 5.5233e-02 4.5804e-02 5.2524e-02 5.2831e-02 5.7212e-02 5.6390e-02 5.7888e-02
+ 6.3712e-02 1.1169e-01 1.1729e-01 1.7220e-01 1.6508e-01 1.2802e-01 1.1154e-01 7.6650e-02
+ 8.2383e-02 1.0484e-01 1.4049e-01 1.4389e-01 1.3232e-01 1.1954e-01 1.1357e-01 1.2675e-01
+ 1.2676e-01 1.2429e-01 1.3353e-01 1.5344e-01 1.8701e-01 2.3442e-01 3.0557e-01 4.1667e-01
+ 5.3642e-01 6.0735e-01 6.2267e-01 5.1198e-01 3.9804e-01 3.0496e-01 2.2915e-01 1.8001e-01
+ 1.5934e-01 1.3785e-01 1.3135e-01 1.2966e-01 1.4743e-01 1.4483e-01 1.2621e-01 1.2515e-01
+ 1.4859e-01 1.0770e-01 9.7658e-02 1.1283e-01 1.2405e-01 1.2890e-01 1.1713e-01 1.5737e-01
+ 1.2043e-01 1.4070e-01 8.3979e-02 8.4501e-02 7.4519e-02 5.5205e-02 5.5618e-02 5.1692e-02
+ 5.9991e-02 4.1950e-02 4.9957e-02 4.9436e-02 4.8202e-02 5.7168e-02 7.3137e-02 6.1462e-02
+ 5.2624e-02 1.1083e-01 8.4107e-02 4.5773e-02 5.0478e-02 1.0655e-01 5.1936e-02 5.2372e-02
+ 8.6177e-02 5.8703e-02 5.2984e-02 8.3566e-02 6.8320e-02 1.5295e-01 1.0932e-01 5.4829e-02
+ 7.0152e-02 9.5818e-02 7.8090e-02 9.1718e-02 9.9054e-02 9.0319e-02 7.5914e-02 7.3442e-02
+ 1.1267e-01 6.2633e-02 5.8315e-02 6.5788e-02 7.2549e-02 7.1889e-02 6.7594e-02 7.2368e-02
+ 7.8102e-02 8.2422e-02 7.9718e-02 8.5915e-02 8.3469e-02 7.1746e-02 8.8168e-02 1.0046e-01
+ 9.8506e-02 8.1946e-02 8.2974e-02 7.7471e-02 1.0194e-01 1.2333e-01 1.5159e-01 1.3685e-01
+ 1.3444e-01 1.2813e-01 1.1924e-01 1.1195e-01 1.3524e-01 1.3865e-01 1.5132e-01 1.7014e-01
+ 2.1869e-01 3.0253e-01 4.0420e-01 6.3995e-01 9.9783e-01 1.3222e+00 1.3238e+00 9.3396e-01
+ 5.9580e-01 4.0303e-01 2.7648e-01 2.0050e-01 1.7760e-01 1.4007e-01 1.3451e-01 1.4181e-01
+ 1.4542e-01 1.2281e-01 1.3583e-01 1.1861e-01 1.6603e-01 1.4447e-01 1.1535e-01 9.2228e-02
+ 9.2788e-02 1.0903e-01 8.6527e-02 1.0194e-01 1.1241e-01 8.4445e-02 6.0725e-02 9.2656e-02
+ 7.8900e-02 7.0013e-02 7.5235e-02 8.1186e-02 9.4749e-02 8.1340e-02 7.8523e-02 7.3946e-02
+ 7.5339e-02 2.1481e-01 7.0052e-02 7.8512e-02 6.4401e-02 7.6311e-02 9.9677e-02 1.2042e-01
+ 8.7207e-02 1.2639e-01 1.1821e-01 8.9272e-02 1.1145e-01 7.5069e-02 -nan(ind) 6.7867e-02
+ -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind)
+ -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind) 1.9739e-01 1.9977e-01
+ -nan(ind) 1.3349e-01 5.3112e-02 6.5805e-02 1.7705e-01 1.0431e-01 1.1411e-01 1.5615e-01
+ 2.7377e-01 1.5436e-01 1.0708e-01 2.1912e-01 1.4287e-01 1.6326e-01 9.4392e-02 1.3716e-01
+ 1.3038e-01 1.1255e-01 9.9820e-02 1.4509e-01 1.4549e-01 1.0841e-01 1.2014e-01 1.3199e-01
+ 1.3044e-01 1.4953e-01 1.5263e-01 1.8867e-01 2.3512e-01 3.4410e-01 5.2832e-01 9.7232e-01
+ 2.0767e+00 3.9633e+00 3.9492e+00 1.9107e+00 8.8655e-01 5.0495e-01 3.1854e-01 2.2050e-01
+ 1.7891e-01 1.6296e-01 1.4505e-01 1.4110e-01 1.4148e-01 1.2692e-01 1.3628e-01 1.1845e-01
+ 1.2873e-01 1.0514e-01 1.0942e-01 1.2674e-01 1.7247e-01 1.4029e-01 1.0497e-01 1.2647e-01
+ 1.7367e-01 1.3342e-01 1.6666e-01 2.4400e-01 1.2374e-01 1.9535e-01 1.1631e-01 1.6618e-01
+ 1.6284e-01 2.1260e-01 9.8624e-02 9.4669e-02 -nan(ind) 1.1607e-01 -nan(ind) -nan(ind)
+ -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind)
+ -nan(ind) -nan(ind) -nan(ind) -nan(ind) 3.3326e-02 4.7274e-02 3.3841e-02 3.5042e-02
+ 4.2255e-02 3.4207e-02 4.0271e-02 4.6298e-02 3.7030e-02 4.2853e-02 5.0730e-02 3.6829e-02
+ 2.8793e-02 3.6631e-02 3.3391e-02 4.6687e-02 3.7720e-02 4.2056e-02 3.6036e-02 4.1470e-02
+ 4.2997e-02 4.0789e-02 5.5754e-02 5.5285e-02 4.9514e-02 6.6154e-02 7.8080e-02 1.0411e-01
+ 1.1178e-01 8.2056e-02 7.6398e-02 8.9178e-02 8.3895e-02 9.2356e-02 1.1916e-01 1.3567e-01
+ 1.2804e-01 1.1684e-01 1.2614e-01 1.3052e-01 1.3539e-01 1.4474e-01 1.6275e-01 1.7879e-01
+ 2.4922e-01 3.6351e-01 5.9560e-01 1.2542e+00 3.7871e+00 1.6338e+01 1.5494e+01 3.5157e+00
+ 1.1525e+00 5.5936e-01 3.3968e-01 2.3642e-01 1.8510e-01 1.6359e-01 1.3304e-01 1.3720e-01
+ 1.3939e-01 1.4571e-01 1.3102e-01 1.0914e-01 1.4194e-01 8.9909e-02 9.8336e-02 8.6187e-02
+ 6.9711e-02 7.1500e-02 6.1552e-02 7.2965e-02 9.2324e-02 7.7927e-02 5.9576e-02 5.9312e-02
+ 5.0925e-02 4.8641e-02 4.9646e-02 4.4050e-02 4.5817e-02 4.1411e-02 3.6068e-02 3.9761e-02
+ 3.9057e-02 4.9669e-02 4.2388e-02 3.9317e-02 3.4990e-02 5.0951e-02 3.6210e-02 4.0914e-02
+ 3.6587e-02 5.4542e-02 3.6191e-02 3.5864e-02 4.8056e-02 3.4005e-02 4.9196e-02 3.2523e-02
+ -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind)
+ -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind)
+ -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind) 8.7077e-01
+ 1.0000e+06 1.5911e-01 5.7111e-01 2.0953e-01 2.9162e-01 2.7839e-01 2.2090e-01 1.3211e-01
+ 1.4537e-01 1.3825e-01 1.1688e-01 1.3360e-01 1.2329e-01 1.2805e-01 1.2197e-01 1.3157e-01
+ 1.5634e-01 1.4901e-01 1.5756e-01 1.8909e-01 2.5500e-01 3.7450e-01 6.0064e-01 1.1810e+00
+ 3.3966e+00 1.3054e+01 1.3717e+01 3.3876e+00 1.1629e+00 5.9549e-01 3.5815e-01 2.4216e-01
+ 2.0470e-01 1.7014e-01 1.6542e-01 1.4850e-01 1.4170e-01 1.2852e-01 1.3411e-01 1.3455e-01
+ 1.3630e-01 1.5599e-01 1.7554e-01 1.9804e-01 1.6056e-01 1.7228e-01 2.7504e-01 4.5524e-01
+ 4.2727e-01 4.6796e-01 5.0035e-01 1.9865e+00 1.0000e+06 -nan(ind) -nan(ind) -nan(ind)
+ -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind)
+ -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind)
+ -nan(ind) -nan(ind) -nan(ind) -nan(ind) -nan(ind) 1.2280e-01 -nan(ind) -nan(ind)
+ 1.3270e-01 -nan(ind) 1.6766e-01 -nan(ind) 9.9917e-02 9.9388e-02 1.5455e-01 1.4545e-01
+ 1.6779e-01 7.9072e-02 9.3197e-02 7.8853e-02 7.2951e-02 7.9781e-02 8.2712e-02 7.9423e-02
+ 9.0295e-02 6.4771e-02 9.2166e-02 8.6882e-02 1.0123e-01 8.7813e-02 8.8442e-02 9.2102e-02
+ 9.6316e-02 8.9564e-02 6.2244e-02 9.1460e-02 7.8320e-02 9.3571e-02 1.3142e-01 1.3791e-01
+ 1.4018e-01 1.3338e-01 1.4100e-01 1.3806e-01 1.3166e-01 1.4929e-01 1.4672e-01 1.7405e-01
+ 2.2666e-01 3.1536e-01 4.9559e-01 9.6615e-01 1.8200e+00 3.3675e+00 3.3318e+00 1.7267e+00
+ 8.4390e-01 4.8718e-01 3.0844e-01 2.2422e-01 1.8200e-01 1.6613e-01 1.5115e-01 1.5110e-01
+ 1.4409e-01 1.2932e-01 1.1453e-01 1.0881e-01 1.5455e-01 1.2325e-01 9.9483e-02 8.6189e-02
+ 7.2225e-02 8.2530e-02 6.1718e-02 8.8918e-02 1.3115e-01 9.4763e-02 1.1140e-01 9.4047e-02
+ 7.7092e-02 8.9045e-02 7.1503e-02 7.6214e-02 8.9800e-02 8.0284e-02 7.5234e-02 7.8461e-02
+ 8.8514e-02 1.0235e-01 7.0864e-02 1.3917e-01 1.0843e-01 9.5305e-02 1.8391e-01 8.3310e-02
+ -nan(ind) 9.2911e-02 -nan(ind) 1.5262e-01 -nan(ind) 9.8604e-02 -nan(ind) -nan(ind)
+ 3.9619e-02 7.4840e-02 4.6122e-02 4.4027e-02 5.7508e-02 4.3590e-02 5.3607e-02 5.3168e-02
+ 3.6803e-02 4.3304e-02 7.5642e-02 4.5227e-02 4.4089e-02 4.8816e-02 4.9977e-02 4.7806e-02
+ 4.2608e-02 4.6177e-02 4.7155e-02 4.8607e-02 5.8999e-02 6.0970e-02 6.5860e-02 5.9380e-02
+ 5.4642e-02 7.9001e-02 9.8692e-02 4.5804e-01 2.1028e-01 1.8114e-01 1.7207e-01 1.4567e-01
+ 1.3947e-01 1.3042e-01 1.1636e-01 1.3541e-01 1.3556e-01 1.0251e-01 1.3559e-01 1.3653e-01
+ 1.2748e-01 1.3130e-01 1.4436e-01 1.6011e-01 2.0809e-01 3.2694e-01 4.1054e-01 5.8269e-01
+ 8.7274e-01 1.1352e+00 1.1409e+00 8.4445e-01 5.6225e-01 3.9487e-01 2.6802e-01 1.9803e-01
+ 1.7230e-01 1.5213e-01 1.3144e-01 1.4712e-01 1.3711e-01 1.2869e-01 1.3120e-01 1.1744e-01
+ 1.4138e-01 1.5320e-01 1.1210e-01 1.4099e-01 1.3526e-01 2.4098e-01 1.8196e-01 2.2004e-01
+ 2.6451e-01 1.5053e-01 6.8005e-02 8.3374e-02 6.3556e-02 6.4168e-02 5.3509e-02 5.4174e-02
+ 5.5635e-02 3.8581e-02 4.3902e-02 4.3407e-02 4.7353e-02 7.0280e-02 5.0321e-02 5.0571e-02
+ 4.5151e-02 5.8389e-02 5.0316e-02 5.1780e-02 4.3082e-02 1.0823e-01 4.4783e-02 5.0290e-02
+ 5.4350e-02 4.4994e-02 3.9554e-02 5.8287e-02 6.0471e-02 8.7786e-02 6.2718e-02 5.4956e-02
+ 9.1338e-02 5.1957e-02 7.2014e-02 5.7774e-02 9.2317e-02 5.1460e-02 8.8135e-02 6.5918e-02
+ 4.7596e-02 5.3806e-02 6.7297e-02 7.8892e-02 8.8959e-02 6.9726e-02 1.0906e-01 1.2121e-01
+ 8.2816e-02 9.3482e-02 8.1945e-02 7.2679e-02 7.5296e-02 9.5442e-02 1.0094e-01 8.9997e-02
+ 9.4684e-02 8.6052e-02 7.5010e-02 9.5953e-02 6.7684e-02 1.1262e-01 1.4184e-01 1.4385e-01
+ 1.2364e-01 1.3667e-01 1.2901e-01 1.2391e-01 1.2636e-01 1.3983e-01 1.4195e-01 1.9994e-01
+ 2.1187e-01 2.4063e-01 3.0014e-01 3.9165e-01 4.9343e-01 5.6399e-01 5.7352e-01 4.8972e-01
+ 3.8803e-01 3.0872e-01 2.3621e-01 1.8551e-01 1.6146e-01 1.5349e-01 1.2972e-01 1.2087e-01
+ 1.1574e-01 1.2652e-01 1.1329e-01 1.5028e-01 1.3380e-01 1.0520e-01 1.1966e-01 9.4836e-02
+ 7.5495e-02 6.3442e-02 8.3340e-02 9.1605e-02 1.2332e-01 7.8069e-02 8.1600e-02 9.4938e-02
+ 8.5244e-02 9.3090e-02 8.1861e-02 9.2109e-02 9.3738e-02 9.3638e-02 1.1300e-01 7.6601e-02
+ 8.4731e-02 6.7326e-02 4.7473e-02 6.5749e-02 5.1588e-02 1.4794e-01 5.3030e-02 5.9376e-02
+ 6.1938e-02 5.6790e-02 5.8957e-02 5.7041e-02 9.7873e-02 7.2189e-02 1.2364e-01 5.7193e-02
+ 4.9152e-02 5.2512e-02 1.0317e-01 5.4503e-02 1.0472e-01 1.1567e-01 6.9122e-02 9.3710e-02
+ 8.6206e-02 8.3186e-02 7.9536e-02 6.4970e-02 6.2017e-02 7.1815e-02 7.2268e-02 1.0716e-02
+ 6.5685e-02 6.3615e-02 6.6911e-02 6.8348e-02 8.8099e-02 4.9869e-02 7.1788e-02 1.0603e-01
+ 6.1676e-02 9.5048e-02 8.6580e-02 2.3340e-01 1.7989e-01 1.4403e-01 1.3442e-01 1.1102e-01
+ 1.2297e-01 1.0961e-01 1.1626e-01 1.2184e-01 9.8636e-02 1.1904e-01 9.1241e-02 1.2285e-01
+ 1.0524e-01 1.5412e-01 1.3685e-01 1.3934e-01 1.6291e-01 1.8917e-01 2.1780e-01 2.6880e-01
+ 3.2147e-01 3.3876e-01 3.5826e-01 3.1851e-01 2.5988e-01 2.3244e-01 1.8058e-01 1.5361e-01
+ 1.4516e-01 1.3101e-01 1.2085e-01 1.1600e-01 1.3080e-01 1.2780e-01 1.0407e-01 1.0149e-01
+ 1.2285e-01 1.1244e-01 9.6884e-02 1.2437e-01 1.3039e-01 1.6492e-01 1.3655e-01 1.5568e-01
+ 2.4517e-01 8.5180e-02 6.3609e-02 7.3208e-02 8.6043e-02 5.3845e-02 6.0609e-02 6.0190e-02
+ 6.7063e-02 1.0186e-01 7.7158e-02 6.6660e-02 8.2107e-02 2.0309e-01 5.6539e-02 8.9622e-02
+ 5.9817e-02 6.7590e-02 1.2904e-01 7.9834e-02 7.9281e-02 8.7562e-02 9.9055e-02 7.7551e-02
+ 5.0875e-02 6.2815e-02 1.1555e-01 6.1114e-02 6.1858e-02 1.0094e-01 6.7996e-02 5.9569e-02
+ 5.3042e-02 6.9155e-02 6.1224e-02 9.5411e-02 6.0489e-02 5.3411e-02 1.8569e-01 6.1622e-02
+ 4.7947e-02 6.3244e-02 6.9609e-02 5.2245e-02 5.4007e-02 5.2205e-02 6.3053e-02 5.6249e-02
+ 5.1814e-02 6.7892e-02 7.4658e-02 7.2246e-02 1.0275e-01 1.1678e-01 1.0206e-01 1.1654e-01
+ 1.1798e-01 1.0782e-01 9.6557e-02 9.8035e-02 9.5723e-02 1.4599e-01 1.0591e-01 1.2287e-01
+ 1.2566e-01 1.1335e-01 1.1405e-01 1.2312e-01 1.0986e-01 1.1689e-01 1.1114e-01 1.1917e-01
+ 1.3709e-01 1.6030e-01 1.8273e-01 2.1019e-01 2.2523e-01 2.3164e-01 2.4972e-01 2.2932e-01
+ 2.1181e-01 1.9005e-01 1.5712e-01 1.3753e-01 1.2903e-01 1.2759e-01 1.2105e-01 1.1806e-01
+ 1.3021e-01 1.1687e-01 1.2860e-01 1.3006e-01 1.4025e-01 1.3600e-01 1.3497e-01 9.2785e-02
+ 8.0769e-02 9.2842e-02 1.1075e-01 1.1265e-01 9.9740e-02 1.1628e-01 1.4185e-01 1.2213e-01
+ 6.0035e-02 5.9458e-02 6.0312e-02 5.2872e-02 4.8865e-02 5.6710e-02 5.3189e-02 4.6225e-02
+ 4.8200e-02 4.3621e-02 6.2725e-02 6.2745e-02 5.8582e-02 8.3728e-02 6.1688e-02 6.5835e-02
+ 4.8102e-02 -nan(ind) 5.9497e-02 5.9134e-02 8.3305e-02 6.0171e-02 5.6578e-02 1.1081e-01
+ 5.3802e-02 -nan(ind) 5.0860e-02 7.0142e-02 8.7873e-02 6.5680e-02 6.5857e-02 4.9665e-02
+ 5.5186e-02 -nan(ind) 7.8163e-02 7.6042e-02 8.7921e-02 9.1581e-02 5.4797e-02 8.5532e-02
+ 7.7420e-02 1.0015e-01 6.7439e-02 1.0949e-01 1.0909e-01 7.1300e-02 1.0734e-01 1.1620e-01
+ 9.1843e-02 6.8892e-02 7.7955e-02 1.0248e-01 1.6208e-01 1.0935e-01 1.5496e-01 1.1648e-01
+ 7.7911e-02 1.0816e-01 1.2753e-01 1.1682e-01 1.1578e-01 1.1695e-01 1.5306e-01 1.2457e-01
+ 1.0817e-01 1.0971e-01 1.0779e-01 1.1361e-01 1.2756e-01 1.4951e-01 1.5301e-01 1.7304e-01
+ 1.9124e-01 1.9460e-01 1.8201e-01 1.8818e-01 1.7888e-01 1.6252e-01 1.5307e-01 1.2745e-01
+ 1.1081e-01 1.1444e-01 1.0987e-01 1.1512e-01 1.4598e-01 1.0987e-01 1.0511e-01 1.3443e-01
+ 1.4348e-01 1.2742e-01 1.0793e-01 9.7365e-02 9.8738e-02 1.4282e-01 1.1552e-01 1.8224e-01
+ 1.4623e-01 8.0780e-02 1.0844e-01 6.9603e-02 1.0323e-01 7.2540e-02 1.0789e-01 1.4713e-01
+ 9.7613e-02 6.2542e-02 6.1134e-02 6.2189e-02 6.3243e-02 7.8722e-02 9.1213e-02 4.7537e-02
+ 4.8637e-02 7.0899e-02 6.3350e-02 8.4928e-02 4.7081e-02 8.2003e-02 5.3350e-02 4.8766e-02
+ -nan(ind) 4.3790e-02 -nan(ind) 5.5572e-02 5.6586e-02 6.7559e-02 6.9540e-02 5.8892e-02
+ 6.2372e-02 8.5325e-02 5.8708e-02 7.0350e-02 6.3857e-02 4.9209e-02 5.4952e-02 6.6888e-02
+ 4.6929e-02 5.5257e-02 6.0867e-02 7.5971e-02 6.3594e-02 5.5284e-02 5.1135e-02 6.4559e-02
+ 5.0922e-02 6.9957e-02 7.4457e-02 5.7686e-02 5.1469e-02 8.0136e-02 7.9518e-02 1.1378e-01
+ 1.0794e-01 1.1308e-01 1.3467e-01 9.0432e-02 1.1180e-01 1.0469e-01 1.0640e-01 1.4402e-01
+ 1.0668e-01 1.2272e-01 1.0810e-01 9.0980e-02 1.2276e-01 9.7231e-02 1.0050e-01 1.1199e-01
+ 1.2199e-01 1.3207e-01 1.3766e-01 1.6234e-01 1.6673e-01 1.6518e-01 1.7412e-01 1.6222e-01
+ 1.4630e-01 1.4311e-01 1.2626e-01 1.2613e-01 1.1697e-01 1.1524e-01 9.9200e-02 1.1401e-01
+ 1.2224e-01 1.2448e-01 1.3454e-01 1.0797e-01 1.3237e-01 1.3585e-01 1.1918e-01 1.3572e-01
+ 1.0516e-01 9.9411e-02 1.4005e-01 9.7740e-02 1.3224e-01 9.2528e-02 5.8074e-02 7.1358e-02
+ 6.0741e-02 7.1811e-02 7.0614e-02 6.1881e-02 7.4656e-02 6.3600e-02 6.5233e-02 5.9619e-02
+ 5.6800e-02 1.1298e-01 5.0577e-02 4.2394e-02 5.5673e-02 6.3129e-02 5.0430e-02 7.1288e-02
+ 6.2672e-02 1.0721e-01 6.3410e-02 7.1280e-02 6.4751e-02 9.7650e-02 7.7344e-02 7.5503e-02
+ 6.7209e-02 1.0335e-01 5.3208e-02 4.3751e-02 8.4266e-02 5.0030e-02 7.0785e-02 -nan(ind)
+ 5.2020e-02 8.4863e-02 -nan(ind) 6.0303e-02 8.6950e-02 7.7457e-02 6.8972e-02 6.5981e-02
+ 6.2108e-02 7.0889e-02 6.7398e-02 5.0455e-02 5.4838e-02 7.1643e-02 6.9356e-02 7.3830e-02
+ 2.0190e-01 9.9522e-02 1.2958e-01 8.9488e-02 1.0704e-01 1.2380e-01 1.1561e-01 1.1528e-01
+ 9.7122e-02 1.1955e-01 1.3718e-01 1.5261e-01 1.2317e-01 1.1829e-01 1.0393e-01 9.9729e-02
+ 9.3209e-02 9.4820e-02 9.9339e-02 9.7812e-02 1.1884e-01 1.3177e-01 1.3635e-01 1.3840e-01
+ 1.4237e-01 1.4003e-01 1.5151e-01 1.4573e-01 1.4111e-01 1.4546e-01 1.2315e-01 1.1923e-01
+ 1.0865e-01 9.9907e-02 8.9867e-02 9.8391e-02 1.1942e-01 9.8162e-02 1.1958e-01 1.0271e-01
+ 1.2785e-01 1.1905e-01 9.5527e-02 6.7150e-02 1.0792e-01 1.2604e-01 1.2550e-01 1.4703e-01
+ 8.3499e-02 1.0553e-01 1.0693e-01 1.9696e-01 9.5885e-02 5.9024e-02 6.4873e-02 7.5029e-02
+ 7.0312e-02 7.0938e-02 8.1074e-02 5.9608e-02 8.5542e-02 5.5597e-02 1.4570e-01 7.0809e-02
+ 6.2320e-02 -nan(ind) 8.7531e-02 4.3806e-02 8.7213e-02 1.0510e-01 5.0857e-02 5.3912e-02
+ 5.5771e-02 6.6697e-02 5.9202e-02 6.1241e-02 4.9092e-02 8.0271e-02 7.2966e-02 6.4633e-02
+ 8.0396e-02 7.1047e-02 6.2993e-02 7.0074e-02 6.8342e-02 5.6033e-02 5.1609e-02 6.1524e-02
+ 5.3988e-02 5.2262e-02 5.9454e-02 1.1646e-01 6.2502e-02 5.3726e-02 6.2271e-02 6.8118e-02
+ 6.8765e-02 8.0839e-02 7.8661e-02 6.2845e-02 8.4191e-02 9.3841e-02 6.0401e-02 9.5831e-02
+ 1.1131e-01 9.6605e-02 1.2238e-01 8.6395e-02 1.4580e-01 1.2865e-01 1.0198e-01 1.0260e-01
+ 1.0684e-01 1.0976e-01 8.7289e-02 1.0992e-01 1.1628e-01 1.0705e-01 1.1289e-01 1.0605e-01
+ 1.2414e-01 1.4767e-01 1.1951e-01 1.3715e-01 1.2938e-01 1.3449e-01 1.5447e-01 1.1991e-01
+ 1.4075e-01 1.4573e-01 1.1993e-01 1.2840e-01 1.1004e-01 9.6394e-02 1.1863e-01 9.9232e-02
+ 1.2663e-01 1.1253e-01 1.1149e-01 1.2827e-01 1.4313e-01 9.7182e-02 1.0674e-01 1.3855e-01
+ 8.7091e-02 9.3918e-02 1.1207e-01 1.1556e-01 9.4933e-02 8.1166e-02 6.9243e-02 7.2718e-02
+ 7.3603e-02 8.1692e-02 8.1732e-02 9.8551e-02 5.7378e-02 5.2915e-02 5.5600e-02 5.4185e-02
+ 5.2774e-02 2.3716e-01 5.6120e-02 7.3967e-02 5.6795e-02 4.4868e-02 9.0114e-02 4.9624e-02
+ 4.1520e-02 1.2471e-01 5.7633e-02 5.5441e-02 1.4168e-01 5.3941e-02 8.4635e-02 4.9373e-02
+ 6.2843e-02 9.6030e-02 4.9497e-02 6.2251e-02 7.6358e-02 7.0742e-02 7.4445e-02 6.5308e-02
+ 5.2221e-02 6.9557e-02 -nan(ind) 6.7483e-02 6.0589e-02 6.1736e-02 1.0056e-01 5.3578e-02
+ 8.0578e-02 7.1314e-02 6.6677e-02 6.5494e-02 7.3654e-02 6.8569e-02 7.7281e-02 5.8392e-02
+ 5.7769e-02 1.4824e-01 9.6463e-02 1.4154e-01 1.0885e-01 1.0256e-01 1.2760e-01 1.2620e-01
+ 1.1264e-01 9.7374e-02 1.3365e-01 1.1026e-01 1.2434e-01 1.1314e-01 1.0003e-01 9.2946e-02
+ 1.0313e-01 1.2889e-01 1.1608e-01 1.2875e-01 1.2236e-01 1.3441e-01 1.4512e-01 1.3620e-01
+ 1.3185e-01 1.4155e-01 1.3983e-01 1.2931e-01 1.3606e-01 1.3138e-01 1.3793e-01 1.1270e-01
+ 9.9183e-02 1.1643e-01 1.0444e-01 1.1121e-01 1.2291e-01 9.1401e-02 1.0567e-01 1.0513e-01
+ 1.2906e-01 1.3046e-01 1.0059e-01 1.4007e-01 1.1405e-01 1.3717e-01 1.2694e-01 7.8921e-02
+ 9.4431e-02 1.1554e-01 7.4847e-02 6.8755e-02 6.8292e-02 8.1079e-02 6.2793e-02 5.9911e-02
+ 7.8844e-02 7.6770e-02 5.9989e-02 6.8022e-02 7.8849e-02 7.8858e-02 6.0301e-02 5.2846e-02
+ 7.2819e-02 1.1199e-01 7.2120e-02 6.3092e-02 7.0368e-02 6.6255e-02 7.2102e-02 5.5471e-02
+ 8.9162e-02 5.6788e-02 1.0213e-01 6.5096e-02 8.0300e-02 8.0301e-02 5.4661e-02 -nan(ind)
+ 5.0462e-02 8.0364e-02 5.6424e-02 8.2660e-02 5.4825e-02 6.5398e-02 7.6034e-02 4.9069e-02
+ 5.3014e-02 8.7532e-02 6.7882e-02 8.4481e-02 7.2722e-02 6.8477e-02 7.3144e-02 6.5378e-02
+ 7.0702e-02 6.6185e-02 6.1761e-02 1.2353e-01 8.9574e-02 1.0991e-01 6.3464e-02 7.2673e-02
+ 1.0014e-01 1.2022e-01 1.7463e-01 1.0465e-01 1.2780e-01 1.2911e-01 7.8383e-02 1.1394e-01
+ 1.0334e-01 8.8885e-02 1.0068e-01 9.0915e-02 1.0013e-01 9.2472e-02 1.0229e-01 1.1139e-01
+ 1.3468e-01 1.2473e-01 1.2180e-01 1.2325e-01 1.3959e-01 1.1221e-01 1.2071e-01 1.3330e-01
+ 1.2933e-01 1.2198e-01 1.0951e-01 1.2934e-01 1.0153e-01 1.2711e-01 1.1295e-01 9.9117e-02
+ 1.1780e-01 1.0176e-01 9.4805e-02 1.0924e-01 1.3492e-01 1.0839e-01 1.1040e-01 1.5823e-01
+ 1.0828e-01 1.0902e-01 1.1329e-01 9.0047e-02 1.0865e-01 7.5586e-02 1.1974e-01 9.3420e-02
+ 1.0905e-01 5.5176e-02 7.5161e-02 7.0153e-02 7.3178e-02 5.6287e-02 6.6644e-02 6.3141e-02
+ 6.2907e-02 5.9848e-02 1.8314e-01 5.4121e-02 4.4528e-02 6.9611e-02 8.3838e-02 5.3860e-02
+ 6.1422e-02 1.8029e-01 1.0390e-01 4.7126e-02 9.9138e-02 6.5519e-02 5.9294e-02 7.6530e-02
+ 1.1622e-01 6.3981e-02 6.4923e-02 5.1831e-02 -nan(ind) 5.3477e-02 4.8012e-02 8.9536e-02
+ 5.4122e-02 6.6232e-02 9.7642e-02 6.3545e-02 1.0187e-01 4.9183e-02 9.6250e-02 7.1029e-02
+ 4.5978e-02 7.9439e-02 6.4129e-02 5.1290e-02 8.0088e-02 6.6799e-02 6.8813e-02 6.4500e-02
+ 7.4927e-02 6.6946e-02 7.2885e-02 1.2924e-01 1.6534e-01 1.0158e-01 1.0145e-01 1.4125e-01
+ 1.3202e-01 1.3977e-01 1.3564e-01 1.1309e-01 9.3579e-02 9.6359e-02 1.0265e-01 8.6117e-02
+ 1.1152e-01 1.2051e-01 1.2020e-01 1.1874e-01 1.2218e-01 1.0876e-01 1.2540e-01 1.2637e-01
+ 1.3549e-01 1.2855e-01 1.4243e-01 1.4216e-01 1.2426e-01 1.2443e-01 1.1728e-01 1.3953e-01
+ 1.3040e-01 1.2148e-01 1.0812e-01 1.0489e-01 1.1483e-01 1.1045e-01 1.0658e-01 9.4398e-02
+ 1.0069e-01 1.2544e-01 1.2949e-01 1.8216e-01 1.3818e-01 1.2081e-01 1.0505e-01 1.6025e-01
+ 9.8256e-02 8.8245e-02 9.1609e-02 9.9688e-02 7.5449e-02 9.0887e-02 7.7193e-02 7.6246e-02
+ 5.2061e-02 5.0311e-02 6.3874e-02 5.9887e-02 5.6426e-02 6.5516e-02 6.4297e-02 6.9030e-02
+ 5.4404e-02 6.8931e-02 8.2898e-02 5.5660e-02 6.0943e-02 7.5161e-02 6.2266e-02 4.7612e-02
+ 1.2707e-01 6.5738e-02 5.3499e-02 -nan(ind) 4.8643e-02 -nan(ind) 5.1854e-02 5.1262e-02
+ 7.8977e-02 4.2227e-02 1.4016e-01 6.4947e-02 7.3770e-02 4.7508e-02 6.8561e-02 6.4986e-02
+ 5.8449e-02 6.3907e-02 1.2829e-01 6.9157e-02 9.3125e-02 6.7008e-02 6.4963e-02 8.1473e-02
+ 8.0008e-02 6.5167e-02 8.7939e-02 5.2991e-02 8.0576e-02 9.5599e-02 1.0887e-01 1.5411e-01
+ 9.3653e-02 1.0549e-01 1.5893e-01 1.0205e-01 1.5395e-01 1.6592e-01 1.2103e-01 8.8270e-02
+ 1.0430e-01 1.2042e-01 9.3161e-02 9.7430e-02 1.0837e-01 1.2478e-01 1.3262e-01 1.1627e-01
+ 1.1211e-01 1.1026e-01 1.4437e-01 1.0527e-01 1.4601e-01 1.3369e-01 9.4640e-02 1.5592e-01
+ 1.4592e-01 1.4341e-01 1.4390e-01 1.5909e-01 1.4460e-01 1.0746e-01 1.1044e-01 9.4382e-02
+ 1.0942e-01 1.4619e-01 1.2521e-01 1.1926e-01 1.1527e-01 1.0869e-01 1.1505e-01 1.2563e-01
+ 9.7818e-02 1.1270e-01 1.0772e-01 9.0016e-02 9.4501e-02 9.6014e-02 9.9153e-02 5.6474e-02
+ 6.8355e-02 8.7404e-02 7.4567e-02 5.8657e-02 6.9123e-02 6.7312e-02 7.2779e-02 5.5756e-02
+ 7.2660e-02 7.7223e-02 7.1475e-02 6.3794e-02 7.5031e-02 5.9897e-02 7.7338e-02 8.9540e-02
+ 6.6438e-02 5.7059e-02 7.6688e-02 6.9906e-02 6.8251e-02 5.5477e-02 -nan(ind) 4.4582e-02
+ 6.4420e-02 6.8825e-02 6.3175e-02 1.0500e-01 4.4873e-02 7.0583e-02 8.4016e-02 4.9388e-02
+ 6.9489e-02 4.8949e-02 1.1210e-01 5.2125e-02 7.1124e-02 5.6163e-02 6.2573e-02 6.4392e-02
+ 9.5280e-02 6.6948e-02 6.6172e-02 7.8490e-02 1.9822e-01 4.8795e-02 7.6997e-02 9.0408e-02
+ 1.0816e-01 8.0443e-02 9.6290e-02 1.3836e-01 2.4805e-01 1.0444e-01 8.2938e-02 1.4938e-01
+ 1.7288e-01 1.6682e-01 9.6295e-02 9.1157e-02 7.7665e-02 9.5043e-02 1.2780e-01 9.5074e-02
+ 1.1371e-01 9.3787e-02 1.1223e-01 1.4458e-01 8.5696e-02 9.2401e-02 1.4700e-01 1.4176e-01
+ 1.2476e-01 1.2560e-01 1.0007e-01 1.4709e-01 1.2569e-01 1.4425e-01 1.1033e-01 1.0838e-01
+ 1.3738e-01 1.0339e-01 1.1729e-01 8.8306e-02 1.0059e-01 1.2701e-01 1.0953e-01 1.2526e-01
+ 1.1963e-01 1.2126e-01 1.3780e-01 1.1065e-01 1.2453e-01 8.3877e-02 1.6027e-01 9.7634e-02
+ 1.3043e-01 6.8251e-02 8.3831e-02 7.3945e-02 6.4417e-02 4.3605e-02 5.9628e-02 8.4100e-02
+ 6.2006e-02 5.7553e-02 8.6326e-02 8.5688e-02 6.5154e-02 4.5053e-02 6.3990e-02 4.7457e-02
+ 5.7589e-02 5.6207e-02 1.0687e-01 6.9699e-02 6.6608e-02 8.0446e-02 7.5756e-02 5.3597e-02
+ 8.9337e-02 4.2034e-02 8.3126e-02 4.4498e-02 1.1155e-01 7.5261e-02 5.1869e-02 1.1555e-01
+ 3.8598e-02 1.0126e-01 6.0091e-02 6.3449e-02 4.8140e-02 -nan(ind) 5.4074e-02 7.6533e-02
+ 7.6184e-02 7.0068e-02 -nan(ind) 7.9724e-02 6.3832e-02 6.3949e-02 6.4841e-02 7.2343e-02
+ 5.2399e-02 7.0219e-02 9.0340e-02 1.1356e-01 8.3573e-02 7.2048e-02 1.3839e-01 1.1165e-01
+ 9.8314e-02 1.0856e-01 1.3552e-01 1.2543e-01 1.1431e-01 1.0433e-01 1.2831e-01 1.4447e-01
+ 7.1212e-02 1.4726e-01 9.7063e-02 1.2771e-01 9.3025e-02 9.7953e-02 1.0991e-01 1.0421e-01
+ 9.1594e-02 1.0910e-01 1.2331e-01 1.0170e-01 1.1475e-01 8.1166e-02 8.5222e-02 1.2191e-01
+ 1.0182e-01 1.1637e-01 1.1275e-01 1.3421e-01 1.0950e-01 8.7447e-02 1.0455e-01 8.1143e-02
+ 1.3495e-01 8.4993e-02 9.8643e-02 1.1255e-01 1.6218e-01 1.6145e-01 1.1360e-01 1.1336e-01
+ 1.2206e-01 1.2250e-01 1.2074e-01 1.2124e-01 8.7531e-02 7.3854e-02 7.5331e-02 6.9314e-02
+ 1.0532e-01 7.0970e-02 5.9197e-02 5.7816e-02 5.2501e-02 8.5077e-02 6.3286e-02 5.7504e-02
+ 6.0251e-02 7.3483e-02 8.7308e-02 4.9114e-02 5.8066e-02 6.5025e-02 7.7320e-02 6.0984e-02
+ 6.4405e-02 8.2503e-02 6.8224e-02 5.4195e-02 1.0594e-01 6.9207e-02 5.7262e-02 7.5136e-02
+ 5.7693e-02 9.9452e-02 8.2849e-02 4.7358e-02 6.9583e-02 7.2133e-02 1.1015e-01 7.7675e-02
+ 5.3176e-02 5.4268e-02 7.6085e-02 5.5728e-02 8.1411e-02 6.7581e-02 6.7059e-02 6.6059e-02
+ 6.8554e-02 5.0025e-02 7.5316e-02 5.2903e-02 8.5110e-02 1.2491e-01 5.1623e-02 7.7129e-02
+ 9.4919e-02 1.2399e-01 9.9234e-02 1.5437e-01 9.5402e-02 1.3083e-01 7.8125e-02 1.0859e-01
+ 1.2898e-01 1.2548e-01 1.1400e-01 1.0111e-01 1.1985e-01 9.1281e-02 9.9764e-02 1.2317e-01
+ 1.3716e-01 1.3961e-01 9.9063e-02 1.1769e-01 1.6680e-01 1.2391e-01 1.4435e-01 9.6903e-02
+ 1.2680e-01 9.7920e-02 1.1451e-01 9.6866e-02 1.1722e-01 1.1272e-01 1.0600e-01 1.0745e-01
+ 1.1953e-01 1.2670e-01 1.0695e-01 1.2002e-01 1.0944e-01 1.3744e-01 8.6297e-02 1.5096e-01
+ 1.2906e-01 1.3642e-01 1.5943e-01 1.1926e-01 9.5506e-02 8.3649e-02 9.1775e-02 6.8447e-02
+ 1.0539e-01 1.1323e-01 8.8915e-02 5.9595e-02 6.4961e-02 5.4196e-02 8.9191e-02 7.0434e-02
+ 5.2188e-02 4.9832e-02 5.7092e-02 5.9549e-02 5.7669e-02 5.8096e-02 6.2313e-02 6.4047e-02
+ 7.1242e-02 7.4748e-02 5.8114e-02 5.3714e-02 5.9455e-02 7.1551e-02 6.7162e-02 6.7308e-02
+ 1.0079e-01 8.5009e-02 9.5217e-02 5.3320e-02 9.7443e-02 4.6590e-02 5.4620e-02 7.9567e-02
+ 5.0118e-02 5.5525e-02 7.2237e-02 5.5692e-02 7.2083e-02 6.0300e-02 7.8215e-02 6.2453e-02
+ 5.2419e-02 1.5636e-01 8.7834e-02 5.4349e-02 8.8277e-02 7.8914e-02 6.0208e-02 2.2709e-01
+ 6.1508e-02 5.4816e-02 7.5218e-02 8.2710e-02 1.0154e-01 5.7927e-02 7.9450e-02 8.0154e-02
+ 8.3498e-02 8.5453e-02 1.6952e-01 8.7339e-02 1.0469e-01 1.1108e-01 1.1194e-01 1.3250e-01
+ 1.5100e-01 1.3711e-01 1.1732e-01 9.3187e-02 7.8803e-02 1.1231e-01 9.1191e-02 9.3265e-02
+ 1.0970e-01 9.3050e-02 1.3526e-01 7.1984e-02 1.1805e-01 9.9954e-02 7.5359e-02 1.1376e-01
+ 7.7793e-02 1.4721e-01 8.1601e-02 1.5650e-01 7.2133e-02 1.1271e-01 7.8843e-02 9.2001e-02
+ 1.1096e-01 9.8977e-02 1.2969e-01 1.6089e-01 1.0022e-01 1.1847e-01 1.0931e-01 9.7330e-02
+ 6.7176e-02 1.3564e-01 9.2527e-02 8.7544e-02 9.6139e-02 6.1849e-02 7.6388e-02 1.2852e-01
+ 7.8051e-02 7.5688e-02 6.3542e-02 5.7629e-02 1.0297e-01 6.1177e-02 6.2821e-02 8.1996e-02
+ 5.1548e-02 1.0657e-01 6.6481e-02 5.0465e-02 4.7230e-02 5.2587e-02 1.1510e-01 5.2507e-02
+ 6.1419e-02 4.5433e-02 5.1496e-02 6.0045e-02 1.0218e-01 5.3100e-02 5.0391e-02 6.5131e-02
+ 5.6230e-02 7.6097e-02 5.1178e-02 7.6479e-02 6.0582e-02 9.1026e-02 1.1391e-01 7.1244e-02
+ 9.0268e-02 7.7333e-02 7.9672e-02 7.8245e-02 7.9958e-02 4.3598e-02 7.9018e-02 7.0907e-02
+ 6.1032e-02 8.5283e-02 1.1416e-01 5.6929e-02 7.3792e-02 6.2743e-02 8.9790e-02 8.2084e-02
+ 5.7841e-02 9.1235e-02 1.5078e-01 8.0629e-02 9.0836e-02 1.1927e-01 8.5000e-02 1.1447e-01
+ 1.0079e-01 8.6416e-02 9.7114e-02 1.4477e-01 9.5799e-02 9.2438e-02 1.1341e-01 8.2723e-02
+ 8.6215e-02 1.3341e-01 7.5248e-02 1.0172e-01 8.7947e-02 9.2529e-02 9.4625e-02 8.3967e-02
+ 8.5464e-02 1.1268e-01 6.2202e-02 1.9413e-01 7.8261e-02 7.9136e-02 9.5299e-02 7.0177e-02
+ 1.1116e-01 7.0487e-02 1.3709e-01 9.2978e-02 1.1766e-01 9.2425e-02 1.1878e-01 8.7420e-02
+ 1.3880e-01 1.0045e-01 1.0425e-01 9.9187e-02 1.1199e-01 6.5320e-02 1.1044e-01 9.1632e-02
+ 9.5358e-02 1.5072e-01 6.6964e-02 7.6018e-02 1.4305e-01 7.9152e-02 6.5741e-02 5.6628e-02
+ 5.5567e-02 8.4045e-02 5.4325e-02 5.4533e-02 8.0243e-02 5.6423e-02 5.1148e-02 9.6777e-02
+ 9.1563e-02 5.4287e-02 9.3248e-02 1.4648e-01 5.3809e-02 8.2652e-02 5.3953e-02 8.3307e-02
+ 6.3324e-02 5.4279e-02 7.3829e-02 5.5746e-02 5.7595e-02 5.3916e-02 7.0332e-02 7.0895e-02
+ 6.1467e-02 1.0468e-01 6.7978e-02 1.1675e-01 5.0333e-02 -nan(ind) 4.6894e-02 5.4624e-02
+ 7.7444e-02 1.4212e-01 9.3063e-02 6.1347e-02 7.5008e-02 4.6522e-02 6.9977e-02 6.0864e-02
+ 7.2594e-02 1.2064e-01 5.3976e-02 5.2253e-02 8.3273e-02 1.0551e-01 1.1774e-01 8.6040e-02
+ 1.0126e-01 8.2559e-02 1.2918e-01 1.0050e-01 1.0527e-01 1.0158e-01 1.1611e-01 9.3190e-02
+ 1.2456e-01 1.0747e-01 1.4500e-01 1.1780e-01 1.1584e-01 1.4122e-01 1.3230e-01 1.5819e-01
+ 1.1748e-01 1.1599e-01 1.3937e-01 1.0460e-01 1.4645e-01 7.4115e-02 1.0110e-01 2.3014e-01
+ 9.4705e-02 1.2332e-01 1.0507e-01 1.2131e-01 1.5714e-01 1.1076e-01 1.6349e-01 1.6460e-01
+ 1.4094e-01 1.1968e-01 1.2061e-01 9.4484e-02 1.2392e-01 1.3968e-01 1.0585e-01 8.5994e-02
+ 1.0155e-01 1.2395e-01 1.0156e-01 8.2213e-02 9.4007e-02 6.3904e-02 7.5940e-02 5.6924e-02
+ 5.6886e-02 5.4767e-02 8.4238e-02 8.6505e-02 7.9160e-02 4.5157e-02 6.4046e-02 8.0030e-02
+ 6.5952e-02 5.9586e-02 1.5188e-01 6.4141e-02 5.5207e-02 5.4292e-02 1.6246e-01 4.6289e-02
+ 5.9000e-02 7.6285e-02 6.4114e-02 6.8934e-02 6.8987e-02 5.7251e-02 6.9509e-02 1.1433e-01
+ 5.0442e-02 7.5632e-02 5.5289e-02 -nan(ind) 9.9884e-02 4.6389e-02 1.3427e-01 5.5970e-02
+ 7.8683e-02 4.6665e-02 1.6046e-01 8.9573e-02 5.8294e-02 7.3037e-02 1.2388e-01 7.0519e-02
+ 7.0633e-02 6.2442e-02 5.0754e-02 1.3939e-01 1.1700e-01 7.4669e-02 1.2552e-01 9.8522e-02
+ 1.2573e-01 1.6383e-01 9.5226e-02 1.1350e-01 9.5741e-02 1.0868e-01 6.9549e-02 6.7947e-02
+ 1.2535e-01 9.8332e-02 9.9655e-02 1.3441e-01 1.0118e-01 1.2192e-01 8.4142e-02 1.2795e-01
+ 1.1750e-01 9.3040e-02 9.9170e-02 1.2861e-01 1.4110e-01 1.0398e-01 1.1406e-01 9.6217e-02
+ 1.1613e-01 1.3339e-01 1.0150e-01 3.1242e-01 1.0603e-01 1.3852e-01 1.2305e-01 1.2278e-01
+ 1.1711e-01 1.3387e-01 1.3390e-01 1.1502e-01 1.3396e-01 8.8888e-02 1.1957e-01 9.5389e-02
+ 1.3241e-01 9.7922e-02 1.0540e-01 1.1961e-01 1.1505e-01 7.6636e-02 1.1351e-01 9.6211e-02
+ 1.2510e-01 8.8465e-02 6.5565e-02 1.6537e-01 8.9092e-02 7.4046e-02 5.2958e-02 6.0402e-02
+ 9.9397e-02 7.3578e-02 5.4090e-02 5.2190e-02 4.7680e-02 5.2721e-02 7.0421e-02 5.2541e-02
+ 4.7140e-02 1.0982e-01 5.9083e-02 7.2244e-02 9.7493e-02 9.2818e-02 5.6316e-02 6.0620e-02
+ 9.1030e-02 9.5031e-02 8.0329e-02 7.0548e-02 5.9271e-02 7.9442e-02 7.3923e-02 7.3651e-02
+ 5.5695e-02 1.4407e-01 8.3762e-02 4.4373e-02 7.4437e-02 1.3400e-01 8.3635e-02 7.9644e-02
+ 1.2474e-01 8.2548e-02 5.5638e-02 9.2188e-02 5.2121e-02 6.6884e-02 1.0907e-01 7.0528e-02
+ 5.7173e-02 1.0478e-01 8.5931e-02 9.7398e-02 8.2860e-02 8.2689e-02 9.0351e-02 1.0477e-01
+ 8.6277e-02 8.4500e-02 1.0442e-01 9.5673e-02 1.1361e-01 1.2873e-01 8.7030e-02 1.2499e-01
+ 6.6657e-02 1.0328e-01 1.0416e-01 1.3109e-01 1.5844e-01 8.9951e-02 1.7099e-01 1.1235e-01
+ 1.3106e-01 1.4475e-01 1.0956e-01 1.2321e-01 9.3766e-02 1.5091e-01 1.0211e-01 1.4138e-01
+ 1.2247e-01 1.2738e-01 1.2281e-01 1.4920e-01 8.9777e-02 1.3782e-01 8.8046e-02 1.1633e-01
+ 8.3268e-02 8.4714e-02 1.1031e-01 8.6445e-02 1.1347e-01 1.1277e-01 1.3916e-01 9.3075e-02
+ 9.1241e-02 1.0310e-01 8.8329e-02 1.0325e-01 6.7886e-02 1.0863e-01 1.0506e-01 4.2980e-02
+ 5.4991e-02 8.9869e-02 6.5057e-02 4.9956e-02 4.7614e-02 5.7458e-02 7.2045e-02 6.2699e-02
+ 5.1591e-02 6.0764e-02 7.3999e-02 7.2207e-02 6.4991e-02 5.5606e-02 9.5996e-02 8.5030e-02
+ 4.8703e-02 8.5965e-02 7.4505e-02 5.5183e-02 1.0906e-01 6.6577e-02 5.7464e-02 6.4327e-02
+ 6.3029e-02 7.8246e-02 6.2479e-02 1.1644e-01 8.0457e-02 5.2805e-02 7.3072e-02 -nan(ind)
+ 4.7449e-02 8.2975e-02 9.6716e-02 6.1533e-02 8.8225e-02 7.8754e-02 5.9670e-02 5.7757e-02
+ 1.2487e-01 1.0135e-01 7.1459e-02 7.4780e-02 7.2044e-02 7.4972e-02 6.9809e-02 6.4989e-02
+ 8.6148e-02 7.2471e-02 7.1194e-02 1.2632e-01 7.5133e-02 1.0383e-01 7.6222e-02 1.1488e-01
+ 1.1957e-01 6.8792e-02 1.0275e-01 9.4614e-02 8.8500e-02 1.2048e-01 8.0090e-02 1.1819e-01
+ 1.0679e-01 9.0032e-02 8.5797e-02 9.5211e-02 1.3953e-01 1.1610e-01 1.1037e-01 9.7873e-02
+ 8.8492e-02 1.1645e-01 9.7772e-02 1.2060e-01 1.1599e-01 8.6737e-02 1.0728e-01 1.0535e-01
+ 7.9259e-02 9.7601e-02 9.6736e-02 1.3783e-01 1.1954e-01 7.5306e-02 7.9852e-02 6.1636e-02
+ 1.7084e-01 8.8792e-02 1.0531e-01 1.1082e-01 7.7683e-02 7.5062e-02 9.9119e-02 7.3775e-02
+ 1.3853e-01 6.8025e-02 7.6357e-02 6.4660e-02 8.7859e-02 5.9861e-02 1.0949e-01 5.6376e-02
+ 5.2874e-02 6.3842e-02 5.6410e-02 8.6426e-02 6.0434e-02 4.3595e-02 5.6167e-02 8.4214e-02
+ 7.7690e-02 5.9031e-02 -nan(ind) 5.5341e-02 -nan(ind) 5.9394e-02 6.0222e-02 5.4258e-02
+ 7.9819e-02 4.5175e-02 7.7885e-02 8.0560e-02 6.9349e-02 -nan(ind) 7.8315e-02 5.0357e-02
+ 7.3868e-02 7.4962e-02 9.0608e-02 5.4001e-02 1.0577e-01 7.1343e-02 5.8255e-02 7.4738e-02
+ 7.6812e-02 5.9490e-02 9.7400e-02 8.7722e-02 7.5130e-02 5.9771e-02 1.4943e-01 5.1752e-02
+ 1.6148e-01 7.8607e-02 9.1570e-02 1.1018e-01 6.4230e-02 1.1426e-01 5.1330e-02 6.9974e-02
+ 9.2967e-02 6.2680e-02 6.9144e-02 9.1475e-02 6.5024e-02 1.2040e-01 6.2094e-02 8.7712e-02
+ 1.7349e-01 1.1409e-01 8.5597e-02 1.2750e-01 8.3870e-02 1.1386e-01 1.4098e-01 8.9406e-02
+ 1.4871e-01 9.6892e-02 1.4530e-01 1.0947e-01 1.0212e-01 1.3743e-01 9.8202e-02 1.0379e-01
+ 1.0605e-01 1.2395e-01 1.1770e-01 1.5098e-01 6.4897e-02 1.4535e-01 9.9816e-02 7.0815e-02
+ 9.5723e-02 7.6861e-02 9.4328e-02 1.7439e-01 5.3511e-02 1.1293e-01 8.4812e-02 6.6522e-02
+ 9.8107e-02 5.3881e-02 6.3371e-02 1.2283e-01 7.7570e-02 6.0640e-02 1.0291e-01 8.0422e-02
+ 6.1668e-02 7.6735e-02 4.7693e-02 6.9279e-02 6.1949e-02 5.3453e-02 5.1261e-02 9.5917e-02
+ 5.5269e-02 5.6883e-02 6.4740e-02 6.6081e-02 5.6348e-02 6.5528e-02 6.7152e-02 6.7184e-02
+ 5.1768e-02 5.8870e-02 6.2863e-02 7.1721e-02 4.9364e-02 6.3703e-02 8.4906e-02 6.4385e-02
+ 8.1821e-02 4.0003e-02 1.6682e-01 6.8427e-02 8.4727e-02 5.0642e-02 6.7062e-02 1.1175e-01
+ 1.1833e-01 6.5168e-02 5.8236e-02 1.1967e-01 4.7240e-02 9.7830e-02 1.1159e-01 8.2006e-02
+ 6.2954e-02 1.5315e-01 5.2338e-02 1.0799e-01 7.4205e-02 8.9203e-02 8.6882e-02 7.2602e-02
+ 1.4039e-01 8.8229e-02 5.9906e-02 8.3218e-02 7.1589e-02 1.0094e-01 8.6621e-02 6.1212e-02
+ 9.0710e-02 8.3103e-02 6.6691e-02 1.0024e-01 6.5053e-02 6.4416e-02 6.1652e-02 9.3637e-02
+ 5.1322e-02 8.5741e-02 7.8631e-02 5.8175e-02 1.6159e-01 5.2011e-02 8.2624e-02 1.5201e-01
+ 5.1286e-02 1.4290e-01 1.0596e-01 5.2661e-02 1.4441e-01 6.0568e-02 6.6464e-02 1.0112e-01
+ 5.6174e-02 9.3889e-02 7.0599e-02 5.7316e-02 8.5830e-02 7.6585e-02 5.2106e-02 5.3821e-02
+ 1.2020e-01 5.1793e-02 8.7562e-02 7.5988e-02 7.2509e-02 7.7984e-02 6.3457e-02 1.0819e-01
+ 7.9778e-02 7.5399e-02 6.8724e-02 6.9674e-02 5.8954e-02 6.4678e-02 8.2610e-02 6.2249e-02
+ 7.1315e-02 6.6380e-02 7.3938e-02 6.6331e-02 6.4482e-02 5.5416e-02 5.4362e-02 6.8594e-02
+ 9.7979e-02 5.6334e-02 4.8880e-02 1.1798e-01 5.7671e-02 5.6698e-02 8.0116e-02 6.2718e-02
+ 7.9678e-02 7.5042e-02 5.0304e-02 -nan(ind) 8.5234e-02 6.4602e-02 7.6522e-02 8.1965e-02
+ 6.5679e-02 -nan(ind) 6.1827e-02 7.2860e-02 6.5214e-02 5.2088e-02 7.0732e-02 4.8219e-02
+ 1.0498e-01 1.3152e-01 5.9670e-02 8.4601e-02 8.5538e-02 5.8056e-02 5.5654e-02 6.3455e-02
+ 7.1388e-02 7.5090e-02 6.3642e-02 9.0559e-02 1.2794e-01 5.6552e-02 9.1232e-02 1.0614e-01
+ 6.5710e-02 1.2908e-01 6.3790e-02 7.1063e-02 4.9651e-02 7.5423e-02 1.5008e-01 9.2776e-02
+ 7.5414e-02 1.1554e-01 8.1578e-02 8.0271e-02 9.4080e-02 1.3198e-01 6.4164e-02 7.0540e-02
+ 1.2984e-01 6.2590e-02 1.5702e-01 1.3069e-01 6.5901e-02 1.3033e-01 9.6070e-02 6.7262e-02
+ 9.4465e-02 8.2015e-02 6.6152e-02 1.0246e-01 7.2322e-02 6.5241e-02 9.9752e-02 7.6227e-02
+ 5.9322e-02 8.3519e-02 9.9464e-02 6.9267e-02 9.2271e-02 6.8801e-02 1.0060e-01 1.1503e-01
+ 6.1807e-02 7.4552e-02 1.7730e-01 7.4585e-02 1.0902e-01 1.0152e-01 6.4256e-02 1.5812e-01
+ 7.0025e-02 5.0476e-02 6.4766e-02 6.9196e-02 5.2580e-02 6.8763e-02 5.3356e-02 7.4875e-02
+ 4.8482e-02 5.7002e-02 8.4711e-02 6.5525e-02 5.0186e-02 7.0928e-02 5.1289e-02 5.0371e-02
+ 7.5913e-02 6.8760e-02 8.8049e-02 4.8420e-02 1.2818e-01 4.8106e-02 1.1457e-01 6.0083e-02
+ 6.1407e-02 6.2724e-02 6.3714e-02 1.0236e-01 9.3030e-02 6.1797e-02 7.6363e-02 6.5331e-02
+ 6.0864e-02 1.0247e-01 5.1931e-02 -nan(ind) 5.1403e-02 1.0215e-01 6.6836e-02 7.3191e-02
+ 7.2196e-02 1.6156e-01 6.3212e-02 6.2201e-02 6.2941e-02 5.3422e-02 8.9182e-02 6.0980e-02
+ 4.7088e-02 1.2947e-01 5.7525e-02 6.3772e-02 1.5584e-01 6.2552e-02 5.8280e-02 1.0427e-01
+ 6.8858e-02 8.0298e-02 7.2027e-02 8.3514e-02 5.5929e-02 8.7095e-02 7.7428e-02 7.1206e-02
+ 7.4542e-02 8.5119e-02 6.5120e-02 7.2315e-02 1.3931e-01 6.1036e-02 1.1532e-01 1.2689e-01
+ 5.0352e-02 9.8384e-02 9.0640e-02 5.4798e-02 1.0581e-01 9.0978e-02 7.1019e-02 1.1977e-01
+ 6.8082e-02 7.1484e-02 1.1435e-01 6.5551e-02 5.6493e-02 5.7128e-02 8.4015e-02 5.4783e-02
+ 7.3432e-02 8.7544e-02 7.0271e-02 7.8096e-02 8.8125e-02 6.4982e-02 7.2169e-02 8.2904e-02
+ 4.9871e-02 7.8155e-02 1.6279e-01 5.7187e-02 6.1565e-02 5.5802e-02 6.8194e-02 7.9030e-02
+ 6.5161e-02 6.5026e-02 6.9324e-02 4.9776e-02 7.7552e-02 5.6881e-02 5.4447e-02 7.1388e-02
+ -nan(ind) 5.1477e-02 9.3498e-02 6.4217e-02 5.5048e-02 7.7009e-02 5.5334e-02 1.1968e-01
+ 7.6440e-02 6.5782e-02 5.5161e-02 8.2100e-02 8.3007e-02 7.1829e-02 8.6074e-02 6.0075e-02
+ 7.4278e-02 8.3160e-02 5.3583e-02 6.1304e-02 7.2982e-02 9.9752e-02 5.7871e-02 5.0091e-02
+ 1.1932e-01 7.2331e-02 5.8069e-02 6.1160e-02 1.1959e-01 4.8958e-02 8.4138e-02 7.2783e-02
+ 6.0659e-02 9.0124e-02 7.6244e-02 5.6250e-02 9.3189e-02 6.7797e-02 4.4189e-02 8.7798e-02
+ 5.4045e-02 7.6503e-02 1.0016e-01 7.0031e-02 7.2569e-02 6.6688e-02 7.5005e-02 6.7679e-02
+ 7.3217e-02 8.9344e-02 5.8973e-02 9.5553e-02 8.3939e-02 7.1208e-02 5.8902e-02 6.5530e-02
+ 1.5360e-01 4.8005e-02 8.2713e-02 1.3021e-01 5.1490e-02 1.2772e-01 7.8347e-02 4.8570e-02
+ 1.2014e-01 9.1804e-02 5.3773e-02 1.0044e-01 5.8920e-02 7.1976e-02 6.5971e-02 7.1281e-02
+ 5.5595e-02 8.6968e-02 6.8596e-02 5.6128e-02 8.4308e-02 6.1364e-02 8.0603e-02 6.0917e-02
+ 6.4790e-02 6.4236e-02 5.9507e-02 1.2666e-01 9.8859e-02 4.4862e-02 8.1846e-02 8.8603e-02
+ 5.5865e-02 1.3853e-01 5.3922e-02 5.7981e-02 8.6611e-02 7.1052e-02 5.3078e-02 7.5502e-02
+ 3.9482e-02 5.4327e-02 6.0594e-02 6.6727e-02 5.2961e-02 7.4196e-02 5.4732e-02 8.6516e-02
+ 5.1040e-02 5.8984e-02 7.9210e-02 6.9178e-02 5.3838e-02 6.0666e-02 5.3535e-02 9.0945e-02
+ 1.3475e-01 7.9440e-02 7.6792e-02 7.4783e-02 6.2081e-02 5.6150e-02 7.4912e-02 6.5540e-02
+ 8.4055e-02 4.9377e-02 8.1999e-02 1.0783e-01 1.0235e-01 6.5755e-02 5.3862e-02 8.6865e-02
+ 4.5782e-02 6.9763e-02 9.1389e-02 5.3584e-02 7.6253e-02 7.8959e-02 4.3256e-02 1.2586e-01
+ 6.7444e-02 4.5377e-02 1.0831e-01 7.4649e-02 5.3497e-02 9.5871e-02 7.2413e-02 6.7919e-02
+ 5.5023e-02 7.7522e-02 8.5782e-02 6.9397e-02 5.8553e-02 1.3376e-01 4.6490e-02 6.6001e-02
+ 8.8610e-02 6.7410e-02 6.7134e-02 6.0579e-02 1.2346e-01 4.3080e-02 1.3017e-01 1.0888e-01
+ 4.7673e-02 1.3196e-01 8.4793e-02 4.5159e-02 9.1448e-02 8.4218e-02 5.5986e-02 1.2072e-01
+ 7.7680e-02 4.2717e-02 6.9993e-02 7.0324e-02 6.5599e-02 4.5690e-02 6.9132e-02 9.6811e-02
+ 5.3918e-02 6.3379e-02 7.8572e-02 5.7127e-02 5.3959e-02 7.3018e-02 5.3394e-02 6.1730e-02
+ 6.8612e-02 8.2235e-02 7.3209e-02 6.7997e-02 7.2068e-02 4.8590e-02 1.0570e-01 5.4042e-02
+ 5.3228e-02 6.0796e-02 7.3836e-02 4.9873e-02 8.6662e-02 4.6804e-02 6.3574e-02 7.4045e-02
+ 6.6163e-02 6.8287e-02 5.6273e-02 1.0679e-01 5.8060e-02 8.6497e-02 6.6197e-02 5.9896e-02
+ 6.7299e-02 6.7006e-02 5.8884e-02 1.2614e-01 8.9628e-02 7.7752e-02 7.1777e-02 6.3139e-02
+ 5.7222e-02 8.8735e-02 7.2012e-02 6.3512e-02 4.3344e-02 1.0098e-01 7.0690e-02 6.7704e-02
+ 6.5644e-02 4.8292e-02 9.9718e-02 4.7969e-02 9.7475e-02 9.6218e-02 4.8843e-02 8.3897e-02
+ 7.1579e-02 4.6562e-02 8.9993e-02 6.2041e-02 6.5914e-02 9.8002e-02 7.8624e-02 5.2139e-02
+ 5.9191e-02 7.9231e-02 7.2815e-02 6.0905e-02 7.8517e-02 7.2024e-02 6.6414e-02 6.6829e-02
+ 6.0577e-02 9.0592e-02 5.1185e-02 7.1587e-02 7.4222e-02 4.7507e-02 7.1046e-02 6.7169e-02
+ 7.4233e-02 4.8398e-02 7.8396e-02 1.1964e-01 5.1840e-02 1.2849e-01 9.1046e-02 5.1799e-02
+ 1.1433e-01 6.8273e-02 5.3277e-02 1.1865e-01 5.6675e-02 6.2131e-02 5.2253e-02 5.1782e-02
+ 8.3913e-02 5.2646e-02 6.9339e-02 5.6401e-02 4.6544e-02 7.4016e-02 6.5462e-02 7.2241e-02
+ 4.7903e-02 6.5750e-02 5.9418e-02 5.3978e-02 5.4519e-02 5.4653e-02 5.6660e-02 7.8131e-02
+ 7.5854e-02 9.0673e-02 4.8814e-02 1.2912e-01 6.4116e-02 4.2349e-02 1.5341e-01 5.2879e-02
+ 7.1248e-02 1.5094e-01 5.3069e-02 7.6290e-02 5.7966e-02 7.4328e-02 8.0244e-02 5.1816e-02
+ 6.6399e-02 6.0126e-02 6.9264e-02 5.8354e-02 5.0313e-02 7.3229e-02 5.7255e-02 5.5428e-02
+ 9.8608e-02 5.2233e-02 5.1151e-02 5.9795e-02 8.3510e-02 1.1630e-01 4.5500e-02 5.5148e-02
+ -nan(ind) 5.7453e-02 7.1936e-02 7.1473e-02 7.6494e-02 1.0476e-01 5.0602e-02 7.7782e-02
+ 8.2618e-02 5.0793e-02 5.8255e-02 4.3736e-02 4.9643e-02 1.0788e-01 7.4718e-02 6.4997e-02
+ 5.2740e-02 6.6425e-02 5.9393e-02 5.7599e-02 1.3252e-01 5.7253e-02 6.3568e-02 6.0162e-02
+ 7.7879e-02 6.4516e-02 5.1715e-02 5.7830e-02 8.9908e-02 5.9996e-02 5.0124e-02 1.3892e-01
+ 6.1750e-02 6.1584e-02 5.9563e-02 8.9341e-02 7.7756e-02 5.4563e-02 1.5176e-01 8.6666e-02
+ 4.5105e-02 9.2259e-02 6.8272e-02 4.5789e-02 7.8586e-02 8.0733e-02 6.3319e-02 8.8317e-02
+ 6.0270e-02 5.8312e-02 6.5938e-02 6.3826e-02 8.1010e-02 7.3925e-02 6.0972e-02 7.0136e-02
+ 8.2559e-02 5.0006e-02 5.1964e-02 1.2281e-01 5.0501e-02 6.6007e-02 4.7846e-02 8.4588e-02
+ 6.7450e-02 6.8194e-02 5.2736e-02 7.3354e-02 5.7121e-02 1.1819e-01 8.3701e-02 4.3176e-02
+ 4.4243e-02 5.9531e-02 4.4715e-02 1.0684e-01 5.9829e-02 5.2437e-02 1.7310e-01 6.7421e-02
+ 8.8607e-02 8.0487e-02 7.1329e-02 1.0389e-01 3.9403e-02 6.6746e-02 5.6886e-02 6.2384e-02
+ 9.8187e-02 4.9976e-02 4.7327e-02 5.8843e-02 6.0393e-02 6.4587e-02 8.2810e-02 7.1012e-02
+ 6.8657e-02 6.6042e-02 9.6059e-02 6.8425e-02 1.2979e-01 9.4692e-02 5.9840e-02 9.7452e-02
+ 6.6734e-02 5.5881e-02 7.2354e-02 1.1313e-01 3.9563e-02 1.1591e-01 1.3301e-01 4.3091e-02
+ 1.2916e-01 8.8433e-02 5.0100e-02 4.2986e-02 6.7283e-02 6.0677e-02 5.9877e-02 6.6610e-02
+ 6.7321e-02 5.3283e-02 8.1027e-02 4.7029e-02 5.6332e-02 7.6849e-02 4.9267e-02 6.2145e-02
+ 6.5388e-02 5.2356e-02 7.1572e-02 7.6140e-02 5.0920e-02 6.2226e-02 6.7769e-02 8.3620e-02
+ 6.5487e-02 5.1286e-02 9.1630e-02 1.2197e-01 4.4997e-02 1.5882e-01 1.0212e-01 4.1836e-02
+ 9.2552e-02 8.3354e-02 5.4033e-02 6.9895e-02 6.7220e-02 5.7787e-02 6.6109e-02 8.0876e-02
+ 7.5505e-02 5.7554e-02 4.6320e-02 8.1227e-02 7.0783e-02 6.6483e-02 1.8871e-01 6.3254e-02
+ 5.8584e-02 3.9983e-02 6.7606e-02 6.7817e-02 6.3141e-02 5.4180e-02 1.5024e-01 4.6849e-02
+ 6.4030e-02 6.8987e-02 9.0375e-02 8.6751e-02 4.7296e-02 1.5462e-01 5.6974e-02 4.8964e-02
+ 8.3235e-02 4.0964e-02 4.9946e-02 6.2843e-02 5.0901e-02 4.7444e-02 5.7547e-02 8.9711e-02
+ 6.3438e-02 1.1821e-01 6.0583e-02 8.2596e-02 5.2323e-02 6.5740e-02 5.3613e-02 8.3048e-02
+ 6.3603e-02 6.0528e-02 1.3945e-01 5.6300e-02 1.1303e-01 8.0568e-02 8.3894e-02 9.5431e-02
+ 8.0948e-02 6.4686e-02 7.4870e-02 5.4690e-02 9.1295e-02 6.7598e-02 6.1484e-02 3.7721e-02
+ 1.0431e-01 3.0952e-01 3.3995e-02 9.3398e-02 7.3062e-02 4.5583e-02 5.6673e-02 5.5708e-02
+ 6.6334e-02 5.8762e-02 7.0863e-02 6.8957e-02 6.5375e-02 5.6852e-02 7.5576e-02 5.8009e-02
+ 1.3097e-01 5.4135e-02 5.7293e-02 1.3096e-01 5.4277e-02 6.5991e-02 6.9409e-02 1.0568e-01
+ 6.0657e-02 6.1406e-02 9.5459e-02 9.3425e-02 7.3636e-02 7.8900e-02 1.2225e-01 1.1825e-01
+ 4.6701e-02 1.5984e-01 1.2444e-01 5.9797e-02 1.0779e-01 1.1312e-01 5.4865e-02 9.1126e-02
+ 9.3735e-02 7.8930e-02 6.4434e-02 5.9413e-02 6.0283e-02 5.7517e-02 4.6404e-02 6.5203e-02
+ 7.6474e-02 5.7697e-02 4.8023e-02 7.3550e-02 7.4133e-02 6.2925e-02 5.5866e-02 4.7771e-02
+ 6.9700e-02 6.7433e-02 6.5508e-02 1.7044e-01 4.7598e-02 5.6866e-02 5.6766e-02 5.9803e-02
+ 6.9970e-02 4.7425e-02 -nan(ind) 9.3988e-02 4.4779e-02 1.0653e-01 6.0040e-02 5.7401e-02
+ 4.7253e-02 7.0724e-02 4.8077e-02 6.9898e-02 -nan(ind) 7.2317e-02 6.5064e-02 7.0790e-02
+ 6.8679e-02 1.1561e-01 5.0661e-02 6.8031e-02 -nan(ind) 8.3092e-02 7.8764e-02 8.7186e-02
+ 4.9806e-02 9.4059e-02 7.0867e-02 5.4413e-02 -nan(ind) 6.9028e-02 6.7768e-02 6.7015e-02
+ 6.3244e-02 7.4193e-02 4.6515e-02 7.8213e-02 1.3751e-01 3.7715e-02 7.2263e-02 7.3612e-02
+ 4.9741e-02 8.3695e-02 6.3383e-02 8.8709e-02 6.8898e-02 4.7735e-02 6.3857e-02 4.9338e-02
+ 5.4262e-02 6.4056e-02 6.9398e-02 8.8604e-02 6.1517e-02 7.2389e-02 5.8993e-02 6.4361e-02
+ 6.0829e-02 8.5212e-02 6.4326e-02 7.2614e-02 4.5091e-02 7.0529e-02 5.0894e-02 8.4601e-02
+ 7.7946e-02 5.6187e-02 6.9021e-02 6.4654e-02 4.4655e-02 1.0084e-01 7.6424e-02 4.6429e-02
+ 1.1472e-01 8.6775e-02 5.7677e-02 7.9757e-02 5.6836e-02 7.0904e-02 5.0659e-02 5.9979e-02
+ 5.4186e-02 5.9495e-02 1.3023e-01 5.0424e-02 8.0212e-02 7.6058e-02 7.1282e-02 7.0616e-02
+ 8.5068e-02 5.2587e-02 6.4026e-02 5.5480e-02 7.1159e-02 7.7359e-02 7.4011e-02 6.9054e-02
+ 1.5769e-01 4.2643e-02 5.7216e-02 5.7959e-02 6.1740e-02 6.8900e-02 3.5747e-02 2.1350e-01
+ 6.5811e-02 3.6848e-02 8.4470e-02 5.7984e-02 8.1148e-02 5.3564e-02 6.1828e-02 9.9304e-02
+ 5.5775e-02 6.6295e-02 7.6349e-02 5.4219e-02 9.1770e-02 5.9592e-02 1.0162e-01 7.8314e-02
+ 7.9476e-02 7.1773e-02 5.5773e-02 9.1588e-02 7.5246e-02 7.9221e-02 7.8908e-02 8.3076e-02
+ 5.6093e-02 7.1750e-02 5.4425e-02 9.9207e-02 6.5217e-02 4.2188e-02 1.0174e-01 6.0624e-02
+ 4.0866e-02 1.2450e-01 6.2322e-02 5.1357e-02 8.3562e-02 7.2293e-02 6.5861e-02 7.9145e-02
+ 6.1178e-02 7.5315e-02 6.8458e-02 1.1376e-01 8.2230e-02 6.4934e-02 1.0104e-01 6.6929e-02
+ 6.8291e-02 9.0217e-02 8.1984e-02 5.2644e-02 6.1700e-02 8.7686e-02 7.9335e-02 7.3353e-02
+ 9.0476e-02 5.9642e-02 6.4249e-02 7.7493e-02 1.1081e-01 5.0215e-02 8.3612e-02 9.2585e-02
+ 4.1612e-02 1.4663e-01 1.0351e-01 4.8623e-02 1.3459e-01 8.1688e-02 5.4669e-02 7.6003e-02
+ 7.2003e-02 5.5077e-02 7.9847e-02 8.5583e-02 8.5626e-02 5.2649e-02 6.2392e-02 8.0479e-02
+ 6.6762e-02 7.8291e-02 8.8087e-02 7.1926e-02 6.6203e-02 6.3342e-02 7.6157e-02 1.2945e-01
+ 1.7247e-01 4.6974e-02 1.1670e-01 5.6755e-02 7.7011e-02 6.4971e-02 1.3390e-01 7.0438e-02
+ 5.0997e-02 1.0709e-01 1.0722e-01 4.1467e-02 1.1202e-01 1.0450e-01 4.0081e-02 6.8011e-02
+ 5.4883e-02 5.0796e-02 5.4976e-02 6.1934e-02 8.0997e-02 8.0111e-02 6.6705e-02 6.7941e-02
+ 6.7880e-02 7.3753e-02 7.3209e-02 6.3094e-02 5.5182e-02 6.4368e-02 1.4131e-01 5.5626e-02
+ 6.5723e-02 1.0242e-01 5.3339e-02 6.4166e-02 6.6054e-02 5.0912e-02 8.9809e-02 5.8487e-02
+ 5.0504e-02 1.2509e-01 6.4511e-02 6.4018e-02 1.1165e-01 4.7730e-02 5.6858e-02 -nan(ind)
+ 6.9706e-02 5.2602e-02 9.6171e-02 8.0836e-02 7.3086e-02 5.5164e-02 9.2976e-02 7.3353e-02
+ 5.1208e-02 6.8011e-02 5.6157e-02 4.5946e-02 1.8528e-01 5.5123e-02 6.2174e-02 5.6425e-02
+ 8.1464e-02 5.3642e-02 8.9381e-02 4.6028e-02 5.6977e-02 1.3471e-01 6.2028e-02 5.8653e-02
+ 9.6552e-02 5.9436e-02 5.9621e-02 7.6994e-02 4.6119e-02 2.2442e-01 8.2323e-02 4.1400e-02
+ 1.0270e-01 9.9757e-02 5.6907e-02 4.8741e-02 6.4962e-02 7.3294e-02 5.6246e-02 6.3907e-02
+ 6.6473e-02 1.0322e-01 5.4641e-02 6.0126e-02 5.1326e-02 6.4555e-02 6.2052e-02 5.4643e-02
+ 7.1403e-02 4.1399e-02 7.3158e-02 5.9832e-02 5.0445e-02 1.3366e-01 6.3226e-02 1.0390e-01
+ 5.6910e-02 7.2719e-02 8.3714e-02 6.6748e-02 1.1496e-01 5.4869e-02 9.1337e-02 1.6689e-01
+ 4.5394e-02 2.0423e-01 1.1310e-01 4.5029e-02 5.8619e-02 8.3829e-02 4.7308e-02 7.7172e-02
+ 5.0138e-02 4.7696e-02 1.3236e-01 6.7227e-02 4.0834e-02 7.6998e-02 5.6288e-02 5.1434e-02
+ 6.8626e-02 5.2178e-02 7.5203e-02 6.7333e-02 5.0970e-02 6.4372e-02 6.2897e-02 5.9290e-02
+ 1.0513e-01 1.6051e-01 7.6857e-02 6.1764e-02 -nan(ind) 1.1894e-01 5.9113e-02 8.2862e-02
+ 1.2340e-01 4.3161e-02 6.9885e-02 5.6079e-02 5.4592e-02 7.6713e-02 5.1868e-02 6.3168e-02
+ 6.9086e-02 6.0958e-02 7.2368e-02 6.7810e-02 5.3565e-02 6.0919e-02 1.2749e-01 5.2922e-02
+ 5.6223e-02 8.7650e-02 8.0838e-02 6.0830e-02 6.0997e-02 1.2069e-01 6.5581e-02 5.3141e-02
+ 7.8949e-02 6.5784e-02 7.3044e-02 5.0532e-02 5.7264e-02 6.0612e-02 8.2064e-02 6.5751e-02
+ 4.3464e-02 2.1088e-01 9.0984e-02 4.1865e-02 1.4804e-01 9.4504e-02 5.0766e-02 8.2609e-02
+ 5.9143e-02 6.5824e-02 6.0746e-02 5.7896e-02 5.9261e-02 4.7156e-02 6.5298e-02 6.2922e-02
+ 6.1718e-02 6.5721e-02 5.1008e-02 7.7161e-02 4.1659e-02 4.8759e-02 7.9688e-02 7.9091e-02
+ 4.8482e-02 5.8460e-02 8.8133e-02 7.0792e-02 5.6077e-02 7.3410e-02 6.5804e-02 7.2185e-02
+ 5.9665e-02 5.9749e-02 5.6599e-02 1.1521e-01 -nan(ind) 5.6239e-02 -nan(ind) 6.6664e-02
+ 5.7589e-02 1.1959e-01 8.5586e-02 -nan(ind) 5.5036e-02 5.5662e-02 8.0175e-02 5.0242e-02
+ 7.1865e-02 4.4078e-02 5.6337e-02 7.6612e-02 7.1103e-02 9.8571e-02 6.5389e-02 8.9882e-02
+ -nan(ind) 6.7173e-02 8.1007e-02 8.0669e-02 7.9003e-02 6.2826e-02 4.0648e-02 1.0790e-01
+ 1.1166e-01 3.8427e-02 1.8420e-01 6.5376e-02 5.7904e-02 6.8994e-02 5.1794e-02 5.9021e-02
+ 7.4615e-02 4.6839e-02 5.3331e-02 7.7132e-02 6.1317e-02 7.5017e-02 4.9568e-02 5.7654e-02
+ 7.8473e-02 4.8231e-02 5.4606e-02 -nan(ind) 5.6722e-02 1.1082e-01 6.0129e-02 8.0555e-02
+ 7.8821e-02 7.5722e-02 8.0468e-02 5.6994e-02 6.9166e-02 4.9330e-02 1.5330e-01 5.8639e-02
+ 6.5221e-02 6.9453e-02 9.4123e-02 5.3138e-02 4.7813e-02 -nan(ind) 1.1627e-01 4.0735e-02
+ 1.3128e-01 9.4849e-02 6.5019e-02 6.2099e-02 5.8488e-02 1.0625e-01 6.1617e-02 7.9263e-02
+ 6.1119e-02 7.0000e-02 1.2368e-01 8.8324e-02 4.4955e-02 6.9237e-02 -nan(ind) 5.0536e-02
+ 6.5867e-02 7.9503e-02 6.5390e-02 1.1462e-01 6.2555e-02 4.6061e-02 6.3193e-02 6.9728e-02
+ 7.2368e-02 5.3706e-02 6.4559e-02 6.4228e-02 7.7899e-02 4.7992e-02 1.9664e-01 4.8453e-02
+ 1.0875e-01 1.1590e-01 4.0656e-02 -nan(ind) 9.1864e-02 3.4454e-02 9.4948e-02 7.0400e-02
+ -nan(ind) 7.3623e-02 5.4460e-02 6.2278e-02 7.9950e-02 7.2486e-02 -nan(ind) 6.3650e-02
+ 6.3799e-02 5.5137e-02 1.0431e-01 7.0386e-02 4.8783e-02 8.6312e-02 3.9681e-02 1.0284e-01
+ 6.9695e-02 4.5677e-02 7.0054e-02 1.7655e-01 3.7544e-02 6.5684e-02 4.9560e-02 6.7321e-02
+ 5.7513e-02 5.1964e-02 5.9633e-02 5.9502e-02 5.3079e-02 6.2091e-02 8.5721e-02 7.3855e-02
+ 8.2858e-02 6.3481e-02 6.7681e-02 1.7412e-01 1.0273e-01 6.7780e-02 5.2350e-02 5.7176e-02
+ 8.7361e-02 5.6716e-02 6.0357e-02 7.3635e-02 8.5720e-02 6.7051e-02 6.2550e-02 1.0807e-01
+ 6.4075e-02 -nan(ind) 6.2468e-02 6.6364e-02 8.2338e-02 8.1695e-02 8.7617e-02 5.8645e-02
+ 4.7768e-02 -nan(ind) 1.7047e-01 5.0860e-02 -nan(ind) 8.6294e-02 7.6381e-02 1.0052e-01
+ 5.4604e-02 8.9069e-02 7.1055e-02 9.9412e-02 7.1389e-02 9.6154e-02 6.4552e-02 6.1011e-02
+ 1.0682e-01 3.9490e-02 6.8620e-02 6.0995e-02 7.9899e-02 4.2511e-02 9.1768e-02 8.1490e-02
+ 9.0444e-02 1.0099e-01 5.5346e-02 6.1492e-02 9.0680e-02 5.5233e-02 8.0080e-02 9.6244e-02
+ 6.4066e-02 9.1825e-02 5.0398e-02 7.3819e-02 5.6190e-02 6.1082e-02 8.0052e-02 3.5787e-02
+ -nan(ind) 6.3548e-02 4.4324e-02 7.3761e-02 6.4178e-02 6.5630e-02 9.2477e-02 5.8768e-02
+ 5.9485e-02 1.2356e-01 4.5457e-02 5.2762e-02 6.9748e-02 8.9478e-02 4.8800e-02 8.2286e-02
+ 4.3420e-02 1.0628e-01 6.2873e-02 4.9130e-02 5.3501e-02 1.1884e-01 -nan(ind) 3.9002e-02
+ -nan(ind) 7.1996e-02 -nan(ind) 7.8665e-02 7.2978e-02 8.6136e-02 5.5845e-02 1.8106e-01
+ 5.2789e-02 2.3656e-02 5.6660e-02 9.6202e-02 1.0080e-01 1.0265e-01 6.2077e-02 8.9910e-02
+ 6.4834e-02 6.7132e-02 1.0481e-01 7.7584e-02 6.7997e-02 9.2227e-02 5.3935e-02 1.5374e-01
+ 5.4395e-02 5.9560e-02 6.8484e-02 5.2027e-02 6.8029e-02 6.2226e-02 6.8092e-02 6.1648e-02
+ 7.3898e-02 6.0364e-02 9.2230e-02 1.0222e-01 4.1336e-02 -nan(ind) 1.0952e-01 4.0056e-02
+ 6.9740e-02 7.2478e-02 5.7972e-02 1.1155e-01 7.1140e-02 7.4420e-02 6.3145e-02 5.4407e-02
+ 7.2658e-02 6.0491e-02 4.6494e-02 8.3025e-02 5.7794e-02 5.7246e-02 5.7540e-02 7.3644e-02
+ 5.8166e-02 7.0975e-02 9.9131e-02 7.2836e-02 7.7219e-02 8.8571e-02 6.0779e-02 -nan(ind)
+ 6.3766e-02 9.4198e-02 6.9321e-02 7.0716e-02 6.7367e-02 5.8274e-02 1.4967e-01 7.3804e-02
+ 8.0446e-02 -nan(ind) 8.3625e-02 -nan(ind) 4.1606e-02 -nan(ind) 7.6810e-02 3.6683e-02
+ 6.1890e-02 7.4971e-02 5.2163e-02 5.8337e-02 6.7852e-02 4.5262e-02 6.5577e-02 6.7101e-02
+ 1.2157e-01 6.6865e-02 1.0886e-01 4.4663e-02 8.3738e-02 7.5699e-02 1.5504e-01 7.5048e-02
+ -nan(ind) -nan(ind) 4.7532e-02 -nan(ind) 5.7152e-02 7.3477e-02 6.4324e-02 8.2544e-02
+ 4.8989e-02 5.4125e-02 1.2020e-01 4.6784e-02 6.5244e-02 1.0430e-01 7.2160e-02 5.0495e-02
+ 5.2886e-02 1.0001e-01 7.8777e-02 5.8825e-02 1.0367e-01 4.8998e-02 5.1841e-02 6.2204e-02
+ 6.6151e-02 5.7692e-02 7.4857e-02 6.2563e-02 1.0260e-01 7.3403e-02 5.3338e-02 8.7284e-02
+ 7.0981e-02 6.5794e-02 5.2614e-02 5.6163e-02 5.7797e-02 1.2293e-01 7.1791e-02 5.5727e-02
+ 4.2966e-02 -nan(ind) 1.5739e-01 4.3670e-02 9.3889e-02 8.6763e-02 1.0030e-01 6.1785e-02
+ 5.0531e-02 7.6140e-02 5.2108e-02 6.9926e-02 9.4999e-02 4.4011e-02 1.0486e-01 9.5593e-02
+ 6.3001e-02 4.9726e-02 6.4578e-02 5.5664e-02 6.9681e-02 6.3775e-02 5.0052e-02 1.7872e-01
+ 5.5397e-02 7.9456e-02 6.2968e-02 6.7564e-02 6.6336e-02 6.8770e-02 1.2365e-01 6.8875e-02
+ 5.2578e-02 1.1021e-01 5.0382e-02 4.5144e-02 1.2558e-01 4.2855e-02 7.9788e-02 9.6336e-02
+ 7.6283e-02 4.9358e-02 -nan(ind) 1.2641e-01 6.0062e-02 1.7123e-01 1.5748e-01 7.4831e-02
+ 7.7926e-02 7.8480e-02 1.1315e-01 6.1362e-02 9.1904e-02 5.2015e-02 9.1231e-02 4.7270e-02
+ 7.6858e-02 7.0686e-02 4.4898e-02 8.5553e-02 -nan(ind) 3.7975e-02 8.1168e-02 7.1605e-02
+ 5.1714e-02 7.9283e-02 4.9773e-02 7.2810e-02 5.3450e-02 5.7607e-02 4.8033e-02 5.4202e-02
+ 6.6813e-02 7.2077e-02 6.6317e-02 5.2699e-02 1.0592e-01 5.7222e-02 5.3484e-02 9.6849e-02
+ 6.4058e-02 8.1325e-02 6.0318e-02 1.1714e-01 7.1230e-02 5.3845e-02 9.5399e-02 1.0055e-01
+ 8.5092e-02 9.8196e-02 6.6265e-02 7.2565e-02 8.1593e-02 1.0496e-01 6.8112e-02 8.2252e-02
+ 8.7314e-02 6.3262e-02 9.8086e-02 5.6843e-02 6.2760e-02 -nan(ind) -nan(ind) 4.9109e-02
+ 1.0433e-01 1.2979e-01 7.2622e-02 1.5491e-01 5.4682e-02 1.1414e-01 1.4490e-01 1.0605e-01
+ 5.2890e-02 6.3417e-02 -nan(ind) 5.5562e-02 7.6230e-02 6.4892e-02 7.2392e-02 6.4980e-02
+ 8.5895e-02 7.8948e-02 9.5523e-02 7.9865e-02 7.5310e-02 7.6900e-02 6.2723e-02 8.1413e-02
+ 5.6008e-02 6.8213e-02 8.2177e-02 7.0018e-02 6.1186e-02 6.2795e-02 7.3463e-02 6.1319e-02
+ 4.7196e-02 7.4114e-02 8.4308e-02 4.7545e-02 1.2130e-01 1.1196e-01 3.9955e-02 -nan(ind)
+ 6.6646e-02 3.8458e-02 9.8323e-02 5.2423e-02 5.2050e-02 7.6125e-02 6.0535e-02 8.1142e-02
+ 5.3390e-02 7.7777e-02 5.5693e-02 7.5405e-02 5.7258e-02 5.4486e-02 1.7999e-01 8.9283e-02
+ 3.0969e-02 -nan(ind) 7.2616e-02 6.0303e-02 7.3419e-02 5.1763e-02 -nan(ind) 6.4531e-02
+ 6.5625e-02 6.3246e-02 5.6778e-02 1.0055e-01 8.3649e-02 5.7584e-02 1.0523e-01 1.1373e-01
+ 5.7506e-02 7.7895e-02 -nan(ind) 8.2972e-02 5.5177e-02 -nan(ind) 6.1141e-02 7.0314e-02
+ 8.7739e-02 6.1445e-02 8.1481e-02 9.2453e-02 5.9184e-02 7.4747e-02 7.3292e-02 5.5825e-02
+ 5.0258e-02 9.6301e-02 7.0555e-02 6.3428e-02 6.1543e-02 5.4215e-02 1.2427e-01 1.0275e-01
+ 4.3705e-02 -nan(ind) -nan(ind) 4.2098e-02 -nan(ind) 8.6529e-02 5.3554e-02 6.8395e-02
+ 7.2124e-02 6.6600e-02 5.2111e-02 5.3037e-02 7.3736e-02 7.1858e-02 6.2011e-02 5.4621e-02
+ 8.0917e-02 7.1026e-02 6.9739e-02 4.7660e-02 5.2375e-02 8.5653e-02 -nan(ind) 4.4677e-02
+ 9.3812e-02 1.0557e-01 9.7280e-02 1.1219e-01 1.2003e-01 -nan(ind) 5.2323e-02 5.4586e-02
+ 1.0839e-01 5.7790e-02 7.8910e-02 9.6389e-02 6.5585e-02 -nan(ind) 3.9308e-02 9.3727e-02
+ 6.1357e-02 1.0849e-01 8.4274e-02 3.4470e-02 -nan(ind) 2.4192e-01 3.6506e-02 5.4671e-02
+ 6.2208e-02 8.5989e-02 7.1843e-02 5.5887e-02 -nan(ind) 6.7695e-02 5.9819e-02 1.1052e-01
+ 5.2155e-02 -nan(ind) 1.0523e-01 6.4690e-02 -nan(ind) 7.6977e-02 5.7845e-02 6.0770e-02
+ 7.0748e-02 1.1801e-01 8.3112e-02 8.3023e-02 5.9679e-02 7.5246e-02 9.9156e-02 9.4059e-02
+ 5.9175e-02 7.1725e-02 5.1458e-02 4.5771e-02 7.0086e-02 5.1548e-02 4.8233e-02 5.0046e-02
+ -nan(ind) 5.0687e-02 7.0796e-02 8.2882e-02 5.1638e-02 7.2898e-02 5.1173e-02 7.9066e-02
+ 7.3717e-02 4.8116e-02 5.5275e-02 1.0289e-01 5.6107e-02 8.3209e-02 6.4297e-02 5.3431e-02
+ 7.8802e-02 7.1832e-02 8.4721e-02 5.2707e-02 4.1558e-02 -nan(ind) -nan(ind) 4.5849e-02
+ 7.4397e-02 8.7724e-02 5.9153e-02 7.7012e-02 6.4069e-02 5.6375e-02 7.1414e-02 8.3026e-02
+ 6.3475e-02 6.2191e-02 5.3092e-02 6.6693e-02 5.8213e-02 5.1647e-02 5.0117e-02 7.2498e-02
+ 9.0520e-02 6.6100e-02 5.7485e-02 4.9722e-02 5.0197e-02 4.9439e-02 5.8966e-02 5.5355e-02
+ 7.4942e-02 5.4806e-02 8.9285e-02 6.0605e-02 1.0516e-01 7.2538e-02 5.2076e-02 7.1430e-02
+ 1.1298e-01 4.6129e-02 -nan(ind) 7.1986e-02 4.9784e-02 7.3241e-02 8.7220e-02 -nan(ind)
+ 6.0904e-02 -nan(ind) 7.6912e-02 5.8414e-02 7.0333e-02 5.3531e-02 8.7660e-02 6.4588e-02
+ 5.6023e-02 1.2033e-01 7.3366e-02 3.8126e-02 1.5546e-01 -nan(ind) 3.8153e-02 6.7302e-02
+ 7.3889e-02 5.0999e-02 7.8893e-02 6.9334e-02 4.7604e-02 6.3865e-02 7.0222e-02 4.2435e-02
+ 7.5126e-02 5.0308e-02 4.0975e-02 9.1106e-02 6.4961e-02 5.3048e-02 8.5590e-02 6.3383e-02
+ 7.4720e-02 7.2528e-02 1.3524e-01 6.0012e-02 6.7492e-02 9.6200e-02 7.4621e-02 7.4722e-02
+ 4.7242e-02 1.0875e-01 8.0369e-02 8.2512e-02 6.4915e-02 5.7953e-02 6.7380e-02 7.9147e-02
+ 1.0217e-01 7.4455e-02 7.9046e-02 6.2694e-02 6.3726e-02 6.6623e-02 1.5001e-01 5.6323e-02
+ 5.8937e-02 -nan(ind) -nan(ind) 5.6578e-02 6.5640e-02 8.3812e-02 7.1601e-02 9.8596e-02
+ 7.8217e-02 7.0228e-02 1.8063e-01 9.6746e-02 7.9977e-02 6.0817e-02 6.6189e-02 -nan(ind)
+ 6.5749e-02 5.9985e-02 6.3293e-02 7.2458e-02 6.6324e-02 1.0575e-01 5.8584e-02 1.0833e-01
+ 4.8717e-02 1.0455e-01 7.1975e-02 -nan(ind) 5.8942e-02 7.5145e-02 5.4604e-02 7.3821e-02
+ 7.8936e-02 6.4353e-02 4.7035e-02 4.6583e-02 5.3292e-02 6.0190e-02 8.5602e-02 5.6675e-02
+ 7.5982e-02 5.0784e-02 4.7928e-02 9.7044e-02 7.5882e-02 4.2322e-02 -nan(ind) 8.7214e-02
+ 3.8866e-02 1.1095e-01 6.0331e-02 5.4136e-02 6.6906e-02 4.1078e-02 5.5004e-02 1.0899e-01
+ 6.6905e-02 3.4448e-02 1.1241e-01 1.1694e-01 4.2424e-02 7.2518e-02 4.9134e-02 6.1931e-02
+ 6.9460e-02 6.3756e-02 6.6444e-02 9.2875e-02 5.4095e-02 9.0244e-02 8.8473e-02 5.9833e-02
+ 5.3194e-02 6.0057e-02 4.6707e-02 8.4086e-02 8.5426e-02 8.7272e-02 5.1366e-02 9.2405e-02
+ 9.4569e-02 8.1135e-02 5.8986e-02 6.1741e-02 1.0583e-01 6.6121e-02 7.1170e-02 5.5968e-02
+ 5.0943e-02 6.9606e-02 6.9035e-02 5.4339e-02 9.5420e-02 5.8297e-02 8.0261e-02 5.7203e-02
+ 5.6090e-02 6.9304e-02 1.3718e-01 6.5283e-02 4.7233e-02 -nan(ind) -nan(ind) 3.9475e-02
+ -nan(ind) 1.1314e-01 5.4780e-02 6.8603e-02 7.5151e-02 6.2303e-02 5.0229e-02 7.1060e-02
+ 6.3025e-02 5.7715e-02 6.8770e-02 4.1288e-02 5.8369e-02 7.8723e-02 7.0046e-02 6.1803e-02
+ 6.6058e-02 6.2998e-02 9.9908e-02 9.0690e-02 5.5536e-02 1.1137e-01 8.9148e-02 6.7265e-02
+ 7.6172e-02 6.4940e-02 7.1348e-02 1.2402e-01 5.4500e-02 1.1694e-01 9.3204e-02 6.2416e-02
+ 7.1777e-02 6.7262e-02 1.0457e-01 -nan(ind) 5.9735e-02 5.6014e-02 6.0739e-02 5.5120e-02
+ 1.2505e-01 7.4902e-02 3.5732e-02 1.0369e-01 9.2425e-02 4.7947e-02 4.4589e-02 6.9885e-02
+ 9.1017e-02 5.1200e-02 -nan(ind) -nan(ind) 5.3664e-02 9.9574e-02 5.8846e-02 9.2480e-02
+ 5.3951e-02 1.2443e-01 7.8876e-02 5.6915e-02 6.4532e-02 1.0334e-01 5.5682e-02 4.6151e-02
+ 7.4077e-02 5.0884e-02 8.8665e-02 5.4538e-02 5.3204e-02 4.9988e-02 5.4362e-02 6.8976e-02
+ 6.7115e-02 6.8310e-02 5.1206e-02 5.3124e-02 7.9016e-02 7.5971e-02 5.7855e-02 6.2115e-02
+ 5.7683e-02 5.5511e-02 8.3279e-02 7.5722e-02 5.9352e-02 9.1304e-02 4.9653e-02 5.8620e-02
+ 6.0289e-02 5.5281e-02 5.4652e-02 5.3741e-02 1.7494e-01 5.7197e-02 1.0938e-01 4.8817e-02
+ 5.4426e-02 -nan(ind) -nan(ind) 4.4665e-02 6.5876e-02 6.2339e-02 6.5834e-02 8.6363e-02
+ 5.4849e-02 4.6677e-02 8.1367e-02 6.4276e-02 5.0351e-02 5.9413e-02 5.3985e-02 5.6009e-02
+ 7.0077e-02 1.4114e-01 4.4872e-02 5.0749e-02 4.3139e-02 6.9217e-02 6.7031e-02 4.6011e-02
+ -nan(ind) 5.7438e-02 1.0847e-01 5.7193e-02 1.1263e-01 5.2895e-02 6.2174e-02 4.8021e-02
+ 7.8555e-02 6.4336e-02 9.4024e-02 6.7467e-02 5.9774e-02 6.3373e-02 6.6150e-02 4.9412e-02
+ 5.8346e-02 8.1454e-02 6.9090e-02 7.2613e-02 5.5772e-02 9.2623e-02 1.0089e-01 4.6756e-02
+ -nan(ind) -nan(ind) 5.5194e-02 9.3533e-02 5.6950e-02 8.5292e-02 -nan(ind) 3.5923e-02
+ 7.6462e-02 6.1448e-02 6.8386e-02 5.2614e-02 5.0818e-02 4.2830e-02 6.3785e-02 7.8059e-02
+ 4.8908e-02 7.9613e-02 5.9152e-02 5.1038e-02 8.8492e-02 7.5218e-02 5.0261e-02 7.9222e-02
+ 7.2385e-02 5.8870e-02 1.0337e-01 7.6058e-02 6.1037e-02 6.8145e-02 7.2397e-02 5.9707e-02
+ 7.9678e-02 1.2343e-01 4.5878e-02 6.1610e-02 8.5003e-02 1.2459e-01 4.6684e-02 -nan(ind)
+ 6.3358e-02 5.7436e-02 8.3497e-02 -nan(ind) 6.0498e-02 6.5579e-02 5.7904e-02 7.9816e-02
+ 7.6231e-02 6.6640e-02 1.0968e-01 5.2334e-02 4.6018e-02 -nan(ind) -nan(ind) 4.7726e-02
+ 5.6619e-02 8.0673e-02 5.6801e-02 1.1003e-01 6.0606e-02 6.9490e-02 7.1858e-02 7.3860e-02
+ 1.1658e-01 6.6505e-02 6.4137e-02 6.2232e-02 -nan(ind) 4.8988e-02 6.1926e-02 -nan(ind)
+ 4.5169e-02 9.9229e-02 1.1351e-01 1.0771e-01 5.1073e-02 7.0315e-02 7.0579e-02 7.3127e-02
+ 6.5385e-02 1.0020e-01 4.6469e-02 6.8583e-02 7.0111e-02 5.3529e-02 9.7632e-02 6.6468e-02
+ 6.4445e-02 1.0221e-01 5.3070e-02 8.8257e-02 8.5911e-02 5.6595e-02 4.9573e-02 7.7419e-02
+ 5.2554e-02 5.0270e-02 1.1969e-01 7.1836e-02 3.6512e-02 -nan(ind) 9.0211e-02 4.5279e-02
+ 9.3921e-02 -nan(ind) 3.9754e-02 -nan(ind) 1.1971e-01 6.1382e-02 -nan(ind) 6.7347e-02
+ 1.1859e-01 1.4008e-01 8.7392e-02 5.5556e-02 9.9793e-02 7.5645e-02 5.4092e-02 1.0481e-01
+ 4.7378e-02 8.1205e-02 -nan(ind) 6.0013e-02 5.7869e-02 7.9990e-02 4.8416e-02 5.9967e-02
+ 6.5926e-02 4.8248e-02 1.0084e-01 5.9957e-02 5.4410e-02 8.1732e-02 6.3250e-02 7.1542e-02
+ 6.4481e-02 1.1836e-01 6.9311e-02 7.8273e-02 7.3663e-02 7.1997e-02 9.7509e-02 5.5948e-02
+ 8.1106e-02 5.6596e-02 6.8967e-02 5.4750e-02 4.9890e-02 7.4420e-02 7.3995e-02 7.2128e-02
+ 4.1691e-02 -nan(ind) -nan(ind) 3.9378e-02 -nan(ind) 8.1627e-02 6.5487e-02 5.2881e-02
+ 9.8908e-02 8.8967e-02 4.7608e-02 6.9080e-02 5.4398e-02 1.0152e-01 7.7226e-02 4.4199e-02
+ 4.6305e-02 8.8142e-02 7.0320e-02 7.2858e-02 8.3872e-02 6.5635e-02 6.0058e-02 7.4997e-02
+ 6.8000e-02 -nan(ind) 4.8074e-02 -nan(ind) 5.3213e-02 8.2498e-02 1.0411e-01 7.4114e-02
+ 4.4831e-02 9.4929e-02 1.0540e-01 5.1443e-02 6.0744e-02 6.5714e-02 9.2130e-02 1.2549e-01
+ 6.0167e-02 7.7453e-02 -nan(ind) 8.0317e-02 6.4823e-02 -nan(ind) 5.3823e-02 -nan(ind)
+ 7.5128e-02 4.9088e-02 -nan(ind) 1.1775e-01 7.7086e-02 4.9807e-02 6.4979e-02 1.5476e-01
+ 1.0175e-01 5.8279e-02 4.9061e-02 6.5521e-02 4.6693e-02 5.5934e-02 1.0084e-01 7.8509e-02
+ 4.6128e-02 6.8151e-02 4.1656e-02 6.6734e-02 7.2433e-02 5.8092e-02 6.9688e-02 1.0215e-01
+ 7.6580e-02 6.9471e-02 6.8381e-02 5.4518e-02 7.7911e-02 -nan(ind) 5.1633e-02 8.6087e-02
+ 8.5966e-02 6.7812e-02 5.8593e-02 7.6315e-02 5.2466e-02 5.7441e-02 -nan(ind) 4.4695e-02
+ 6.2482e-02 8.7414e-02 5.0393e-02 6.9213e-02 8.2508e-02 6.3708e-02 5.6519e-02 4.6628e-02
+ -nan(ind) 6.0863e-02 7.1460e-02 7.2866e-02 5.1158e-02 -nan(ind) -nan(ind) 5.0768e-02
+ 5.0073e-02 6.3357e-02 6.0230e-02 -nan(ind) 5.4826e-02 4.8231e-02 5.6539e-02 1.2358e-01
+ 5.7860e-02 5.7898e-02 6.4293e-02 5.2763e-02 5.1208e-02 6.6021e-02 7.0635e-02 6.2858e-02
+ 5.1882e-02 8.4278e-02 5.0405e-02 -nan(ind) 6.5563e-02 6.3737e-02 -nan(ind) 4.9289e-02
+ 1.0855e-01 5.3071e-02 1.0502e-01 5.9294e-02 6.7717e-02 5.3746e-02 7.4979e-02 1.1443e-01
+ 6.3605e-02 6.4936e-02 7.4963e-02 6.1285e-02 8.1636e-02 5.4517e-02 6.0306e-02 5.2350e-02
+ 7.6735e-02 5.3212e-02 6.1626e-02 6.3533e-02 -nan(ind) 5.3153e-02 5.4629e-02 -nan(ind)
diff --git a/src/sas/sasview/test/convertible_files/YBCO_12685__ISIS2D.txt b/src/sas/sasview/test/convertible_files/YBCO_12685__ISIS2D.txt
new file mode 100644
index 0000000..e3182a8
--- /dev/null
+++ b/src/sas/sasview/test/convertible_files/YBCO_12685__ISIS2D.txt
@@ -0,0 +1,1184 @@
+ SANS2D Sun 20-MAY-2012 11:32 Workspace: 12685rear_2D_8.0_16.5
+ 6 q (1/Angstrom)
+ 6 q (1/Angstrom)
+ 0 Cross Section (1/cm)
+ 1
+ Nb + YBaCuO 10K 0.5T 2.5deg CW
+ 69
+ -2.550000e-02 -2.475000e-02 -2.400000e-02 -2.325000e-02 -2.250000e-02 -2.175000e-02 -2.100000e-02 -2.025000e-02
+ -1.950000e-02 -1.875000e-02 -1.800000e-02 -1.725000e-02 -1.650000e-02 -1.575000e-02 -1.500000e-02 -1.425000e-02
+ -1.350000e-02 -1.275000e-02 -1.200000e-02 -1.125000e-02 -1.050000e-02 -9.750000e-03 -9.000000e-03 -8.250000e-03
+ -7.500000e-03 -6.750000e-03 -6.000000e-03 -5.250000e-03 -4.500000e-03 -3.750000e-03 -3.000000e-03 -2.250000e-03
+ -1.500000e-03 -7.500000e-04 0.000000e+00 7.500000e-04 1.500000e-03 2.250000e-03 3.000000e-03 3.750000e-03
+ 4.500000e-03 5.250000e-03 6.000000e-03 6.750000e-03 7.500000e-03 8.250000e-03 9.000000e-03 9.750000e-03
+ 1.050000e-02 1.125000e-02 1.200000e-02 1.275000e-02 1.350000e-02 1.425000e-02 1.500000e-02 1.575000e-02
+ 1.650000e-02 1.725000e-02 1.800000e-02 1.875000e-02 1.950000e-02 2.025000e-02 2.100000e-02 2.175000e-02
+ 2.250000e-02 2.325000e-02 2.400000e-02 2.475000e-02 2.550000e-02
+ 69
+ -2.550000e-02 -2.475000e-02 -2.400000e-02 -2.325000e-02 -2.250000e-02 -2.175000e-02 -2.100000e-02 -2.025000e-02
+ -1.950000e-02 -1.875000e-02 -1.800000e-02 -1.725000e-02 -1.650000e-02 -1.575000e-02 -1.500000e-02 -1.425000e-02
+ -1.350000e-02 -1.275000e-02 -1.200000e-02 -1.125000e-02 -1.050000e-02 -9.750000e-03 -9.000000e-03 -8.250000e-03
+ -7.500000e-03 -6.750000e-03 -6.000000e-03 -5.250000e-03 -4.500000e-03 -3.750000e-03 -3.000000e-03 -2.250000e-03
+ -1.500000e-03 -7.500000e-04 0.000000e+00 7.500000e-04 1.500000e-03 2.250000e-03 3.000000e-03 3.750000e-03
+ 4.500000e-03 5.250000e-03 6.000000e-03 6.750000e-03 7.500000e-03 8.250000e-03 9.000000e-03 9.750000e-03
+ 1.050000e-02 1.125000e-02 1.200000e-02 1.275000e-02 1.350000e-02 1.425000e-02 1.500000e-02 1.575000e-02
+ 1.650000e-02 1.725000e-02 1.800000e-02 1.875000e-02 1.950000e-02 2.025000e-02 2.100000e-02 2.175000e-02
+ 2.250000e-02 2.325000e-02 2.400000e-02 2.475000e-02 2.550000e-02
+ 68 68 1.000000000000e+00
+ 3(8E12.4)
+ 1.4387e-01 -1.1860e+00 2.2213e-01 0.0000e+00 1.4101e-01 -3.0026e-01 1.4388e+00 -3.5062e-01
+ 3.2003e-01 1.6894e-01 3.6212e-02 0.0000e+00 -9.9851e-01 -2.8757e-01 6.1521e-01 -5.4004e-01
+ -2.6275e-01 9.3031e-02 -5.5918e-01 1.5796e-01 -6.0635e-02 6.9406e-02 5.8132e-01 -2.4103e-01
+ -8.9020e-01 2.8037e-01 9.4007e-01 -8.6712e-01 5.2639e-01 3.0609e-01 -2.7414e-01 -4.9319e-01
+ 1.4812e-01 -4.0854e-01 2.4445e-01 2.3358e-01 -6.8426e-01 -3.9550e-01 1.0192e-03 -5.6476e-01
+ 3.7885e-01 -1.3294e+00 -5.9166e-01 3.8655e-01 -2.3577e-01 2.3046e-01 3.8052e-01 1.1434e+00
+ 2.4850e-01 -7.0055e-01 0.0000e+00 -8.6796e-01 -4.6390e-01 1.4822e-01 6.6170e-01 -8.8851e-01
+ -2.9694e-01 -5.3768e-01 1.9956e-02 -3.7854e-01 -7.4004e-01 -6.3471e-01 -5.0358e-01 -3.7487e-01
+ 3.3566e-01 -3.1049e-01 -3.2594e-01 -1.3677e+00 -5.9514e-01 3.7183e-01 1.5846e-01 -4.9908e-01
+ 6.5831e-01 4.6078e-01 -3.1661e-02 2.7506e-01 5.6851e-01 1.6502e-02 3.6482e-02 -5.1545e-01
+ 1.9992e-02 -7.7476e-01 -3.0582e-01 3.3569e-01 -6.5183e-02 -1.0847e-01 4.3513e-02 4.2341e-01
+ -6.1212e-01 1.0630e-01 -1.3977e+00 -1.6396e-01 -2.3267e-01 -3.2830e-01 4.2063e-01 -8.2309e-01
+ -4.8062e-01 3.0831e-01 -4.2373e-01 6.3705e-01 1.2962e-01 -6.8304e-02 -4.5751e-01 -8.2813e-01
+ -5.8253e-01 1.7458e-02 -2.8554e-01 3.9609e-02 8.8192e-01 3.4264e-01 -1.2180e+00 -2.0846e-01
+ 3.2587e-01 3.4977e-01 -4.8944e-01 7.3723e-01 1.6544e-02 3.7943e-01 7.1389e-01 5.6309e-02
+ 8.0877e-01 5.9120e-02 -4.7339e-01 -8.7873e-01 -6.6154e-01 2.5098e-02 1.1272e+00 -5.8493e-01
+ -5.0019e-01 4.3834e-01 -6.2891e-01 -1.9754e-01 -3.9251e-01 7.4153e-02 2.3901e-01 -6.2732e-01
+ -3.0718e-02 1.5877e-01 -1.6717e-02 -8.9997e-01 3.3530e-02 3.8421e-01 9.1017e-01 3.7225e-02
+ -3.8472e-01 2.3828e-01 -2.7511e-01 -5.0246e-01 -5.0885e-01 -1.1410e-02 -6.6646e-01 5.1380e-01
+ -9.5983e-01 -1.7985e-01 -1.8110e-01 1.2217e-01 5.6299e-01 9.4178e-01 4.0794e-01 5.5786e-01
+ -2.6563e-01 3.7638e-01 -6.2780e-01 -2.6616e-01 4.6449e-01 7.9586e-01 -1.2802e+00 -2.0056e-01
+ 4.6283e-01 1.5466e-01 4.1749e-01 -3.4986e-01 2.3357e-01 1.1085e-01 -3.9108e-01 -1.3440e-01
+ 1.9713e-01 -1.7007e-01 1.9438e-01 -7.1820e-01 -1.1761e+00 -4.7876e-01 3.8675e-01 -1.1348e-02
+ 1.0867e-01 1.4630e-01 9.9545e-01 2.6898e-02 4.7260e-01 2.7605e-01 5.2576e-01 1.5575e-01
+ 3.7752e-01 -7.5359e-01 3.4534e-01 3.0330e-01 -7.4313e-01 3.2083e-01 5.7497e-01 -8.7271e-01
+ 8.1069e-01 -4.2544e-01 -3.2930e-01 -2.4694e-01 3.6887e-01 -3.6198e-01 3.4866e-01 -3.1095e-01
+ -3.5679e-01 2.5891e-01 3.5710e-01 -2.7289e-01 1.6183e-01 4.4299e-01 -3.1525e-01 1.0706e+00
+ -1.8723e-01 3.9145e-01 -6.9368e-01 -1.5817e-01 -1.4168e-01 -2.1154e-01 8.7440e-01 3.7433e-01
+ -1.2986e+00 4.8517e-01 1.3945e-01 0.0000e+00 1.4504e-01 1.1005e+00 -5.3547e-01 1.5079e-01
+ -7.1596e-01 8.7781e-01 4.0323e-02 -1.0168e+00 7.3007e-01 8.8391e-01 4.5551e-01 1.1181e+00
+ -1.1316e+00 -3.2759e-01 7.3188e-01 -8.1813e-01 3.1203e-01 1.0075e+00 -3.5043e-01 -3.7952e-01
+ 3.9468e-01 2.3892e-01 6.4726e-01 2.2452e+00 1.0416e+00 1.0213e+00 3.9638e-01 4.4952e-02
+ 7.0129e-01 2.7144e-01 6.4894e-02 -3.3749e-01 2.8469e-01 4.2525e-01 -3.9453e-01 -7.7540e-01
+ 2.2993e-01 -3.5089e-01 6.3389e-01 -7.9792e-01 1.2421e+00 9.5937e-01 7.3827e-04 -1.0333e+00
+ 1.2623e-02 -2.9705e-01 -1.4993e-01 1.2161e+00 0.0000e+00 0.0000e+00 -8.0328e-01 -2.0603e-01
+ 2.0306e-02 6.0103e-01 4.1853e-01 2.5236e-01 7.4251e-01 1.8089e+00 8.4068e-02 7.9474e-01
+ 4.1564e-01 -3.3472e-01 4.9155e-01 -4.8483e-01 -3.2593e-01 1.3189e+00 -1.3096e-01 5.6120e-01
+ -1.0730e+00 -1.6758e+00 -1.2318e-01 2.4898e-01 -9.4597e-02 -1.0314e-02 2.7310e-01 -3.0786e-01
+ 9.9660e-03 -4.0146e-01 -3.6647e-01 1.2539e+00 8.9840e-01 4.0198e-02 1.2002e+00 -1.4016e+00
+ 1.0692e+00 -4.1184e-01 -1.2816e+00 0.0000e+00 -2.0577e+00 3.9400e-01 2.3187e-01 -2.2876e-01
+ -3.8182e-01 1.1458e-01 6.7397e-01 2.2689e-01 3.3266e-01 -1.9455e-01 4.1879e-02 -1.3232e+00
+ 1.0074e+00 4.3410e-01 -3.9600e-01 0.0000e+00 3.0643e-01 1.2252e-01 1.9781e-02 -1.0146e-01
+ -1.4057e+00 -1.0192e+00 9.2160e-01 6.4877e-01 1.2050e-01 -1.8561e-01 -3.1863e-01 -9.1236e-01
+ 0.0000e+00 1.7243e-02 1.5233e-01 3.6540e-01 -5.7006e-01 -8.5853e-01 -2.5761e-03 6.8658e-01
+ -1.5774e-01 -7.5669e-01 2.5255e-01 -3.8128e-01 -9.6533e-01 -4.4838e-01 -8.8761e-02 -1.0685e+00
+ 1.6830e-02 1.4850e-01 -2.4433e-01 4.1218e-01 5.3488e-01 6.8132e-01 1.3210e-01 -5.8970e-01
+ 1.4903e+00 -5.2244e-01 1.5931e-01 -2.3082e-01 -1.0120e+00 1.8933e+00 -6.7311e-01 -3.4307e-01
+ -3.7889e-01 -7.5691e-02 7.1907e-01 1.2901e+00 3.3729e-01 -6.5022e-01 -3.7235e-01 1.8538e-02
+ -2.7559e-01 -8.3352e-02 -5.5874e-01 -6.2903e-01 7.0634e-01 -7.7588e-01 -1.1768e+00 2.9744e-02
+ -4.6626e-01 -4.4219e-01 -5.6585e-01 -8.5853e-01 -8.4455e-02 4.0430e-01 -1.8075e-01 1.0775e-01
+ -1.8937e-01 1.0861e+00 9.7301e-01 0.0000e+00 -4.6590e-01 -3.4428e-01 1.9896e-01 6.6665e-01
+ 6.7412e-03 2.9045e-01 -2.4915e-01 -3.1006e-01 -5.8683e-01 3.7296e-01 -1.3616e-01 1.8766e-01
+ -5.1129e-01 -2.7252e-01 1.2285e-01 -8.6815e-02 -7.6487e-01 -4.6091e-02 3.4622e-01 -3.9190e-01
+ -3.2172e-01 1.5161e-01 -3.7110e-01 2.3636e-01 -6.3505e-01 7.4224e-01 1.1069e+00 1.0956e+00
+ 8.0927e-01 1.0885e+00 -1.2336e-01 5.9383e-01 2.1281e+00 5.9946e-01 3.3162e-01 3.9561e-01
+ 1.7154e+00 7.1205e-01 -1.1762e-01 -7.2947e-02 1.8270e-01 7.1583e-01 -2.5069e-01 6.3193e-01
+ -9.6351e-01 -3.4256e-01 9.6423e-01 1.0005e-01 -2.6997e-01 -4.2885e-01 -8.9232e-02 -5.5245e-01
+ 3.2623e-01 -3.9169e-01 -1.2703e+00 2.8357e-01 -1.1392e+00 -8.7608e-01 -6.2160e-01 3.9763e-01
+ -8.3404e-01 1.6336e-02 -1.3460e-01 -6.7319e-01 1.7885e-01 -2.9370e-01 1.1493e+00 -4.0682e-01
+ 2.1548e-01 3.6474e-01 3.4051e-01 2.4226e-01 -6.4679e-01 3.3425e-02 4.2705e-01 -9.9252e-01
+ -1.1548e-01 3.6025e-01 1.4856e+00 6.9816e-01 1.9495e-01 4.9288e-01 1.7334e-01 -6.9904e-02
+ -2.8558e-01 4.0710e-01 5.2981e-01 3.5152e-01 -2.4414e-01 2.9204e-01 4.7196e-01 -6.4008e-01
+ -5.0394e-01 8.0811e-01 -1.1811e+00 -3.0178e-01 1.6070e+00 -1.9709e-01 4.4872e-01 3.7379e-01
+ 3.2771e-02 -5.7603e-01 7.3996e-01 -1.3261e-01 -7.9828e-01 -1.3181e+00 -2.0779e-01 -2.5333e-01
+ 2.7298e-01 3.8409e-01 -5.0954e-01 -2.5652e-01 -7.0246e-01 -1.4569e+00 6.4936e-01 6.5224e-01
+ 9.6500e-01 -7.9442e-02 4.4563e-01 3.3112e-01 -2.3686e-01 -1.4241e+00 -6.7504e-01 -5.3265e-01
+ 8.7168e-01 -7.9506e-01 4.4002e-01 -6.2475e-01 -4.7958e-02 1.6797e-01 2.9700e-01 -6.5920e-01
+ 2.7431e-01 3.4686e-01 1.5981e-01 -6.2141e-01 -3.0516e-01 -2.9002e-01 1.5451e-01 4.1713e-01
+ -6.2090e-01 0.0000e+00 -1.7619e-01 5.5510e-01 -2.8341e-01 -1.5465e-02 -5.4898e-01 -4.9770e-01
+ -9.9793e-02 3.4385e-02 -1.0679e-01 7.2187e-02 6.3417e-01 -1.6995e-01 -3.4130e-01 6.5362e-01
+ -7.4682e-01 -1.5807e+00 2.1335e-02 -9.3114e-01 -4.5214e-01 -3.6278e-01 -1.1421e-01 5.5913e-01
+ 8.3369e-01 9.2825e-01 -4.7951e-01 -6.1735e-01 8.8888e-01 1.6540e-01 8.9907e-01 -6.5943e-01
+ -8.3566e-01 1.4593e-01 1.9981e-01 1.7921e+00 -7.1151e-01 1.9408e+00 8.7855e-01 -6.4840e-01
+ 4.7559e-01 7.6647e-01 -1.9312e-01 -1.1306e+00 1.0164e+00 3.6945e-02 -1.1960e-01 -1.3553e+00
+ 3.8410e-01 4.1576e-01 -1.3949e+00 5.2666e-01 -5.8230e-01 1.6094e-01 8.2882e-01 5.8113e-01
+ -3.4223e-01 -9.7295e-01 3.8143e-01 2.4465e-01 8.9758e-01 3.1232e-01 4.8786e-01 4.3206e-01
+ 1.8547e-01 2.1010e-02 2.0396e-02 -3.3484e-01 4.9554e-02 -3.2730e-01 -6.3798e-02 1.5636e-01
+ 3.9112e-01 -3.4080e-01 -5.8163e-02 -4.7796e-01 3.6974e-01 -2.5964e-01 -3.0047e-01 -1.2796e-01
+ 1.0366e-01 -1.1597e-01 2.2721e-01 -8.3751e-01 6.2497e-01 -2.8824e-01 1.0860e+00 -4.5365e-01
+ -1.0207e+00 5.1761e-01 -1.7580e-01 -2.4346e-01 6.1064e-02 -5.3198e-01 -1.1616e-01 3.6665e-01
+ -8.7205e-01 8.4497e-01 -8.9668e-01 -4.0127e-01 1.4480e+00 -8.2697e-01 -7.0998e-01 -3.9980e-01
+ -8.2530e-01 3.4864e-01 -7.8332e-02 4.1365e-02 2.7034e-02 5.7229e-01 1.0762e+00 5.2549e-01
+ 1.7305e-01 -3.8026e-01 8.0684e-01 3.7085e-01 -9.0076e-01 -7.7306e-01 3.7421e-01 -1.4252e-01
+ 3.4772e-01 7.5466e-01 1.6638e-01 2.2801e-01 -3.9137e-01 1.6435e-01 -2.9838e-01 -4.1279e-01
+ -1.0591e-01 -7.6106e-01 -2.4160e-01 -2.2941e-01 7.9187e-02 0.0000e+00 -1.2436e-01 -2.6395e-01
+ -8.9457e-01 -1.1426e+00 -1.4831e-01 2.3728e-01 2.9936e-01 6.6332e-03 1.0716e-01 -8.6030e-01
+ -3.5379e-01 1.1363e-01 -3.1621e-01 2.7579e-02 1.4817e+00 -3.3835e-01 -7.8050e-01 -2.3079e+00
+ -8.4366e-01 4.6019e-01 8.4822e-01 -9.7619e-01 -2.0307e+00 -7.4524e-01 -9.3031e-01 2.9093e-01
+ 4.9083e-01 2.5337e-01 7.2933e-01 8.0246e-01 4.8918e-01 1.9003e-01 5.7550e-01 1.1326e+00
+ -1.3512e-01 -1.1392e-01 -2.1608e-01 2.8710e-01 -9.0164e-02 8.0309e-02 1.4719e+00 3.5585e-02
+ -7.4112e-01 3.7610e-01 1.0911e+00 1.6725e-01 -1.7357e+00 4.8239e-01 -2.3216e-01 -1.3208e+00
+ 1.5001e+00 6.3873e-01 -9.5685e-01 4.9566e-01 -6.3591e-01 -9.6808e-01 -1.0515e+00 2.7540e-02
+ 1.3133e-01 1.5332e-01 -8.1986e-01 -4.1819e-01 -1.2183e+00 9.2127e-01 5.1733e-01 1.1317e-01
+ -5.0076e-01 -1.4110e-03 1.1117e+00 -6.7684e-01 6.0708e-01 6.9685e-01 5.4407e-01 -6.6750e-01
+ -1.0293e+00 8.4402e-01 6.2641e-01 5.7821e-01 -3.7712e-01 -1.1497e+00 1.2809e-01 4.4793e-01
+ -5.4375e-01 6.9236e-01 5.1927e-01 -4.0588e-01 -5.5075e-02 -4.6652e-01 -7.8526e-01 8.0610e-01
+ 7.4095e-01 2.5310e-01 7.4436e-01 1.5426e-01 5.6370e-01 -1.2705e+00 -5.8821e-01 -6.7211e-01
+ 4.1219e-01 3.8476e-01 -1.5197e-01 1.4981e+00 8.0159e-01 -5.8733e-01 -3.2015e-01 5.3102e-01
+ 4.5283e-01 3.8869e-02 2.0038e+00 -1.2943e+00 -6.5239e-01 -8.5445e-01 -2.0179e-02 2.2866e+00
+ -3.6824e-01 -8.9962e-01 7.2873e-02 7.4152e-01 -9.4364e-01 1.2150e-01 6.5957e-01 1.3043e+00
+ -7.2360e-01 2.0398e-01 1.0781e-01 -9.4292e-03 -1.5482e-01 4.5728e-01 4.9709e-01 -3.0589e-01
+ -1.1015e+00 1.7937e-02 5.5919e-01 1.3448e+00 -2.6783e-01 -1.0302e-01 3.2360e-01 -2.8964e-01
+ 2.8696e-01 1.9696e-02 1.5701e+00 3.6496e-01 -5.2677e-01 4.9110e-01 3.4782e-01 6.4000e-01
+ 3.0806e-01 7.8844e-01 9.9610e-01 3.1558e-01 1.0542e+00 -5.2827e-01 6.6680e-01 -3.7223e-01
+ -9.8301e-01 -4.8228e-01 -6.8027e-01 1.2455e+00 8.4788e-01 1.2230e+00 1.1693e-01 -4.9892e-01
+ -2.0143e-01 -2.7606e-01 -1.3689e-01 -6.2049e-02 4.6528e-01 -5.2990e-01 1.2173e+00 -7.3659e-01
+ -8.0564e-01 1.3477e+00 3.7588e-01 7.5938e-01 -4.8554e-03 -8.1383e-01 -7.2499e-01 -4.3745e-01
+ 5.5936e-01 -1.6504e+00 1.1533e+00 -1.6514e-01 -1.0120e+00 9.5860e-02 2.5025e+00 -3.6973e-01
+ 8.2476e-01 2.2536e-01 -6.2529e-01 -8.7476e-01 -1.0768e+00 -9.4796e-01 8.0210e-01 -1.5312e-01
+ 5.1502e-01 2.5486e+00 2.2390e-01 1.5417e-02 1.7432e-01 1.6420e-02 9.2823e-01 2.4917e-02
+ -6.8973e-01 4.1887e-01 -1.3870e-01 3.1571e-01 6.9429e-02 7.5065e-01 6.5450e-01 6.6460e-01
+ -1.1756e-01 1.9464e-02 -1.0355e-01 1.8052e+00 6.4086e-01 6.4207e-02 6.1787e-01 -3.4206e-01
+ 4.3703e-01 7.6736e-01 3.3140e-01 -1.3445e+00 1.0510e-01 6.1138e-02 3.3931e-01 -4.9538e-01
+ 9.6656e-01 9.1632e-01 9.6506e-01 6.3707e-01 1.1120e+00 -1.9677e+00 1.1359e+00 -7.9455e-01
+ 5.0528e-01 -5.0857e-01 4.0867e-01 -1.5512e+00 -1.2045e-01 -1.6394e+00 -5.9110e-02 -1.2362e+00
+ -7.5578e-01 -2.0692e+00 -1.0273e+00 6.0904e-01 6.0316e-02 6.0793e-01 -2.7959e-01 -6.9101e-01
+ -1.3968e+00 -3.8725e-01 4.2222e-01 7.1010e-01 -8.3985e-01 -1.0753e+00 4.9271e-01 1.3213e-01
+ -6.1847e-01 -1.3607e-01 5.9231e-01 6.5734e-01 9.3308e-01 -9.4990e-01 -8.6397e-01 5.6538e-01
+ 2.9983e-01 -2.6920e-01 3.4675e-02 1.0603e+00 -6.5144e-02 -5.7160e-01 2.7105e-01 -3.0054e-01
+ 4.4776e-02 -4.4332e-01 3.1577e-01 -6.0379e-01 -4.6294e-01 -6.1477e-01 -2.3785e-01 -5.6878e-01
+ -2.9156e-01 -6.4540e-02 -2.7926e-01 6.8640e-01 -1.0053e+00 -9.3093e-01 4.8763e-01 -6.0634e-01
+ 3.7609e-01 2.0707e+00 2.0649e-01 1.6846e+00 -7.9935e-01 -1.9599e-01 -1.4964e+00 -5.4072e-01
+ -1.9491e-02 -1.7439e-01 2.4317e-02 1.6339e-01 1.1942e+00 -4.3583e-01 -2.7331e-01 -1.7665e+00
+ 3.5997e-01 3.0572e-01 1.0993e-01 8.7637e-01 -5.2777e-01 -1.0974e+00 -3.5972e-01 -4.1973e-01
+ 1.0559e+00 5.5133e-01 1.1173e+00 -4.3944e-01 -3.1447e-02 -9.8692e-02 -1.9226e-01 -2.3820e-01
+ 6.3757e-01 -3.4495e-01 -2.1251e-02 1.7226e-01 -9.9609e-01 -1.2029e-01 3.3286e-01 2.4224e-01
+ -3.2517e-01 1.6132e+00 -3.4289e-02 -1.8220e-01 3.5942e-01 -2.8841e-01 -2.6975e-01 -2.5914e-01
+ 2.8929e-02 -9.2287e-01 -4.1666e-01 -6.2383e-01 4.9635e-02 8.3532e-02 -4.5359e-01 -1.0867e+00
+ -1.3652e+00 -9.0623e-02 9.8659e-01 -2.1326e-01 -3.7885e-02 -2.4547e-01 4.3728e-01 5.0833e-02
+ -1.7981e-01 -5.4436e-01 -7.7253e-02 -6.6881e-01 2.7415e-01 2.9526e-01 3.2946e-01 1.6033e+00
+ -6.4547e-01 -8.1112e-01 -1.4507e+00 -9.3997e-01 -4.6104e-01 9.6048e-01 9.9464e-01 9.0772e-01
+ 4.0667e-01 2.9114e+00 -1.1249e-02 -2.6859e-01 1.0912e+00 7.2002e-01 1.6386e+00 -1.8421e+00
+ -5.6026e-01 -4.1118e-02 6.8393e-01 1.6203e+00 -1.2959e+00 -2.8972e-01 6.4540e-01 8.8201e-01
+ -1.2047e+00 -1.6965e+00 1.2550e+00 -4.3090e-01 -7.8748e-01 5.1944e-01 -1.2549e-01 -2.2045e-01
+ 1.5514e-01 6.2684e-01 -2.6668e-02 1.8925e+00 -1.7298e-01 0.0000e+00 6.0147e-01 -1.1107e+00
+ -3.8262e-01 3.9688e-01 -3.0494e-01 4.9059e-01 -1.1168e+00 9.6494e-01 6.6074e-01 3.2262e-01
+ 1.2448e-01 -2.6293e-01 -2.7941e-01 7.9914e-01 2.0709e-02 5.1092e-01 3.4793e-01 -2.6626e-02
+ -5.5146e-01 7.3193e-01 6.1108e-01 3.3290e-01 1.0959e+00 -2.1741e-01 -4.5397e-01 1.2030e-01
+ 1.0078e+00 -2.5144e-02 -2.7856e-01 5.9305e-01 1.0202e+00 1.9032e+00 1.3557e-01 -8.0300e-01
+ -2.6813e-01 -6.5043e-01 -9.1479e-01 -2.6905e-01 5.9701e-01 -2.2049e+00 -1.8434e+00 6.4151e-01
+ 1.2933e+00 2.6680e+00 7.2214e-01 1.0009e+00 2.6952e+00 -8.8867e-01 1.4705e+00 -2.5931e-01
+ 9.8622e-01 1.9733e-01 1.1628e-01 -1.6573e+00 -5.2352e-01 2.4055e-01 -6.7538e-01 9.7320e-01
+ -1.1664e+00 -2.6306e-01 9.9007e-01 1.0670e+00 -1.0386e+00 3.9072e-01 5.4138e-01 -4.1316e-01
+ 1.3612e+00 -2.7742e-01 6.4221e-01 1.2051e-01 -4.6980e-01 1.9303e-01 1.1390e-01 1.1188e+00
+ 2.9889e-01 3.5808e-01 1.0520e+00 4.8260e-01 6.4567e-01 -9.6801e-02 7.2471e-01 1.1080e-01
+ -1.1581e+00 -3.5474e-01 -2.5054e-01 -3.6158e-01 9.9449e-02 -2.4547e-01 1.9879e-01 9.7475e-02
+ -1.7713e+00 5.0027e-01 -2.6025e-01 4.3515e-01 -1.0067e+00 -6.0384e-01 -6.7632e-01 -1.4876e+00
+ 4.6224e-01 -1.4187e+00 1.2909e+00 1.2260e+00 -9.0502e-02 -1.7225e+00 -3.8962e-01 -8.4680e-01
+ 7.2855e-01 6.9167e-01 8.5213e-01 6.5441e+00 1.6999e+00 2.2890e+00 3.1132e+00 3.1667e+00
+ 1.4564e+00 4.5523e+00 2.9679e+00 1.4038e+00 2.8708e-01 1.3182e+00 1.0715e+00 -1.6076e+00
+ 8.4131e-01 1.8863e+00 -1.1985e+00 8.9958e-01 1.2178e+00 -7.1887e-01 1.0978e+00 1.6032e+00
+ -1.3167e+00 -1.2056e-01 -5.1125e-01 8.5805e-01 3.6287e-01 -1.2418e+00 -3.4282e-01 3.9151e-02
+ -9.7441e-01 7.3915e-01 1.1918e+00 4.7649e-01 -9.2838e-02 1.5990e-01 -5.0353e-01 -3.6376e-01
+ 6.2027e-01 7.2416e-01 3.0742e-01 -5.7422e-01 -1.5597e-01 -3.8860e-01 3.2442e-02 4.3343e-02
+ 5.3627e-01 3.3195e-01 2.9862e-01 7.7658e-01 9.5473e-01 -5.3653e-01 6.8669e-01 -1.0699e+00
+ -3.2819e-01 6.9193e-01 5.0679e-01 7.1947e-01 1.8281e+00 -2.7312e-01 4.8452e-01 -1.4302e+00
+ 1.3561e+00 1.1815e+00 1.2008e+00 2.2111e+00 6.2856e-01 3.2068e+00 6.5068e+00 4.3193e+00
+ 6.4042e+00 4.9724e+00 7.4728e+00 5.3583e+00 5.4944e+00 4.7515e+00 2.9525e+00 1.4967e+00
+ 1.0351e+00 -8.8081e-01 1.0614e+00 -1.3264e+00 -2.7350e-02 6.5644e-01 -3.5879e-01 -1.0924e+00
+ -1.5245e+00 1.0567e+00 -2.3336e-01 -1.4379e-02 1.1800e-02 8.6715e-01 3.2551e-01 -1.5414e-01
+ -1.4445e+00 -7.6240e-01 -7.9529e-01 4.7528e-01 3.2411e-01 9.0400e-01 -5.4773e-01 -7.2380e-01
+ 3.1769e-02 -2.4641e-02 -1.5334e-01 -1.1280e-01 3.4748e-01 -1.1843e-01 -2.2111e-01 -8.5179e-01
+ -1.8066e-01 3.6565e-01 -3.4394e-01 7.9278e-01 1.8511e-02 -1.1467e+00 -5.7938e-01 7.5118e-01
+ 1.3522e-01 1.9339e-01 -1.2116e+00 -1.3216e-01 -3.8486e-01 -1.8972e+00 1.1719e+00 -4.4336e-01
+ 8.7476e-01 1.5167e+00 1.4048e+00 1.3469e-01 2.1110e-01 1.3422e+00 5.8104e+00 9.1239e-01
+ 2.4116e+00 3.4621e+00 4.6959e+00 6.9203e+00 3.6484e+00 4.7005e+00 8.4613e+00 5.8427e+00
+ 6.7749e-01 4.3841e+00 3.1269e+00 -1.3866e+00 -6.4928e-01 3.1133e+00 2.0223e-01 1.9806e+00
+ -8.7443e-01 1.1180e+00 -1.9307e+00 4.5122e-02 -8.1213e-01 -1.1458e-01 -2.1244e+00 -1.2537e+00
+ -5.0375e-02 -2.2476e-01 -7.4880e-01 4.0539e-01 -8.1140e-01 2.0108e+00 -3.5335e-01 3.6810e-01
+ -1.0989e+00 2.3053e-01 1.5386e-01 3.1034e-01 5.1922e-01 4.2873e-01 3.7868e-02 1.0090e+00
+ 2.7192e-01 8.9088e-01 1.0453e+00 -2.1030e-01 -2.0521e-02 7.4578e-01 -9.9104e-02 -6.9427e-01
+ -4.7646e-02 -5.0816e-01 -6.9516e-01 2.5800e-01 -7.2312e-01 -8.4381e-02 -3.1363e-02 2.0228e+00
+ 1.8095e-01 -6.9321e-02 3.3065e-01 -1.8615e+00 2.5152e-01 -2.2038e-01 -1.1430e+00 1.3908e+00
+ 8.9381e-01 4.4751e+00 1.3668e+00 2.9922e+00 1.9772e+00 1.2450e+00 4.0628e+00 2.8927e+00
+ 2.9678e+00 7.1387e+00 4.7889e+00 4.6476e+00 5.3320e+00 1.4590e+00 3.3834e+00 4.9247e+00
+ 2.6882e+00 2.6777e+00 1.5318e+00 3.3269e-01 4.4604e-01 3.1336e-01 1.6623e+00 5.7170e-01
+ 1.4968e-01 -5.3944e-01 7.4193e-01 1.4764e-01 6.8267e-01 9.0107e-01 -1.9412e+00 1.2426e-01
+ 9.3659e-01 -1.3547e-01 -4.0337e-01 -3.5657e-01 -8.4806e-01 1.4532e-01 8.2922e-01 -1.7965e+00
+ 9.4830e-02 -3.2038e-01 -2.8938e-01 1.6745e-01 -1.9678e-01 1.2575e-03 8.6714e-01 2.5013e-02
+ 1.5088e-01 -3.3160e-01 2.0968e+00 2.5720e-01 -1.5056e+00 6.9641e-01 1.6488e-01 -3.7958e-01
+ 6.4899e-01 -1.9216e+00 -8.0956e-01 1.2121e+00 -7.7350e-01 1.4350e+00 6.1096e-01 -2.3586e-01
+ -1.7908e+00 -1.9939e+00 2.1731e+00 2.2270e+00 1.9137e+00 1.5871e+00 6.6026e+00 1.8589e+00
+ 1.0617e+00 -2.0292e+00 1.2523e+00 3.1231e-01 5.8795e-01 -3.6891e+00 4.6231e+00 3.3510e-01
+ 2.6456e+00 2.6671e+00 4.2612e+00 2.2076e+00 5.0537e+00 1.5943e+00 -3.3816e+00 7.9178e-01
+ 5.0295e-02 -7.5530e-01 -6.5786e-01 -1.2915e+00 -5.5411e-02 -2.4926e+00 7.7859e-01 7.5968e-01
+ 2.3497e-01 -4.4218e-01 2.4107e+00 6.7767e-01 5.9344e-01 2.9131e-01 -2.6716e-01 2.3247e+00
+ -5.9126e-01 3.3361e-01 -2.4251e-01 4.8741e-01 -8.1367e-01 2.7528e-01 -2.2821e-01 -2.6682e-01
+ 3.3810e-01 -3.4964e-01 5.0645e-01 -5.5952e-01 -4.0147e-01 4.0168e-01 1.6168e+00 7.9306e-01
+ -5.8895e-01 -1.3741e-01 -7.5473e-01 -3.5308e-01 -9.8702e-01 3.3216e-01 6.2654e-01 2.4967e+00
+ -1.4022e-01 3.6038e+00 4.7889e-02 -9.6479e-01 1.5140e+00 1.8011e+00 6.5080e-01 2.8486e+00
+ 5.6261e+00 6.9805e+00 4.5952e+00 3.2132e+00 -1.1767e+00 4.3342e+00 4.7914e+00 7.4296e-01
+ -7.0010e-01 -6.1277e-01 1.0980e-01 1.9680e+00 1.9575e+00 8.2726e-01 2.4408e+00 1.2200e+00
+ 2.5756e+00 1.6801e+00 6.4847e+00 3.9574e+00 -1.2006e+00 7.5716e-01 -5.8700e-01 -3.1289e-01
+ 1.0643e+00 -1.1219e-01 -9.6708e-01 2.3693e-01 4.0969e-01 -8.3535e-01 9.6121e-03 1.7678e-01
+ 1.5974e-01 -5.3381e-01 -2.4401e-02 4.7726e-01 -1.4723e-01 -1.6808e-01 3.1458e-01 -1.8766e-01
+ 7.5319e-01 1.0321e-02 -8.7182e-01 5.0640e-02 -5.1434e-01 -6.9993e-03 -8.9478e-02 -3.2091e-01
+ 1.4795e-01 -1.9233e-01 4.8655e-01 4.1685e-02 8.0566e-01 4.9476e-01 -6.7256e-02 -4.8915e-01
+ 1.9762e+00 9.9408e-01 -2.4509e-02 3.3574e-01 -1.5167e+00 1.1125e+00 2.2498e+00 6.6731e-01
+ -1.8186e+00 9.7942e-01 2.2807e+00 5.2109e+00 1.2471e+01 3.3323e+00 4.1064e+00 1.6437e+00
+ 5.7510e+00 -2.2083e+00 1.6973e+00 -1.7828e-01 1.5431e+00 -3.8262e+00 9.8276e-01 -1.8263e+00
+ 1.3696e+00 -2.3430e+00 3.1990e+00 2.9701e+00 2.3873e-01 6.0541e+00 3.0500e+00 6.0422e+00
+ 3.9373e+00 5.8187e+00 4.7526e+00 6.2267e-01 -1.3726e+00 5.3586e-01 1.8964e-02 -1.2124e+00
+ -2.2145e-01 8.6410e-01 3.3043e-01 -4.0294e-01 3.2929e-01 -1.7010e+00 3.2997e-01 2.6562e-01
+ -4.5746e-01 -3.2845e-01 1.0224e+00 4.1611e-01 6.3761e-02 -5.8196e-01 -3.8996e-02 1.6901e-02
+ 8.6961e-01 2.1085e-01 7.2207e-02 -6.1232e-01 -1.8286e-01 -5.0038e-02 -7.5680e-02 3.7901e-01
+ 1.4108e+00 -3.4903e-01 -5.4859e-01 8.5772e-01 -1.3516e+00 -1.6386e+00 1.1949e+00 1.9192e+00
+ 5.4177e-01 2.8790e+00 2.3257e+00 3.3232e+00 1.1124e+00 7.8369e-01 9.3165e+00 9.5326e+00
+ 8.8580e+00 6.3279e+00 2.2201e+00 -1.6163e+00 2.5118e+00 1.7807e+00 2.3517e+00 3.6572e+00
+ 2.9149e+00 4.1492e+00 3.6874e+00 2.7405e-01 -5.7522e+00 -8.1459e-01 -2.1628e+00 -4.5291e+00
+ 2.6318e+00 8.7408e+00 4.5244e+00 6.0617e+00 5.9006e+00 3.8323e+00 8.2138e-02 1.8778e+00
+ -2.6400e-01 -1.8040e+00 3.3702e-01 -4.3783e-01 -1.0023e+00 2.0723e+00 1.2841e+00 -2.6990e-01
+ 2.2807e-01 1.6712e-01 1.4864e-01 1.0051e+00 -1.7803e+00 5.5110e-01 -2.1968e-01 8.3082e-01
+ 1.1290e+00 7.1652e-01 5.3432e-01 9.9175e-01 -2.7263e-01 4.3680e-01 -7.0487e-01 -6.7156e-01
+ -8.2124e-01 1.2135e+00 1.8086e-01 7.8860e-01 -5.8148e-01 -9.4070e-01 -2.6958e-01 -9.5719e-01
+ 1.8969e-01 6.9882e-01 -1.8027e-01 4.6620e-01 7.8421e-01 2.5246e+00 -2.6922e+00 2.3380e-01
+ 3.2851e+00 6.1438e+00 1.4449e+01 6.8156e+00 1.0737e+01 3.8269e+00 2.5148e+00 -3.8876e+00
+ 2.8279e+00 7.1612e-01 1.0273e+00 -1.5380e+00 1.1517e+00 8.4552e+00 5.3250e+00 -2.7674e+00
+ 3.6404e+00 7.4585e+00 -3.7342e+00 -2.7515e+00 2.7867e-01 3.4400e+00 6.6180e+00 9.5828e+00
+ 3.3805e+00 2.3832e+00 2.7617e+00 1.9206e+00 1.7181e-01 2.8554e+00 -8.4216e-01 1.3613e+00
+ -1.1208e+00 -9.2333e-01 -1.9640e-01 -8.5512e-01 -1.3946e-01 -1.1358e+00 7.8327e-01 -9.4190e-01
+ -1.1465e+00 4.4864e-01 1.4042e+00 -2.8222e-01 -6.5997e-01 1.8601e-02 -1.0848e-01 6.3028e-01
+ 5.6189e-01 3.1306e-02 2.0910e-01 -1.1091e+00 1.2209e+00 -1.0012e-01 1.1936e-01 -6.3691e-01
+ -2.5300e-01 3.1254e-01 1.9524e-01 4.0015e-01 -1.2669e+00 -7.5664e-02 -1.3882e+00 7.7067e-01
+ 3.2094e+00 -2.0388e+00 -1.7695e-02 1.3857e+00 1.6457e+00 6.0436e+00 9.2698e+00 1.1962e+01
+ 4.3508e+00 3.6083e+00 7.0194e+00 8.3672e-01 -7.1163e+00 1.6544e+00 -1.2194e-01 -1.7782e+00
+ 6.2652e+00 6.3950e+00 7.8609e+00 -1.7411e+00 -4.0743e+00 6.0852e+00 -5.5960e+00 6.8140e+00
+ -1.1467e-01 3.7662e+00 5.7864e+00 9.7486e+00 1.5403e+00 4.1136e+00 2.8297e+00 7.8216e-01
+ -6.8345e-01 -7.9140e-01 -1.4720e+00 5.1406e-01 1.2742e+00 2.8797e-01 -4.7357e-01 1.7752e+00
+ 8.5238e-01 4.1051e-01 2.7421e-01 3.6784e-01 2.3440e-01 1.2469e+00 3.8074e-01 -5.0260e-01
+ -3.0878e-01 3.1774e-01 -2.4166e-01 -1.7600e-01 7.1687e-01 -6.8786e-01 3.6352e-01 -1.5916e+00
+ -2.4167e-01 -8.4299e-02 -6.5710e-01 -4.7963e-01 5.7367e-01 -6.0165e-01 2.5803e+00 1.5392e+00
+ 1.5719e+00 9.2289e-01 -5.6848e-01 -2.0332e+00 -1.2606e+00 -2.8324e-01 -4.9223e-01 3.0082e+00
+ 4.0137e+00 6.7571e+00 6.9662e+00 8.7624e+00 3.2939e+00 -6.9126e-01 4.3176e+00 1.8204e+00
+ 7.2617e+00 1.2108e+00 7.9624e+00 -5.8634e+00 -1.5287e+01 1.3494e+01 -4.2198e+00 -6.3005e-01
+ -1.1260e+01 1.3657e+01 4.4095e+00 1.4035e+00 -9.8502e+00 3.2084e+00 4.3899e+00 4.6993e+00
+ 8.1348e+00 6.6612e+00 6.7240e+00 4.0497e-01 8.8499e-01 -1.9101e+00 -5.0105e-01 -1.9921e+00
+ 4.3681e-01 -9.4534e-02 -3.2836e-01 -2.0312e-01 3.7750e-01 1.2259e+00 7.4488e-01 5.9419e-01
+ -2.8184e-01 5.3924e-01 1.0947e-01 -1.0318e+00 -7.2947e-01 1.5646e+00 -3.4598e-01 -1.7503e-01
+ 5.3043e-01 6.2409e-01 3.8455e-01 -1.8334e-01 1.0290e+00 1.0336e+00 -3.8747e-01 5.8796e-01
+ -2.6367e-01 1.4754e+00 1.2213e-01 -4.7044e-01 1.4057e+00 3.5867e+00 4.7571e-01 2.7804e+00
+ 3.7457e-01 -1.8583e+00 -2.6647e+00 6.8676e+00 8.6827e+00 1.0077e+01 1.4219e+01 1.1280e+01
+ 7.5443e+00 -2.9096e-01 5.5894e+00 1.7936e+00 -8.0099e+00 1.5628e+01 -1.6535e+00 1.8317e+01
+ -5.0938e+01 5.7312e+01 -1.3666e+01 1.7411e+01 -2.1145e+00 2.2963e+00 4.8660e+00 1.9957e+00
+ -4.9064e+00 -4.1795e+00 3.3841e+00 2.0290e+00 2.9482e+00 4.3987e+00 1.2999e+00 4.6495e+00
+ 1.5800e+00 1.4540e+00 8.6769e-02 -3.4401e-01 -3.0849e-01 5.9534e-01 1.7749e-01 -1.0527e+00
+ -2.3469e+00 -1.1720e+00 -1.0187e+00 -6.2629e-01 4.2061e-01 2.5304e-02 -8.4682e-01 -6.4443e-01
+ -3.3787e-01 2.2549e-01 -3.0034e-01 -6.0862e-01 -9.6729e-03 -8.0627e-01 -5.9051e-01 1.0431e+00
+ 4.7512e-01 1.7605e-01 -2.0141e-02 1.1807e+00 -5.9050e-01 1.8935e+00 2.5097e-01 -3.5419e-01
+ -1.8751e+00 -1.1148e+00 2.4153e+00 1.6221e+00 -3.6339e-01 1.2136e+00 6.1451e-01 7.3474e+00
+ 7.6469e+00 1.3488e+00 5.6389e+00 5.2965e+00 2.2705e+00 -5.4782e-01 -4.3954e+00 -8.1692e+00
+ 7.7194e+00 -2.0663e+00 1.0043e+01 3.3419e+01 9.4644e+01 0.0000e+00 0.0000e+00 -5.9495e+00
+ -8.1179e+01 2.0969e+01 -2.6781e+01 4.6367e-02 4.4316e+00 -8.1920e+00 -6.3269e+00 9.7291e+00
+ 9.1004e+00 2.6660e+00 4.0620e+00 3.2316e+00 1.7312e+00 1.6382e+00 -2.8001e+00 2.5143e-01
+ 4.7387e-01 -4.1125e-01 -5.8979e-01 1.0661e+00 -1.5164e+00 8.4316e-01 -5.8132e-01 7.8504e-01
+ 1.3488e-01 -6.6125e-01 8.1178e-02 2.3418e-02 -6.8475e-01 -6.4909e-01 1.2672e+00 1.8224e-01
+ -6.5883e-02 -8.6069e-02 8.9925e-01 7.3534e-01 -6.3298e-02 5.6003e-01 -2.9633e-01 1.2237e-01
+ 9.7255e-02 7.8015e-01 4.7508e-01 1.0906e+00 1.7982e+00 -3.0586e-01 3.0508e+00 1.6776e-01
+ -6.8385e-01 1.9942e+00 -1.4891e+00 4.2522e+00 3.1434e+00 1.0460e+01 9.7499e+00 4.3643e+00
+ 4.1383e+00 -9.8555e+00 -1.0045e+00 -1.0396e+01 -1.1132e+01 -8.9107e+00 2.1468e+02 0.0000e+00
+ 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 3.2387e+01 -6.2700e+01 1.0641e+00
+ -4.6709e+00 -6.3868e+00 -1.4121e+00 -6.2705e+00 9.3575e+00 7.2861e+00 9.6314e-01 2.9193e+00
+ 2.5900e+00 -8.8372e-01 1.2291e+00 -4.3941e-01 2.7647e-02 -7.2597e-01 1.6116e+00 1.2025e+00
+ 1.2092e+00 -5.8781e-02 -3.4022e-03 -7.7998e-01 -3.3736e-02 -1.1969e+00 3.4784e-01 5.3749e-01
+ -5.0558e-02 4.2960e-01 -3.0907e-01 -3.5045e-01 2.3085e-01 2.2221e-02 -1.1037e+00 -2.7929e-01
+ 5.8757e-02 1.3458e+00 -3.0745e-02 9.3258e-01 -5.0709e-01 -1.0385e+00 1.8221e+00 1.1730e+00
+ 1.9737e+00 1.1821e+00 3.0878e-02 -4.6209e-01 9.4059e-01 2.0268e+00 1.4825e+00 1.8500e+00
+ 5.1107e+00 5.6813e+00 3.9308e+00 3.0547e+00 -1.8901e-01 -2.6931e+00 -1.0498e+00 -2.6696e+01
+ -7.5846e+00 -2.1681e+01 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00
+ 0.0000e+00 0.0000e+00 -3.0677e+00 1.1679e+01 -8.0352e+00 -5.5527e+00 3.9293e+00 4.6491e+00
+ 6.2844e+00 5.8084e+00 6.7479e-01 -1.3514e+00 -1.9273e+00 1.4240e+00 -1.0705e-01 3.4218e-01
+ 8.0654e-02 -3.9719e-01 1.2135e+00 1.5571e+00 9.8450e-01 -1.0117e+00 -5.6854e-01 1.2115e-01
+ -9.3383e-01 -1.5491e-02 6.3111e-01 9.9642e-01 1.7165e-01 2.5534e-01 8.3999e-01 -6.5158e-01
+ -1.6826e-01 6.0680e-01 -1.0434e+00 -5.1908e-02 -6.6766e-01 1.8585e+00 -2.9760e-01 3.0664e-01
+ 1.7471e+00 -2.2225e-01 -1.0471e+00 -3.5183e-03 1.7144e+00 8.2318e-01 -8.0645e-01 4.8471e-01
+ 1.3536e+00 -2.3114e+00 1.7749e+00 -2.9241e+00 3.1933e+00 3.7472e+00 8.6657e+00 -3.8506e+00
+ -3.1169e+00 2.5723e+00 -4.7975e+00 -3.7115e+00 -2.5964e+00 0.0000e+00 0.0000e+00 0.0000e+00
+ 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 6.8456e+01 3.1293e+01
+ -8.7610e+00 -1.6123e+00 3.9179e+00 2.2083e+00 -8.6204e+00 8.7775e+00 3.4100e+00 2.7145e+00
+ 4.1800e-01 8.8933e-01 7.3284e-01 4.1939e-02 -8.9062e-01 -4.1397e-01 -1.7826e+00 -1.1836e+00
+ 5.4579e-01 6.5770e-01 -7.6431e-01 -1.2050e-01 1.1586e+00 1.1142e+00 -8.2623e-01 8.1138e-01
+ 1.8101e+00 -9.6843e-01 0.0000e+00 -3.9276e-01 1.2581e-01 -5.7232e-01 6.1040e-01 -8.8675e-01
+ -1.5008e-01 -5.3505e-01 9.8864e-01 7.4094e-01 -8.3988e-01 -2.3184e+00 1.4643e-01 -2.7465e-01
+ -8.2453e-01 8.9753e-01 6.4049e-01 3.6217e+00 6.6214e-01 5.6692e-01 1.5125e+00 1.9054e+00
+ -1.2263e-01 2.2378e+00 -5.0552e-01 3.1726e+00 -5.9342e+00 2.1307e+00 -5.0905e+00 1.1793e+01
+ 1.5395e+01 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00
+ 0.0000e+00 0.0000e+00 0.0000e+00 -5.2500e+01 5.3646e+01 1.5779e+01 -9.6108e+00 5.8930e+00
+ 1.9894e+00 -5.4977e+00 -1.7980e+00 -5.8616e+00 -4.0356e-01 4.2634e+00 -8.7565e-01 -4.8260e+00
+ 3.7270e+00 -1.5776e+00 3.4516e-01 1.1381e-01 2.3123e+00 -3.7722e-01 2.1554e-01 9.0294e-01
+ -3.4293e-01 2.9486e-01 3.2885e-02 -1.1071e+00 8.0292e-01 -3.3850e-01 9.0844e-01 -5.3212e-01
+ -1.3047e+00 -2.8078e-01 3.7355e-01 3.8181e-01 1.8336e+00 -2.9710e-01 1.0103e+00 5.5849e-01
+ 1.6753e-01 7.6460e-01 1.4878e+00 5.8786e-01 -5.3943e-01 1.2685e+00 1.7054e+00 3.2821e+00
+ -2.3080e+00 -2.7041e+00 -1.8104e+00 -3.4489e+00 3.2527e+00 1.3695e+00 7.0481e+00 1.2208e-01
+ -5.7166e+00 -1.5818e+01 -2.6151e+01 5.4552e-01 -1.3015e+01 0.0000e+00 0.0000e+00 0.0000e+00
+ 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 -1.9472e+01
+ -1.2062e+01 8.7621e+00 1.2006e+01 5.0618e+00 7.0983e-02 3.7697e+00 -2.2484e+00 1.7562e+00
+ 5.7645e+00 2.5620e-01 2.9598e+00 4.0310e+00 -3.4430e+00 -1.9300e-01 2.3154e+00 -2.0625e+00
+ 4.0968e+00 -2.2906e-01 -2.5589e-01 1.0958e+00 -1.3620e-01 -4.7687e-01 -9.3601e-01 1.3319e+00
+ 1.6835e-01 -5.7272e-01 6.8630e-01 4.8181e-01 -9.1164e-01 6.3005e-01 9.9863e-01 -1.2754e-01
+ -8.0027e-01 -2.6228e-01 -1.3123e+00 5.0412e-01 1.5094e-01 2.9515e-01 5.5912e-01 -1.3654e+00
+ 1.1923e+00 -8.4448e-01 -8.3937e-01 9.9034e-01 1.1440e+00 2.7563e+00 4.3055e+00 3.8581e+00
+ 3.2874e+00 4.5993e+00 2.1129e+00 1.3348e+00 2.0243e+00 4.2540e+00 5.0662e+00 8.5214e+00
+ -2.9593e+01 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00
+ 0.0000e+00 0.0000e+00 0.0000e+00 4.6219e+01 -3.7258e+01 -1.3350e+01 -1.2391e+00 1.9029e+01
+ -2.7328e+00 3.8402e+00 1.3836e+01 -5.6856e-01 -3.4819e+00 -5.3010e-01 -1.3345e-01 -4.9388e-01
+ 1.6240e+00 -1.2764e+00 7.0910e-01 1.7537e+00 1.9867e+00 -1.0004e+00 -2.4902e-01 -6.0432e-02
+ -1.5673e+00 -1.9594e-01 -2.2361e-01 4.8961e-01 -3.2622e-01 1.2566e+00 -6.6130e-01 5.4317e-01
+ -1.1495e+00 -3.1774e-01 7.8898e-01 8.1236e-02 1.6771e+00 -2.5208e-01 -1.7391e-01 5.0083e-01
+ -7.7416e-01 2.9342e+00 1.6620e+00 1.0399e+00 3.7366e-01 -1.9490e+00 -1.7275e+00 -1.4663e+00
+ -3.7096e-01 -3.3109e+00 8.0583e-01 6.4497e+00 7.5488e+00 9.0620e+00 5.2967e+00 9.0468e+00
+ 7.5563e+00 1.0976e+01 4.3191e+00 1.2100e+01 3.8284e+01 -3.0593e+01 0.0000e+00 0.0000e+00
+ 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 3.4211e+01 1.8967e+01
+ 4.4191e+00 1.3965e+01 -4.9550e+00 -2.2532e+00 3.0682e+00 6.5644e+00 -6.3301e-02 1.8603e+00
+ 2.4713e+00 5.0131e+00 -1.1260e+00 1.6026e+00 3.5758e-01 -1.4391e+00 -4.1847e+00 -1.8033e+00
+ 5.9125e-01 1.3416e+00 1.2427e+00 2.7190e-01 -8.4575e-01 -1.2841e-01 2.0057e-01 -1.2040e+00
+ -5.3962e-01 3.7132e-01 -5.9883e-02 -3.4314e-01 -3.8424e-01 -1.8104e-01 -3.5380e-01 -9.9671e-01
+ -2.4123e-01 4.1790e-01 6.0268e-01 -7.7999e-01 -4.7246e-01 1.3402e-01 7.0429e-01 1.3567e+00
+ -1.0348e+00 -8.3306e-01 -1.4485e+00 -2.6127e-01 1.0786e+00 4.2169e-01 -1.2155e+00 5.6678e+00
+ 6.4368e+00 1.0161e+01 5.3231e+00 -1.8873e+00 6.3435e-01 -1.2852e+01 -2.8102e+00 -1.5219e+00
+ -3.7070e+01 6.3455e+01 3.3408e+01 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00
+ 0.0000e+00 -3.0118e+01 8.2473e+00 -1.3562e+01 -2.2887e+00 1.1920e+01 1.8946e+00 8.4264e+00
+ 2.5110e+00 9.0009e+00 8.0693e-01 6.9864e+00 3.3295e+00 -1.4737e+00 -1.3528e+00 4.3861e-01
+ 3.6106e+00 -6.4474e-02 -5.3418e-01 4.9928e-02 -9.5307e-02 4.5036e-01 1.2304e-01 3.9512e-01
+ -4.1369e-01 1.7021e-01 1.3080e+00 -2.0021e-01 2.3388e-03 1.0125e+00 3.3557e-01 7.5916e-02
+ 1.1284e+00 -3.2808e-01 -2.8100e-01 -1.5395e-01 4.2596e-01 -1.6030e-01 1.7515e-01 -1.0405e+00
+ -8.3901e-01 1.0103e+00 1.1542e+00 5.1337e-01 -9.1436e-01 -2.9417e-01 1.3474e+00 -7.2041e-01
+ -6.1111e-01 -1.8509e+00 1.9403e+00 2.7701e+00 5.5234e+00 6.9990e+00 6.0093e+00 8.0473e+00
+ -4.4329e-01 -3.2805e+00 1.7135e+00 -1.4073e+00 8.8237e+00 1.1522e+01 8.6730e+01 -5.6646e-01
+ 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 1.0046e-01 -1.9750e+01 -1.5617e+01 -2.2047e+01
+ 6.4994e-01 -2.9948e+00 -3.4738e+00 6.4718e+00 6.3680e+00 5.2095e+00 1.8460e+00 -4.2771e-01
+ 3.9188e+00 2.5048e+00 -7.0720e-01 -8.8893e-01 -1.1181e+00 7.9164e-01 -1.2142e+00 -2.6106e-01
+ -2.8272e-01 -8.9210e-01 -9.4080e-02 -1.9080e-01 -1.0389e+00 -5.4074e-01 -2.6223e-01 -1.1524e+00
+ 1.1970e+00 1.6473e-01 -6.9356e-02 1.2657e-01 -1.2981e+00 -1.0227e+00 -1.1845e+00 -1.3897e-01
+ 6.6722e-01 6.0964e-01 -1.0309e+00 -5.2980e-01 -3.4625e-01 7.9960e-01 1.0556e+00 5.7730e-01
+ 5.5181e-01 1.0387e+00 4.0671e-01 9.6533e-01 1.4726e+00 1.2761e+00 -1.6824e+00 2.9106e+00
+ 8.4834e+00 1.3505e+01 1.8504e+01 1.1073e+01 8.1912e+00 7.4245e+00 -3.3145e+00 -4.6983e+00
+ -9.4635e-01 1.4991e+01 1.9910e+01 -9.3100e+00 -7.6735e+00 1.4965e+00 -7.8010e+01 2.1120e+01
+ -2.6521e+01 -1.7770e+00 -5.0800e+00 -5.1369e+00 6.3378e+00 -4.3631e+00 -1.1057e+00 4.2509e+00
+ 1.2053e+01 8.7558e+00 2.5184e+00 6.1252e+00 3.1545e+00 2.0446e+00 9.3734e-01 -5.5479e-01
+ 2.2482e-02 1.7559e+00 -1.1698e+00 3.5230e-01 -2.0366e+00 -8.9792e-01 4.1328e-02 -7.4239e-01
+ -1.6107e+00 5.8997e-01 6.0962e-01 -9.2167e-01 1.5396e+00 8.5821e-02 1.9965e-01 -3.8446e-01
+ 2.9224e-01 -1.6067e-01 3.4957e-01 6.5653e-01 5.5870e-02 1.4442e+00 -2.5401e-02 -2.8795e-01
+ -6.9826e-01 2.9886e-01 2.0167e+00 -1.7482e-01 6.8453e-01 1.7414e+00 -5.2833e-01 1.7776e-01
+ -1.2072e-01 4.3027e-01 1.0822e+00 4.8107e+00 9.9218e+00 1.6796e+01 1.6788e+01 2.2810e+01
+ 1.4967e+00 1.6646e+00 -1.5933e+00 -3.2863e+00 5.0337e+00 -9.0927e+00 -7.4230e+00 3.2286e+01
+ -2.5143e+01 -7.3818e+00 1.2023e+01 -5.8129e+00 9.2123e+00 1.4890e+01 4.3753e+00 -5.4698e+00
+ -6.7896e+00 3.2794e-01 1.3049e+01 7.5188e+00 1.2113e+01 1.1703e+01 3.7014e+00 1.6436e+00
+ 6.9923e-01 9.0889e-01 2.6005e+00 -9.9728e-01 -9.0083e-01 1.7954e-01 -8.5485e-01 -1.8474e+00
+ -3.6636e-02 5.7809e-01 1.1341e+00 5.3200e-01 1.1318e+00 5.5972e-01 1.6682e-01 -7.7224e-01
+ -4.9245e-01 -1.2925e+00 -1.4076e+00 5.5789e-01 -3.1017e-01 -6.6210e-01 -5.4817e-01 6.6396e-01
+ -6.0624e-01 -7.1292e-01 5.7849e-02 1.1377e+00 -2.1694e-01 3.7845e-01 -1.6412e+00 -1.3058e+00
+ 6.2543e-02 2.1184e+00 1.1689e+00 1.3588e+00 -6.0172e-01 1.1329e+00 1.5775e+00 2.8192e+00
+ 1.2966e+01 1.7076e+01 2.3880e+01 1.9650e+01 1.3840e+01 8.6757e+00 6.4796e+00 -1.3038e+00
+ -5.8698e+00 -2.8981e+00 -4.0260e+00 -1.4232e+01 5.2357e+00 2.7960e-01 2.4211e+01 -7.6878e+00
+ 1.6094e+01 2.9968e+00 5.9146e+00 -2.4827e+00 1.3443e+00 8.5095e-01 1.2382e+01 1.0335e+01
+ 1.8874e+01 7.6303e+00 4.2106e+00 1.8407e+00 3.2132e+00 7.5057e-01 1.5154e+00 -2.9942e-01
+ -1.2928e+00 -2.1758e-01 -2.9474e-01 4.1199e-01 -1.3522e+00 -3.5836e-01 -1.8793e-01 -3.0883e-01
+ 3.7077e-01 -1.4628e+00 -8.8090e-01 4.6655e-02 -5.1406e-02 3.9763e-01 -5.7236e-01 -2.1068e-01
+ -4.6889e-01 -2.7118e-01 -8.1603e-02 2.0089e-02 -2.1276e-01 1.9945e-02 -1.3538e-01 -7.2439e-01
+ 1.0106e+00 -8.4553e-02 1.0230e+00 -6.8268e-01 6.7938e-01 -1.5974e+00 1.6488e+00 1.0339e+00
+ 1.1101e+00 1.0980e+00 6.4366e-01 1.4931e+00 3.8180e+00 1.5231e+01 2.0307e+01 2.7738e+01
+ 1.4746e+01 1.4045e+01 1.5913e+00 9.1390e-01 5.0540e+00 7.7227e+00 8.3324e+00 -1.7013e+00
+ 2.1843e+00 5.9105e+00 6.1808e+00 -4.2150e+00 1.3133e+00 4.2266e+00 1.1013e+00 6.6414e+00
+ 3.9241e+00 3.9650e+00 7.7210e+00 1.4738e+01 1.2495e+01 1.0482e+01 4.9184e+00 1.4433e+00
+ -3.8462e-01 -4.2434e-01 -9.5219e-01 -6.4243e-01 1.5947e+00 -1.1884e+00 -1.0565e+00 -4.7376e-01
+ -4.4265e-01 1.3021e+00 7.0531e-01 8.2803e-02 -1.2040e-01 7.7450e-01 -8.8358e-01 2.2634e-03
+ 8.4271e-01 -2.0105e-01 4.4114e-01 1.6572e-01 1.2030e-01 -6.9249e-01 8.4886e-01 6.6094e-01
+ -2.1252e-01 1.5965e-01 -8.5839e-01 -1.0167e+00 -9.3107e-01 -1.1221e+00 1.2003e+00 9.3390e-01
+ 1.3274e-01 -8.8009e-02 1.4852e-01 1.1098e+00 2.1388e-02 9.9611e-04 -1.8970e-01 3.4561e+00
+ 5.1068e+00 9.9742e+00 1.5298e+01 1.8420e+01 2.1058e+01 1.3676e+01 4.1291e+00 1.6808e-01
+ -2.2150e+00 -3.0857e+00 -1.5701e+00 -1.0548e+01 -3.6782e+00 4.2042e+00 -1.1536e+01 5.6380e+00
+ 2.1733e+00 5.8273e-01 2.2227e-01 1.6123e+00 6.0374e+00 1.0920e+01 1.0661e+01 1.2722e+01
+ 6.9839e+00 3.5695e+00 -1.3551e+00 2.6732e-01 1.6269e+00 4.5974e-01 2.1734e+00 -5.5439e-02
+ 1.5967e+00 -1.1233e+00 -4.2720e-01 -5.1713e-01 -2.9458e-02 -9.0691e-01 -5.5869e-01 3.4946e-02
+ -8.7667e-01 1.7919e-02 -7.5101e-01 2.1188e-01 -3.0667e-01 3.9353e-01 -5.3964e-01 3.4857e-02
+ 4.8925e-01 6.4205e-01 -6.0361e-02 3.0180e-01 -2.1765e-01 -7.2383e-02 2.1696e-01 -4.9527e-04
+ 7.2189e-01 4.1387e-01 9.7448e-01 1.0140e+00 -1.3160e+00 -5.1630e-01 2.3441e-01 -1.2571e+00
+ -1.8324e-01 1.7265e-01 6.3195e-01 -3.4672e-01 -1.6967e-01 2.9720e+00 4.7034e+00 1.3342e+01
+ 1.3955e+01 1.3282e+01 3.5301e+00 -1.4171e+00 5.1415e+00 -4.3944e+00 5.6027e+00 1.2780e+00
+ -2.2954e+00 1.5613e+00 1.2491e+00 1.0578e+00 2.5654e+00 2.0510e+00 5.6621e-01 -3.9708e-02
+ 5.1244e+00 1.1844e+01 1.1175e+01 8.4760e+00 7.4401e+00 1.3782e+00 -1.5500e+00 2.8594e-01
+ 8.2435e-01 5.6275e-01 1.3853e+00 2.0340e-01 7.6557e-01 -9.5551e-01 -1.0025e+00 -2.1310e-01
+ 1.8884e-01 -1.2701e-01 -5.2958e-01 6.1334e-01 4.3932e-01 2.5077e-01 1.0925e+00 1.4539e-01
+ -5.3839e-02 1.4815e+00 -6.2204e-01 3.7409e-01 8.4615e-01 -8.4918e-01 2.2698e-01 5.5491e-01
+ -5.2211e-01 -2.6876e-01 -1.8953e-01 -3.3271e-01 -5.5738e-01 3.1745e-02 -5.4456e-01 5.4327e-01
+ 1.4018e+00 -1.5395e+00 -1.2651e+00 -1.1900e+00 1.2784e+00 -5.8751e-02 1.6670e+00 3.9391e-01
+ 7.4728e-01 6.9207e+00 6.6611e+00 7.8740e+00 7.3249e+00 8.9405e+00 6.2419e+00 3.1207e+00
+ 6.9456e+00 6.0955e+00 -2.9763e+00 1.2534e+00 -1.1422e+00 -3.9096e+00 1.9355e+00 1.3802e+00
+ 4.0317e+00 9.9758e-01 1.9128e+00 7.2159e+00 6.6756e+00 8.1108e+00 1.4452e+01 8.3490e+00
+ 2.4909e+00 2.8192e+00 2.0486e+00 -9.0700e-01 -9.2717e-01 -8.6093e-02 2.5136e-01 1.1295e-01
+ 1.2433e-01 1.6782e+00 -5.4927e-01 -4.2585e-01 -1.2012e+00 6.7090e-01 1.5453e+00 3.9892e-02
+ -2.8612e-01 -3.9968e-02 -3.9023e-01 4.4051e-02 2.5450e-01 3.3013e-01 2.0826e-03 -2.8306e-01
+ 3.4373e-01 5.4807e-01 1.5569e-01 -1.1589e+00 2.0104e-01 -5.0141e-01 1.5622e-01 1.0217e+00
+ -1.1634e-01 3.3915e-01 3.5783e-01 5.6776e-01 -3.2281e-01 -8.1429e-01 -8.1203e-01 1.9654e+00
+ -1.1579e+00 -5.2096e-01 -1.3349e+00 -6.6694e-01 -1.2645e+00 -1.0310e+00 -1.5894e+00 3.6471e+00
+ 7.0010e+00 7.9187e+00 7.1901e+00 4.5826e+00 2.2260e+00 1.4741e+00 5.0941e+00 3.0039e+00
+ -3.3344e+00 1.7189e+00 4.8583e+00 2.7443e+00 4.8926e+00 7.2705e+00 5.7540e+00 8.3180e+00
+ 5.4994e+00 5.2630e+00 9.4456e+00 1.3983e+00 3.4121e+00 3.1778e+00 -1.3474e+00 3.2781e+00
+ 2.2390e+00 -3.1940e-01 -2.9128e-01 5.9946e-01 -8.1435e-01 1.3794e-01 6.5905e-01 -3.6152e-01
+ 4.8012e-01 -9.6030e-01 1.3152e+00 3.7571e-01 6.5366e-01 -3.5655e-01 8.7529e-01 3.9827e-01
+ -2.9050e-01 2.9486e-02 1.7433e-02 6.3930e-01 -3.9117e-01 0.0000e+00 -4.3339e-01 -5.1664e-01
+ -4.9479e-01 1.1388e+00 7.4796e-02 4.8146e-02 -1.6409e+00 -3.1928e-01 -7.5418e-01 3.4677e-01
+ 1.2052e-01 -2.2064e+00 -1.7619e-02 -7.8859e-01 -8.9724e-01 1.5625e+00 1.1849e+00 -1.6038e+00
+ 2.9375e-02 -1.7216e-01 -1.3190e+00 1.3134e-01 4.8514e+00 5.8045e+00 3.5952e+00 7.5392e+00
+ 7.9756e+00 7.3474e+00 8.0466e+00 5.9973e+00 7.9142e+00 3.3854e+00 1.1740e+01 -2.0897e+00
+ 1.2768e+00 7.6534e+00 9.9729e+00 3.4981e+00 2.8816e+00 3.6487e+00 6.5252e+00 1.1020e-01
+ 1.6820e+00 5.7659e-01 2.1488e-01 -1.4611e+00 -5.7094e-01 1.1990e+00 -1.4646e-01 4.3446e-01
+ -6.4338e-01 5.0441e-01 2.2520e-01 7.5816e-01 -7.6248e-01 -3.9336e-01 3.6887e-01 -1.4322e+00
+ -1.6396e+00 7.8721e-01 3.6892e-01 5.0892e-02 -9.7259e-03 0.0000e+00 -3.5184e-01 -6.4345e-01
+ -5.7267e-01 -1.6426e+00 -1.3744e-01 1.4861e-01 -2.0788e-01 -4.1227e-01 -1.7909e-02 4.5002e-01
+ 3.7402e-01 -6.1419e-02 -1.2545e+00 1.8125e+00 8.3173e-01 -6.3502e-01 1.3130e+00 3.8733e-01
+ -1.2626e+00 8.9614e-01 -3.4917e-01 -5.0431e-01 1.7734e-01 8.7191e-01 -1.1609e-01 5.0936e-01
+ 2.5913e+00 1.4414e+00 3.4737e+00 5.4565e+00 7.2057e+00 1.0871e+01 1.4181e+01 1.3889e+01
+ 2.0678e+01 1.9005e+01 1.4171e+01 1.1541e+01 7.7307e+00 1.0468e+01 3.3426e+00 3.1239e+00
+ 3.5571e+00 1.7730e+00 6.0631e-01 6.3080e-02 -9.5256e-01 3.6296e-01 -1.1420e+00 2.7633e+00
+ 3.6210e-01 -3.6897e-01 -5.6195e-01 -9.3127e-01 -4.9932e-01 -1.1355e+00 -3.1439e-01 2.7590e-01
+ 1.3051e+00 5.2385e-01 -1.5254e-01 1.1314e+00 1.0290e+00 3.5277e-02 -7.6442e-01 1.0528e+00
+ 2.3796e-01 3.5863e-02 -9.3166e-01 -5.1138e-01 4.8426e-01 6.9392e-01 1.7708e-02 1.2119e-01
+ 1.0791e+00 7.7514e-01 -4.4349e-01 -4.5141e-01 -8.9125e-01 -1.4580e+00 -4.8079e-01 7.9674e-01
+ 8.4852e-01 -5.6347e-01 1.0646e+00 1.4867e+00 -4.7969e-01 9.2325e-01 -6.4600e-01 -2.8763e-01
+ -3.0012e-03 -4.5199e-01 -5.1870e-02 5.1075e-01 8.8273e-02 -1.7149e+00 4.0947e+00 4.0791e+00
+ 3.6373e+00 9.7723e+00 1.1929e+01 1.6502e+01 2.0542e+01 1.7149e+01 1.2216e+01 9.6489e+00
+ 8.9002e+00 6.1091e+00 6.8382e+00 -7.4320e-01 2.2107e+00 2.0766e+00 1.7977e-01 1.9873e-01
+ 1.6078e+00 2.0322e+00 -5.1844e-01 -7.7462e-01 -1.1221e+00 -7.1959e-01 8.7697e-01 1.9538e-01
+ 4.7639e-01 1.7507e-01 8.4499e-01 1.5104e-01 -4.9756e-01 -6.8363e-01 1.2112e+00 -3.2303e-01
+ 7.1786e-01 -4.5055e-01 2.6221e-01 6.1362e-01 1.3214e+00 -4.4492e-01 -3.2761e-01 1.7998e-01
+ 6.5403e-01 -3.8831e-01 1.9000e-02 -6.9155e-01 1.1779e+00 -5.6048e-01 -9.0170e-01 1.6746e-01
+ 4.0065e-01 -2.9676e-01 -1.4964e+00 1.2258e+00 1.5438e-01 1.6472e+00 -9.8027e-02 -1.7092e-01
+ 2.2514e-01 -1.2489e+00 1.3489e+00 -2.1495e-01 -1.3179e+00 -1.1588e+00 -8.4684e-01 -3.4921e-01
+ 2.1262e+00 1.4460e+00 6.2265e-01 3.2519e+00 2.7424e+00 4.9553e+00 7.0277e+00 1.2283e+01
+ 1.2917e+01 1.5725e+01 1.4719e+01 5.2823e+00 6.3213e+00 3.6703e+00 -3.0097e+00 2.0828e+00
+ 2.0678e+00 -1.0977e+00 7.5175e-01 7.2617e-02 -6.4194e-01 6.7674e-01 -5.7931e-01 -9.8836e-01
+ 1.7500e+00 -1.1396e+00 -7.5055e-01 1.6227e+00 -4.6466e-01 -9.1284e-01 -1.0043e+00 -8.8030e-01
+ -1.1618e+00 2.7621e-01 2.9998e-01 -3.3326e-01 -4.9634e-01 2.0657e-01 2.7200e-01 2.6415e-02
+ 2.3951e-01 3.9517e-01 -1.4516e-01 -5.7423e-01 -4.2842e-01 -9.2854e-01 -1.7459e-01 1.3647e+00
+ -1.2196e-01 4.1121e-01 -3.1774e-01 -3.5955e-01 -9.0803e-01 -1.0485e+00 -6.2208e-01 4.1599e-01
+ 1.7347e-01 -9.3917e-01 1.0988e+00 4.8736e-02 8.8156e-02 -6.1881e-01 -4.5439e-01 -2.5561e+00
+ 7.5972e-01 8.9905e-01 -2.2995e-01 1.5877e-01 3.4264e-01 1.7341e+00 1.6163e+00 1.8174e-01
+ 2.0415e+00 3.4079e+00 4.3254e+00 4.5926e+00 6.5469e+00 1.1315e+01 9.7713e+00 1.0742e+00
+ 6.4890e+00 1.0996e+00 5.4837e-01 1.8262e+00 3.6094e-01 6.5977e-01 1.8465e+00 -2.5503e-01
+ 8.3924e-01 -1.3374e+00 -4.5800e-01 7.6185e-01 5.4887e-01 -1.1127e+00 -1.8423e-01 6.1468e-01
+ 7.7202e-01 -1.2225e+00 -5.5370e-01 5.1473e-01 -5.1899e-01 -8.2909e-01 -4.3315e-01 -3.0034e-01
+ -5.7634e-01 7.4628e-02 -1.5144e-01 -7.7475e-01 2.2857e-01 4.2428e-01 4.6910e-01 -4.3234e-01
+ 9.0146e-01 3.5002e-01 1.4942e+00 2.5463e-01 -6.0922e-01 2.5535e-01 -1.3877e-01 2.8191e-01
+ 1.5730e-01 4.3232e-01 1.8778e-01 3.6381e-01 1.4132e-01 -1.0064e+00 -3.1328e-01 -3.1892e-01
+ -1.1244e+00 -9.2414e-01 1.2899e+00 -1.4566e+00 3.0297e-01 3.2132e-01 -8.8057e-01 -2.2100e+00
+ -1.5588e+00 1.8688e+00 -1.5634e+00 2.3583e-02 1.3792e+00 2.0406e+00 -5.4338e-02 3.1379e+00
+ 6.4138e-02 1.6638e+00 5.0181e+00 3.5367e+00 8.3854e-01 1.1753e-01 -1.8359e-01 -1.7996e+00
+ -1.2811e+00 -8.0230e-01 -7.4175e-01 1.0189e+00 8.2806e-01 2.0459e+00 -2.3705e+00 9.3156e-01
+ 7.6887e-01 -8.5180e-02 5.3781e-01 -2.7315e-01 1.3305e+00 -9.1385e-01 1.3558e+00 -2.9358e-01
+ 5.2154e-01 4.2704e-01 -8.9939e-01 4.8680e-01 1.8411e-01 -2.6401e-01 -1.0410e+00 2.3353e-01
+ -5.8731e-01 -1.4881e+00 -7.5216e-01 1.1997e-01 0.0000e+00 -3.9282e-01 7.9682e-01 1.4182e-01
+ 2.1142e-01 -9.6956e-01 4.0813e-01 -2.8802e-01 4.9862e-01 1.6798e-01 -2.9692e-01 1.1264e-01
+ 7.8111e-01 -2.4514e-01 -6.7636e-01 -4.7138e-01 1.5404e-01 7.4911e-02 5.3363e-01 1.3104e+00
+ 8.5927e-01 -1.2932e-01 -1.8669e-01 3.0541e-01 -1.0222e+00 -2.3841e+00 -1.2823e+00 9.6357e-01
+ 3.3897e-01 2.6965e+00 3.9674e-01 -1.3394e+00 -7.7398e-01 -1.1732e-01 5.1843e-01 -1.1784e+00
+ 3.8385e-01 1.0462e+00 -1.0329e-01 1.0844e-03 3.6775e-01 -1.4556e+00 5.7234e-01 -2.5272e-01
+ 1.2363e-01 -1.3543e+00 2.3345e-01 -8.1325e-01 -3.3033e-01 -2.8827e-01 1.8585e+00 -7.3827e-01
+ 6.0154e-01 -8.3168e-01 -1.2647e-01 5.0834e-01 5.2901e-02 2.6482e-02 -6.2504e-01 2.2977e-02
+ 1.0223e-01 -1.3420e-01 -3.1309e-01 4.5675e-01 0.0000e+00 6.9807e-01 1.9188e-02 -8.9513e-01
+ 2.4534e-01 1.4858e+00 -4.8025e-01 -1.8665e-01 -7.0999e-01 6.2663e-01 -8.8079e-02 -1.9047e+00
+ -3.3400e-02 -3.7188e-01 -1.0471e+00 -1.1510e+00 3.8262e-01 -1.0635e+00 8.0343e-01 2.9867e-01
+ 5.3738e-01 6.5330e-01 4.5653e-01 -5.5939e-01 1.6219e+00 1.0351e+00 -1.7459e+00 -3.7755e-01
+ -3.6204e-01 -6.7787e-01 -2.7282e-01 2.9920e-01 -1.2643e+00 3.9816e-01 -5.1474e-05 -2.0535e-01
+ 8.9886e-01 3.1806e+00 3.4483e-01 2.1785e-01 1.5149e+00 -3.3292e-02 1.2096e+00 8.8386e-01
+ -3.1509e-01 -1.4085e+00 4.3683e-02 -4.8209e-02 1.9292e+00 -2.0850e-01 4.6569e-02 6.0636e-02
+ 2.0551e-01 -4.6661e-01 1.9258e-02 -6.5551e-01 -6.8724e-03 -1.0340e+00 -4.9515e-01 -1.8104e-01
+ -2.4963e-02 1.3449e+00 -4.0476e-01 -1.0373e+00 4.2894e-01 8.6133e-01 -4.9121e-01 4.7942e-01
+ -6.0313e-02 4.0890e-01 3.6969e-01 3.8981e-02 2.4198e-01 -3.2230e-01 -3.0990e-01 -1.4390e+00
+ 5.5585e-01 1.4830e+00 -3.6683e-01 -9.5812e-01 1.0812e+00 2.3717e-01 1.2530e+00 -3.1590e-01
+ 2.1728e-01 2.6540e-01 7.5212e-01 2.5702e-01 -4.5292e-01 -1.1658e+00 -2.5634e-01 -7.7656e-01
+ -9.8909e-02 -1.8405e+00 -6.2566e-01 1.7045e-02 9.4380e-01 1.4036e+00 1.0868e+00 -9.1642e-01
+ 1.0842e+00 1.2824e+00 1.2594e+00 1.0638e+00 8.1209e-01 2.1716e+00 -9.3353e-01 1.7046e+00
+ -1.1628e+00 6.3862e-01 4.6793e-01 1.1133e+00 2.1859e-01 2.1462e-01 -8.4401e-01 1.2359e+00
+ 9.5134e-02 3.1416e-01 -9.0666e-01 -1.0393e+00 -7.4391e-01 -4.4249e-01 -1.2674e+00 -3.3662e-01
+ -6.7343e-01 3.7641e-02 6.9209e-01 -2.5949e-01 -1.2013e+00 5.7694e-01 4.4532e-02 -4.9726e-01
+ 1.0639e+00 -9.8495e-02 -5.2632e-01 3.8781e-01 3.8241e-01 1.2544e+00 -6.4518e-02 1.9948e-02
+ 1.5671e-02 1.9765e-02 -1.3254e-01 3.6320e-02 -1.8262e-01 8.6826e-01 5.6818e-02 -9.7554e-01
+ -9.1952e-01 1.2787e-01 -4.8844e-01 -3.0589e-01 -4.7639e-01 3.5193e-01 -7.6050e-01 -1.0499e+00
+ 9.9943e-02 -6.5242e-01 -8.6157e-02 7.2638e-01 6.5534e-01 -3.9069e-01 -2.2689e-01 1.7078e-01
+ 1.5414e-01 2.4880e-01 -5.6667e-01 -1.2237e+00 -1.7738e+00 -6.1973e-01 9.8638e-01 -2.0459e+00
+ -1.4533e+00 -1.4376e+00 -8.2230e-01 -3.7907e-01 -1.1335e-01 -8.8800e-01 -3.8632e-01 -1.8368e-01
+ 5.1391e-01 1.3318e+00 4.6682e-01 1.7507e+00 5.3107e-02 1.0875e+00 -3.2734e-01 4.1760e-01
+ -2.4467e-01 9.3638e-01 1.0933e+00 5.6608e-01 -9.0616e-01 -2.7537e-01 -4.0628e-01 3.8077e-01
+ 1.1322e+00 4.5034e-01 2.2340e-01 9.8333e-01 3.8631e-01 4.4586e-01 5.4049e-01 -8.5011e-02
+ 0.0000e+00 6.5524e-01 -5.8022e-01 3.1545e-01 3.1744e-01 4.5661e-01 2.8308e-02 -8.6089e-02
+ 3.6578e-01 -6.2253e-01 3.8606e-01 -6.8352e-02 -2.1727e-01 2.2253e-02 3.9144e-01 -6.1340e-01
+ 8.9441e-01 8.0440e-01 -7.2675e-02 3.8599e-01 1.1265e+00 1.8212e-01 -6.9814e-02 2.0235e+00
+ -8.4490e-01 -3.0550e-01 -5.3689e-01 -5.2662e-01 -6.3923e-01 -4.7964e-01 6.1838e-01 1.3259e+00
+ -9.8856e-01 -1.2562e-02 6.3318e-01 -1.0114e+00 -5.5108e-02 2.3097e+00 4.1825e-01 -7.2727e-01
+ 9.9544e-01 -1.2146e+00 -7.2017e-01 -7.6980e-03 -6.9441e-01 1.7047e+00 -6.6263e-01 1.8140e+00
+ 3.9318e-01 4.7112e-01 8.9539e-01 4.2294e-01 -1.3924e+00 -1.4495e-01 1.1326e+00 2.2553e-01
+ 1.3825e-01 1.9130e-01 -2.5468e-01 8.4789e-02 5.9314e-01 1.0435e+00 -6.9953e-01 5.3286e-01
+ 3.2538e-01 4.8132e-01 6.2974e-01 -7.4906e-01 -9.5656e-01 5.6516e-01 -1.6149e-01 -7.0135e-07
+ 5.1375e-01 5.1791e-01 1.3230e-01 -3.6680e-03 2.6170e-01 -1.6330e-01 1.2029e+00 -1.3654e-01
+ -5.9482e-01 -4.9983e-01 -6.2495e-01 6.6190e-01 5.6859e-01 9.7449e-01 -5.2522e-01 1.2837e-03
+ 1.0933e+00 3.0870e-01 9.0973e-02 5.0979e-02 -5.9693e-01 7.4534e-01 8.5122e-02 -5.1450e-01
+ 4.1914e-01 1.7683e-01 7.0700e-02 1.0429e-01 9.2651e-01 8.8852e-01 1.0893e-01 6.3758e-01
+ 9.6703e-01 -1.6143e-01 1.2060e+00 5.7880e-02 -1.1622e+00 -1.4970e-01 4.7858e-02 -1.2042e+00
+ -5.0761e-01 8.1743e-01 3.1344e-01 -5.1295e-02 8.4171e-01 3.2723e-01 -5.0817e-01 7.3953e-01
+ -5.5316e-01 6.8103e-02 5.1071e-02 5.4325e-01 -1.9482e-01 7.6876e-01 -8.3249e-01 4.4035e-01
+ -1.5420e-01 2.7520e-01 1.0635e-01 2.4698e-01 2.7427e-01 -2.5321e-01 -2.4805e-01 6.6675e-03
+ -2.2003e-01 1.5996e-02 -1.0317e+00 3.2544e-01 1.6059e-02 2.3848e-01 -1.8862e-01 3.6280e-01
+ 1.3707e-01 -4.4451e-01 5.3878e-01 6.8477e-01 -5.7019e-01 1.2334e-01 -2.7286e-01 4.1594e-01
+ -8.4469e-01 -1.8263e+00 3.3498e-01 -1.3008e-01 -1.7462e-01 -6.6370e-01 -1.4811e-01 2.0786e-02
+ 2.6778e-01 1.5623e-01 5.2117e-01 1.0615e+00 9.4357e-02 -5.8955e-02 8.2088e-01 1.4463e+00
+ -5.1995e-01 1.3363e+00 4.2480e-02 -2.4998e-01 -5.7420e-02 3.8816e-01 -1.0597e+00 6.9281e-01
+ -1.7996e-01 -5.3748e-02 1.1947e+00 1.4057e-01 -9.6886e-02 9.2436e-01 -1.1257e+00 -1.2959e+00
+ -8.6785e-01 5.6422e-01 1.5370e-01 -1.1663e-01 4.6690e-02 2.0762e-01 1.2973e-01 2.7528e-01
+ -2.2789e-01 -3.3094e-01 3.5487e-01 3.1590e-02 3.6354e-01 -1.2773e-01 -6.3128e-03 6.0314e-01
+ 3.5037e-01 6.4315e-02 -2.8711e-01 -1.1761e-01 -3.0740e-01 6.0554e-01 2.2320e-02 -2.8546e-01
+ -8.0841e-01 -1.8743e-01 -5.7848e-01 4.2771e-01 -1.4231e-01 7.0267e-01 2.1042e-01 -2.0408e-01
+ -5.5596e-01 -4.7534e-01 6.7926e-01 -3.1335e-01 -3.0925e-01 6.7193e-01 -4.1970e-01 -1.1954e-01
+ 8.2736e-01 1.0301e+00 3.1795e-01 -4.5587e-01 -1.1567e+00 1.0472e+00 6.7376e-01 7.6202e-01
+ -3.2856e-01 8.2563e-01 -4.6036e-01 -3.0397e-01 1.4506e-01 -2.0480e-01 3.5293e-02 -1.6297e+00
+ -1.9362e+00 8.0186e-01 -9.3623e-01 1.0107e+00 4.2459e-01 5.3397e-01 5.0180e-01 -9.1014e-01
+ 2.1938e+00 2.3889e-01 6.2685e-01 -7.2641e-02 1.5367e-01 3.0879e-01 1.5087e-01 1.9195e+00
+ 1.6936e-01 -1.2532e-01 1.4101e-01 2.9639e-01 1.1078e+00 -9.9819e-01 5.4123e-01 -1.4976e-01
+ -7.8282e-01 -5.8414e-02 -5.2549e-01 3.0774e-01 -8.8578e-01 2.3736e-01 1.9210e-01 -3.7041e-01
+ 1.3269e-01 3.7872e-01 1.4228e-01 6.5427e-01 6.2952e-01 -3.7324e-01 -2.3910e-01 -2.3032e-01
+ 6.1865e-01 8.2990e-01 -2.4712e-01 1.4316e-01 2.8962e-01 7.7917e-01 -6.0085e-01 3.8770e-01
+ -3.0027e-01 2.1919e-01 -6.5387e-02 -2.0244e-01 -1.4907e-01 -1.7094e+00 1.3707e-01 8.7391e-01
+ -1.5802e-01 -3.2731e-02 -4.4048e-01 -3.8215e-01 3.7759e-01 -1.7823e-01 -6.0460e-01 -2.1349e-01
+ -9.2006e-01 -6.0061e-01 5.4711e-01 -6.0708e-01 1.0947e+00 -6.4393e-02 -1.8966e+00 -4.8580e-01
+ 5.3363e-01 -4.2060e-01 -5.3386e-01 -3.5191e-01 -5.2037e-01 4.2198e-01 4.6710e-01 2.8701e-01
+ -6.0618e-01 8.5655e-01 8.2852e-01 4.8661e-01 6.4538e-01 5.5509e-01 1.0612e+00 -3.4965e-02
+ -8.6295e-02 3.8604e-01 -6.8908e-01 -3.3535e-01 -3.3798e-01 -6.7054e-02 -9.2808e-01 1.2114e+00
+ -1.3123e+00 5.7747e-01 -1.6425e-01 -4.4334e-01 -4.0675e-02 -7.2458e-01 1.5311e-01 5.0933e-03
+ 4.9632e-01 -1.2355e+00 1.8283e-01 1.0507e+00 1.3206e+00 -1.3859e+00 1.4787e+00 0.0000e+00
+ -9.0771e-01 3.0525e-01 -4.0613e-01 1.1210e+00 -3.9086e-01 -6.8057e-01 1.6358e+00 9.8411e-01
+ 4.3091e-01 8.2985e-01 8.0849e-01 -5.5176e-01 -2.2052e-01 5.2332e-01 2.5727e+00 -8.3118e-01
+ -3.5195e-01 1.5394e-01 -1.5002e-01 8.7727e-01 1.0500e+00 -1.2257e+00 1.2113e+00 -5.5592e-02
+ 2.7534e-01 7.6151e-01 1.0747e+00 -1.6543e+00 -9.2356e-01 7.2450e-01 5.7152e-02 2.1940e-01
+ 3.7234e-01 1.1153e-01 -3.2872e-01 2.9251e-01 -4.6780e-02 -7.1680e-01 1.7593e+00 -5.4564e-02
+ -8.4425e-02 6.1200e-01 -3.7409e-01 2.2402e-03 1.1200e+00 -1.1396e+00 3.1728e-01 5.0021e-01
+ -1.6527e-01 0.0000e+00 -7.2828e-01 -1.2359e+00 -6.0524e-02 0.0000e+00 -3.4995e-01 2.3124e-01
+ -1.0763e+00 -5.8822e-01 7.8595e-01 -3.3229e-02 -4.9001e-01 7.2243e-01 -1.2349e+00 6.6461e-01
+ 7.7395e-01 -3.9954e-01 7.9549e-01 3.9815e-01 3.2527e-01 -2.6294e-01 -1.0486e+00 4.0414e-01
+ 9.1161e-01 3.4917e-02 -1.1064e+00 1.4120e-01 5.2663e-01 -5.4564e-01 -2.1155e-01 -2.3590e-01
+ -4.2987e-01 1.5136e-01 1.7386e-01 2.8417e-01 6.4046e-01 3.2754e-01 -6.4022e-01 6.0609e-01
+ 4.1873e-01 -6.9318e-01 -2.6502e-01 1.2384e+00 6.7585e-01 -1.5085e+00 -4.4060e-01 6.3858e-01
+ -1.6823e-01 1.1257e+00 2.5442e-01 1.8123e-02 -3.0771e-01 1.0823e+00 -4.1826e-01 1.3563e-01
+ -8.4678e-01 -1.6234e-01 9.1056e-01 -1.9265e-01 4.8227e-01 5.9921e-01 3.7543e-02 -6.8568e-01
+ -2.1298e-01 -6.5467e-01 1.6036e-01 1.0216e-01 1.2539e+00 -1.8585e-01 1.8430e-02 -3.0217e-01
+ 1.1848e-02 4.7430e-01 -9.4180e-01 -3.3585e-01 -2.1538e-01 9.9233e-01 -6.5802e-01 4.5752e-01
+ -7.2761e-01 4.1339e-01 3.0877e-01 -1.2278e-01 9.0495e-01 4.3383e-01 1.7739e-01 -4.1641e-01
+ -2.2921e-01 -8.4949e-01 7.6225e-01 6.0783e-01 8.6612e-01 1.2575e+00 -4.5607e-01 1.8447e-01
+ -8.7127e-01 6.6443e-01 2.4979e-02 5.6005e-02 6.1406e-01 -3.2609e-01 -7.2965e-02 1.2881e+00
+ 5.8477e-01 7.3603e-01 -1.3210e-01 -7.7164e-01 -1.7514e+00 -2.3280e-01 2.7472e-01 1.0668e+00
+ 7.7243e-01 -2.2586e-01 -3.5096e-01 -1.3324e+00 3.4250e-01 -1.5678e-01 8.4727e-01 -7.7397e-01
+ 1.0656e+00 -5.7531e-01 4.3364e-01 3.2056e-03 -7.1519e-01 -3.0655e-01 4.5179e-01 3.4680e-01
+ -7.4841e-01 -6.4918e-01 2.2320e-02 3.4708e-02 -4.0152e-01 2.0803e-03 3.3105e-03 -2.1893e-01
+ -3.2360e-01 3.2159e-01 7.3669e-01 3.6935e-01 7.2376e-01 3.5639e-02 3.4071e-01 0.0000e+00
+ -3.5754e-01 -7.0004e-01 -9.4043e-01 -6.9736e-03 -2.8337e-01 -7.7277e-01 5.7595e-01 -9.0612e-02
+ 5.5925e-01 5.4933e-01 -2.9531e-01 1.6916e-01 3.2903e-01 4.2138e-01 1.3537e+00 4.1610e-01
+ -1.7835e-01 -6.6293e-01 -5.2723e-01 -1.1982e-02 -1.2289e+00 2.8987e-01 -1.3825e+00 0.0000e+00
+ -2.8139e-01 -4.5249e-01 -7.3372e-01 -4.7403e-01 2.0495e-02 2.2502e-01 -5.8311e-02 3.4690e-02
+ -6.3056e-01 5.8268e-01 -1.0477e+00 1.1699e+00 4.6064e-01 -2.0059e+00 1.0007e+00 1.2452e-01
+ 4.5068e-01 3.2788e-02 -6.8196e-02 4.2886e-01 2.2763e-01 9.9323e-01 8.2772e-01 1.5241e-02
+ 6.6784e-01 7.8825e-01 1.4012e-01 7.2141e-02 -5.3528e-01 -1.4272e+00 -2.7581e-02 2.6275e-01
+ -2.2417e-02 6.6765e-01 -5.0163e-01 -4.9129e-02 -2.9261e-01 0.0000e+00 1.2424e+00 3.1630e-01
+ 5.3399e-02 1.4723e-02 1.9046e-01 -7.0550e-01 3.3096e-01 3.5728e-02 6.6083e-01 1.7026e-02
+ -1.2038e-01 -5.3373e-01 7.6127e-01 5.1114e-01 8.2569e-01 -3.8410e-01 1.7727e+00 -3.6685e-01
+ 2.0883e-02 -1.0528e-01 -3.8857e-01 -6.6174e-01 -3.4527e-01 8.7875e-01 5.9053e-01 2.4319e-02
+ -4.8167e-01 2.1918e-02 4.0203e-01 5.1043e-01 3.1353e-01 -8.3972e-01 2.1353e-02 3.8799e-01
+ -6.8244e-01 -3.2088e-02 -6.2196e-02 6.3708e-01 1.2072e+00 -4.8612e-01 -3.3618e-01 -2.1198e-01
+ -2.7086e-01 -3.1104e-01 4.5163e-02 -1.3401e-01 -8.1399e-01 2.2740e-01 7.6301e-02 0.0000e+00
+ 2.7401e-01 6.3423e-01 9.6454e-01 4.2801e-01 -3.7220e-01 -3.3001e-02 1.0938e+00 -1.0281e+00
+ -4.5697e-01 2.8605e-01 -5.3673e-01 -6.4902e-01 2.0424e-02 -1.2043e-01 6.0286e-01 1.1026e-01
+ 3.0086e-01 4.6358e-01 -4.2700e-01 8.2821e-01 -4.3253e-01 -7.3191e-01 -2.1973e-01 9.8306e-03
+ 2.2303e-02 2.1782e-01 -3.9524e-01 -1.1088e-01 -1.2327e+00 -5.7332e-01 -2.3893e-01 3.2547e-01
+ 5.8887e-01 2.5592e-02 1.7309e-02 1.7237e-02 1.7139e-01 8.1292e-01 1.6201e-02 -1.0475e-01
+ 1.7470e-02 4.9970e-01 1.8166e-01 0.0000e+00 7.4215e-01 -1.4853e-01 9.3328e-01 3.9622e-01
+ 1.1003e+00 2.7300e-01 -6.4646e-02 3.0896e-01 -1.3894e+00 6.5867e-01 -1.8399e-01 6.9612e-01
+ -3.8033e-01 3.2596e-01 -3.4647e-01 1.2559e-01 1.7293e-02 4.6702e-02 -2.7687e-01 -2.7257e-02
+ -2.9387e-01 -3.6041e-01 1.6735e-01 -8.5290e-01 -5.4546e-01 3.3719e-01 1.8938e-03 9.4747e-01
+ 0.0000e+00 8.5863e-01 -6.3868e-02 -4.6481e-01 3.1605e-01 3.2637e-02 3.9651e-01 5.3987e-01
+ 3.8062e-02 -6.4377e-01 4.2180e-01 -9.4072e-01 -3.6002e-01 3.2434e-01 -1.5031e-01 9.4287e-01
+ 4.5366e-02 5.5139e-01 -7.2247e-01 -7.7783e-01 3.6740e-01 1.3669e-01 -2.0273e-01 4.3105e-01
+ 5.9416e-01 7.2158e-01 2.6562e-01 0.0000e+00 5.1223e-01 5.6194e-01 7.1944e-01 3.7254e-01
+ 3.2003e-01 5.6035e-01 6.5287e-01 0.0000e+00 5.9403e-01 6.1125e-01 6.3259e-01 7.3253e-01
+ 5.5619e-01 5.7891e-01 4.6897e-01 6.3654e-01 6.7008e-01 7.8446e-01 4.4775e-01 4.4657e-01
+ 5.7599e-01 6.0294e-01 5.4235e-01 7.2542e-01 4.3503e-01 7.6444e-01 5.3806e-01 3.8452e-01
+ 8.6150e-01 7.3886e-01 7.3135e-01 8.3242e-01 4.9012e-01 5.6825e-01 4.2161e-01 4.4550e-01
+ 5.6522e-01 9.3285e-01 6.1490e-01 6.2370e-01 5.6753e-01 5.7448e-01 3.8052e-01 6.5457e-01
+ 6.8072e-01 8.1718e-01 0.0000e+00 7.4113e-01 6.1854e-01 6.1921e-01 4.6790e-01 5.1299e-01
+ 5.7033e-01 4.6973e-01 5.0668e-01 6.3653e-01 5.7475e-01 4.5127e-01 4.6815e-01 3.7488e-01
+ 3.3566e-01 3.1615e-01 3.2594e-01 6.5778e-01 4.2083e-01 3.7184e-01 5.9067e-01 4.9827e-01
+ 6.5553e-01 3.9540e-01 1.0474e-01 4.4086e-01 5.8834e-01 4.2046e-01 6.5643e-01 4.7167e-01
+ 5.0557e-01 5.2542e-01 3.0582e-01 7.9856e-01 6.1405e-01 6.2786e-01 5.7428e-01 5.0961e-01
+ 6.3699e-01 1.9764e-01 8.6114e-01 5.0142e-01 5.0475e-01 6.1521e-01 7.4047e-01 5.0502e-01
+ 5.2477e-01 6.9243e-01 6.7275e-01 4.5047e-01 4.7749e-01 4.7191e-01 5.6982e-01 1.0899e+00
+ 9.9780e-01 4.4615e-01 5.3501e-01 7.1722e-01 5.3563e-01 4.8822e-01 7.6398e-01 2.6948e-01
+ 3.4985e-01 6.4614e-01 8.3054e-01 5.2815e-01 4.1956e-01 7.4912e-01 7.6088e-01 4.1497e-01
+ 7.7686e-01 6.6681e-01 5.9380e-01 8.1480e-01 5.5712e-01 6.2429e-01 6.4613e-01 4.3282e-01
+ 4.7759e-01 3.8725e-01 4.3495e-01 2.7218e-01 6.0582e-01 5.8100e-01 6.0406e-01 4.4660e-01
+ 1.3456e-01 6.8920e-01 3.1652e-01 7.0143e-01 4.2596e-01 5.4517e-01 7.0241e-01 6.6492e-01
+ 7.9635e-01 4.6777e-01 2.8398e-01 5.5984e-01 4.8505e-01 4.7470e-01 5.3208e-01 7.3009e-01
+ 6.2213e-01 3.3963e-01 7.1988e-01 6.9645e-01 6.9670e-01 5.4375e-01 6.4983e-01 6.7051e-01
+ 3.5807e-01 8.3668e-01 6.1985e-01 4.3932e-01 5.8098e-01 6.8138e-01 5.8979e-01 5.6433e-01
+ 5.2157e-01 5.4520e-01 4.5193e-01 6.5585e-01 5.6880e-01 3.6701e-01 5.7251e-01 2.2722e-01
+ 3.4749e-01 5.8757e-01 5.7839e-01 7.5700e-01 6.4030e-01 6.1140e-01 6.7758e-01 4.4826e-01
+ 6.3858e-01 4.9277e-01 5.7020e-01 4.8503e-01 4.1349e-01 6.1365e-01 8.3835e-01 5.0915e-01
+ 4.9007e-01 6.8546e-01 5.5722e-01 3.0330e-01 4.5175e-01 5.1789e-01 4.0657e-01 5.5527e-01
+ 6.7679e-01 5.6247e-01 3.2053e-01 5.0658e-01 7.2782e-01 6.7844e-01 3.4866e-01 3.3695e-01
+ 3.5679e-01 5.9353e-01 3.5711e-01 6.1617e-01 4.7903e-01 8.0923e-01 6.3328e-01 6.1815e-01
+ 8.1730e-01 6.0743e-01 4.9051e-01 2.5087e-01 7.7174e-01 6.9996e-01 8.4558e-01 3.7433e-01
+ 7.0285e-01 5.9343e-01 5.8779e-01 0.0000e+00 4.3706e-01 9.1239e-01 7.6065e-01 7.1417e-01
+ 7.1742e-01 1.0007e+00 8.4390e-01 7.7402e-01 8.7690e-01 5.5656e-01 8.9901e-01 1.2531e+00
+ 6.8706e-01 6.1367e-01 5.1753e-01 5.7852e-01 8.3628e-01 9.6457e-01 3.5044e-01 4.2442e-01
+ 3.9468e-01 2.9722e-01 7.0577e-01 1.0525e+00 7.6020e-01 7.9935e-01 6.3957e-01 7.1697e-01
+ 1.0253e+00 6.7893e-01 1.5498e-01 3.3749e-01 6.6363e-01 4.2525e-01 3.9454e-01 7.0415e-01
+ 5.9611e-01 3.8281e-01 5.4373e-01 1.0577e+00 7.9579e-01 7.0118e-01 5.2414e-01 5.9657e-01
+ 6.7566e-02 5.5722e-01 8.4467e-01 8.8065e-01 0.0000e+00 0.0000e+00 5.6802e-01 2.6216e-01
+ 5.1027e-01 7.3377e-01 6.6629e-01 5.5835e-01 7.1313e-01 9.3264e-01 4.9881e-01 9.4925e-01
+ 6.7059e-01 6.5804e-01 4.4091e-01 5.4537e-01 8.4373e-01 9.5504e-01 4.6903e-01 6.7785e-01
+ 1.0007e+00 8.3681e-01 5.3715e-01 3.0946e-01 6.4379e-01 1.0300e+00 3.2332e-01 9.5610e-01
+ 6.3937e-01 7.9745e-01 6.8674e-01 9.7195e-01 8.6258e-01 7.3003e-01 8.0374e-01 9.7340e-01
+ 9.5743e-01 3.7995e-01 6.7528e-01 0.0000e+00 8.7909e-01 1.0249e+00 7.6487e-01 9.4512e-01
+ 7.3670e-01 2.1339e-01 5.5438e-01 3.9864e-01 7.6193e-01 2.6911e-01 7.4387e-01 7.5667e-01
+ 7.8271e-01 6.9856e-01 7.4255e-01 0.0000e+00 3.3731e-01 9.2082e-01 4.9709e-01 5.3336e-01
+ 9.0311e-01 6.2899e-01 5.9700e-01 6.8695e-01 5.9800e-01 5.4136e-01 4.8402e-01 7.0141e-01
+ 0.0000e+00 4.4135e-01 2.2273e-01 3.6540e-01 5.7916e-01 6.2285e-01 6.0347e-01 5.6529e-01
+ 7.0158e-01 6.8731e-01 4.9994e-01 5.7815e-01 6.8630e-01 3.6799e-01 6.6464e-01 5.5582e-01
+ 4.2650e-01 8.0733e-01 6.7471e-01 3.4881e-01 4.4241e-01 6.8464e-01 5.5751e-01 5.7067e-01
+ 7.9917e-01 5.1666e-01 4.6326e-01 6.8928e-01 6.0446e-01 8.4336e-01 6.5311e-01 8.8876e-01
+ 6.9340e-01 3.8272e-01 8.5162e-01 9.3622e-01 6.1866e-01 6.7933e-01 7.4306e-01 4.6710e-01
+ 6.1981e-01 5.4012e-01 7.7013e-01 5.9563e-01 6.9595e-01 7.0905e-01 8.1765e-01 5.3367e-01
+ 6.4201e-01 4.6510e-01 6.9814e-01 7.7366e-01 5.5983e-01 4.0430e-01 8.1657e-01 4.7224e-01
+ 4.6787e-01 6.8536e-01 6.1342e-01 0.0000e+00 5.8532e-01 4.4621e-01 6.7821e-01 6.6884e-01
+ 4.2419e-01 9.5196e-01 3.3245e-01 5.8064e-01 4.7999e-01 7.3715e-01 6.7962e-01 8.5726e-01
+ 4.9404e-01 3.1236e-01 7.0037e-01 6.2478e-01 8.8598e-01 4.8968e-01 5.5901e-01 7.4576e-01
+ 5.5906e-01 6.3849e-01 3.7110e-01 4.8866e-01 6.5079e-01 5.2017e-01 7.8431e-01 5.9396e-01
+ 5.7225e-01 6.2849e-01 4.9081e-01 6.3397e-01 1.0250e+00 4.5990e-01 3.3163e-01 8.3462e-01
+ 8.1787e-01 5.7976e-01 9.2748e-01 9.5056e-01 5.4027e-01 6.7054e-01 6.9129e-01 5.0959e-01
+ 7.6490e-01 6.4169e-01 9.9083e-01 4.7105e-01 9.3550e-01 7.9003e-01 5.6885e-01 7.9002e-01
+ 5.2655e-01 7.0925e-01 6.7717e-01 2.8357e-01 6.5773e-01 7.5854e-01 4.3477e-01 4.0503e-01
+ 5.1287e-01 7.6497e-01 4.2337e-01 8.8312e-01 7.6435e-01 5.5006e-01 6.7910e-01 5.6101e-01
+ 9.1249e-01 5.8855e-01 3.4051e-01 7.0574e-01 4.0030e-01 5.7671e-01 4.0534e-01 5.3633e-01
+ 4.5228e-01 3.3547e-01 7.1731e-01 6.6929e-01 7.4204e-01 7.1499e-01 9.1645e-01 4.6615e-01
+ 3.3832e-01 4.5015e-01 4.3394e-01 6.9408e-01 6.3004e-01 2.9543e-01 5.2226e-01 5.9106e-01
+ 5.5028e-01 6.5672e-01 9.0920e-01 5.6211e-01 7.4772e-01 7.1455e-01 8.0586e-01 7.6540e-01
+ 5.9294e-01 5.2292e-01 4.6213e-01 7.6479e-01 5.6475e-01 6.7016e-01 9.3174e-01 1.0247e+00
+ 4.3960e-01 7.5530e-01 5.3220e-01 8.0535e-01 5.8335e-01 7.8634e-01 7.7815e-01 8.7119e-01
+ 7.1790e-01 7.1397e-01 5.6806e-01 5.6622e-01 4.4353e-01 7.5924e-01 7.4286e-01 5.1679e-01
+ 7.0584e-01 6.2824e-01 4.4399e-01 5.5531e-01 5.5434e-01 8.5776e-01 3.5803e-01 6.0103e-01
+ 4.4323e-01 6.6419e-01 5.6897e-01 5.6891e-01 2.9198e-01 4.8925e-01 4.5416e-01 5.2399e-01
+ 6.4836e-01 0.0000e+00 3.9120e-01 6.2061e-01 6.2631e-01 7.4157e-02 7.3358e-01 6.8672e-01
+ 9.4284e-01 4.5931e-01 5.6493e-01 6.2991e-01 6.3926e-01 6.4419e-01 6.2521e-01 6.8817e-01
+ 5.1584e-01 8.5003e-01 5.4786e-01 5.6344e-01 6.5065e-01 9.7690e-01 7.6831e-01 8.4835e-01
+ 8.5776e-01 8.4811e-01 9.8764e-01 8.3545e-01 8.2548e-01 8.2212e-01 8.8195e-01 1.0714e+00
+ 7.2158e-01 9.0745e-01 1.1087e+00 1.2857e+00 7.6100e-01 9.3084e-01 9.4810e-01 4.9642e-01
+ 6.3383e-01 7.6266e-01 7.7558e-01 1.2058e+00 1.0914e+00 6.6706e-01 6.3875e-01 7.2281e-01
+ 6.2021e-01 6.1630e-01 8.9280e-01 4.1035e-01 6.0796e-01 4.6739e-01 5.7410e-01 5.5777e-01
+ 3.4223e-01 6.9687e-01 8.1542e-01 4.2248e-01 7.8250e-01 3.4410e-01 4.1297e-01 4.4205e-01
+ 4.0671e-01 5.3670e-01 5.2354e-01 6.2667e-01 5.5259e-01 6.1347e-01 4.5398e-01 6.1651e-01
+ 5.4502e-01 7.1766e-01 7.4112e-01 8.1385e-01 5.9885e-01 6.2315e-01 5.2760e-01 5.4098e-01
+ 7.2644e-01 8.7791e-01 5.5432e-01 9.3218e-01 7.6016e-01 5.4006e-01 1.0458e+00 9.4855e-01
+ 9.4865e-01 8.8766e-01 6.5193e-01 6.7159e-01 6.2623e-01 9.6878e-01 8.4808e-01 3.6681e-01
+ 1.0180e+00 6.1627e-01 8.1398e-01 8.5951e-01 7.1486e-01 1.0130e+00 1.2496e+00 8.8365e-01
+ 1.0121e+00 9.5527e-01 7.7788e-01 8.4774e-01 9.2683e-01 1.1930e+00 7.5365e-01 5.7977e-01
+ 7.5225e-01 7.2881e-01 7.0043e-01 5.9840e-01 7.9932e-01 7.6143e-01 6.1385e-01 6.4184e-01
+ 8.0313e-01 9.8318e-01 5.5777e-01 5.5566e-01 4.9038e-01 5.2884e-01 5.6298e-01 7.2432e-01
+ 3.9903e-01 4.7825e-01 5.8314e-01 2.8590e-01 5.2865e-01 0.0000e+00 4.8565e-01 5.3673e-01
+ 6.0699e-01 1.0158e+00 2.6674e-01 7.0617e-01 5.4329e-01 1.2737e+00 1.3470e+00 7.9715e-01
+ 7.4020e-01 7.5330e-01 8.7455e-01 6.8289e-01 9.7297e-01 1.0132e+00 6.1823e-01 1.1601e+00
+ 1.1477e+00 5.9706e-01 6.7232e-01 9.4409e-01 1.0939e+00 9.5650e-01 1.1857e+00 8.8308e-01
+ 1.0069e+00 1.0693e+00 1.2446e+00 1.2191e+00 8.4058e-01 1.1119e+00 1.2418e+00 1.0221e+00
+ 1.1436e+00 1.1519e+00 1.5366e+00 6.0167e-01 1.5108e+00 1.1412e+00 9.7636e-01 8.8781e-01
+ 1.2828e+00 1.0937e+00 8.3980e-01 7.2792e-01 1.4497e+00 7.7708e-01 3.3378e-01 1.0041e+00
+ 1.1060e+00 8.7917e-01 6.8553e-01 8.8990e-01 8.4102e-01 1.0149e+00 7.2207e-01 6.9117e-01
+ 8.6199e-01 6.7232e-01 6.3960e-01 5.6259e-01 7.6545e-01 1.1157e+00 8.3319e-01 7.0467e-01
+ 5.1266e-01 2.4832e-02 7.8613e-01 5.7717e-01 5.8325e-01 5.0543e-01 6.1767e-01 8.7700e-01
+ 7.2585e-01 5.2713e-01 9.1718e-01 5.8143e-01 5.0013e-01 7.7742e-01 6.0612e-01 5.2062e-01
+ 5.6824e-01 6.9732e-01 7.5588e-01 7.7632e-01 9.1437e-01 9.2262e-01 7.8843e-01 9.9487e-01
+ 6.6688e-01 9.5367e-01 9.3777e-01 9.3305e-01 9.5211e-01 9.9242e-01 8.5002e-01 7.8256e-01
+ 9.2680e-01 1.1250e+00 8.1662e-01 7.5526e-01 1.1166e+00 8.1455e-01 8.6618e-01 1.1727e+00
+ 8.6447e-01 8.0752e-01 1.1289e+00 1.0171e+00 6.5635e-01 1.0991e+00 8.5794e-01 9.0697e-01
+ 8.6740e-01 7.9568e-01 7.5747e-01 9.8254e-01 8.2703e-01 8.6204e-01 1.0056e+00 7.6309e-01
+ 7.5419e-01 8.3493e-01 7.4935e-01 6.9955e-01 6.7993e-01 7.3711e-01 6.2776e-01 3.0589e-01
+ 5.7310e-01 4.5683e-01 5.9231e-01 9.9272e-01 6.9448e-01 4.2168e-01 3.2360e-01 5.4245e-01
+ 4.7985e-01 5.0170e-01 6.9856e-01 5.6943e-01 7.1199e-01 3.9198e-01 5.9757e-01 5.2143e-01
+ 3.0806e-01 5.1523e-01 8.3290e-01 5.0944e-01 6.0863e-01 6.9961e-01 7.0221e-01 7.8199e-01
+ 6.5637e-01 7.4966e-01 4.8103e-01 7.5111e-01 6.7007e-01 8.0385e-01 6.9313e-01 8.3148e-01
+ 8.4002e-01 9.0386e-01 9.5391e-01 8.8308e-01 8.8000e-01 1.0698e+00 1.0802e+00 9.2594e-01
+ 1.0628e+00 9.6599e-01 9.6927e-01 1.4541e+00 9.9882e-01 9.1015e-01 8.4259e-01 9.6199e-01
+ 8.2750e-01 8.6735e-01 8.7490e-01 9.1849e-01 8.7106e-01 1.0933e+00 1.0372e+00 1.0238e+00
+ 9.7139e-01 5.3477e-01 5.0298e-01 5.9782e-01 8.2003e-01 6.7499e-01 8.8898e-01 5.4414e-01
+ 7.2674e-01 1.0154e+00 2.7972e-01 7.8261e-01 5.5232e-01 7.2853e-02 6.7251e-01 7.5139e-01
+ 6.4317e-01 6.1696e-01 5.3207e-01 3.1571e-01 3.6943e-01 5.2506e-01 8.3896e-01 6.5070e-01
+ 4.8204e-01 8.6476e-01 4.3390e-01 9.3763e-01 4.5317e-01 8.1683e-01 8.1236e-01 6.8245e-01
+ 6.7553e-01 8.7513e-01 5.4175e-01 9.5698e-01 8.8627e-01 7.8864e-01 1.0198e+00 5.5862e-01
+ 9.5276e-01 9.5820e-01 1.0191e+00 1.0207e+00 1.2676e+00 1.2001e+00 9.8940e-01 8.7704e-01
+ 7.6441e-01 1.2501e+00 1.2083e+00 1.1696e+00 1.2132e+00 9.9164e-01 1.0398e+00 1.5582e+00
+ 8.6042e-01 1.1105e+00 9.2833e-01 1.0133e+00 1.0167e+00 8.3385e-01 9.2934e-01 1.1183e+00
+ 1.1798e+00 8.2661e-01 7.9745e-01 7.0095e-01 1.0117e+00 8.3094e-01 9.9178e-01 7.8560e-01
+ 9.7550e-01 1.0614e+00 7.2728e-01 6.4654e-01 5.3488e-01 1.0101e+00 7.1851e-01 8.1275e-01
+ 3.0775e-01 6.9581e-01 7.2164e-01 7.5727e-01 5.1901e-01 4.2255e-01 6.2044e-01 3.0054e-01
+ 4.2854e-01 6.4235e-01 3.1577e-01 6.3063e-01 4.9958e-01 6.4191e-01 7.5650e-01 8.8557e-01
+ 5.4597e-01 4.3566e-01 7.2143e-01 8.2030e-01 7.7307e-01 9.0936e-01 6.8605e-01 8.2967e-01
+ 9.0430e-01 1.0473e+00 1.2194e+00 1.1919e+00 1.0562e+00 8.3862e-01 9.3453e-01 7.0259e-01
+ 1.2352e+00 8.6417e-01 7.8618e-01 1.1543e+00 1.0342e+00 7.4559e-01 1.3300e+00 1.1237e+00
+ 1.2631e+00 1.1424e+00 1.1704e+00 9.8650e-01 1.0395e+00 1.1901e+00 1.2269e+00 1.1175e+00
+ 1.3298e+00 8.0554e-01 9.8674e-01 7.6426e-01 9.8132e-01 1.0589e+00 1.0549e+00 1.0719e+00
+ 1.0316e+00 8.6485e-01 8.5117e-01 9.1316e-01 1.0601e+00 9.2228e-01 8.6060e-01 3.7186e-01
+ 3.8705e-01 8.4474e-01 7.5253e-01 5.8054e-01 7.1069e-01 7.2083e-01 4.4764e-01 8.8976e-01
+ 6.8718e-01 5.4919e-01 5.2054e-01 4.4112e-01 4.9660e-01 7.3837e-01 3.6635e-01 5.8379e-01
+ 8.1666e-01 1.6873e-01 7.5617e-01 2.7439e-01 1.4514e-01 7.1344e-01 5.3597e-01 7.4598e-01
+ 1.1597e+00 8.3039e-01 7.6481e-01 7.6651e-01 8.8859e-01 9.9142e-01 1.1635e+00 1.2139e+00
+ 1.0710e+00 9.5646e-01 9.2533e-01 1.1658e+00 1.0405e+00 1.0403e+00 1.1829e+00 1.2618e+00
+ 1.2326e+00 1.4151e+00 1.2518e+00 1.3032e+00 1.5380e+00 1.0758e+00 1.2712e+00 1.4846e+00
+ 1.5673e+00 1.4768e+00 1.2428e+00 1.3070e+00 1.1549e+00 1.0747e+00 8.8286e-01 1.0871e+00
+ 8.9775e-01 1.0730e+00 1.1645e+00 1.2594e+00 9.7988e-01 8.9528e-01 8.9638e-01 6.0917e-01
+ 9.8207e-01 7.3767e-01 8.2924e-01 1.0067e+00 4.8695e-01 0.0000e+00 4.6641e-01 6.5065e-01
+ 3.6275e-01 7.7764e-01 6.1181e-01 4.5228e-01 7.3118e-01 5.7426e-01 4.6722e-01 3.2262e-01
+ 1.9632e-01 5.0628e-01 5.2324e-01 6.5060e-01 5.1496e-01 4.1528e-01 7.7577e-01 7.0895e-01
+ 7.3930e-01 9.3351e-01 9.7678e-01 5.3712e-01 6.9977e-01 8.3286e-01 8.0742e-01 7.8865e-01
+ 9.8604e-01 1.0279e+00 8.6586e-01 7.4946e-01 1.1114e+00 1.1437e+00 1.1640e+00 1.3309e+00
+ 9.6911e-01 1.3187e+00 1.4415e+00 1.2606e+00 1.1922e+00 1.1915e+00 1.6500e+00 1.2539e+00
+ 1.5546e+00 1.5452e+00 1.7708e+00 1.6446e+00 1.8525e+00 1.3598e+00 1.3008e+00 1.7246e+00
+ 1.3237e+00 1.0361e+00 7.5119e-01 1.0768e+00 9.9195e-01 9.5994e-01 1.0818e+00 9.7570e-01
+ 7.9053e-01 6.8055e-01 6.1557e-01 7.4892e-01 1.3301e+00 9.0014e-01 1.0099e+00 7.5904e-01
+ 7.2918e-01 7.9057e-01 7.6507e-01 5.2220e-01 7.1632e-01 9.1833e-01 4.2300e-01 8.1052e-01
+ 5.7977e-01 3.5809e-01 6.0739e-01 4.0880e-01 5.5207e-01 5.1668e-01 6.9137e-01 2.4914e-01
+ 8.3332e-01 8.0787e-01 5.7115e-01 3.7189e-01 6.7960e-01 5.8425e-01 7.9021e-01 7.0880e-01
+ 1.0115e+00 7.7712e-01 7.6234e-01 7.7421e-01 1.0829e+00 1.2372e+00 1.0389e+00 1.0731e+00
+ 1.4585e+00 1.1650e+00 1.1727e+00 1.2344e+00 1.5399e+00 1.2088e+00 1.3084e+00 1.2428e+00
+ 1.3181e+00 1.5366e+00 1.6522e+00 2.2247e+00 1.8055e+00 1.9157e+00 1.8726e+00 2.1649e+00
+ 1.5628e+00 1.6736e+00 1.5452e+00 1.2139e+00 1.3883e+00 1.7174e+00 1.2540e+00 1.4433e+00
+ 1.2704e+00 1.1921e+00 1.5528e+00 1.1494e+00 1.0792e+00 7.8124e-01 8.6756e-01 9.3285e-01
+ 1.2440e+00 1.0526e+00 8.4568e-01 9.1665e-01 1.1047e+00 1.0296e+00 1.0183e+00 6.9719e-01
+ 8.5711e-01 7.0991e-01 6.3080e-01 4.7650e-01 5.1685e-01 3.7675e-01 6.6973e-01 6.0835e-01
+ 4.9798e-01 6.9552e-01 2.9988e-01 4.8680e-01 7.2551e-01 6.4750e-01 7.4591e-01 7.4500e-01
+ 6.1583e-01 6.2566e-01 8.5086e-01 5.4685e-01 6.1934e-01 1.1750e+00 1.0176e+00 1.0399e+00
+ 9.0872e-01 9.9910e-01 1.0003e+00 8.7841e-01 1.3538e+00 1.2628e+00 7.7111e-01 1.3048e+00
+ 1.6114e+00 1.5099e+00 1.2822e+00 1.7240e+00 1.6518e+00 1.8968e+00 1.8197e+00 1.9844e+00
+ 2.2770e+00 2.1317e+00 2.2303e+00 2.1401e+00 1.9576e+00 1.8719e+00 1.6650e+00 1.4721e+00
+ 1.5933e+00 1.6680e+00 1.0729e+00 1.0105e+00 1.2063e+00 1.1216e+00 1.2113e+00 1.3023e+00
+ 8.8812e-01 9.1925e-01 1.3091e+00 8.0988e-01 1.1807e+00 6.3748e-01 8.5831e-01 9.4099e-01
+ 6.3264e-01 7.7661e-01 5.9371e-01 5.7269e-01 5.0994e-01 6.2775e-01 5.6235e-01 6.8413e-01
+ 5.6644e-01 4.3556e-01 4.1520e-01 5.5811e-01 5.3962e-01 7.4795e-01 8.3589e-01 7.1217e-01
+ 4.3661e-01 5.9055e-01 6.4448e-01 5.6059e-01 4.7280e-01 1.0528e+00 8.1889e-01 8.8931e-01
+ 1.0036e+00 1.0451e+00 1.0382e+00 9.4138e-01 9.5565e-01 1.3324e+00 9.0583e-01 1.3353e+00
+ 1.0640e+00 1.2343e+00 9.5461e-01 1.5194e+00 1.9680e+00 2.0037e+00 2.1611e+00 1.8135e+00
+ 2.0975e+00 2.2835e+00 2.2501e+00 2.4273e+00 2.3520e+00 2.7134e+00 2.6252e+00 3.2136e+00
+ 2.5931e+00 2.0322e+00 1.7587e+00 1.6499e+00 1.6392e+00 1.8332e+00 1.4165e+00 1.6122e+00
+ 1.6150e+00 1.2994e+00 1.4189e+00 1.5746e+00 1.3560e+00 1.1772e+00 1.1510e+00 1.0084e+00
+ 6.1238e-01 7.9150e-01 1.0961e+00 9.0239e-01 5.0354e-01 1.0339e+00 4.8481e-01 5.9423e-01
+ 5.9561e-01 4.3005e-01 2.2618e-01 9.2348e-01 8.7778e-01 7.1118e-01 6.8332e-01 6.0867e-01
+ 2.7192e-01 7.0975e-01 5.5136e-01 6.6737e-01 8.8971e-01 5.6944e-01 7.8180e-01 6.0272e-01
+ 8.5877e-01 5.3078e-01 8.7391e-01 7.2523e-01 8.7875e-01 8.5337e-01 6.7028e-01 8.4531e-01
+ 8.7766e-01 1.2181e+00 8.2012e-01 1.3396e+00 1.1834e+00 1.4389e+00 1.3963e+00 1.4720e+00
+ 1.8201e+00 1.8705e+00 1.6625e+00 2.1955e+00 2.1209e+00 2.0165e+00 2.2496e+00 2.2534e+00
+ 2.2862e+00 2.4006e+00 2.4014e+00 2.6478e+00 2.4984e+00 2.0622e+00 2.2044e+00 2.1534e+00
+ 1.7684e+00 1.8633e+00 1.3877e+00 1.4754e+00 1.3441e+00 1.3685e+00 1.4794e+00 1.4088e+00
+ 1.6315e+00 1.1060e+00 1.1121e+00 7.3378e-01 6.4760e-01 8.6151e-01 7.6298e-01 8.2459e-01
+ 5.6524e-01 4.7490e-01 8.6649e-01 6.7884e-01 5.6749e-01 7.8528e-01 5.3758e-01 9.6982e-01
+ 3.7004e-01 7.9367e-01 2.8939e-01 2.2388e-01 5.9783e-01 5.9812e-01 6.1317e-01 6.3351e-01
+ 2.5409e-01 6.3033e-01 1.0531e+00 7.8211e-01 8.0491e-01 7.2352e-01 6.9237e-01 1.0039e+00
+ 1.0587e+00 9.8455e-01 1.1533e+00 1.3304e+00 1.3993e+00 1.2522e+00 1.4184e+00 1.4596e+00
+ 1.8630e+00 2.1113e+00 1.8373e+00 1.9867e+00 2.3973e+00 2.2720e+00 2.2458e+00 3.0345e+00
+ 2.5440e+00 2.3466e+00 2.7650e+00 2.3985e+00 2.5693e+00 2.7701e+00 3.5574e+00 3.6836e+00
+ 2.6068e+00 2.6601e+00 2.7002e+00 2.4796e+00 2.5243e+00 2.0637e+00 1.9164e+00 1.8409e+00
+ 1.8583e+00 1.6539e+00 1.9190e+00 1.3134e+00 1.5352e+00 1.3910e+00 1.3401e+00 8.6709e-01
+ 1.2274e+00 8.4748e-01 1.2007e+00 8.4407e-01 7.3970e-01 1.1990e+00 3.3658e-01 1.2077e+00
+ 4.8703e-01 5.2554e-01 3.1450e-01 4.8742e-01 5.7536e-01 7.2859e-01 3.1789e-01 8.0081e-01
+ 5.2647e-01 3.4965e-01 4.6212e-01 4.1015e-01 8.0522e-01 8.0848e-01 8.8474e-01 9.5118e-01
+ 7.7213e-01 6.9029e-01 6.8885e-01 8.1629e-01 9.3249e-01 1.0964e+00 9.5212e-01 1.2918e+00
+ 9.9547e-01 1.3651e+00 1.4121e+00 1.3592e+00 1.4711e+00 1.5680e+00 1.9654e+00 2.0592e+00
+ 2.3581e+00 2.5662e+00 2.1220e+00 2.3787e+00 2.0954e+00 2.5386e+00 2.5034e+00 2.6676e+00
+ 2.5994e+00 2.8262e+00 2.8299e+00 2.8320e+00 2.6392e+00 2.5415e+00 2.3334e+00 2.3553e+00
+ 2.1168e+00 2.2562e+00 2.3489e+00 2.2429e+00 1.8569e+00 1.6471e+00 1.7633e+00 1.4765e+00
+ 1.1477e+00 9.4054e-01 1.2248e+00 7.9443e-01 9.6155e-01 8.2922e-01 1.0867e+00 6.4495e-01
+ 6.7838e-01 6.2611e-01 7.2427e-01 4.9933e-01 4.8263e-01 7.0803e-01 6.4648e-01 8.7981e-01
+ 4.9025e-01 7.2194e-01 7.0617e-01 6.2634e-01 5.3759e-01 6.5768e-01 5.7709e-01 7.3535e-01
+ 6.0370e-01 7.0468e-01 8.4465e-01 7.5659e-01 8.3831e-01 7.8578e-01 7.3705e-01 9.6869e-01
+ 1.1637e+00 9.8619e-01 9.4698e-01 1.0917e+00 1.0645e+00 1.0814e+00 1.6780e+00 1.1972e+00
+ 1.5362e+00 1.7278e+00 2.1980e+00 2.4514e+00 2.9344e+00 2.6312e+00 2.7079e+00 2.3021e+00
+ 3.0331e+00 2.6133e+00 2.7577e+00 2.9516e+00 3.1016e+00 3.3002e+00 3.5992e+00 3.9662e+00
+ 2.9078e+00 2.7999e+00 2.4045e+00 2.6751e+00 2.3809e+00 2.6809e+00 2.3750e+00 2.6779e+00
+ 2.1725e+00 1.9813e+00 1.9482e+00 1.5773e+00 1.3441e+00 1.0662e+00 1.4063e+00 8.8741e-01
+ 1.3956e+00 9.0291e-01 7.1397e-01 9.3263e-01 7.3411e-01 9.1902e-01 4.8136e-01 7.2646e-01
+ 8.1333e-01 5.6662e-01 5.5845e-01 4.1611e-01 6.1384e-01 4.7619e-01 4.1449e-01 4.2723e-01
+ 6.7577e-01 7.0607e-01 4.4893e-01 6.3956e-01 6.0113e-01 9.2562e-01 6.7325e-01 7.4972e-01
+ 8.1739e-01 5.2477e-01 6.7869e-01 7.4936e-01 9.4251e-01 1.0600e+00 1.3866e+00 1.2528e+00
+ 7.9123e-01 1.4639e+00 1.2915e+00 1.4601e+00 1.7552e+00 2.0986e+00 2.4484e+00 2.7786e+00
+ 3.2703e+00 3.0145e+00 2.3844e+00 2.7479e+00 3.2384e+00 3.3838e+00 3.3992e+00 3.6213e+00
+ 4.5306e+00 4.4266e+00 4.9394e+00 4.2146e+00 3.6587e+00 3.2983e+00 3.0549e+00 2.7050e+00
+ 2.6392e+00 3.0178e+00 2.6095e+00 2.6464e+00 2.6201e+00 2.1653e+00 1.4809e+00 1.6618e+00
+ 1.3550e+00 1.3411e+00 1.2453e+00 9.9647e-01 1.3480e+00 1.1171e+00 9.5335e-01 8.6838e-01
+ 8.7911e-01 5.4344e-01 1.2686e+00 7.6509e-01 9.7130e-01 6.0934e-01 9.9031e-01 5.8749e-01
+ 6.4517e-01 8.1753e-01 5.0569e-01 5.7260e-01 6.4694e-01 4.3680e-01 8.2290e-01 7.4991e-01
+ 9.6676e-01 1.0094e+00 6.7499e-01 1.1952e+00 6.2392e-01 9.7600e-01 1.0185e+00 1.2470e+00
+ 8.2424e-01 1.1669e+00 1.3178e+00 1.1228e+00 1.2456e+00 1.1007e+00 1.8810e+00 1.4519e+00
+ 2.1959e+00 2.2944e+00 3.0638e+00 3.2990e+00 3.7960e+00 3.2867e+00 3.1875e+00 3.3097e+00
+ 3.5876e+00 4.3038e+00 4.7550e+00 4.7422e+00 6.0054e+00 6.3707e+00 7.7411e+00 5.3848e+00
+ 5.4079e+00 4.0506e+00 3.8193e+00 3.7489e+00 3.2678e+00 3.9343e+00 3.0279e+00 2.9684e+00
+ 2.6442e+00 1.9696e+00 2.3925e+00 1.9465e+00 1.7289e+00 1.5621e+00 1.1711e+00 1.2439e+00
+ 1.3241e+00 9.4292e-01 1.0209e+00 7.7725e-01 8.8524e-01 1.0796e+00 7.0717e-01 9.3977e-01
+ 1.0068e+00 8.8542e-01 9.0722e-01 7.9666e-01 6.8982e-01 4.7154e-01 8.9727e-01 4.8198e-01
+ 6.3616e-01 5.9023e-01 7.9142e-01 6.5382e-01 7.5341e-01 5.7341e-01 7.0103e-01 9.2726e-01
+ 6.3953e-01 8.4539e-01 6.3091e-01 8.8514e-01 1.1070e+00 1.1918e+00 1.1798e+00 1.0635e+00
+ 1.2133e+00 1.4660e+00 1.5800e+00 1.7966e+00 2.0038e+00 2.4493e+00 2.6753e+00 2.9206e+00
+ 3.2670e+00 3.2952e+00 3.3012e+00 3.8119e+00 4.3075e+00 4.1925e+00 6.1718e+00 6.3883e+00
+ 9.5053e+00 9.5675e+00 1.1303e+01 7.2940e+00 6.2955e+00 5.5714e+00 4.8229e+00 4.4709e+00
+ 3.0600e+00 3.4512e+00 3.1131e+00 3.1507e+00 2.7946e+00 2.3950e+00 2.0335e+00 1.6557e+00
+ 1.3994e+00 1.2790e+00 1.4194e+00 1.0021e+00 9.7998e-01 1.0616e+00 1.1082e+00 1.0600e+00
+ 8.9517e-01 6.6200e-01 7.8679e-01 8.3827e-01 7.0857e-01 7.5504e-01 6.1121e-01 8.4962e-01
+ 7.8150e-01 7.6475e-01 5.5360e-01 5.2650e-01 8.1794e-01 4.8640e-01 3.6352e-01 9.4199e-01
+ 8.2881e-01 5.5692e-01 7.7685e-01 8.1000e-01 9.2980e-01 1.1025e+00 1.1289e+00 1.1238e+00
+ 1.0825e+00 1.0476e+00 1.1449e+00 1.2323e+00 1.6805e+00 1.9971e+00 1.8341e+00 1.8526e+00
+ 2.4655e+00 3.4020e+00 3.0651e+00 3.3881e+00 3.6525e+00 3.9853e+00 3.9248e+00 4.8742e+00
+ 7.0405e+00 6.3430e+00 8.3865e+00 1.2596e+01 1.5193e+01 1.5999e+01 2.2549e+01 1.2316e+01
+ 1.0802e+01 9.3349e+00 6.8629e+00 6.2317e+00 4.2163e+00 4.0440e+00 3.7288e+00 3.5334e+00
+ 3.2292e+00 2.8241e+00 2.2118e+00 2.0218e+00 1.7633e+00 1.3852e+00 1.8260e+00 1.1238e+00
+ 1.1260e+00 1.2277e+00 8.7759e-01 9.5213e-01 1.1377e+00 7.9341e-01 9.2412e-01 9.1137e-01
+ 8.7551e-01 1.1424e+00 9.2100e-01 7.0287e-01 7.7309e-01 7.8234e-01 6.4702e-01 4.3759e-01
+ 4.0372e-01 4.9392e-01 8.2625e-01 3.8508e-01 6.2297e-01 7.4892e-01 1.0404e+00 1.0165e+00
+ 1.0326e+00 9.1599e-01 9.4162e-01 1.1836e+00 1.0044e+00 1.7077e+00 1.3175e+00 1.5570e+00
+ 1.2585e+00 1.4743e+00 1.5058e+00 1.9828e+00 2.5331e+00 3.1101e+00 3.1752e+00 3.4742e+00
+ 4.0230e+00 4.1438e+00 5.0186e+00 7.0188e+00 8.8932e+00 1.2209e+01 1.4220e+01 2.2554e+01
+ 3.3013e+01 3.9297e+01 5.6649e+01 2.0553e+01 2.1185e+01 1.5606e+01 1.0619e+01 7.9344e+00
+ 6.9707e+00 4.4658e+00 3.2806e+00 3.4264e+00 2.9256e+00 2.2695e+00 2.3974e+00 2.2694e+00
+ 1.9370e+00 1.7066e+00 1.6233e+00 1.1857e+00 8.6392e-01 1.0489e+00 9.8677e-01 9.4331e-01
+ 1.0003e+00 7.0782e-01 8.5468e-01 9.9314e-01 9.9799e-01 7.8586e-01 7.8531e-01 7.8468e-01
+ 7.9451e-01 6.3556e-01 5.6249e-01 5.1997e-01 7.1175e-01 5.3126e-01 7.2530e-01 9.4369e-01
+ 6.5124e-01 9.5927e-01 8.2531e-01 8.2392e-01 1.0568e+00 1.3704e+00 1.0318e+00 9.4824e-01
+ 1.2905e+00 1.2373e+00 1.5507e+00 1.4462e+00 1.6541e+00 1.7953e+00 1.8219e+00 2.1000e+00
+ 2.5777e+00 3.0224e+00 3.0855e+00 3.4561e+00 4.0994e+00 4.6636e+00 5.3254e+00 7.5566e+00
+ 1.1410e+01 1.8027e+01 2.4226e+01 4.0183e+01 9.5731e+01 0.0000e+00 0.0000e+00 5.0461e+01
+ 4.9945e+01 2.3082e+01 1.2769e+01 1.0601e+01 6.7270e+00 5.6639e+00 4.0606e+00 3.6989e+00
+ 3.2313e+00 2.5364e+00 2.8125e+00 2.0315e+00 1.9217e+00 1.4879e+00 1.2500e+00 1.2541e+00
+ 1.2912e+00 1.3438e+00 9.1947e-01 9.8200e-01 8.1547e-01 1.1285e+00 1.0357e+00 1.0326e+00
+ 6.6308e-01 6.8106e-01 9.2156e-01 5.9517e-01 9.0059e-01 4.5898e-01 6.6689e-01 6.7308e-01
+ 7.7592e-01 7.7155e-01 7.5407e-01 4.8811e-01 6.6326e-01 9.0620e-01 7.8686e-01 1.1356e+00
+ 9.0234e-01 1.0974e+00 1.2358e+00 1.0797e+00 1.1068e+00 1.0315e+00 1.3315e+00 1.3913e+00
+ 1.4667e+00 1.7789e+00 2.2658e+00 2.0770e+00 2.5085e+00 3.0566e+00 3.2878e+00 3.6157e+00
+ 4.2623e+00 5.6376e+00 6.5582e+00 1.0011e+01 1.6979e+01 3.7153e+01 1.3999e+02 0.0000e+00
+ 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 5.0798e+01 2.9791e+01 1.5701e+01
+ 9.7027e+00 6.5765e+00 4.1549e+00 3.9029e+00 3.6117e+00 2.7764e+00 2.8207e+00 2.2922e+00
+ 1.8877e+00 1.6550e+00 1.6729e+00 1.3423e+00 1.4997e+00 1.3577e+00 8.3081e-01 1.0992e+00
+ 8.3853e-01 1.0185e+00 8.3547e-01 8.1737e-01 7.5002e-01 7.8304e-01 5.8310e-01 9.9641e-01
+ 6.3099e-01 7.4478e-01 3.0907e-01 7.2601e-01 5.7438e-01 5.5766e-01 1.2210e+00 7.6145e-01
+ 6.4521e-01 8.5279e-01 7.3365e-01 1.2321e+00 1.0082e+00 1.1419e+00 1.3395e+00 1.0632e+00
+ 1.3316e+00 1.7011e+00 1.4223e+00 1.6420e+00 1.6912e+00 1.9256e+00 2.3121e+00 2.6863e+00
+ 2.8567e+00 3.3177e+00 3.7523e+00 4.0093e+00 5.1703e+00 6.4021e+00 9.8606e+00 1.5212e+01
+ 2.2926e+01 5.2061e+01 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00
+ 0.0000e+00 0.0000e+00 4.2920e+01 2.1048e+01 1.0234e+01 7.2279e+00 5.7676e+00 5.0339e+00
+ 3.9776e+00 3.3794e+00 3.5170e+00 2.6118e+00 2.2177e+00 2.0435e+00 1.9393e+00 1.6475e+00
+ 1.8254e+00 1.2995e+00 1.3221e+00 1.2135e+00 1.2076e+00 1.4161e+00 8.0113e-01 8.2912e-01
+ 1.0094e+00 8.8782e-01 7.5802e-01 7.3359e-01 6.9425e-01 7.5652e-01 7.5464e-01 6.8079e-01
+ 4.9055e-01 7.0144e-01 8.8208e-01 1.1014e+00 5.7209e-01 1.3050e+00 7.2199e-01 1.2590e+00
+ 8.7359e-01 1.0964e+00 9.7182e-01 1.0459e+00 1.6474e+00 1.3213e+00 2.0316e+00 2.0125e+00
+ 2.1363e+00 2.2772e+00 2.7129e+00 3.0248e+00 3.5706e+00 4.1831e+00 4.4169e+00 4.9057e+00
+ 6.6421e+00 8.1947e+00 1.1590e+01 2.0113e+01 3.2341e+01 0.0000e+00 0.0000e+00 0.0000e+00
+ 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 9.4845e+01 3.2048e+01
+ 1.7402e+01 1.1822e+01 7.5638e+00 5.6422e+00 5.3144e+00 4.4963e+00 4.2581e+00 4.2315e+00
+ 3.0596e+00 2.4810e+00 2.3847e+00 1.7348e+00 2.1012e+00 1.9570e+00 1.4964e+00 1.6161e+00
+ 1.1726e+00 1.2189e+00 1.0717e+00 1.4448e+00 7.0816e-01 9.6704e-01 6.4059e-01 1.0516e+00
+ 9.5439e-01 6.1501e-01 0.0000e+00 4.0935e-01 7.7059e-01 4.6424e-01 1.1193e+00 9.3634e-01
+ 9.3025e-01 9.4203e-01 1.2752e+00 1.1046e+00 1.0044e+00 1.2568e+00 1.3498e+00 1.2968e+00
+ 1.7136e+00 1.4270e+00 1.4809e+00 1.8233e+00 2.1147e+00 2.3778e+00 2.5402e+00 2.5502e+00
+ 3.2987e+00 4.0144e+00 4.1734e+00 4.6894e+00 6.6659e+00 9.5358e+00 1.3827e+01 2.5674e+01
+ 4.8290e+01 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00
+ 0.0000e+00 0.0000e+00 0.0000e+00 6.5155e+01 2.5056e+01 1.6639e+01 1.1380e+01 7.5326e+00
+ 5.8403e+00 5.6161e+00 5.5948e+00 4.9945e+00 3.9312e+00 2.9059e+00 3.0976e+00 2.2734e+00
+ 2.6140e+00 1.4715e+00 1.8166e+00 1.2819e+00 1.3912e+00 1.3378e+00 1.1989e+00 1.2415e+00
+ 8.7480e-01 7.2146e-01 7.8994e-01 7.4993e-01 6.7703e-01 7.2925e-01 9.0866e-01 8.8486e-01
+ 8.1337e-01 6.6850e-01 4.9144e-01 8.7909e-01 7.9945e-01 8.2925e-01 8.4653e-01 8.9984e-01
+ 9.1907e-01 8.4075e-01 1.1417e+00 1.0967e+00 1.2269e+00 1.5324e+00 1.5451e+00 2.0120e+00
+ 2.1375e+00 1.9890e+00 2.3910e+00 2.6960e+00 3.1518e+00 3.8316e+00 4.2823e+00 4.8430e+00
+ 6.1112e+00 9.0076e+00 1.2522e+01 1.9856e+01 3.9600e+01 0.0000e+00 0.0000e+00 0.0000e+00
+ 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 4.6911e+01
+ 2.0968e+01 1.4981e+01 1.0916e+01 7.7767e+00 6.2730e+00 5.6648e+00 5.6687e+00 5.2948e+00
+ 4.3533e+00 3.8283e+00 3.8793e+00 2.8804e+00 3.1820e+00 1.9809e+00 1.8923e+00 1.5363e+00
+ 1.5427e+00 1.4031e+00 1.0189e+00 9.6902e-01 7.8051e-01 8.1739e-01 8.9791e-01 1.0722e+00
+ 7.2592e-01 7.5874e-01 7.0706e-01 7.7218e-01 6.6947e-01 4.7361e-01 8.1724e-01 3.6501e-01
+ 9.4214e-01 7.7193e-01 9.0767e-01 9.7506e-01 7.3702e-01 1.0621e+00 1.2566e+00 1.2471e+00
+ 1.2688e+00 1.3761e+00 1.7828e+00 1.7873e+00 1.6943e+00 2.0984e+00 2.4688e+00 2.5240e+00
+ 2.7625e+00 3.3469e+00 3.6888e+00 4.1253e+00 5.9543e+00 8.0116e+00 1.0882e+01 1.9134e+01
+ 4.6472e+01 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00
+ 0.0000e+00 0.0000e+00 0.0000e+00 5.9915e+01 2.1783e+01 1.3002e+01 9.1307e+00 7.0605e+00
+ 5.5682e+00 4.9423e+00 5.1764e+00 4.5027e+00 3.7275e+00 3.2843e+00 3.3236e+00 2.7249e+00
+ 2.9640e+00 2.0415e+00 1.8913e+00 1.3645e+00 1.5055e+00 1.4571e+00 1.2345e+00 8.4631e-01
+ 1.1003e+00 9.9392e-01 5.1188e-01 8.5165e-01 8.0090e-01 7.4637e-01 9.7852e-01 8.3453e-01
+ 6.6561e-01 5.9539e-01 7.0601e-01 6.7856e-01 1.0839e+00 7.5452e-01 8.7689e-01 8.3999e-01
+ 1.0489e+00 1.0106e+00 1.0068e+00 9.7749e-01 1.2394e+00 1.3336e+00 1.4037e+00 1.7929e+00
+ 1.3819e+00 1.7518e+00 2.5622e+00 2.2555e+00 2.8251e+00 3.2407e+00 3.6402e+00 4.3512e+00
+ 5.2273e+00 7.1346e+00 9.8226e+00 1.5472e+01 2.7959e+01 6.7487e+01 0.0000e+00 0.0000e+00
+ 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 5.3729e+01 2.3803e+01
+ 1.3299e+01 1.0020e+01 7.3161e+00 5.3677e+00 4.4820e+00 4.0826e+00 3.9939e+00 3.4101e+00
+ 3.3523e+00 2.6954e+00 2.6584e+00 2.0050e+00 2.0679e+00 1.7666e+00 1.5436e+00 1.3533e+00
+ 1.4129e+00 1.3191e+00 1.2398e+00 1.1971e+00 7.5116e-01 8.1781e-01 7.3238e-01 6.6847e-01
+ 5.6381e-01 7.9733e-01 6.9579e-01 6.8842e-01 5.3547e-01 7.5265e-01 7.0054e-01 6.9069e-01
+ 1.1532e+00 7.9242e-01 8.9413e-01 7.4401e-01 1.0142e+00 8.4238e-01 1.4220e+00 1.0918e+00
+ 1.1502e+00 1.3549e+00 1.3184e+00 1.2824e+00 1.5634e+00 1.6996e+00 2.1552e+00 2.3311e+00
+ 2.7676e+00 3.3949e+00 3.3286e+00 3.5655e+00 4.7480e+00 6.1602e+00 7.7632e+00 1.2137e+01
+ 1.6861e+01 2.5545e+01 6.9461e+01 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00
+ 0.0000e+00 8.7847e+01 2.9572e+01 1.6660e+01 1.0471e+01 6.1766e+00 4.6191e+00 4.1427e+00
+ 3.6123e+00 3.4399e+00 3.2945e+00 2.8658e+00 2.3218e+00 2.0985e+00 2.0316e+00 1.4707e+00
+ 1.5249e+00 1.6637e+00 1.3473e+00 1.2244e+00 1.0553e+00 1.5340e+00 1.2276e+00 1.0357e+00
+ 7.7496e-01 9.5354e-01 8.4048e-01 9.2511e-01 6.6175e-01 7.3166e-01 3.3405e-01 7.6736e-01
+ 7.3249e-01 3.2808e-01 5.5355e-01 7.3876e-01 5.3245e-01 9.4447e-01 1.1606e+00 9.1472e-01
+ 8.5913e-01 7.7653e-01 1.0665e+00 1.0610e+00 1.0952e+00 1.4113e+00 1.0125e+00 1.4630e+00
+ 1.4118e+00 1.6103e+00 1.8716e+00 2.2283e+00 2.6251e+00 3.4565e+00 3.2401e+00 3.8224e+00
+ 4.3468e+00 4.7953e+00 5.4748e+00 8.9107e+00 1.0479e+01 1.8607e+01 2.9766e+01 4.9231e+01
+ 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 1.1351e+02 2.8160e+01 1.7967e+01 1.1793e+01
+ 7.1475e+00 5.2454e+00 3.6995e+00 3.9936e+00 3.7281e+00 2.8699e+00 2.3887e+00 1.9050e+00
+ 2.0429e+00 1.7078e+00 1.6660e+00 1.3952e+00 1.2784e+00 1.3935e+00 1.0308e+00 1.0435e+00
+ 7.3076e-01 1.0967e+00 8.1866e-01 1.1105e+00 8.9448e-01 4.3920e-01 4.6927e-01 8.3200e-01
+ 6.3341e-01 4.5529e-01 6.6187e-01 7.6860e-01 7.8092e-01 6.4422e-01 6.3213e-01 8.5810e-01
+ 5.9626e-01 9.5893e-01 8.4439e-01 9.7517e-01 9.5513e-01 7.9148e-01 8.9710e-01 1.1087e+00
+ 1.4065e+00 1.2520e+00 1.3112e+00 1.8326e+00 1.6835e+00 1.6292e+00 1.4546e+00 2.3115e+00
+ 3.0137e+00 3.2164e+00 3.8545e+00 3.5845e+00 4.1463e+00 4.7524e+00 5.6986e+00 6.4824e+00
+ 8.7348e+00 1.0517e+01 1.6271e+01 2.6468e+01 4.2391e+01 3.1401e+01 4.4240e+01 2.7518e+01
+ 2.9520e+01 1.6025e+01 1.0632e+01 8.1995e+00 5.9277e+00 4.6151e+00 3.9743e+00 3.4502e+00
+ 3.5254e+00 3.1332e+00 2.7815e+00 2.6918e+00 1.8721e+00 1.8093e+00 1.5879e+00 9.2406e-01
+ 1.6892e+00 1.0544e+00 1.1402e+00 1.0929e+00 8.0777e-01 1.1696e+00 1.3202e-01 5.1259e-01
+ 9.8989e-01 6.5851e-01 9.0320e-01 6.5173e-01 1.0054e+00 6.1268e-01 5.8573e-01 7.6706e-01
+ 4.9959e-01 7.8486e-01 6.9052e-01 4.6424e-01 6.9486e-01 7.9318e-01 6.7496e-01 6.4851e-01
+ 8.7359e-01 8.9668e-01 9.5643e-01 1.0658e+00 8.6771e-01 1.0691e+00 1.1305e+00 1.3940e+00
+ 1.1982e+00 1.6296e+00 1.6879e+00 1.8701e+00 2.6515e+00 3.3069e+00 3.4838e+00 3.6984e+00
+ 3.8791e+00 4.1926e+00 4.4234e+00 6.2060e+00 6.0524e+00 8.0609e+00 1.0307e+01 1.6207e+01
+ 1.8092e+01 1.6908e+01 2.0110e+01 1.4190e+01 1.1960e+01 1.0456e+01 7.6298e+00 6.2609e+00
+ 4.9900e+00 4.1145e+00 3.3675e+00 3.3763e+00 3.4935e+00 2.7332e+00 2.6165e+00 1.9981e+00
+ 1.5993e+00 1.7188e+00 1.4038e+00 1.3174e+00 1.0681e+00 1.1203e+00 1.0135e+00 1.1052e+00
+ 8.7263e-01 1.2273e+00 8.9777e-01 8.2011e-01 9.4941e-01 6.6213e-01 6.9383e-01 8.0665e-01
+ 3.8373e-01 1.0437e+00 8.4715e-01 6.6571e-01 4.4076e-01 6.9195e-01 4.1359e-01 5.1521e-01
+ 6.3356e-01 4.8435e-01 6.5459e-01 7.3274e-01 7.6386e-01 6.8630e-01 7.4425e-01 9.9440e-01
+ 8.5132e-01 1.1182e+00 1.0053e+00 1.2812e+00 1.1711e+00 1.2848e+00 1.7067e+00 1.7390e+00
+ 2.4719e+00 3.1736e+00 3.6719e+00 3.5799e+00 3.8723e+00 3.9625e+00 3.8083e+00 4.2169e+00
+ 5.5388e+00 5.4238e+00 8.5427e+00 8.7154e+00 9.4672e+00 9.6391e+00 1.1111e+01 8.4196e+00
+ 7.7378e+00 6.5322e+00 5.0917e+00 5.2263e+00 3.4764e+00 3.4786e+00 3.1285e+00 3.1180e+00
+ 3.2303e+00 2.3185e+00 2.3533e+00 1.8237e+00 1.5560e+00 1.3865e+00 1.0932e+00 1.3342e+00
+ 1.0610e+00 6.1789e-01 8.0966e-01 1.2089e+00 9.3432e-01 1.0854e+00 9.1458e-01 7.7874e-01
+ 7.3487e-01 6.8503e-01 7.8955e-01 7.7419e-01 7.6307e-01 5.9169e-01 4.3751e-01 8.2664e-01
+ 6.5850e-01 4.6272e-01 8.2337e-01 5.0871e-01 7.2862e-01 5.0961e-01 6.0314e-01 7.7475e-01
+ 9.2695e-01 9.4635e-01 9.4779e-01 9.5680e-01 1.0269e+00 1.4734e+00 1.2645e+00 1.1188e+00
+ 1.0577e+00 1.2639e+00 1.5454e+00 1.8775e+00 2.3554e+00 3.1676e+00 3.6772e+00 3.6866e+00
+ 4.3349e+00 3.9596e+00 3.7069e+00 4.1830e+00 4.2214e+00 4.6342e+00 5.6953e+00 5.9303e+00
+ 6.8892e+00 6.5817e+00 7.3213e+00 5.9292e+00 5.2613e+00 5.5341e+00 4.4044e+00 4.0128e+00
+ 3.3051e+00 3.7024e+00 3.1726e+00 3.5702e+00 3.0915e+00 2.6954e+00 2.6037e+00 1.7896e+00
+ 1.4798e+00 1.3395e+00 1.3618e+00 1.0208e+00 1.3649e+00 9.4865e-01 1.0702e+00 9.4986e-01
+ 1.1164e+00 1.3343e+00 8.7317e-01 1.0748e+00 5.5273e-01 7.9774e-01 7.0280e-01 6.5064e-01
+ 7.2139e-01 4.7046e-01 4.0656e-01 7.2973e-01 5.6476e-01 4.8967e-01 5.0998e-01 6.3872e-01
+ 5.4602e-01 6.0937e-01 7.5800e-01 9.4833e-01 7.0236e-01 6.9084e-01 9.5855e-01 9.1198e-01
+ 9.5110e-01 9.1807e-01 1.0595e+00 1.0218e+00 1.2728e+00 1.3475e+00 1.8261e+00 1.7446e+00
+ 2.1617e+00 2.5917e+00 3.0138e+00 3.3289e+00 3.8230e+00 3.1834e+00 3.1328e+00 3.0503e+00
+ 3.6545e+00 3.5898e+00 3.7212e+00 4.3662e+00 4.2269e+00 4.5226e+00 4.5331e+00 4.8227e+00
+ 3.9210e+00 3.3356e+00 3.1356e+00 3.5857e+00 3.0791e+00 3.4900e+00 2.9649e+00 3.1672e+00
+ 2.5267e+00 2.1517e+00 1.9954e+00 1.6638e+00 1.3283e+00 1.4518e+00 1.2632e+00 9.2889e-01
+ 1.1602e+00 1.2641e+00 9.7317e-01 5.8957e-01 8.1000e-01 1.0440e+00 7.0485e-01 6.2887e-01
+ 6.7374e-01 4.5636e-01 6.2419e-01 7.4956e-01 5.5239e-01 7.4729e-01 6.0693e-01 6.3152e-01
+ 6.1008e-01 8.4820e-01 7.3876e-01 4.0666e-01 9.0870e-01 6.9148e-01 6.4515e-01 6.9784e-01
+ 8.8561e-01 8.3808e-01 8.1425e-01 9.1991e-01 1.1297e+00 1.0499e+00 9.5568e-01 1.1484e+00
+ 1.0418e+00 1.3103e+00 1.4393e+00 1.4386e+00 1.8243e+00 2.5584e+00 2.6885e+00 3.1259e+00
+ 3.2014e+00 3.4691e+00 2.8616e+00 3.2026e+00 3.1613e+00 2.9170e+00 3.5059e+00 3.9672e+00
+ 3.9200e+00 3.8769e+00 4.5891e+00 4.2822e+00 3.5470e+00 3.1832e+00 2.7409e+00 2.8327e+00
+ 3.0952e+00 3.2185e+00 2.6727e+00 3.0869e+00 2.4151e+00 1.9207e+00 1.5014e+00 1.1624e+00
+ 1.4424e+00 1.3991e+00 1.4486e+00 6.8971e-01 1.2068e+00 1.2910e+00 1.0852e+00 1.0989e+00
+ 6.3991e-01 4.9916e-01 6.0868e-01 9.0367e-01 8.3932e-01 8.1202e-01 9.2835e-01 2.4268e-01
+ 6.7668e-01 9.1401e-01 5.6685e-01 3.7409e-01 4.8854e-01 6.2235e-01 4.8680e-01 4.8814e-01
+ 4.0083e-01 7.2697e-01 7.6775e-01 3.3271e-01 7.3827e-01 5.7071e-01 8.1463e-01 8.1140e-01
+ 8.4585e-01 9.8270e-01 8.7285e-01 9.8296e-01 1.1108e+00 1.2972e+00 1.5196e+00 1.4512e+00
+ 1.7463e+00 2.3910e+00 2.0997e+00 2.4977e+00 3.0434e+00 2.9903e+00 2.5911e+00 2.8583e+00
+ 2.6735e+00 2.7177e+00 3.0668e+00 3.2663e+00 3.0958e+00 3.0717e+00 3.4579e+00 3.4759e+00
+ 3.0543e+00 2.5514e+00 2.1726e+00 2.5072e+00 2.3803e+00 2.9697e+00 2.6097e+00 2.3373e+00
+ 2.2195e+00 1.6051e+00 1.7227e+00 1.5032e+00 1.1934e+00 1.2743e+00 1.1310e+00 7.0584e-01
+ 1.2835e+00 1.0840e+00 6.3177e-01 9.6786e-01 8.3730e-01 7.7928e-01 9.6761e-01 5.3862e-01
+ 2.8887e-01 6.3566e-01 7.8057e-01 7.8825e-01 6.3993e-01 3.3013e-01 4.4409e-01 5.3031e-01
+ 6.8485e-01 4.4424e-01 5.9825e-01 9.3761e-01 7.0921e-01 5.9262e-01 8.4074e-01 6.0775e-01
+ 5.7712e-01 8.8120e-01 7.0696e-01 7.7476e-01 7.8562e-01 1.0221e+00 1.1476e+00 1.2257e+00
+ 1.0729e+00 1.1592e+00 1.4012e+00 1.8105e+00 1.3975e+00 1.9331e+00 1.8646e+00 2.0403e+00
+ 2.6150e+00 2.4747e+00 2.5822e+00 2.3618e+00 2.6036e+00 2.7077e+00 2.5833e+00 2.1951e+00
+ 2.7725e+00 3.0310e+00 3.1004e+00 3.0434e+00 2.6440e+00 2.6550e+00 2.5436e+00 2.5267e+00
+ 2.1971e+00 2.3324e+00 2.1710e+00 2.0559e+00 1.8038e+00 1.5256e+00 1.2395e+00 1.4842e+00
+ 1.3827e+00 9.6130e-01 1.1451e+00 1.0627e+00 1.0267e+00 7.2066e-01 6.9803e-01 9.5137e-01
+ 8.6266e-01 6.2062e-01 8.8041e-01 8.6741e-01 7.7485e-01 5.8879e-01 5.2851e-01 3.9828e-01
+ 2.9050e-01 1.0473e-01 4.4519e-01 4.5206e-01 3.9288e-01 0.0000e+00 6.2746e-01 8.8582e-01
+ 4.2479e-01 6.5753e-01 4.4990e-01 8.4593e-01 1.0223e+00 3.1928e-01 7.8820e-01 9.9547e-01
+ 1.0171e+00 1.1412e+00 7.6071e-01 9.7475e-01 1.1184e+00 1.6407e+00 1.1274e+00 1.4749e+00
+ 1.6886e+00 1.5619e+00 1.6679e+00 1.7942e+00 2.4290e+00 2.3281e+00 1.8599e+00 2.4950e+00
+ 2.7345e+00 2.6515e+00 3.1064e+00 2.6008e+00 3.3500e+00 2.8580e+00 3.3334e+00 2.4728e+00
+ 2.6507e+00 2.5488e+00 2.6689e+00 2.5231e+00 2.3131e+00 2.1404e+00 2.0858e+00 1.9254e+00
+ 1.8218e+00 1.4332e+00 1.8061e+00 1.2980e+00 1.3579e+00 1.0824e+00 1.1883e+00 1.1137e+00
+ 1.2342e+00 7.8437e-01 6.5963e-01 5.2832e-01 7.9838e-01 8.9856e-01 3.9001e-01 7.1613e-01
+ 7.4494e-01 7.5612e-01 6.3372e-01 6.7287e-01 6.8839e-01 0.0000e+00 3.5184e-01 8.5513e-01
+ 3.9575e-01 9.3322e-01 4.8611e-01 6.2095e-01 4.9160e-01 5.1682e-01 6.1498e-01 7.2197e-01
+ 8.4625e-01 1.0314e+00 6.2986e-01 8.4463e-01 1.0012e+00 9.3683e-01 9.0432e-01 1.1644e+00
+ 1.1565e+00 1.1797e+00 1.4096e+00 1.0663e+00 1.2789e+00 1.6010e+00 1.4137e+00 1.5567e+00
+ 1.4569e+00 1.8596e+00 1.6700e+00 2.0895e+00 2.5412e+00 2.7097e+00 2.8458e+00 2.9468e+00
+ 3.3274e+00 3.3117e+00 2.9586e+00 3.1044e+00 2.8171e+00 2.2215e+00 2.0149e+00 2.0284e+00
+ 1.6870e+00 2.0030e+00 1.4959e+00 1.7373e+00 1.1838e+00 1.1315e+00 1.3918e+00 1.3344e+00
+ 8.4840e-01 8.9260e-01 9.0630e-01 1.0636e+00 1.2061e+00 8.7174e-01 5.6882e-01 3.5883e-01
+ 8.2742e-01 1.0948e+00 6.6130e-01 8.9182e-01 6.8647e-01 6.4169e-01 5.0829e-01 8.6913e-01
+ 4.6950e-01 4.7709e-01 7.1625e-01 6.1058e-01 8.3221e-01 7.7175e-01 4.5020e-01 6.6929e-01
+ 6.1181e-01 5.1256e-01 8.0725e-01 3.7170e-01 8.4239e-01 8.7079e-01 1.0836e+00 8.2322e-01
+ 7.5109e-01 1.0445e+00 9.0597e-01 1.1347e+00 1.4657e+00 1.0290e+00 1.1355e+00 1.0873e+00
+ 1.5307e+00 1.4820e+00 1.3078e+00 1.0916e+00 1.1688e+00 1.6816e+00 1.6377e+00 2.0355e+00
+ 1.9695e+00 2.1466e+00 2.8435e+00 2.9696e+00 3.2723e+00 2.9679e+00 3.1350e+00 2.8606e+00
+ 2.5339e+00 2.2108e+00 2.1415e+00 2.0449e+00 1.5250e+00 1.4422e+00 1.3287e+00 1.5725e+00
+ 1.2625e+00 1.4024e+00 1.1100e+00 1.2142e+00 9.6484e-01 9.2184e-01 1.3111e+00 8.5945e-01
+ 1.0873e+00 6.8755e-01 9.2818e-01 6.3916e-01 7.1795e-01 9.4675e-01 9.7171e-01 5.7802e-01
+ 7.6988e-01 7.0746e-01 6.2514e-01 7.5041e-01 6.5557e-01 5.9248e-01 3.2761e-01 2.4660e-01
+ 4.6869e-01 7.2737e-01 4.8649e-01 7.2220e-01 6.8589e-01 6.9013e-01 7.6271e-01 5.4163e-01
+ 8.0266e-01 7.2950e-01 1.0130e+00 1.0745e+00 7.5017e-01 1.0825e+00 1.4132e+00 1.4677e+00
+ 9.8180e-01 9.9552e-01 1.0126e+00 1.4221e+00 1.2264e+00 1.4178e+00 1.2629e+00 9.9021e-01
+ 1.8445e+00 1.5581e+00 1.6624e+00 1.7653e+00 2.0445e+00 2.0066e+00 2.3510e+00 2.7732e+00
+ 2.7269e+00 2.8994e+00 3.0516e+00 3.0420e+00 2.5623e+00 1.9350e+00 1.8289e+00 1.6685e+00
+ 1.7396e+00 1.6277e+00 1.3335e+00 1.3958e+00 1.1190e+00 1.4627e+00 1.2014e+00 8.6648e-01
+ 1.0434e+00 1.2476e+00 1.0380e+00 9.2538e-01 5.7075e-01 6.3587e-01 6.8926e-01 7.8046e-01
+ 9.3655e-01 7.9137e-01 6.6742e-01 9.0963e-01 6.0166e-01 6.8870e-01 6.2552e-01 6.7478e-01
+ 6.6555e-01 6.7088e-01 2.2725e-01 6.8030e-01 3.4861e-01 8.4427e-01 6.5460e-01 6.7810e-01
+ 7.1249e-01 1.0177e+00 5.9531e-01 3.5955e-01 5.2426e-01 5.4903e-01 1.0090e+00 4.3016e-01
+ 7.4425e-01 5.6787e-01 9.3929e-01 1.0743e+00 1.2610e+00 8.5384e-01 1.1229e+00 1.0143e+00
+ 9.4842e-01 9.3564e-01 1.3438e+00 1.3743e+00 1.9336e+00 1.0930e+00 1.0848e+00 1.2175e+00
+ 1.5984e+00 1.5540e+00 2.0179e+00 1.9221e+00 2.3203e+00 2.2220e+00 2.1679e+00 2.1509e+00
+ 2.1080e+00 1.7303e+00 1.2767e+00 1.6537e+00 1.0331e+00 1.4767e+00 1.2096e+00 1.3424e+00
+ 1.0269e+00 8.6719e-01 1.0218e+00 1.3481e+00 1.1100e+00 9.0846e-01 1.1446e+00 1.0135e+00
+ 6.8935e-01 8.5926e-01 8.8487e-01 8.9172e-01 7.3392e-01 5.8627e-01 7.6730e-01 5.6237e-01
+ 5.7033e-01 4.4465e-01 5.5465e-01 5.5557e-01 5.6554e-01 5.7476e-01 6.0030e-01 4.1602e-01
+ 5.2665e-01 8.4227e-01 6.8427e-01 7.4612e-01 4.8523e-01 5.3588e-01 7.2213e-01 7.8527e-01
+ 7.9287e-01 7.7450e-01 7.6115e-01 7.4639e-01 9.8894e-01 1.1300e+00 7.1562e-01 1.0140e+00
+ 8.8479e-01 1.0949e+00 1.2627e+00 9.5783e-01 8.4270e-01 1.2532e+00 1.2723e+00 1.0751e+00
+ 1.3731e+00 1.4783e+00 1.1899e+00 1.1871e+00 1.3617e+00 1.5638e+00 1.3670e+00 1.5918e+00
+ 1.9634e+00 1.6725e+00 1.7602e+00 1.7894e+00 1.2099e+00 1.0250e+00 1.0492e+00 1.3165e+00
+ 1.0802e+00 1.1077e+00 1.3026e+00 1.2119e+00 1.3077e+00 1.0641e+00 1.2353e+00 9.4462e-01
+ 9.8142e-01 9.7477e-01 1.0960e+00 9.0340e-01 9.9968e-01 7.8775e-01 9.3259e-01 5.4980e-01
+ 8.2451e-01 4.3577e-01 7.8298e-01 7.3596e-01 6.5962e-01 7.2002e-01 5.4815e-01 4.9530e-01
+ 6.0169e-01 8.3839e-01 5.6737e-01 5.0081e-01 0.0000e+00 3.9282e-01 6.8761e-01 7.1946e-01
+ 5.8028e-01 6.4560e-01 6.5827e-01 8.6429e-01 6.2843e-01 3.6834e-01 7.6709e-01 4.2220e-01
+ 5.6401e-01 1.2331e+00 6.5250e-01 7.5836e-01 7.9014e-01 1.1022e+00 1.0772e+00 1.2986e+00
+ 1.1948e+00 1.2573e+00 7.9281e-01 8.4581e-01 1.1802e+00 1.1002e+00 1.0827e+00 1.3884e+00
+ 1.2083e+00 1.4866e+00 1.1849e+00 1.4480e+00 1.0842e+00 1.4924e+00 1.6364e+00 1.6845e+00
+ 1.3674e+00 1.0210e+00 9.4714e-01 1.2059e+00 1.2440e+00 1.0846e+00 1.0512e+00 8.2079e-01
+ 1.0185e+00 8.1507e-01 1.1672e+00 9.6595e-01 8.8620e-01 9.1507e-01 8.7011e-01 7.3470e-01
+ 7.7113e-01 9.1332e-01 5.0352e-01 1.1307e+00 7.0851e-01 6.6796e-01 4.4359e-01 4.8871e-01
+ 7.3163e-01 5.4065e-01 5.6106e-01 4.5675e-01 0.0000e+00 4.9362e-01 4.8848e-01 6.6596e-01
+ 7.9924e-01 7.9062e-01 6.2709e-01 5.8036e-01 7.4209e-01 7.6257e-01 7.4360e-01 8.5183e-01
+ 7.0559e-01 8.7442e-01 6.0457e-01 9.5159e-01 7.9028e-01 8.6280e-01 1.0148e+00 1.0779e+00
+ 1.0510e+00 7.0556e-01 9.5216e-01 1.0312e+00 1.4441e+00 7.4977e-01 1.0409e+00 1.0938e+00
+ 8.7737e-01 1.2925e+00 7.0656e-01 1.1698e+00 1.3141e+00 1.0164e+00 1.4541e+00 1.4306e+00
+ 1.1719e+00 1.6082e+00 1.4637e+00 1.5508e+00 1.3881e+00 8.2769e-01 1.2601e+00 8.3333e-01
+ 1.0514e+00 1.0452e+00 8.7851e-01 1.0556e+00 1.3188e+00 9.7797e-01 8.2657e-01 9.5495e-01
+ 9.4160e-01 6.2057e-01 4.8680e-01 6.7990e-01 8.8560e-01 9.0547e-01 5.7462e-01 5.7157e-01
+ 7.6190e-01 7.2138e-01 5.5452e-01 7.9772e-01 7.1769e-01 5.6744e-01 6.2170e-01 4.7942e-01
+ 6.2170e-01 4.1432e-01 3.6970e-01 6.9486e-01 6.6010e-01 5.8503e-01 3.0990e-01 7.1954e-01
+ 8.1220e-01 7.4154e-01 8.5660e-01 5.6278e-01 6.2424e-01 8.5965e-01 6.7930e-01 5.9194e-01
+ 7.9576e-01 8.3056e-01 9.3742e-01 8.9530e-01 5.2994e-01 8.2793e-01 8.0963e-01 1.1937e+00
+ 8.8559e-01 1.1844e+00 8.5835e-01 1.0469e+00 1.0171e+00 7.5477e-01 9.2028e-01 1.0652e+00
+ 9.6974e-01 1.0788e+00 1.2902e+00 1.1485e+00 1.0969e+00 1.0657e+00 1.2511e+00 1.0117e+00
+ 1.0624e+00 1.1190e+00 8.5045e-01 1.0054e+00 1.0780e+00 1.0052e+00 8.6242e-01 1.1246e+00
+ 7.3041e-01 8.1440e-01 7.7886e-01 1.0117e+00 1.0245e+00 9.2262e-01 1.2843e+00 4.7557e-01
+ 7.0359e-01 8.3901e-01 8.6459e-01 8.3865e-01 9.2440e-01 7.3590e-01 7.9440e-01 6.4951e-01
+ 7.4962e-01 6.3530e-01 6.2344e-01 6.2571e-01 6.1598e-01 6.9141e-01 4.2732e-01 5.0509e-01
+ 3.9792e-01 5.0116e-01 6.2790e-01 6.5413e-01 8.0970e-01 5.9349e-01 8.2879e-01 7.5959e-01
+ 6.8008e-01 5.5180e-01 5.9625e-01 5.5752e-01 8.8647e-01 8.1147e-01 7.8914e-01 8.8397e-01
+ 8.8704e-01 1.0173e+00 1.0859e+00 1.0621e+00 7.1546e-01 6.5106e-01 7.0539e-01 1.0066e+00
+ 1.2482e+00 1.0484e+00 1.1521e+00 1.0355e+00 1.0231e+00 1.1614e+00 1.2838e+00 1.0458e+00
+ 1.3113e+00 1.1787e+00 1.1499e+00 1.4513e+00 9.2865e-01 1.0118e+00 9.8864e-01 6.3854e-01
+ 9.2366e-01 8.6306e-01 8.7148e-01 1.0902e+00 7.7965e-01 8.7205e-01 6.1310e-01 9.8272e-01
+ 5.1750e-01 6.7830e-01 8.8657e-01 4.5008e-01 8.0164e-01 5.4911e-01 3.7134e-01 7.5114e-01
+ 6.8176e-01 1.1561e+00 5.5315e-01 5.6774e-01 6.1945e-01 6.5877e-01 6.1904e-01 5.6589e-01
+ 0.0000e+00 4.6382e-01 7.6835e-01 3.1545e-01 5.1226e-01 4.2276e-01 5.6265e-01 6.4282e-01
+ 5.9013e-01 6.5049e-01 6.2268e-01 5.9910e-01 5.2920e-01 7.3273e-01 8.7073e-01 6.2812e-01
+ 8.5035e-01 7.5308e-01 6.5416e-01 6.2272e-01 6.8833e-01 9.5971e-01 5.9897e-01 9.4187e-01
+ 9.6467e-01 1.0743e+00 1.0274e+00 1.0167e+00 6.7567e-01 1.2233e+00 1.1655e+00 9.9449e-01
+ 1.3018e+00 9.4104e-01 1.2060e+00 1.1374e+00 1.1348e+00 1.1829e+00 9.7795e-01 1.1040e+00
+ 8.9447e-01 9.1667e-01 8.2826e-01 1.3199e+00 8.5741e-01 9.5014e-01 8.0515e-01 1.0705e+00
+ 7.9270e-01 1.0312e+00 1.0490e+00 1.1273e+00 8.1390e-01 1.0196e+00 6.5390e-01 6.5650e-01
+ 2.3313e-01 6.2156e-01 9.2511e-01 5.7296e-01 5.4496e-01 6.8766e-01 4.9465e-01 6.2506e-01
+ 3.2538e-01 6.1595e-01 5.6537e-01 5.2968e-01 5.5228e-01 6.5977e-01 2.2695e-01 4.5546e-01
+ 5.1527e-01 6.6223e-01 5.8019e-01 5.8662e-01 7.9234e-01 3.2775e-01 6.1519e-01 9.6199e-01
+ 7.4471e-01 5.6981e-01 6.8067e-01 6.3159e-01 6.4989e-01 5.6263e-01 6.7000e-01 4.3185e-01
+ 7.0320e-01 6.0249e-01 8.5266e-01 6.8925e-01 5.9288e-01 8.1852e-01 7.7636e-01 7.3423e-01
+ 5.2571e-01 8.1784e-01 8.1350e-01 7.1710e-01 6.5688e-01 9.6005e-01 5.4735e-01 9.2973e-01
+ 1.0611e+00 4.7541e-01 8.2851e-01 1.2527e+00 1.0001e+00 9.7119e-01 8.6292e-01 8.6591e-01
+ 7.8335e-01 9.9468e-01 9.0563e-01 8.7872e-01 9.6235e-01 7.3460e-01 6.5817e-01 9.7941e-01
+ 8.0014e-01 7.3905e-01 7.6843e-01 6.9665e-01 8.6951e-01 4.7252e-01 4.8065e-01 5.6728e-01
+ 6.4515e-01 4.8205e-01 3.3177e-01 7.4233e-01 6.0593e-01 6.5392e-01 4.6457e-01 2.8235e-01
+ 6.4826e-01 4.0761e-01 5.4062e-01 6.4364e-01 4.0849e-01 4.6388e-01 4.8947e-01 6.1256e-01
+ 6.6811e-01 6.0256e-01 7.2630e-01 8.7075e-01 5.9552e-01 6.0816e-01 9.9978e-01 3.5934e-01
+ 5.3659e-01 9.2418e-01 5.4087e-01 6.5513e-01 3.5414e-01 8.6575e-01 7.9881e-01 9.9010e-01
+ 5.7831e-01 8.2570e-01 8.7891e-01 7.2274e-01 5.7902e-01 7.6387e-01 8.9392e-01 6.8674e-01
+ 7.6520e-01 1.1926e+00 5.5703e-01 5.3467e-01 7.0949e-01 6.3978e-01 7.7328e-01 1.2845e+00
+ 6.6021e-01 6.7869e-01 7.4436e-01 9.6550e-01 3.9359e-01 6.9273e-01 6.7609e-01 8.3776e-01
+ 6.0466e-01 8.8113e-01 1.0519e+00 8.5118e-01 5.8389e-01 8.2103e-01 5.4011e-01 6.9912e-01
+ 5.9819e-01 7.2696e-01 7.0119e-01 4.2214e-01 7.1854e-01 9.7017e-01 5.2052e-01 7.2733e-01
+ 6.1040e-01 5.7880e-01 2.8712e-01 4.8188e-01 3.0740e-01 7.5992e-01 5.5462e-01 5.3452e-01
+ 6.4936e-01 6.1660e-01 4.0905e-01 3.7366e-01 2.0805e-01 7.6692e-01 4.2181e-01 7.9662e-01
+ 6.0187e-01 5.8508e-01 7.7528e-01 5.1199e-01 5.8443e-01 4.7514e-01 6.9570e-01 8.1044e-01
+ 5.7924e-01 7.3337e-01 5.9897e-01 5.6226e-01 7.9071e-01 8.3979e-01 6.0200e-01 7.8748e-01
+ 6.1591e-01 8.3103e-01 6.7615e-01 8.1362e-01 7.9189e-01 8.0210e-01 7.0101e-01 9.8928e-01
+ 9.2123e-01 7.5460e-01 9.4911e-01 6.5208e-01 4.6093e-01 6.4642e-01 7.8366e-01 7.4394e-01
+ 8.0010e-01 6.3766e-01 9.2446e-01 6.9793e-01 5.8162e-01 4.9181e-01 2.3010e-01 9.7186e-01
+ 4.4617e-01 5.6906e-01 4.4407e-01 6.5796e-01 7.1008e-01 5.4920e-01 5.8462e-01 6.9439e-01
+ 6.5106e-01 5.7130e-01 7.7524e-01 5.4989e-01 6.3900e-01 6.3451e-01 7.5558e-01 6.0302e-01
+ 4.8396e-01 5.6322e-01 4.8727e-01 6.2559e-01 9.4190e-01 3.4923e-01 5.6544e-01 4.3793e-01
+ 7.5587e-01 7.3265e-01 7.9147e-01 4.5849e-01 9.2285e-01 5.0773e-01 5.0963e-01 7.6882e-01
+ 5.6263e-01 4.8501e-01 6.7555e-01 6.1943e-01 6.6412e-01 9.4536e-01 6.3952e-01 5.6133e-01
+ 4.8223e-01 9.9991e-01 8.3745e-01 3.8215e-01 7.1113e-01 9.2391e-01 6.5589e-01 2.9090e-01
+ 1.0013e+00 5.2436e-01 9.0963e-01 9.4712e-01 1.1897e+00 8.1104e-01 1.2402e+00 1.0203e+00
+ 1.0813e+00 5.5146e-01 4.5119e-01 7.9209e-01 7.9388e-01 4.1861e-01 8.3004e-01 1.0181e+00
+ 8.0823e-01 7.7835e-01 9.2414e-01 1.0810e+00 9.9999e-01 4.5899e-01 6.5767e-01 6.9229e-01
+ 6.5995e-01 6.2290e-01 4.8726e-01 3.3535e-01 3.3798e-01 1.6003e-01 6.0290e-01 8.8200e-01
+ 8.2315e-01 9.7080e-01 4.0314e-01 7.7211e-01 5.3477e-01 5.1236e-01 6.8883e-01 6.9638e-01
+ 5.5899e-01 7.1336e-01 5.8303e-01 8.7315e-01 9.9840e-01 8.6919e-01 7.3963e-01 0.0000e+00
+ 5.7124e-01 8.6790e-01 3.8830e-01 6.4721e-01 7.3232e-01 7.1095e-01 7.6884e-01 6.9396e-01
+ 8.5118e-01 5.8680e-01 6.4402e-01 8.9640e-01 5.7494e-01 9.3323e-01 9.3878e-01 5.1086e-01
+ 9.0953e-01 7.8485e-01 5.1292e-01 7.3478e-01 9.8403e-01 8.1504e-01 1.0108e+00 8.1033e-01
+ 7.3747e-01 7.9859e-01 6.7874e-01 8.7949e-01 7.9019e-01 6.7313e-01 6.4849e-01 5.9797e-01
+ 7.3428e-01 5.6754e-01 5.6669e-01 6.2594e-01 4.6219e-01 4.7251e-01 9.4698e-01 7.7826e-01
+ 7.2147e-01 7.5538e-01 3.7410e-01 4.5775e-01 7.7966e-01 9.3034e-01 4.0968e-01 4.2318e-01
+ 9.5859e-01 0.0000e+00 8.6050e-01 6.7592e-01 8.1824e-01 0.0000e+00 3.4995e-01 3.2979e-01
+ 6.3243e-01 4.3515e-01 5.5576e-01 1.1036e-01 3.8923e-01 6.2469e-01 6.4016e-01 4.6996e-01
+ 6.5823e-01 5.7292e-01 8.2463e-01 7.8514e-01 5.2483e-01 4.9022e-01 7.1729e-01 4.8578e-01
+ 6.8995e-01 8.3970e-01 5.6972e-01 6.9176e-01 7.3955e-01 7.3454e-01 4.7416e-01 6.5020e-01
+ 8.4943e-01 8.2315e-01 5.9232e-01 2.8417e-01 6.9301e-01 3.2754e-01 6.7989e-01 4.2858e-01
+ 3.8109e-01 7.2355e-01 8.2982e-01 8.2188e-01 8.5052e-01 7.4157e-01 7.7848e-01 6.3428e-01
+ 5.9552e-01 8.2263e-01 7.7460e-01 4.6482e-01 7.1890e-01 8.3263e-01 7.0210e-01 4.9175e-01
+ 7.0427e-01 6.2588e-01 7.0665e-01 7.9336e-01 6.7113e-01 6.0489e-01 6.7296e-01 5.5123e-01
+ 7.1686e-01 7.1797e-01 7.9101e-01 7.3100e-01 6.2797e-01 2.7204e-01 4.6489e-01 5.4520e-01
+ 5.9575e-01 3.8835e-01 6.6793e-01 6.2970e-01 3.6889e-01 5.7294e-01 5.2445e-01 3.8153e-01
+ 5.9379e-01 6.6669e-01 5.8484e-01 4.7262e-01 7.0322e-01 9.6588e-01 8.1376e-01 4.1641e-01
+ 6.8442e-01 6.9113e-01 5.3900e-01 5.3641e-01 8.0756e-01 9.2233e-01 5.7263e-01 5.4576e-01
+ 5.4935e-01 6.4865e-01 6.3788e-01 6.0196e-01 7.2924e-01 8.4535e-01 8.5630e-01 8.7128e-01
+ 5.1236e-01 9.1224e-01 7.9943e-01 5.3767e-01 1.1605e+00 8.6714e-01 6.8049e-01 1.0627e+00
+ 5.2330e-01 9.7035e-01 6.5715e-01 9.3900e-01 6.9107e-01 6.5740e-01 8.1621e-01 5.4729e-01
+ 6.1526e-01 8.9708e-01 6.1702e-01 5.7833e-01 5.0976e-01 6.7141e-01 8.7729e-01 5.0140e-01
+ 4.8786e-01 6.5995e-01 5.6500e-01 6.2429e-01 4.1229e-01 5.1159e-01 7.6059e-01 5.6539e-01
+ 6.0607e-01 4.9990e-01 5.2093e-01 3.6936e-01 5.1179e-01 5.2912e-01 3.4071e-01 0.0000e+00
+ 3.5754e-01 4.9501e-01 6.8872e-01 1.0428e-01 2.8337e-01 5.0308e-01 7.4495e-01 6.0741e-01
+ 4.8909e-01 6.0272e-01 5.6017e-01 2.4699e-01 3.1486e-01 3.5694e-01 7.3792e-01 5.5534e-01
+ 5.8993e-01 4.6877e-01 3.9438e-01 4.8856e-01 6.0736e-01 4.6349e-01 7.9941e-01 0.0000e+00
+ 5.2711e-01 5.9080e-01 4.9332e-01 5.6507e-01 5.1963e-01 5.4631e-01 7.0566e-01 6.1494e-01
+ 7.6779e-01 6.4447e-01 5.5835e-01 5.8138e-01 6.7448e-01 7.8105e-01 5.7779e-01 8.6001e-01
+ 7.8089e-01 4.3105e-01 4.4259e-01 9.1779e-01 6.4268e-01 8.3055e-01 6.5325e-01 6.8230e-01
+ 6.8359e-01 5.6433e-01 5.2444e-01 7.0274e-01 5.5916e-01 7.0259e-01 4.8136e-01 2.6275e-01
+ 7.4866e-01 6.3894e-01 7.9476e-01 5.0708e-01 4.6684e-01 0.0000e+00 6.4938e-01 3.1630e-01
+ 4.0057e-01 7.1344e-01 2.3787e-01 4.9887e-01 5.3425e-01 6.4096e-01 6.3499e-01 4.3390e-01
+ 5.6617e-01 5.5082e-01 5.4102e-01 7.3095e-01 5.8923e-01 3.8410e-01 8.8639e-01 3.6685e-01
+ 5.2915e-01 1.8893e-01 3.8857e-01 8.7676e-01 4.8984e-01 6.2138e-01 4.7151e-01 6.1358e-01
+ 4.1380e-01 5.5404e-01 4.0203e-01 8.2270e-01 9.7520e-01 1.0884e+00 5.3409e-01 6.2393e-01
+ 6.8080e-01 8.3380e-01 1.4772e-01 5.8190e-01 9.8473e-01 9.8906e-01 8.1520e-01 7.7920e-01
+ 7.5267e-01 5.8285e-01 8.1130e-01 5.4210e-01 8.5067e-01 4.4295e-01 6.3178e-01 0.0000e+00
+ 5.9546e-01 7.5652e-01 7.9643e-01 4.2802e-01 5.0301e-01 6.2033e-01 6.3698e-01 6.6384e-01
+ 8.2275e-01 4.5429e-01 5.5538e-01 6.7811e-01 5.1742e-01 4.9457e-01 7.0343e-01 6.9848e-01
+ 6.9230e-01 7.4731e-01 5.7772e-01 7.6468e-01 7.9844e-01 7.8165e-01 4.1879e-01 6.2952e-01
+ 5.6605e-01 3.0034e-01 3.9524e-01 2.0276e-01 5.5454e-01 4.0540e-01 6.1724e-01 5.2535e-01
+ 5.7736e-01 4.0301e-01 4.3669e-01 4.3293e-01 4.4774e-01 6.8168e-01 4.1205e-01 5.7866e-01
+ 4.4286e-01 3.9432e-01 3.2871e-01 0.0000e+00 6.2085e-01 5.0822e-01 5.4361e-01 6.9286e-01
+ 5.7160e-01 4.9402e-01 5.7831e-01 4.1289e-01 8.3786e-01 6.3270e-01 4.3314e-01 5.5723e-01
+ 6.2555e-01 5.2584e-01 6.6127e-01 4.4599e-01 5.2119e-01 3.5501e-01 5.1845e-01 7.5531e-01
+ 2.9387e-01 7.3730e-01 6.7682e-01 7.9768e-01 5.9915e-01 3.3720e-01 3.7896e-01 5.5938e-01
+ 0.0000e+00 6.2193e-01 5.9317e-01 7.8121e-01 3.6771e-01 5.8634e-01 6.6697e-01 3.6688e-01
+ 6.8218e-01 4.2074e-01 6.5319e-01 7.3412e-01 3.3960e-01 6.3659e-01 2.1187e-01 7.2814e-01
+ 6.7449e-01 6.5625e-01 4.8098e-01 4.9354e-01 3.3179e-01 5.2723e-01 2.4252e-01 3.5505e-01
diff --git a/sasview/test/convertible_files/Z83000.I1D b/src/sas/sasview/test/convertible_files/Z83000.I1D
similarity index 100%
rename from sasview/test/convertible_files/Z83000.I1D
rename to src/sas/sasview/test/convertible_files/Z83000.I1D
diff --git a/sasview/test/convertible_files/Z83000.QAX b/src/sas/sasview/test/convertible_files/Z83000.QAX
similarity index 100%
rename from sasview/test/convertible_files/Z83000.QAX
rename to src/sas/sasview/test/convertible_files/Z83000.QAX
diff --git a/sasview/test/convertible_files/Z83001.I1D b/src/sas/sasview/test/convertible_files/Z83001.I1D
similarity index 100%
rename from sasview/test/convertible_files/Z83001.I1D
rename to src/sas/sasview/test/convertible_files/Z83001.I1D
diff --git a/sasview/test/convertible_files/Z83001.QAX b/src/sas/sasview/test/convertible_files/Z83001.QAX
similarity index 100%
rename from sasview/test/convertible_files/Z83001.QAX
rename to src/sas/sasview/test/convertible_files/Z83001.QAX
diff --git a/sasview/test/convertible_files/Z83002.I1D b/src/sas/sasview/test/convertible_files/Z83002.I1D
similarity index 100%
rename from sasview/test/convertible_files/Z83002.I1D
rename to src/sas/sasview/test/convertible_files/Z83002.I1D
diff --git a/sasview/test/convertible_files/Z98000.I1D b/src/sas/sasview/test/convertible_files/Z98000.I1D
similarity index 100%
rename from sasview/test/convertible_files/Z98000.I1D
rename to src/sas/sasview/test/convertible_files/Z98000.I1D
diff --git a/sasview/test/convertible_files/Z98000.QAX b/src/sas/sasview/test/convertible_files/Z98000.QAX
similarity index 100%
rename from sasview/test/convertible_files/Z98000.QAX
rename to src/sas/sasview/test/convertible_files/Z98000.QAX
diff --git a/sasview/test/convertible_files/Z98001.I1D b/src/sas/sasview/test/convertible_files/Z98001.I1D
similarity index 100%
rename from sasview/test/convertible_files/Z98001.I1D
rename to src/sas/sasview/test/convertible_files/Z98001.I1D
diff --git a/sasview/test/convertible_files/Z98001.QAX b/src/sas/sasview/test/convertible_files/Z98001.QAX
similarity index 100%
rename from sasview/test/convertible_files/Z98001.QAX
rename to src/sas/sasview/test/convertible_files/Z98001.QAX
diff --git a/sasview/test/convertible_files/Z98002.I1D b/src/sas/sasview/test/convertible_files/Z98002.I1D
similarity index 100%
rename from sasview/test/convertible_files/Z98002.I1D
rename to src/sas/sasview/test/convertible_files/Z98002.I1D
diff --git a/sasview/test/coordinate_data/A_Raw_Example-1.omf b/src/sas/sasview/test/coordinate_data/A_Raw_Example-1.omf
similarity index 100%
rename from sasview/test/coordinate_data/A_Raw_Example-1.omf
rename to src/sas/sasview/test/coordinate_data/A_Raw_Example-1.omf
diff --git a/sasview/test/coordinate_data/diamond.pdb b/src/sas/sasview/test/coordinate_data/diamond.pdb
similarity index 100%
rename from sasview/test/coordinate_data/diamond.pdb
rename to src/sas/sasview/test/coordinate_data/diamond.pdb
diff --git a/sasview/test/coordinate_data/dna.pdb b/src/sas/sasview/test/coordinate_data/dna.pdb
similarity index 100%
rename from sasview/test/coordinate_data/dna.pdb
rename to src/sas/sasview/test/coordinate_data/dna.pdb
diff --git a/sasview/test/coordinate_data/sld_file.sld b/src/sas/sasview/test/coordinate_data/sld_file.sld
similarity index 100%
rename from sasview/test/coordinate_data/sld_file.sld
rename to src/sas/sasview/test/coordinate_data/sld_file.sld
diff --git a/sasview/test/image_data/ISIS_98940_greyscale_bmp.bmp b/src/sas/sasview/test/image_data/ISIS_98940_greyscale_bmp.bmp
similarity index 100%
rename from sasview/test/image_data/ISIS_98940_greyscale_bmp.bmp
rename to src/sas/sasview/test/image_data/ISIS_98940_greyscale_bmp.bmp
diff --git a/sasview/test/image_data/ISIS_98940_greyscale_gif.gif b/src/sas/sasview/test/image_data/ISIS_98940_greyscale_gif.gif
similarity index 100%
rename from sasview/test/image_data/ISIS_98940_greyscale_gif.gif
rename to src/sas/sasview/test/image_data/ISIS_98940_greyscale_gif.gif
diff --git a/sasview/test/image_data/ISIS_98940_greyscale_jpg.jpg b/src/sas/sasview/test/image_data/ISIS_98940_greyscale_jpg.jpg
similarity index 100%
rename from sasview/test/image_data/ISIS_98940_greyscale_jpg.jpg
rename to src/sas/sasview/test/image_data/ISIS_98940_greyscale_jpg.jpg
diff --git a/sasview/test/image_data/ISIS_98940_greyscale_png.png b/src/sas/sasview/test/image_data/ISIS_98940_greyscale_png.png
similarity index 100%
rename from sasview/test/image_data/ISIS_98940_greyscale_png.png
rename to src/sas/sasview/test/image_data/ISIS_98940_greyscale_png.png
diff --git a/sasview/test/image_data/ISIS_98940_greyscale_tif.tif b/src/sas/sasview/test/image_data/ISIS_98940_greyscale_tif.tif
similarity index 100%
rename from sasview/test/image_data/ISIS_98940_greyscale_tif.tif
rename to src/sas/sasview/test/image_data/ISIS_98940_greyscale_tif.tif
diff --git a/sasview/test/media/testdata_help.rst b/src/sas/sasview/test/media/testdata_help.rst
similarity index 100%
rename from sasview/test/media/testdata_help.rst
rename to src/sas/sasview/test/media/testdata_help.rst
diff --git a/src/sas/sasview/test/nr_data/NR_Ni_down_state.txt b/src/sas/sasview/test/nr_data/NR_Ni_down_state.txt
new file mode 100644
index 0000000..5712f26
--- /dev/null
+++ b/src/sas/sasview/test/nr_data/NR_Ni_down_state.txt
@@ -0,0 +1,270 @@
+0.0135131 0.961716 0.0289101
+0.0136482 0.928560 0.0257264
+0.0137847 0.927453 0.0245886
+0.0139226 0.941584 0.0237276
+0.0140618 0.955294 0.0231578
+0.0142024 0.969653 0.0225102
+0.0143444 0.925495 0.0205497
+0.0144879 0.946830 0.0214205
+0.0146328 0.960356 0.0229919
+0.0147791 0.969672 0.0228891
+0.0149269 0.994970 0.0221259
+0.0150762 0.988369 0.0204817
+0.0152269 0.957256 0.0201544
+0.0153792 0.989881 0.0217797
+0.0155330 0.980922 0.0198305
+0.0156883 0.981569 0.0190783
+0.0158452 0.989446 0.0204594
+0.0160036 0.983710 0.0194286
+0.0161637 0.983005 0.0184112
+0.0163253 0.995114 0.0194257
+0.0164886 0.956886 0.0175143
+0.0166535 0.959668 0.0181797
+0.0168200 0.982260 0.0185512
+0.0169882 0.958189 0.0166085
+0.0171581 0.987396 0.0175854
+0.0173297 0.968367 0.0168996
+0.0175030 0.957182 0.0162304
+0.0176780 0.988894 0.0168458
+0.0178548 0.960474 0.0158700
+0.0180333 0.995827 0.0165555
+0.0182136 0.988815 0.0158878
+0.0183958 1.00000 0.0167942
+0.0185797 0.977605 0.0164546
+0.0187655 0.981470 0.0172425
+0.0189532 0.946679 0.0162052
+0.0191427 0.949973 0.0154345
+0.0193341 0.953328 0.0157336
+0.0195275 0.942870 0.0146470
+0.0197228 0.865491 0.0135139
+0.0199200 0.724828 0.0116757
+0.0201192 0.607757 0.00934533
+0.0203204 0.482825 0.00772872
+0.0205236 0.415805 0.00706963
+0.0207288 0.431391 0.00668147
+0.0209361 0.468545 0.00707058
+0.0211455 0.440465 0.00739142
+0.0213569 0.360291 0.00659603
+0.0215705 0.265286 0.00458124
+0.0217862 0.190373 0.00337329
+0.0220041 0.131369 0.00277100
+0.0222241 0.116842 0.00275864
+0.0224463 0.135662 0.00274717
+0.0226708 0.175561 0.00299595
+0.0228975 0.203123 0.00322181
+0.0231265 0.215788 0.00351678
+0.0233578 0.208668 0.00369891
+0.0235913 0.184629 0.00369386
+0.0238272 0.140462 0.00306832
+0.0240655 0.0956962 0.00220858
+0.0243062 0.0625630 0.00154711
+0.0245492 0.0427102 0.00111663
+0.0247947 0.0387433 0.000991448
+0.0250427 0.0446114 0.00103143
+0.0252931 0.0598101 0.00122246
+0.0255460 0.0789298 0.00149030
+0.0258015 0.0905049 0.00163303
+0.0260595 0.0953088 0.00171869
+0.0263201 0.0928272 0.00168653
+0.0265833 0.0802002 0.00149458
+0.0268491 0.0624360 0.00202876
+0.0271176 0.0475461 0.00106416
+0.0273888 0.0293066 0.000759623
+0.0276627 0.0177505 0.000549906
+0.0279393 0.0158879 0.000535357
+0.0282187 0.0195091 0.000635344
+0.0285009 0.0271216 0.000780177
+0.0287859 0.0357927 0.000946546
+0.0290738 0.0431081 0.00101791
+0.0293645 0.0483732 0.000976205
+0.0296582 0.0476611 0.000891638
+0.0299547 0.0434431 0.000841549
+0.0302543 0.0350126 0.000771050
+0.0305568 0.0249405 0.000608008
+0.0308624 0.0165013 0.000444320
+0.0311710 0.0102057 0.000353606
+0.0314827 0.00753721 0.000321873
+0.0317976 0.00745373 0.000306921
+0.0321155 0.0110146 0.000372374
+0.0324367 0.0164208 0.000453754
+0.0327611 0.0201040 0.000483163
+0.0330887 0.0225158 0.000530436
+0.0334196 0.0233820 0.000535194
+0.0337537 0.0212166 0.000455583
+0.0340913 0.0177449 0.000421772
+0.0344322 0.0128987 0.000342278
+0.0347765 0.00840363 0.000262032
+0.0351243 0.00520726 0.000199761
+0.0354755 0.00322697 0.000160004
+0.0358303 0.00396699 0.000175721
+0.0361886 0.00549414 0.000209278
+0.0365505 0.00795821 0.000263088
+0.0369160 0.0112167 0.000291701
+0.0372851 0.0117972 0.000329579
+0.0376580 0.0116843 0.000318453
+0.0380346 0.0102174 0.000281684
+0.0384149 0.00790020 0.000256543
+0.0387991 0.00572115 0.000193975
+0.0391871 0.00334086 0.000151395
+0.0395789 0.00241902 0.000126783
+0.0399747 0.00242089 0.000115682
+0.0403745 0.00298051 0.000151159
+0.0407782 0.00449386 0.000169450
+0.0411860 0.00559413 0.000171939
+0.0415978 0.00656132 0.000194755
+0.0420138 0.00615893 0.000197202
+0.0424340 0.00515349 0.000160442
+0.0428583 0.00367690 0.000131414
+0.0432869 0.00240650 0.000110371
+0.0437197 0.00136148 9.10878e-005
+0.0441569 0.00109911 7.49597e-005
+0.0445985 0.00148090 7.89773e-005
+0.0450445 0.00215200 9.46369e-005
+0.0454949 0.00288529 0.000119962
+0.0459499 0.00340265 0.000138753
+0.0464094 0.00302818 0.000138364
+0.0468735 0.00265330 0.000114874
+0.0473422 0.00186224 8.99007e-005
+0.0478156 0.00130027 6.88261e-005
+0.0482938 0.000729895 5.01516e-005
+0.0487767 0.000733598 5.29683e-005
+0.0492645 0.000965806 6.66057e-005
+0.0497571 0.00122742 8.04649e-005
+0.0502547 0.00188900 9.17640e-005
+0.0507573 0.00197926 9.69844e-005
+0.0512648 0.00194916 9.89258e-005
+0.0517775 0.00121589 7.89538e-005
+0.0522953 0.000764875 6.22980e-005
+0.0528182 0.000472794 4.84979e-005
+0.0533464 0.000506488 4.88253e-005
+0.0538799 0.000847941 4.51291e-005
+0.0544187 0.00109914 3.98390e-005
+0.0549628 0.00127840 4.34440e-005
+0.0555125 0.00127151 4.25206e-005
+0.0560676 0.00105505 3.97131e-005
+0.0566283 0.000656319 3.20738e-005
+0.0571946 0.000369127 2.30134e-005
+0.0577665 0.000256208 1.67293e-005
+0.0583442 0.000341549 1.80821e-005
+0.0589276 0.000525350 2.23722e-005
+0.0595169 0.000707067 2.80791e-005
+0.0601121 0.000732983 2.88039e-005
+0.0607132 0.000609604 2.44764e-005
+0.0613203 0.000402103 1.83544e-005
+0.0619335 0.000232529 1.48272e-005
+0.0625528 0.000159466 1.24213e-005
+0.0631784 0.000212669 1.31560e-005
+0.0638102 0.000301192 1.62700e-005
+0.0644483 0.000384585 1.80468e-005
+0.0650927 0.000392482 1.66049e-005
+0.0657437 0.000300217 1.54710e-005
+0.0664011 0.000174950 1.19922e-005
+0.0670651 0.000113914 8.40536e-006
+0.0677358 0.000129762 8.97984e-006
+0.0684131 0.000203802 1.11276e-005
+0.0690973 0.000261373 1.32348e-005
+0.0697882 0.000231401 1.18130e-005
+0.0704861 0.000189973 1.05043e-005
+0.0711910 0.000112650 7.75920e-006
+0.0719029 8.36777e-005 6.42533e-006
+0.0726219 9.53090e-005 6.92844e-006
+0.0733481 0.000129155 8.43305e-006
+0.0740816 0.000149337 9.16137e-006
+0.0748224 0.000142083 8.95509e-006
+0.0755707 0.000104498 8.11742e-006
+0.0763264 5.51500e-005 5.68376e-006
+0.0770896 4.56451e-005 4.60212e-006
+0.0778605 6.69216e-005 5.54031e-006
+0.0786391 0.000102127 6.83728e-006
+0.0794255 0.000109424 6.77086e-006
+0.0802198 7.91852e-005 6.01307e-006
+0.0810220 4.70756e-005 4.44617e-006
+0.0818322 3.45894e-005 3.60117e-006
+0.0826505 4.85846e-005 4.65928e-006
+0.0834770 6.54984e-005 5.05416e-006
+0.0843118 6.61836e-005 4.65011e-006
+0.0851549 5.40963e-005 4.45143e-006
+0.0860064 3.32253e-005 3.82976e-006
+0.0868665 2.77195e-005 3.22363e-006
+0.0877352 3.99215e-005 3.47155e-006
+0.0886125 4.85937e-005 3.86409e-006
+0.0894987 4.19518e-005 3.85924e-006
+0.0903936 2.93644e-005 3.51765e-006
+0.0912976 1.84919e-005 2.57534e-006
+0.0922106 2.28534e-005 2.60437e-006
+0.0931327 2.60631e-005 2.58705e-006
+0.0940640 3.32946e-005 2.96033e-006
+0.0950046 3.06952e-005 2.95997e-006
+0.0959547 1.96745e-005 2.49459e-006
+0.0969142 1.74632e-005 2.61927e-006
+0.0978834 2.36251e-005 2.99198e-006
+0.0988622 2.58019e-005 2.91423e-006
+0.0998508 2.28860e-005 2.61580e-006
+0.100849 1.83878e-005 2.18794e-006
+0.101858 1.84457e-005 2.11072e-006
+0.102876 1.86714e-005 2.00120e-006
+0.103905 2.19172e-005 2.15043e-006
+0.104944 1.99397e-005 2.04872e-006
+0.105994 1.63090e-005 1.80768e-006
+0.107054 1.58171e-005 1.75729e-006
+0.108124 1.68862e-005 1.78580e-006
+0.109205 1.74742e-005 1.85548e-006
+0.110297 1.36636e-005 1.69776e-006
+0.111400 1.13221e-005 1.48611e-006
+0.112514 1.58675e-005 1.83587e-006
+0.113640 1.80107e-005 2.12691e-006
+0.114776 1.38732e-005 1.96903e-006
+0.115924 1.43731e-005 2.17735e-006
+0.117083 1.21113e-005 1.96583e-006
+0.118254 1.20323e-005 1.74579e-006
+0.119436 1.39372e-005 1.70376e-006
+0.120631 1.26248e-005 1.43339e-006
+0.121837 1.18092e-005 1.33477e-006
+0.123055 1.29617e-005 1.41826e-006
+0.124286 1.39771e-005 1.69843e-006
+0.125529 1.10016e-005 1.74992e-006
+0.126784 1.12125e-005 1.77286e-006
+0.128052 1.13120e-005 1.49003e-006
+0.129332 1.26270e-005 1.34613e-006
+0.130626 1.35165e-005 1.35823e-006
+0.131932 1.25121e-005 1.59387e-006
+0.133251 6.50278e-006 1.30668e-006
+0.134584 9.58740e-006 1.43288e-006
+0.135930 9.51385e-006 1.12552e-006
+0.137289 9.11121e-006 1.10765e-006
+0.138662 8.82149e-006 1.38154e-006
+0.140048 9.66351e-006 1.52420e-006
+0.141449 9.53824e-006 1.18517e-006
+0.142863 9.40040e-006 1.09195e-006
+0.144292 9.20342e-006 1.44739e-006
+0.145735 7.99837e-006 1.40429e-006
+0.147192 8.42277e-006 1.08536e-006
+0.148664 8.17632e-006 1.11240e-006
+0.150151 7.03281e-006 1.33254e-006
+0.151652 5.72622e-006 1.04311e-006
+0.153169 6.51698e-006 9.04852e-007
+0.154701 7.76097e-006 1.40378e-006
+0.156248 4.49492e-006 1.07033e-006
+0.157810 7.04137e-006 9.64938e-007
+0.159388 9.37001e-006 1.53602e-006
+0.160982 5.36727e-006 1.20574e-006
+0.162592 6.28461e-006 9.28192e-007
+0.164218 7.18453e-006 1.40781e-006
+0.165860 5.42702e-006 1.19363e-006
+0.167519 6.21826e-006 9.48908e-007
+0.169194 7.50868e-006 1.47579e-006
+0.170886 5.88385e-006 1.09746e-006
+0.172595 5.63279e-006 1.08928e-006
+0.174321 6.17295e-006 1.39311e-006
+0.176064 5.90737e-006 9.81572e-007
+0.177824 5.69360e-006 1.37163e-006
+0.179603 7.94174e-006 1.48206e-006
+0.181399 7.79740e-006 1.37861e-006
+0.183213 5.91423e-006 1.43756e-006
+0.185045 5.62244e-006 1.00030e-006
+0.186895 5.28405e-006 1.37394e-006
+0.188764 6.66913e-006 1.22218e-006
+0.190652 7.24359e-006 1.63249e-006
+0.192558 5.17379e-006 1.27412e-006
+0.194484 5.19469e-006 1.25254e-006
+0.196429 7.03632e-006 1.64492e-006
\ No newline at end of file
diff --git a/src/sas/sasview/test/nr_data/NR_Ni_up_state.txt b/src/sas/sasview/test/nr_data/NR_Ni_up_state.txt
new file mode 100644
index 0000000..55784b5
--- /dev/null
+++ b/src/sas/sasview/test/nr_data/NR_Ni_up_state.txt
@@ -0,0 +1,271 @@
+0.0135131 0.890444 0.0262786
+0.0136482 0.935330 0.0259193
+0.0137847 0.937904 0.0247850
+0.0139226 0.920789 0.0227660
+0.0140618 0.900099 0.0212259
+0.0142024 0.945226 0.0217617
+0.0143444 0.951055 0.0212824
+0.0144879 0.957775 0.0219603
+0.0146328 0.928407 0.0220038
+0.0147791 0.938651 0.0220779
+0.0149269 0.942624 0.0203130
+0.0150762 0.968576 0.0203592
+0.0152269 0.963471 0.0204578
+0.0153792 1.00000 0.0218980
+0.0155330 0.956413 0.0192828
+0.0156883 0.967985 0.0189510
+0.0158452 0.983214 0.0204685
+0.0160036 0.975873 0.0191942
+0.0161637 0.970828 0.0180809
+0.0163253 0.953108 0.0182468
+0.0164886 0.965581 0.0177873
+0.0166535 0.992478 0.0190076
+0.0168200 0.958453 0.0179890
+0.0169882 0.992206 0.0176097
+0.0171581 0.955405 0.0168827
+0.0173297 0.921141 0.0155541
+0.0175030 0.945313 0.0160285
+0.0176780 0.968827 0.0161772
+0.0178548 0.963786 0.0157828
+0.0180333 0.976643 0.0159298
+0.0182136 0.997707 0.0161089
+0.0183958 0.999089 0.0167029
+0.0185797 0.958310 0.0159275
+0.0187655 0.957777 0.0166667
+0.0189532 0.958045 0.0163302
+0.0191427 0.975430 0.0158459
+0.0193341 0.997848 0.0166963
+0.0195275 0.988457 0.0152566
+0.0197228 0.956352 0.0148362
+0.0199200 0.961294 0.0151805
+0.0201192 0.944681 0.0133290
+0.0203204 0.950151 0.0139594
+0.0205236 0.952151 0.0144395
+0.0207288 0.962761 0.0136300
+0.0209361 0.952821 0.0129448
+0.0211455 0.935431 0.0142022
+0.0213569 0.931837 0.0145305
+0.0215705 0.934838 0.0129845
+0.0217862 0.919501 0.0121554
+0.0220041 0.917384 0.0131459
+0.0222241 0.912095 0.0137868
+0.0224463 0.900258 0.0129017
+0.0226708 0.863043 0.0110902
+0.0228975 0.804609 0.00998542
+0.0231265 0.702971 0.00907879
+0.0233578 0.582803 0.00835776
+0.0235913 0.499274 0.00813344
+0.0238272 0.457627 0.00737342
+0.0240655 0.457010 0.00685862
+0.0243062 0.414854 0.00597847
+0.0245492 0.321860 0.00451427
+0.0247947 0.231179 0.00323022
+0.0250427 0.178828 0.00254536
+0.0252931 0.173932 0.00250011
+0.0255460 0.208037 0.00293913
+0.0258015 0.243198 0.00334274
+0.0260595 0.253268 0.00347777
+0.0263201 0.226739 0.00310213
+0.0265833 0.183134 0.00264496
+0.0268491 0.118744 0.00277693
+0.0271176 0.0779644 0.00131408
+0.0273888 0.0534515 0.000960760
+0.0276627 0.0600233 0.00105750
+0.0279393 0.0860045 0.00137475
+0.0282187 0.114457 0.00172018
+0.0285009 0.132804 0.00195653
+0.0287859 0.135787 0.00207031
+0.0290738 0.122882 0.00186907
+0.0293645 0.0954101 0.00138548
+0.0296582 0.0639541 0.00100915
+0.0299547 0.0369641 0.000705270
+0.0302543 0.0230399 0.000556493
+0.0305568 0.0230098 0.000527283
+0.0308624 0.0336483 0.000635125
+0.0311710 0.0482873 0.000846293
+0.0314827 0.0609644 0.000983252
+0.0317976 0.0697305 0.00100906
+0.0321155 0.0677983 0.000970672
+0.0324367 0.0579627 0.000906563
+0.0327611 0.0427337 0.000702598
+0.0330887 0.0282752 0.000546546
+0.0334196 0.0159950 0.000389415
+0.0337537 0.0108447 0.000287468
+0.0340913 0.0126007 0.000322600
+0.0344322 0.0192608 0.000403920
+0.0347765 0.0267967 0.000510294
+0.0351243 0.0333365 0.000559690
+0.0354755 0.0371050 0.000596374
+0.0358303 0.0331868 0.000557501
+0.0361886 0.0280282 0.000478515
+0.0365505 0.0207209 0.000388521
+0.0369160 0.0121958 0.000300031
+0.0372851 0.00746941 0.000216308
+0.0376580 0.00586737 0.000190893
+0.0380346 0.00745861 0.000236754
+0.0384149 0.0120105 0.000311255
+0.0387991 0.0152087 0.000327587
+0.0391871 0.0183588 0.000388454
+0.0395789 0.0183722 0.000373042
+0.0399747 0.0168055 0.000316003
+0.0403745 0.0129610 0.000285392
+0.0407782 0.00760377 0.000220562
+0.0411860 0.00493496 0.000147263
+0.0415978 0.00296770 0.000122952
+0.0420138 0.00406351 0.000148090
+0.0424340 0.00592403 0.000174364
+0.0428583 0.00826475 0.000202906
+0.0432869 0.00974176 0.000239734
+0.0437197 0.0103830 0.000248928
+0.0441569 0.00835037 0.000215107
+0.0445985 0.00641313 0.000164260
+0.0450445 0.00378030 0.000119854
+0.0454949 0.00247600 9.51508e-005
+0.0459499 0.00194234 9.89274e-005
+0.0464094 0.00288153 0.000120924
+0.0468735 0.00389862 0.000132749
+0.0473422 0.00509683 0.000139483
+0.0478156 0.00545632 0.000142910
+0.0482938 0.00521387 0.000133907
+0.0487767 0.00423846 0.000120710
+0.0492645 0.00280647 9.49906e-005
+0.0497571 0.00195349 7.91897e-005
+0.0502547 0.00123686 7.18016e-005
+0.0507573 0.00161302 8.75042e-005
+0.0512648 0.00249490 0.000111290
+0.0517775 0.00333323 0.000127660
+0.0522953 0.00373402 0.000132958
+0.0528182 0.00310304 0.000119289
+0.0533464 0.00233205 0.000103688
+0.0538799 0.00137475 5.84675e-005
+0.0544187 0.000862859 3.47591e-005
+0.0549628 0.000794436 3.22238e-005
+0.0555125 0.00124380 4.09830e-005
+0.0560676 0.00180554 5.09379e-005
+0.0566283 0.00214211 5.63167e-005
+0.0571946 0.00207049 5.22190e-005
+0.0577665 0.00151467 4.06905e-005
+0.0583442 0.000918109 3.00631e-005
+0.0589276 0.000523212 2.09745e-005
+0.0595169 0.000454332 2.03172e-005
+0.0601121 0.000735518 2.79901e-005
+0.0607132 0.00108549 3.14789e-005
+0.0613203 0.00136057 3.44964e-005
+0.0619335 0.00121586 3.34158e-005
+0.0625528 0.000861177 2.78032e-005
+0.0631784 0.000462963 1.73513e-005
+0.0638102 0.000297269 1.45077e-005
+0.0644483 0.000348487 1.63272e-005
+0.0650927 0.000596505 2.06857e-005
+0.0657437 0.000788588 2.49641e-005
+0.0664011 0.000792275 2.49458e-005
+0.0670651 0.000595311 2.04429e-005
+0.0677358 0.000335338 1.45775e-005
+0.0684131 0.000199648 1.03786e-005
+0.0690973 0.000249447 1.21945e-005
+0.0697882 0.000400587 1.53933e-005
+0.0704861 0.000484298 1.67965e-005
+0.0711910 0.000504908 1.67182e-005
+0.0719029 0.000369647 1.36735e-005
+0.0726219 0.000203649 9.63227e-006
+0.0733481 0.000142743 7.77255e-006
+0.0740816 0.000194778 1.04837e-005
+0.0748224 0.000298843 1.25264e-005
+0.0755707 0.000345177 1.47736e-005
+0.0763264 0.000300334 1.30570e-005
+0.0770896 0.000202304 9.43365e-006
+0.0778605 0.000135146 7.41379e-006
+0.0786391 0.000123260 6.90168e-006
+0.0794255 0.000184296 8.85156e-006
+0.0802198 0.000237201 1.02218e-005
+0.0810220 0.000214790 9.11023e-006
+0.0818322 0.000150690 7.18279e-006
+0.0826505 9.00454e-005 5.94710e-006
+0.0834770 9.03782e-005 5.68063e-006
+0.0843118 0.000141873 6.65217e-006
+0.0851549 0.000163560 7.63910e-006
+0.0860064 0.000140535 7.78581e-006
+0.0868665 8.93858e-005 6.03004e-006
+0.0877352 5.92666e-005 4.20128e-006
+0.0886125 7.64039e-005 4.82042e-006
+0.0894987 0.000114803 6.52339e-006
+0.0903936 0.000104782 6.40088e-006
+0.0912976 9.52229e-005 5.82799e-006
+0.0922106 7.06955e-005 4.50775e-006
+0.0931327 6.13081e-005 3.90124e-006
+0.0940640 7.00385e-005 4.21881e-006
+0.0950046 8.86484e-005 5.05629e-006
+0.0959547 7.72893e-005 4.88504e-006
+0.0969142 5.64858e-005 4.53387e-006
+0.0978834 4.76953e-005 4.16508e-006
+0.0988622 5.88348e-005 4.27643e-006
+0.0998508 6.48796e-005 4.20775e-006
+0.100849 6.28582e-005 4.03470e-006
+0.101858 4.47171e-005 3.24721e-006
+0.102876 4.03740e-005 2.88885e-006
+0.103905 5.14897e-005 3.19467e-006
+0.104944 5.35973e-005 3.27317e-006
+0.105994 4.52867e-005 2.94382e-006
+0.107054 4.09899e-005 2.78586e-006
+0.108124 3.89382e-005 2.65950e-006
+0.109205 4.50738e-005 2.85791e-006
+0.110297 4.60581e-005 2.99755e-006
+0.111400 3.75724e-005 2.73234e-006
+0.112514 3.48787e-005 2.73813e-006
+0.113640 3.25430e-005 2.75431e-006
+0.114776 3.53942e-005 3.04983e-006
+0.115924 4.39496e-005 3.71032e-006
+0.117083 3.17644e-005 3.11403e-006
+0.118254 2.71429e-005 2.55242e-006
+0.119436 3.51949e-005 2.66951e-006
+0.120631 3.38018e-005 2.29772e-006
+0.121837 2.76843e-005 1.99876e-006
+0.123055 2.47541e-005 1.94364e-006
+0.124286 2.72585e-005 2.26720e-006
+0.125529 3.07760e-005 2.86434e-006
+0.126784 2.76326e-005 2.72626e-006
+0.128052 2.75574e-005 2.27391e-006
+0.129332 2.50036e-005 1.83227e-006
+0.130626 2.48078e-005 1.80178e-006
+0.131932 2.66661e-005 2.21521e-006
+0.133251 2.57189e-005 2.50880e-006
+0.134584 2.10161e-005 2.03183e-006
+0.135930 2.37672e-005 1.76491e-006
+0.137289 2.28594e-005 1.74215e-006
+0.138662 1.80161e-005 1.94190e-006
+0.140048 1.92866e-005 2.11669e-006
+0.141449 1.71485e-005 1.54830e-006
+0.142863 1.67488e-005 1.43106e-006
+0.144292 1.72791e-005 1.94554e-006
+0.145735 1.69174e-005 2.00432e-006
+0.147192 1.66274e-005 1.49065e-006
+0.148664 1.71027e-005 1.54594e-006
+0.150151 1.86616e-005 2.11933e-006
+0.151652 1.26504e-005 1.49963e-006
+0.153169 1.31255e-005 1.26642e-006
+0.154701 1.48463e-005 1.90985e-006
+0.156248 1.46561e-005 1.88141e-006
+0.157810 1.43918e-005 1.34402e-006
+0.159388 1.41340e-005 1.85734e-006
+0.160982 1.35302e-005 1.87224e-006
+0.162592 1.41379e-005 1.36227e-006
+0.164218 1.47340e-005 1.97722e-006
+0.165860 1.34600e-005 1.84475e-006
+0.167519 1.25573e-005 1.35258e-006
+0.169194 1.12740e-005 1.78517e-006
+0.170886 1.56259e-005 1.82379e-006
+0.172595 1.53380e-005 1.81382e-006
+0.174321 9.92309e-006 1.74326e-006
+0.176064 1.13755e-005 1.35011e-006
+0.177824 1.25446e-005 1.99229e-006
+0.179603 1.08790e-005 1.67270e-006
+0.181399 1.07734e-005 1.56341e-006
+0.183213 1.12529e-005 1.94532e-006
+0.185045 1.11770e-005 1.38234e-006
+0.186895 1.10891e-005 1.95535e-006
+0.188764 1.42045e-005 1.75034e-006
+0.190652 1.54966e-005 2.33973e-006
+0.192558 1.20368e-005 1.90797e-006
+0.194484 1.15704e-005 1.87052e-006
+0.196429 1.01103e-005 1.94929e-006
+
diff --git a/sasview/test/other_files/dist _THETA_weights.txt b/src/sas/sasview/test/other_files/dist _THETA_weights.txt
similarity index 100%
rename from sasview/test/other_files/dist _THETA_weights.txt
rename to src/sas/sasview/test/other_files/dist _THETA_weights.txt
diff --git a/sasview/test/other_files/phi_weights.txt b/src/sas/sasview/test/other_files/phi_weights.txt
similarity index 100%
rename from sasview/test/other_files/phi_weights.txt
rename to src/sas/sasview/test/other_files/phi_weights.txt
diff --git a/sasview/test/other_files/radius_dist.txt b/src/sas/sasview/test/other_files/radius_dist.txt
similarity index 100%
rename from sasview/test/other_files/radius_dist.txt
rename to src/sas/sasview/test/other_files/radius_dist.txt
diff --git a/sasview/test/other_files/theta_weights.txt b/src/sas/sasview/test/other_files/theta_weights.txt
similarity index 100%
rename from sasview/test/other_files/theta_weights.txt
rename to src/sas/sasview/test/other_files/theta_weights.txt
diff --git a/sasview/test/save_states/constrained_fit_project.svs b/src/sas/sasview/test/save_states/constrained_fit_project.svs
similarity index 100%
rename from sasview/test/save_states/constrained_fit_project.svs
rename to src/sas/sasview/test/save_states/constrained_fit_project.svs
diff --git a/sasview/test/save_states/fit_pr_and_invariant_project.svs b/src/sas/sasview/test/save_states/fit_pr_and_invariant_project.svs
similarity index 100%
rename from sasview/test/save_states/fit_pr_and_invariant_project.svs
rename to src/sas/sasview/test/save_states/fit_pr_and_invariant_project.svs
diff --git a/sasview/test/save_states/fitstate.fitv b/src/sas/sasview/test/save_states/fitstate.fitv
similarity index 100%
rename from sasview/test/save_states/fitstate.fitv
rename to src/sas/sasview/test/save_states/fitstate.fitv
diff --git a/sasview/test/save_states/project_multiplicative_constraint.svs b/src/sas/sasview/test/save_states/project_multiplicative_constraint.svs
similarity index 100%
rename from sasview/test/save_states/project_multiplicative_constraint.svs
rename to src/sas/sasview/test/save_states/project_multiplicative_constraint.svs
diff --git a/sasview/test/save_states/prstate.prv b/src/sas/sasview/test/save_states/prstate.prv
similarity index 100%
rename from sasview/test/save_states/prstate.prv
rename to src/sas/sasview/test/save_states/prstate.prv
diff --git a/sasview/test/save_states/test.inv b/src/sas/sasview/test/save_states/test.inv
similarity index 100%
rename from sasview/test/save_states/test.inv
rename to src/sas/sasview/test/save_states/test.inv
diff --git a/sasview/test/save_states/test002.inv b/src/sas/sasview/test/save_states/test002.inv
similarity index 100%
rename from sasview/test/save_states/test002.inv
rename to src/sas/sasview/test/save_states/test002.inv
diff --git a/src/sas/sasview/test/sesans_data/sphere2micron.ses b/src/sas/sasview/test/sesans_data/sphere2micron.ses
new file mode 100644
index 0000000..568e252
--- /dev/null
+++ b/src/sas/sasview/test/sesans_data/sphere2micron.ses
@@ -0,0 +1,60 @@
+FileFormatVersion 1.0
+DataFileTitle Polystyrene of Markus Strobl, Full Sine, ++ only
+Sample Polystyrene 2 um in 53% H2O, 47% D2O
+Settings D1=D2=20x8 mm,Ds = 16x10 mm (WxH), GF1 =scanning, GF2 = 2.5 A. 2 um polystyrene in 53% H2O, 47% D2O; 8.55% contrast
+Operator CPD
+Date do 10 jul 2014 16:37:30
+ScanType sine one element scan
+Thickness 2.00E-01
+Thickness_unit cm
+Theta_zmax 0.0168
+Theta_zmax_unit radians
+Theta_ymax 0.0168
+Theta_ymax_unit radians
+Orientation Z
+SpinEchoLength_unit A
+Depolarisation_unit A-2 cm-1
+Wavelength_unit A
+
+BEGIN_DATA
+SpinEchoLength Depolarisation Depolarisation_error SpinEchoLength_error Wavelength Wavelength_error Polarisation Polarisation_error
+391.56 0.0041929 0.0036894 19.578 2.11 0.1055 1.0037 0.0032974
+1564 -0.0046571 0.0038185 78.2 2.11 0.1055 0.99586 0.003386
+2735.6 -0.017007 0.0038132 136.78 2.11 0.1055 0.98497 0.0033444
+3907.9 -0.033462 0.0035068 195.39 2.11 0.1055 0.97064 0.0030309
+5080.2 -0.047483 0.0038208 254.01 2.11 0.1055 0.9586 0.0032613
+6251.8 -0.070375 0.00376 312.59 2.11 0.1055 0.93926 0.0031446
+7423.2 -0.092217 0.0037927 371.16 2.11 0.1055 0.92117 0.0031108
+8595.5 -0.10238 0.004006 429.77 2.11 0.1055 0.91287 0.0032562
+9767.7 -0.12672 0.0038534 488.39 2.11 0.1055 0.8933 0.0030651
+10940 -0.1374 0.004243 546.98 2.11 0.1055 0.88484 0.003343
+12112 -0.16072 0.0045837 605.58 2.11 0.1055 0.86666 0.0035372
+13284 -0.16623 0.0045613 664.2 2.11 0.1055 0.86242 0.0035027
+14456 -0.18468 0.0044918 722.79 2.11 0.1055 0.84837 0.0033931
+15628 -0.19143 0.0048967 781.38 2.11 0.1055 0.84328 0.0036768
+16800 -0.20029 0.0045421 840.02 2.11 0.1055 0.83666 0.0033837
+17971 -0.19798 0.0046642 898.56 2.11 0.1055 0.83838 0.0034819
+19143 -0.21442 0.0047052 957.17 2.11 0.1055 0.82619 0.0034614
+20316 -0.20885 0.0044931 1015.8 2.11 0.1055 0.8303 0.0033218
+21488 -0.21393 0.0049186 1074.4 2.11 0.1055 0.82655 0.00362
+22660 -0.20685 0.004423 1133 2.11 0.1055 0.83179 0.0032758
+23832 -0.20802 0.0046979 1191.6 2.11 0.1055 0.83092 0.0034758
+25003 -0.19848 0.0045953 1250.2 2.11 0.1055 0.838 0.0034289
+26175 -0.21117 0.0044567 1308.8 2.11 0.1055 0.82859 0.0032881
+27347 -0.21283 0.004137 1367.4 2.11 0.1055 0.82736 0.0030477
+28520 -0.2042 0.0044587 1426 2.11 0.1055 0.83375 0.0033101
+29692 -0.2112 0.0042852 1484.6 2.11 0.1055 0.82857 0.0031615
+30864 -0.20319 0.0043483 1543.2 2.11 0.1055 0.8345 0.003231
+32036 -0.20752 0.0044297 1601.8 2.11 0.1055 0.83129 0.0032788
+33207 -0.20654 0.0043188 1660.4 2.11 0.1055 0.83201 0.0031995
+34380 -0.20126 0.0046375 1719 2.11 0.1055 0.83593 0.0034518
+35551 -0.20924 0.0042871 1777.6 2.11 0.1055 0.83001 0.0031684
+36724 -0.21323 0.0045471 1836.2 2.11 0.1055 0.82707 0.0033487
+37895 -0.21324 0.0045354 1894.7 2.11 0.1055 0.82706 0.00334
+39067 -0.19905 0.0044141 1953.4 2.11 0.1055 0.83758 0.003292
+40239 -0.1991 0.0047441 2012 2.11 0.1055 0.83754 0.003538
+41411 -0.20359 0.0050136 2070.5 2.11 0.1055 0.8342 0.003724
+42583 -0.21032 0.0049474 2129.1 2.11 0.1055 0.82922 0.0036529
+43755 -0.20689 0.0048203 2187.8 2.11 0.1055 0.83176 0.00357
+44927 -0.21075 0.0052337 2246.4 2.11 0.1055 0.8289 0.0038628
+46099 -0.19956 0.0047827 2304.9 2.11 0.1055 0.8372 0.0035653
diff --git a/src/sas/sasview/test/sesans_data/sphere_isis.ses b/src/sas/sasview/test/sesans_data/sphere_isis.ses
new file mode 100644
index 0000000..034c5c4
--- /dev/null
+++ b/src/sas/sasview/test/sesans_data/sphere_isis.ses
@@ -0,0 +1,73 @@
+FileFormatVersion 1.0
+DataFileTitle PMMA in Mixed Deuterated decalin
+Sample Ostensibly 40$ 100nm radius PMMA hard spheres in mixed deuterarted decalin.
+Thickness 2
+Thickness_unit mm
+Theta_zmax 0.09
+Theta_zmax_unit radians
+Theta_ymax 0.09
+Theta_ymax_unit radians
+Orientation Z
+SpinEchoLength_unit A
+Depolarisation_unit A-2 cm-1
+Wavelength_unit A
+
+BEGIN_DATA
+SpinEchoLength Depolarisation Depolarisation_error Wavelength
+260.0 -1.42E-3 2.04E-3 1.612452
+280.8 -1.45E-3 1.87E-3 1.675709
+303.264 -1.64E-3 1.23E-3 1.741448
+327.525 -1.69E-3 1.17E-3 1.809765
+353.727 -2.23E-3 9.09E-4 1.880763
+382.025 -2.26E-3 8.58E-4 1.954546
+412.587 -2.41E-3 7.29E-4 2.031224
+445.594 -2.58E-3 6.75E-4 2.11091
+481.242 -2.88E-3 6.04E-4 2.193723
+519.741 -3.35E-3 5.56E-4 2.279783
+561.32 -3.60E-3 5.22E-4 2.369219
+606.226 -3.92E-3 4.91E-4 2.462166
+654.724 -4.36E-3 4.73E-4 2.558758
+707.102 -4.67E-3 4.54E-4 2.659139
+763.67 -4.91E-3 4.22E-4 2.763458
+824.764 -5.32E-3 3.88E-4 2.87187
+890.745 -5.43E-3 3.53E-4 2.984535
+962.005 -5.61E-3 3.28E-4 3.101621
+1038.97 -5.83E-3 3.07E-4 3.223306
+1122.08 -5.88E-3 2.91E-4 3.349746
+1211.85 -5.91E-3 2.73E-4 3.481164
+1308.8 -5.71E-3 2.61E-4 3.617734
+1413.5 -5.40E-3 2.49E-4 3.759654
+1526.58 -5.10E-3 2.41E-4 3.907147
+1648.71 -4.77E-3 2.34E-4 4.060431
+1780.6 -4.34E-3 2.26E-4 4.219716
+1923.05 -4.18E-3 2.20E-4 4.385259
+2076.9 -4.08E-3 2.16E-4 4.557302
+2243.05 -4.37E-3 2.13E-4 4.736085
+2422.49 -4.66E-3 2.10E-4 4.92188
+2616.29 -4.96E-3 2.06E-4 5.114968
+2825.59 -5.04E-3 2.03E-4 5.315628
+3051.64 -4.96E-3 1.99E-4 5.524165
+3295.77 -4.72E-3 1.97E-4 5.74088
+3559.43 -4.52E-3 1.92E-4 5.966096
+3844.19 -4.65E-3 1.93E-4 6.200153
+4151.72 -4.74E-3 1.96E-4 6.443384
+4483.86 -4.87E-3 1.99E-4 6.696163
+4842.57 -4.81E-3 2.05E-4 6.958858
+5229.98 -4.57E-3 2.09E-4 7.23186
+5648.38 -4.72E-3 2.17E-4 7.515571
+6100.25 -4.79E-3 2.23E-4 7.81041
+6588.27 -4.68E-3 2.28E-4 8.116816
+7115.33 -4.61E-3 2.32E-4 8.435242
+7684.55 -4.78E-3 2.46E-4 8.766157
+8299.32 -4.74E-3 2.46E-4 9.11006
+8963.26 -4.56E-3 2.50E-4 9.467449
+9680.32 -4.70E-3 2.58E-4 9.838862
+10454.7 -4.81E-3 2.64E-4 10.224823
+11291.1 -4.65E-3 2.69E-4 10.625959
+12194.4 -4.43E-3 2.79E-4 11.042826
+13170.0 -4.55E-3 3.01E-4 11.476062
+14223.6 -4.35E-3 3.20E-4 11.926274
+15361.5 -4.24E-3 3.51E-4 12.394152
+16590.4 -4.68E-3 4.12E-4 12.880373
+17917.6 -4.96E-3 4.98E-4 13.385664
+19303.4 -4.56E-3 5.98E-4 13.893668
diff --git a/sasview/test/upcoming_formats/1000A_sphere_sm.xml b/src/sas/sasview/test/upcoming_formats/1000A_sphere_sm.xml
similarity index 100%
rename from sasview/test/upcoming_formats/1000A_sphere_sm.xml
rename to src/sas/sasview/test/upcoming_formats/1000A_sphere_sm.xml
diff --git a/sasview/welcome_panel.py b/src/sas/sasview/welcome_panel.py
similarity index 95%
rename from sasview/welcome_panel.py
rename to src/sas/sasview/welcome_panel.py
index 73173c7..71fcbf2 100644
--- a/sasview/welcome_panel.py
+++ b/src/sas/sasview/welcome_panel.py
@@ -1,180 +1,184 @@
-"""
- Welcome page
-"""
-import wx
-import wx.aui
-import wx.lib.hyperlink
-import os.path
-import os, sys
-import local_config as config
-from wx.lib.scrolledpanel import ScrolledPanel
-from sas.sasgui.guiframe.panel_base import PanelBase
-#Font size width
-if sys.platform.count("win32") > 0:
- FONT_VARIANT = 0
-else:
- FONT_VARIANT = 1
-
-class WelcomePanel(wx.aui.AuiNotebook, PanelBase):
- """
- Panel created like about box as a welcome page
- Shows product name, current version, authors,
- and link to the product page.
- """
- ## Internal nickname for the window, used by the AUI manager
- window_name = "default"
- ## Name to appear on the window title bar
- window_caption = "Welcome panel"
- ## Flag to tell the AUI manager to put this panel in the center pane
- CENTER_PANE = True
-
-
- def __init__(self, parent, *args, **kwds):
- kwds["style"] = wx.aui.AUI_NB_DEFAULT_STYLE
-
- wx.aui.AuiNotebook.__init__(self, parent, *args, **kwds)
- PanelBase.__init__(self)
- #For sasview the parent is guiframe
- self.parent = parent.parent
- self.frame = None
- self.manager = None
-
- welcome_page = WelcomePage(self)
- self.AddPage(welcome_page, "Welcome")
-
- self.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CLOSE, self.on_close_page)
- self.Center()
-
- def set_manager(self, manager):
- """
- the manager of the panel in this case the application itself
- """
- self.manager = manager
-
- def on_close_page(self, event):
- """
- Called when the welcome panel is closed
- """
- if self.parent is not None:
- self.parent.on_close_welcome_panel()
- event.Veto()
-
- def set_data(self, data=None):
- """
- """
- pass
-
- def set_frame(self, frame):
- """
- """
- self.frame = frame
- if frame != None:
- self.frame.Bind(wx.EVT_CLOSE, self.on_close_page)
-
- def get_frame(self):
- """
- """
- return self.frame
-
-
-class WelcomePage(ScrolledPanel):
- """
- Panel created like about box as a welcome page
- Shows product name, current version, authors,
- and link to the product page.
- """
- ## Internal nickname for the window, used by the AUI manager
- window_name = "default"
- ## Name to appear on the window title bar
- window_caption = "Welcome panel"
- ## Flag to tell the AUI manager to put this panel in the center pane
- CENTER_PANE = True
-
-
- def __init__(self, parent, *args, **kwds):
- kwds["style"] = wx.DEFAULT_DIALOG_STYLE
-
- ScrolledPanel.__init__(self, parent, **kwds)
- self.SetupScrolling()
- image = os.path.join(config._welcome_image)
- self.SetWindowVariant(variant=FONT_VARIANT)
- self.bitmap_logo = wx.StaticBitmap(self, -1, wx.Bitmap(image))
-
- self.label_copyright = wx.StaticText(self, -1, config._copyright)
- self.static_line_1 = wx.StaticLine(self, -1)
- self.label_acknowledgement = wx.StaticText(self, -1,
- config._acknowledgement)
-
- self.hyperlink_license = wx.StaticText(self, -1,
- "Comments? Bugs? Requests?")
- send_ticket = "Send us a ticket at: "
- send_ticket += "help at sasview.org"
- self.hyperlink_paper = \
- wx.lib.hyperlink.HyperLinkCtrl(self, -1,
- send_ticket, URL=config._license)
-
- self.label_title = \
- wx.StaticText(self, -1,
- config.__appname__ + " " + str(config.__version__))
- try:
- build_num = str(config.__build__)
- except:
- build_num = str(config.__version__)
- self.label_build = wx.StaticText(self, -1, "Build: " + build_num)
-
- sizer_main = wx.BoxSizer(wx.VERTICAL)
- sizer_header = wx.BoxSizer(wx.HORIZONTAL)
- sizer_build = wx.BoxSizer(wx.VERTICAL)
-
- sizer_header.Add(self.bitmap_logo, 0, wx.EXPAND | wx.LEFT, 5)
-
- sizer_build.Add(self.label_acknowledgement, 0,
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- sizer_build.Add((5, 5))
- sizer_build.Add(self.label_title, 0,
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- sizer_build.Add(self.label_build, 0,
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- sizer_build.Add(self.label_copyright, 0,
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- sizer_build.Add((5, 5))
- sizer_build.Add(self.hyperlink_license, 0,
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
- sizer_build.Add(self.hyperlink_paper, 0,
- wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
-
- sizer_main.Add(sizer_header, 0, wx.TOP | wx.EXPAND, 3)
- sizer_main.Add(self.static_line_1, 0, wx.EXPAND, 0)
- sizer_main.Add(sizer_build, 0, wx.BOTTOM | wx.EXPAND, 3)
-
- self.SetAutoLayout(True)
- self.SetSizer(sizer_main)
- self.Fit()
-
- def set_data(self, data=None):
- """
- """
- pass
-
-class ViewApp(wx.App):
- """
- Test application
- """
- def OnInit(self):
- self.frame = WelcomeFrame(None, -1, "Test App")
- self.frame.Show(True)
- return True
-
-class WelcomeFrame(wx.Frame):
- """
- Test frame
- """
- def __init__(self, parent, id, title):
- wx.Frame.__init__(self, parent, id, title, size=(570, 400))
- WelcomePanel(self)
- self.Centre()
- self.Show(True)
-
-if __name__ == "__main__":
- app = ViewApp(0)
- app.MainLoop()
+"""
+ Welcome page
+"""
+import wx
+import wx.aui
+import wx.lib.hyperlink
+import os.path
+import os, sys
+
+from wx.lib.scrolledpanel import ScrolledPanel
+
+from sas import get_local_config
+from sas.sasgui.guiframe.panel_base import PanelBase
+config = get_local_config()
+
+#Font size width
+if sys.platform.count("win32") > 0:
+ FONT_VARIANT = 0
+else:
+ FONT_VARIANT = 1
+
+class WelcomePanel(wx.aui.AuiNotebook, PanelBase):
+ """
+ Panel created like about box as a welcome page
+ Shows product name, current version, authors,
+ and link to the product page.
+ """
+ ## Internal nickname for the window, used by the AUI manager
+ window_name = "default"
+ ## Name to appear on the window title bar
+ window_caption = "Welcome panel"
+ ## Flag to tell the AUI manager to put this panel in the center pane
+ CENTER_PANE = True
+
+
+ def __init__(self, parent, *args, **kwds):
+ kwds["style"] = wx.aui.AUI_NB_DEFAULT_STYLE
+
+ wx.aui.AuiNotebook.__init__(self, parent, *args, **kwds)
+ PanelBase.__init__(self)
+ #For sasview the parent is guiframe
+ self.parent = parent.parent
+ self.frame = None
+ self.manager = None
+
+ welcome_page = WelcomePage(self)
+ self.AddPage(welcome_page, "Welcome")
+
+ self.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CLOSE, self.on_close_page)
+ self.Center()
+
+ def set_manager(self, manager):
+ """
+ the manager of the panel in this case the application itself
+ """
+ self.manager = manager
+
+ def on_close_page(self, event):
+ """
+ Called when the welcome panel is closed
+ """
+ if self.parent is not None:
+ self.parent.on_close_welcome_panel()
+ event.Veto()
+
+ def set_data(self, data=None):
+ """
+ """
+ pass
+
+ def set_frame(self, frame):
+ """
+ """
+ self.frame = frame
+ if frame is not None:
+ self.frame.Bind(wx.EVT_CLOSE, self.on_close_page)
+
+ def get_frame(self):
+ """
+ """
+ return self.frame
+
+
+class WelcomePage(ScrolledPanel):
+ """
+ Panel created like about box as a welcome page
+ Shows product name, current version, authors,
+ and link to the product page.
+ """
+ ## Internal nickname for the window, used by the AUI manager
+ window_name = "default"
+ ## Name to appear on the window title bar
+ window_caption = "Welcome panel"
+ ## Flag to tell the AUI manager to put this panel in the center pane
+ CENTER_PANE = True
+
+
+ def __init__(self, parent, *args, **kwds):
+ kwds["style"] = wx.DEFAULT_DIALOG_STYLE
+
+ ScrolledPanel.__init__(self, parent, **kwds)
+ self.SetupScrolling()
+ image = os.path.join(config._welcome_image)
+ self.SetWindowVariant(variant=FONT_VARIANT)
+ self.bitmap_logo = wx.StaticBitmap(self, -1, wx.Bitmap(image))
+
+ self.label_copyright = wx.StaticText(self, -1, config._copyright)
+ self.static_line_1 = wx.StaticLine(self, -1)
+ self.label_acknowledgement = wx.StaticText(self, -1,
+ config._acknowledgement)
+
+ self.hyperlink_license = wx.StaticText(self, -1,
+ "Comments? Bugs? Requests?")
+ send_ticket = "Send us a ticket at: "
+ send_ticket += "help at sasview.org"
+ self.hyperlink_paper = \
+ wx.lib.hyperlink.HyperLinkCtrl(self, -1,
+ send_ticket, URL=config._license)
+
+ self.label_title = \
+ wx.StaticText(self, -1,
+ config.__appname__ + " " + str(config.__version__))
+ try:
+ build_num = str(config.__build__)
+ except:
+ build_num = str(config.__version__)
+ self.label_build = wx.StaticText(self, -1, "Build: " + build_num)
+
+ sizer_main = wx.BoxSizer(wx.VERTICAL)
+ sizer_header = wx.BoxSizer(wx.HORIZONTAL)
+ sizer_build = wx.BoxSizer(wx.VERTICAL)
+
+ sizer_header.Add(self.bitmap_logo, 0, wx.EXPAND | wx.LEFT, 5)
+
+ sizer_build.Add(self.label_acknowledgement, 0,
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ sizer_build.Add((5, 5))
+ sizer_build.Add(self.label_title, 0,
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ sizer_build.Add(self.label_build, 0,
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ sizer_build.Add(self.label_copyright, 0,
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ sizer_build.Add((5, 5))
+ sizer_build.Add(self.hyperlink_license, 0,
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+ sizer_build.Add(self.hyperlink_paper, 0,
+ wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
+
+ sizer_main.Add(sizer_header, 0, wx.TOP | wx.EXPAND, 3)
+ sizer_main.Add(self.static_line_1, 0, wx.EXPAND, 0)
+ sizer_main.Add(sizer_build, 0, wx.BOTTOM | wx.EXPAND, 3)
+
+ self.SetAutoLayout(True)
+ self.SetSizer(sizer_main)
+ self.Fit()
+
+ def set_data(self, data=None):
+ """
+ """
+ pass
+
+class ViewApp(wx.App):
+ """
+ Test application
+ """
+ def OnInit(self):
+ self.frame = WelcomeFrame(None, -1, "Test App")
+ self.frame.Show(True)
+ return True
+
+class WelcomeFrame(wx.Frame):
+ """
+ Test frame
+ """
+ def __init__(self, parent, id, title):
+ wx.Frame.__init__(self, parent, id, title, size=(570, 400))
+ WelcomePanel(self)
+ self.Centre()
+ self.Show(True)
+
+if __name__ == "__main__":
+ app = ViewApp(0)
+ app.MainLoop()
diff --git a/sasview/wxcruft.py b/src/sas/sasview/wxcruft.py
similarity index 97%
rename from sasview/wxcruft.py
rename to src/sas/sasview/wxcruft.py
index b2c11f4..c46ae6d 100644
--- a/sasview/wxcruft.py
+++ b/src/sas/sasview/wxcruft.py
@@ -1,3 +1,5 @@
+from __future__ import print_function
+
import inspect
import wx
from wx import Timer
@@ -28,7 +30,7 @@ def NewId():
tag = " via CallLater"
else:
tag = ""
- print "NewId %d from %s(%d):%s%s"%(id, path, line, function, tag)
+ print("NewId %d from %s(%d):%s%s"%(id, path, line, function, tag))
return id
def _get_caller(distance=0):
diff --git a/test/README.rst b/test/README.rst
index 84b4431..810450c 100644
--- a/test/README.rst
+++ b/test/README.rst
@@ -1,16 +1,16 @@
-Running Tests
-=============
-
-Tests are stored in subdirectories of the test directory, as
-*package/test/utest_\*.py*. Other files in the test subdirectory are
-data, expected output and other support files. Before running any tests
-you must first run *setup.py build* in the root. Tests are run against the
-current source directory with run magic to find the compiled code, so you
-only need to rebuild between tests if you are modifying the C code.
-
-Tests can be run in Eclipse (or other IDE) by selecting *utest_sasview.py*
-and selecting run. This will run all of the tests. To run tests for one
-one package, edit the *utest_sasview.py* run command and add the package
-directory to the command arguments. To run an individual test,
-select *run_one.py* and edit the command arguments to include the path to
-the desired test file.
+Running Tests
+=============
+
+Tests are stored in subdirectories of the test directory, as
+*package/test/utest_\*.py*. Other files in the test subdirectory are
+data, expected output and other support files. Before running any tests
+you must first run *setup.py build* in the root. Tests are run against the
+current source directory with run magic to find the compiled code, so you
+only need to rebuild between tests if you are modifying the C code.
+
+Tests can be run in Eclipse (or other IDE) by selecting *utest_sasview.py*
+and selecting run. This will run all of the tests. To run tests for one
+one package, edit the *utest_sasview.py* run command and add the package
+directory to the command arguments. To run an individual test,
+select *run_one.py* and edit the command arguments to include the path to
+the desired test file.
diff --git a/src/sas/__init__.py b/test/calculatorview/__init__.py
similarity index 100%
copy from src/sas/__init__.py
copy to test/calculatorview/__init__.py
diff --git a/src/sas/__init__.py b/test/calculatorview/test/__init__.py
similarity index 100%
copy from src/sas/__init__.py
copy to test/calculatorview/test/__init__.py
diff --git a/test/calculatorview/test/utest_gui_sld.py b/test/calculatorview/test/utest_gui_sld.py
index 8cfdc1e..7004a90 100644
--- a/test/calculatorview/test/utest_gui_sld.py
+++ b/test/calculatorview/test/utest_gui_sld.py
@@ -1,191 +1,191 @@
-"""
-test gui for sld calculator
-"""
-
-import unittest
-import wx
-
-H2O_DENSITY = 1.0
-WAVELENGTH = 6.0
-
-class testTextCtrl(unittest.TestCase):
- """
- txtctrl should have a pink background when the result are incorrect
- and white when reset or correct value
- """
- def setUp(self):
- """
- Create an Sld calculator
- """
- self.app = wx.App()
- from sas.sasgui.perspectives.calculator.sld_panel import SldWindow
- self.sld_frame = SldWindow()
-
- def testCompoundTextCtrl(self):
- """
- Test Compund textCtrl
- """
- #add invalid value for compound
- self.sld_frame.panel.compound_ctl.SetValue("String not in table")
- self.sld_frame.panel.density_ctl.SetValue(str(H2O_DENSITY))
- id = self.sld_frame.panel.button_calculate.GetId()
- clickEvent = wx.CommandEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, id)
- self.sld_frame.panel.ProcessEvent(clickEvent)
- bkg = self.sld_frame.panel.compound_ctl.GetBackgroundColour()
- self.assert_(bkg.GetAsString() == 'pink')
- #compute invariant without entering a value for compound
- self.sld_frame.panel.compound_ctl.SetValue("")
- self.sld_frame.panel.density_ctl.SetValue(str(H2O_DENSITY))
- self.sld_frame.panel.ProcessEvent(clickEvent)
- bkg = self.sld_frame.panel.compound_ctl.GetBackgroundColour()
- self.assert_(bkg.GetAsString() == 'pink')
- #compute invariant without entering a value for compound
- self.sld_frame.panel.compound_ctl.SetValue("H2O")
- self.sld_frame.panel.density_ctl.SetValue(str(H2O_DENSITY))
- self.sld_frame.panel.ProcessEvent(clickEvent)
- bkg = self.sld_frame.panel.compound_ctl.GetBackgroundColour()
- self.assert_(bkg.GetAsString() == 'white')
-
- def testDensityTextCtrl(self):
- """
- Test Density textCtrl
-
- """
- #add invalid value for density
- self.sld_frame.panel.compound_ctl.SetValue("H2O")
- self.sld_frame.panel.density_ctl.SetValue("invalid density")
- id = self.sld_frame.panel.button_calculate.GetId()
- clickEvent = wx.CommandEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, id)
- self.sld_frame.panel.ProcessEvent(clickEvent)
- bkg = self.sld_frame.panel.density_ctl.GetBackgroundColour()
- self.assert_(bkg.GetAsString() == 'pink')
- #compute invariant without entering a value for density
- self.sld_frame.panel.compound_ctl.SetValue("H2O")
- self.sld_frame.panel.density_ctl.SetValue("")
- self.sld_frame.panel.ProcessEvent(clickEvent)
- bkg = self.sld_frame.panel.density_ctl.GetBackgroundColour()
- self.assert_(bkg.GetAsString() == 'pink')
- #compute invariant without entering a value for density
- self.sld_frame.panel.compound_ctl.SetValue("H2O")
- self.sld_frame.panel.density_ctl.SetValue(str(H2O_DENSITY))
- self.sld_frame.panel.ProcessEvent(clickEvent)
- bkg = self.sld_frame.panel.density_ctl.GetBackgroundColour()
- self.assert_(bkg.GetAsString() == 'white')
-
- def testWavelengthTextCtrl(self):
- """
- Test wavelength textCtrl
-
- """
- #add invalid value for wavelength
- self.sld_frame.panel.compound_ctl.SetValue("H2O")
- self.sld_frame.panel.density_ctl.SetValue(str(H2O_DENSITY))
- self.sld_frame.panel.wavelength_ctl.SetValue("invalid wavelength")
- id = self.sld_frame.panel.button_calculate.GetId()
- clickEvent = wx.CommandEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, id)
- self.sld_frame.panel.ProcessEvent(clickEvent)
- bkg = self.sld_frame.panel.wavelength_ctl.GetBackgroundColour()
- self.assert_(bkg.GetAsString() == 'pink')
- #compute invariant without entering a value for wavelegnth
- self.sld_frame.panel.compound_ctl.SetValue("H2O")
- self.sld_frame.panel.density_ctl.SetValue(str(H2O_DENSITY))
- self.sld_frame.panel.wavelength_ctl.SetValue("")
- self.sld_frame.panel.ProcessEvent(clickEvent)
- cp_bkg = self.sld_frame.panel.compound_ctl.GetBackgroundColour()
- self.assert_(cp_bkg.GetAsString() == 'white')
- ds_bkg = self.sld_frame.panel.density_ctl.GetBackgroundColour()
- self.assert_(ds_bkg.GetAsString() == 'white')
- wv_bkg = self.sld_frame.panel.wavelength_ctl.GetBackgroundColour()
- value = self.sld_frame.panel.wavelength_ctl.GetValue()
- self.assert_(wv_bkg.GetAsString() == 'white')
- self.assert_(float(value) == WAVELENGTH)
- sld_real = self.sld_frame.panel.neutron_sld_real_ctl.GetValue()
- sld_im = self.sld_frame.panel.neutron_sld_im_ctl.GetValue()
- mo_real = self.sld_frame.panel.mo_ka_sld_real_ctl.GetValue()
- mo_im = self.sld_frame.panel.mo_ka_sld_im_ctl.GetValue()
- cu_real = self.sld_frame.panel.cu_ka_sld_real_ctl.GetValue()
- cu_im = self.sld_frame.panel.cu_ka_sld_im_ctl.GetValue()
- abs = self.sld_frame.panel.neutron_abs_ctl.GetValue()
- incoh = self.sld_frame.panel.neutron_inc_ctl.GetValue()
- length = self.sld_frame.panel.neutron_length_ctl.GetValue()
-
- self.assertAlmostEquals(float(sld_real), 1.04e-6, 1)
- self.assertAlmostEquals(float(sld_im), -1.5e-7, 1)
- #test absorption value
- self.assertAlmostEquals(float(abs) , 0.0741, 2)
- self.assertAlmostEquals(float(incoh), 5.62, 2)
- #Test length
- self.assertAlmostEquals(float(length), 0.1755, 2)
- #test Cu sld
- self.assertAlmostEquals(float(cu_real), 9.46e-6, 1)
- self.assertAlmostEquals(float(cu_im), 3.01e-8)
- # test Mo sld
- self.assertAlmostEquals(float(mo_real), 9.43e-6)
- self.assertAlmostEquals(float(mo_im), 5.65e-7, 1)
- #compute invariant with all correct inputs value
- self.sld_frame.panel.compound_ctl.SetValue("H2O")
- self.sld_frame.panel.density_ctl.SetValue(str(H2O_DENSITY))
- self.sld_frame.panel.wavelength_ctl.SetValue(str(WAVELENGTH/2))
- self.sld_frame.panel.ProcessEvent(clickEvent)
- bkg = self.sld_frame.panel.wavelength_ctl.GetBackgroundColour()
- value = self.sld_frame.panel.wavelength_ctl.GetValue()
- self.assert_(bkg.GetAsString() == 'white')
- self.assert_(float(value) == WAVELENGTH/2)
-
- def testSomeCombination(self):
- """
- Test other error
- """
- #only wavelength is invalid
- self.sld_frame.panel.compound_ctl.SetValue("H2O")
- self.sld_frame.panel.density_ctl.SetValue(str(H2O_DENSITY))
- self.sld_frame.panel.wavelength_ctl.SetValue("invalid wavelength")
- id = self.sld_frame.panel.button_calculate.GetId()
- clickEvent = wx.CommandEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, id)
- self.sld_frame.panel.ProcessEvent(clickEvent)
- cp_bkg = self.sld_frame.panel.compound_ctl.GetBackgroundColour()
- self.assert_(cp_bkg.GetAsString() == 'white')
- ds_bkg = self.sld_frame.panel.density_ctl.GetBackgroundColour()
- self.assert_(ds_bkg.GetAsString() == 'white')
- wv_bkg = self.sld_frame.panel.wavelength_ctl.GetBackgroundColour()
- self.assert_(wv_bkg.GetAsString() == 'pink')
- #density, wavelength is invalid
- self.sld_frame.panel.compound_ctl.SetValue("H2O")
- self.sld_frame.panel.density_ctl.SetValue("invalid density")
- self.sld_frame.panel.wavelength_ctl.SetValue("invalid wavelength")
- id = self.sld_frame.panel.button_calculate.GetId()
- clickEvent = wx.CommandEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, id)
- self.sld_frame.panel.ProcessEvent(clickEvent)
- cp_bkg = self.sld_frame.panel.compound_ctl.GetBackgroundColour()
- self.assert_(cp_bkg.GetAsString() == 'white')
- ds_bkg = self.sld_frame.panel.density_ctl.GetBackgroundColour()
- self.assert_(ds_bkg.GetAsString() == 'pink')
- wv_bkg = self.sld_frame.panel.wavelength_ctl.GetBackgroundColour()
- self.assert_(wv_bkg.GetAsString() == 'pink')
- #density, wavelength is invalid
- self.sld_frame.panel.compound_ctl.SetValue("invalid compound")
- self.sld_frame.panel.density_ctl.SetValue("invalid density")
- self.sld_frame.panel.wavelength_ctl.SetValue("")
- id = self.sld_frame.panel.button_calculate.GetId()
- clickEvent = wx.CommandEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, id)
- self.sld_frame.panel.ProcessEvent(clickEvent)
- cp_bkg = self.sld_frame.panel.compound_ctl.GetBackgroundColour()
- self.assert_(cp_bkg.GetAsString() == 'pink')
- ds_bkg = self.sld_frame.panel.density_ctl.GetBackgroundColour()
- self.assert_(ds_bkg.GetAsString() == 'pink')
- wv_bkg = self.sld_frame.panel.wavelength_ctl.GetBackgroundColour()
- self.assert_(wv_bkg.GetAsString() == 'white')
- value = self.sld_frame.panel.wavelength_ctl.GetValue()
- self.assert_(float(value) == WAVELENGTH)
-
-
-
- def tearDown(self):
- """
- Destroy the sld calculator frame
- """
- self.sld_frame.Close()
- self.app.MainLoop()
-
-if __name__ == "__main__":
- unittest.main()
+"""
+test gui for sld calculator
+"""
+
+import unittest
+import wx
+
+H2O_DENSITY = 1.0
+WAVELENGTH = 6.0
+
+class testTextCtrl(unittest.TestCase):
+ """
+ txtctrl should have a pink background when the result are incorrect
+ and white when reset or correct value
+ """
+ def setUp(self):
+ """
+ Create an Sld calculator
+ """
+ self.app = wx.App()
+ from sas.sasgui.perspectives.calculator.sld_panel import SldWindow
+ self.sld_frame = SldWindow()
+
+ def testCompoundTextCtrl(self):
+ """
+ Test Compund textCtrl
+ """
+ #add invalid value for compound
+ self.sld_frame.panel.compound_ctl.SetValue("String not in table")
+ self.sld_frame.panel.density_ctl.SetValue(str(H2O_DENSITY))
+ id = self.sld_frame.panel.button_calculate.GetId()
+ clickEvent = wx.CommandEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, id)
+ self.sld_frame.panel.ProcessEvent(clickEvent)
+ bkg = self.sld_frame.panel.compound_ctl.GetBackgroundColour()
+ self.assert_(bkg.GetAsString() == 'pink')
+ #compute invariant without entering a value for compound
+ self.sld_frame.panel.compound_ctl.SetValue("")
+ self.sld_frame.panel.density_ctl.SetValue(str(H2O_DENSITY))
+ self.sld_frame.panel.ProcessEvent(clickEvent)
+ bkg = self.sld_frame.panel.compound_ctl.GetBackgroundColour()
+ self.assert_(bkg.GetAsString() == 'pink')
+ #compute invariant without entering a value for compound
+ self.sld_frame.panel.compound_ctl.SetValue("H2O")
+ self.sld_frame.panel.density_ctl.SetValue(str(H2O_DENSITY))
+ self.sld_frame.panel.ProcessEvent(clickEvent)
+ bkg = self.sld_frame.panel.compound_ctl.GetBackgroundColour()
+ self.assert_(bkg.GetAsString() == 'white')
+
+ def testDensityTextCtrl(self):
+ """
+ Test Density textCtrl
+
+ """
+ #add invalid value for density
+ self.sld_frame.panel.compound_ctl.SetValue("H2O")
+ self.sld_frame.panel.density_ctl.SetValue("invalid density")
+ id = self.sld_frame.panel.button_calculate.GetId()
+ clickEvent = wx.CommandEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, id)
+ self.sld_frame.panel.ProcessEvent(clickEvent)
+ bkg = self.sld_frame.panel.density_ctl.GetBackgroundColour()
+ self.assert_(bkg.GetAsString() == 'pink')
+ #compute invariant without entering a value for density
+ self.sld_frame.panel.compound_ctl.SetValue("H2O")
+ self.sld_frame.panel.density_ctl.SetValue("")
+ self.sld_frame.panel.ProcessEvent(clickEvent)
+ bkg = self.sld_frame.panel.density_ctl.GetBackgroundColour()
+ self.assert_(bkg.GetAsString() == 'pink')
+ #compute invariant without entering a value for density
+ self.sld_frame.panel.compound_ctl.SetValue("H2O")
+ self.sld_frame.panel.density_ctl.SetValue(str(H2O_DENSITY))
+ self.sld_frame.panel.ProcessEvent(clickEvent)
+ bkg = self.sld_frame.panel.density_ctl.GetBackgroundColour()
+ self.assert_(bkg.GetAsString() == 'white')
+
+ def testWavelengthTextCtrl(self):
+ """
+ Test wavelength textCtrl
+
+ """
+ #add invalid value for wavelength
+ self.sld_frame.panel.compound_ctl.SetValue("H2O")
+ self.sld_frame.panel.density_ctl.SetValue(str(H2O_DENSITY))
+ self.sld_frame.panel.wavelength_ctl.SetValue("invalid wavelength")
+ id = self.sld_frame.panel.button_calculate.GetId()
+ clickEvent = wx.CommandEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, id)
+ self.sld_frame.panel.ProcessEvent(clickEvent)
+ bkg = self.sld_frame.panel.wavelength_ctl.GetBackgroundColour()
+ self.assert_(bkg.GetAsString() == 'pink')
+ #compute invariant without entering a value for wavelegnth
+ self.sld_frame.panel.compound_ctl.SetValue("H2O")
+ self.sld_frame.panel.density_ctl.SetValue(str(H2O_DENSITY))
+ self.sld_frame.panel.wavelength_ctl.SetValue("")
+ self.sld_frame.panel.ProcessEvent(clickEvent)
+ cp_bkg = self.sld_frame.panel.compound_ctl.GetBackgroundColour()
+ self.assert_(cp_bkg.GetAsString() == 'white')
+ ds_bkg = self.sld_frame.panel.density_ctl.GetBackgroundColour()
+ self.assert_(ds_bkg.GetAsString() == 'white')
+ wv_bkg = self.sld_frame.panel.wavelength_ctl.GetBackgroundColour()
+ value = self.sld_frame.panel.wavelength_ctl.GetValue()
+ self.assert_(wv_bkg.GetAsString() == 'white')
+ self.assert_(float(value) == WAVELENGTH)
+ sld_real = self.sld_frame.panel.neutron_sld_real_ctl.GetValue()
+ sld_im = self.sld_frame.panel.neutron_sld_im_ctl.GetValue()
+ mo_real = self.sld_frame.panel.mo_ka_sld_real_ctl.GetValue()
+ mo_im = self.sld_frame.panel.mo_ka_sld_im_ctl.GetValue()
+ cu_real = self.sld_frame.panel.cu_ka_sld_real_ctl.GetValue()
+ cu_im = self.sld_frame.panel.cu_ka_sld_im_ctl.GetValue()
+ abs = self.sld_frame.panel.neutron_abs_ctl.GetValue()
+ incoh = self.sld_frame.panel.neutron_inc_ctl.GetValue()
+ length = self.sld_frame.panel.neutron_length_ctl.GetValue()
+
+ self.assertAlmostEquals(float(sld_real), 1.04e-6, 1)
+ self.assertAlmostEquals(float(sld_im), -1.5e-7, 1)
+ #test absorption value
+ self.assertAlmostEquals(float(abs) , 0.0741, 2)
+ self.assertAlmostEquals(float(incoh), 5.62, 2)
+ #Test length
+ self.assertAlmostEquals(float(length), 0.1755, 2)
+ #test Cu sld
+ self.assertAlmostEquals(float(cu_real), 9.46e-6, 1)
+ self.assertAlmostEquals(float(cu_im), 3.01e-8)
+ # test Mo sld
+ self.assertAlmostEquals(float(mo_real), 9.43e-6)
+ self.assertAlmostEquals(float(mo_im), 5.65e-7, 1)
+ #compute invariant with all correct inputs value
+ self.sld_frame.panel.compound_ctl.SetValue("H2O")
+ self.sld_frame.panel.density_ctl.SetValue(str(H2O_DENSITY))
+ self.sld_frame.panel.wavelength_ctl.SetValue(str(WAVELENGTH/2))
+ self.sld_frame.panel.ProcessEvent(clickEvent)
+ bkg = self.sld_frame.panel.wavelength_ctl.GetBackgroundColour()
+ value = self.sld_frame.panel.wavelength_ctl.GetValue()
+ self.assert_(bkg.GetAsString() == 'white')
+ self.assert_(float(value) == WAVELENGTH/2)
+
+ def testSomeCombination(self):
+ """
+ Test other error
+ """
+ #only wavelength is invalid
+ self.sld_frame.panel.compound_ctl.SetValue("H2O")
+ self.sld_frame.panel.density_ctl.SetValue(str(H2O_DENSITY))
+ self.sld_frame.panel.wavelength_ctl.SetValue("invalid wavelength")
+ id = self.sld_frame.panel.button_calculate.GetId()
+ clickEvent = wx.CommandEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, id)
+ self.sld_frame.panel.ProcessEvent(clickEvent)
+ cp_bkg = self.sld_frame.panel.compound_ctl.GetBackgroundColour()
+ self.assert_(cp_bkg.GetAsString() == 'white')
+ ds_bkg = self.sld_frame.panel.density_ctl.GetBackgroundColour()
+ self.assert_(ds_bkg.GetAsString() == 'white')
+ wv_bkg = self.sld_frame.panel.wavelength_ctl.GetBackgroundColour()
+ self.assert_(wv_bkg.GetAsString() == 'pink')
+ #density, wavelength is invalid
+ self.sld_frame.panel.compound_ctl.SetValue("H2O")
+ self.sld_frame.panel.density_ctl.SetValue("invalid density")
+ self.sld_frame.panel.wavelength_ctl.SetValue("invalid wavelength")
+ id = self.sld_frame.panel.button_calculate.GetId()
+ clickEvent = wx.CommandEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, id)
+ self.sld_frame.panel.ProcessEvent(clickEvent)
+ cp_bkg = self.sld_frame.panel.compound_ctl.GetBackgroundColour()
+ self.assert_(cp_bkg.GetAsString() == 'white')
+ ds_bkg = self.sld_frame.panel.density_ctl.GetBackgroundColour()
+ self.assert_(ds_bkg.GetAsString() == 'pink')
+ wv_bkg = self.sld_frame.panel.wavelength_ctl.GetBackgroundColour()
+ self.assert_(wv_bkg.GetAsString() == 'pink')
+ #density, wavelength is invalid
+ self.sld_frame.panel.compound_ctl.SetValue("invalid compound")
+ self.sld_frame.panel.density_ctl.SetValue("invalid density")
+ self.sld_frame.panel.wavelength_ctl.SetValue("")
+ id = self.sld_frame.panel.button_calculate.GetId()
+ clickEvent = wx.CommandEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, id)
+ self.sld_frame.panel.ProcessEvent(clickEvent)
+ cp_bkg = self.sld_frame.panel.compound_ctl.GetBackgroundColour()
+ self.assert_(cp_bkg.GetAsString() == 'pink')
+ ds_bkg = self.sld_frame.panel.density_ctl.GetBackgroundColour()
+ self.assert_(ds_bkg.GetAsString() == 'pink')
+ wv_bkg = self.sld_frame.panel.wavelength_ctl.GetBackgroundColour()
+ self.assert_(wv_bkg.GetAsString() == 'white')
+ value = self.sld_frame.panel.wavelength_ctl.GetValue()
+ self.assert_(float(value) == WAVELENGTH)
+
+
+
+ def tearDown(self):
+ """
+ Destroy the sld calculator frame
+ """
+ self.sld_frame.Close()
+ self.app.MainLoop()
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/src/sas/__init__.py b/test/corfunc/__init__.py
similarity index 100%
copy from src/sas/__init__.py
copy to test/corfunc/__init__.py
diff --git a/src/sas/__init__.py b/test/corfunc/test/__init__.py
similarity index 100%
copy from src/sas/__init__.py
copy to test/corfunc/test/__init__.py
diff --git a/test/corfunc/test/gamma1_out.txt b/test/corfunc/test/gamma1_out.txt
new file mode 100644
index 0000000..c3de00f
--- /dev/null
+++ b/test/corfunc/test/gamma1_out.txt
@@ -0,0 +1,1816 @@
+# <index> <X> <Y> <dY> <dX>
+0 0.0 1.0 0.0 0.0
+1 0.110224 0.990725916054 0.0 0.0
+2 0.220447 0.97839722295 0.0 0.0
+3 0.330671 0.966651562661 0.0 0.0
+4 0.440894 0.954730368816 0.0 0.0
+5 0.551118 0.942986380163 0.0 0.0
+6 0.661341 0.931214497255 0.0 0.0
+7 0.771565 0.919550207569 0.0 0.0
+8 0.881789 0.907898011296 0.0 0.0
+9 0.992012 0.896329680189 0.0 0.0
+10 1.10224 0.884790018984 0.0 0.0
+11 1.21246 0.873323510721 0.0 0.0
+12 1.32268 0.861894222085 0.0 0.0
+13 1.43291 0.850532450049 0.0 0.0
+14 1.54313 0.839212959145 0.0 0.0
+15 1.65335 0.82795773246 0.0 0.0
+16 1.76358 0.816748091093 0.0 0.0
+17 1.8738 0.805600729216 0.0 0.0
+18 1.98402 0.794501277356 0.0 0.0
+19 2.09425 0.783462857713 0.0 0.0
+20 2.20447 0.772474085432 0.0 0.0
+21 2.3147 0.761545557694 0.0 0.0
+22 2.42492 0.750668042577 0.0 0.0
+23 2.53514 0.73985028693 0.0 0.0
+24 2.64537 0.729084663256 0.0 0.0
+25 2.75559 0.718378522418 0.0 0.0
+26 2.86581 0.707725464893 0.0 0.0
+27 2.97604 0.697131762652 0.0 0.0
+28 3.08626 0.686591977155 0.0 0.0
+29 3.19648 0.676111529494 0.0 0.0
+30 3.30671 0.665685747414 0.0 0.0
+31 3.41693 0.655319369237 0.0 0.0
+32 3.52715 0.645008343653 0.0 0.0
+33 3.63738 0.634756852806 0.0 0.0
+34 3.7476 0.624561355592 0.0 0.0
+35 3.85783 0.614425575118 0.0 0.0
+36 3.96805 0.604346394561 0.0 0.0
+37 4.07827 0.594327153713 0.0 0.0
+38 4.1885 0.584365092347 0.0 0.0
+39 4.29872 0.574463226774 0.0 0.0
+40 4.40894 0.56461909926 0.0 0.0
+41 4.51917 0.554835450556 0.0 0.0
+42 4.62939 0.545110081592 0.0 0.0
+43 4.73961 0.535445496348 0.0 0.0
+44 4.84984 0.525839718534 0.0 0.0
+45 4.96006 0.516295047028 0.0 0.0
+46 5.07028 0.506809698637 0.0 0.0
+47 5.18051 0.497385793244 0.0 0.0
+48 5.29073 0.488021715945 0.0 0.0
+49 5.40096 0.47871942929 0.0 0.0
+50 5.51118 0.469477465762 0.0 0.0
+51 5.6214 0.460297648701 0.0 0.0
+52 5.73163 0.45117864019 0.0 0.0
+53 5.84185 0.442122139611 0.0 0.0
+54 5.95207 0.433126923416 0.0 0.0
+55 6.0623 0.424194579926 0.0 0.0
+56 6.17252 0.415323986805 0.0 0.0
+57 6.28274 0.406516632302 0.0 0.0
+58 6.39297 0.39777148385 0.0 0.0
+59 6.50319 0.38908993899 0.0 0.0
+60 6.61341 0.380471044956 0.0 0.0
+61 6.72364 0.371916116584 0.0 0.0
+62 6.83386 0.363424272123 0.0 0.0
+63 6.94409 0.354996750638 0.0 0.0
+64 7.05431 0.346632733596 0.0 0.0
+65 7.16453 0.338333390238 0.0 0.0
+66 7.27476 0.330097958364 0.0 0.0
+67 7.38498 0.321927542534 0.0 0.0
+68 7.4952 0.3138214307 0.0 0.0
+69 7.60543 0.305780667222 0.0 0.0
+70 7.71565 0.297804584654 0.0 0.0
+71 7.82587 0.289894171035 0.0 0.0
+72 7.9361 0.282048798536 0.0 0.0
+73 8.04632 0.274269402264 0.0 0.0
+74 8.15654 0.266555389458 0.0 0.0
+75 8.26677 0.258907645258 0.0 0.0
+76 8.37699 0.251325607878 0.0 0.0
+77 8.48722 0.243810115056 0.0 0.0
+78 8.59744 0.236360632233 0.0 0.0
+79 8.70766 0.228977952016 0.0 0.0
+80 8.81789 0.221661563637 0.0 0.0
+81 8.92811 0.214412216567 0.0 0.0
+82 9.03833 0.207229420679 0.0 0.0
+83 9.14856 0.200113884057 0.0 0.0
+84 9.25878 0.193065134333 0.0 0.0
+85 9.369 0.186083839721 0.0 0.0
+86 9.47923 0.179169542974 0.0 0.0
+87 9.58945 0.172322873788 0.0 0.0
+88 9.69968 0.165543387578 0.0 0.0
+89 9.8099 0.158831676717 0.0 0.0
+90 9.92012 0.15218730704 0.0 0.0
+91 10.0303 0.145610834637 0.0 0.0
+92 10.1406 0.139101833674 0.0 0.0
+93 10.2508 0.132660824925 0.0 0.0
+94 10.361 0.126287388925 0.0 0.0
+95 10.4712 0.119982011987 0.0 0.0
+96 10.5815 0.113744279227 0.0 0.0
+97 10.6917 0.107574643266 0.0 0.0
+98 10.8019 0.101472692125 0.0 0.0
+99 10.9121 0.0954388454313 0.0 0.0
+100 11.0224 0.0894726925798 0.0 0.0
+101 11.1326 0.0835746208184 0.0 0.0
+102 11.2428 0.0777442195201 0.0 0.0
+103 11.353 0.071981844107 0.0 0.0
+104 11.4633 0.0662870826373 0.0 0.0
+105 11.5735 0.0606602592303 0.0 0.0
+106 11.6837 0.055100959431 0.0 0.0
+107 11.7939 0.0496094765602 0.0 0.0
+108 11.9041 0.0441853925207 0.0 0.0
+109 12.0144 0.0388289703368 0.0 0.0
+110 12.1246 0.0335397872332 0.0 0.0
+111 12.2348 0.028318076389 0.0 0.0
+112 12.345 0.0231634094423 0.0 0.0
+113 12.4553 0.0180759901405 0.0 0.0
+114 12.5655 0.0130553837091 0.0 0.0
+115 12.6757 0.00810176488766 0.0 0.0
+116 12.7859 0.00321469172454 0.0 0.0
+117 12.8962 -0.00160568962788 0.0 0.0
+118 13.0064 -0.0063598289827 0.0 0.0
+119 13.1166 -0.0110476083445 0.0 0.0
+120 13.2268 -0.0156694860028 0.0 0.0
+121 13.3371 -0.0202253717031 0.0 0.0
+122 13.4473 -0.024715732735 0.0 0.0
+123 13.5575 -0.0291405061662 0.0 0.0
+124 13.6677 -0.0335001687559 0.0 0.0
+125 13.7779 -0.0377946844341 0.0 0.0
+126 13.8882 -0.042024539853 0.0 0.0
+127 13.9984 -0.0461897253597 0.0 0.0
+128 14.1086 -0.0502907378085 0.0 0.0
+129 14.2188 -0.0543275935191 0.0 0.0
+130 14.3291 -0.0583007998233 0.0 0.0
+131 14.4393 -0.0622103985237 0.0 0.0
+132 14.5495 -0.0660569076443 0.0 0.0
+133 14.6597 -0.0698403939821 0.0 0.0
+134 14.77 -0.0735613864024 0.0 0.0
+135 14.8802 -0.0772199761761 0.0 0.0
+136 14.9904 -0.0808167031176 0.0 0.0
+137 15.1006 -0.084351682432 0.0 0.0
+138 15.2109 -0.0878254649147 0.0 0.0
+139 15.3211 -0.0912381891718 0.0 0.0
+140 15.4313 -0.0945904169545 0.0 0.0
+141 15.5415 -0.0978823096895 0.0 0.0
+142 15.6517 -0.101114440028 0.0 0.0
+143 15.762 -0.104286991624 0.0 0.0
+144 15.8722 -0.107400547905 0.0 0.0
+145 15.9824 -0.110455314144 0.0 0.0
+146 16.0926 -0.11345188437 0.0 0.0
+147 16.2029 -0.116390484849 0.0 0.0
+148 16.3131 -0.119271719992 0.0 0.0
+149 16.4233 -0.122095836399 0.0 0.0
+150 16.5335 -0.124863448616 0.0 0.0
+151 16.6438 -0.127574822884 0.0 0.0
+152 16.754 -0.130230583596 0.0 0.0
+153 16.8642 -0.132831015925 0.0 0.0
+154 16.9744 -0.135376753767 0.0 0.0
+155 17.0847 -0.137868100516 0.0 0.0
+156 17.1949 -0.140305699186 0.0 0.0
+157 17.3051 -0.142689870649 0.0 0.0
+158 17.4153 -0.145021266619 0.0 0.0
+159 17.5255 -0.147300224686 0.0 0.0
+160 17.6358 -0.14952740481 0.0 0.0
+161 17.746 -0.151703160521 0.0 0.0
+162 17.8562 -0.153828159537 0.0 0.0
+163 17.9664 -0.155902770531 0.0 0.0
+164 18.0767 -0.157927668463 0.0 0.0
+165 18.1869 -0.15990323633 0.0 0.0
+166 18.2971 -0.161830155783 0.0 0.0
+167 18.4073 -0.163708823332 0.0 0.0
+168 18.5176 -0.165539926726 0.0 0.0
+169 18.6278 -0.167323875136 0.0 0.0
+170 18.738 -0.169061361836 0.0 0.0
+171 18.8482 -0.170752807782 0.0 0.0
+172 18.9585 -0.172398911143 0.0 0.0
+173 19.0687 -0.174000103816 0.0 0.0
+174 19.1789 -0.17555708819 0.0 0.0
+175 19.2891 -0.177070306231 0.0 0.0
+176 19.3994 -0.178540463901 0.0 0.0
+177 19.5096 -0.179968012333 0.0 0.0
+178 19.6198 -0.181353660371 0.0 0.0
+179 19.73 -0.18269786743 0.0 0.0
+180 19.8402 -0.184001344538 0.0 0.0
+181 19.9505 -0.185264558485 0.0 0.0
+182 20.0607 -0.186488221776 0.0 0.0
+183 20.1709 -0.187672807672 0.0 0.0
+184 20.2811 -0.188819029418 0.0 0.0
+185 20.3914 -0.189927365856 0.0 0.0
+186 20.5016 -0.190998530234 0.0 0.0
+187 20.6118 -0.192033006054 0.0 0.0
+188 20.722 -0.193031505836 0.0 0.0
+189 20.8323 -0.193994516843 0.0 0.0
+190 20.9425 -0.194922750109 0.0 0.0
+191 21.0527 -0.195816695754 0.0 0.0
+192 21.1629 -0.196677062576 0.0 0.0
+193 21.2732 -0.197504342672 0.0 0.0
+194 21.3834 -0.198299241824 0.0 0.0
+195 21.4936 -0.199062253217 0.0 0.0
+196 21.6038 -0.199794078898 0.0 0.0
+197 21.714 -0.20049521222 0.0 0.0
+198 21.8243 -0.201166350751 0.0 0.0
+199 21.9345 -0.201807987148 0.0 0.0
+200 22.0447 -0.202420813757 0.0 0.0
+201 22.1549 -0.203005321672 0.0 0.0
+202 22.2652 -0.203562197265 0.0 0.0
+203 22.3754 -0.204091929227 0.0 0.0
+204 22.4856 -0.204595197238 0.0 0.0
+205 22.5958 -0.205072486732 0.0 0.0
+206 22.7061 -0.205524469984 0.0 0.0
+207 22.8163 -0.205951628347 0.0 0.0
+208 22.9265 -0.206354625986 0.0 0.0
+209 23.0367 -0.206733939376 0.0 0.0
+210 23.147 -0.207090223869 0.0 0.0
+211 23.2572 -0.207423950274 0.0 0.0
+212 23.3674 -0.207735764469 0.0 0.0
+213 23.4776 -0.208026130819 0.0 0.0
+214 23.5878 -0.208295685067 0.0 0.0
+215 23.6981 -0.208544884398 0.0 0.0
+216 23.8083 -0.208774353773 0.0 0.0
+217 23.9185 -0.20898454249 0.0 0.0
+218 24.0287 -0.209176064089 0.0 0.0
+219 24.139 -0.209349359284 0.0 0.0
+220 24.2492 -0.209505029619 0.0 0.0
+221 24.3594 -0.209643506538 0.0 0.0
+222 24.4696 -0.209765379005 0.0 0.0
+223 24.5799 -0.209871068569 0.0 0.0
+224 24.6901 -0.209961151052 0.0 0.0
+225 24.8003 -0.210036037489 0.0 0.0
+226 24.9105 -0.210096290046 0.0 0.0
+227 25.0208 -0.210142308649 0.0 0.0
+228 25.131 -0.210174641323 0.0 0.0
+229 25.2412 -0.210193676308 0.0 0.0
+230 25.3514 -0.210199947025 0.0 0.0
+231 25.4616 -0.210193829517 0.0 0.0
+232 25.5719 -0.210175842147 0.0 0.0
+233 25.6821 -0.210146348262 0.0 0.0
+234 25.7923 -0.210105850764 0.0 0.0
+235 25.9025 -0.210054699849 0.0 0.0
+236 26.0128 -0.209993382569 0.0 0.0
+237 26.123 -0.209922235543 0.0 0.0
+238 26.2332 -0.209841729619 0.0 0.0
+239 26.3434 -0.209752187451 0.0 0.0
+240 26.4537 -0.209654063376 0.0 0.0
+241 26.5639 -0.209547665705 0.0 0.0
+242 26.6741 -0.20943343199 0.0 0.0
+243 26.7843 -0.209311655881 0.0 0.0
+244 26.8946 -0.209182757874 0.0 0.0
+245 27.0048 -0.209047016686 0.0 0.0
+246 27.115 -0.208904835548 0.0 0.0
+247 27.2252 -0.208756477971 0.0 0.0
+248 27.3354 -0.208602329743 0.0 0.0
+249 27.4457 -0.208442638956 0.0 0.0
+250 27.5559 -0.208277773805 0.0 0.0
+251 27.6661 -0.208107966787 0.0 0.0
+252 27.7763 -0.207933568379 0.0 0.0
+253 27.8866 -0.207754795341 0.0 0.0
+254 27.9968 -0.207571980356 0.0 0.0
+255 28.107 -0.207385324334 0.0 0.0
+256 28.2172 -0.207195142123 0.0 0.0
+257 28.3275 -0.207001618698 0.0 0.0
+258 28.4377 -0.20680505107 0.0 0.0
+259 28.5479 -0.206605608246 0.0 0.0
+260 28.6581 -0.206403569408 0.0 0.0
+261 28.7684 -0.2061990876 0.0 0.0
+262 28.8786 -0.205992424235 0.0 0.0
+263 28.9888 -0.205783716416 0.0 0.0
+264 29.099 -0.205573207883 0.0 0.0
+265 29.2093 -0.205361019872 0.0 0.0
+266 29.3195 -0.205147378554 0.0 0.0
+267 29.4297 -0.204932389409 0.0 0.0
+268 29.5399 -0.204716261209 0.0 0.0
+269 29.6501 -0.204499083776 0.0 0.0
+270 29.7604 -0.204281048697 0.0 0.0
+271 29.8706 -0.204062230302 0.0 0.0
+272 29.9808 -0.203842803194 0.0 0.0
+273 30.091 -0.203622826427 0.0 0.0
+274 30.2013 -0.203402457853 0.0 0.0
+275 30.3115 -0.20318174149 0.0 0.0
+276 30.4217 -0.202960818709 0.0 0.0
+277 30.5319 -0.202739718755 0.0 0.0
+278 30.6422 -0.202518566834 0.0 0.0
+279 30.7524 -0.202297377678 0.0 0.0
+280 30.8626 -0.202076260687 0.0 0.0
+281 30.9728 -0.201855216398 0.0 0.0
+282 31.0831 -0.201634338742 0.0 0.0
+283 31.1933 -0.201413614427 0.0 0.0
+284 31.3035 -0.201193122292 0.0 0.0
+285 31.4137 -0.200972835584 0.0 0.0
+286 31.5239 -0.20075281846 0.0 0.0
+287 31.6342 -0.200533031098 0.0 0.0
+288 31.7444 -0.200313523429 0.0 0.0
+289 31.8546 -0.200094242942 0.0 0.0
+290 31.9648 -0.199875225817 0.0 0.0
+291 32.0751 -0.199656407304 0.0 0.0
+292 32.1853 -0.199437810288 0.0 0.0
+293 32.2955 -0.199219358253 0.0 0.0
+294 32.4057 -0.199001061276 0.0 0.0
+295 32.516 -0.198782831565 0.0 0.0
+296 32.6262 -0.198564666897 0.0 0.0
+297 32.7364 -0.198346468699 0.0 0.0
+298 32.8466 -0.198128222983 0.0 0.0
+299 32.9569 -0.197909820904 0.0 0.0
+300 33.0671 -0.197691237269 0.0 0.0
+301 33.1773 -0.197472353471 0.0 0.0
+302 33.2875 -0.197253133679 0.0 0.0
+303 33.3977 -0.19703345008 0.0 0.0
+304 33.508 -0.196813256756 0.0 0.0
+305 33.6182 -0.196592417255 0.0 0.0
+306 33.7284 -0.196370876157 0.0 0.0
+307 33.8386 -0.196148488931 0.0 0.0
+308 33.9489 -0.195925191248 0.0 0.0
+309 34.0591 -0.195700831076 0.0 0.0
+310 34.1693 -0.195475335783 0.0 0.0
+311 34.2795 -0.195248546401 0.0 0.0
+312 34.3898 -0.195020382619 0.0 0.0
+313 34.5 -0.194790679118 0.0 0.0
+314 34.6102 -0.194559348513 0.0 0.0
+315 34.7204 -0.194326219739 0.0 0.0
+316 34.8307 -0.194091198936 0.0 0.0
+317 34.9409 -0.193854109907 0.0 0.0
+318 35.0511 -0.193614852927 0.0 0.0
+319 35.1613 -0.193373247259 0.0 0.0
+320 35.2715 -0.19312918794 0.0 0.0
+321 35.3818 -0.19288249029 0.0 0.0
+322 35.492 -0.192633044718 0.0 0.0
+323 35.6022 -0.192380663207 0.0 0.0
+324 35.7124 -0.192125232152 0.0 0.0
+325 35.8227 -0.191866560779 0.0 0.0
+326 35.9329 -0.191604532096 0.0 0.0
+327 36.0431 -0.191338953158 0.0 0.0
+328 36.1533 -0.191069704185 0.0 0.0
+329 36.2636 -0.190796590653 0.0 0.0
+330 36.3738 -0.190519490592 0.0 0.0
+331 36.484 -0.190238208465 0.0 0.0
+332 36.5942 -0.189952620721 0.0 0.0
+333 36.7045 -0.189662531373 0.0 0.0
+334 36.8147 -0.189367815854 0.0 0.0
+335 36.9249 -0.189068278307 0.0 0.0
+336 37.0351 -0.188763793721 0.0 0.0
+337 37.1453 -0.188454166904 0.0 0.0
+338 37.2556 -0.188139272963 0.0 0.0
+339 37.3658 -0.18781891792 0.0 0.0
+340 37.476 -0.187492977534 0.0 0.0
+341 37.5862 -0.187161259572 0.0 0.0
+342 37.6965 -0.186823640969 0.0 0.0
+343 37.8067 -0.186479931756 0.0 0.0
+344 37.9169 -0.186130010562 0.0 0.0
+345 38.0271 -0.185773690164 0.0 0.0
+346 38.1374 -0.185410851399 0.0 0.0
+347 38.2476 -0.185041310262 0.0 0.0
+348 38.3578 -0.184664950289 0.0 0.0
+349 38.468 -0.184281591148 0.0 0.0
+350 38.5783 -0.183891119533 0.0 0.0
+351 38.6885 -0.183493359242 0.0 0.0
+352 38.7987 -0.183088200571 0.0 0.0
+353 38.9089 -0.18267547187 0.0 0.0
+354 39.0191 -0.182255067459 0.0 0.0
+355 39.1294 -0.181826820652 0.0 0.0
+356 39.2396 -0.181390630205 0.0 0.0
+357 39.3498 -0.180946334773 0.0 0.0
+358 39.46 -0.18049383793 0.0 0.0
+359 39.5703 -0.180032984041 0.0 0.0
+360 39.6805 -0.179563681873 0.0 0.0
+361 39.7907 -0.179085781827 0.0 0.0
+362 39.9009 -0.178599198204 0.0 0.0
+363 40.0112 -0.178103787783 0.0 0.0
+364 40.1214 -0.1775994707 0.0 0.0
+365 40.2316 -0.17708611041 0.0 0.0
+366 40.3418 -0.176563633194 0.0 0.0
+367 40.4521 -0.176031909441 0.0 0.0
+368 40.5623 -0.175490871868 0.0 0.0
+369 40.6725 -0.174940398043 0.0 0.0
+370 40.7827 -0.174380427358 0.0 0.0
+371 40.893 -0.173810844811 0.0 0.0
+372 41.0032 -0.173231596674 0.0 0.0
+373 41.1134 -0.172642575592 0.0 0.0
+374 41.2236 -0.172043734928 0.0 0.0
+375 41.3338 -0.171434975129 0.0 0.0
+376 41.4441 -0.170816256853 0.0 0.0
+377 41.5543 -0.170187488498 0.0 0.0
+378 41.6645 -0.16954863817 0.0 0.0
+379 41.7747 -0.168899622357 0.0 0.0
+380 41.885 -0.168240416739 0.0 0.0
+381 41.9952 -0.167570946009 0.0 0.0
+382 42.1054 -0.16689119353 0.0 0.0
+383 42.2156 -0.166201092279 0.0 0.0
+384 42.3259 -0.165500633394 0.0 0.0
+385 42.4361 -0.164789758208 0.0 0.0
+386 42.5463 -0.164068465674 0.0 0.0
+387 42.6565 -0.163336705533 0.0 0.0
+388 42.7668 -0.162594484603 0.0 0.0
+389 42.877 -0.16184176104 0.0 0.0
+390 42.9872 -0.161078549533 0.0 0.0
+391 43.0974 -0.16030481667 0.0 0.0
+392 43.2076 -0.159520585001 0.0 0.0
+393 43.3179 -0.158725829502 0.0 0.0
+394 43.4281 -0.157920580582 0.0 0.0
+395 43.5383 -0.157104821545 0.0 0.0
+396 43.6485 -0.156278590606 0.0 0.0
+397 43.7588 -0.155441879354 0.0 0.0
+398 43.869 -0.154594733707 0.0 0.0
+399 43.9792 -0.153737153469 0.0 0.0
+400 44.0894 -0.152869192191 0.0 0.0
+401 44.1997 -0.151990857752 0.0 0.0
+402 44.3099 -0.151102211244 0.0 0.0
+403 44.4201 -0.150203268506 0.0 0.0
+404 44.5303 -0.14929409803 0.0 0.0
+405 44.6406 -0.14837472347 0.0 0.0
+406 44.7508 -0.14744522059 0.0 0.0
+407 44.861 -0.146505620698 0.0 0.0
+408 44.9712 -0.145556006646 0.0 0.0
+409 45.0814 -0.144596417245 0.0 0.0
+410 45.1917 -0.143626942253 0.0 0.0
+411 45.3019 -0.14264762778 0.0 0.0
+412 45.4121 -0.141658570318 0.0 0.0
+413 45.5223 -0.140659823051 0.0 0.0
+414 45.6326 -0.139651489009 0.0 0.0
+415 45.7428 -0.138633628234 0.0 0.0
+416 45.853 -0.137606350064 0.0 0.0
+417 45.9632 -0.136569721176 0.0 0.0
+418 46.0735 -0.135523856978 0.0 0.0
+419 46.1837 -0.134468830542 0.0 0.0
+420 46.2939 -0.133404763098 0.0 0.0
+421 46.4041 -0.132331733862 0.0 0.0
+422 46.5144 -0.131249869638 0.0 0.0
+423 46.6246 -0.130159255504 0.0 0.0
+424 46.7348 -0.129060023589 0.0 0.0
+425 46.845 -0.12795226456 0.0 0.0
+426 46.9552 -0.12683611559 0.0 0.0
+427 47.0655 -0.125711672662 0.0 0.0
+428 47.1757 -0.124579077706 0.0 0.0
+429 47.2859 -0.12343843174 0.0 0.0
+430 47.3961 -0.122289881163 0.0 0.0
+431 47.5064 -0.121133531727 0.0 0.0
+432 47.6166 -0.119969534022 0.0 0.0
+433 47.7268 -0.118797998229 0.0 0.0
+434 47.837 -0.117619078824 0.0 0.0
+435 47.9473 -0.116432890121 0.0 0.0
+436 48.0575 -0.115239590192 0.0 0.0
+437 48.1677 -0.11403929717 0.0 0.0
+438 48.2779 -0.112832172414 0.0 0.0
+439 48.3882 -0.111618337577 0.0 0.0
+440 48.4984 -0.110397957006 0.0 0.0
+441 48.6086 -0.109171155556 0.0 0.0
+442 48.7188 -0.107938100259 0.0 0.0
+443 48.829 -0.106698918871 0.0 0.0
+444 48.9393 -0.1054537808 0.0 0.0
+445 49.0495 -0.10420281639 0.0 0.0
+446 49.1597 -0.102946197133 0.0 0.0
+447 49.2699 -0.101684055653 0.0 0.0
+448 49.3802 -0.10041656522 0.0 0.0
+449 49.4904 -0.0991438604408 0.0 0.0
+450 49.6006 -0.0978661160652 0.0 0.0
+451 49.7108 -0.0965834683782 0.0 0.0
+452 49.8211 -0.0952960933198 0.0 0.0
+453 49.9313 -0.0940041285654 0.0 0.0
+454 50.0415 -0.0927077509426 0.0 0.0
+455 50.1517 -0.0914070992372 0.0 0.0
+456 50.262 -0.0901023508823 0.0 0.0
+457 50.3722 -0.0887936454779 0.0 0.0
+458 50.4824 -0.0874811608015 0.0 0.0
+459 50.5926 -0.0861650369861 0.0 0.0
+460 50.7029 -0.0848454518724 0.0 0.0
+461 50.8131 -0.0835225458617 0.0 0.0
+462 50.9233 -0.082196496615 0.0 0.0
+463 51.0335 -0.0808674445153 0.0 0.0
+464 51.1437 -0.0795355667865 0.0 0.0
+465 51.254 -0.0782010035674 0.0 0.0
+466 51.3642 -0.0768639313852 0.0 0.0
+467 51.4744 -0.0755244898808 0.0 0.0
+468 51.5846 -0.0741828546576 0.0 0.0
+469 51.6949 -0.0728391646308 0.0 0.0
+470 51.8051 -0.0714935942455 0.0 0.0
+471 51.9153 -0.0701462814672 0.0 0.0
+472 52.0255 -0.0687973993706 0.0 0.0
+473 52.1358 -0.0674470847597 0.0 0.0
+474 52.246 -0.0660955091249 0.0 0.0
+475 52.3562 -0.0647428079186 0.0 0.0
+476 52.4664 -0.0633891508524 0.0 0.0
+477 52.5767 -0.0620346718134 0.0 0.0
+478 52.6869 -0.0606795385831 0.0 0.0
+479 52.7971 -0.0593238832964 0.0 0.0
+480 52.9073 -0.0579678716142 0.0 0.0
+481 53.0175 -0.0566116337732 0.0 0.0
+482 53.1278 -0.0552553331571 0.0 0.0
+483 53.238 -0.0538990979275 0.0 0.0
+484 53.3482 -0.0525430890622 0.0 0.0
+485 53.4584 -0.0511874325056 0.0 0.0
+486 53.5687 -0.0498322866853 0.0 0.0
+487 53.6789 -0.0484777752072 0.0 0.0
+488 53.7891 -0.0471240538178 0.0 0.0
+489 53.8993 -0.0457712436779 0.0 0.0
+490 54.0096 -0.044419497741 0.0 0.0
+491 54.1198 -0.0430689346014 0.0 0.0
+492 54.23 -0.0417197043429 0.0 0.0
+493 54.3402 -0.0403719229028 0.0 0.0
+494 54.4505 -0.0390257373866 0.0 0.0
+495 54.5607 -0.0376812610094 0.0 0.0
+496 54.6709 -0.0363386378428 0.0 0.0
+497 54.7811 -0.0349979782772 0.0 0.0
+498 54.8913 -0.0336594233059 0.0 0.0
+499 55.0016 -0.0323230804555 0.0 0.0
+500 55.1118 -0.0309890875628 0.0 0.0
+501 55.222 -0.0296575492675 0.0 0.0
+502 55.3322 -0.0283286002128 0.0 0.0
+503 55.4425 -0.0270023420963 0.0 0.0
+504 55.5527 -0.0256789063749 0.0 0.0
+505 55.6629 -0.0243583917698 0.0 0.0
+506 55.7731 -0.0230409265228 0.0 0.0
+507 55.8834 -0.021726606387 0.0 0.0
+508 55.9936 -0.0204155563879 0.0 0.0
+509 56.1038 -0.0191078693012 0.0 0.0
+510 56.214 -0.017803666944 0.0 0.0
+511 56.3242 -0.0165030391334 0.0 0.0
+512 56.4345 -0.0152061044866 0.0 0.0
+513 56.5447 -0.0139129498883 0.0 0.0
+514 56.6549 -0.0126236907891 0.0 0.0
+515 56.7651 -0.0113384111631 0.0 0.0
+516 56.8754 -0.0100572233288 0.0 0.0
+517 56.9856 -0.00878020839276 0.0 0.0
+518 57.0958 -0.0075074755935 0.0 0.0
+519 57.206 -0.00623910321328 0.0 0.0
+520 57.3163 -0.00497519745793 0.0 0.0
+521 57.4265 -0.00371583384147 0.0 0.0
+522 57.5367 -0.00246111561249 0.0 0.0
+523 57.6469 -0.00121111556583 0.0 0.0
+524 57.7572 3.40659323422e-05 0.0 0.0
+525 57.8674 0.00127435873981 0.0 0.0
+526 57.9776 0.00250966530143 0.0 0.0
+527 58.0878 0.00373991803734 0.0 0.0
+528 58.1981 0.00496502213595 0.0 0.0
+529 58.3083 0.00618491249877 0.0 0.0
+530 58.4185 0.00739949696009 0.0 0.0
+531 58.5287 0.00860871282205 0.0 0.0
+532 58.639 0.00981247047965 0.0 0.0
+533 58.7492 0.0110107095393 0.0 0.0
+534 58.8594 0.0122033428603 0.0 0.0
+535 58.9696 0.0133903122539 0.0 0.0
+536 59.0798 0.0145715329625 0.0 0.0
+537 59.1901 0.0157469488877 0.0 0.0
+538 59.3003 0.0169164775557 0.0 0.0
+539 59.4105 0.0180800648684 0.0 0.0
+540 59.5207 0.0192376305168 0.0 0.0
+541 59.631 0.0203891223193 0.0 0.0
+542 59.7412 0.0215344620095 0.0 0.0
+543 59.8514 0.0226735992312 0.0 0.0
+544 59.9616 0.0238064576462 0.0 0.0
+545 60.0719 0.0249329886157 0.0 0.0
+546 60.1821 0.0260531176465 0.0 0.0
+547 60.2923 0.0271667976865 0.0 0.0
+548 60.4025 0.028273955998 0.0 0.0
+549 60.5127 0.0293745470025 0.0 0.0
+550 60.623 0.0304684996127 0.0 0.0
+551 60.7332 0.0315557696361 0.0 0.0
+552 60.8434 0.0326362875221 0.0 0.0
+553 60.9536 0.0337100103543 0.0 0.0
+554 61.0639 0.0347768700263 0.0 0.0
+555 61.1741 0.0358368248175 0.0 0.0
+556 61.2843 0.0368898079357 0.0 0.0
+557 61.3945 0.0379357787761 0.0 0.0
+558 61.5048 0.0389746717719 0.0 0.0
+559 61.615 0.040006447329 0.0 0.0
+560 61.7252 0.0410310410253 0.0 0.0
+561 61.8354 0.042048414185 0.0 0.0
+562 61.9457 0.0430585034428 0.0 0.0
+563 62.0559 0.0440612709578 0.0 0.0
+564 62.1661 0.0450566543415 0.0 0.0
+565 62.2763 0.0460446165118 0.0 0.0
+566 62.3865 0.047025095972 0.0 0.0
+567 62.4968 0.0479980563284 0.0 0.0
+568 62.607 0.0489634369137 0.0 0.0
+569 62.7172 0.0499212019437 0.0 0.0
+570 62.8274 0.0508712915123 0.0 0.0
+571 62.9377 0.0518136704005 0.0 0.0
+572 63.0479 0.0527482793928 0.0 0.0
+573 63.1581 0.053675083775 0.0 0.0
+574 63.2683 0.0545940249801 0.0 0.0
+575 63.3786 0.0555050687475 0.0 0.0
+576 63.4888 0.0564081571109 0.0 0.0
+577 63.599 0.0573032562275 0.0 0.0
+578 63.7092 0.0581903086884 0.0 0.0
+579 63.8195 0.0590692810316 0.0 0.0
+580 63.9297 0.0599401163841 0.0 0.0
+581 64.0399 0.0608027816347 0.0 0.0
+582 64.1501 0.0616572204182 0.0 0.0
+583 64.2604 0.0625033999637 0.0 0.0
+584 64.3706 0.0633412643907 0.0 0.0
+585 64.4808 0.0641707812624 0.0 0.0
+586 64.591 0.0649918951763 0.0 0.0
+587 64.7012 0.0658045740224 0.0 0.0
+588 64.8115 0.0666087628816 0.0 0.0
+589 64.9217 0.0674044299695 0.0 0.0
+590 65.0319 0.0681915208639 0.0 0.0
+591 65.1421 0.0689700041207 0.0 0.0
+592 65.2524 0.0697398258267 0.0 0.0
+593 65.3626 0.0705009548996 0.0 0.0
+594 65.4728 0.0712533379561 0.0 0.0
+595 65.583 0.0719969443139 0.0 0.0
+596 65.6933 0.0727317211523 0.0 0.0
+597 65.8035 0.0734576382114 0.0 0.0
+598 65.9137 0.0741746432784 0.0 0.0
+599 66.0239 0.0748827065768 0.0 0.0
+600 66.1342 0.0755817765343 0.0 0.0
+601 66.2444 0.0762718238997 0.0 0.0
+602 66.3546 0.0769527978173 0.0 0.0
+603 66.4648 0.0776246696169 0.0 0.0
+604 66.575 0.0782873892097 0.0 0.0
+605 66.6853 0.0789409285824 0.0 0.0
+606 66.7955 0.0795852384789 0.0 0.0
+607 66.9057 0.0802202916158 0.0 0.0
+608 67.0159 0.0808460396512 0.0 0.0
+609 67.1262 0.0814624561108 0.0 0.0
+610 67.2364 0.0820694936398 0.0 0.0
+611 67.3466 0.0826671266636 0.0 0.0
+612 67.4568 0.0832553089116 0.0 0.0
+613 67.5671 0.0838340157914 0.0 0.0
+614 67.6773 0.0844032022135 0.0 0.0
+615 67.7875 0.084962844668 0.0 0.0
+616 67.8977 0.0855128993393 0.0 0.0
+617 68.0079 0.0860533439075 0.0 0.0
+618 68.1182 0.0865841359322 0.0 0.0
+619 68.2284 0.0871052544021 0.0 0.0
+620 68.3386 0.0876166583446 0.0 0.0
+621 68.4488 0.0881183281678 0.0 0.0
+622 68.5591 0.0886102245032 0.0 0.0
+623 68.6693 0.0890923292659 0.0 0.0
+624 68.7795 0.0895646048186 0.0 0.0
+625 68.8897 0.0900270347082 0.0 0.0
+626 69.0 0.0904795831344 0.0 0.0
+627 69.1102 0.0909222354087 0.0 0.0
+628 69.2204 0.0913549576853 0.0 0.0
+629 69.3306 0.0917777371561 0.0 0.0
+630 69.4409 0.092190542059 0.0 0.0
+631 69.5511 0.0925933615997 0.0 0.0
+632 69.6613 0.0929861662087 0.0 0.0
+633 69.7715 0.0933689472378 0.0 0.0
+634 69.8818 0.0937416774387 0.0 0.0
+635 69.992 0.0941043504276 0.0 0.0
+636 70.1022 0.0944569414123 0.0 0.0
+637 70.2124 0.094799446397 0.0 0.0
+638 70.3226 0.0951318431588 0.0 0.0
+639 70.4329 0.0954541302266 0.0 0.0
+640 70.5431 0.0957662880755 0.0 0.0
+641 70.6533 0.0960683178708 0.0 0.0
+642 70.7635 0.0963602029101 0.0 0.0
+643 70.8738 0.0966419471228 0.0 0.0
+644 70.984 0.0969135367481 0.0 0.0
+645 71.0942 0.0971749785908 0.0 0.0
+646 71.2044 0.0974262619615 0.0 0.0
+647 71.3147 0.0976673966496 0.0 0.0
+648 71.4249 0.097898375142 0.0 0.0
+649 71.5351 0.0981192103465 0.0 0.0
+650 71.6453 0.0983298980227 0.0 0.0
+651 71.7556 0.0985304543001 0.0 0.0
+652 71.8658 0.0987208783283 0.0 0.0
+653 71.976 0.0989011895601 0.0 0.0
+654 72.0862 0.0990713906259 0.0 0.0
+655 72.1964 0.0992315044095 0.0 0.0
+656 72.3067 0.0993815371158 0.0 0.0
+657 72.4169 0.0995215151452 0.0 0.0
+658 72.5271 0.0996514483764 0.0 0.0
+659 72.6373 0.0997713668025 0.0 0.0
+660 72.7476 0.0998812840545 0.0 0.0
+661 72.8578 0.0999812338182 0.0 0.0
+662 72.968 0.100071233535 0.0 0.0
+663 73.0782 0.100151320641 0.0 0.0
+664 73.1885 0.100221516489 0.0 0.0
+665 73.2987 0.100281862312 0.0 0.0
+666 73.4089 0.100332383416 0.0 0.0
+667 73.5191 0.100373124917 0.0 0.0
+668 73.6294 0.100404116113 0.0 0.0
+669 73.7396 0.100425406034 0.0 0.0
+670 73.8498 0.100437028035 0.0 0.0
+671 73.96 0.100439035088 0.0 0.0
+672 74.0703 0.100431464627 0.0 0.0
+673 74.1805 0.100414373614 0.0 0.0
+674 74.2907 0.100387803572 0.0 0.0
+675 74.4009 0.100351815467 0.0 0.0
+676 74.5111 0.10030645494 0.0 0.0
+677 74.6214 0.100251786961 0.0 0.0
+678 74.7316 0.10018786128 0.0 0.0
+679 74.8418 0.100114746884 0.0 0.0
+680 74.952 0.100032497628 0.0 0.0
+681 75.0623 0.0999411864846 0.0 0.0
+682 75.1725 0.0998408714086 0.0 0.0
+683 75.2827 0.0997316293392 0.0 0.0
+684 75.3929 0.0996135222865 0.0 0.0
+685 75.5032 0.0994866311337 0.0 0.0
+686 75.6134 0.0993510219032 0.0 0.0
+687 75.7236 0.0992067793784 0.0 0.0
+688 75.8338 0.0990539735403 0.0 0.0
+689 75.944 0.0988926930172 0.0 0.0
+690 76.0543 0.0987230116853 0.0 0.0
+691 76.1645 0.0985450219508 0.0 0.0
+692 76.2747 0.0983588015206 0.0 0.0
+693 76.3849 0.0981644464856 0.0 0.0
+694 76.4952 0.0979620383069 0.0 0.0
+695 76.6054 0.0977516766709 0.0 0.0
+696 76.7156 0.0975334466932 0.0 0.0
+697 76.8258 0.0973074515663 0.0 0.0
+698 76.9361 0.0970737799416 0.0 0.0
+699 77.0463 0.0968325384043 0.0 0.0
+700 77.1565 0.0965838190408 0.0 0.0
+701 77.2667 0.0963277316998 0.0 0.0
+702 77.377 0.0960643717591 0.0 0.0
+703 77.4872 0.0957938522175 0.0 0.0
+704 77.5974 0.0955162716086 0.0 0.0
+705 77.7076 0.0952317459247 0.0 0.0
+706 77.8178 0.094940376706 0.0 0.0
+707 77.9281 0.0946422827964 0.0 0.0
+708 78.0383 0.0943375685846 0.0 0.0
+709 78.1485 0.0940263555942 0.0 0.0
+710 78.2587 0.0937087509041 0.0 0.0
+711 78.369 0.0933848785343 0.0 0.0
+712 78.4792 0.0930548480824 0.0 0.0
+713 78.5894 0.0927187859021 0.0 0.0
+714 78.6996 0.0923768038927 0.0 0.0
+715 78.8099 0.0920290305622 0.0 0.0
+716 78.9201 0.0916755799384 0.0 0.0
+717 79.0303 0.0913165824606 0.0 0.0
+718 79.1405 0.0909521540913 0.0 0.0
+719 79.2508 0.0905824270022 0.0 0.0
+720 79.361 0.0902075188729 0.0 0.0
+721 79.4712 0.0898275634009 0.0 0.0
+722 79.5814 0.0894426797621 0.0 0.0
+723 79.6917 0.0890530029629 0.0 0.0
+724 79.8019 0.0886586534561 0.0 0.0
+725 79.9121 0.0882597673275 0.0 0.0
+726 80.0223 0.0878564660804 0.0 0.0
+727 80.1326 0.0874488866469 0.0 0.0
+728 80.2428 0.0870371513533 0.0 0.0
+729 80.353 0.0866213977411 0.0 0.0
+730 80.4632 0.0862017487137 0.0 0.0
+731 80.5734 0.0857783421967 0.0 0.0
+732 80.6837 0.0853513014153 0.0 0.0
+733 80.7939 0.0849207644393 0.0 0.0
+734 80.9041 0.0844868545848 0.0 0.0
+735 81.0143 0.0840497097978 0.0 0.0
+736 81.1245 0.0836094532489 0.0 0.0
+737 81.2348 0.0831662225199 0.0 0.0
+738 81.345 0.0827201403712 0.0 0.0
+739 81.4552 0.0822713437804 0.0 0.0
+740 81.5655 0.0818199548466 0.0 0.0
+741 81.6757 0.0813661096857 0.0 0.0
+742 81.7859 0.0809099294979 0.0 0.0
+743 81.8961 0.0804515492758 0.0 0.0
+744 82.0063 0.0799910890688 0.0 0.0
+745 82.1166 0.0795286825118 0.0 0.0
+746 82.2268 0.0790644482371 0.0 0.0
+747 82.337 0.0785985182758 0.0 0.0
+748 82.4472 0.0781310096116 0.0 0.0
+749 82.5575 0.0776620524058 0.0 0.0
+750 82.6677 0.0771917617532 0.0 0.0
+751 82.7779 0.0767202657153 0.0 0.0
+752 82.8881 0.0762476772389 0.0 0.0
+753 82.9984 0.0757741220541 0.0 0.0
+754 83.1086 0.0752997107253 0.0 0.0
+755 83.2188 0.0748245664066 0.0 0.0
+756 83.329 0.0743487970535 0.0 0.0
+757 83.4393 0.0738725230148 0.0 0.0
+758 83.5495 0.0733958494043 0.0 0.0
+759 83.6597 0.072918893545 0.0 0.0
+760 83.7699 0.0724417574875 0.0 0.0
+761 83.8801 0.0719645553093 0.0 0.0
+762 83.9904 0.0714873857802 0.0 0.0
+763 84.1006 0.0710103595306 0.0 0.0
+764 84.2108 0.0705335718367 0.0 0.0
+765 84.321 0.0700571296735 0.0 0.0
+766 84.4313 0.0695811246313 0.0 0.0
+767 84.5415 0.0691056598441 0.0 0.0
+768 84.6517 0.0686308230069 0.0 0.0
+769 84.7619 0.0681567132302 0.0 0.0
+770 84.8722 0.0676834141582 0.0 0.0
+771 84.9824 0.0672110206722 0.0 0.0
+772 85.0926 0.0667396122029 0.0 0.0
+773 85.2028 0.0662692792514 0.0 0.0
+774 85.3131 0.0658000968583 0.0 0.0
+775 85.4233 0.0653321509944 0.0 0.0
+776 85.5335 0.0648655121683 0.0 0.0
+777 85.6437 0.0644002616698 0.0 0.0
+778 85.7539 0.0639364653392 0.0 0.0
+779 85.8642 0.0634741996572 0.0 0.0
+780 85.9744 0.0630135256667 0.0 0.0
+781 86.0846 0.062554514932 0.0 0.0
+782 86.1948 0.0620972235695 0.0 0.0
+783 86.3051 0.0616417181226 0.0 0.0
+784 86.4153 0.0611880497023 0.0 0.0
+785 86.5255 0.0607362797168 0.0 0.0
+786 86.6357 0.06028645419 0.0 0.0
+787 86.746 0.0598386293215 0.0 0.0
+788 86.8562 0.0593928459664 0.0 0.0
+789 86.9664 0.0589491550682 0.0 0.0
+790 87.0766 0.0585075922346 0.0 0.0
+791 87.1869 0.0580682031034 0.0 0.0
+792 87.2971 0.0576310180063 0.0 0.0
+793 87.4073 0.0571960772255 0.0 0.0
+794 87.5175 0.0567634057905 0.0 0.0
+795 87.6277 0.0563330386039 0.0 0.0
+796 87.738 0.0559049953759 0.0 0.0
+797 87.8482 0.0554793056293 0.0 0.0
+798 87.9584 0.0550559837493 0.0 0.0
+799 88.0686 0.0546350538793 0.0 0.0
+800 88.1789 0.0542165251108 0.0 0.0
+801 88.2891 0.0538004162153 0.0 0.0
+802 88.3993 0.0533867310124 0.0 0.0
+803 88.5095 0.0529754829713 0.0 0.0
+804 88.6198 0.0525666706478 0.0 0.0
+805 88.73 0.0521603022676 0.0 0.0
+806 88.8402 0.0517563712109 0.0 0.0
+807 88.9504 0.0513548804875 0.0 0.0
+808 89.0607 0.0509558183882 0.0 0.0
+809 89.1709 0.0505591828025 0.0 0.0
+810 89.2811 0.0501649570024 0.0 0.0
+811 89.3913 0.0497731338556 0.0 0.0
+812 89.5015 0.0493836917328 0.0 0.0
+813 89.6118 0.0489966185643 0.0 0.0
+814 89.722 0.0486118879428 0.0 0.0
+815 89.8322 0.0482294830138 0.0 0.0
+816 89.9425 0.0478493726844 0.0 0.0
+817 90.0527 0.0474715354635 0.0 0.0
+818 90.1629 0.0470959357338 0.0 0.0
+819 90.2731 0.0467225474913 0.0 0.0
+820 90.3833 0.046351330775 0.0 0.0
+821 90.4936 0.0459822552208 0.0 0.0
+822 90.6038 0.0456152766883 0.0 0.0
+823 90.714 0.0452503606464 0.0 0.0
+824 90.8242 0.0448874589368 0.0 0.0
+825 90.9344 0.0445265330658 0.0 0.0
+826 91.0447 0.0441675310458 0.0 0.0
+827 91.1549 0.0438104106215 0.0 0.0
+828 91.2651 0.0434551161776 0.0 0.0
+829 91.3754 0.0431016019103 0.0 0.0
+830 91.4856 0.0427498087988 0.0 0.0
+831 91.5958 0.0423996877011 0.0 0.0
+832 91.706 0.0420511764275 0.0 0.0
+833 91.8162 0.0417042227204 0.0 0.0
+834 91.9265 0.0413587614702 0.0 0.0
+835 92.0367 0.0410147375286 0.0 0.0
+836 92.1469 0.0406720831154 0.0 0.0
+837 92.2571 0.0403307404595 0.0 0.0
+838 92.3674 0.0399906393297 0.0 0.0
+839 92.4776 0.0396517196148 0.0 0.0
+840 92.5878 0.0393139088928 0.0 0.0
+841 92.698 0.0389771449564 0.0 0.0
+842 92.8083 0.0386413534787 0.0 0.0
+843 92.9185 0.0383064704234 0.0 0.0
+844 93.0287 0.0379724198357 0.0 0.0
+845 93.1389 0.0376391361113 0.0 0.0
+846 93.2491 0.0373065419547 0.0 0.0
+847 93.3594 0.0369745704883 0.0 0.0
+848 93.4696 0.0366431433392 0.0 0.0
+849 93.5798 0.0363121926511 0.0 0.0
+850 93.69 0.0359816392573 0.0 0.0
+851 93.8003 0.0356514146124 0.0 0.0
+852 93.9105 0.0353214390497 0.0 0.0
+853 94.0207 0.0349916436202 0.0 0.0
+854 94.1309 0.0346619484453 0.0 0.0
+855 94.2412 0.0343322844715 0.0 0.0
+856 94.3514 0.0340025719012 0.0 0.0
+857 94.4616 0.0336727418634 0.0 0.0
+858 94.5718 0.0333427149386 0.0 0.0
+859 94.6821 0.0330124227292 0.0 0.0
+860 94.7923 0.032681786483 0.0 0.0
+861 94.9025 0.0323507385733 0.0 0.0
+862 95.0127 0.0320192012083 0.0 0.0
+863 95.123 0.0316871078063 0.0 0.0
+864 95.2332 0.0313543818404 0.0 0.0
+865 95.3434 0.0310209580541 0.0 0.0
+866 95.4536 0.0306867614636 0.0 0.0
+867 95.5638 0.0303517284372 0.0 0.0
+868 95.6741 0.0300157858006 0.0 0.0
+869 95.7843 0.0296788718318 0.0 0.0
+870 95.8945 0.0293409154337 0.0 0.0
+871 96.0047 0.0290018570832 0.0 0.0
+872 96.115 0.0286616280143 0.0 0.0
+873 96.2252 0.0283201711744 0.0 0.0
+874 96.3354 0.0279774204049 0.0 0.0
+875 96.4456 0.027633321352 0.0 0.0
+876 96.5559 0.0272878107595 0.0 0.0
+877 96.6661 0.0269408372038 0.0 0.0
+878 96.7763 0.0265923405664 0.0 0.0
+879 96.8865 0.0262422726252 0.0 0.0
+880 96.9968 0.0258905766207 0.0 0.0
+881 97.107 0.0255372077683 0.0 0.0
+882 97.2172 0.0251821128996 0.0 0.0
+883 97.3274 0.024825250893 0.0 0.0
+884 97.4376 0.0244665723844 0.0 0.0
+885 97.5479 0.0241060401291 0.0 0.0
+886 97.6581 0.0237436087819 0.0 0.0
+887 97.7683 0.0233792451686 0.0 0.0
+888 97.8785 0.0230129081624 0.0 0.0
+889 97.9888 0.0226445688472 0.0 0.0
+890 98.099 0.0222741905026 0.0 0.0
+891 98.2092 0.0219017486448 0.0 0.0
+892 98.3194 0.0215272111241 0.0 0.0
+893 98.4297 0.0211505580557 0.0 0.0
+894 98.5399 0.0207717620316 0.0 0.0
+895 98.6501 0.0203908079054 0.0 0.0
+896 98.7603 0.0200076731334 0.0 0.0
+897 98.8706 0.0196223474772 0.0 0.0
+898 98.9808 0.01923481337 0.0 0.0
+899 99.091 0.0188450655966 0.0 0.0
+900 99.2012 0.0184530916937 0.0 0.0
+901 99.3114 0.0180588915601 0.0 0.0
+902 99.4217 0.0176624579478 0.0 0.0
+903 99.5319 0.0172637959546 0.0 0.0
+904 99.6421 0.016862903626 0.0 0.0
+905 99.7523 0.016459791334 0.0 0.0
+906 99.8626 0.0160544624871 0.0 0.0
+907 99.9728 0.0156469327969 0.0 0.0
+908 100.083 0.0152372110697 0.0 0.0
+909 100.193 0.0148253184059 0.0 0.0
+910 100.303 0.0144112690449 0.0 0.0
+911 100.414 0.0139950894962 0.0 0.0
+912 100.524 0.0135767994568 0.0 0.0
+913 100.634 0.0131564308489 0.0 0.0
+914 100.744 0.0127340088274 0.0 0.0
+915 100.855 0.0123095707223 0.0 0.0
+916 100.965 0.0118831471222 0.0 0.0
+917 101.075 0.0114547807504 0.0 0.0
+918 101.185 0.0110245075929 0.0 0.0
+919 101.295 0.0105923757165 0.0 0.0
+920 101.406 0.0101584264678 0.0 0.0
+921 101.516 0.00972271318856 0.0 0.0
+922 101.626 0.00928528252436 0.0 0.0
+923 101.736 0.00884619301898 0.0 0.0
+924 101.847 0.00840549652564 0.0 0.0
+925 101.957 0.00796325670442 0.0 0.0
+926 102.067 0.00751953052368 0.0 0.0
+927 102.177 0.00707438663938 0.0 0.0
+928 102.287 0.00662788702828 0.0 0.0
+929 102.398 0.00618010521701 0.0 0.0
+930 102.508 0.00573110804686 0.0 0.0
+931 102.618 0.00528097380865 0.0 0.0
+932 102.728 0.00482977403218 0.0 0.0
+933 102.839 0.00437759161794 0.0 0.0
+934 102.949 0.00392450264503 0.0 0.0
+935 103.059 0.00347059443827 0.0 0.0
+936 103.169 0.00301594744671 0.0 0.0
+937 103.279 0.00256065324636 0.0 0.0
+938 103.39 0.00210479646924 0.0 0.0
+939 103.5 0.00164847272573 0.0 0.0
+940 103.61 0.00119177063919 0.0 0.0
+941 103.72 0.000734789655771 0.0 0.0
+942 103.831 0.000277622151631 0.0 0.0
+943 103.941 -0.000179628813379 0.0 0.0
+944 104.051 -0.000636867317697 0.0 0.0
+945 104.161 -0.00109398694291 0.0 0.0
+946 104.272 -0.00155088846695 0.0 0.0
+947 104.382 -0.00200746234338 0.0 0.0
+948 104.492 -0.00246360631946 0.0 0.0
+949 104.602 -0.00291920795843 0.0 0.0
+950 104.712 -0.00337416225685 0.0 0.0
+951 104.823 -0.00382835415803 0.0 0.0
+952 104.933 -0.00428167616572 0.0 0.0
+953 105.043 -0.00473401089156 0.0 0.0
+954 105.153 -0.00518524861995 0.0 0.0
+955 105.264 -0.00563526993591 0.0 0.0
+956 105.374 -0.00608396316697 0.0 0.0
+957 105.484 -0.00653120717947 0.0 0.0
+958 105.594 -0.00697688866013 0.0 0.0
+959 105.704 -0.00742088501349 0.0 0.0
+960 105.815 -0.00786308162507 0.0 0.0
+961 105.925 -0.00830335474603 0.0 0.0
+962 106.035 -0.00874158873834 0.0 0.0
+963 106.145 -0.00917765904131 0.0 0.0
+964 106.256 -0.00961144929685 0.0 0.0
+965 106.366 -0.0100428344459 0.0 0.0
+966 106.476 -0.0104716977396 0.0 0.0
+967 106.586 -0.0108979139243 0.0 0.0
+968 106.696 -0.0113213661961 0.0 0.0
+969 106.807 -0.0117419294215 0.0 0.0
+970 106.917 -0.0121594870577 0.0 0.0
+971 107.027 -0.0125739144316 0.0 0.0
+972 107.137 -0.012985095577 0.0 0.0
+973 107.248 -0.0133929065993 0.0 0.0
+974 107.358 -0.0137972324405 0.0 0.0
+975 107.468 -0.014197950311 0.0 0.0
+976 107.578 -0.0145949463772 0.0 0.0
+977 107.688 -0.0149880992788 0.0 0.0
+978 107.799 -0.015377296733 0.0 0.0
+979 107.909 -0.0157624191204 0.0 0.0
+980 108.019 -0.0161433560365 0.0 0.0
+981 108.129 -0.0165199899181 0.0 0.0
+982 108.24 -0.0168922125487 0.0 0.0
+983 108.35 -0.0172599087391 0.0 0.0
+984 108.46 -0.0176229727743 0.0 0.0
+985 108.57 -0.0179812921399 0.0 0.0
+986 108.68 -0.0183347639255 0.0 0.0
+987 108.791 -0.0186832786134 0.0 0.0
+988 108.901 -0.0190267363761 0.0 0.0
+989 109.011 -0.019365030985 0.0 0.0
+990 109.121 -0.0196980660054 0.0 0.0
+991 109.232 -0.0200257387783 0.0 0.0
+992 109.342 -0.0203479565396 0.0 0.0
+993 109.452 -0.0206646204796 0.0 0.0
+994 109.562 -0.0209756417886 0.0 0.0
+995 109.672 -0.0212809257664 0.0 0.0
+996 109.783 -0.0215803878224 0.0 0.0
+997 109.893 -0.021873937636 0.0 0.0
+998 110.003 -0.0221614950746 0.0 0.0
+999 110.113 -0.0224429744588 0.0 0.0
+1000 110.224 -0.0227183003548 0.0 0.0
+1001 110.334 -0.0229873919467 0.0 0.0
+1002 110.444 -0.0232501787557 0.0 0.0
+1003 110.554 -0.023506585028 0.0 0.0
+1004 110.664 -0.0237565454752 0.0 0.0
+1005 110.775 -0.0239999896224 0.0 0.0
+1006 110.885 -0.0242368575448 0.0 0.0
+1007 110.995 -0.0244670842771 0.0 0.0
+1008 111.105 -0.0246906154428 0.0 0.0
+1009 111.216 -0.024907391753 0.0 0.0
+1010 111.326 -0.025117364566 0.0 0.0
+1011 111.436 -0.0253204804462 0.0 0.0
+1012 111.546 -0.0255166966419 0.0 0.0
+1013 111.656 -0.02570596571 0.0 0.0
+1014 111.767 -0.0258882509515 0.0 0.0
+1015 111.877 -0.0260635110555 0.0 0.0
+1016 111.987 -0.0262317154843 0.0 0.0
+1017 112.097 -0.0263928292044 0.0 0.0
+1018 112.208 -0.0265468279456 0.0 0.0
+1019 112.318 -0.026693683037 0.0 0.0
+1020 112.428 -0.0268333765941 0.0 0.0
+1021 112.538 -0.0269658863962 0.0 0.0
+1022 112.648 -0.0270912010097 0.0 0.0
+1023 112.759 -0.027209304745 0.0 0.0
+1024 112.869 -0.0273201926813 0.0 0.0
+1025 112.979 -0.0274238556989 0.0 0.0
+1026 113.089 -0.0275202954543 0.0 0.0
+1027 113.2 -0.0276095094216 0.0 0.0
+1028 113.31 -0.0276915058576 0.0 0.0
+1029 113.42 -0.0277662888611 0.0 0.0
+1030 113.53 -0.0278338732839 0.0 0.0
+1031 113.641 -0.0278942698562 0.0 0.0
+1032 113.751 -0.0279475000171 0.0 0.0
+1033 113.861 -0.0279935811012 0.0 0.0
+1034 113.971 -0.0280325411202 0.0 0.0
+1035 114.081 -0.0280644039703 0.0 0.0
+1036 114.192 -0.0280892041835 0.0 0.0
+1037 114.302 -0.0281069721811 0.0 0.0
+1038 114.412 -0.0281177489453 0.0 0.0
+1039 114.522 -0.0281215713406 0.0 0.0
+1040 114.633 -0.0281184867282 0.0 0.0
+1041 114.743 -0.0281085383337 0.0 0.0
+1042 114.853 -0.0280917797898 0.0 0.0
+1043 114.963 -0.0280682605849 0.0 0.0
+1044 115.073 -0.0280380405034 0.0 0.0
+1045 115.184 -0.0280011751624 0.0 0.0
+1046 115.294 -0.0279577303899 0.0 0.0
+1047 115.404 -0.0279077677881 0.0 0.0
+1048 115.514 -0.027851359065 0.0 0.0
+1049 115.625 -0.0277885716608 0.0 0.0
+1050 115.735 -0.0277194830036 0.0 0.0
+1051 115.845 -0.0276441661981 0.0 0.0
+1052 115.955 -0.0275627042173 0.0 0.0
+1053 116.065 -0.0274751756331 0.0 0.0
+1054 116.176 -0.0273816687725 0.0 0.0
+1055 116.286 -0.0272822674814 0.0 0.0
+1056 116.396 -0.0271770652345 0.0 0.0
+1057 116.506 -0.0270661509222 0.0 0.0
+1058 116.617 -0.0269496229417 0.0 0.0
+1059 116.727 -0.0268275750212 0.0 0.0
+1060 116.837 -0.0267001102324 0.0 0.0
+1061 116.947 -0.0265673268908 0.0 0.0
+1062 117.057 -0.0264293325093 0.0 0.0
+1063 117.168 -0.0262862297275 0.0 0.0
+1064 117.278 -0.0261381302359 0.0 0.0
+1065 117.388 -0.0259851407454 0.0 0.0
+1066 117.498 -0.0258273768454 0.0 0.0
+1067 117.609 -0.0256649490377 0.0 0.0
+1068 117.719 -0.0254979765344 0.0 0.0
+1069 117.829 -0.025326573341 0.0 0.0
+1070 117.939 -0.0251508620033 0.0 0.0
+1071 118.049 -0.0249709597282 0.0 0.0
+1072 118.16 -0.0247869920986 0.0 0.0
+1073 118.27 -0.0245990792237 0.0 0.0
+1074 118.38 -0.0244073494084 0.0 0.0
+1075 118.49 -0.024211925359 0.0 0.0
+1076 118.601 -0.0240129377834 0.0 0.0
+1077 118.711 -0.0238105116668 0.0 0.0
+1078 118.821 -0.0236047798059 0.0 0.0
+1079 118.931 -0.0233958691323 0.0 0.0
+1080 119.041 -0.0231839142075 0.0 0.0
+1081 119.152 -0.0229690435942 0.0 0.0
+1082 119.262 -0.0227513932655 0.0 0.0
+1083 119.372 -0.0225310930969 0.0 0.0
+1084 119.482 -0.0223082801556 0.0 0.0
+1085 119.593 -0.0220830852523 0.0 0.0
+1086 119.703 -0.0218556462474 0.0 0.0
+1087 119.813 -0.0216260945572 0.0 0.0
+1088 119.923 -0.0213945684582 0.0 0.0
+1089 120.033 -0.0211611996628 0.0 0.0
+1090 120.144 -0.0209261265344 0.0 0.0
+1091 120.254 -0.020689480721 0.0 0.0
+1092 120.364 -0.020451400343 0.0 0.0
+1093 120.474 -0.0202120166575 0.0 0.0
+1094 120.585 -0.0199714671962 0.0 0.0
+1095 120.695 -0.0197298824932 0.0 0.0
+1096 120.805 -0.0194873991572 0.0 0.0
+1097 120.915 -0.0192441466724 0.0 0.0
+1098 121.025 -0.0190002603956 0.0 0.0
+1099 121.136 -0.0187558684213 0.0 0.0
+1100 121.246 -0.0185111045439 0.0 0.0
+1101 121.356 -0.0182660951396 0.0 0.0
+1102 121.466 -0.0180209721152 0.0 0.0
+1103 121.577 -0.0177758598232 0.0 0.0
+1104 121.687 -0.0175308879553 0.0 0.0
+1105 121.797 -0.01728617854 0.0 0.0
+1106 121.907 -0.0170418587494 0.0 0.0
+1107 122.018 -0.0167980479724 0.0 0.0
+1108 122.128 -0.0165548705716 0.0 0.0
+1109 122.238 -0.016312443005 0.0 0.0
+1110 122.348 -0.0160708865291 0.0 0.0
+1111 122.458 -0.0158303143834 0.0 0.0
+1112 122.569 -0.01559084445 0.0 0.0
+1113 122.679 -0.0153525864637 0.0 0.0
+1114 122.789 -0.015115654667 0.0 0.0
+1115 122.899 -0.0148801550247 0.0 0.0
+1116 123.01 -0.014646197878 0.0 0.0
+1117 123.12 -0.0144138851787 0.0 0.0
+1118 123.23 -0.014183323107 0.0 0.0
+1119 123.34 -0.0139546093676 0.0 0.0
+1120 123.45 -0.0137278457491 0.0 0.0
+1121 123.561 -0.0135031254734 0.0 0.0
+1122 123.671 -0.0132805457255 0.0 0.0
+1123 123.781 -0.0130601950221 0.0 0.0
+1124 123.891 -0.0128421657386 0.0 0.0
+1125 124.002 -0.0126265414954 0.0 0.0
+1126 124.112 -0.0124134096543 0.0 0.0
+1127 124.222 -0.0122028487611 0.0 0.0
+1128 124.332 -0.0119949409872 0.0 0.0
+1129 124.442 -0.0117897596246 0.0 0.0
+1130 124.553 -0.0115873814999 0.0 0.0
+1131 124.663 -0.0113878745001 0.0 0.0
+1132 124.773 -0.0111913099545 0.0 0.0
+1133 124.883 -0.0109977502055 0.0 0.0
+1134 124.994 -0.010807260956 0.0 0.0
+1135 125.104 -0.0106198988908 0.0 0.0
+1136 125.214 -0.0104357239606 0.0 0.0
+1137 125.324 -0.0102547870927 0.0 0.0
+1138 125.434 -0.0100771423901 0.0 0.0
+1139 125.545 -0.00990283493273 0.0 0.0
+1140 125.655 -0.00973191289875 0.0 0.0
+1141 125.765 -0.00956441544464 0.0 0.0
+1142 125.875 -0.00940038476962 0.0 0.0
+1143 125.986 -0.00923985404462 0.0 0.0
+1144 126.096 -0.00908285944813 0.0 0.0
+1145 126.206 -0.00892942813531 0.0 0.0
+1146 126.316 -0.0087795902323 0.0 0.0
+1147 126.426 -0.00863336685208 0.0 0.0
+1148 126.537 -0.00849078207399 0.0 0.0
+1149 126.647 -0.00835185095759 0.0 0.0
+1150 126.757 -0.00821659154402 0.0 0.0
+1151 126.867 -0.00808501286653 0.0 0.0
+1152 126.978 -0.00795712693509 0.0 0.0
+1153 127.088 -0.0078329368057 0.0 0.0
+1154 127.198 -0.00771244849384 0.0 0.0
+1155 127.308 -0.00759565913076 0.0 0.0
+1156 127.418 -0.00748256880219 0.0 0.0
+1157 127.529 -0.00737316876919 0.0 0.0
+1158 127.639 -0.00726745327884 0.0 0.0
+1159 127.749 -0.00716540780477 0.0 0.0
+1160 127.859 -0.00706702083797 0.0 0.0
+1161 127.97 -0.00697227217856 0.0 0.0
+1162 128.08 -0.00688114467114 0.0 0.0
+1163 128.19 -0.00679361255014 0.0 0.0
+1164 128.3 -0.00670965315025 0.0 0.0
+1165 128.41 -0.00662923526708 0.0 0.0
+1166 128.521 -0.00655233086192 0.0 0.0
+1167 128.631 -0.0064789034599 0.0 0.0
+1168 128.741 -0.00640891978774 0.0 0.0
+1169 128.851 -0.00634233826461 0.0 0.0
+1170 128.962 -0.00627912056689 0.0 0.0
+1171 129.072 -0.00621922016326 0.0 0.0
+1172 129.182 -0.00616259388853 0.0 0.0
+1173 129.292 -0.00610919044508 0.0 0.0
+1174 129.402 -0.00605896200695 0.0 0.0
+1175 129.513 -0.00601185274266 0.0 0.0
+1176 129.623 -0.00596781036477 0.0 0.0
+1177 129.733 -0.0059267747148 0.0 0.0
+1178 129.843 -0.00588868927625 0.0 0.0
+1179 129.954 -0.0058534898023 0.0 0.0
+1180 130.064 -0.00582111576366 0.0 0.0
+1181 130.174 -0.00579149907299 0.0 0.0
+1182 130.284 -0.00576457544065 0.0 0.0
+1183 130.395 -0.00574027317569 0.0 0.0
+1184 130.505 -0.00571852449501 0.0 0.0
+1185 130.615 -0.00569925435717 0.0 0.0
+1186 130.725 -0.00568239174099 0.0 0.0
+1187 130.835 -0.00566785854264 0.0 0.0
+1188 130.946 -0.00565558077213 0.0 0.0
+1189 131.056 -0.00564547751227 0.0 0.0
+1190 131.166 -0.005637472119 0.0 0.0
+1191 131.276 -0.00563148113137 0.0 0.0
+1192 131.387 -0.00562742551721 0.0 0.0
+1193 131.497 -0.0056252196013 0.0 0.0
+1194 131.607 -0.00562478222796 0.0 0.0
+1195 131.717 -0.00562602579301 0.0 0.0
+1196 131.827 -0.00562886734167 0.0 0.0
+1197 131.938 -0.00563321762453 0.0 0.0
+1198 132.048 -0.00563899218408 0.0 0.0
+1199 132.158 -0.00564610043677 0.0 0.0
+1200 132.268 -0.00565445671676 0.0 0.0
+1201 132.379 -0.00566396941574 0.0 0.0
+1202 132.489 -0.00567455196751 0.0 0.0
+1203 132.599 -0.00568611203569 0.0 0.0
+1204 132.709 -0.00569856246567 0.0 0.0
+1205 132.819 -0.00571181049892 0.0 0.0
+1206 132.93 -0.00572576869735 0.0 0.0
+1207 133.04 -0.00574034419035 0.0 0.0
+1208 133.15 -0.00575544955011 0.0 0.0
+1209 133.26 -0.0057709921039 0.0 0.0
+1210 133.371 -0.00578688475095 0.0 0.0
+1211 133.481 -0.00580303529921 0.0 0.0
+1212 133.591 -0.00581935727687 0.0 0.0
+1213 133.701 -0.00583575928368 0.0 0.0
+1214 133.811 -0.00585215577097 0.0 0.0
+1215 133.922 -0.0058684564168 0.0 0.0
+1216 134.032 -0.00588457688605 0.0 0.0
+1217 134.142 -0.00590042823838 0.0 0.0
+1218 134.252 -0.00591592763177 0.0 0.0
+1219 134.363 -0.00593098778489 0.0 0.0
+1220 134.473 -0.00594552764065 0.0 0.0
+1221 134.583 -0.00595946184685 0.0 0.0
+1222 134.693 -0.00597271140173 0.0 0.0
+1223 134.803 -0.00598519315846 0.0 0.0
+1224 134.914 -0.00599683043518 0.0 0.0
+1225 135.024 -0.00600754254498 0.0 0.0
+1226 135.134 -0.00601725538651 0.0 0.0
+1227 135.244 -0.00602589098589 0.0 0.0
+1228 135.355 -0.0060333780665 0.0 0.0
+1229 135.465 -0.00603964161231 0.0 0.0
+1230 135.575 -0.00604461339774 0.0 0.0
+1231 135.685 -0.00604822161043 0.0 0.0
+1232 135.795 -0.00605040129556 0.0 0.0
+1233 135.906 -0.0060510840542 0.0 0.0
+1234 136.016 -0.006050208432 0.0 0.0
+1235 136.126 -0.00604770963818 0.0 0.0
+1236 136.236 -0.00604352992713 0.0 0.0
+1237 136.347 -0.00603760831368 0.0 0.0
+1238 136.457 -0.00602989093689 0.0 0.0
+1239 136.567 -0.00602032080845 0.0 0.0
+1240 136.677 -0.00600884813202 0.0 0.0
+1241 136.787 -0.00599542007322 0.0 0.0
+1242 136.898 -0.00597999106214 0.0 0.0
+1243 137.008 -0.0059625125798 0.0 0.0
+1244 137.118 -0.00594294342115 0.0 0.0
+1245 137.228 -0.00592123952788 0.0 0.0
+1246 137.339 -0.00589736418979 0.0 0.0
+1247 137.449 -0.00587127792404 0.0 0.0
+1248 137.559 -0.00584294864583 0.0 0.0
+1249 137.669 -0.00581234155162 0.0 0.0
+1250 137.779 -0.00577942927155 0.0 0.0
+1251 137.89 -0.00574418178906 0.0 0.0
+1252 138.0 -0.00570657653052 0.0 0.0
+1253 138.11 -0.0056665883345 0.0 0.0
+1254 138.22 -0.0056241994999 0.0 0.0
+1255 138.331 -0.00557938978338 0.0 0.0
+1256 138.441 -0.00553214639714 0.0 0.0
+1257 138.551 -0.00548245406969 0.0 0.0
+1258 138.661 -0.00543030496884 0.0 0.0
+1259 138.771 -0.00537568880392 0.0 0.0
+1260 138.882 -0.00531860272918 0.0 0.0
+1261 138.992 -0.0052590414493 0.0 0.0
+1262 139.102 -0.00519700710176 0.0 0.0
+1263 139.212 -0.005132499378 0.0 0.0
+1264 139.323 -0.0050655253962 0.0 0.0
+1265 139.433 -0.00499608980662 0.0 0.0
+1266 139.543 -0.00492420467052 0.0 0.0
+1267 139.653 -0.00484987957611 0.0 0.0
+1268 139.764 -0.00477313146917 0.0 0.0
+1269 139.874 -0.00469397482079 0.0 0.0
+1270 139.984 -0.00461243140515 0.0 0.0
+1271 140.094 -0.00452852050554 0.0 0.0
+1272 140.204 -0.00444226864177 0.0 0.0
+1273 140.315 -0.00435369982398 0.0 0.0
+1274 140.425 -0.0042628452321 0.0 0.0
+1275 140.535 -0.00416973349179 0.0 0.0
+1276 140.645 -0.00407440033721 0.0 0.0
+1277 140.756 -0.00397687889298 0.0 0.0
+1278 140.866 -0.00387720932702 0.0 0.0
+1279 140.976 -0.0037754291318 0.0 0.0
+1280 141.086 -0.00367158276108 0.0 0.0
+1281 141.196 -0.0035657119392 0.0 0.0
+1282 141.307 -0.00345786525578 0.0 0.0
+1283 141.417 -0.00334808850187 0.0 0.0
+1284 141.527 -0.00323643423313 0.0 0.0
+1285 141.637 -0.00312295214925 0.0 0.0
+1286 141.748 -0.00300769858157 0.0 0.0
+1287 141.858 -0.00289072695108 0.0 0.0
+1288 141.968 -0.00277209718852 0.0 0.0
+1289 142.078 -0.00265186622691 0.0 0.0
+1290 142.188 -0.00253009740004 0.0 0.0
+1291 142.299 -0.00240685093568 0.0 0.0
+1292 142.409 -0.00228219336747 0.0 0.0
+1293 142.519 -0.00215618799806 0.0 0.0
+1294 142.629 -0.00202890432956 0.0 0.0
+1295 142.74 -0.00190040851638 0.0 0.0
+1296 142.85 -0.00177077279247 0.0 0.0
+1297 142.96 -0.00164006593255 0.0 0.0
+1298 143.07 -0.00150836265217 0.0 0.0
+1299 143.18 -0.00137573410259 0.0 0.0
+1300 143.291 -0.00124225722825 0.0 0.0
+1301 143.401 -0.00110800531364 0.0 0.0
+1302 143.511 -0.000973057263159 0.0 0.0
+1303 143.621 -0.000837488228235 0.0 0.0
+1304 143.732 -0.000701378828736 0.0 0.0
+1305 143.842 -0.000564805804089 0.0 0.0
+1306 143.952 -0.000427851217921 0.0 0.0
+1307 144.062 -0.000290593127258 0.0 0.0
+1308 144.172 -0.000153114769187 0.0 0.0
+1309 144.283 -1.54952477207e-05 0.0 0.0
+1310 144.393 0.000122181320944 0.0 0.0
+1311 144.503 0.000259835057137 0.0 0.0
+1312 144.613 0.000397381239309 0.0 0.0
+1313 144.724 0.000534739502548 0.0 0.0
+1314 144.834 0.00067182480242 0.0 0.0
+1315 144.944 0.000808556570734 0.0 0.0
+1316 145.054 0.000944849714915 0.0 0.0
+1317 145.164 0.00108062376293 0.0 0.0
+1318 145.275 0.00121579385179 0.0 0.0
+1319 145.385 0.00135027988763 0.0 0.0
+1320 145.495 0.00148399752075 0.0 0.0
+1321 145.605 0.00161686731025 0.0 0.0
+1322 145.716 0.00174880571273 0.0 0.0
+1323 145.826 0.00187973422385 0.0 0.0
+1324 145.936 0.00200957037781 0.0 0.0
+1325 146.046 0.00213823687106 0.0 0.0
+1326 146.156 0.0022656526099 0.0 0.0
+1327 146.267 0.00239174176699 0.0 0.0
+1328 146.377 0.00251642487356 0.0 0.0
+1329 146.487 0.00263962785577 0.0 0.0
+1330 146.597 0.00276127314304 0.0 0.0
+1331 146.708 0.00288128866964 0.0 0.0
+1332 146.818 0.00299959901782 0.0 0.0
+1333 146.928 0.00311613439485 0.0 0.0
+1334 147.038 0.00323082178915 0.0 0.0
+1335 147.148 0.00334359392105 0.0 0.0
+1336 147.259 0.00345438043886 0.0 0.0
+1337 147.369 0.0035631168098 0.0 0.0
+1338 147.479 0.00366973558029 0.0 0.0
+1339 147.589 0.00377417520156 0.0 0.0
+1340 147.7 0.00387637133392 0.0 0.0
+1341 147.81 0.00397626564568 0.0 0.0
+1342 147.92 0.00407379712143 0.0 0.0
+1343 148.03 0.00416891085501 0.0 0.0
+1344 148.141 0.00426154937233 0.0 0.0
+1345 148.251 0.00435166138735 0.0 0.0
+1346 148.361 0.00443919315252 0.0 0.0
+1347 148.471 0.00452409720246 0.0 0.0
+1348 148.581 0.00460632369907 0.0 0.0
+1349 148.692 0.0046858291735 0.0 0.0
+1350 148.802 0.004762567852 0.0 0.0
+1351 148.912 0.0048365004374 0.0 0.0
+1352 149.022 0.00490758539222 0.0 0.0
+1353 149.133 0.00497578770584 0.0 0.0
+1354 149.243 0.0050410702521 0.0 0.0
+1355 149.353 0.00510340242962 0.0 0.0
+1356 149.463 0.00516275164056 0.0 0.0
+1357 149.573 0.00521909183612 0.0 0.0
+1358 149.684 0.00527239504716 0.0 0.0
+1359 149.794 0.0053226398946 0.0 0.0
+1360 149.904 0.00536980312343 0.0 0.0
+1361 150.014 0.00541386811741 0.0 0.0
+1362 150.125 0.00545481643468 0.0 0.0
+1363 150.235 0.00549263628763 0.0 0.0
+1364 150.345 0.0055273141076 0.0 0.0
+1365 150.455 0.00555884300697 0.0 0.0
+1366 150.565 0.00558721434465 0.0 0.0
+1367 150.676 0.00561242616754 0.0 0.0
+1368 150.786 0.00563447480031 0.0 0.0
+1369 150.896 0.00565336326019 0.0 0.0
+1370 151.006 0.00566909285471 0.0 0.0
+1371 151.117 0.00568167157861 0.0 0.0
+1372 151.227 0.00569110572191 0.0 0.0
+1373 151.337 0.00569740826713 0.0 0.0
+1374 151.447 0.00570059047495 0.0 0.0
+1375 151.557 0.00570067027336 0.0 0.0
+1376 151.668 0.00569766388298 0.0 0.0
+1377 151.778 0.00569159414233 0.0 0.0
+1378 151.888 0.00568248217328 0.0 0.0
+1379 151.998 0.00567035568083 0.0 0.0
+1380 152.109 0.00565524063579 0.0 0.0
+1381 152.219 0.00563716952429 0.0 0.0
+1382 152.329 0.00561617309399 0.0 0.0
+1383 152.439 0.00559228853416 0.0 0.0
+1384 152.549 0.00556555127085 0.0 0.0
+1385 152.66 0.00553600310731 0.0 0.0
+1386 152.77 0.0055036840179 0.0 0.0
+1387 152.88 0.00546864031909 0.0 0.0
+1388 152.99 0.00543091642443 0.0 0.0
+1389 153.101 0.0053905630098 0.0 0.0
+1390 153.211 0.00534762879015 0.0 0.0
+1391 153.321 0.00530216867336 0.0 0.0
+1392 153.431 0.00525423552656 0.0 0.0
+1393 153.541 0.00520388830599 0.0 0.0
+1394 153.652 0.00515118387816 0.0 0.0
+1395 153.762 0.00509618509193 0.0 0.0
+1396 153.872 0.00503895261007 0.0 0.0
+1397 153.982 0.0049795529926 0.0 0.0
+1398 154.093 0.00491805052549 0.0 0.0
+1399 154.203 0.00485451526291 0.0 0.0
+1400 154.313 0.00478901492101 0.0 0.0
+1401 154.423 0.00472162283046 0.0 0.0
+1402 154.533 0.00465240992229 0.0 0.0
+1403 154.644 0.0045814526004 0.0 0.0
+1404 154.754 0.004508824761 0.0 0.0
+1405 154.864 0.00443460566429 0.0 0.0
+1406 154.974 0.00435887193345 0.0 0.0
+1407 155.085 0.00428170543876 0.0 0.0
+1408 155.195 0.00420318529191 0.0 0.0
+1409 155.305 0.00412339571583 0.0 0.0
+1410 155.415 0.00404241806529 0.0 0.0
+1411 155.525 0.00396033865113 0.0 0.0
+1412 155.636 0.0038772408081 0.0 0.0
+1413 155.746 0.0037932126777 0.0 0.0
+1414 155.856 0.00370833929317 0.0 0.0
+1415 155.966 0.00362271036643 0.0 0.0
+1416 156.077 0.00353641234911 0.0 0.0
+1417 156.187 0.00344953624018 0.0 0.0
+1418 156.297 0.00336216963706 0.0 0.0
+1419 156.407 0.00327440453891 0.0 0.0
+1420 156.517 0.00318632941146 0.0 0.0
+1421 156.628 0.00309803694844 0.0 0.0
+1422 156.738 0.00300961621374 0.0 0.0
+1423 156.848 0.00292116030382 0.0 0.0
+1424 156.958 0.00283275857417 0.0 0.0
+1425 157.069 0.00274450424927 0.0 0.0
+1426 157.179 0.00265648667787 0.0 0.0
+1427 157.289 0.00256879891942 0.0 0.0
+1428 157.399 0.00248153001093 0.0 0.0
+1429 157.509 0.00239477256771 0.0 0.0
+1430 157.62 0.00230861502031 0.0 0.0
+1431 157.73 0.00222314923929 0.0 0.0
+1432 157.84 0.00213846276116 0.0 0.0
+1433 157.95 0.0020546464113 0.0 0.0
+1434 158.061 0.00197178655872 0.0 0.0
+1435 158.171 0.00188997268415 0.0 0.0
+1436 158.281 0.00180928969447 0.0 0.0
+1437 158.391 0.00172982545171 0.0 0.0
+1438 158.502 0.00165166311027 0.0 0.0
+1439 158.612 0.00157488863889 0.0 0.0
+1440 158.722 0.00149958315333 0.0 0.0
+1441 158.832 0.00142583045263 0.0 0.0
+1442 158.942 0.00135370934558 0.0 0.0
+1443 159.053 0.00128330118534 0.0 0.0
+1444 159.163 0.00121468221313 0.0 0.0
+1445 159.273 0.00114793106977 0.0 0.0
+1446 159.383 0.00108312116565 0.0 0.0
+1447 159.494 0.00102032817758 0.0 0.0
+1448 159.604 0.000959622438713 0.0 0.0
+1449 159.714 0.000901076401323 0.0 0.0
+1450 159.824 0.000844757090349 0.0 0.0
+1451 159.934 0.000790733496893 0.0 0.0
+1452 160.045 0.000739069090036 0.0 0.0
+1453 160.155 0.000689829195063 0.0 0.0
+1454 160.265 0.000643073478588 0.0 0.0
+1455 160.375 0.000598863400212 0.0 0.0
+1456 160.486 0.000557254618094 0.0 0.0
+1457 160.596 0.000518304494006 0.0 0.0
+1458 160.706 0.00048206450813 0.0 0.0
+1459 160.816 0.00044858771952 0.0 0.0
+1460 160.926 0.000417921239939 0.0 0.0
+1461 161.037 0.000390113649594 0.0 0.0
+1462 161.147 0.00036520752324 0.0 0.0
+1463 161.257 0.000343246792045 0.0 0.0
+1464 161.367 0.00032426932985 0.0 0.0
+1465 161.478 0.000308314276839 0.0 0.0
+1466 161.588 0.000295414650967 0.0 0.0
+1467 161.698 0.000285604667284 0.0 0.0
+1468 161.808 0.00027891236128 0.0 0.0
+1469 161.918 0.000275366895498 0.0 0.0
+1470 162.029 0.000274991207265 0.0 0.0
+1471 162.139 0.000277809300777 0.0 0.0
+1472 162.249 0.000283838923024 0.0 0.0
+1473 162.359 0.000293098818212 0.0 0.0
+1474 162.47 0.000305601457263 0.0 0.0
+1475 162.58 0.000321360260738 0.0 0.0
+1476 162.69 0.00034038235347 0.0 0.0
+1477 162.8 0.000362675763241 0.0 0.0
+1478 162.91 0.000388242225924 0.0 0.0
+1479 163.021 0.000417084342587 0.0 0.0
+1480 163.131 0.000449198408872 0.0 0.0
+1481 163.241 0.000484581581964 0.0 0.0
+1482 163.351 0.000523224705721 0.0 0.0
+1483 163.462 0.000565119474994 0.0 0.0
+1484 163.572 0.000610251283617 0.0 0.0
+1485 163.682 0.000658606385599 0.0 0.0
+1486 163.792 0.000710164728012 0.0 0.0
+1487 163.902 0.000764907139531 0.0 0.0
+1488 164.013 0.00082280818183 0.0 0.0
+1489 164.123 0.000883843285351 0.0 0.0
+1490 164.233 0.000947981669763 0.0 0.0
+1491 164.343 0.00101519344389 0.0 0.0
+1492 164.454 0.00108544254068 0.0 0.0
+1493 164.564 0.00115869382624 0.0 0.0
+1494 164.674 0.00123490602947 0.0 0.0
+1495 164.784 0.00131403886877 0.0 0.0
+1496 164.894 0.00139604597663 0.0 0.0
+1497 165.005 0.0014808820191 0.0 0.0
+1498 165.115 0.00156849565778 0.0 0.0
+1499 165.225 0.00165883662319 0.0 0.0
+1500 165.335 0.00175184874571 0.0 0.0
+1501 165.446 0.00184747696706 0.0 0.0
+1502 165.556 0.00194566041902 0.0 0.0
+1503 165.666 0.00204633942207 0.0 0.0
+1504 165.776 0.00214944856865 0.0 0.0
+1505 165.887 0.00225492371815 0.0 0.0
+1506 165.997 0.00236269512214 0.0 0.0
+1507 166.107 0.00247269435626 0.0 0.0
+1508 166.217 0.002584847508 0.0 0.0
+1509 166.327 0.00269908208712 0.0 0.0
+1510 166.438 0.0028153202146 0.0 0.0
+1511 166.548 0.00293348554019 0.0 0.0
+1512 166.658 0.00305349644942 0.0 0.0
+1513 166.768 0.00317527294861 0.0 0.0
+1514 166.879 0.00329872991443 0.0 0.0
+1515 166.989 0.00342378395356 0.0 0.0
+1516 167.099 0.00355034667289 0.0 0.0
+1517 167.209 0.00367833152957 0.0 0.0
+1518 167.319 0.00380764710759 0.0 0.0
+1519 167.43 0.00393820397216 0.0 0.0
+1520 167.54 0.0040699079538 0.0 0.0
+1521 167.65 0.00420266699365 0.0 0.0
+1522 167.76 0.00433638443661 0.0 0.0
+1523 167.871 0.00447096587253 0.0 0.0
+1524 167.981 0.00460631245033 0.0 0.0
+1525 168.091 0.00474232768849 0.0 0.0
+1526 168.201 0.00487891082451 0.0 0.0
+1527 168.311 0.00501596360378 0.0 0.0
+1528 168.422 0.00515338365011 0.0 0.0
+1529 168.532 0.00529107122774 0.0 0.0
+1530 168.642 0.00542892263794 0.0 0.0
+1531 168.752 0.00556683698828 0.0 0.0
+1532 168.863 0.00570470955739 0.0 0.0
+1533 168.973 0.00584243858896 0.0 0.0
+1534 169.083 0.00597991866761 0.0 0.0
+1535 169.193 0.006117047478 0.0 0.0
+1536 169.303 0.00625371921883 0.0 0.0
+1537 169.414 0.00638983133729 0.0 0.0
+1538 169.524 0.00652527796127 0.0 0.0
+1539 169.634 0.0066599566084 0.0 0.0
+1540 169.744 0.00679376166247 0.0 0.0
+1541 169.855 0.00692659102156 0.0 0.0
+1542 169.965 0.00705833963771 0.0 0.0
+1543 170.075 0.0071889061278 0.0 0.0
+1544 170.185 0.00731818629577 0.0 0.0
+1545 170.295 0.00744607981093 0.0 0.0
+1546 170.406 0.00757248365842 0.0 0.0
+1547 170.516 0.00769729883378 0.0 0.0
+1548 170.626 0.00782042384318 0.0 0.0
+1549 170.736 0.00794176132187 0.0 0.0
+1550 170.847 0.00806121158377 0.0 0.0
+1551 170.957 0.0081786792248 0.0 0.0
+1552 171.067 0.00829406666608 0.0 0.0
+1553 171.177 0.00840728076099 0.0 0.0
+1554 171.287 0.00851822634084 0.0 0.0
+1555 171.398 0.0086268128131 0.0 0.0
+1556 171.508 0.00873294770053 0.0 0.0
+1557 171.618 0.00883654326191 0.0 0.0
+1558 171.728 0.00893750999536 0.0 0.0
+1559 171.839 0.009035763273 0.0 0.0
+1560 171.949 0.0091312168763 0.0 0.0
+1561 172.059 0.0092237895382 0.0 0.0
+1562 172.169 0.00931339858836 0.0 0.0
+1563 172.279 0.00939996640098 0.0 0.0
+1564 172.39 0.00948341408908 0.0 0.0
+1565 172.5 0.0095636679391 0.0 0.0
+1566 172.61 0.00964065308063 0.0 0.0
+1567 172.72 0.00971429995267 0.0 0.0
+1568 172.831 0.00978453794051 0.0 0.0
+1569 172.941 0.00985130186694 0.0 0.0
+1570 173.051 0.00991452559018 0.0 0.0
+1571 173.161 0.0099741485216 0.0 0.0
+1572 173.271 0.0100301092297 0.0 0.0
+1573 173.382 0.010082351895 0.0 0.0
+1574 173.492 0.010130819988 0.0 0.0
+1575 173.602 0.0101754626676 0.0 0.0
+1576 173.712 0.0102162284673 0.0 0.0
+1577 173.823 0.0102530717116 0.0 0.0
+1578 173.933 0.010285946165 0.0 0.0
+1579 174.043 0.0103148114562 0.0 0.0
+1580 174.153 0.0103396267542 0.0 0.0
+1581 174.263 0.0103603571321 0.0 0.0
+1582 174.374 0.010376967284 0.0 0.0
+1583 174.484 0.0103894278658 0.0 0.0
+1584 174.594 0.0103977092193 0.0 0.0
+1585 174.704 0.0104017876843 0.0 0.0
+1586 174.815 0.0104016393582 0.0 0.0
+1587 174.925 0.0103972463587 0.0 0.0
+1588 175.035 0.0103885906151 0.0 0.0
+1589 175.145 0.0103756601175 0.0 0.0
+1590 175.255 0.0103584426813 0.0 0.0
+1591 175.366 0.0103369322222 0.0 0.0
+1592 175.476 0.0103111225123 0.0 0.0
+1593 175.586 0.0102810134215 0.0 0.0
+1594 175.696 0.0102466047061 0.0 0.0
+1595 175.807 0.0102079022274 0.0 0.0
+1596 175.917 0.0101649117333 0.0 0.0
+1597 176.027 0.0101176450795 0.0 0.0
+1598 176.137 0.0100661140038 0.0 0.0
+1599 176.248 0.0100103363484 0.0 0.0
+1600 176.358 0.00995032982262 0.0 0.0
+1601 176.468 0.00988611820575 0.0 0.0
+1602 176.578 0.00981772516541 0.0 0.0
+1603 176.688 0.00974518035356 0.0 0.0
+1604 176.799 0.00966851333004 0.0 0.0
+1605 176.909 0.00958775958344 0.0 0.0
+1606 177.019 0.009502954469 0.0 0.0
+1607 177.129 0.00941413922464 0.0 0.0
+1608 177.24 0.00932135492096 0.0 0.0
+1609 177.35 0.00922464844058 0.0 0.0
+1610 177.46 0.00912406645548 0.0 0.0
+1611 177.57 0.00901966138438 0.0 0.0
+1612 177.68 0.00891148536075 0.0 0.0
+1613 177.791 0.00879959620846 0.0 0.0
+1614 177.901 0.00868405138877 0.0 0.0
+1615 178.011 0.00856491396824 0.0 0.0
+1616 178.121 0.00844224657695 0.0 0.0
+1617 178.232 0.00831611736563 0.0 0.0
+1618 178.342 0.00818659394345 0.0 0.0
+1619 178.452 0.00805374937365 0.0 0.0
+1620 178.562 0.00791765605469 0.0 0.0
+1621 178.672 0.00777839174634 0.0 0.0
+1622 178.783 0.00763603345824 0.0 0.0
+1623 178.893 0.00749066341367 0.0 0.0
+1624 179.003 0.0073423630142 0.0 0.0
+1625 179.113 0.00719121873819 0.0 0.0
+1626 179.224 0.00703731612264 0.0 0.0
+1627 179.334 0.00688074567207 0.0 0.0
+1628 179.444 0.00672159682296 0.0 0.0
+1629 179.554 0.00655996383411 0.0 0.0
+1630 179.664 0.00639593979783 0.0 0.0
+1631 179.775 0.00622962246057 0.0 0.0
+1632 179.885 0.00606110829041 0.0 0.0
+1633 179.995 0.00589049826462 0.0 0.0
+1634 180.105 0.00571789193489 0.0 0.0
+1635 180.216 0.00554339322319 0.0 0.0
+1636 180.326 0.00536710448646 0.0 0.0
+1637 180.436 0.00518913228656 0.0 0.0
+1638 180.546 0.00500958148919 0.0 0.0
+1639 180.656 0.00482856099465 0.0 0.0
+1640 180.767 0.00464617787177 0.0 0.0
+1641 180.877 0.00446254305044 0.0 0.0
+1642 180.987 0.00427776548541 0.0 0.0
+1643 181.097 0.00409195782074 0.0 0.0
+1644 181.208 0.00390523057647 0.0 0.0
+1645 181.318 0.00371769779263 0.0 0.0
+1646 181.428 0.00352947122111 0.0 0.0
+1647 181.538 0.00334066598113 0.0 0.0
+1648 181.648 0.00315139472516 0.0 0.0
+1649 181.759 0.00296177331125 0.0 0.0
+1650 181.869 0.00277191497042 0.0 0.0
+1651 181.979 0.00258193596348 0.0 0.0
+1652 182.089 0.00239194976621 0.0 0.0
+1653 182.2 0.00220207270438 0.0 0.0
+1654 182.31 0.00201241816136 0.0 0.0
+1655 182.42 0.00182310219929 0.0 0.0
+1656 182.53 0.00163423776846 0.0 0.0
+1657 182.64 0.00144594033108 0.0 0.0
+1658 182.751 0.00125832206964 0.0 0.0
+1659 182.861 0.00107149751612 0.0 0.0
+1660 182.971 0.000885577752022 0.0 0.0
+1661 183.081 0.000700676034819 0.0 0.0
+1662 183.192 0.00051690202946 0.0 0.0
+1663 183.302 0.000334367393278 0.0 0.0
+1664 183.412 0.000153180027741 0.0 0.0
+1665 183.522 -2.65503182957e-05 0.0 0.0
+1666 183.632 -0.00020471781948 0.0 0.0
+1667 183.743 -0.000381214979853 0.0 0.0
+1668 183.853 -0.00055593835335 0.0 0.0
+1669 183.963 -0.000728782994931 0.0 0.0
+1670 184.073 -0.000899648172198 0.0 0.0
+1671 184.184 -0.00106843178063 0.0 0.0
+1672 184.294 -0.00123503610179 0.0 0.0
+1673 184.404 -0.00139936218003 0.0 0.0
+1674 184.514 -0.00156131558873 0.0 0.0
+1675 184.624 -0.00172080082179 0.0 0.0
+1676 184.735 -0.00187772702617 0.0 0.0
+1677 184.845 -0.00203200240876 0.0 0.0
+1678 184.955 -0.00218353997596 0.0 0.0
+1679 185.065 -0.00233225192238 0.0 0.0
+1680 185.176 -0.00247805535232 0.0 0.0
+1681 185.286 -0.00262086671707 0.0 0.0
+1682 185.396 -0.00276060747505 0.0 0.0
+1683 185.506 -0.00289719855939 0.0 0.0
+1684 185.617 -0.00303056603067 0.0 0.0
+1685 185.727 -0.00316063554007 0.0 0.0
+1686 185.837 -0.00328733795303 0.0 0.0
+1687 185.947 -0.00341060386575 0.0 0.0
+1688 186.057 -0.00353036916555 0.0 0.0
+1689 186.168 -0.00364656958385 0.0 0.0
+1690 186.278 -0.00375914622327 0.0 0.0
+1691 186.388 -0.00386804013768 0.0 0.0
+1692 186.498 -0.00397319783179 0.0 0.0
+1693 186.609 -0.00407456583576 0.0 0.0
+1694 186.719 -0.00417209623235 0.0 0.0
+1695 186.829 -0.00426574118416 0.0 0.0
+1696 186.939 -0.00435545847742 0.0 0.0
+1697 187.049 -0.00444120606141 0.0 0.0
+1698 187.16 -0.0045229475557 0.0 0.0
+1699 187.27 -0.00460064680311 0.0 0.0
+1700 187.38 -0.00467427337798 0.0 0.0
+1701 187.49 -0.00474379711522 0.0 0.0
+1702 187.601 -0.0048091936318 0.0 0.0
+1703 187.711 -0.00487043885526 0.0 0.0
+1704 187.821 -0.00492751450075 0.0 0.0
+1705 187.931 -0.00498040265961 0.0 0.0
+1706 188.041 -0.00502909121481 0.0 0.0
+1707 188.152 -0.00507356845278 0.0 0.0
+1708 188.262 -0.00511382846816 0.0 0.0
+1709 188.372 -0.00514986577093 0.0 0.0
+1710 188.482 -0.00518168068931 0.0 0.0
+1711 188.593 -0.00520927397003 0.0 0.0
+1712 188.703 -0.00523265216021 0.0 0.0
+1713 188.813 -0.00525182224189 0.0 0.0
+1714 188.923 -0.00526679697862 0.0 0.0
+1715 189.033 -0.00527758954438 0.0 0.0
+1716 189.144 -0.00528421887185 0.0 0.0
+1717 189.254 -0.0052867043052 0.0 0.0
+1718 189.364 -0.00528507087748 0.0 0.0
+1719 189.474 -0.00527934403002 0.0 0.0
+1720 189.585 -0.00526955484379 0.0 0.0
+1721 189.695 -0.00525573475371 0.0 0.0
+1722 189.805 -0.0052379208011 0.0 0.0
+1723 189.915 -0.0052161503236 0.0 0.0
+1724 190.025 -0.00519046619322 0.0 0.0
+1725 190.136 -0.00516091154717 0.0 0.0
+1726 190.246 -0.00512753495549 0.0 0.0
+1727 190.356 -0.00509038520818 0.0 0.0
+1728 190.466 -0.00504951644435 0.0 0.0
+1729 190.577 -0.00500498293299 0.0 0.0
+1730 190.687 -0.00495684423384 0.0 0.0
+1731 190.797 -0.00490515992407 0.0 0.0
+1732 190.907 -0.00484999479166 0.0 0.0
+1733 191.017 -0.00479141354485 0.0 0.0
+1734 191.128 -0.00472948600602 0.0 0.0
+1735 191.238 -0.00466428180205 0.0 0.0
+1736 191.348 -0.00459587558125 0.0 0.0
+1737 191.458 -0.00452434169009 0.0 0.0
+1738 191.569 -0.00444975934612 0.0 0.0
+1739 191.679 -0.00437220738994 0.0 0.0
+1740 191.789 -0.00429176939718 0.0 0.0
+1741 191.899 -0.00420852842764 0.0 0.0
+1742 192.009 -0.00412257215751 0.0 0.0
+1743 192.12 -0.00403398762754 0.0 0.0
+1744 192.23 -0.00394286633992 0.0 0.0
+1745 192.34 -0.0038492990389 0.0 0.0
+1746 192.45 -0.00375338078275 0.0 0.0
+1747 192.561 -0.00365520572777 0.0 0.0
+1748 192.671 -0.00355487220662 0.0 0.0
+1749 192.781 -0.00345247749283 0.0 0.0
+1750 192.891 -0.003348122891 0.0 0.0
+1751 193.001 -0.00324190849217 0.0 0.0
+1752 193.112 -0.00313393825815 0.0 0.0
+1753 193.222 -0.00302431478955 0.0 0.0
+1754 193.332 -0.00291314439185 0.0 0.0
+1755 193.442 -0.00280053185007 0.0 0.0
+1756 193.553 -0.00268658548779 0.0 0.0
+1757 193.663 -0.00257141195355 0.0 0.0
+1758 193.773 -0.00245512124747 0.0 0.0
+1759 193.883 -0.0023378215649 0.0 0.0
+1760 193.994 -0.00221962423271 0.0 0.0
+1761 194.104 -0.00210063864814 0.0 0.0
+1762 194.214 -0.00198097715403 0.0 0.0
+1763 194.324 -0.0018607499796 0.0 0.0
+1764 194.434 -0.00174007014456 0.0 0.0
+1765 194.545 -0.00161904837199 0.0 0.0
+1766 194.655 -0.00149779801325 0.0 0.0
+1767 194.765 -0.00137642992668 0.0 0.0
+1768 194.875 -0.00125505745771 0.0 0.0
+1769 194.986 -0.0011337912618 0.0 0.0
+1770 195.096 -0.00101274429948 0.0 0.0
+1771 195.206 -0.000892026702755 0.0 0.0
+1772 195.316 -0.000771750696202 0.0 0.0
+1773 195.426 -0.000652025532422 0.0 0.0
+1774 195.537 -0.00053296236928 0.0 0.0
+1775 195.647 -0.000414669213538 0.0 0.0
+1776 195.757 -0.000297255839069 0.0 0.0
+1777 195.867 -0.000180828661746 0.0 0.0
+1778 195.978 -6.549570695e-05 0.0 0.0
+1779 196.088 4.86385056733e-05 0.0 0.0
+1780 196.198 0.000161468039502 0.0 0.0
+1781 196.308 0.000272890609016 0.0 0.0
+1782 196.418 0.00038280269353 0.0 0.0
+1783 196.529 0.000491104557615 0.0 0.0
+1784 196.639 0.000597695423246 0.0 0.0
+1785 196.749 0.000702478425152 0.0 0.0
+1786 196.859 0.000805355825805 0.0 0.0
+1787 196.97 0.000906233954052 0.0 0.0
+1788 197.08 0.00100501840857 0.0 0.0
+1789 197.19 0.00110161900949 0.0 0.0
+1790 197.3 0.00119594499232 0.0 0.0
+1791 197.41 0.00128790995059 0.0 0.0
+1792 197.521 0.00137742704076 0.0 0.0
+1793 197.631 0.00146441390754 0.0 0.0
+1794 197.741 0.00154878789955 0.0 0.0
+1795 197.851 0.00163047097629 0.0 0.0
+1796 197.962 0.00170938493995 0.0 0.0
+1797 198.072 0.00178545631787 0.0 0.0
+1798 198.182 0.00185861160064 0.0 0.0
+1799 198.292 0.00192878213639 0.0 0.0
+1800 198.402 0.00199589932924 0.0 0.0
+1801 198.513 0.0020598995663 0.0 0.0
+1802 198.623 0.00212071939046 0.0 0.0
+1803 198.733 0.00217830043254 0.0 0.0
+1804 198.843 0.00223258457828 0.0 0.0
+1805 198.954 0.00228351888438 0.0 0.0
+1806 199.064 0.00233105077894 0.0 0.0
+1807 199.174 0.0023751329214 0.0 0.0
+1808 199.284 0.00241571843154 0.0 0.0
+1809 199.394 0.00245276574401 0.0 0.0
+1810 199.505 0.00248623383032 0.0 0.0
+1811 199.615 0.00251608702735 0.0 0.0
+1812 199.725 0.00254229029531 0.0 0.0
+1813 199.835 0.00256481400386 0.0 0.0
+1814 199.946 0.00258362920436 0.0 0.0
diff --git a/test/corfunc/test/gamma3_out.txt b/test/corfunc/test/gamma3_out.txt
new file mode 100644
index 0000000..3308cd9
--- /dev/null
+++ b/test/corfunc/test/gamma3_out.txt
@@ -0,0 +1,1816 @@
+# <index> <X> <Y> <dY> <dX>
+0 0.0 1.0 0.0 0.0
+1 0.110224 0.995362958027 0.0 0.0
+2 0.220447 0.989962263764 0.0 0.0
+3 0.330671 0.984149640373 0.0 0.0
+4 0.440894 0.978284971318 0.0 0.0
+5 0.551118 0.972399652907 0.0 0.0
+6 0.661341 0.966516450011 0.0 0.0
+7 0.771565 0.9606401499 0.0 0.0
+8 0.881789 0.954775644445 0.0 0.0
+9 0.992012 0.948924335939 0.0 0.0
+10 1.10224 0.943087886673 0.0 0.0
+11 1.21246 0.937266872164 0.0 0.0
+12 1.32268 0.931462040967 0.0 0.0
+13 1.43291 0.92567367568 0.0 0.0
+14 1.54313 0.919902180421 0.0 0.0
+15 1.65335 0.914147727269 0.0 0.0
+16 1.76358 0.908410547811 0.0 0.0
+17 1.8738 0.902690771732 0.0 0.0
+18 1.98402 0.89698857094 0.0 0.0
+19 2.09425 0.891304014569 0.0 0.0
+20 2.20447 0.885637239871 0.0 0.0
+21 2.3147 0.87998830588 0.0 0.0
+22 2.42492 0.874357331114 0.0 0.0
+23 2.53514 0.868744381612 0.0 0.0
+24 2.64537 0.863149500927 0.0 0.0
+25 2.75559 0.857572787016 0.0 0.0
+26 2.86581 0.852014285715 0.0 0.0
+27 2.97604 0.846474078306 0.0 0.0
+28 3.08626 0.840952216279 0.0 0.0
+29 3.19648 0.835448754502 0.0 0.0
+30 3.30671 0.829963753007 0.0 0.0
+31 3.41693 0.824497265145 0.0 0.0
+32 3.52715 0.819049336916 0.0 0.0
+33 3.63738 0.813620044296 0.0 0.0
+34 3.7476 0.808209419461 0.0 0.0
+35 3.85783 0.802817537724 0.0 0.0
+36 3.96805 0.797444452915 0.0 0.0
+37 4.07827 0.792090193517 0.0 0.0
+38 4.1885 0.78675481413 0.0 0.0
+39 4.29872 0.781438378244 0.0 0.0
+40 4.40894 0.776140961614 0.0 0.0
+41 4.51917 0.770862592378 0.0 0.0
+42 4.62939 0.765603279379 0.0 0.0
+43 4.73961 0.760363165402 0.0 0.0
+44 4.84984 0.755142234904 0.0 0.0
+45 4.96006 0.749940563022 0.0 0.0
+46 5.07028 0.74475824664 0.0 0.0
+47 5.18051 0.739595226374 0.0 0.0
+48 5.29073 0.734451667489 0.0 0.0
+49 5.40096 0.729327533202 0.0 0.0
+50 5.51118 0.724222986821 0.0 0.0
+51 5.6214 0.719137948204 0.0 0.0
+52 5.73163 0.714072580847 0.0 0.0
+53 5.84185 0.709026892311 0.0 0.0
+54 5.95207 0.704000914211 0.0 0.0
+55 6.0623 0.698994721168 0.0 0.0
+56 6.17252 0.694008387161 0.0 0.0
+57 6.28274 0.689041921367 0.0 0.0
+58 6.39297 0.684095419396 0.0 0.0
+59 6.50319 0.679168890613 0.0 0.0
+60 6.61341 0.674262430038 0.0 0.0
+61 6.72364 0.669376026351 0.0 0.0
+62 6.83386 0.664509836869 0.0 0.0
+63 6.94409 0.659663786879 0.0 0.0
+64 7.05431 0.654838033276 0.0 0.0
+65 7.16453 0.650032584652 0.0 0.0
+66 7.27476 0.645247471794 0.0 0.0
+67 7.38498 0.640482766462 0.0 0.0
+68 7.4952 0.635738519205 0.0 0.0
+69 7.60543 0.631014800191 0.0 0.0
+70 7.71565 0.626311618425 0.0 0.0
+71 7.82587 0.621629043953 0.0 0.0
+72 7.9361 0.616967165622 0.0 0.0
+73 8.04632 0.612325931469 0.0 0.0
+74 8.15654 0.607705510159 0.0 0.0
+75 8.26677 0.603105809696 0.0 0.0
+76 8.37699 0.598527036452 0.0 0.0
+77 8.48722 0.593969117406 0.0 0.0
+78 8.59744 0.589432138784 0.0 0.0
+79 8.70766 0.584916184542 0.0 0.0
+80 8.81789 0.58042122143 0.0 0.0
+81 8.92811 0.57594733315 0.0 0.0
+82 9.03833 0.571494601317 0.0 0.0
+83 9.14856 0.567062953788 0.0 0.0
+84 9.25878 0.56265254837 0.0 0.0
+85 9.369 0.558263462616 0.0 0.0
+86 9.47923 0.553895547921 0.0 0.0
+87 9.58945 0.54954899644 0.0 0.0
+88 9.69968 0.545223808918 0.0 0.0
+89 9.8099 0.540920060233 0.0 0.0
+90 9.92012 0.536637676535 0.0 0.0
+91 10.0303 0.532376805849 0.0 0.0
+92 10.1406 0.52813751868 0.0 0.0
+93 10.2508 0.523919702736 0.0 0.0
+94 10.361 0.519723429735 0.0 0.0
+95 10.4712 0.515548804688 0.0 0.0
+96 10.5815 0.511395857893 0.0 0.0
+97 10.6917 0.507264547833 0.0 0.0
+98 10.8019 0.503154904928 0.0 0.0
+99 10.9121 0.499067098458 0.0 0.0
+100 11.0224 0.495000978128 0.0 0.0
+101 11.1326 0.490956641283 0.0 0.0
+102 11.2428 0.486934078221 0.0 0.0
+103 11.353 0.482933416344 0.0 0.0
+104 11.4633 0.478954573637 0.0 0.0
+105 11.5735 0.474997640048 0.0 0.0
+106 11.6837 0.471062566975 0.0 0.0
+107 11.7939 0.467149407536 0.0 0.0
+108 11.9041 0.463258179018 0.0 0.0
+109 12.0144 0.459388930531 0.0 0.0
+110 12.1246 0.455541576782 0.0 0.0
+111 12.2348 0.451716264176 0.0 0.0
+112 12.345 0.447912904843 0.0 0.0
+113 12.4553 0.444131575104 0.0 0.0
+114 12.5655 0.440372186404 0.0 0.0
+115 12.6757 0.436634844461 0.0 0.0
+116 12.7859 0.432919554576 0.0 0.0
+117 12.8962 0.42922628892 0.0 0.0
+118 13.0064 0.425554987844 0.0 0.0
+119 13.1166 0.421905748914 0.0 0.0
+120 13.2268 0.418278571553 0.0 0.0
+121 13.3371 0.414673391809 0.0 0.0
+122 13.4473 0.41109020788 0.0 0.0
+123 13.5575 0.407529138628 0.0 0.0
+124 13.6677 0.403990023776 0.0 0.0
+125 13.7779 0.400472918087 0.0 0.0
+126 13.8882 0.396977782641 0.0 0.0
+127 13.9984 0.393504697206 0.0 0.0
+128 14.1086 0.390053559118 0.0 0.0
+129 14.2188 0.386624355519 0.0 0.0
+130 14.3291 0.383217188951 0.0 0.0
+131 14.4393 0.379831894679 0.0 0.0
+132 14.5495 0.376468513585 0.0 0.0
+133 14.6597 0.3731269968 0.0 0.0
+134 14.77 0.369807408852 0.0 0.0
+135 14.8802 0.366509639726 0.0 0.0
+136 14.9904 0.363233693283 0.0 0.0
+137 15.1006 0.359979570736 0.0 0.0
+138 15.2109 0.356747187406 0.0 0.0
+139 15.3211 0.353536541618 0.0 0.0
+140 15.4313 0.350347601692 0.0 0.0
+141 15.5415 0.347180334281 0.0 0.0
+142 15.6517 0.344034704394 0.0 0.0
+143 15.762 0.340910702214 0.0 0.0
+144 15.8722 0.33780826204 0.0 0.0
+145 15.9824 0.334727290973 0.0 0.0
+146 16.0926 0.331667827744 0.0 0.0
+147 16.2029 0.328629802245 0.0 0.0
+148 16.3131 0.325613221421 0.0 0.0
+149 16.4233 0.322617882843 0.0 0.0
+150 16.5335 0.319643894537 0.0 0.0
+151 16.6438 0.316691205257 0.0 0.0
+152 16.754 0.313759661379 0.0 0.0
+153 16.8642 0.310849261271 0.0 0.0
+154 16.9744 0.307959950257 0.0 0.0
+155 17.0847 0.305091672052 0.0 0.0
+156 17.1949 0.302244368776 0.0 0.0
+157 17.3051 0.299417980959 0.0 0.0
+158 17.4153 0.296612495796 0.0 0.0
+159 17.5255 0.293827753579 0.0 0.0
+160 17.6358 0.291063738994 0.0 0.0
+161 17.746 0.288320386316 0.0 0.0
+162 17.8562 0.28559762829 0.0 0.0
+163 17.9664 0.282895396133 0.0 0.0
+164 18.0767 0.280213665683 0.0 0.0
+165 18.1869 0.277552226569 0.0 0.0
+166 18.2971 0.274911144317 0.0 0.0
+167 18.4073 0.272290297853 0.0 0.0
+168 18.5176 0.26968961099 0.0 0.0
+169 18.6278 0.2671090061 0.0 0.0
+170 18.738 0.264548492236 0.0 0.0
+171 18.8482 0.262007768011 0.0 0.0
+172 18.9585 0.259486928656 0.0 0.0
+173 19.0687 0.256985846738 0.0 0.0
+174 19.1789 0.254504437699 0.0 0.0
+175 19.2891 0.25204257329 0.0 0.0
+176 19.3994 0.249600293526 0.0 0.0
+177 19.5096 0.24717742423 0.0 0.0
+178 19.6198 0.244773834291 0.0 0.0
+179 19.73 0.242389474845 0.0 0.0
+180 19.8402 0.240024212935 0.0 0.0
+181 19.9505 0.237678077317 0.0 0.0
+182 20.0607 0.235350810936 0.0 0.0
+183 20.1709 0.233042439325 0.0 0.0
+184 20.2811 0.230752903834 0.0 0.0
+185 20.3914 0.228481908813 0.0 0.0
+186 20.5016 0.226229552104 0.0 0.0
+187 20.6118 0.223995577533 0.0 0.0
+188 20.722 0.22178000028 0.0 0.0
+189 20.8323 0.219582679137 0.0 0.0
+190 20.9425 0.217403510761 0.0 0.0
+191 21.0527 0.215242428031 0.0 0.0
+192 21.1629 0.213099250886 0.0 0.0
+193 21.2732 0.210973910719 0.0 0.0
+194 21.3834 0.20886630043 0.0 0.0
+195 21.4936 0.206776312045 0.0 0.0
+196 21.6038 0.204703801062 0.0 0.0
+197 21.714 0.202648764937 0.0 0.0
+198 21.8243 0.20061102115 0.0 0.0
+199 21.9345 0.198590388927 0.0 0.0
+200 22.0447 0.196586896183 0.0 0.0
+201 22.1549 0.194600291572 0.0 0.0
+202 22.2652 0.192630599257 0.0 0.0
+203 22.3754 0.190677602517 0.0 0.0
+204 22.4856 0.188741187624 0.0 0.0
+205 22.5958 0.186821372472 0.0 0.0
+206 22.7061 0.184917841914 0.0 0.0
+207 22.8163 0.183030612232 0.0 0.0
+208 22.9265 0.181159533449 0.0 0.0
+209 23.0367 0.179304488194 0.0 0.0
+210 23.147 0.177465390314 0.0 0.0
+211 23.2572 0.175642026495 0.0 0.0
+212 23.3674 0.173834404281 0.0 0.0
+213 23.4776 0.17204231037 0.0 0.0
+214 23.5878 0.1702656568 0.0 0.0
+215 23.6981 0.168504293525 0.0 0.0
+216 23.8083 0.166758191578 0.0 0.0
+217 23.9185 0.165027139648 0.0 0.0
+218 24.0287 0.16331107716 0.0 0.0
+219 24.139 0.161609824025 0.0 0.0
+220 24.2492 0.159923260153 0.0 0.0
+221 24.3594 0.158251351687 0.0 0.0
+222 24.4696 0.156593890312 0.0 0.0
+223 24.5799 0.15495075555 0.0 0.0
+224 24.6901 0.153321911034 0.0 0.0
+225 24.8003 0.151707150501 0.0 0.0
+226 24.9105 0.150106408504 0.0 0.0
+227 25.0208 0.148519480991 0.0 0.0
+228 25.131 0.146946329435 0.0 0.0
+229 25.2412 0.145386831928 0.0 0.0
+230 25.3514 0.143840786775 0.0 0.0
+231 25.4616 0.142308153621 0.0 0.0
+232 25.5719 0.140788810972 0.0 0.0
+233 25.6821 0.139282585626 0.0 0.0
+234 25.7923 0.137789409306 0.0 0.0
+235 25.9025 0.136309084653 0.0 0.0
+236 26.0128 0.134841568933 0.0 0.0
+237 26.123 0.133386716794 0.0 0.0
+238 26.2332 0.131944408922 0.0 0.0
+239 26.3434 0.130514526342 0.0 0.0
+240 26.4537 0.129096974871 0.0 0.0
+241 26.5639 0.127691587223 0.0 0.0
+242 26.6741 0.12629827022 0.0 0.0
+243 26.7843 0.124916906484 0.0 0.0
+244 26.8946 0.123547355497 0.0 0.0
+245 27.0048 0.122189571618 0.0 0.0
+246 27.115 0.120843391336 0.0 0.0
+247 27.2252 0.11950865325 0.0 0.0
+248 27.3354 0.118185334901 0.0 0.0
+249 27.4457 0.116873230413 0.0 0.0
+250 27.5559 0.115572316926 0.0 0.0
+251 27.6661 0.114282391327 0.0 0.0
+252 27.7763 0.113003408429 0.0 0.0
+253 27.8866 0.11173527777 0.0 0.0
+254 27.9968 0.110477778807 0.0 0.0
+255 28.107 0.109230888727 0.0 0.0
+256 28.2172 0.107994476005 0.0 0.0
+257 28.3275 0.106768431698 0.0 0.0
+258 28.4377 0.105552626662 0.0 0.0
+259 28.5479 0.104347016336 0.0 0.0
+260 28.6581 0.103151451859 0.0 0.0
+261 28.7684 0.101965806978 0.0 0.0
+262 28.8786 0.100789997467 0.0 0.0
+263 28.9888 0.0996238990675 0.0 0.0
+264 29.099 0.0984674687703 0.0 0.0
+265 29.2093 0.0973205240978 0.0 0.0
+266 29.3195 0.096183023288 0.0 0.0
+267 29.4297 0.0950548846759 0.0 0.0
+268 29.5399 0.0939359111586 0.0 0.0
+269 29.6501 0.0928261009874 0.0 0.0
+270 29.7604 0.091725279485 0.0 0.0
+271 29.8706 0.0906334071226 0.0 0.0
+272 29.9808 0.0895503688463 0.0 0.0
+273 30.091 0.0884760696998 0.0 0.0
+274 30.2013 0.0874104340901 0.0 0.0
+275 30.3115 0.0863533321714 0.0 0.0
+276 30.4217 0.0853046904967 0.0 0.0
+277 30.5319 0.0842644181311 0.0 0.0
+278 30.6422 0.0832324251703 0.0 0.0
+279 30.7524 0.0822086050955 0.0 0.0
+280 30.8626 0.0811929230329 0.0 0.0
+281 30.9728 0.080185256663 0.0 0.0
+282 31.0831 0.0791854858121 0.0 0.0
+283 31.1933 0.0781935950506 0.0 0.0
+284 31.3035 0.0772094321642 0.0 0.0
+285 31.4137 0.0762329828009 0.0 0.0
+286 31.5239 0.0752641146916 0.0 0.0
+287 31.6342 0.0743027479214 0.0 0.0
+288 31.7444 0.0733488694632 0.0 0.0
+289 31.8546 0.0724023021797 0.0 0.0
+290 31.9648 0.0714630349671 0.0 0.0
+291 32.0751 0.0705309915795 0.0 0.0
+292 32.1853 0.0696060490382 0.0 0.0
+293 32.2955 0.0686881977065 0.0 0.0
+294 32.4057 0.0677773015062 0.0 0.0
+295 32.516 0.0668733520587 0.0 0.0
+296 32.6262 0.0659762474239 0.0 0.0
+297 32.7364 0.0650858877006 0.0 0.0
+298 32.8466 0.0642022359612 0.0 0.0
+299 32.9569 0.0633252554916 0.0 0.0
+300 33.0671 0.0624548197418 0.0 0.0
+301 33.1773 0.06159095403 0.0 0.0
+302 33.2875 0.0607334751434 0.0 0.0
+303 33.3977 0.0598823805674 0.0 0.0
+304 33.508 0.0590376380389 0.0 0.0
+305 33.6182 0.0581991287889 0.0 0.0
+306 33.7284 0.0573668516632 0.0 0.0
+307 33.8386 0.0565406909543 0.0 0.0
+308 33.9489 0.0557206468437 0.0 0.0
+309 34.0591 0.0549066347335 0.0 0.0
+310 34.1693 0.0540985719197 0.0 0.0
+311 34.2795 0.0532964605803 0.0 0.0
+312 34.3898 0.0525001925117 0.0 0.0
+313 34.5 0.051709771214 0.0 0.0
+314 34.6102 0.0509250914181 0.0 0.0
+315 34.7204 0.0501461579341 0.0 0.0
+316 34.8307 0.0493728950636 0.0 0.0
+317 34.9409 0.0486052289052 0.0 0.0
+318 35.0511 0.0478431662047 0.0 0.0
+319 35.1613 0.0470866088432 0.0 0.0
+320 35.2715 0.0463355648324 0.0 0.0
+321 35.3818 0.0455899388337 0.0 0.0
+322 35.492 0.0448497401016 0.0 0.0
+323 35.6022 0.0441149013821 0.0 0.0
+324 35.7124 0.0433853571129 0.0 0.0
+325 35.8227 0.042661118362 0.0 0.0
+326 35.9329 0.0419420965245 0.0 0.0
+327 36.0431 0.0412283038404 0.0 0.0
+328 36.1533 0.0405196787571 0.0 0.0
+329 36.2636 0.0398161613314 0.0 0.0
+330 36.3738 0.0391177414014 0.0 0.0
+331 36.484 0.0384244090281 0.0 0.0
+332 36.5942 0.0377360832475 0.0 0.0
+333 36.7045 0.0370527796078 0.0 0.0
+334 36.8147 0.0363744195795 0.0 0.0
+335 36.9249 0.0357010197363 0.0 0.0
+336 37.0351 0.0350325039245 0.0 0.0
+337 37.1453 0.0343688897012 0.0 0.0
+338 37.2556 0.0337101032293 0.0 0.0
+339 37.3658 0.0330561404398 0.0 0.0
+340 37.476 0.0324070422158 0.0 0.0
+341 37.5862 0.0317626482175 0.0 0.0
+342 37.6965 0.0311230012578 0.0 0.0
+343 37.8067 0.0304880772968 0.0 0.0
+344 37.9169 0.0298578747742 0.0 0.0
+345 38.0271 0.0292323490653 0.0 0.0
+346 38.1374 0.0286114568615 0.0 0.0
+347 38.2476 0.0279951986773 0.0 0.0
+348 38.3578 0.0273835750979 0.0 0.0
+349 38.468 0.0267765239274 0.0 0.0
+350 38.5783 0.0261740471796 0.0 0.0
+351 38.6885 0.0255761675389 0.0 0.0
+352 38.7987 0.0249827842694 0.0 0.0
+353 38.9089 0.0243939418327 0.0 0.0
+354 39.0191 0.0238096028611 0.0 0.0
+355 39.1294 0.0232297311422 0.0 0.0
+356 39.2396 0.0226543511691 0.0 0.0
+357 39.3498 0.0220834080137 0.0 0.0
+358 39.46 0.021516926623 0.0 0.0
+359 39.5703 0.0209548537269 0.0 0.0
+360 39.6805 0.020397195425 0.0 0.0
+361 39.7907 0.0198439768285 0.0 0.0
+362 39.9009 0.0192951087432 0.0 0.0
+363 40.0112 0.0187506174163 0.0 0.0
+364 40.1214 0.0182104911347 0.0 0.0
+365 40.2316 0.0176747371011 0.0 0.0
+366 40.3418 0.0171433073545 0.0 0.0
+367 40.4521 0.0166162463899 0.0 0.0
+368 40.5623 0.0160934891839 0.0 0.0
+369 40.6725 0.0155750264018 0.0 0.0
+370 40.7827 0.0150608668037 0.0 0.0
+371 40.893 0.0145510013457 0.0 0.0
+372 41.0032 0.0140454562083 0.0 0.0
+373 41.1134 0.0135441529941 0.0 0.0
+374 41.2236 0.0130471186771 0.0 0.0
+375 41.3338 0.0125543624329 0.0 0.0
+376 41.4441 0.0120658425892 0.0 0.0
+377 41.5543 0.0115815856499 0.0 0.0
+378 41.6645 0.0111015510259 0.0 0.0
+379 41.7747 0.0106257651011 0.0 0.0
+380 41.885 0.0101541883135 0.0 0.0
+381 41.9952 0.00968684687597 0.0 0.0
+382 42.1054 0.00922371818556 0.0 0.0
+383 42.2156 0.00876479617715 0.0 0.0
+384 42.3259 0.00831005925101 0.0 0.0
+385 42.4361 0.00785951757557 0.0 0.0
+386 42.5463 0.00741318093911 0.0 0.0
+387 42.6565 0.00697101295284 0.0 0.0
+388 42.7668 0.00653303884104 0.0 0.0
+389 42.877 0.00609923798167 0.0 0.0
+390 42.9872 0.00566959035271 0.0 0.0
+391 43.0974 0.0052441058907 0.0 0.0
+392 43.2076 0.00482277954601 0.0 0.0
+393 43.3179 0.00440563512517 0.0 0.0
+394 43.4281 0.00399260992804 0.0 0.0
+395 43.5383 0.00358374209973 0.0 0.0
+396 43.6485 0.00317901241574 0.0 0.0
+397 43.7588 0.0027784021643 0.0 0.0
+398 43.869 0.00238192050607 0.0 0.0
+399 43.9792 0.00198958963997 0.0 0.0
+400 44.0894 0.00160135034387 0.0 0.0
+401 44.1997 0.00121722490757 0.0 0.0
+402 44.3099 0.000837208358398 0.0 0.0
+403 44.4201 0.000461308654964 0.0 0.0
+404 44.5303 8.95075411272e-05 0.0 0.0
+405 44.6406 -0.000278212813152 0.0 0.0
+406 44.7508 -0.000641832163486 0.0 0.0
+407 44.861 -0.00100138096775 0.0 0.0
+408 44.9712 -0.00135685198757 0.0 0.0
+409 45.0814 -0.0017082385649 0.0 0.0
+410 45.1917 -0.00205554661615 0.0 0.0
+411 45.3019 -0.002398817719 0.0 0.0
+412 45.4121 -0.00273803357939 0.0 0.0
+413 45.5223 -0.00307318855664 0.0 0.0
+414 45.6326 -0.0034043119112 0.0 0.0
+415 45.7428 -0.00373138692301 0.0 0.0
+416 45.853 -0.00405444257527 0.0 0.0
+417 45.9632 -0.00437346300051 0.0 0.0
+418 46.0735 -0.00468847693027 0.0 0.0
+419 46.1837 -0.00499948010833 0.0 0.0
+420 46.2939 -0.0053064583138 0.0 0.0
+421 46.4041 -0.00560946119387 0.0 0.0
+422 46.5144 -0.00590847477446 0.0 0.0
+423 46.6246 -0.00620348619 0.0 0.0
+424 46.7348 -0.00649454397385 0.0 0.0
+425 46.845 -0.00678163553883 0.0 0.0
+426 46.9552 -0.0070647591848 0.0 0.0
+427 47.0655 -0.00734393314227 0.0 0.0
+428 47.1757 -0.00761917538656 0.0 0.0
+429 47.2859 -0.00789048491073 0.0 0.0
+430 47.3961 -0.00815787059947 0.0 0.0
+431 47.5064 -0.00842132335343 0.0 0.0
+432 47.6166 -0.00868088895183 0.0 0.0
+433 47.7268 -0.00893655863822 0.0 0.0
+434 47.837 -0.00918833345848 0.0 0.0
+435 47.9473 -0.00943624079861 0.0 0.0
+436 48.0575 -0.00968026525185 0.0 0.0
+437 48.1677 -0.00992044270999 0.0 0.0
+438 48.2779 -0.0101567834938 0.0 0.0
+439 48.3882 -0.0103892901241 0.0 0.0
+440 48.4984 -0.0106179736798 0.0 0.0
+441 48.6086 -0.0108428377023 0.0 0.0
+442 48.7188 -0.0110639016564 0.0 0.0
+443 48.829 -0.0112811848058 0.0 0.0
+444 48.9393 -0.0114946841013 0.0 0.0
+445 49.0495 -0.011704426541 0.0 0.0
+446 49.1597 -0.0119104171681 0.0 0.0
+447 49.2699 -0.0121126616766 0.0 0.0
+448 49.3802 -0.0123111801161 0.0 0.0
+449 49.4904 -0.0125059923461 0.0 0.0
+450 49.6006 -0.0126970982422 0.0 0.0
+451 49.7108 -0.0128845181474 0.0 0.0
+452 49.8211 -0.0130682658725 0.0 0.0
+453 49.9313 -0.0132483616717 0.0 0.0
+454 50.0415 -0.0134248134308 0.0 0.0
+455 50.1517 -0.0135976296628 0.0 0.0
+456 50.262 -0.0137668370298 0.0 0.0
+457 50.3722 -0.0139324444565 0.0 0.0
+458 50.4824 -0.0140944558876 0.0 0.0
+459 50.5926 -0.0142529091009 0.0 0.0
+460 50.7029 -0.0144078084188 0.0 0.0
+461 50.8131 -0.014559169613 0.0 0.0
+462 50.9233 -0.0147070035573 0.0 0.0
+463 51.0335 -0.0148513316849 0.0 0.0
+464 51.1437 -0.0149921703815 0.0 0.0
+465 51.254 -0.0151295362335 0.0 0.0
+466 51.3642 -0.0152634506491 0.0 0.0
+467 51.4744 -0.0153939258439 0.0 0.0
+468 51.5846 -0.015520970214 0.0 0.0
+469 51.6949 -0.0156446187075 0.0 0.0
+470 51.8051 -0.0157648800576 0.0 0.0
+471 51.9153 -0.0158817719929 0.0 0.0
+472 52.0255 -0.0159953085002 0.0 0.0
+473 52.1358 -0.0161055155222 0.0 0.0
+474 52.246 -0.0162124036862 0.0 0.0
+475 52.3562 -0.0163159952391 0.0 0.0
+476 52.4664 -0.0164163122355 0.0 0.0
+477 52.5767 -0.0165133698367 0.0 0.0
+478 52.6869 -0.0166071837155 0.0 0.0
+479 52.7971 -0.0166977731754 0.0 0.0
+480 52.9073 -0.0167851667228 0.0 0.0
+481 53.0175 -0.0168693774408 0.0 0.0
+482 53.1278 -0.0169504220411 0.0 0.0
+483 53.238 -0.0170283257843 0.0 0.0
+484 53.3482 -0.0171031030643 0.0 0.0
+485 53.4584 -0.0171747789768 0.0 0.0
+486 53.5687 -0.017243368608 0.0 0.0
+487 53.6789 -0.0173088968787 0.0 0.0
+488 53.7891 -0.0173713817046 0.0 0.0
+489 53.8993 -0.017430843497 0.0 0.0
+490 54.0096 -0.0174872988806 0.0 0.0
+491 54.1198 -0.0175407763045 0.0 0.0
+492 54.23 -0.0175912891026 0.0 0.0
+493 54.3402 -0.0176388651081 0.0 0.0
+494 54.4505 -0.0176835217556 0.0 0.0
+495 54.5607 -0.0177252786347 0.0 0.0
+496 54.6709 -0.0177641584144 0.0 0.0
+497 54.7811 -0.0178001835452 0.0 0.0
+498 54.8913 -0.0178333739685 0.0 0.0
+499 55.0016 -0.0178637510525 0.0 0.0
+500 55.1118 -0.0178913343342 0.0 0.0
+501 55.222 -0.0179161491451 0.0 0.0
+502 55.3322 -0.0179382151522 0.0 0.0
+503 55.4425 -0.0179575533313 0.0 0.0
+504 55.5527 -0.0179741867237 0.0 0.0
+505 55.6629 -0.017988136418 0.0 0.0
+506 55.7731 -0.0179994230558 0.0 0.0
+507 55.8834 -0.0180080708406 0.0 0.0
+508 55.9936 -0.0180141005035 0.0 0.0
+509 56.1038 -0.0180175339917 0.0 0.0
+510 56.214 -0.0180183932609 0.0 0.0
+511 56.3242 -0.0180167004493 0.0 0.0
+512 56.4345 -0.0180124774615 0.0 0.0
+513 56.5447 -0.0180057466692 0.0 0.0
+514 56.6549 -0.0179965297115 0.0 0.0
+515 56.7651 -0.0179848489489 0.0 0.0
+516 56.8754 -0.0179707265273 0.0 0.0
+517 56.9856 -0.0179541857511 0.0 0.0
+518 57.0958 -0.0179352465042 0.0 0.0
+519 57.206 -0.0179139328539 0.0 0.0
+520 57.3163 -0.017890266333 0.0 0.0
+521 57.4265 -0.017864268237 0.0 0.0
+522 57.5367 -0.0178359625602 0.0 0.0
+523 57.6469 -0.0178053695376 0.0 0.0
+524 57.7572 -0.0177725134758 0.0 0.0
+525 57.8674 -0.0177374142841 0.0 0.0
+526 57.9776 -0.017700095276 0.0 0.0
+527 58.0878 -0.0176605813441 0.0 0.0
+528 58.1981 -0.0176188891664 0.0 0.0
+529 58.3083 -0.0175750436153 0.0 0.0
+530 58.4185 -0.0175290668043 0.0 0.0
+531 58.5287 -0.0174809824874 0.0 0.0
+532 58.639 -0.0174308094058 0.0 0.0
+533 58.7492 -0.0173785748806 0.0 0.0
+534 58.8594 -0.017324295573 0.0 0.0
+535 58.9696 -0.0172679933375 0.0 0.0
+536 59.0798 -0.0172096920145 0.0 0.0
+537 59.1901 -0.0171494135298 0.0 0.0
+538 59.3003 -0.0170871840748 0.0 0.0
+539 59.4105 -0.01702301689 0.0 0.0
+540 59.5207 -0.0169569381095 0.0 0.0
+541 59.631 -0.0168889718607 0.0 0.0
+542 59.7412 -0.0168191351783 0.0 0.0
+543 59.8514 -0.0167474545927 0.0 0.0
+544 59.9616 -0.0166739467965 0.0 0.0
+545 60.0719 -0.0165986384868 0.0 0.0
+546 60.1821 -0.0165215460155 0.0 0.0
+547 60.2923 -0.0164426962355 0.0 0.0
+548 60.4025 -0.0163621079433 0.0 0.0
+549 60.5127 -0.0162798025592 0.0 0.0
+550 60.623 -0.0161957985522 0.0 0.0
+551 60.7332 -0.0161101230571 0.0 0.0
+552 60.8434 -0.0160227914132 0.0 0.0
+553 60.9536 -0.0159338278088 0.0 0.0
+554 61.0639 -0.0158432565374 0.0 0.0
+555 61.1741 -0.0157510956247 0.0 0.0
+556 61.2843 -0.0156573628884 0.0 0.0
+557 61.3945 -0.0155620825257 0.0 0.0
+558 61.5048 -0.0154652754834 0.0 0.0
+559 61.615 -0.0153669694446 0.0 0.0
+560 61.7252 -0.015267171634 0.0 0.0
+561 61.8354 -0.0151659166427 0.0 0.0
+562 61.9457 -0.0150632111734 0.0 0.0
+563 62.0559 -0.0149590829107 0.0 0.0
+564 62.1661 -0.0148535524601 0.0 0.0
+565 62.2763 -0.0147466477565 0.0 0.0
+566 62.3865 -0.0146383744891 0.0 0.0
+567 62.4968 -0.0145287605024 0.0 0.0
+568 62.607 -0.0144178261695 0.0 0.0
+569 62.7172 -0.014305595682 0.0 0.0
+570 62.8274 -0.0141920854491 0.0 0.0
+571 62.9377 -0.0140773117018 0.0 0.0
+572 63.0479 -0.0139613025222 0.0 0.0
+573 63.1581 -0.0138440699602 0.0 0.0
+574 63.2683 -0.0137256380589 0.0 0.0
+575 63.3786 -0.0136060391781 0.0 0.0
+576 63.4888 -0.0134852683846 0.0 0.0
+577 63.599 -0.0133633579643 0.0 0.0
+578 63.7092 -0.0132403277045 0.0 0.0
+579 63.8195 -0.0131162016227 0.0 0.0
+580 63.9297 -0.012990990798 0.0 0.0
+581 64.0399 -0.0128647235091 0.0 0.0
+582 64.1501 -0.0127374149694 0.0 0.0
+583 64.2604 -0.0126090758076 0.0 0.0
+584 64.3706 -0.0124797432283 0.0 0.0
+585 64.4808 -0.0123494277148 0.0 0.0
+586 64.591 -0.0122181485912 0.0 0.0
+587 64.7012 -0.0120859159875 0.0 0.0
+588 64.8115 -0.0119527674184 0.0 0.0
+589 64.9217 -0.0118187128688 0.0 0.0
+590 65.0319 -0.0116837714348 0.0 0.0
+591 65.1421 -0.0115479621562 0.0 0.0
+592 65.2524 -0.011411304016 0.0 0.0
+593 65.3626 -0.01127380644 0.0 0.0
+594 65.4728 -0.0111355073321 0.0 0.0
+595 65.583 -0.0109964159735 0.0 0.0
+596 65.6933 -0.0108565414571 0.0 0.0
+597 65.8035 -0.0107159218472 0.0 0.0
+598 65.9137 -0.0105745660919 0.0 0.0
+599 66.0239 -0.0104324927806 0.0 0.0
+600 66.1342 -0.010289710581 0.0 0.0
+601 66.2444 -0.0101462577351 0.0 0.0
+602 66.3546 -0.0100021527239 0.0 0.0
+603 66.4648 -0.00985738395814 0.0 0.0
+604 66.575 -0.00971199977807 0.0 0.0
+605 66.6853 -0.00956600839897 0.0 0.0
+606 66.7955 -0.0094194178867 0.0 0.0
+607 66.9057 -0.00927226667169 0.0 0.0
+608 67.0159 -0.00912456267229 0.0 0.0
+609 67.1262 -0.00897632391233 0.0 0.0
+610 67.2364 -0.00882755807823 0.0 0.0
+611 67.3466 -0.00867830367147 0.0 0.0
+612 67.4568 -0.0085285682284 0.0 0.0
+613 67.5671 -0.00837836954021 0.0 0.0
+614 67.6773 -0.00822771492858 0.0 0.0
+615 67.7875 -0.00807664292069 0.0 0.0
+616 67.8977 -0.00792516068456 0.0 0.0
+617 68.0079 -0.00777328577198 0.0 0.0
+618 68.1182 -0.00762103567354 0.0 0.0
+619 68.2284 -0.00746842781806 0.0 0.0
+620 68.3386 -0.00731546900212 0.0 0.0
+621 68.4488 -0.00716219770266 0.0 0.0
+622 68.5591 -0.00700862055509 0.0 0.0
+623 68.6693 -0.00685475473424 0.0 0.0
+624 68.7795 -0.00670060669742 0.0 0.0
+625 68.8897 -0.00654621482601 0.0 0.0
+626 69.0 -0.00639158540973 0.0 0.0
+627 69.1102 -0.00623672465511 0.0 0.0
+628 69.2204 -0.00608167083795 0.0 0.0
+629 69.3306 -0.00592642999154 0.0 0.0
+630 69.4409 -0.00577101881367 0.0 0.0
+631 69.5511 -0.00561545393001 0.0 0.0
+632 69.6613 -0.00545975189293 0.0 0.0
+633 69.7715 -0.00530391841163 0.0 0.0
+634 69.8818 -0.00514799145998 0.0 0.0
+635 69.992 -0.00499197656058 0.0 0.0
+636 70.1022 -0.00483588996074 0.0 0.0
+637 70.2124 -0.00467973703739 0.0 0.0
+638 70.3226 -0.00452355549338 0.0 0.0
+639 70.4329 -0.00436733971333 0.0 0.0
+640 70.5431 -0.0042111380389 0.0 0.0
+641 70.6533 -0.00405492305626 0.0 0.0
+642 70.7635 -0.00389874296916 0.0 0.0
+643 70.8738 -0.00374260261014 0.0 0.0
+644 70.984 -0.00358651755118 0.0 0.0
+645 71.0942 -0.00343050327311 0.0 0.0
+646 71.2044 -0.0032745751639 0.0 0.0
+647 71.3147 -0.00311873774767 0.0 0.0
+648 71.4249 -0.00296302779389 0.0 0.0
+649 71.5351 -0.00280743884701 0.0 0.0
+650 71.6453 -0.00265201818689 0.0 0.0
+651 71.7556 -0.00249673767827 0.0 0.0
+652 71.8658 -0.00234164438702 0.0 0.0
+653 71.976 -0.00218674223972 0.0 0.0
+654 72.0862 -0.00203204582034 0.0 0.0
+655 72.1964 -0.00187755892798 0.0 0.0
+656 72.3067 -0.00172332797286 0.0 0.0
+657 72.4169 -0.00156932450313 0.0 0.0
+658 72.5271 -0.00141559466817 0.0 0.0
+659 72.6373 -0.00126213120935 0.0 0.0
+660 72.7476 -0.00110896927451 0.0 0.0
+661 72.8578 -0.0009561120102 0.0 0.0
+662 72.968 -0.00080357307898 0.0 0.0
+663 73.0782 -0.000651355499941 0.0 0.0
+664 73.1885 -0.000499493756993 0.0 0.0
+665 73.2987 -0.000347990583859 0.0 0.0
+666 73.4089 -0.000196859135986 0.0 0.0
+667 73.5191 -4.61124371366e-05 0.0 0.0
+668 73.6294 0.000104247013971 0.0 0.0
+669 73.7396 0.0002541856491 0.0 0.0
+670 73.8498 0.000403701273948 0.0 0.0
+671 73.96 0.000552791714936 0.0 0.0
+672 74.0703 0.000701423998196 0.0 0.0
+673 74.1805 0.000849606506932 0.0 0.0
+674 74.2907 0.000997296473403 0.0 0.0
+675 74.4009 0.00114451271659 0.0 0.0
+676 74.5111 0.00129124338813 0.0 0.0
+677 74.6214 0.00143745657735 0.0 0.0
+678 74.7316 0.00158316107875 0.0 0.0
+679 74.8418 0.00172831539836 0.0 0.0
+680 74.952 0.00187292860136 0.0 0.0
+681 75.0623 0.0020170096276 0.0 0.0
+682 75.1725 0.0021605176914 0.0 0.0
+683 75.2827 0.00230346200539 0.0 0.0
+684 75.3929 0.00244581229252 0.0 0.0
+685 75.5032 0.00258756813683 0.0 0.0
+686 75.6134 0.00272872913741 0.0 0.0
+687 75.7236 0.00286925605222 0.0 0.0
+688 75.8338 0.00300917797411 0.0 0.0
+689 75.944 0.00314845614683 0.0 0.0
+690 76.0543 0.00328709079728 0.0 0.0
+691 76.1645 0.00342508216595 0.0 0.0
+692 76.2747 0.00356240203124 0.0 0.0
+693 76.3849 0.00369906046097 0.0 0.0
+694 76.4952 0.00383502977554 0.0 0.0
+695 76.6054 0.00397031086557 0.0 0.0
+696 76.7156 0.00410489533144 0.0 0.0
+697 76.8258 0.00423877495682 0.0 0.0
+698 76.9361 0.00437195091428 0.0 0.0
+699 77.0463 0.00450439692252 0.0 0.0
+700 77.1565 0.00463612365717 0.0 0.0
+701 77.2667 0.00476710541204 0.0 0.0
+702 77.377 0.00489733503238 0.0 0.0
+703 77.4872 0.00502683240482 0.0 0.0
+704 77.5974 0.0051555636729 0.0 0.0
+705 77.7076 0.00528353994602 0.0 0.0
+706 77.8178 0.00541072819753 0.0 0.0
+707 77.9281 0.00553714857971 0.0 0.0
+708 78.0383 0.00566278614239 0.0 0.0
+709 78.1485 0.00578763494619 0.0 0.0
+710 78.2587 0.00591169782094 0.0 0.0
+711 78.369 0.00603495204297 0.0 0.0
+712 78.4792 0.00615740085638 0.0 0.0
+713 78.5894 0.00627904750963 0.0 0.0
+714 78.6996 0.00639987019999 0.0 0.0
+715 78.8099 0.00651988088595 0.0 0.0
+716 78.9201 0.00663905014535 0.0 0.0
+717 79.0303 0.00675739841894 0.0 0.0
+718 79.1405 0.00687492138896 0.0 0.0
+719 79.2508 0.00699159880315 0.0 0.0
+720 79.361 0.00710744302561 0.0 0.0
+721 79.4712 0.00722243442742 0.0 0.0
+722 79.5814 0.00733656974989 0.0 0.0
+723 79.6917 0.00744986942219 0.0 0.0
+724 79.8019 0.00756230683959 0.0 0.0
+725 79.9121 0.00767389475185 0.0 0.0
+726 80.0223 0.00778461508942 0.0 0.0
+727 80.1326 0.00789448074945 0.0 0.0
+728 80.2428 0.00800347428438 0.0 0.0
+729 80.353 0.00811159378603 0.0 0.0
+730 80.4632 0.00821885977803 0.0 0.0
+731 80.5734 0.00832524824671 0.0 0.0
+732 80.6837 0.00843077243724 0.0 0.0
+733 80.7939 0.00853541644556 0.0 0.0
+734 80.9041 0.00863917930077 0.0 0.0
+735 81.0143 0.00874208155308 0.0 0.0
+736 81.1245 0.00884409396808 0.0 0.0
+737 81.2348 0.00894524422789 0.0 0.0
+738 81.345 0.0090455108744 0.0 0.0
+739 81.4552 0.00914490071092 0.0 0.0
+740 81.5655 0.00924342051611 0.0 0.0
+741 81.6757 0.00934105679563 0.0 0.0
+742 81.7859 0.00943782338216 0.0 0.0
+743 81.8961 0.00953370073934 0.0 0.0
+744 82.0063 0.00962870950302 0.0 0.0
+745 82.1166 0.00972285035661 0.0 0.0
+746 82.2268 0.00981611125542 0.0 0.0
+747 82.337 0.00990850625986 0.0 0.0
+748 82.4472 0.0100000238897 0.0 0.0
+749 82.5575 0.0100906720162 0.0 0.0
+750 82.6677 0.0101804522626 0.0 0.0
+751 82.7779 0.0102693664055 0.0 0.0
+752 82.8881 0.010357422459 0.0 0.0
+753 82.9984 0.0104446103092 0.0 0.0
+754 83.1086 0.0105309382804 0.0 0.0
+755 83.2188 0.010616414645 0.0 0.0
+756 83.329 0.0107010300756 0.0 0.0
+757 83.4393 0.0107847989287 0.0 0.0
+758 83.5495 0.0108677066538 0.0 0.0
+759 83.6597 0.0109497791166 0.0 0.0
+760 83.7699 0.0110310022474 0.0 0.0
+761 83.8801 0.011111384898 0.0 0.0
+762 83.9904 0.0111909303555 0.0 0.0
+763 84.1006 0.0112696365857 0.0 0.0
+764 84.2108 0.0113475233926 0.0 0.0
+765 84.321 0.0114245781769 0.0 0.0
+766 84.4313 0.0115008100847 0.0 0.0
+767 84.5415 0.0115762281848 0.0 0.0
+768 84.6517 0.0116508259973 0.0 0.0
+769 84.7619 0.0117246179102 0.0 0.0
+770 84.8722 0.0117975978671 0.0 0.0
+771 84.9824 0.0118697702449 0.0 0.0
+772 85.0926 0.0119411543133 0.0 0.0
+773 85.2028 0.0120117396189 0.0 0.0
+774 85.3131 0.0120815404488 0.0 0.0
+775 85.4233 0.0121505517359 0.0 0.0
+776 85.5335 0.0122187829902 0.0 0.0
+777 85.6437 0.012286243621 0.0 0.0
+778 85.7539 0.0123529244963 0.0 0.0
+779 85.8642 0.0124188489628 0.0 0.0
+780 85.9744 0.0124840082191 0.0 0.0
+781 86.0846 0.0125484118394 0.0 0.0
+782 86.1948 0.0126120692857 0.0 0.0
+783 86.3051 0.0126749768602 0.0 0.0
+784 86.4153 0.0127371484352 0.0 0.0
+785 86.5255 0.0127985763659 0.0 0.0
+786 86.6357 0.0128592787156 0.0 0.0
+787 86.746 0.0129192606614 0.0 0.0
+788 86.8562 0.0129785192234 0.0 0.0
+789 86.9664 0.0130370639129 0.0 0.0
+790 87.0766 0.0130949001118 0.0 0.0
+791 87.1869 0.0131520332264 0.0 0.0
+792 87.2971 0.0132084686834 0.0 0.0
+793 87.4073 0.013264211927 0.0 0.0
+794 87.5175 0.0133192722208 0.0 0.0
+795 87.6277 0.0133736474111 0.0 0.0
+796 87.738 0.0134273505006 0.0 0.0
+797 87.8482 0.0134803795336 0.0 0.0
+798 87.9584 0.0135327400899 0.0 0.0
+799 88.0686 0.013584448468 0.0 0.0
+800 88.1789 0.0136354993492 0.0 0.0
+801 88.2891 0.0136859052597 0.0 0.0
+802 88.3993 0.0137356646674 0.0 0.0
+803 88.5095 0.0137847864942 0.0 0.0
+804 88.6198 0.0138332795016 0.0 0.0
+805 88.73 0.0138811390548 0.0 0.0
+806 88.8402 0.0139283837672 0.0 0.0
+807 88.9504 0.0139750091138 0.0 0.0
+808 89.0607 0.014021023669 0.0 0.0
+809 89.1709 0.0140664358378 0.0 0.0
+810 89.2811 0.0141112445618 0.0 0.0
+811 89.3913 0.0141554612323 0.0 0.0
+812 89.5015 0.0141990818568 0.0 0.0
+813 89.6118 0.0142421206368 0.0 0.0
+814 89.722 0.0142845825338 0.0 0.0
+815 89.8322 0.0143264666681 0.0 0.0
+816 89.9425 0.0143677837829 0.0 0.0
+817 90.0527 0.0144085302295 0.0 0.0
+818 90.1629 0.0144487221198 0.0 0.0
+819 90.2731 0.014488353094 0.0 0.0
+820 90.3833 0.0145274361285 0.0 0.0
+821 90.4936 0.0145659757794 0.0 0.0
+822 90.6038 0.0146039712826 0.0 0.0
+823 90.714 0.0146414323992 0.0 0.0
+824 90.8242 0.0146783583725 0.0 0.0
+825 90.9344 0.0147147536368 0.0 0.0
+826 91.0447 0.0147506299898 0.0 0.0
+827 91.1549 0.0147859841442 0.0 0.0
+828 91.2651 0.0148208251165 0.0 0.0
+829 91.3754 0.0148551521244 0.0 0.0
+830 91.4856 0.0148889715407 0.0 0.0
+831 91.5958 0.0149222895425 0.0 0.0
+832 91.706 0.0149551053063 0.0 0.0
+833 91.8162 0.0149874248425 0.0 0.0
+834 91.9265 0.0150192517647 0.0 0.0
+835 92.0367 0.0150505895969 0.0 0.0
+836 92.1469 0.0150814439061 0.0 0.0
+837 92.2571 0.0151118137634 0.0 0.0
+838 92.3674 0.0151417066236 0.0 0.0
+839 92.4776 0.0151711215056 0.0 0.0
+840 92.5878 0.0152000615429 0.0 0.0
+841 92.698 0.0152285356789 0.0 0.0
+842 92.8083 0.0152565408395 0.0 0.0
+843 92.9185 0.0152840836794 0.0 0.0
+844 93.0287 0.0153111630673 0.0 0.0
+845 93.1389 0.0153377834969 0.0 0.0
+846 93.2491 0.0153639456474 0.0 0.0
+847 93.3594 0.0153896555322 0.0 0.0
+848 93.4696 0.0154149153789 0.0 0.0
+849 93.5798 0.0154397238885 0.0 0.0
+850 93.69 0.0154640865963 0.0 0.0
+851 93.8003 0.0154880021339 0.0 0.0
+852 93.9105 0.0155114740972 0.0 0.0
+853 94.0207 0.0155345058901 0.0 0.0
+854 94.1309 0.0155570944786 0.0 0.0
+855 94.2412 0.0155792477383 0.0 0.0
+856 94.3514 0.0156009625635 0.0 0.0
+857 94.4616 0.0156222419218 0.0 0.0
+858 94.5718 0.0156430885937 0.0 0.0
+859 94.6821 0.0156635009408 0.0 0.0
+860 94.7923 0.0156834829447 0.0 0.0
+861 94.9025 0.0157030315532 0.0 0.0
+862 95.0127 0.0157221518335 0.0 0.0
+863 95.123 0.0157408446109 0.0 0.0
+864 95.2332 0.015759108099 0.0 0.0
+865 95.3434 0.0157769455416 0.0 0.0
+866 95.4536 0.0157943551005 0.0 0.0
+867 95.5638 0.0158113373858 0.0 0.0
+868 95.6741 0.0158278963604 0.0 0.0
+869 95.7843 0.0158440289422 0.0 0.0
+870 95.8945 0.0158597376737 0.0 0.0
+871 96.0047 0.0158750206131 0.0 0.0
+872 96.115 0.0158898779795 0.0 0.0
+873 96.2252 0.0159043129131 0.0 0.0
+874 96.3354 0.0159183214317 0.0 0.0
+875 96.4456 0.0159319073597 0.0 0.0
+876 96.5559 0.0159450677241 0.0 0.0
+877 96.6661 0.0159578041606 0.0 0.0
+878 96.7763 0.0159701146572 0.0 0.0
+879 96.8865 0.015981999787 0.0 0.0
+880 96.9968 0.0159934599745 0.0 0.0
+881 97.107 0.0160044924469 0.0 0.0
+882 97.2172 0.0160150997817 0.0 0.0
+883 97.3274 0.0160252792176 0.0 0.0
+884 97.4376 0.0160350309123 0.0 0.0
+885 97.5479 0.0160443548867 0.0 0.0
+886 97.6581 0.016053249183 0.0 0.0
+887 97.7683 0.0160617143236 0.0 0.0
+888 97.8785 0.016069747834 0.0 0.0
+889 97.9888 0.0160773506298 0.0 0.0
+890 98.099 0.0160845218332 0.0 0.0
+891 98.2092 0.0160912596042 0.0 0.0
+892 98.3194 0.0160975640004 0.0 0.0
+893 98.4297 0.0161034332484 0.0 0.0
+894 98.5399 0.0161088668623 0.0 0.0
+895 98.6501 0.016113864245 0.0 0.0
+896 98.7603 0.01611842343 0.0 0.0
+897 98.8706 0.0161225447062 0.0 0.0
+898 98.9808 0.0161262262029 0.0 0.0
+899 99.091 0.0161294672126 0.0 0.0
+900 99.2012 0.0161322667372 0.0 0.0
+901 99.3114 0.0161346236128 0.0 0.0
+902 99.4217 0.0161365372976 0.0 0.0
+903 99.5319 0.0161380063663 0.0 0.0
+904 99.6421 0.0161390299604 0.0 0.0
+905 99.7523 0.0161396071377 0.0 0.0
+906 99.8626 0.0161397368485 0.0 0.0
+907 99.9728 0.0161394181553 0.0 0.0
+908 100.083 0.0161386501649 0.0 0.0
+909 100.193 0.0161374319381 0.0 0.0
+910 100.303 0.0161357625815 0.0 0.0
+911 100.414 0.0161336412278 0.0 0.0
+912 100.524 0.016131066861 0.0 0.0
+913 100.634 0.0161280390313 0.0 0.0
+914 100.744 0.0161245565481 0.0 0.0
+915 100.855 0.0161206191597 0.0 0.0
+916 100.965 0.016116226235 0.0 0.0
+917 101.075 0.0161113761798 0.0 0.0
+918 101.185 0.016106069365 0.0 0.0
+919 101.295 0.0161003044995 0.0 0.0
+920 101.406 0.0160940818758 0.0 0.0
+921 101.516 0.0160874006425 0.0 0.0
+922 101.626 0.0160802599102 0.0 0.0
+923 101.736 0.0160726608558 0.0 0.0
+924 101.847 0.0160646010994 0.0 0.0
+925 101.957 0.016056082071 0.0 0.0
+926 102.067 0.0160471030661 0.0 0.0
+927 102.177 0.0160376633542 0.0 0.0
+928 102.287 0.0160277649194 0.0 0.0
+929 102.398 0.016017405087 0.0 0.0
+930 102.508 0.016006586866 0.0 0.0
+931 102.618 0.0159953082594 0.0 0.0
+932 102.728 0.015983569503 0.0 0.0
+933 102.839 0.0159713726012 0.0 0.0
+934 102.949 0.0159587163284 0.0 0.0
+935 103.059 0.0159456029848 0.0 0.0
+936 103.169 0.0159320332673 0.0 0.0
+937 103.279 0.0159180050519 0.0 0.0
+938 103.39 0.0159035220363 0.0 0.0
+939 103.5 0.0158885831235 0.0 0.0
+940 103.61 0.0158731913835 0.0 0.0
+941 103.72 0.0158573457834 0.0 0.0
+942 103.831 0.0158410497116 0.0 0.0
+943 103.941 0.0158243045216 0.0 0.0
+944 104.051 0.0158071080993 0.0 0.0
+945 104.161 0.0157894654801 0.0 0.0
+946 104.272 0.0157713758187 0.0 0.0
+947 104.382 0.0157528433196 0.0 0.0
+948 104.492 0.0157338685341 0.0 0.0
+949 104.602 0.0157144520304 0.0 0.0
+950 104.712 0.0156945998856 0.0 0.0
+951 104.823 0.0156743087271 0.0 0.0
+952 104.933 0.0156535849713 0.0 0.0
+953 105.043 0.015632429553 0.0 0.0
+954 105.153 0.0156108434294 0.0 0.0
+955 105.264 0.0155888336701 0.0 0.0
+956 105.374 0.0155663968506 0.0 0.0
+957 105.484 0.0155435419627 0.0 0.0
+958 105.594 0.0155202671782 0.0 0.0
+959 105.704 0.0154965754447 0.0 0.0
+960 105.815 0.0154724731547 0.0 0.0
+961 105.925 0.0154479601957 0.0 0.0
+962 106.035 0.0154230432958 0.0 0.0
+963 106.145 0.0153977259532 0.0 0.0
+964 106.256 0.0153720064409 0.0 0.0
+965 106.366 0.0153458937403 0.0 0.0
+966 106.476 0.0153193880135 0.0 0.0
+967 106.586 0.0152924968159 0.0 0.0
+968 106.696 0.0152652223063 0.0 0.0
+969 106.807 0.015237566676 0.0 0.0
+970 106.917 0.0152095379646 0.0 0.0
+971 107.027 0.0151811385741 0.0 0.0
+972 107.137 0.0151523729285 0.0 0.0
+973 107.248 0.0151232435429 0.0 0.0
+974 107.358 0.0150937590829 0.0 0.0
+975 107.468 0.0150639222664 0.0 0.0
+976 107.578 0.0150337358442 0.0 0.0
+977 107.688 0.0150032089336 0.0 0.0
+978 107.799 0.0149723423466 0.0 0.0
+979 107.909 0.0149411476489 0.0 0.0
+980 108.019 0.0149096236153 0.0 0.0
+981 108.129 0.014877775532 0.0 0.0
+982 108.24 0.014845613228 0.0 0.0
+983 108.35 0.0148131400084 0.0 0.0
+984 108.46 0.0147803637414 0.0 0.0
+985 108.57 0.0147472855787 0.0 0.0
+986 108.68 0.0147139112598 0.0 0.0
+987 108.791 0.0146802512646 0.0 0.0
+988 108.901 0.0146463068759 0.0 0.0
+989 109.011 0.0146120888148 0.0 0.0
+990 109.121 0.01457760083 0.0 0.0
+991 109.232 0.0145428466946 0.0 0.0
+992 109.342 0.0145078398901 0.0 0.0
+993 109.452 0.0144725770449 0.0 0.0
+994 109.562 0.0144370718561 0.0 0.0
+995 109.672 0.0144013283371 0.0 0.0
+996 109.783 0.0143653505208 0.0 0.0
+997 109.893 0.0143291499697 0.0 0.0
+998 110.003 0.0142927283139 0.0 0.0
+999 110.113 0.0142560998258 0.0 0.0
+1000 110.224 0.0142192636623 0.0 0.0
+1001 110.334 0.0141822266029 0.0 0.0
+1002 110.444 0.0141450006252 0.0 0.0
+1003 110.554 0.0141075874727 0.0 0.0
+1004 110.664 0.0140699992634 0.0 0.0
+1005 110.775 0.0140322377733 0.0 0.0
+1006 110.885 0.0139943178679 0.0 0.0
+1007 110.995 0.0139562387314 0.0 0.0
+1008 111.105 0.0139180074292 0.0 0.0
+1009 111.216 0.0138796363634 0.0 0.0
+1010 111.326 0.0138411273573 0.0 0.0
+1011 111.436 0.0138024955704 0.0 0.0
+1012 111.546 0.0137637428428 0.0 0.0
+1013 111.656 0.0137248709908 0.0 0.0
+1014 111.767 0.0136858952865 0.0 0.0
+1015 111.877 0.0136468175503 0.0 0.0
+1016 111.987 0.0136076504145 0.0 0.0
+1017 112.097 0.0135683983982 0.0 0.0
+1018 112.208 0.013529066009 0.0 0.0
+1019 112.318 0.0134896686411 0.0 0.0
+1020 112.428 0.0134502026054 0.0 0.0
+1021 112.538 0.0134106833057 0.0 0.0
+1022 112.648 0.0133711152068 0.0 0.0
+1023 112.759 0.0133315027537 0.0 0.0
+1024 112.869 0.0132918585959 0.0 0.0
+1025 112.979 0.0132521843907 0.0 0.0
+1026 113.089 0.0132124954955 0.0 0.0
+1027 113.2 0.0131727907603 0.0 0.0
+1028 113.31 0.0131330772521 0.0 0.0
+1029 113.42 0.013093367498 0.0 0.0
+1030 113.53 0.0130536629944 0.0 0.0
+1031 113.641 0.0130139761908 0.0 0.0
+1032 113.751 0.0129743085046 0.0 0.0
+1033 113.861 0.0129346722926 0.0 0.0
+1034 113.971 0.0128950743618 0.0 0.0
+1035 114.081 0.0128555132602 0.0 0.0
+1036 114.192 0.012816003919 0.0 0.0
+1037 114.302 0.0127765475234 0.0 0.0
+1038 114.412 0.012737158853 0.0 0.0
+1039 114.522 0.0126978389716 0.0 0.0
+1040 114.633 0.0126585889162 0.0 0.0
+1041 114.743 0.0126194232418 0.0 0.0
+1042 114.853 0.0125803428529 0.0 0.0
+1043 114.963 0.012541359412 0.0 0.0
+1044 115.073 0.0125024763876 0.0 0.0
+1045 115.184 0.0124636971956 0.0 0.0
+1046 115.294 0.0124250332201 0.0 0.0
+1047 115.404 0.0123864877066 0.0 0.0
+1048 115.514 0.012348066501 0.0 0.0
+1049 115.625 0.0123097753605 0.0 0.0
+1050 115.735 0.012271617313 0.0 0.0
+1051 115.845 0.0122336032138 0.0 0.0
+1052 115.955 0.0121957332784 0.0 0.0
+1053 116.065 0.0121580181294 0.0 0.0
+1054 116.176 0.0121204630211 0.0 0.0
+1055 116.286 0.0120830653473 0.0 0.0
+1056 116.396 0.0120458379624 0.0 0.0
+1057 116.506 0.0120087806832 0.0 0.0
+1058 116.617 0.0119719035022 0.0 0.0
+1059 116.727 0.0119352086056 0.0 0.0
+1060 116.837 0.0118986981119 0.0 0.0
+1061 116.947 0.0118623841168 0.0 0.0
+1062 117.057 0.0118262609821 0.0 0.0
+1063 117.168 0.0117903405255 0.0 0.0
+1064 117.278 0.0117546219587 0.0 0.0
+1065 117.388 0.0117191142919 0.0 0.0
+1066 117.498 0.0116838214378 0.0 0.0
+1067 117.609 0.0116487399102 0.0 0.0
+1068 117.719 0.011613883125 0.0 0.0
+1069 117.829 0.0115792450116 0.0 0.0
+1070 117.939 0.0115448362372 0.0 0.0
+1071 118.049 0.011510657734 0.0 0.0
+1072 118.16 0.011476710361 0.0 0.0
+1073 118.27 0.0114430018974 0.0 0.0
+1074 118.38 0.0114095306299 0.0 0.0
+1075 118.49 0.0113763063145 0.0 0.0
+1076 118.601 0.0113433247295 0.0 0.0
+1077 118.711 0.0113105884815 0.0 0.0
+1078 118.821 0.011278104541 0.0 0.0
+1079 118.931 0.0112458707209 0.0 0.0
+1080 119.041 0.0112138936632 0.0 0.0
+1081 119.152 0.0111821753787 0.0 0.0
+1082 119.262 0.0111507112209 0.0 0.0
+1083 119.372 0.0111195095335 0.0 0.0
+1084 119.482 0.0110885676581 0.0 0.0
+1085 119.593 0.0110578914091 0.0 0.0
+1086 119.703 0.011027480045 0.0 0.0
+1087 119.813 0.010997332754 0.0 0.0
+1088 119.923 0.0109674548537 0.0 0.0
+1089 120.033 0.0109378452718 0.0 0.0
+1090 120.144 0.0109085048968 0.0 0.0
+1091 120.254 0.0108794344902 0.0 0.0
+1092 120.364 0.0108506326958 0.0 0.0
+1093 120.474 0.0108221040101 0.0 0.0
+1094 120.585 0.0107938468229 0.0 0.0
+1095 120.695 0.0107658633307 0.0 0.0
+1096 120.805 0.0107381478811 0.0 0.0
+1097 120.915 0.0107107062661 0.0 0.0
+1098 121.025 0.0106835364616 0.0 0.0
+1099 121.136 0.010656636384 0.0 0.0
+1100 121.246 0.0106300094151 0.0 0.0
+1101 121.356 0.01060365141 0.0 0.0
+1102 121.466 0.0105775672472 0.0 0.0
+1103 121.577 0.0105517508011 0.0 0.0
+1104 121.687 0.0105262013114 0.0 0.0
+1105 121.797 0.0105009214029 0.0 0.0
+1106 121.907 0.0104759065547 0.0 0.0
+1107 122.018 0.0104511591007 0.0 0.0
+1108 122.128 0.010426676073 0.0 0.0
+1109 122.238 0.0104024561327 0.0 0.0
+1110 122.348 0.0103784978387 0.0 0.0
+1111 122.458 0.0103547980106 0.0 0.0
+1112 122.569 0.0103313582892 0.0 0.0
+1113 122.679 0.0103081752965 0.0 0.0
+1114 122.789 0.0102852456161 0.0 0.0
+1115 122.899 0.0102625704996 0.0 0.0
+1116 123.01 0.0102401447949 0.0 0.0
+1117 123.12 0.0102179710393 0.0 0.0
+1118 123.23 0.0101960424233 0.0 0.0
+1119 123.34 0.0101743567142 0.0 0.0
+1120 123.45 0.0101529145635 0.0 0.0
+1121 123.561 0.01013171204 0.0 0.0
+1122 123.671 0.0101107480884 0.0 0.0
+1123 123.781 0.0100900157937 0.0 0.0
+1124 123.891 0.0100695168283 0.0 0.0
+1125 124.002 0.0100492470367 0.0 0.0
+1126 124.112 0.0100292022477 0.0 0.0
+1127 124.222 0.0100093823871 0.0 0.0
+1128 124.332 0.00998978180053 0.0 0.0
+1129 124.442 0.00997040023277 0.0 0.0
+1130 124.553 0.0099512346269 0.0 0.0
+1131 124.663 0.00993227794078 0.0 0.0
+1132 124.773 0.00991353099796 0.0 0.0
+1133 124.883 0.00989498802652 0.0 0.0
+1134 124.994 0.00987664837164 0.0 0.0
+1135 125.104 0.00985850748456 0.0 0.0
+1136 125.214 0.00984056082016 0.0 0.0
+1137 125.324 0.00982280874931 0.0 0.0
+1138 125.434 0.00980524298077 0.0 0.0
+1139 125.545 0.00978786376876 0.0 0.0
+1140 125.655 0.0097706664602 0.0 0.0
+1141 125.765 0.00975364641565 0.0 0.0
+1142 125.875 0.00973680250522 0.0 0.0
+1143 125.986 0.00972012889009 0.0 0.0
+1144 126.096 0.00970362549502 0.0 0.0
+1145 126.206 0.00968728534002 0.0 0.0
+1146 126.316 0.00967110489684 0.0 0.0
+1147 126.426 0.00965508284261 0.0 0.0
+1148 126.537 0.00963921338906 0.0 0.0
+1149 126.647 0.00962349624545 0.0 0.0
+1150 126.757 0.00960792563685 0.0 0.0
+1151 126.867 0.00959249585366 0.0 0.0
+1152 126.978 0.00957720653799 0.0 0.0
+1153 127.088 0.00956205200626 0.0 0.0
+1154 127.198 0.00954703079801 0.0 0.0
+1155 127.308 0.00953213728617 0.0 0.0
+1156 127.418 0.00951736999857 0.0 0.0
+1157 127.529 0.00950272539848 0.0 0.0
+1158 127.639 0.00948819695425 0.0 0.0
+1159 127.749 0.009473784213 0.0 0.0
+1160 127.859 0.00945948172378 0.0 0.0
+1161 127.97 0.00944528803659 0.0 0.0
+1162 128.08 0.00943119875867 0.0 0.0
+1163 128.19 0.00941720955077 0.0 0.0
+1164 128.3 0.00940331997059 0.0 0.0
+1165 128.41 0.00938952286712 0.0 0.0
+1166 128.521 0.00937581689661 0.0 0.0
+1167 128.631 0.00936220071307 0.0 0.0
+1168 128.741 0.00934866735767 0.0 0.0
+1169 128.851 0.00933521743198 0.0 0.0
+1170 128.962 0.00932184411108 0.0 0.0
+1171 129.072 0.00930854620471 0.0 0.0
+1172 129.182 0.00929532253685 0.0 0.0
+1173 129.292 0.00928216649123 0.0 0.0
+1174 129.402 0.00926907699776 0.0 0.0
+1175 129.513 0.00925605120797 0.0 0.0
+1176 129.623 0.00924308812227 0.0 0.0
+1177 129.733 0.00923018320087 0.0 0.0
+1178 129.843 0.00921733199 0.0 0.0
+1179 129.954 0.00920453543156 0.0 0.0
+1180 130.064 0.0091917874276 0.0 0.0
+1181 130.174 0.00917908901627 0.0 0.0
+1182 130.284 0.00916643425436 0.0 0.0
+1183 130.395 0.00915382253995 0.0 0.0
+1184 130.505 0.00914125331719 0.0 0.0
+1185 130.615 0.00912872087919 0.0 0.0
+1186 130.725 0.00911622481013 0.0 0.0
+1187 130.835 0.00910376302264 0.0 0.0
+1188 130.946 0.00909133521953 0.0 0.0
+1189 131.056 0.00907893773018 0.0 0.0
+1190 131.166 0.00906656697221 0.0 0.0
+1191 131.276 0.0090542228653 0.0 0.0
+1192 131.387 0.00904190368548 0.0 0.0
+1193 131.497 0.00902960948429 0.0 0.0
+1194 131.607 0.00901733528381 0.0 0.0
+1195 131.717 0.00900508128969 0.0 0.0
+1196 131.827 0.00899284777264 0.0 0.0
+1197 131.938 0.00898063000045 0.0 0.0
+1198 132.048 0.00896843008797 0.0 0.0
+1199 132.158 0.00895624346649 0.0 0.0
+1200 132.268 0.00894407071324 0.0 0.0
+1201 132.379 0.00893191247436 0.0 0.0
+1202 132.489 0.00891976442517 0.0 0.0
+1203 132.599 0.00890762904846 0.0 0.0
+1204 132.709 0.00889550385817 0.0 0.0
+1205 132.819 0.00888338645263 0.0 0.0
+1206 132.93 0.00887127786323 0.0 0.0
+1207 133.04 0.00885917751812 0.0 0.0
+1208 133.15 0.00884708659456 0.0 0.0
+1209 133.26 0.008835002997 0.0 0.0
+1210 133.371 0.0088229247114 0.0 0.0
+1211 133.481 0.00881085314372 0.0 0.0
+1212 133.591 0.00879878810022 0.0 0.0
+1213 133.701 0.00878673112897 0.0 0.0
+1214 133.811 0.00877467884496 0.0 0.0
+1215 133.922 0.00876263294483 0.0 0.0
+1216 134.032 0.00875059519155 0.0 0.0
+1217 134.142 0.00873856242057 0.0 0.0
+1218 134.252 0.00872653820178 0.0 0.0
+1219 134.363 0.00871451951336 0.0 0.0
+1220 134.473 0.00870250839697 0.0 0.0
+1221 134.583 0.00869050695528 0.0 0.0
+1222 134.693 0.0086785123735 0.0 0.0
+1223 134.803 0.00866652854523 0.0 0.0
+1224 134.914 0.00865455278859 0.0 0.0
+1225 135.024 0.00864258746257 0.0 0.0
+1226 135.134 0.00863063497995 0.0 0.0
+1227 135.244 0.00861869285004 0.0 0.0
+1228 135.355 0.00860676360594 0.0 0.0
+1229 135.465 0.00859484818127 0.0 0.0
+1230 135.575 0.00858294921089 0.0 0.0
+1231 135.685 0.00857106608639 0.0 0.0
+1232 135.795 0.00855919826077 0.0 0.0
+1233 135.906 0.00854735016467 0.0 0.0
+1234 136.016 0.0085355197115 0.0 0.0
+1235 136.126 0.00852370978423 0.0 0.0
+1236 136.236 0.00851192330017 0.0 0.0
+1237 136.347 0.00850015832643 0.0 0.0
+1238 136.457 0.00848841949278 0.0 0.0
+1239 136.567 0.00847670496192 0.0 0.0
+1240 136.677 0.00846501781193 0.0 0.0
+1241 136.787 0.00845336114359 0.0 0.0
+1242 136.898 0.00844173325234 0.0 0.0
+1243 137.008 0.00843013730932 0.0 0.0
+1244 137.118 0.00841857650089 0.0 0.0
+1245 137.228 0.00840704924218 0.0 0.0
+1246 137.339 0.0083955603678 0.0 0.0
+1247 137.449 0.0083841083653 0.0 0.0
+1248 137.559 0.00837269651863 0.0 0.0
+1249 137.669 0.00836132654119 0.0 0.0
+1250 137.779 0.00835000173243 0.0 0.0
+1251 137.89 0.00833872070678 0.0 0.0
+1252 138.0 0.00832748835285 0.0 0.0
+1253 138.11 0.00831630333951 0.0 0.0
+1254 138.22 0.00830516901353 0.0 0.0
+1255 138.331 0.00829408870756 0.0 0.0
+1256 138.441 0.00828306116084 0.0 0.0
+1257 138.551 0.0082720897213 0.0 0.0
+1258 138.661 0.00826117771457 0.0 0.0
+1259 138.771 0.00825032393673 0.0 0.0
+1260 138.882 0.00823953320944 0.0 0.0
+1261 138.992 0.00822880435927 0.0 0.0
+1262 139.102 0.00821814216627 0.0 0.0
+1263 139.212 0.00820754548162 0.0 0.0
+1264 139.323 0.00819701903393 0.0 0.0
+1265 139.433 0.00818656169326 0.0 0.0
+1266 139.543 0.00817617669062 0.0 0.0
+1267 139.653 0.00816586721057 0.0 0.0
+1268 139.764 0.00815563214087 0.0 0.0
+1269 139.874 0.00814547463443 0.0 0.0
+1270 139.984 0.00813539779005 0.0 0.0
+1271 140.094 0.00812540050081 0.0 0.0
+1272 140.204 0.00811548719427 0.0 0.0
+1273 140.315 0.00810565676041 0.0 0.0
+1274 140.425 0.00809591218089 0.0 0.0
+1275 140.535 0.0080862563711 0.0 0.0
+1276 140.645 0.00807668820684 0.0 0.0
+1277 140.756 0.00806721054362 0.0 0.0
+1278 140.866 0.00805782486563 0.0 0.0
+1279 140.976 0.00804853390735 0.0 0.0
+1280 141.086 0.00803933778103 0.0 0.0
+1281 141.196 0.00803023660225 0.0 0.0
+1282 141.307 0.00802123298026 0.0 0.0
+1283 141.417 0.00801232820921 0.0 0.0
+1284 141.527 0.00800352475876 0.0 0.0
+1285 141.637 0.00799482260329 0.0 0.0
+1286 141.748 0.00798622171613 0.0 0.0
+1287 141.858 0.00797772559524 0.0 0.0
+1288 141.968 0.00796933295751 0.0 0.0
+1289 142.078 0.00796104600089 0.0 0.0
+1290 142.188 0.00795286682784 0.0 0.0
+1291 142.299 0.00794479409372 0.0 0.0
+1292 142.409 0.00793683090163 0.0 0.0
+1293 142.519 0.00792897586192 0.0 0.0
+1294 142.629 0.00792123083938 0.0 0.0
+1295 142.74 0.00791359759674 0.0 0.0
+1296 142.85 0.00790607467157 0.0 0.0
+1297 142.96 0.00789866371627 0.0 0.0
+1298 143.07 0.00789136526851 0.0 0.0
+1299 143.18 0.00788418080208 0.0 0.0
+1300 143.291 0.00787710972731 0.0 0.0
+1301 143.401 0.00787015144409 0.0 0.0
+1302 143.511 0.007863307235 0.0 0.0
+1303 143.621 0.00785657734283 0.0 0.0
+1304 143.732 0.00784996286492 0.0 0.0
+1305 143.842 0.00784346209127 0.0 0.0
+1306 143.952 0.00783707688193 0.0 0.0
+1307 144.062 0.00783080633522 0.0 0.0
+1308 144.172 0.00782464953676 0.0 0.0
+1309 144.283 0.00781860723072 0.0 0.0
+1310 144.393 0.00781267923054 0.0 0.0
+1311 144.503 0.00780686609188 0.0 0.0
+1312 144.613 0.0078011666831 0.0 0.0
+1313 144.724 0.00779557985906 0.0 0.0
+1314 144.834 0.0077901059752 0.0 0.0
+1315 144.944 0.00778474453562 0.0 0.0
+1316 145.054 0.00777949570911 0.0 0.0
+1317 145.164 0.00777435742382 0.0 0.0
+1318 145.275 0.00776932972764 0.0 0.0
+1319 145.385 0.007764412561 0.0 0.0
+1320 145.495 0.00775960376251 0.0 0.0
+1321 145.605 0.00775490380419 0.0 0.0
+1322 145.716 0.00775031046618 0.0 0.0
+1323 145.826 0.00774582342271 0.0 0.0
+1324 145.936 0.00774144224506 0.0 0.0
+1325 146.046 0.00773716462817 0.0 0.0
+1326 146.156 0.00773299003062 0.0 0.0
+1327 146.267 0.00772891781172 0.0 0.0
+1328 146.377 0.00772494558497 0.0 0.0
+1329 146.487 0.00772107313741 0.0 0.0
+1330 146.597 0.00771729803082 0.0 0.0
+1331 146.708 0.00771361938365 0.0 0.0
+1332 146.818 0.00771003622244 0.0 0.0
+1333 146.928 0.00770654603578 0.0 0.0
+1334 147.038 0.00770314822197 0.0 0.0
+1335 147.148 0.00769984022414 0.0 0.0
+1336 147.259 0.0076966208503 0.0 0.0
+1337 147.369 0.00769348839226 0.0 0.0
+1338 147.479 0.00769044151909 0.0 0.0
+1339 147.589 0.00768747759179 0.0 0.0
+1340 147.7 0.00768459559422 0.0 0.0
+1341 147.81 0.00768179246346 0.0 0.0
+1342 147.92 0.00767906783556 0.0 0.0
+1343 148.03 0.00767641898074 0.0 0.0
+1344 148.141 0.00767384355347 0.0 0.0
+1345 148.251 0.00767134024299 0.0 0.0
+1346 148.361 0.0076689059624 0.0 0.0
+1347 148.471 0.00766653997114 0.0 0.0
+1348 148.581 0.00766423947675 0.0 0.0
+1349 148.692 0.00766200202329 0.0 0.0
+1350 148.802 0.00765982605709 0.0 0.0
+1351 148.912 0.00765770848428 0.0 0.0
+1352 149.022 0.00765564825564 0.0 0.0
+1353 149.133 0.00765364226382 0.0 0.0
+1354 149.243 0.00765168880089 0.0 0.0
+1355 149.353 0.00764978530736 0.0 0.0
+1356 149.463 0.00764792897159 0.0 0.0
+1357 149.573 0.00764611875876 0.0 0.0
+1358 149.684 0.00764435108275 0.0 0.0
+1359 149.794 0.00764262434639 0.0 0.0
+1360 149.904 0.00764093595789 0.0 0.0
+1361 150.014 0.00763928310539 0.0 0.0
+1362 150.125 0.00763766434334 0.0 0.0
+1363 150.235 0.00763607662945 0.0 0.0
+1364 150.345 0.00763451803616 0.0 0.0
+1365 150.455 0.00763298576386 0.0 0.0
+1366 150.565 0.00763147766172 0.0 0.0
+1367 150.676 0.007629991366 0.0 0.0
+1368 150.786 0.00762852472074 0.0 0.0
+1369 150.896 0.00762707516813 0.0 0.0
+1370 151.006 0.00762564016624 0.0 0.0
+1371 151.117 0.00762421758235 0.0 0.0
+1372 151.227 0.00762280509492 0.0 0.0
+1373 151.337 0.0076214005905 0.0 0.0
+1374 151.447 0.00762000158152 0.0 0.0
+1375 151.557 0.00761860560028 0.0 0.0
+1376 151.668 0.0076172105847 0.0 0.0
+1377 151.778 0.00761581429959 0.0 0.0
+1378 151.888 0.00761441472586 0.0 0.0
+1379 151.998 0.00761300928736 0.0 0.0
+1380 152.109 0.00761159621068 0.0 0.0
+1381 152.219 0.00761017277229 0.0 0.0
+1382 152.329 0.00760873765422 0.0 0.0
+1383 152.439 0.00760728838676 0.0 0.0
+1384 152.549 0.00760582272402 0.0 0.0
+1385 152.66 0.00760433885714 0.0 0.0
+1386 152.77 0.00760283481176 0.0 0.0
+1387 152.88 0.00760130886146 0.0 0.0
+1388 152.99 0.00759975868443 0.0 0.0
+1389 153.101 0.00759818285051 0.0 0.0
+1390 153.211 0.00759657910491 0.0 0.0
+1391 153.321 0.00759494588995 0.0 0.0
+1392 153.431 0.0075932817037 0.0 0.0
+1393 153.541 0.0075915843983 0.0 0.0
+1394 153.652 0.0075898528032 0.0 0.0
+1395 153.762 0.00758808460131 0.0 0.0
+1396 153.872 0.00758627922753 0.0 0.0
+1397 153.982 0.00758443469795 0.0 0.0
+1398 154.093 0.00758254930872 0.0 0.0
+1399 154.203 0.00758062219095 0.0 0.0
+1400 154.313 0.00757865120052 0.0 0.0
+1401 154.423 0.00757663614507 0.0 0.0
+1402 154.533 0.00757457496503 0.0 0.0
+1403 154.644 0.00757246705859 0.0 0.0
+1404 154.754 0.00757031102464 0.0 0.0
+1405 154.864 0.00756810519507 0.0 0.0
+1406 154.974 0.00756584979163 0.0 0.0
+1407 155.085 0.00756354294385 0.0 0.0
+1408 155.195 0.00756118440992 0.0 0.0
+1409 155.305 0.00755877271662 0.0 0.0
+1410 155.415 0.00755630743165 0.0 0.0
+1411 155.525 0.00755378820601 0.0 0.0
+1412 155.636 0.0075512140628 0.0 0.0
+1413 155.746 0.00754858442911 0.0 0.0
+1414 155.856 0.00754589842331 0.0 0.0
+1415 155.966 0.0075431559628 0.0 0.0
+1416 156.077 0.00754035705133 0.0 0.0
+1417 156.187 0.00753750059414 0.0 0.0
+1418 156.297 0.0075345871262 0.0 0.0
+1419 156.407 0.00753161564891 0.0 0.0
+1420 156.517 0.00752858643813 0.0 0.0
+1421 156.628 0.00752549943019 0.0 0.0
+1422 156.738 0.00752235506051 0.0 0.0
+1423 156.848 0.00751915296587 0.0 0.0
+1424 156.958 0.00751589282357 0.0 0.0
+1425 157.069 0.00751257526924 0.0 0.0
+1426 157.179 0.00750920055839 0.0 0.0
+1427 157.289 0.0075057694844 0.0 0.0
+1428 157.399 0.00750228147878 0.0 0.0
+1429 157.509 0.00749873795119 0.0 0.0
+1430 157.62 0.00749513792865 0.0 0.0
+1431 157.73 0.00749148397187 0.0 0.0
+1432 157.84 0.00748777571229 0.0 0.0
+1433 157.95 0.00748401331858 0.0 0.0
+1434 158.061 0.00748019858139 0.0 0.0
+1435 158.171 0.00747633071777 0.0 0.0
+1436 158.281 0.00747241273575 0.0 0.0
+1437 158.391 0.00746844448822 0.0 0.0
+1438 158.502 0.00746442640059 0.0 0.0
+1439 158.612 0.00746036062253 0.0 0.0
+1440 158.722 0.0074562465518 0.0 0.0
+1441 158.832 0.00745208761264 0.0 0.0
+1442 158.942 0.00744788328361 0.0 0.0
+1443 159.053 0.00744363598062 0.0 0.0
+1444 159.163 0.00743934642432 0.0 0.0
+1445 159.273 0.00743501476948 0.0 0.0
+1446 159.383 0.00743064481608 0.0 0.0
+1447 159.494 0.00742623620384 0.0 0.0
+1448 159.604 0.00742179164922 0.0 0.0
+1449 159.714 0.00741731084303 0.0 0.0
+1450 159.824 0.00741279785086 0.0 0.0
+1451 159.934 0.00740825243009 0.0 0.0
+1452 160.045 0.00740367750762 0.0 0.0
+1453 160.155 0.00739907416202 0.0 0.0
+1454 160.265 0.00739444285865 0.0 0.0
+1455 160.375 0.00738978794486 0.0 0.0
+1456 160.486 0.00738510930917 0.0 0.0
+1457 160.596 0.0073804100993 0.0 0.0
+1458 160.706 0.00737569155182 0.0 0.0
+1459 160.816 0.00737095427157 0.0 0.0
+1460 160.926 0.00736620282566 0.0 0.0
+1461 161.037 0.00736143721436 0.0 0.0
+1462 161.147 0.00735666075463 0.0 0.0
+1463 161.257 0.00735187414587 0.0 0.0
+1464 161.367 0.00734708009416 0.0 0.0
+1465 161.478 0.00734228066458 0.0 0.0
+1466 161.588 0.00733747860557 0.0 0.0
+1467 161.698 0.00733267601781 0.0 0.0
+1468 161.808 0.00732787302339 0.0 0.0
+1469 161.918 0.00732307308366 0.0 0.0
+1470 162.029 0.00731827834101 0.0 0.0
+1471 162.139 0.00731349161023 0.0 0.0
+1472 162.249 0.00730871438768 0.0 0.0
+1473 162.359 0.00730394818113 0.0 0.0
+1474 162.47 0.0072991958245 0.0 0.0
+1475 162.58 0.00729445949274 0.0 0.0
+1476 162.69 0.00728974201458 0.0 0.0
+1477 162.8 0.00728504425905 0.0 0.0
+1478 162.91 0.00728036969912 0.0 0.0
+1479 163.021 0.00727571920873 0.0 0.0
+1480 163.131 0.00727109559753 0.0 0.0
+1481 163.241 0.00726650165511 0.0 0.0
+1482 163.351 0.00726193825355 0.0 0.0
+1483 163.462 0.00725740878843 0.0 0.0
+1484 163.572 0.00725291350281 0.0 0.0
+1485 163.682 0.00724845698887 0.0 0.0
+1486 163.792 0.00724404008781 0.0 0.0
+1487 163.902 0.00723966426195 0.0 0.0
+1488 164.013 0.00723533276982 0.0 0.0
+1489 164.123 0.00723104584417 0.0 0.0
+1490 164.233 0.00722680785915 0.0 0.0
+1491 164.343 0.00722261902288 0.0 0.0
+1492 164.454 0.00721848244273 0.0 0.0
+1493 164.564 0.00721439945706 0.0 0.0
+1494 164.674 0.00721037083935 0.0 0.0
+1495 164.784 0.00720640067553 0.0 0.0
+1496 164.894 0.00720248913024 0.0 0.0
+1497 165.005 0.00719863907256 0.0 0.0
+1498 165.115 0.00719485118581 0.0 0.0
+1499 165.225 0.00719112771416 0.0 0.0
+1500 165.335 0.00718747083433 0.0 0.0
+1501 165.446 0.00718388116298 0.0 0.0
+1502 165.556 0.00718036128007 0.0 0.0
+1503 165.666 0.00717691175294 0.0 0.0
+1504 165.776 0.00717353456555 0.0 0.0
+1505 165.887 0.00717023116717 0.0 0.0
+1506 165.997 0.00716700340536 0.0 0.0
+1507 166.107 0.00716385217379 0.0 0.0
+1508 166.217 0.0071607783477 0.0 0.0
+1509 166.327 0.00715778361235 0.0 0.0
+1510 166.438 0.0071548691633 0.0 0.0
+1511 166.548 0.00715203653382 0.0 0.0
+1512 166.658 0.0071492860257 0.0 0.0
+1513 166.768 0.0071466190612 0.0 0.0
+1514 166.879 0.00714403661288 0.0 0.0
+1515 166.989 0.00714153994056 0.0 0.0
+1516 167.099 0.00713912954174 0.0 0.0
+1517 167.209 0.00713680589029 0.0 0.0
+1518 167.319 0.00713457005481 0.0 0.0
+1519 167.43 0.00713242270853 0.0 0.0
+1520 167.54 0.00713036474721 0.0 0.0
+1521 167.65 0.00712839642157 0.0 0.0
+1522 167.76 0.00712651795649 0.0 0.0
+1523 167.871 0.00712473029274 0.0 0.0
+1524 167.981 0.0071230332916 0.0 0.0
+1525 168.091 0.00712142771416 0.0 0.0
+1526 168.201 0.00711991355121 0.0 0.0
+1527 168.311 0.00711849076605 0.0 0.0
+1528 168.422 0.0071171596625 0.0 0.0
+1529 168.532 0.00711592026826 0.0 0.0
+1530 168.642 0.00711477270325 0.0 0.0
+1531 168.752 0.00711371654415 0.0 0.0
+1532 168.863 0.00711275191099 0.0 0.0
+1533 168.973 0.00711187817652 0.0 0.0
+1534 169.083 0.00711109551831 0.0 0.0
+1535 169.193 0.00711040332133 0.0 0.0
+1536 169.303 0.00710980106249 0.0 0.0
+1537 169.414 0.00710928840212 0.0 0.0
+1538 169.524 0.00710886456669 0.0 0.0
+1539 169.634 0.00710852915182 0.0 0.0
+1540 169.744 0.00710828130087 0.0 0.0
+1541 169.855 0.00710812031195 0.0 0.0
+1542 169.965 0.00710804531508 0.0 0.0
+1543 170.075 0.00710805541265 0.0 0.0
+1544 170.185 0.00710814963445 0.0 0.0
+1545 170.295 0.0071083269795 0.0 0.0
+1546 170.406 0.00710858630729 0.0 0.0
+1547 170.516 0.0071089264885 0.0 0.0
+1548 170.626 0.00710934642367 0.0 0.0
+1549 170.736 0.00710984460359 0.0 0.0
+1550 170.847 0.00711041988723 0.0 0.0
+1551 170.957 0.00711107071889 0.0 0.0
+1552 171.067 0.00711179582363 0.0 0.0
+1553 171.177 0.00711259359843 0.0 0.0
+1554 171.287 0.00711346247374 0.0 0.0
+1555 171.398 0.00711440069452 0.0 0.0
+1556 171.508 0.00711540670148 0.0 0.0
+1557 171.618 0.00711647890976 0.0 0.0
+1558 171.728 0.00711761539408 0.0 0.0
+1559 171.839 0.00711881431731 0.0 0.0
+1560 171.949 0.00712007361801 0.0 0.0
+1561 172.059 0.00712139170884 0.0 0.0
+1562 172.169 0.00712276624165 0.0 0.0
+1563 172.279 0.00712419556728 0.0 0.0
+1564 172.39 0.00712567742072 0.0 0.0
+1565 172.5 0.00712720947195 0.0 0.0
+1566 172.61 0.00712878998512 0.0 0.0
+1567 172.72 0.00713041632231 0.0 0.0
+1568 172.831 0.00713208692519 0.0 0.0
+1569 172.941 0.00713379859186 0.0 0.0
+1570 173.051 0.00713554947208 0.0 0.0
+1571 173.161 0.00713733746576 0.0 0.0
+1572 173.271 0.0071391596976 0.0 0.0
+1573 173.382 0.00714101451691 0.0 0.0
+1574 173.492 0.00714289845575 0.0 0.0
+1575 173.602 0.00714480982337 0.0 0.0
+1576 173.712 0.00714674559549 0.0 0.0
+1577 173.823 0.00714870378816 0.0 0.0
+1578 173.933 0.00715068131693 0.0 0.0
+1579 174.043 0.00715267588974 0.0 0.0
+1580 174.153 0.00715468520204 0.0 0.0
+1581 174.263 0.00715670609762 0.0 0.0
+1582 174.374 0.00715873652013 0.0 0.0
+1583 174.484 0.00716077355987 0.0 0.0
+1584 174.594 0.00716281429278 0.0 0.0
+1585 174.704 0.00716485663205 0.0 0.0
+1586 174.815 0.00716689735245 0.0 0.0
+1587 174.925 0.0071689346342 0.0 0.0
+1588 175.035 0.00717096467852 0.0 0.0
+1589 175.145 0.00717298537612 0.0 0.0
+1590 175.255 0.00717499433041 0.0 0.0
+1591 175.366 0.00717698831171 0.0 0.0
+1592 175.476 0.00717896547458 0.0 0.0
+1593 175.586 0.00718092205845 0.0 0.0
+1594 175.696 0.00718285621918 0.0 0.0
+1595 175.807 0.00718476477034 0.0 0.0
+1596 175.917 0.00718664533916 0.0 0.0
+1597 176.027 0.00718849580902 0.0 0.0
+1598 176.137 0.00719031254087 0.0 0.0
+1599 176.248 0.00719209369488 0.0 0.0
+1600 176.358 0.00719383619673 0.0 0.0
+1601 176.468 0.0071955379668 0.0 0.0
+1602 176.578 0.00719719622275 0.0 0.0
+1603 176.688 0.00719880822361 0.0 0.0
+1604 176.799 0.00720037192251 0.0 0.0
+1605 176.909 0.00720188442014 0.0 0.0
+1606 177.019 0.00720334369676 0.0 0.0
+1607 177.129 0.00720474713422 0.0 0.0
+1608 177.24 0.00720609235546 0.0 0.0
+1609 177.35 0.00720737683898 0.0 0.0
+1610 177.46 0.00720859846249 0.0 0.0
+1611 177.57 0.00720975511387 0.0 0.0
+1612 177.68 0.00721084438952 0.0 0.0
+1613 177.791 0.00721186409471 0.0 0.0
+1614 177.901 0.00721281194472 0.0 0.0
+1615 178.011 0.00721368609108 0.0 0.0
+1616 178.121 0.00721448422523 0.0 0.0
+1617 178.232 0.00721520464657 0.0 0.0
+1618 178.342 0.00721584498221 0.0 0.0
+1619 178.452 0.00721640350597 0.0 0.0
+1620 178.562 0.00721687840746 0.0 0.0
+1621 178.672 0.00721726773009 0.0 0.0
+1622 178.783 0.00721756985026 0.0 0.0
+1623 178.893 0.00721778288121 0.0 0.0
+1624 179.003 0.00721790524173 0.0 0.0
+1625 179.113 0.00721793532681 0.0 0.0
+1626 179.224 0.00721787157582 0.0 0.0
+1627 179.334 0.00721771245451 0.0 0.0
+1628 179.444 0.00721745661553 0.0 0.0
+1629 179.554 0.00721710259027 0.0 0.0
+1630 179.664 0.00721664916201 0.0 0.0
+1631 179.775 0.00721609502872 0.0 0.0
+1632 179.885 0.00721543881843 0.0 0.0
+1633 179.995 0.00721467987242 0.0 0.0
+1634 180.105 0.00721381661635 0.0 0.0
+1635 180.216 0.00721284839625 0.0 0.0
+1636 180.326 0.00721177386264 0.0 0.0
+1637 180.436 0.00721059274384 0.0 0.0
+1638 180.546 0.00720930394232 0.0 0.0
+1639 180.656 0.00720790653199 0.0 0.0
+1640 180.767 0.0072064002346 0.0 0.0
+1641 180.877 0.00720478381231 0.0 0.0
+1642 180.987 0.00720305763136 0.0 0.0
+1643 181.097 0.00720122052989 0.0 0.0
+1644 181.208 0.00719927262553 0.0 0.0
+1645 181.318 0.00719721334204 0.0 0.0
+1646 181.428 0.00719504182624 0.0 0.0
+1647 181.538 0.00719275909743 0.0 0.0
+1648 181.648 0.00719036410941 0.0 0.0
+1649 181.759 0.0071878574814 0.0 0.0
+1650 181.869 0.00718523890735 0.0 0.0
+1651 181.979 0.00718250772679 0.0 0.0
+1652 182.089 0.00717966561622 0.0 0.0
+1653 182.2 0.007176711644 0.0 0.0
+1654 182.31 0.00717364693034 0.0 0.0
+1655 182.42 0.00717047099768 0.0 0.0
+1656 182.53 0.00716718470987 0.0 0.0
+1657 182.64 0.00716378857408 0.0 0.0
+1658 182.751 0.00716028364985 0.0 0.0
+1659 182.861 0.00715667010822 0.0 0.0
+1660 182.971 0.0071529481421 0.0 0.0
+1661 183.081 0.00714911902586 0.0 0.0
+1662 183.192 0.00714518359849 0.0 0.0
+1663 183.302 0.00714114332254 0.0 0.0
+1664 183.412 0.00713699804661 0.0 0.0
+1665 183.522 0.00713274994854 0.0 0.0
+1666 183.632 0.00712839894464 0.0 0.0
+1667 183.743 0.00712394677735 0.0 0.0
+1668 183.853 0.00711939529088 0.0 0.0
+1669 183.963 0.00711474449887 0.0 0.0
+1670 184.073 0.00710999702121 0.0 0.0
+1671 184.184 0.00710515226318 0.0 0.0
+1672 184.294 0.0071002143532 0.0 0.0
+1673 184.404 0.00709518345089 0.0 0.0
+1674 184.514 0.00709006040317 0.0 0.0
+1675 184.624 0.00708484823706 0.0 0.0
+1676 184.735 0.00707954643662 0.0 0.0
+1677 184.845 0.00707415964801 0.0 0.0
+1678 184.955 0.00706868740578 0.0 0.0
+1679 185.065 0.0070631330329 0.0 0.0
+1680 185.176 0.00705749762585 0.0 0.0
+1681 185.286 0.0070517815028 0.0 0.0
+1682 185.396 0.00704598977159 0.0 0.0
+1683 185.506 0.00704012202259 0.0 0.0
+1684 185.617 0.00703418190643 0.0 0.0
+1685 185.727 0.00702816984393 0.0 0.0
+1686 185.837 0.00702208876123 0.0 0.0
+1687 185.947 0.00701594164819 0.0 0.0
+1688 186.057 0.00700972897654 0.0 0.0
+1689 186.168 0.00700345554078 0.0 0.0
+1690 186.278 0.00699711922769 0.0 0.0
+1691 186.388 0.00699072668155 0.0 0.0
+1692 186.498 0.00698427844231 0.0 0.0
+1693 186.609 0.00697777593153 0.0 0.0
+1694 186.719 0.00697122329504 0.0 0.0
+1695 186.829 0.00696462017371 0.0 0.0
+1696 186.939 0.00695797261252 0.0 0.0
+1697 187.049 0.00695128026513 0.0 0.0
+1698 187.16 0.00694454741021 0.0 0.0
+1699 187.27 0.00693777556233 0.0 0.0
+1700 187.38 0.00693096529275 0.0 0.0
+1701 187.49 0.00692412283923 0.0 0.0
+1702 187.601 0.00691724784194 0.0 0.0
+1703 187.711 0.00691034469029 0.0 0.0
+1704 187.821 0.00690341396577 0.0 0.0
+1705 187.931 0.00689645912239 0.0 0.0
+1706 188.041 0.00688948266082 0.0 0.0
+1707 188.152 0.00688248805065 0.0 0.0
+1708 188.262 0.0068754768263 0.0 0.0
+1709 188.372 0.00686845051394 0.0 0.0
+1710 188.482 0.00686141257903 0.0 0.0
+1711 188.593 0.00685436550966 0.0 0.0
+1712 188.703 0.00684731276182 0.0 0.0
+1713 188.813 0.00684025582949 0.0 0.0
+1714 188.923 0.00683319619452 0.0 0.0
+1715 189.033 0.00682613728007 0.0 0.0
+1716 189.144 0.00681908151666 0.0 0.0
+1717 189.254 0.00681203229335 0.0 0.0
+1718 189.364 0.00680499005345 0.0 0.0
+1719 189.474 0.00679795912122 0.0 0.0
+1720 189.585 0.00679093893171 0.0 0.0
+1721 189.695 0.00678393570055 0.0 0.0
+1722 189.805 0.00677694978701 0.0 0.0
+1723 189.915 0.00676998250399 0.0 0.0
+1724 190.025 0.00676303802865 0.0 0.0
+1725 190.136 0.00675611569898 0.0 0.0
+1726 190.246 0.00674922153379 0.0 0.0
+1727 190.356 0.00674235481892 0.0 0.0
+1728 190.466 0.00673551957384 0.0 0.0
+1729 190.577 0.0067287169296 0.0 0.0
+1730 190.687 0.0067219470577 0.0 0.0
+1731 190.797 0.00671521571145 0.0 0.0
+1732 190.907 0.00670852205447 0.0 0.0
+1733 191.017 0.00670186986281 0.0 0.0
+1734 191.128 0.00669526008899 0.0 0.0
+1735 191.238 0.00668869275125 0.0 0.0
+1736 191.348 0.00668217327482 0.0 0.0
+1737 191.458 0.0066757006876 0.0 0.0
+1738 191.569 0.0066692784757 0.0 0.0
+1739 191.679 0.00666290650591 0.0 0.0
+1740 191.789 0.00665658726245 0.0 0.0
+1741 191.899 0.0066503222884 0.0 0.0
+1742 192.009 0.00664411393328 0.0 0.0
+1743 192.12 0.00663796276615 0.0 0.0
+1744 192.23 0.00663187016931 0.0 0.0
+1745 192.34 0.00662583663495 0.0 0.0
+1746 192.45 0.00661986427789 0.0 0.0
+1747 192.561 0.00661395512955 0.0 0.0
+1748 192.671 0.00660810951848 0.0 0.0
+1749 192.781 0.00660232774203 0.0 0.0
+1750 192.891 0.00659661164808 0.0 0.0
+1751 193.001 0.00659096221487 0.0 0.0
+1752 193.112 0.00658538113239 0.0 0.0
+1753 193.222 0.00657986771204 0.0 0.0
+1754 193.332 0.00657442352218 0.0 0.0
+1755 193.442 0.00656905003961 0.0 0.0
+1756 193.553 0.00656374644739 0.0 0.0
+1757 193.663 0.00655851482199 0.0 0.0
+1758 193.773 0.00655335426005 0.0 0.0
+1759 193.883 0.00654826596821 0.0 0.0
+1760 193.994 0.00654325036498 0.0 0.0
+1761 194.104 0.00653830848902 0.0 0.0
+1762 194.214 0.00653343993675 0.0 0.0
+1763 194.324 0.00652864427202 0.0 0.0
+1764 194.434 0.00652392233281 0.0 0.0
+1765 194.545 0.0065192742189 0.0 0.0
+1766 194.655 0.00651470059925 0.0 0.0
+1767 194.765 0.00651020018008 0.0 0.0
+1768 194.875 0.00650577411659 0.0 0.0
+1769 194.986 0.00650142042715 0.0 0.0
+1770 195.096 0.00649714130544 0.0 0.0
+1771 195.206 0.00649293526648 0.0 0.0
+1772 195.316 0.00648880139711 0.0 0.0
+1773 195.426 0.00648474043889 0.0 0.0
+1774 195.537 0.00648075025118 0.0 0.0
+1775 195.647 0.00647683251828 0.0 0.0
+1776 195.757 0.00647298555005 0.0 0.0
+1777 195.867 0.00646920817945 0.0 0.0
+1778 195.978 0.00646550074896 0.0 0.0
+1779 196.088 0.00646186096697 0.0 0.0
+1780 196.198 0.00645829002971 0.0 0.0
+1781 196.308 0.00645478556876 0.0 0.0
+1782 196.418 0.00645134762311 0.0 0.0
+1783 196.529 0.00644797472122 0.0 0.0
+1784 196.639 0.00644466490727 0.0 0.0
+1785 196.749 0.00644141892052 0.0 0.0
+1786 196.859 0.00643823425848 0.0 0.0
+1787 196.97 0.00643511060664 0.0 0.0
+1788 197.08 0.00643204585384 0.0 0.0
+1789 197.19 0.00642903913771 0.0 0.0
+1790 197.3 0.00642608911552 0.0 0.0
+1791 197.41 0.00642319479856 0.0 0.0
+1792 197.521 0.00642035434404 0.0 0.0
+1793 197.631 0.00641756588795 0.0 0.0
+1794 197.741 0.00641482830268 0.0 0.0
+1795 197.851 0.00641214002573 0.0 0.0
+1796 197.962 0.00640949981993 0.0 0.0
+1797 198.072 0.00640690567204 0.0 0.0
+1798 198.182 0.00640435555112 0.0 0.0
+1799 198.292 0.0064018484493 0.0 0.0
+1800 198.402 0.00639938192391 0.0 0.0
+1801 198.513 0.0063969548768 0.0 0.0
+1802 198.623 0.00639456515401 0.0 0.0
+1803 198.733 0.00639221058769 0.0 0.0
+1804 198.843 0.00638988963832 0.0 0.0
+1805 198.954 0.00638760040873 0.0 0.0
+1806 199.064 0.00638534128932 0.0 0.0
+1807 199.174 0.00638310970897 0.0 0.0
+1808 199.284 0.00638090431847 0.0 0.0
+1809 199.394 0.00637872221786 0.0 0.0
+1810 199.505 0.00637656260966 0.0 0.0
+1811 199.615 0.00637442286717 0.0 0.0
+1812 199.725 0.00637230065942 0.0 0.0
+1813 199.835 0.00637019452327 0.0 0.0
+1814 199.946 0.00636810152339 0.0 0.0
diff --git a/test/corfunc/test/idf_out.txt b/test/corfunc/test/idf_out.txt
new file mode 100644
index 0000000..d62b6a8
--- /dev/null
+++ b/test/corfunc/test/idf_out.txt
@@ -0,0 +1,1816 @@
+# <index> <X> <Y> <dY> <dX>
+0 0.0 -0.00197352569561 0.0 0.0
+1 0.110224 0.00464381516819 0.0 0.0
+2 0.220447 0.00464447904948 0.0 0.0
+3 0.330671 0.00464558435577 0.0 0.0
+4 0.440894 0.00464713002044 0.0 0.0
+5 0.551118 0.00464911584599 0.0 0.0
+6 0.661341 0.00465153797316 0.0 0.0
+7 0.771565 0.00465439730637 0.0 0.0
+8 0.881789 0.00465768753139 0.0 0.0
+9 0.992012 0.004661410189 0.0 0.0
+10 1.10224 0.00466555733369 0.0 0.0
+11 1.21246 0.00467012948163 0.0 0.0
+12 1.32268 0.00467511931786 0.0 0.0
+13 1.43291 0.00468052516592 0.0 0.0
+14 1.54313 0.00468633907735 0.0 0.0
+15 1.65335 0.00469256009359 0.0 0.0
+16 1.76358 0.00469917820325 0.0 0.0
+17 1.8738 0.00470619100787 0.0 0.0
+18 1.98402 0.00471359063335 0.0 0.0
+19 2.09425 0.00472137020764 0.0 0.0
+20 2.20447 0.00472952494669 0.0 0.0
+21 2.3147 0.00473804382059 0.0 0.0
+22 2.42492 0.00474692389943 0.0 0.0
+23 2.53514 0.00475615221508 0.0 0.0
+24 2.64537 0.00476572568539 0.0 0.0
+25 2.75559 0.00477563136411 0.0 0.0
+26 2.86581 0.00478586187214 0.0 0.0
+27 2.97604 0.00479641011998 0.0 0.0
+28 3.08626 0.0048072618348 0.0 0.0
+29 3.19648 0.004818412662 0.0 0.0
+30 3.30671 0.00482984773414 0.0 0.0
+31 3.41693 0.00484156083929 0.0 0.0
+32 3.52715 0.00485353586901 0.0 0.0
+33 3.63738 0.00486576928653 0.0 0.0
+34 3.7476 0.00487824224166 0.0 0.0
+35 3.85783 0.00489094868602 0.0 0.0
+36 3.96805 0.00490387385019 0.0 0.0
+37 4.07827 0.00491700874348 0.0 0.0
+38 4.1885 0.00493033534533 0.0 0.0
+39 4.29872 0.0049438509624 0.0 0.0
+40 4.40894 0.0049575304979 0.0 0.0
+41 4.51917 0.00497137368352 0.0 0.0
+42 4.62939 0.00498535725348 0.0 0.0
+43 4.73961 0.00499947449262 0.0 0.0
+44 4.84984 0.00501370894945 0.0 0.0
+45 4.96006 0.00502804647608 0.0 0.0
+46 5.07028 0.00504247783162 0.0 0.0
+47 5.18051 0.00505698156442 0.0 0.0
+48 5.29073 0.00507155143332 0.0 0.0
+49 5.40096 0.00508616686398 0.0 0.0
+50 5.51118 0.00510081808195 0.0 0.0
+51 5.6214 0.00511548782725 0.0 0.0
+52 5.73163 0.0051301621488 0.0 0.0
+53 5.84185 0.00514482855934 0.0 0.0
+54 5.95207 0.00515946684423 0.0 0.0
+55 6.0623 0.00517406957425 0.0 0.0
+56 6.17252 0.00518861554444 0.0 0.0
+57 6.28274 0.00520309223874 0.0 0.0
+58 6.39297 0.00521748596517 0.0 0.0
+59 6.50319 0.00523177922353 0.0 0.0
+60 6.61341 0.00524595700078 0.0 0.0
+61 6.72364 0.00526000691278 0.0 0.0
+62 6.83386 0.00527391169588 0.0 0.0
+63 6.94409 0.00528765441626 0.0 0.0
+64 7.05431 0.00530122493249 0.0 0.0
+65 7.16453 0.00531460284228 0.0 0.0
+66 7.27476 0.00532777687947 0.0 0.0
+67 7.38498 0.00534072977089 0.0 0.0
+68 7.4952 0.00535344775223 0.0 0.0
+69 7.60543 0.00536591519038 0.0 0.0
+70 7.71565 0.00537811651955 0.0 0.0
+71 7.82587 0.00539004067747 0.0 0.0
+72 7.9361 0.00540166647551 0.0 0.0
+73 8.04632 0.00541298575959 0.0 0.0
+74 8.15654 0.00542397923323 0.0 0.0
+75 8.26677 0.0054346373116 0.0 0.0
+76 8.37699 0.00544493860551 0.0 0.0
+77 8.48722 0.00545487868486 0.0 0.0
+78 8.59744 0.00546443293382 0.0 0.0
+79 8.70766 0.00547359725755 0.0 0.0
+80 8.81789 0.00548235055113 0.0 0.0
+81 8.92811 0.00549068332539 0.0 0.0
+82 9.03833 0.00549858284168 0.0 0.0
+83 9.14856 0.00550603124259 0.0 0.0
+84 9.25878 0.00551302199341 0.0 0.0
+85 9.369 0.00551953709134 0.0 0.0
+86 9.47923 0.00552556776331 0.0 0.0
+87 9.58945 0.00553109886472 0.0 0.0
+88 9.69968 0.00553611986598 0.0 0.0
+89 9.8099 0.00554062133665 0.0 0.0
+90 9.92012 0.00554458313167 0.0 0.0
+91 10.0303 0.00554800922928 0.0 0.0
+92 10.1406 0.00555086885308 0.0 0.0
+93 10.2508 0.00555317243864 0.0 0.0
+94 10.361 0.0055548887675 0.0 0.0
+95 10.4712 0.00555602707489 0.0 0.0
+96 10.5815 0.00555656143601 0.0 0.0
+97 10.6917 0.00555649235824 0.0 0.0
+98 10.8019 0.00555580777072 0.0 0.0
+99 10.9121 0.00555449443372 0.0 0.0
+100 11.0224 0.00555255338042 0.0 0.0
+101 11.1326 0.00554996430084 0.0 0.0
+102 11.2428 0.00554673021838 0.0 0.0
+103 11.353 0.00554283581816 0.0 0.0
+104 11.4633 0.005538276587 0.0 0.0
+105 11.5735 0.00553304825835 0.0 0.0
+106 11.6837 0.00552713714602 0.0 0.0
+107 11.7939 0.00552054521497 0.0 0.0
+108 11.9041 0.00551326139132 0.0 0.0
+109 12.0144 0.00550527925981 0.0 0.0
+110 12.1246 0.00549660085878 0.0 0.0
+111 12.2348 0.00548721006904 0.0 0.0
+112 12.345 0.00547711481881 0.0 0.0
+113 12.4553 0.00546630005315 0.0 0.0
+114 12.5655 0.00545477107638 0.0 0.0
+115 12.6757 0.00544251749932 0.0 0.0
+116 12.7859 0.00542954171922 0.0 0.0
+117 12.8962 0.0054158374658 0.0 0.0
+118 13.0064 0.0054014060736 0.0 0.0
+119 13.1166 0.00538624201558 0.0 0.0
+120 13.2268 0.00537034730896 0.0 0.0
+121 13.3371 0.00535371976667 0.0 0.0
+122 13.4473 0.0053363569075 0.0 0.0
+123 13.5575 0.00531826318396 0.0 0.0
+124 13.6677 0.00529943451446 0.0 0.0
+125 13.7779 0.00527987285224 0.0 0.0
+126 13.8882 0.00525958066312 0.0 0.0
+127 13.9984 0.00523855828496 0.0 0.0
+128 14.1086 0.00521680623347 0.0 0.0
+129 14.2188 0.00519433033363 0.0 0.0
+130 14.3291 0.00517112883237 0.0 0.0
+131 14.4393 0.00514720935772 0.0 0.0
+132 14.5495 0.0051225702624 0.0 0.0
+133 14.6597 0.00509722092772 0.0 0.0
+134 14.77 0.00507116077254 0.0 0.0
+135 14.8802 0.00504439668159 0.0 0.0
+136 14.9904 0.00501693490026 0.0 0.0
+137 15.1006 0.0049887768211 0.0 0.0
+138 15.2109 0.00495993274121 0.0 0.0
+139 15.3211 0.00493040496591 0.0 0.0
+140 15.4313 0.00490020389566 0.0 0.0
+141 15.5415 0.0048693311272 0.0 0.0
+142 15.6517 0.00483780055517 0.0 0.0
+143 15.762 0.00480561264516 0.0 0.0
+144 15.8722 0.00477278191791 0.0 0.0
+145 15.9824 0.00473931186128 0.0 0.0
+146 16.0926 0.00470521286828 0.0 0.0
+147 16.2029 0.00467049633184 0.0 0.0
+148 16.3131 0.0046351648384 0.0 0.0
+149 16.4233 0.00459923801732 0.0 0.0
+150 16.5335 0.00456271476758 0.0 0.0
+151 16.6438 0.00452561550893 0.0 0.0
+152 16.754 0.00448794305025 0.0 0.0
+153 16.8642 0.00444971405631 0.0 0.0
+154 16.9744 0.0044109348052 0.0 0.0
+155 17.0847 0.00437162211421 0.0 0.0
+156 17.1949 0.00433178194137 0.0 0.0
+157 17.3051 0.00429143264743 0.0 0.0
+158 17.4153 0.00425058029054 0.0 0.0
+159 17.5255 0.00420924377553 0.0 0.0
+160 17.6358 0.00416742981329 0.0 0.0
+161 17.746 0.00412515763811 0.0 0.0
+162 17.8562 0.00408243490118 0.0 0.0
+163 17.9664 0.00403928030288 0.0 0.0
+164 18.0767 0.0039957041328 0.0 0.0
+165 18.1869 0.00395172284911 0.0 0.0
+166 18.2971 0.00390734739122 0.0 0.0
+167 18.4073 0.00386259888939 0.0 0.0
+168 18.5176 0.00381748314015 0.0 0.0
+169 18.6278 0.00377202279697 0.0 0.0
+170 18.738 0.0037262291714 0.0 0.0
+171 18.8482 0.00368011741601 0.0 0.0
+172 18.9585 0.00363370423244 0.0 0.0
+173 19.0687 0.00358700601994 0.0 0.0
+174 19.1789 0.00354003477508 0.0 0.0
+175 19.2891 0.00349281091552 0.0 0.0
+176 19.3994 0.00344534680569 0.0 0.0
+177 19.5096 0.00339766176408 0.0 0.0
+178 19.6198 0.0033497682822 0.0 0.0
+179 19.73 0.0033016862877 0.0 0.0
+180 19.8402 0.00325343006346 0.0 0.0
+181 19.9505 0.00320501594018 0.0 0.0
+182 20.0607 0.0031564625399 0.0 0.0
+183 20.1709 0.00310778390895 0.0 0.0
+184 20.2811 0.00305899822034 0.0 0.0
+185 20.3914 0.00301012180903 0.0 0.0
+186 20.5016 0.00296117224967 0.0 0.0
+187 20.6118 0.00291216367744 0.0 0.0
+188 20.722 0.00286311682516 0.0 0.0
+189 20.8323 0.00281404459517 0.0 0.0
+190 20.9425 0.00276496683615 0.0 0.0
+191 21.0527 0.00271589868618 0.0 0.0
+192 21.1629 0.00266685475653 0.0 0.0
+193 21.2732 0.00261786062767 0.0 0.0
+194 21.3834 0.00256891723678 0.0 0.0
+195 21.4936 0.00252005991236 0.0 0.0
+196 21.6038 0.00247128766111 0.0 0.0
+197 21.714 0.00242263234455 0.0 0.0
+198 21.8243 0.00237409612535 0.0 0.0
+199 21.9345 0.00232570860013 0.0 0.0
+200 22.0447 0.00227747364176 0.0 0.0
+201 22.1549 0.00222942010486 0.0 0.0
+202 22.2652 0.00218154975533 0.0 0.0
+203 22.3754 0.00213389310261 0.0 0.0
+204 22.4856 0.00208645255972 0.0 0.0
+205 22.5958 0.00203925477231 0.0 0.0
+206 22.7061 0.0019923067529 0.0 0.0
+207 22.8163 0.00194562985421 0.0 0.0
+208 22.9265 0.00189923411223 0.0 0.0
+209 23.0367 0.00185313987157 0.0 0.0
+210 23.147 0.0018073566881 0.0 0.0
+211 23.2572 0.00176190184499 0.0 0.0
+212 23.3674 0.00171679104989 0.0 0.0
+213 23.4776 0.00167203357507 0.0 0.0
+214 23.5878 0.00162765040944 0.0 0.0
+215 23.6981 0.00158364742314 0.0 0.0
+216 23.8083 0.00154004469216 0.0 0.0
+217 23.9185 0.00149685233247 0.0 0.0
+218 24.0287 0.00145408315486 0.0 0.0
+219 24.139 0.0014117513333 0.0 0.0
+220 24.2492 0.0013698680478 0.0 0.0
+221 24.3594 0.00132844770479 0.0 0.0
+222 24.4696 0.00128749765871 0.0 0.0
+223 24.5799 0.00124703778836 0.0 0.0
+224 24.6901 0.00120706794285 0.0 0.0
+225 24.8003 0.00116761318635 0.0 0.0
+226 24.9105 0.00112866943244 0.0 0.0
+227 25.0208 0.00109026131845 0.0 0.0
+228 25.131 0.00105238842288 0.0 0.0
+229 25.2412 0.00101506700192 0.0 0.0
+230 25.3514 0.000978303267492 0.0 0.0
+231 25.4616 0.000942108490229 0.0 0.0
+232 25.5719 0.000906491767773 0.0 0.0
+233 25.6821 0.000871459093189 0.0 0.0
+234 25.7923 0.000837023018581 0.0 0.0
+235 25.9025 0.000803187346363 0.0 0.0
+236 26.0128 0.000769963656803 0.0 0.0
+237 26.123 0.000737355906992 0.0 0.0
+238 26.2332 0.000705373713192 0.0 0.0
+239 26.3434 0.000674021129137 0.0 0.0
+240 26.4537 0.000643309121841 0.0 0.0
+241 26.5639 0.000613236021888 0.0 0.0
+242 26.6741 0.000583816787571 0.0 0.0
+243 26.7843 0.000555048511493 0.0 0.0
+244 26.8946 0.000526941568605 0.0 0.0
+245 27.0048 0.000499496479545 0.0 0.0
+246 27.115 0.000472722533669 0.0 0.0
+247 27.2252 0.000446616889176 0.0 0.0
+248 27.3354 0.000421190703634 0.0 0.0
+249 27.4457 0.000396439046118 0.0 0.0
+250 27.5559 0.000372372410713 0.0 0.0
+251 27.6661 0.000348987109401 0.0 0.0
+252 27.7763 0.00032628923271 0.0 0.0
+253 27.8866 0.00030427827279 0.0 0.0
+254 27.9968 0.000282956351342 0.0 0.0
+255 28.107 0.000262324548942 0.0 0.0
+256 28.2172 0.000242384022883 0.0 0.0
+257 28.3275 0.000223132846754 0.0 0.0
+258 28.4377 0.00020457413375 0.0 0.0
+259 28.5479 0.000186705008719 0.0 0.0
+260 28.6581 0.000169525725402 0.0 0.0
+261 28.7684 0.000153035271427 0.0 0.0
+262 28.8786 0.000137231605555 0.0 0.0
+263 28.9888 0.000122113562997 0.0 0.0
+264 29.099 0.000107677598282 0.0 0.0
+265 29.2093 9.39254124201e-05 0.0 0.0
+266 29.3195 8.08461019425e-05 0.0 0.0
+267 29.4297 6.84464680022e-05 0.0 0.0
+268 29.5399 5.67156811816e-05 0.0 0.0
+269 29.6501 4.56512907554e-05 0.0 0.0
+270 29.7604 3.52541540529e-05 0.0 0.0
+271 29.8706 2.55105295553e-05 0.0 0.0
+272 29.9808 1.64265701122e-05 0.0 0.0
+273 30.091 7.98745751591e-06 0.0 0.0
+274 30.2013 1.94385602979e-07 0.0 0.0
+275 30.3115 -6.96065708274e-06 0.0 0.0
+276 30.4217 -1.34851305438e-05 0.0 0.0
+277 30.5319 -1.93818548434e-05 0.0 0.0
+278 30.6422 -2.46594406869e-05 0.0 0.0
+279 30.7524 -2.93263292071e-05 0.0 0.0
+280 30.8626 -3.33847859855e-05 0.0 0.0
+281 30.9728 -3.68471561421e-05 0.0 0.0
+282 31.0831 -3.97187303623e-05 0.0 0.0
+283 31.1933 -4.20056113167e-05 0.0 0.0
+284 31.3035 -4.37221345433e-05 0.0 0.0
+285 31.4137 -4.48658633525e-05 0.0 0.0
+286 31.5239 -4.54595736073e-05 0.0 0.0
+287 31.6342 -4.54980938583e-05 0.0 0.0
+288 31.7444 -4.49997445227e-05 0.0 0.0
+289 31.8546 -4.3971281182e-05 0.0 0.0
+290 31.9648 -4.24194641295e-05 0.0 0.0
+291 32.0751 -4.03590746377e-05 0.0 0.0
+292 32.1853 -3.77943870933e-05 0.0 0.0
+293 32.2955 -3.47404088947e-05 0.0 0.0
+294 32.4057 -3.12044942464e-05 0.0 0.0
+295 32.516 -2.71968949547e-05 0.0 0.0
+296 32.6262 -2.27311792665e-05 0.0 0.0
+297 32.7364 -1.78135266217e-05 0.0 0.0
+298 32.8466 -1.24596710564e-05 0.0 0.0
+299 32.9569 -6.67737554113e-06 0.0 0.0
+300 33.0671 -4.7787004209e-07 0.0 0.0
+301 33.1773 6.12410407991e-06 0.0 0.0
+302 33.2875 1.31220066789e-05 0.0 0.0
+303 33.3977 2.05002359967e-05 0.0 0.0
+304 33.508 2.824905125e-05 0.0 0.0
+305 33.6182 3.63566796488e-05 0.0 0.0
+306 33.7284 4.48096359426e-05 0.0 0.0
+307 33.8386 5.35992633513e-05 0.0 0.0
+308 33.9489 6.27083555248e-05 0.0 0.0
+309 34.0591 7.21305909312e-05 0.0 0.0
+310 34.1693 8.18500742839e-05 0.0 0.0
+311 34.2795 9.18536960962e-05 0.0 0.0
+312 34.3898 0.00010213534148 0.0 0.0
+313 34.5 0.000112672118648 0.0 0.0
+314 34.6102 0.000123464573757 0.0 0.0
+315 34.7204 0.000134487977041 0.0 0.0
+316 34.8307 0.000145739018538 0.0 0.0
+317 34.9409 0.000157200344796 0.0 0.0
+318 35.0511 0.000168861334042 0.0 0.0
+319 35.1613 0.000180709645549 0.0 0.0
+320 35.2715 0.000192730840508 0.0 0.0
+321 35.3818 0.000204917886388 0.0 0.0
+322 35.492 0.000217248752733 0.0 0.0
+323 35.6022 0.000229724442097 0.0 0.0
+324 35.7124 0.000242318001056 0.0 0.0
+325 35.8227 0.000255031023871 0.0 0.0
+326 35.9329 0.000267838905547 0.0 0.0
+327 36.0431 0.000280741402709 0.0 0.0
+328 36.1533 0.00029371457396 0.0 0.0
+329 36.2636 0.000306757693668 0.0 0.0
+330 36.3738 0.000319850255087 0.0 0.0
+331 36.484 0.000332984326309 0.0 0.0
+332 36.5942 0.000346149571063 0.0 0.0
+333 36.7045 0.000359329762047 0.0 0.0
+334 36.8147 0.000372519255223 0.0 0.0
+335 36.9249 0.000385699618157 0.0 0.0
+336 37.0351 0.000398868944377 0.0 0.0
+337 37.1453 0.000412004541457 0.0 0.0
+338 37.2556 0.000425107830684 0.0 0.0
+339 37.3658 0.000438156404777 0.0 0.0
+340 37.476 0.000451148936992 0.0 0.0
+341 37.5862 0.000464068827201 0.0 0.0
+342 37.6965 0.000476907659237 0.0 0.0
+343 37.8067 0.000489656718669 0.0 0.0
+344 37.9169 0.000502302608426 0.0 0.0
+345 38.0271 0.000514838943717 0.0 0.0
+346 38.1374 0.000527253459398 0.0 0.0
+347 38.2476 0.000539536832503 0.0 0.0
+348 38.3578 0.000551682597156 0.0 0.0
+349 38.468 0.000563676526578 0.0 0.0
+350 38.5783 0.000575515075243 0.0 0.0
+351 38.6885 0.000587184269132 0.0 0.0
+352 38.7987 0.00059868040732 0.0 0.0
+353 38.9089 0.000609991436097 0.0 0.0
+354 39.0191 0.000621110828127 0.0 0.0
+355 39.1294 0.000632030150561 0.0 0.0
+356 39.2396 0.000642742208789 0.0 0.0
+357 39.3498 0.000653239125361 0.0 0.0
+358 39.46 0.000663512856753 0.0 0.0
+359 39.5703 0.000673557416573 0.0 0.0
+360 39.6805 0.000683366065341 0.0 0.0
+361 39.7907 0.000692930768301 0.0 0.0
+362 39.9009 0.000702245768078 0.0 0.0
+363 40.0112 0.000711307034249 0.0 0.0
+364 40.1214 0.000720103278266 0.0 0.0
+365 40.2316 0.000728636210364 0.0 0.0
+366 40.3418 0.000736892954361 0.0 0.0
+367 40.4521 0.000744873382285 0.0 0.0
+368 40.5623 0.000752570444789 0.0 0.0
+369 40.6725 0.000759980119731 0.0 0.0
+370 40.7827 0.000767095551374 0.0 0.0
+371 40.893 0.000773918974034 0.0 0.0
+372 41.0032 0.000780434523339 0.0 0.0
+373 41.1134 0.000786654346986 0.0 0.0
+374 41.2236 0.000792558005862 0.0 0.0
+375 41.3338 0.000798157180408 0.0 0.0
+376 41.4441 0.000803437111344 0.0 0.0
+377 41.5543 0.000808403210387 0.0 0.0
+378 41.6645 0.00081304757961 0.0 0.0
+379 41.7747 0.000817371004429 0.0 0.0
+380 41.885 0.000821370392217 0.0 0.0
+381 41.9952 0.000825042026615 0.0 0.0
+382 42.1054 0.000828389870169 0.0 0.0
+383 42.2156 0.00083140320462 0.0 0.0
+384 42.3259 0.000834092390069 0.0 0.0
+385 42.4361 0.000836445424066 0.0 0.0
+386 42.5463 0.000838470849787 0.0 0.0
+387 42.6565 0.000840159979955 0.0 0.0
+388 42.7668 0.000841520901439 0.0 0.0
+389 42.877 0.000842546174121 0.0 0.0
+390 42.9872 0.000843240733613 0.0 0.0
+391 43.0974 0.000843603118188 0.0 0.0
+392 43.2076 0.000843635204417 0.0 0.0
+393 43.3179 0.000843334601725 0.0 0.0
+394 43.4281 0.000842709334821 0.0 0.0
+395 43.5383 0.000841750659771 0.0 0.0
+396 43.6485 0.00084047004073 0.0 0.0
+397 43.7588 0.000838863537793 0.0 0.0
+398 43.869 0.000836932411051 0.0 0.0
+399 43.9792 0.000834683554515 0.0 0.0
+400 44.0894 0.000832114410103 0.0 0.0
+401 44.1997 0.000829229926483 0.0 0.0
+402 44.3099 0.000826032285586 0.0 0.0
+403 44.4201 0.000822524132704 0.0 0.0
+404 44.5303 0.00081870943185 0.0 0.0
+405 44.6406 0.000814588553583 0.0 0.0
+406 44.7508 0.000810169415549 0.0 0.0
+407 44.861 0.000805451737807 0.0 0.0
+408 44.9712 0.000800439277463 0.0 0.0
+409 45.0814 0.000795140721957 0.0 0.0
+410 45.1917 0.000789551698054 0.0 0.0
+411 45.3019 0.00078368533711 0.0 0.0
+412 45.4121 0.000777539038948 0.0 0.0
+413 45.5223 0.000771120788417 0.0 0.0
+414 45.6326 0.000764434370929 0.0 0.0
+415 45.7428 0.000757483905158 0.0 0.0
+416 45.853 0.000750274772085 0.0 0.0
+417 45.9632 0.000742812033838 0.0 0.0
+418 46.0735 0.000735099596247 0.0 0.0
+419 46.1837 0.000727145193074 0.0 0.0
+420 46.2939 0.000718949336693 0.0 0.0
+421 46.4041 0.000710523916173 0.0 0.0
+422 46.5144 0.00070186820353 0.0 0.0
+423 46.6246 0.000692991225156 0.0 0.0
+424 46.7348 0.000683898099091 0.0 0.0
+425 46.845 0.000674593287954 0.0 0.0
+426 46.9552 0.00066508430844 0.0 0.0
+427 47.0655 0.000655375523056 0.0 0.0
+428 47.1757 0.000645472985118 0.0 0.0
+429 47.2859 0.0006353846405 0.0 0.0
+430 47.3961 0.000625112811107 0.0 0.0
+431 47.5064 0.000614667222898 0.0 0.0
+432 47.6166 0.000604051560125 0.0 0.0
+433 47.7268 0.000593273480603 0.0 0.0
+434 47.837 0.000582337794986 0.0 0.0
+435 47.9473 0.000571251325024 0.0 0.0
+436 48.0575 0.000560021016723 0.0 0.0
+437 48.1677 0.000548651894632 0.0 0.0
+438 48.2779 0.000537150699011 0.0 0.0
+439 48.3882 0.000525523542065 0.0 0.0
+440 48.4984 0.000513777601226 0.0 0.0
+441 48.6086 0.00050191718532 0.0 0.0
+442 48.7188 0.00048995079954 0.0 0.0
+443 48.829 0.000477882340775 0.0 0.0
+444 48.9393 0.000465721355656 0.0 0.0
+445 49.0495 0.000453468570496 0.0 0.0
+446 49.1597 0.00044113784793 0.0 0.0
+447 49.2699 0.000428726367817 0.0 0.0
+448 49.3802 0.000416249460679 0.0 0.0
+449 49.4904 0.000403703834353 0.0 0.0
+450 49.6006 0.00039110562686 0.0 0.0
+451 49.7108 0.000378449803648 0.0 0.0
+452 49.8211 0.000365753015085 0.0 0.0
+453 49.9313 0.000353012611634 0.0 0.0
+454 50.0415 0.000340239396141 0.0 0.0
+455 50.1517 0.000327437518378 0.0 0.0
+456 50.262 0.000314612451998 0.0 0.0
+457 50.3722 0.000301769914698 0.0 0.0
+458 50.4824 0.000288916014318 0.0 0.0
+459 50.5926 0.000276055996274 0.0 0.0
+460 50.7029 0.000263194886725 0.0 0.0
+461 50.8131 0.000250336537382 0.0 0.0
+462 50.9233 0.000237492188105 0.0 0.0
+463 51.0335 0.000224656810365 0.0 0.0
+464 51.1437 0.000211846522706 0.0 0.0
+465 51.254 0.000199056201743 0.0 0.0
+466 51.3642 0.000186300367146 0.0 0.0
+467 51.4744 0.000173573716633 0.0 0.0
+468 51.5846 0.000160890509655 0.0 0.0
+469 51.6949 0.000148247132818 0.0 0.0
+470 51.8051 0.000135654467572 0.0 0.0
+471 51.9153 0.000123111898973 0.0 0.0
+472 52.0255 0.000110626552334 0.0 0.0
+473 52.1358 9.82029176411e-05 0.0 0.0
+474 52.246 8.58398033807e-05 0.0 0.0
+475 52.3562 7.35507828367e-05 0.0 0.0
+476 52.4664 6.13283122267e-05 0.0 0.0
+477 52.5767 4.91850545733e-05 0.0 0.0
+478 52.6869 3.71187216896e-05 0.0 0.0
+479 52.7971 2.51374352114e-05 0.0 0.0
+480 52.9073 1.32383030858e-05 0.0 0.0
+481 53.0175 1.43176680842e-06 0.0 0.0
+482 53.1278 -1.02851387654e-05 0.0 0.0
+483 53.238 -2.19070437836e-05 0.0 0.0
+484 53.3482 -3.34302205573e-05 0.0 0.0
+485 53.4584 -4.48551734375e-05 0.0 0.0
+486 53.5687 -5.61756295677e-05 0.0 0.0
+487 53.6789 -6.73921162452e-05 0.0 0.0
+488 53.7891 -7.85019034486e-05 0.0 0.0
+489 53.8993 -8.95006745919e-05 0.0 0.0
+490 54.0096 -0.000100389519248 0.0 0.0
+491 54.1198 -0.000111164832459 0.0 0.0
+492 54.23 -0.000121825668187 0.0 0.0
+493 54.3402 -0.000132367838814 0.0 0.0
+494 54.4505 -0.000142795918565 0.0 0.0
+495 54.5607 -0.000153101048653 0.0 0.0
+496 54.6709 -0.000163286928286 0.0 0.0
+497 54.7811 -0.000173351937596 0.0 0.0
+498 54.8913 -0.000183293292792 0.0 0.0
+499 55.0016 -0.000193110297975 0.0 0.0
+500 55.1118 -0.000202806609862 0.0 0.0
+501 55.222 -0.00021237244305 0.0 0.0
+502 55.3322 -0.000221818298263 0.0 0.0
+503 55.4425 -0.000231134974629 0.0 0.0
+504 55.5527 -0.000240327038522 0.0 0.0
+505 55.6629 -0.000249391821874 0.0 0.0
+506 55.7731 -0.00025833160884 0.0 0.0
+507 55.8834 -0.00026714414049 0.0 0.0
+508 55.9936 -0.000275831017457 0.0 0.0
+509 56.1038 -0.000284391748062 0.0 0.0
+510 56.214 -0.000292827868084 0.0 0.0
+511 56.3242 -0.000301136977851 0.0 0.0
+512 56.4345 -0.000309324918971 0.0 0.0
+513 56.5447 -0.000317385173487 0.0 0.0
+514 56.6549 -0.000325326711867 0.0 0.0
+515 56.7651 -0.000333140903909 0.0 0.0
+516 56.8754 -0.00034083975069 0.0 0.0
+517 56.9856 -0.000348412279377 0.0 0.0
+518 57.0958 -0.0003558719648 0.0 0.0
+519 57.206 -0.000363206723602 0.0 0.0
+520 57.3163 -0.000370431717063 0.0 0.0
+521 57.4265 -0.000377535538931 0.0 0.0
+522 57.5367 -0.000384529224769 0.0 0.0
+523 57.6469 -0.00039140872205 0.0 0.0
+524 57.7572 -0.000398176567125 0.0 0.0
+525 57.8674 -0.000404837215024 0.0 0.0
+526 57.9776 -0.000411387470443 0.0 0.0
+527 58.0878 -0.000417834109035 0.0 0.0
+528 58.1981 -0.000424173698025 0.0 0.0
+529 58.3083 -0.000430414531944 0.0 0.0
+530 58.4185 -0.000436550063518 0.0 0.0
+531 58.5287 -0.000442591828041 0.0 0.0
+532 58.639 -0.000448531669864 0.0 0.0
+533 58.7492 -0.000454381849253 0.0 0.0
+534 58.8594 -0.000460134912047 0.0 0.0
+535 58.9696 -0.000465799176676 0.0 0.0
+536 59.0798 -0.000471375751279 0.0 0.0
+537 59.1901 -0.000476862044605 0.0 0.0
+538 59.3003 -0.00048226904146 0.0 0.0
+539 59.4105 -0.000487588201425 0.0 0.0
+540 59.5207 -0.000492831272046 0.0 0.0
+541 59.631 -0.000497994460044 0.0 0.0
+542 59.7412 -0.000503080314643 0.0 0.0
+543 59.8514 -0.000508097228574 0.0 0.0
+544 59.9616 -0.000513035305286 0.0 0.0
+545 60.0719 -0.000517911349027 0.0 0.0
+546 60.1821 -0.000522714125385 0.0 0.0
+547 60.2923 -0.000527455275176 0.0 0.0
+548 60.4025 -0.000532132886334 0.0 0.0
+549 60.5127 -0.000536747596346 0.0 0.0
+550 60.623 -0.000541306867395 0.0 0.0
+551 60.7332 -0.000545804851675 0.0 0.0
+552 60.8434 -0.000550254871686 0.0 0.0
+553 60.9536 -0.000554643817904 0.0 0.0
+554 61.0639 -0.000558990265133 0.0 0.0
+555 61.1741 -0.000563282258339 0.0 0.0
+556 61.2843 -0.000567530852198 0.0 0.0
+557 61.3945 -0.000571733123553 0.0 0.0
+558 61.5048 -0.000575893136437 0.0 0.0
+559 61.615 -0.000580011602098 0.0 0.0
+560 61.7252 -0.000584091155487 0.0 0.0
+561 61.8354 -0.000588132763354 0.0 0.0
+562 61.9457 -0.000592138889574 0.0 0.0
+563 62.0559 -0.000596110086069 0.0 0.0
+564 62.1661 -0.00060004902728 0.0 0.0
+565 62.2763 -0.000603956951372 0.0 0.0
+566 62.3865 -0.000607834532424 0.0 0.0
+567 62.4968 -0.000611683905352 0.0 0.0
+568 62.607 -0.000615507064257 0.0 0.0
+569 62.7172 -0.000619303544311 0.0 0.0
+570 62.8274 -0.000623075407727 0.0 0.0
+571 62.9377 -0.000626825217359 0.0 0.0
+572 63.0479 -0.000630550869653 0.0 0.0
+573 63.1581 -0.000634257029104 0.0 0.0
+574 63.2683 -0.000637941049203 0.0 0.0
+575 63.3786 -0.000641607432433 0.0 0.0
+576 63.4888 -0.000645252648997 0.0 0.0
+577 63.599 -0.000648882844997 0.0 0.0
+578 63.7092 -0.000652492594125 0.0 0.0
+579 63.8195 -0.000656087971223 0.0 0.0
+580 63.9297 -0.000659664940338 0.0 0.0
+581 64.0399 -0.000663227952212 0.0 0.0
+582 64.1501 -0.000666772688998 0.0 0.0
+583 64.2604 -0.000670305561401 0.0 0.0
+584 64.3706 -0.000673818472688 0.0 0.0
+585 64.4808 -0.000677321668707 0.0 0.0
+586 64.591 -0.000680803691932 0.0 0.0
+587 64.7012 -0.000684276309994 0.0 0.0
+588 64.8115 -0.000687728067945 0.0 0.0
+589 64.9217 -0.000691168691703 0.0 0.0
+590 65.0319 -0.000694589101842 0.0 0.0
+591 65.1421 -0.000697996755354 0.0 0.0
+592 65.2524 -0.000701384041695 0.0 0.0
+593 65.3626 -0.000704757216366 0.0 0.0
+594 65.4728 -0.000708108061697 0.0 0.0
+595 65.583 -0.000711443961107 0.0 0.0
+596 65.6933 -0.000714757014687 0.0 0.0
+597 65.8035 -0.000718051762929 0.0 0.0
+598 65.9137 -0.000721321660634 0.0 0.0
+599 66.0239 -0.000724572918687 0.0 0.0
+600 66.1342 -0.000727796684673 0.0 0.0
+601 66.2444 -0.000730997421863 0.0 0.0
+602 66.3546 -0.000734170862683 0.0 0.0
+603 66.4648 -0.000737317239334 0.0 0.0
+604 66.575 -0.000740433769583 0.0 0.0
+605 66.6853 -0.000743520595854 0.0 0.0
+606 66.7955 -0.000746574294077 0.0 0.0
+607 66.9057 -0.000749594788988 0.0 0.0
+608 67.0159 -0.000752579159168 0.0 0.0
+609 67.1262 -0.000755527535049 0.0 0.0
+610 67.2364 -0.000758435214409 0.0 0.0
+611 67.3466 -0.000761303139906 0.0 0.0
+612 67.4568 -0.000764127846134 0.0 0.0
+613 67.5671 -0.000766907172894 0.0 0.0
+614 67.6773 -0.000769640639713 0.0 0.0
+615 67.7875 -0.000772324055139 0.0 0.0
+616 67.8977 -0.000774957161492 0.0 0.0
+617 68.0079 -0.000777536764017 0.0 0.0
+618 68.1182 -0.000780059274543 0.0 0.0
+619 68.2284 -0.000782527899488 0.0 0.0
+620 68.3386 -0.000784931087509 0.0 0.0
+621 68.4488 -0.000787276353405 0.0 0.0
+622 68.5591 -0.00078955451878 0.0 0.0
+623 68.6693 -0.00079176518464 0.0 0.0
+624 68.7795 -0.000793908091292 0.0 0.0
+625 68.8897 -0.000795976003432 0.0 0.0
+626 69.0 -0.000797972284607 0.0 0.0
+627 69.1102 -0.000799888029748 0.0 0.0
+628 69.2204 -0.000801728295572 0.0 0.0
+629 69.3306 -0.000803481319324 0.0 0.0
+630 69.4409 -0.000805154204969 0.0 0.0
+631 69.5511 -0.000806736221899 0.0 0.0
+632 69.6613 -0.000808230572409 0.0 0.0
+633 69.7715 -0.00080963088076 0.0 0.0
+634 69.8818 -0.000810937513217 0.0 0.0
+635 69.992 -0.00081214461273 0.0 0.0
+636 70.1022 -0.00081325344391 0.0 0.0
+637 70.2124 -0.000814258443307 0.0 0.0
+638 70.3226 -0.000815157980721 0.0 0.0
+639 70.4329 -0.000815950138998 0.0 0.0
+640 70.5431 -0.000816631694197 0.0 0.0
+641 70.6533 -0.000817200545527 0.0 0.0
+642 70.7635 -0.000817653748761 0.0 0.0
+643 70.8738 -0.000817989260275 0.0 0.0
+644 70.984 -0.00081820557695 0.0 0.0
+645 71.0942 -0.000818296500929 0.0 0.0
+646 71.2044 -0.000818267157413 0.0 0.0
+647 71.3147 -0.000818105392192 0.0 0.0
+648 71.4249 -0.000817818531887 0.0 0.0
+649 71.5351 -0.000817396793261 0.0 0.0
+650 71.6453 -0.000816843950473 0.0 0.0
+651 71.7556 -0.000816152312158 0.0 0.0
+652 71.8658 -0.000815325230262 0.0 0.0
+653 71.976 -0.000814356527228 0.0 0.0
+654 72.0862 -0.000813246034095 0.0 0.0
+655 72.1964 -0.000811992569481 0.0 0.0
+656 72.3067 -0.000810592080346 0.0 0.0
+657 72.4169 -0.000809045073436 0.0 0.0
+658 72.5271 -0.000807348724251 0.0 0.0
+659 72.6373 -0.000805501944576 0.0 0.0
+660 72.7476 -0.000803500831505 0.0 0.0
+661 72.8578 -0.000801349776556 0.0 0.0
+662 72.968 -0.000799040049668 0.0 0.0
+663 73.0782 -0.000796575022703 0.0 0.0
+664 73.1885 -0.000793953187138 0.0 0.0
+665 73.2987 -0.00079117176791 0.0 0.0
+666 73.4089 -0.000788229626793 0.0 0.0
+667 73.5191 -0.00078512857791 0.0 0.0
+668 73.6294 -0.000781864775117 0.0 0.0
+669 73.7396 -0.000778437410865 0.0 0.0
+670 73.8498 -0.000774849812348 0.0 0.0
+671 73.96 -0.00077109523922 0.0 0.0
+672 74.0703 -0.000767178902003 0.0 0.0
+673 74.1805 -0.000763096485556 0.0 0.0
+674 74.2907 -0.000758850676718 0.0 0.0
+675 74.4009 -0.000754437485738 0.0 0.0
+676 74.5111 -0.000749862225406 0.0 0.0
+677 74.6214 -0.000745119272805 0.0 0.0
+678 74.7316 -0.000740213143448 0.0 0.0
+679 74.8418 -0.000735140547473 0.0 0.0
+680 74.952 -0.000729906838244 0.0 0.0
+681 75.0623 -0.000724504250491 0.0 0.0
+682 75.1725 -0.00071894438019 0.0 0.0
+683 75.2827 -0.000713216153335 0.0 0.0
+684 75.3929 -0.000707331227636 0.0 0.0
+685 75.5032 -0.000701281170981 0.0 0.0
+686 75.6134 -0.000695074524152 0.0 0.0
+687 75.7236 -0.000688707140618 0.0 0.0
+688 75.8338 -0.000682183167626 0.0 0.0
+689 75.944 -0.000675503515806 0.0 0.0
+690 76.0543 -0.000668667978868 0.0 0.0
+691 76.1645 -0.000661680624231 0.0 0.0
+692 76.2747 -0.000654541868483 0.0 0.0
+693 76.3849 -0.00064725244116 0.0 0.0
+694 76.4952 -0.000639817906103 0.0 0.0
+695 76.6054 -0.000632234712799 0.0 0.0
+696 76.7156 -0.000624511132856 0.0 0.0
+697 76.8258 -0.000616644284174 0.0 0.0
+698 76.9361 -0.000608640913989 0.0 0.0
+699 77.0463 -0.000600498157181 0.0 0.0
+700 77.1565 -0.000592225674785 0.0 0.0
+701 77.2667 -0.000583819195564 0.0 0.0
+702 77.377 -0.000575286158208 0.0 0.0
+703 77.4872 -0.000566627095908 0.0 0.0
+704 77.5974 -0.000557846551933 0.0 0.0
+705 77.7076 -0.000548946957363 0.0 0.0
+706 77.8178 -0.000539930321452 0.0 0.0
+707 77.9281 -0.00053080295161 0.0 0.0
+708 78.0383 -0.000521564731612 0.0 0.0
+709 78.1485 -0.000512221776577 0.0 0.0
+710 78.2587 -0.000502777457715 0.0 0.0
+711 78.369 -0.000493232944194 0.0 0.0
+712 78.4792 -0.000483594849645 0.0 0.0
+713 78.5894 -0.000473867629939 0.0 0.0
+714 78.6996 -0.000464050034964 0.0 0.0
+715 78.8099 -0.000454153399604 0.0 0.0
+716 78.9201 -0.000444175648239 0.0 0.0
+717 79.0303 -0.000434124761444 0.0 0.0
+718 79.1405 -0.000424003004963 0.0 0.0
+719 79.2508 -0.000413815959208 0.0 0.0
+720 79.361 -0.000403566658609 0.0 0.0
+721 79.4712 -0.000393261720981 0.0 0.0
+722 79.5814 -0.000382902475916 0.0 0.0
+723 79.6917 -0.000372497367695 0.0 0.0
+724 79.8019 -0.000362047194805 0.0 0.0
+725 79.9121 -0.000351560050659 0.0 0.0
+726 80.0223 -0.00034103821387 0.0 0.0
+727 80.1326 -0.00033048742589 0.0 0.0
+728 80.2428 -0.000319913152999 0.0 0.0
+729 80.353 -0.000309319208655 0.0 0.0
+730 80.4632 -0.000298710176914 0.0 0.0
+731 80.5734 -0.000288094454457 0.0 0.0
+732 80.6837 -0.000277470227912 0.0 0.0
+733 80.7939 -0.00026685084972 0.0 0.0
+734 80.9041 -0.000256234288435 0.0 0.0
+735 81.0143 -0.000245629922379 0.0 0.0
+736 81.1245 -0.000235040467757 0.0 0.0
+737 81.2348 -0.00022447332114 0.0 0.0
+738 81.345 -0.00021393006613 0.0 0.0
+739 81.4552 -0.000203420619269 0.0 0.0
+740 81.5655 -0.000192945047218 0.0 0.0
+741 81.6757 -0.000182511924224 0.0 0.0
+742 81.7859 -0.000172125939471 0.0 0.0
+743 81.8961 -0.000161789743475 0.0 0.0
+744 82.0063 -0.00015151179964 0.0 0.0
+745 82.1166 -0.000141294928839 0.0 0.0
+746 82.2268 -0.000131145082225 0.0 0.0
+747 82.337 -0.000121065704216 0.0 0.0
+748 82.4472 -0.000111066479879 0.0 0.0
+749 82.5575 -0.000101143931028 0.0 0.0
+750 82.6677 -9.1313636191e-05 0.0 0.0
+751 82.7779 -8.15698203079e-05 0.0 0.0
+752 82.8881 -7.19268414563e-05 0.0 0.0
+753 82.9984 -6.23808362162e-05 0.0 0.0
+754 83.1086 -5.29455419296e-05 0.0 0.0
+755 83.2188 -4.36154550899e-05 0.0 0.0
+756 83.329 -3.44066170255e-05 0.0 0.0
+757 83.4393 -2.53116059672e-05 0.0 0.0
+758 83.5495 -1.63470068736e-05 0.0 0.0
+759 83.6597 -7.50527354059e-06 0.0 0.0
+760 83.7699 1.19727026976e-06 0.0 0.0
+761 83.8801 9.7677262088e-06 0.0 0.0
+762 83.9904 1.8192138304e-05 0.0 0.0
+763 84.1006 2.64737328986e-05 0.0 0.0
+764 84.2108 3.46029760398e-05 0.0 0.0
+765 84.321 4.25800437973e-05 0.0 0.0
+766 84.4313 5.03993093124e-05 0.0 0.0
+767 84.5415 5.80543344521e-05 0.0 0.0
+768 84.6517 6.55484838659e-05 0.0 0.0
+769 84.7619 7.28699807986e-05 0.0 0.0
+770 84.8722 8.00208522134e-05 0.0 0.0
+771 84.9824 8.69961534073e-05 0.0 0.0
+772 85.0926 9.37917242067e-05 0.0 0.0
+773 85.2028 0.000100405820313 0.0 0.0
+774 85.3131 0.000106834129611 0.0 0.0
+775 85.4233 0.000113075628924 0.0 0.0
+776 85.5335 0.000119124038567 0.0 0.0
+777 85.6437 0.000124981961534 0.0 0.0
+778 85.7539 0.000130640185376 0.0 0.0
+779 85.8642 0.000136103557841 0.0 0.0
+780 85.9744 0.000141363519222 0.0 0.0
+781 86.0846 0.000146421218885 0.0 0.0
+782 86.1948 0.000151274290992 0.0 0.0
+783 86.3051 0.000155920817525 0.0 0.0
+784 86.4153 0.000160356612405 0.0 0.0
+785 86.5255 0.000164585758478 0.0 0.0
+786 86.6357 0.000168598517844 0.0 0.0
+787 86.746 0.00017240290115 0.0 0.0
+788 86.8562 0.000175989803607 0.0 0.0
+789 86.9664 0.0001793620868 0.0 0.0
+790 87.0766 0.000182519272014 0.0 0.0
+791 87.1869 0.000185457707002 0.0 0.0
+792 87.2971 0.000188180357593 0.0 0.0
+793 87.4073 0.000190683287064 0.0 0.0
+794 87.5175 0.000192969264104 0.0 0.0
+795 87.6277 0.000195035232913 0.0 0.0
+796 87.738 0.000196884736672 0.0 0.0
+797 87.8482 0.000198513265368 0.0 0.0
+798 87.9584 0.000199925885865 0.0 0.0
+799 88.0686 0.000201120265427 0.0 0.0
+800 88.1789 0.000202096222975 0.0 0.0
+801 88.2891 0.000202857636231 0.0 0.0
+802 88.3993 0.000203404212552 0.0 0.0
+803 88.5095 0.000203731763151 0.0 0.0
+804 88.6198 0.000203854043942 0.0 0.0
+805 88.73 0.000203756182511 0.0 0.0
+806 88.8402 0.0002034546891 0.0 0.0
+807 88.9504 0.00020293940607 0.0 0.0
+808 89.0607 0.000202222072762 0.0 0.0
+809 89.1709 0.000201294673193 0.0 0.0
+810 89.2811 0.000200169514677 0.0 0.0
+811 89.3913 0.000198840366567 0.0 0.0
+812 89.5015 0.000197313346598 0.0 0.0
+813 89.6118 0.000195592553463 0.0 0.0
+814 89.722 0.000193677415774 0.0 0.0
+815 89.8322 0.000191570872437 0.0 0.0
+816 89.9425 0.000189280383231 0.0 0.0
+817 90.0527 0.000186802001469 0.0 0.0
+818 90.1629 0.000184144721061 0.0 0.0
+819 90.2731 0.000181310716576 0.0 0.0
+820 90.3833 0.000178298422001 0.0 0.0
+821 90.4936 0.000175121939087 0.0 0.0
+822 90.6038 0.000171771390839 0.0 0.0
+823 90.714 0.000168264367531 0.0 0.0
+824 90.8242 0.000164593360187 0.0 0.0
+825 90.9344 0.000160770504249 0.0 0.0
+826 91.0447 0.000156795804003 0.0 0.0
+827 91.1549 0.000152673389513 0.0 0.0
+828 91.2651 0.000148412361768 0.0 0.0
+829 91.3754 0.000144008992458 0.0 0.0
+830 91.4856 0.00013947799645 0.0 0.0
+831 91.5958 0.000134813930121 0.0 0.0
+832 91.706 0.000130030199588 0.0 0.0
+833 91.8162 0.00012512671872 0.0 0.0
+834 91.9265 0.000120107914819 0.0 0.0
+835 92.0367 0.000114985326925 0.0 0.0
+836 92.1469 0.000109754426944 0.0 0.0
+837 92.2571 0.000104428977904 0.0 0.0
+838 92.3674 9.90103623267e-05 0.0 0.0
+839 92.4776 9.35031105057e-05 0.0 0.0
+840 92.5878 8.79159489384e-05 0.0 0.0
+841 92.698 8.2251224543e-05 0.0 0.0
+842 92.8083 7.65165840266e-05 0.0 0.0
+843 92.9185 7.07176771746e-05 0.0 0.0
+844 93.0287 6.48561962524e-05 0.0 0.0
+845 93.1389 5.89467781783e-05 0.0 0.0
+846 93.2491 5.29831133962e-05 0.0 0.0
+847 93.3594 4.69837276623e-05 0.0 0.0
+848 93.4696 4.09426696449e-05 0.0 0.0
+849 93.5798 3.4876092786e-05 0.0 0.0
+850 93.69 2.87814232045e-05 0.0 0.0
+851 93.8003 2.26717428431e-05 0.0 0.0
+852 93.9105 1.65466679619e-05 0.0 0.0
+853 94.0207 1.04173296399e-05 0.0 0.0
+854 94.1309 4.28641281702e-06 0.0 0.0
+855 94.2412 -1.83856873574e-06 0.0 0.0
+856 94.3514 -7.95217813993e-06 0.0 0.0
+857 94.4616 -1.40482812545e-05 0.0 0.0
+858 94.5718 -2.01209168528e-05 0.0 0.0
+859 94.6821 -2.61645509223e-05 0.0 0.0
+860 94.7923 -3.21719627683e-05 0.0 0.0
+861 94.9025 -3.81387621365e-05 0.0 0.0
+862 95.0127 -4.40593992995e-05 0.0 0.0
+863 95.123 -4.99236593562e-05 0.0 0.0
+864 95.2332 -5.57349440577e-05 0.0 0.0
+865 95.3434 -6.14743618378e-05 0.0 0.0
+866 95.4536 -6.71509191241e-05 0.0 0.0
+867 95.5638 -7.27446856915e-05 0.0 0.0
+868 95.6741 -7.82623888165e-05 0.0 0.0
+869 95.7843 -8.36895853104e-05 0.0 0.0
+870 95.8945 -8.90237362158e-05 0.0 0.0
+871 96.0047 -9.42644266545e-05 0.0 0.0
+872 96.115 -9.93928708984e-05 0.0 0.0
+873 96.2252 -0.000104423333712 0.0 0.0
+874 96.3354 -0.000109329449091 0.0 0.0
+875 96.4456 -0.000114123478921 0.0 0.0
+876 96.5559 -0.000118789542523 0.0 0.0
+877 96.6661 -0.000123328130768 0.0 0.0
+878 96.7763 -0.000127730881591 0.0 0.0
+879 96.8865 -0.000131996999895 0.0 0.0
+880 96.9968 -0.00013611663344 0.0 0.0
+881 97.107 -0.00014009147366 0.0 0.0
+882 97.2172 -0.000143909457309 0.0 0.0
+883 97.3274 -0.000147575724295 0.0 0.0
+884 97.4376 -0.000151074641607 0.0 0.0
+885 97.5479 -0.000154414452578 0.0 0.0
+886 97.6581 -0.000157578991838 0.0 0.0
+887 97.7683 -0.000160575574084 0.0 0.0
+888 97.8785 -0.000163390772074 0.0 0.0
+889 97.9888 -0.000166028500667 0.0 0.0
+890 98.099 -0.000168480231656 0.0 0.0
+891 98.2092 -0.000170745712146 0.0 0.0
+892 98.3194 -0.000172820447499 0.0 0.0
+893 98.4297 -0.00017469938958 0.0 0.0
+894 98.5399 -0.000176385680342 0.0 0.0
+895 98.6501 -0.000177869074409 0.0 0.0
+896 98.7603 -0.00017915154393 0.0 0.0
+897 98.8706 -0.000180231175674 0.0 0.0
+898 98.9808 -0.000181100390215 0.0 0.0
+899 99.091 -0.00018176519612 0.0 0.0
+900 99.2012 -0.000182214754587 0.0 0.0
+901 99.3114 -0.000182454681513 0.0 0.0
+902 99.4217 -0.000182478098039 0.0 0.0
+903 99.5319 -0.00018228668144 0.0 0.0
+904 99.6421 -0.000181877771473 0.0 0.0
+905 99.7523 -0.000181249443884 0.0 0.0
+906 99.8626 -0.000180402421684 0.0 0.0
+907 99.9728 -0.00017933497758 0.0 0.0
+908 100.083 -0.000178045346124 0.0 0.0
+909 100.193 -0.000176535949192 0.0 0.0
+910 100.303 -0.000174802342443 0.0 0.0
+911 100.414 -0.000172848542454 0.0 0.0
+912 100.524 -0.00017067093682 0.0 0.0
+913 100.634 -0.000168272701949 0.0 0.0
+914 100.744 -0.000165651221455 0.0 0.0
+915 100.855 -0.000162810960472 0.0 0.0
+916 100.965 -0.000159746365381 0.0 0.0
+917 101.075 -0.000156467058689 0.0 0.0
+918 101.185 -0.000152963906454 0.0 0.0
+919 101.295 -0.000149247745568 0.0 0.0
+920 101.406 -0.000145312345068 0.0 0.0
+921 101.516 -0.000141163929022 0.0 0.0
+922 101.626 -0.000136802276424 0.0 0.0
+923 101.736 -0.000132229244429 0.0 0.0
+924 101.847 -0.000127448249081 0.0 0.0
+925 101.957 -0.000122457808243 0.0 0.0
+926 102.067 -0.000117267875029 0.0 0.0
+927 102.177 -0.00011186833796 0.0 0.0
+928 102.287 -0.000106279475986 0.0 0.0
+929 102.398 -0.000100483640717 0.0 0.0
+930 102.508 -9.45028198722e-05 0.0 0.0
+931 102.618 -8.83264736786e-05 0.0 0.0
+932 102.728 -8.19660320133e-05 0.0 0.0
+933 102.839 -7.54198160679e-05 0.0 0.0
+934 102.949 -6.86956254134e-05 0.0 0.0
+935 103.059 -6.17939603166e-05 0.0 0.0
+936 103.169 -5.47201369186e-05 0.0 0.0
+937 103.279 -4.74778891856e-05 0.0 0.0
+938 103.39 -4.0072910423e-05 0.0 0.0
+939 103.5 -3.2505255918e-05 0.0 0.0
+940 103.61 -2.47849962102e-05 0.0 0.0
+941 103.72 -1.6911993814e-05 0.0 0.0
+942 103.831 -8.89463229495e-06 0.0 0.0
+943 103.941 -7.323916304e-07 0.0 0.0
+944 104.051 7.56052333158e-06 0.0 0.0
+945 104.161 1.59919020138e-05 0.0 0.0
+946 104.272 2.45424665659e-05 0.0 0.0
+947 104.382 3.3219680083e-05 0.0 0.0
+948 104.492 4.20097906523e-05 0.0 0.0
+949 104.602 5.09091383054e-05 0.0 0.0
+950 104.712 5.99167290849e-05 0.0 0.0
+951 104.823 6.90178590038e-05 0.0 0.0
+952 104.933 7.82184507009e-05 0.0 0.0
+953 105.043 8.75001649418e-05 0.0 0.0
+954 105.153 9.6867442483e-05 0.0 0.0
+955 105.264 0.000106309691905 0.0 0.0
+956 105.374 0.000115818062061 0.0 0.0
+957 105.484 0.000125393990738 0.0 0.0
+958 105.594 0.000135024561691 0.0 0.0
+959 105.704 0.000144704786276 0.0 0.0
+960 105.815 0.000154432482114 0.0 0.0
+961 105.925 0.000164195638102 0.0 0.0
+962 106.035 0.000173991025053 0.0 0.0
+963 106.145 0.000183813228118 0.0 0.0
+964 106.256 0.000193650692422 0.0 0.0
+965 106.366 0.000203504426938 0.0 0.0
+966 106.476 0.00021336012666 0.0 0.0
+967 106.586 0.000223217144703 0.0 0.0
+968 106.696 0.000233065714113 0.0 0.0
+969 106.807 0.000242900543325 0.0 0.0
+970 106.917 0.000252713542532 0.0 0.0
+971 107.027 0.000262500831481 0.0 0.0
+972 107.137 0.000272252334208 0.0 0.0
+973 107.248 0.000281964894036 0.0 0.0
+974 107.358 0.000291628132144 0.0 0.0
+975 107.468 0.00030124036607 0.0 0.0
+976 107.578 0.000310788845545 0.0 0.0
+977 107.688 0.000320273829795 0.0 0.0
+978 107.799 0.000329682582315 0.0 0.0
+979 107.909 0.000339013131745 0.0 0.0
+980 108.019 0.000348256592197 0.0 0.0
+981 108.129 0.000357407563917 0.0 0.0
+982 108.24 0.000366459612241 0.0 0.0
+983 108.35 0.000375405391801 0.0 0.0
+984 108.46 0.000384241481283 0.0 0.0
+985 108.57 0.00039295776811 0.0 0.0
+986 108.68 0.000401550655726 0.0 0.0
+987 108.791 0.000410015585402 0.0 0.0
+988 108.901 0.00041834131549 0.0 0.0
+989 109.011 0.000426529063793 0.0 0.0
+990 109.121 0.000434565166396 0.0 0.0
+991 109.232 0.000442452921054 0.0 0.0
+992 109.342 0.000450176731932 0.0 0.0
+993 109.452 0.000457740949387 0.0 0.0
+994 109.562 0.000465131522965 0.0 0.0
+995 109.672 0.000472350712979 0.0 0.0
+996 109.783 0.000479385393105 0.0 0.0
+997 109.893 0.000486240868167 0.0 0.0
+998 110.003 0.000492897710588 0.0 0.0
+999 110.113 0.000499369708404 0.0 0.0
+1000 110.224 0.000505631537371 0.0 0.0
+1001 110.334 0.000511697547569 0.0 0.0
+1002 110.444 0.000517549738545 0.0 0.0
+1003 110.554 0.00052318969267 0.0 0.0
+1004 110.664 0.000528614104579 0.0 0.0
+1005 110.775 0.000533815395052 0.0 0.0
+1006 110.885 0.000538791573593 0.0 0.0
+1007 110.995 0.000543539809562 0.0 0.0
+1008 111.105 0.000548054364246 0.0 0.0
+1009 111.216 0.000552333998328 0.0 0.0
+1010 111.326 0.000556372439762 0.0 0.0
+1011 111.436 0.000560170755644 0.0 0.0
+1012 111.546 0.000563722230451 0.0 0.0
+1013 111.656 0.000567025427017 0.0 0.0
+1014 111.767 0.000570078293821 0.0 0.0
+1015 111.877 0.000572878516714 0.0 0.0
+1016 111.987 0.000575419837157 0.0 0.0
+1017 112.097 0.000577708716034 0.0 0.0
+1018 112.208 0.000579732187054 0.0 0.0
+1019 112.318 0.000581499199079 0.0 0.0
+1020 112.428 0.000582997870326 0.0 0.0
+1021 112.538 0.000584238145451 0.0 0.0
+1022 112.648 0.000585204967481 0.0 0.0
+1023 112.759 0.000585913275793 0.0 0.0
+1024 112.869 0.000586345918064 0.0 0.0
+1025 112.979 0.000586515952264 0.0 0.0
+1026 113.089 0.000586413072003 0.0 0.0
+1027 113.2 0.000586043044041 0.0 0.0
+1028 113.31 0.000585401459947 0.0 0.0
+1029 113.42 0.00058449255385 0.0 0.0
+1030 113.53 0.000583311289525 0.0 0.0
+1031 113.641 0.000581864076306 0.0 0.0
+1032 113.751 0.000580145738139 0.0 0.0
+1033 113.861 0.000578160897581 0.0 0.0
+1034 113.971 0.000575909200637 0.0 0.0
+1035 114.081 0.00057339136286 0.0 0.0
+1036 114.192 0.000570608571233 0.0 0.0
+1037 114.302 0.00056756383482 0.0 0.0
+1038 114.412 0.000564256761143 0.0 0.0
+1039 114.522 0.000560690804278 0.0 0.0
+1040 114.633 0.00055686589074 0.0 0.0
+1041 114.743 0.000552787975117 0.0 0.0
+1042 114.853 0.000548452776955 0.0 0.0
+1043 114.963 0.000543872752633 0.0 0.0
+1044 115.073 0.00053903881082 0.0 0.0
+1045 115.184 0.000533964650225 0.0 0.0
+1046 115.294 0.000528643951536 0.0 0.0
+1047 115.404 0.000523089363916 0.0 0.0
+1048 115.514 0.000517293548641 0.0 0.0
+1049 115.625 0.000511271622812 0.0 0.0
+1050 115.735 0.000505015035432 0.0 0.0
+1051 115.845 0.000498539698344 0.0 0.0
+1052 115.955 0.000491838872336 0.0 0.0
+1053 116.065 0.000484925491008 0.0 0.0
+1054 116.176 0.000477796193379 0.0 0.0
+1055 116.286 0.000470461467886 0.0 0.0
+1056 116.396 0.000462922606072 0.0 0.0
+1057 116.506 0.000455185215808 0.0 0.0
+1058 116.617 0.000447252883577 0.0 0.0
+1059 116.727 0.000439133611888 0.0 0.0
+1060 116.837 0.000430828383662 0.0 0.0
+1061 116.947 0.000422345721316 0.0 0.0
+1062 117.057 0.000413689474153 0.0 0.0
+1063 117.168 0.000404865039094 0.0 0.0
+1064 117.278 0.000395877943268 0.0 0.0
+1065 117.388 0.000386734812843 0.0 0.0
+1066 117.498 0.000377439792134 0.0 0.0
+1067 117.609 0.000368000286698 0.0 0.0
+1068 117.719 0.000358420955819 0.0 0.0
+1069 117.829 0.000348708483204 0.0 0.0
+1070 117.939 0.000338869728144 0.0 0.0
+1071 118.049 0.000328908438021 0.0 0.0
+1072 118.16 0.00031883442944 0.0 0.0
+1073 118.27 0.000308650460847 0.0 0.0
+1074 118.38 0.000298365662392 0.0 0.0
+1075 118.49 0.000287985350222 0.0 0.0
+1076 118.601 0.000277515748377 0.0 0.0
+1077 118.711 0.000266964414382 0.0 0.0
+1078 118.821 0.00025633743525 0.0 0.0
+1079 118.931 0.000245641687425 0.0 0.0
+1080 119.041 0.000234882306601 0.0 0.0
+1081 119.152 0.000224071910613 0.0 0.0
+1082 119.262 0.000213205829687 0.0 0.0
+1083 119.372 0.000202305641729 0.0 0.0
+1084 119.482 0.000191365666582 0.0 0.0
+1085 119.593 0.000180398763943 0.0 0.0
+1086 119.703 0.000169411620024 0.0 0.0
+1087 119.813 0.000158410207436 0.0 0.0
+1088 119.923 0.000147399943026 0.0 0.0
+1089 120.033 0.00013639096516 0.0 0.0
+1090 120.144 0.000125387589422 0.0 0.0
+1091 120.254 0.000114397659968 0.0 0.0
+1092 120.364 0.00010342757569 0.0 0.0
+1093 120.474 9.24853411453e-05 0.0 0.0
+1094 120.585 8.15753029943e-05 0.0 0.0
+1095 120.695 7.07083167435e-05 0.0 0.0
+1096 120.805 5.98848528589e-05 0.0 0.0
+1097 120.915 4.91197243144e-05 0.0 0.0
+1098 121.025 3.84112577943e-05 0.0 0.0
+1099 121.136 2.77725566831e-05 0.0 0.0
+1100 121.246 1.72062247421e-05 0.0 0.0
+1101 121.356 6.72080687983e-06 0.0 0.0
+1102 121.466 -3.67922879427e-06 0.0 0.0
+1103 121.577 -1.39838218774e-05 0.0 0.0
+1104 121.687 -2.41935344529e-05 0.0 0.0
+1105 121.797 -3.42925224784e-05 0.0 0.0
+1106 121.907 -4.42857032821e-05 0.0 0.0
+1107 122.018 -5.4155846538e-05 0.0 0.0
+1108 122.128 -6.39086324318e-05 0.0 0.0
+1109 122.238 -7.3525689657e-05 0.0 0.0
+1110 122.348 -8.30143444243e-05 0.0 0.0
+1111 122.458 -9.23570863782e-05 0.0 0.0
+1112 122.569 -0.000101557566214 0.0 0.0
+1113 122.679 -0.000110604741094 0.0 0.0
+1114 122.789 -0.000119495376824 0.0 0.0
+1115 122.899 -0.000128225321019 0.0 0.0
+1116 123.01 -0.000136786881851 0.0 0.0
+1117 123.12 -0.000145177742908 0.0 0.0
+1118 123.23 -0.000153391504904 0.0 0.0
+1119 123.34 -0.000161424571919 0.0 0.0
+1120 123.45 -0.000169270841238 0.0 0.0
+1121 123.561 -0.000176929382008 0.0 0.0
+1122 123.671 -0.000184389654888 0.0 0.0
+1123 123.781 -0.000191656798042 0.0 0.0
+1124 123.891 -0.000198715940986 0.0 0.0
+1125 124.002 -0.000205574475597 0.0 0.0
+1126 124.112 -0.000212218325108 0.0 0.0
+1127 124.222 -0.00021865384094 0.0 0.0
+1128 124.332 -0.000224867445207 0.0 0.0
+1129 124.442 -0.000230867635498 0.0 0.0
+1130 124.553 -0.000236638732026 0.0 0.0
+1131 124.663 -0.000242190886126 0.0 0.0
+1132 124.773 -0.000247508322601 0.0 0.0
+1133 124.883 -0.000252601626538 0.0 0.0
+1134 124.994 -0.000257456733707 0.0 0.0
+1135 125.104 -0.000262080281553 0.0 0.0
+1136 125.214 -0.000266465339838 0.0 0.0
+1137 125.324 -0.00027061126524 0.0 0.0
+1138 125.434 -0.000274518814441 0.0 0.0
+1139 125.545 -0.000278181112756 0.0 0.0
+1140 125.655 -0.000281604537932 0.0 0.0
+1141 125.765 -0.000284779338146 0.0 0.0
+1142 125.875 -0.000287713084304 0.0 0.0
+1143 125.986 -0.000290397240588 0.0 0.0
+1144 126.096 -0.000292838855934 0.0 0.0
+1145 126.206 -0.000295029896924 0.0 0.0
+1146 126.316 -0.000296976743001 0.0 0.0
+1147 126.426 -0.000298675880208 0.0 0.0
+1148 126.537 -0.000300126526423 0.0 0.0
+1149 126.647 -0.000301334434405 0.0 0.0
+1150 126.757 -0.00030229179062 0.0 0.0
+1151 126.867 -0.000303007994178 0.0 0.0
+1152 126.978 -0.000303477065609 0.0 0.0
+1153 127.088 -0.000303703992844 0.0 0.0
+1154 127.198 -0.000303689192218 0.0 0.0
+1155 127.308 -0.00030343250305 0.0 0.0
+1156 127.418 -0.00030293758334 0.0 0.0
+1157 127.529 -0.000302205395557 0.0 0.0
+1158 127.639 -0.000301236967703 0.0 0.0
+1159 127.749 -0.000300035669477 0.0 0.0
+1160 127.859 -0.000298603480666 0.0 0.0
+1161 127.97 -0.00029694202228 0.0 0.0
+1162 128.08 -0.000295054471144 0.0 0.0
+1163 128.19 -0.000292944528896 0.0 0.0
+1164 128.3 -0.000290611778756 0.0 0.0
+1165 128.41 -0.000288064113775 0.0 0.0
+1166 128.521 -0.000285300824076 0.0 0.0
+1167 128.631 -0.000282326007765 0.0 0.0
+1168 128.741 -0.000279145664151 0.0 0.0
+1169 128.851 -0.000275759562692 0.0 0.0
+1170 128.962 -0.000272173551148 0.0 0.0
+1171 129.072 -0.000268394406105 0.0 0.0
+1172 129.182 -0.00026441746854 0.0 0.0
+1173 129.292 -0.000260259269093 0.0 0.0
+1174 129.402 -0.000255911643549 0.0 0.0
+1175 129.513 -0.000251389901724 0.0 0.0
+1176 129.623 -0.000246688561722 0.0 0.0
+1177 129.733 -0.000241822253028 0.0 0.0
+1178 129.843 -0.000236787217239 0.0 0.0
+1179 129.954 -0.000231593227396 0.0 0.0
+1180 130.064 -0.000226245147546 0.0 0.0
+1181 130.174 -0.000220744361097 0.0 0.0
+1182 130.284 -0.000215101908731 0.0 0.0
+1183 130.395 -0.000209316802828 0.0 0.0
+1184 130.505 -0.000203400385289 0.0 0.0
+1185 130.615 -0.000197351507153 0.0 0.0
+1186 130.725 -0.000191185135464 0.0 0.0
+1187 130.835 -0.00018489474284 0.0 0.0
+1188 130.946 -0.00017849744021 0.0 0.0
+1189 131.056 -0.000171992791739 0.0 0.0
+1190 131.166 -0.000165386045579 0.0 0.0
+1191 131.276 -0.000158687866627 0.0 0.0
+1192 131.387 -0.000151900438277 0.0 0.0
+1193 131.497 -0.000145029039193 0.0 0.0
+1194 131.607 -0.000138084156151 0.0 0.0
+1195 131.717 -0.00013106700163 0.0 0.0
+1196 131.827 -0.000123987080441 0.0 0.0
+1197 131.938 -0.000116848434768 0.0 0.0
+1198 132.048 -0.000109659289357 0.0 0.0
+1199 132.158 -0.000102422726301 0.0 0.0
+1200 132.268 -9.51498772687e-05 0.0 0.0
+1201 132.379 -8.78406710114e-05 0.0 0.0
+1202 132.489 -8.05079807828e-05 0.0 0.0
+1203 132.599 -7.31519260105e-05 0.0 0.0
+1204 132.709 -6.57842885824e-05 0.0 0.0
+1205 132.819 -5.84061685749e-05 0.0 0.0
+1206 132.93 -5.102924018e-05 0.0 0.0
+1207 133.04 -4.36526397352e-05 0.0 0.0
+1208 133.15 -3.62917787178e-05 0.0 0.0
+1209 133.26 -2.89431427578e-05 0.0 0.0
+1210 133.371 -2.16207167724e-05 0.0 0.0
+1211 133.481 -1.43249280544e-05 0.0 0.0
+1212 133.591 -7.0665785841e-06 0.0 0.0
+1213 133.701 1.52486467019e-07 0.0 0.0
+1214 133.811 7.32337781335e-06 0.0 0.0
+1215 133.922 1.44422212238e-05 0.0 0.0
+1216 134.032 2.15003917051e-05 0.0 0.0
+1217 134.142 2.84964733367e-05 0.0 0.0
+1218 134.252 3.54194793434e-05 0.0 0.0
+1219 134.363 4.22684792892e-05 0.0 0.0
+1220 134.473 4.9034601279e-05 0.0 0.0
+1221 134.583 5.57144429048e-05 0.0 0.0
+1222 134.693 6.23009589398e-05 0.0 0.0
+1223 134.803 6.87900433757e-05 0.0 0.0
+1224 134.914 7.51763571466e-05 0.0 0.0
+1225 135.024 8.14532545809e-05 0.0 0.0
+1226 135.134 8.76186334383e-05 0.0 0.0
+1227 135.244 9.36636537774e-05 0.0 0.0
+1228 135.355 9.95876613761e-05 0.0 0.0
+1229 135.465 0.000105383001986 0.0 0.0
+1230 135.575 0.000111044883999 0.0 0.0
+1231 135.685 0.000116572816326 0.0 0.0
+1232 135.795 0.000121955913827 0.0 0.0
+1233 135.906 0.000127196810129 0.0 0.0
+1234 136.016 0.000132286042704 0.0 0.0
+1235 136.126 0.000137222461615 0.0 0.0
+1236 136.236 0.00014200160918 0.0 0.0
+1237 136.347 0.000146619658421 0.0 0.0
+1238 136.457 0.000151072745031 0.0 0.0
+1239 136.567 0.000155357649145 0.0 0.0
+1240 136.677 0.000159472133759 0.0 0.0
+1241 136.787 0.000163410670621 0.0 0.0
+1242 136.898 0.000167173013132 0.0 0.0
+1243 137.008 0.000170754360299 0.0 0.0
+1244 137.118 0.000174152363591 0.0 0.0
+1245 137.228 0.000177365892294 0.0 0.0
+1246 137.339 0.000180390625497 0.0 0.0
+1247 137.449 0.000183225127504 0.0 0.0
+1248 137.559 0.000185868253973 0.0 0.0
+1249 137.669 0.000188316869274 0.0 0.0
+1250 137.779 0.000190568980929 0.0 0.0
+1251 137.89 0.000192625327131 0.0 0.0
+1252 138.0 0.00019448104481 0.0 0.0
+1253 138.11 0.000196138696832 0.0 0.0
+1254 138.22 0.000197592730437 0.0 0.0
+1255 138.331 0.000198848797411 0.0 0.0
+1256 138.441 0.000199896528398 0.0 0.0
+1257 138.551 0.000200747180638 0.0 0.0
+1258 138.661 0.000201388700994 0.0 0.0
+1259 138.771 0.000201830776554 0.0 0.0
+1260 138.882 0.000202065087128 0.0 0.0
+1261 138.992 0.000202098848858 0.0 0.0
+1262 139.102 0.000201926879616 0.0 0.0
+1263 139.212 0.000201552148903 0.0 0.0
+1264 139.323 0.000200976306799 0.0 0.0
+1265 139.433 0.000200196630179 0.0 0.0
+1266 139.543 0.000199217771994 0.0 0.0
+1267 139.653 0.000198038642527 0.0 0.0
+1268 139.764 0.000196661035672 0.0 0.0
+1269 139.874 0.000195086986967 0.0 0.0
+1270 139.984 0.000193316427771 0.0 0.0
+1271 140.094 0.000191354278425 0.0 0.0
+1272 140.204 0.000189197872242 0.0 0.0
+1273 140.315 0.00018685417927 0.0 0.0
+1274 140.425 0.00018432154874 0.0 0.0
+1275 140.535 0.000181604618084 0.0 0.0
+1276 140.645 0.000178705462477 0.0 0.0
+1277 140.756 0.000175625071992 0.0 0.0
+1278 140.866 0.000172369941732 0.0 0.0
+1279 140.976 0.000168938628005 0.0 0.0
+1280 141.086 0.00016533820419 0.0 0.0
+1281 141.196 0.000161568360629 0.0 0.0
+1282 141.307 0.000157636086144 0.0 0.0
+1283 141.417 0.000153541949297 0.0 0.0
+1284 141.527 0.00014929009054 0.0 0.0
+1285 141.637 0.000144887677217 0.0 0.0
+1286 141.748 0.000140331699677 0.0 0.0
+1287 141.858 0.000135634692949 0.0 0.0
+1288 141.968 0.000130792556843 0.0 0.0
+1289 142.078 0.000125816231014 0.0 0.0
+1290 142.188 0.000120706397224 0.0 0.0
+1291 142.299 0.000115466812038 0.0 0.0
+1292 142.409 0.000110107372436 0.0 0.0
+1293 142.519 0.000104623703186 0.0 0.0
+1294 142.629 9.90324683171e-05 0.0 0.0
+1295 142.74 9.33245035196e-05 0.0 0.0
+1296 142.85 8.75198435933e-05 0.0 0.0
+1297 142.96 8.16085796171e-05 0.0 0.0
+1298 143.07 7.56099506288e-05 0.0 0.0
+1299 143.18 6.95165048363e-05 0.0 0.0
+1300 143.291 6.33432111205e-05 0.0 0.0
+1301 143.401 5.70899099569e-05 0.0 0.0
+1302 143.511 5.07640014411e-05 0.0 0.0
+1303 143.621 4.43700150502e-05 0.0 0.0
+1304 143.732 3.79149593775e-05 0.0 0.0
+1305 143.842 3.14022407019e-05 0.0 0.0
+1306 143.952 2.48401531834e-05 0.0 0.0
+1307 144.062 1.82308830237e-05 0.0 0.0
+1308 144.172 1.15834363431e-05 0.0 0.0
+1309 144.283 4.90233704527e-06 0.0 0.0
+1310 144.393 -1.80869739608e-06 0.0 0.0
+1311 144.503 -8.53939439887e-06 0.0 0.0
+1312 144.613 -1.52899392026e-05 0.0 0.0
+1313 144.724 -2.20474277124e-05 0.0 0.0
+1314 144.834 -2.881412678e-05 0.0 0.0
+1315 144.944 -3.55765866939e-05 0.0 0.0
+1316 145.054 -4.2334211627e-05 0.0 0.0
+1317 145.164 -4.90794510215e-05 0.0 0.0
+1318 145.275 -5.58048525589e-05 0.0 0.0
+1319 145.385 -6.25095179174e-05 0.0 0.0
+1320 145.495 -6.91806779337e-05 0.0 0.0
+1321 145.605 -7.58203881357e-05 0.0 0.0
+1322 145.716 -8.24143009649e-05 0.0 0.0
+1323 145.826 -8.89667241215e-05 0.0 0.0
+1324 145.936 -9.54624057096e-05 0.0 0.0
+1325 146.046 -0.000101902827169 0.0 0.0
+1326 146.156 -0.000108277789491 0.0 0.0
+1327 146.267 -0.000114586097981 0.0 0.0
+1328 146.377 -0.000120817304481 0.0 0.0
+1329 146.487 -0.000126971088931 0.0 0.0
+1330 146.597 -0.000133037917441 0.0 0.0
+1331 146.708 -0.000139016475443 0.0 0.0
+1332 146.818 -0.000144897092241 0.0 0.0
+1333 146.928 -0.000150679632642 0.0 0.0
+1334 147.038 -0.000156354863447 0.0 0.0
+1335 147.148 -0.000161920115297 0.0 0.0
+1336 147.259 -0.000167371254048 0.0 0.0
+1337 147.369 -0.000172699694658 0.0 0.0
+1338 147.479 -0.000177907016037 0.0 0.0
+1339 147.589 -0.000182981668517 0.0 0.0
+1340 147.7 -0.000187925465523 0.0 0.0
+1341 147.81 -0.000192729522132 0.0 0.0
+1342 147.92 -0.000197392822648 0.0 0.0
+1343 148.03 -0.000201908239305 0.0 0.0
+1344 148.141 -0.000206275243616 0.0 0.0
+1345 148.251 -0.000210487248193 0.0 0.0
+1346 148.361 -0.000214541068073 0.0 0.0
+1347 148.471 -0.000218435036657 0.0 0.0
+1348 148.581 -0.000222160976111 0.0 0.0
+1349 148.692 -0.000225724723488 0.0 0.0
+1350 148.802 -0.000229108443911 0.0 0.0
+1351 148.912 -0.00023232684953 0.0 0.0
+1352 149.022 -0.000235360917917 0.0 0.0
+1353 149.133 -0.000238217811428 0.0 0.0
+1354 149.243 -0.000240893084145 0.0 0.0
+1355 149.353 -0.000243379250273 0.0 0.0
+1356 149.463 -0.000245682957418 0.0 0.0
+1357 149.573 -0.000247791313661 0.0 0.0
+1358 149.684 -0.000249712916974 0.0 0.0
+1359 149.794 -0.000251437185931 0.0 0.0
+1360 149.904 -0.000252968945288 0.0 0.0
+1361 150.014 -0.000254300631189 0.0 0.0
+1362 150.125 -0.000255437481289 0.0 0.0
+1363 150.235 -0.000256371852993 0.0 0.0
+1364 150.345 -0.000257107641166 0.0 0.0
+1365 150.455 -0.000257640244947 0.0 0.0
+1366 150.565 -0.000257972392499 0.0 0.0
+1367 150.676 -0.000258100037484 0.0 0.0
+1368 150.786 -0.000258025426563 0.0 0.0
+1369 150.896 -0.000257746874179 0.0 0.0
+1370 151.006 -0.000257264828706 0.0 0.0
+1371 151.117 -0.000256580371261 0.0 0.0
+1372 151.227 -0.000255689744577 0.0 0.0
+1373 151.337 -0.00025460008727 0.0 0.0
+1374 151.447 -0.000253305235386 0.0 0.0
+1375 151.557 -0.000251810416869 0.0 0.0
+1376 151.668 -0.000250114343693 0.0 0.0
+1377 151.778 -0.000248219507362 0.0 0.0
+1378 151.888 -0.000246125602018 0.0 0.0
+1379 151.998 -0.000243834669148 0.0 0.0
+1380 152.109 -0.000241350501455 0.0 0.0
+1381 152.219 -0.00023866909341 0.0 0.0
+1382 152.329 -0.000235800771573 0.0 0.0
+1383 152.439 -0.000232737553362 0.0 0.0
+1384 152.549 -0.000229491398466 0.0 0.0
+1385 152.66 -0.000226058091395 0.0 0.0
+1386 152.77 -0.000222441754009 0.0 0.0
+1387 152.88 -0.000218646885461 0.0 0.0
+1388 152.99 -0.000214673670062 0.0 0.0
+1389 153.101 -0.000210528264892 0.0 0.0
+1390 153.211 -0.000206208426821 0.0 0.0
+1391 153.321 -0.000201724341346 0.0 0.0
+1392 153.431 -0.000197073725454 0.0 0.0
+1393 153.541 -0.000192263003119 0.0 0.0
+1394 153.652 -0.000187293817597 0.0 0.0
+1395 153.762 -0.000182173843888 0.0 0.0
+1396 153.872 -0.000176900810876 0.0 0.0
+1397 153.982 -0.000171484917625 0.0 0.0
+1398 154.093 -0.000165926861908 0.0 0.0
+1399 154.203 -0.000160229940127 0.0 0.0
+1400 154.313 -0.000154405062252 0.0 0.0
+1401 154.423 -0.000148444935887 0.0 0.0
+1402 154.533 -0.000142368844931 0.0 0.0
+1403 154.644 -0.000136167210983 0.0 0.0
+1404 154.754 -0.000129856640999 0.0 0.0
+1405 154.864 -0.000123433314911 0.0 0.0
+1406 154.974 -0.000116908525725 0.0 0.0
+1407 155.085 -0.000110282550012 0.0 0.0
+1408 155.195 -0.000103565113015 0.0 0.0
+1409 155.305 -9.67559960237e-05 0.0 0.0
+1410 155.415 -8.98678487457e-05 0.0 0.0
+1411 155.525 -8.28971773627e-05 0.0 0.0
+1412 155.636 -7.58588029368e-05 0.0 0.0
+1413 155.746 -6.87503224871e-05 0.0 0.0
+1414 155.856 -6.15823020306e-05 0.0 0.0
+1415 155.966 -5.43591682977e-05 0.0 0.0
+1416 156.077 -4.70848445382e-05 0.0 0.0
+1417 156.187 -3.97688393821e-05 0.0 0.0
+1418 156.297 -3.24122479641e-05 0.0 0.0
+1419 156.407 -2.50251846329e-05 0.0 0.0
+1420 156.517 -1.7612391134e-05 0.0 0.0
+1421 156.628 -1.01754332033e-05 0.0 0.0
+1422 156.738 -2.73040637319e-06 0.0 0.0
+1423 156.848 4.73074946927e-06 0.0 0.0
+1424 156.958 1.21864874831e-05 0.0 0.0
+1425 157.069 1.96467739862e-05 0.0 0.0
+1426 157.179 2.70898698875e-05 0.0 0.0
+1427 157.289 3.4523644163e-05 0.0 0.0
+1428 157.399 4.19319777128e-05 0.0 0.0
+1429 157.509 4.93149688187e-05 0.0 0.0
+1430 157.62 5.66637069452e-05 0.0 0.0
+1431 157.73 6.39729622224e-05 0.0 0.0
+1432 157.84 7.1236808379e-05 0.0 0.0
+1433 157.95 7.84508484779e-05 0.0 0.0
+1434 158.061 8.5604855848e-05 0.0 0.0
+1435 158.171 9.26994479111e-05 0.0 0.0
+1436 158.281 9.97217905405e-05 0.0 0.0
+1437 158.391 0.000106672626137 0.0 0.0
+1438 158.502 0.000113541406311 0.0 0.0
+1439 158.612 0.000120324737019 0.0 0.0
+1440 158.722 0.000127017437103 0.0 0.0
+1441 158.832 0.000133611593487 0.0 0.0
+1442 158.942 0.00014010525265 0.0 0.0
+1443 159.053 0.000146489339901 0.0 0.0
+1444 159.163 0.000152761975062 0.0 0.0
+1445 159.273 0.000158914503191 0.0 0.0
+1446 159.383 0.00016494550569 0.0 0.0
+1447 159.494 0.00017084671933 0.0 0.0
+1448 159.604 0.000176614182252 0.0 0.0
+1449 159.714 0.000182245640624 0.0 0.0
+1450 159.824 0.000187730469736 0.0 0.0
+1451 159.934 0.000193070936133 0.0 0.0
+1452 160.045 0.000198257912769 0.0 0.0
+1453 160.155 0.00020328576587 0.0 0.0
+1454 160.265 0.000208159376613 0.0 0.0
+1455 160.375 0.000212858140901 0.0 0.0
+1456 160.486 0.00021739802737 0.0 0.0
+1457 160.596 0.000221755476531 0.0 0.0
+1458 160.706 0.000225943857524 0.0 0.0
+1459 160.816 0.000229944784011 0.0 0.0
+1460 160.926 0.00023376716613 0.0 0.0
+1461 161.037 0.000237397948485 0.0 0.0
+1462 161.147 0.00024084038258 0.0 0.0
+1463 161.257 0.000244087337898 0.0 0.0
+1464 161.367 0.000247138793415 0.0 0.0
+1465 161.478 0.000249988706006 0.0 0.0
+1466 161.588 0.000252638492641 0.0 0.0
+1467 161.698 0.000255081066532 0.0 0.0
+1468 161.808 0.000257318614668 0.0 0.0
+1469 161.918 0.000259344504404 0.0 0.0
+1470 162.029 0.000261160998687 0.0 0.0
+1471 162.139 0.000262763034984 0.0 0.0
+1472 162.249 0.000264149830341 0.0 0.0
+1473 162.359 0.000265320959444 0.0 0.0
+1474 162.47 0.000266273164141 0.0 0.0
+1475 162.58 0.000267007565092 0.0 0.0
+1476 162.69 0.000267519293831 0.0 0.0
+1477 162.8 0.000267813556109 0.0 0.0
+1478 162.91 0.000267882473789 0.0 0.0
+1479 163.021 0.000267731651376 0.0 0.0
+1480 163.131 0.000267356825254 0.0 0.0
+1481 163.241 0.000266760011977 0.0 0.0
+1482 163.351 0.000265939680972 0.0 0.0
+1483 163.462 0.000264896971915 0.0 0.0
+1484 163.572 0.000263633314476 0.0 0.0
+1485 163.682 0.000262144724292 0.0 0.0
+1486 163.792 0.000260438431916 0.0 0.0
+1487 163.902 0.000258510092568 0.0 0.0
+1488 164.013 0.000256362629401 0.0 0.0
+1489 164.123 0.00025399791051 0.0 0.0
+1490 164.233 0.000251416289319 0.0 0.0
+1491 164.343 0.000248618954275 0.0 0.0
+1492 164.454 0.000245610042355 0.0 0.0
+1493 164.564 0.000242386665548 0.0 0.0
+1494 164.674 0.000238958122584 0.0 0.0
+1495 164.784 0.000235317973716 0.0 0.0
+1496 164.894 0.000231476820157 0.0 0.0
+1497 165.005 0.000227430889716 0.0 0.0
+1498 165.115 0.000223186077352 0.0 0.0
+1499 165.225 0.000218746003297 0.0 0.0
+1500 165.335 0.000214109830438 0.0 0.0
+1501 165.446 0.000209285718569 0.0 0.0
+1502 165.556 0.000204272494265 0.0 0.0
+1503 165.666 0.000199077219746 0.0 0.0
+1504 165.776 0.000193699498885 0.0 0.0
+1505 165.887 0.000188150028487 0.0 0.0
+1506 165.997 0.000182422044935 0.0 0.0
+1507 166.107 0.000176532237619 0.0 0.0
+1508 166.217 0.000170472641308 0.0 0.0
+1509 166.327 0.000164258164213 0.0 0.0
+1510 166.438 0.000157883598196 0.0 0.0
+1511 166.548 0.000151363817512 0.0 0.0
+1512 166.658 0.000144691618963 0.0 0.0
+1513 166.768 0.000137884962222 0.0 0.0
+1514 166.879 0.000130935358343 0.0 0.0
+1515 166.989 0.000123861022758 0.0 0.0
+1516 167.099 0.000116654721248 0.0 0.0
+1517 167.209 0.000109332639667 0.0 0.0
+1518 167.319 0.000101890681722 0.0 0.0
+1519 167.43 9.43430015718e-05 0.0 0.0
+1520 167.54 8.66871882188e-05 0.0 0.0
+1521 167.65 7.89358139355e-05 0.0 0.0
+1522 167.76 7.10881806298e-05 0.0 0.0
+1523 167.871 6.31571491175e-05 0.0 0.0
+1524 167.981 5.51403208809e-05 0.0 0.0
+1525 168.091 4.70527917183e-05 0.0 0.0
+1526 168.201 3.88913017812e-05 0.0 0.0
+1527 168.311 3.06715429209e-05 0.0 0.0
+1528 168.422 2.23893419011e-05 0.0 0.0
+1529 168.532 1.40605654417e-05 0.0 0.0
+1530 168.642 5.68490911782e-06 0.0 0.0
+1531 168.752 -2.72860641007e-06 0.0 0.0
+1532 168.863 -1.11744112039e-05 0.0 0.0
+1533 168.973 -1.96449544359e-05 0.0 0.0
+1534 169.083 -2.81365302338e-05 0.0 0.0
+1535 169.193 -3.66389212575e-05 0.0 0.0
+1536 169.303 -4.51498739043e-05 0.0 0.0
+1537 169.414 -5.36582943725e-05 0.0 0.0
+1538 169.524 -6.21638749163e-05 0.0 0.0
+1539 169.634 -7.06511879098e-05 0.0 0.0
+1540 169.744 -7.91262113939e-05 0.0 0.0
+1541 169.855 -8.75674848083e-05 0.0 0.0
+1542 169.965 -9.59829679469e-05 0.0 0.0
+1543 170.075 -0.000104356608658 0.0 0.0
+1544 170.185 -0.000112684564782 0.0 0.0
+1545 170.295 -0.00012096293552 0.0 0.0
+1546 170.406 -0.000129182741458 0.0 0.0
+1547 170.516 -0.000137336694936 0.0 0.0
+1548 170.626 -0.000145422928889 0.0 0.0
+1549 170.736 -0.000153429802598 0.0 0.0
+1550 170.847 -0.000161355416835 0.0 0.0
+1551 170.957 -0.000169191176752 0.0 0.0
+1552 171.067 -0.000176931909636 0.0 0.0
+1553 171.177 -0.000184571754996 0.0 0.0
+1554 171.287 -0.000192103209901 0.0 0.0
+1555 171.398 -0.000199524570443 0.0 0.0
+1556 171.508 -0.000206822221979 0.0 0.0
+1557 171.618 -0.000214001537206 0.0 0.0
+1558 171.728 -0.000221045217041 0.0 0.0
+1559 171.839 -0.000227955638146 0.0 0.0
+1560 171.949 -0.000234726369099 0.0 0.0
+1561 172.059 -0.000241346179485 0.0 0.0
+1562 172.169 -0.000247820114315 0.0 0.0
+1563 172.279 -0.000254131515601 0.0 0.0
+1564 172.39 -0.000260285165366 0.0 0.0
+1565 172.5 -0.00026627004762 0.0 0.0
+1566 172.61 -0.000272083408741 0.0 0.0
+1567 172.72 -0.000277722294645 0.0 0.0
+1568 172.831 -0.000283176475907 0.0 0.0
+1569 172.941 -0.00028845139225 0.0 0.0
+1570 173.051 -0.000293530552804 0.0 0.0
+1571 173.161 -0.000298420729028 0.0 0.0
+1572 173.271 -0.000303111146634 0.0 0.0
+1573 173.382 -0.000307600939358 0.0 0.0
+1574 173.492 -0.000311884627538 0.0 0.0
+1575 173.602 -0.000315962008367 0.0 0.0
+1576 173.712 -0.000319822952463 0.0 0.0
+1577 173.823 -0.000323474075254 0.0 0.0
+1578 173.933 -0.00032690187716 0.0 0.0
+1579 174.043 -0.000330111583297 0.0 0.0
+1580 174.153 -0.000333095080113 0.0 0.0
+1581 174.263 -0.000335853868643 0.0 0.0
+1582 174.374 -0.00033838143134 0.0 0.0
+1583 174.484 -0.000340679185839 0.0 0.0
+1584 174.594 -0.000342742874933 0.0 0.0
+1585 174.704 -0.00034457061649 0.0 0.0
+1586 174.815 -0.000346162526901 0.0 0.0
+1587 174.925 -0.000347514694929 0.0 0.0
+1588 175.035 -0.000348626233115 0.0 0.0
+1589 175.145 -0.000349498887465 0.0 0.0
+1590 175.255 -0.000350125990152 0.0 0.0
+1591 175.366 -0.000350512579079 0.0 0.0
+1592 175.476 -0.000350653471907 0.0 0.0
+1593 175.586 -0.000350551814074 0.0 0.0
+1594 175.696 -0.000350202961284 0.0 0.0
+1595 175.807 -0.000349612864118 0.0 0.0
+1596 175.917 -0.000348773902183 0.0 0.0
+1597 176.027 -0.000347695449257 0.0 0.0
+1598 176.137 -0.000346367209131 0.0 0.0
+1599 176.248 -0.000344801270023 0.0 0.0
+1600 176.358 -0.00034298897849 0.0 0.0
+1601 176.468 -0.00034093527198 0.0 0.0
+1602 176.578 -0.000338644917558 0.0 0.0
+1603 176.688 -0.00033610927337 0.0 0.0
+1604 176.799 -0.000333342501898 0.0 0.0
+1605 176.909 -0.000330333934239 0.0 0.0
+1606 177.019 -0.000327097585727 0.0 0.0
+1607 177.129 -0.000323622406628 0.0 0.0
+1608 177.24 -0.000319925101459 0.0 0.0
+1609 177.35 -0.000315992924593 0.0 0.0
+1610 177.46 -0.000311842903299 0.0 0.0
+1611 177.57 -0.000307465782688 0.0 0.0
+1612 177.68 -0.000302873497615 0.0 0.0
+1613 177.791 -0.000298062082827 0.0 0.0
+1614 177.901 -0.000293041150318 0.0 0.0
+1615 178.011 -0.000287808436745 0.0 0.0
+1616 178.121 -0.000282371301545 0.0 0.0
+1617 178.232 -0.000276733480855 0.0 0.0
+1618 178.342 -0.000270893716485 0.0 0.0
+1619 178.452 -0.000264866002264 0.0 0.0
+1620 178.562 -0.000258642351221 0.0 0.0
+1621 178.672 -0.000252237777139 0.0 0.0
+1622 178.783 -0.000245650380815 0.0 0.0
+1623 178.893 -0.000238886699833 0.0 0.0
+1624 179.003 -0.000231951797185 0.0 0.0
+1625 179.113 -0.00022485098824 0.0 0.0
+1626 179.224 -0.00021758677685 0.0 0.0
+1627 179.334 -0.000210167706088 0.0 0.0
+1628 179.444 -0.000202597302376 0.0 0.0
+1629 179.554 -0.00019487908992 0.0 0.0
+1630 179.664 -0.000187024414159 0.0 0.0
+1631 179.775 -0.000179030461941 0.0 0.0
+1632 179.885 -0.000170911607766 0.0 0.0
+1633 179.995 -0.000162666408171 0.0 0.0
+1634 180.105 -0.000154306699372 0.0 0.0
+1635 180.216 -0.000145832516504 0.0 0.0
+1636 180.326 -0.000137257372766 0.0 0.0
+1637 180.436 -0.000128578120769 0.0 0.0
+1638 180.546 -0.000119812237915 0.0 0.0
+1639 180.656 -0.000110952878668 0.0 0.0
+1640 180.767 -0.000102021361137 0.0 0.0
+1641 180.877 -9.30079938999e-05 0.0 0.0
+1642 180.987 -8.39363820851e-05 0.0 0.0
+1643 181.097 -7.4795441512e-05 0.0 0.0
+1644 181.208 -6.56093108589e-05 0.0 0.0
+1645 181.318 -5.63685744498e-05 0.0 0.0
+1646 181.428 -4.70933063052e-05 0.0 0.0
+1647 181.538 -3.7779911294e-05 0.0 0.0
+1648 181.648 -2.84436629186e-05 0.0 0.0
+1649 181.759 -1.90834000302e-05 0.0 0.0
+1650 181.869 -9.71395001329e-06 0.0 0.0
+1651 181.979 -3.33898936347e-07 0.0 0.0
+1652 182.089 9.04111362581e-06 0.0 0.0
+1653 182.2 1.84132829304e-05 0.0 0.0
+1654 182.31 2.77673439365e-05 0.0 0.0
+1655 182.42 3.71035402064e-05 0.0 0.0
+1656 182.53 4.64093076339e-05 0.0 0.0
+1657 182.64 5.56821425786e-05 0.0 0.0
+1658 182.751 6.49126715718e-05 0.0 0.0
+1659 182.861 7.4095166644e-05 0.0 0.0
+1660 182.971 8.32217761105e-05 0.0 0.0
+1661 183.081 9.22886477344e-05 0.0 0.0
+1662 183.192 0.000101284925168 0.0 0.0
+1663 183.302 0.000110207096197 0.0 0.0
+1664 183.412 0.000119048380619 0.0 0.0
+1665 183.522 0.000127800681689 0.0 0.0
+1666 183.632 0.000136457962303 0.0 0.0
+1667 183.743 0.000145016042668 0.0 0.0
+1668 183.853 0.000153465602875 0.0 0.0
+1669 183.963 0.000161800983988 0.0 0.0
+1670 184.073 0.000170020048727 0.0 0.0
+1671 184.184 0.000178108105023 0.0 0.0
+1672 184.294 0.000186070937278 0.0 0.0
+1673 184.404 0.000193889818181 0.0 0.0
+1674 184.514 0.000201571200215 0.0 0.0
+1675 184.624 0.000209098006757 0.0 0.0
+1676 184.735 0.000216476839656 0.0 0.0
+1677 184.845 0.000223687934532 0.0 0.0
+1678 184.955 0.000230741354094 0.0 0.0
+1679 185.065 0.000237618209163 0.0 0.0
+1680 185.176 0.000244323622084 0.0 0.0
+1681 185.286 0.000250845147568 0.0 0.0
+1682 185.396 0.000257184820808 0.0 0.0
+1683 185.506 0.000263330356739 0.0 0.0
+1684 185.617 0.000269284693859 0.0 0.0
+1685 185.727 0.000275038454079 0.0 0.0
+1686 185.837 0.000280588436076 0.0 0.0
+1687 185.947 0.000285932544074 0.0 0.0
+1688 186.057 0.000291063068997 0.0 0.0
+1689 186.168 0.000295981416717 0.0 0.0
+1690 186.278 0.000300677536214 0.0 0.0
+1691 186.388 0.000305154210068 0.0 0.0
+1692 186.498 0.000309404248581 0.0 0.0
+1693 186.609 0.000313424262069 0.0 0.0
+1694 186.719 0.000317215331754 0.0 0.0
+1695 186.829 0.000320769243619 0.0 0.0
+1696 186.939 0.000324087996836 0.0 0.0
+1697 187.049 0.000327165308813 0.0 0.0
+1698 187.16 0.00033000346036 0.0 0.0
+1699 187.27 0.000332593775307 0.0 0.0
+1700 187.38 0.000334943382489 0.0 0.0
+1701 187.49 0.000337039981945 0.0 0.0
+1702 187.601 0.000338891903973 0.0 0.0
+1703 187.711 0.000340491170665 0.0 0.0
+1704 187.821 0.000341839302989 0.0 0.0
+1705 187.931 0.00034293507793 0.0 0.0
+1706 188.041 0.000343777616914 0.0 0.0
+1707 188.152 0.000344365791944 0.0 0.0
+1708 188.262 0.00034470063933 0.0 0.0
+1709 188.372 0.000344779421078 0.0 0.0
+1710 188.482 0.000344605181616 0.0 0.0
+1711 188.593 0.000344176300368 0.0 0.0
+1712 188.703 0.000343492904753 0.0 0.0
+1713 188.813 0.000342556152924 0.0 0.0
+1714 188.923 0.000341367471129 0.0 0.0
+1715 189.033 0.000339927174171 0.0 0.0
+1716 189.144 0.000338234009763 0.0 0.0
+1717 189.254 0.000336296344993 0.0 0.0
+1718 189.364 0.000334105032488 0.0 0.0
+1719 189.474 0.000331673224631 0.0 0.0
+1720 189.585 0.000328993233471 0.0 0.0
+1721 189.695 0.000326074104923 0.0 0.0
+1722 189.805 0.000322912352982 0.0 0.0
+1723 189.915 0.000319517462708 0.0 0.0
+1724 190.025 0.000315881526557 0.0 0.0
+1725 190.136 0.000312021917409 0.0 0.0
+1726 190.246 0.00030792434344 0.0 0.0
+1727 190.356 0.000303609446506 0.0 0.0
+1728 190.466 0.000299065640732 0.0 0.0
+1729 190.577 0.000294306730029 0.0 0.0
+1730 190.687 0.000289330780668 0.0 0.0
+1731 190.797 0.000284143990197 0.0 0.0
+1732 190.907 0.000278749903237 0.0 0.0
+1733 191.017 0.000273151168244 0.0 0.0
+1734 191.128 0.000267356357211 0.0 0.0
+1735 191.238 0.000261363039193 0.0 0.0
+1736 191.348 0.000255182678447 0.0 0.0
+1737 191.458 0.000248816967996 0.0 0.0
+1738 191.569 0.000242269208961 0.0 0.0
+1739 191.679 0.000235547394731 0.0 0.0
+1740 191.789 0.000228655739803 0.0 0.0
+1741 191.899 0.000221598752133 0.0 0.0
+1742 192.009 0.000214382041951 0.0 0.0
+1743 192.12 0.000207012729753 0.0 0.0
+1744 192.23 0.000199493739271 0.0 0.0
+1745 192.34 0.000191833686784 0.0 0.0
+1746 192.45 0.000184036744439 0.0 0.0
+1747 192.561 0.000176108556243 0.0 0.0
+1748 192.671 0.000168057851293 0.0 0.0
+1749 192.781 0.000159886375115 0.0 0.0
+1750 192.891 0.000151606071145 0.0 0.0
+1751 193.001 0.00014321737496 0.0 0.0
+1752 193.112 0.000134732365944 0.0 0.0
+1753 193.222 0.000126152086541 0.0 0.0
+1754 193.332 0.000117488933694 0.0 0.0
+1755 193.442 0.000108743875334 0.0 0.0
+1756 193.553 9.99282334665e-05 0.0 0.0
+1757 193.663 9.10471158466e-05 0.0 0.0
+1758 193.773 8.21039576787e-05 0.0 0.0
+1759 193.883 7.31157799569e-05 0.0 0.0
+1760 193.994 6.40738438978e-05 0.0 0.0
+1761 194.104 5.5002501456e-05 0.0 0.0
+1762 194.214 4.58935067512e-05 0.0 0.0
+1763 194.324 3.67658888512e-05 0.0 0.0
+1764 194.434 2.76176908626e-05 0.0 0.0
+1765 194.545 1.84617241096e-05 0.0 0.0
+1766 194.655 9.30402751638e-06 0.0 0.0
+1767 194.765 1.47189464719e-07 0.0 0.0
+1768 194.875 -8.99319729187e-06 0.0 0.0
+1769 194.986 -1.81183961862e-05 0.0 0.0
+1770 195.096 -2.7216714605e-05 0.0 0.0
+1771 195.206 -3.62810942662e-05 0.0 0.0
+1772 195.316 -4.53078512127e-05 0.0 0.0
+1773 195.426 -5.4285461911e-05 0.0 0.0
+1774 195.537 -6.32093415566e-05 0.0 0.0
+1775 195.647 -7.20754087921e-05 0.0 0.0
+1776 195.757 -8.08681533837e-05 0.0 0.0
+1777 195.867 -8.95917815527e-05 0.0 0.0
+1778 195.978 -9.82299050789e-05 0.0 0.0
+1779 196.088 -0.000106782481553 0.0 0.0
+1780 196.198 -0.000115238607989 0.0 0.0
+1781 196.308 -0.000123593241665 0.0 0.0
+1782 196.418 -0.000131841879323 0.0 0.0
+1783 196.529 -0.000139971736097 0.0 0.0
+1784 196.639 -0.000147986409272 0.0 0.0
+1785 196.749 -0.000155867980723 0.0 0.0
+1786 196.859 -0.000163621327334 0.0 0.0
+1787 196.97 -0.000171231032244 0.0 0.0
+1788 197.08 -0.000178698702332 0.0 0.0
+1789 197.19 -0.000186011736278 0.0 0.0
+1790 197.3 -0.000193170992937 0.0 0.0
+1791 197.41 -0.000200163984332 0.0 0.0
+1792 197.521 -0.000206992194708 0.0 0.0
+1793 197.631 -0.000213642963042 0.0 0.0
+1794 197.741 -0.000220118641589 0.0 0.0
+1795 197.851 -0.000226405860449 0.0 0.0
+1796 197.962 -0.000232508059708 0.0 0.0
+1797 198.072 -0.000238413175973 0.0 0.0
+1798 198.182 -0.000244120533127 0.0 0.0
+1799 198.292 -0.000249625503574 0.0 0.0
+1800 198.402 -0.000254920369164 0.0 0.0
+1801 198.513 -0.000260006350728 0.0 0.0
+1802 198.623 -0.000264872472187 0.0 0.0
+1803 198.733 -0.000269522268195 0.0 0.0
+1804 198.843 -0.000273945458811 0.0 0.0
+1805 198.954 -0.000278142191946 0.0 0.0
+1806 199.064 -0.00028210797719 0.0 0.0
+1807 199.174 -0.000285840050687 0.0 0.0
+1808 199.284 -0.000289333906775 0.0 0.0
+1809 199.394 -0.000292588030428 0.0 0.0
+1810 199.505 -0.000295600089235 0.0 0.0
+1811 199.615 -0.000298364894157 0.0 0.0
+1812 199.725 -0.000300884142331 0.0 0.0
+1813 199.835 -0.000303151948384 0.0 0.0
+1814 199.946 -0.000305168028548 0.0 0.0
diff --git a/test/corfunc/test/utest_corfunc.py b/test/corfunc/test/utest_corfunc.py
index c20c67e..e7bf5f3 100644
--- a/test/corfunc/test/utest_corfunc.py
+++ b/test/corfunc/test/utest_corfunc.py
@@ -1,30 +1,45 @@
"""
Unit Tests for CorfuncCalculator class
"""
+from __future__ import division, print_function
import unittest
import time
+
import numpy as np
+
from sas.sascalc.corfunc.corfunc_calculator import CorfuncCalculator
from sas.sascalc.dataloader.data_info import Data1D
-import matplotlib.pyplot as plt
+
class TestCalculator(unittest.TestCase):
def setUp(self):
self.data = load_data()
+ # Note: to generate target values from the GUI:
+ # * load the data from test/corfunc/test/98929.txt
+ # * set qrange to (0, 0.013), (0.15, 0.24)
+ # * select fourier transform type
+ # * click Calculate Bg
+ # * click Extrapolate
+ # * click Compute Parameters
+ # * copy the Guinier and Porod values to the extrapolate function
+ # * for each graph, grab the data from DataInfo and store it in _out.txt
self.calculator = CorfuncCalculator(data=self.data, lowerq=0.013,
upperq=(0.15, 0.24))
+ self.calculator.background = 0.3
self.extrapolation = None
+ self.transformation = None
+ self.results = [np.loadtxt(filename+"_out.txt").T[2]
+ for filename in ("gamma1", "gamma3", "idf")]
def extrapolate(self):
- params, extrapolation = self.calculator.compute_extrapolation()
-
+ params, extrapolation, s2 = self.calculator.compute_extrapolation()
# Check the extrapolation parameters
- self.assertAlmostEqual(params['A'], 4.19, places=2)
- self.assertAlmostEqual(params['B'], -25470, places=0)
- self.assertAlmostEqual(params['K'], 4.5e-5, places=2)
- self.assertAlmostEqual(params['sigma'], 2.2e-10, places=2)
+ self.assertAlmostEqual(params['A'], 4.18970, places=5)
+ self.assertAlmostEqual(params['B'], -25469.9, places=1)
+ self.assertAlmostEqual(params['K'], 4.44660e-5, places=10)
+ #self.assertAlmostEqual(params['sigma'], 1.70181e-10, places=15)
# Ensure the extraplation tends to the background value
self.assertAlmostEqual(extrapolation.y[-1], self.calculator.background)
@@ -56,32 +71,45 @@ class TestCalculator(unittest.TestCase):
if not self.calculator.transform_isrunning():
break
- def transform_callback(self, transform):
- self.assertIsNotNone(transform)
- self.assertAlmostEqual(transform.y[0], 1)
- self.assertAlmostEqual(transform.y[-1], 0, 5)
- self.transformation = transform
+ def transform_callback(self, transforms):
+ transform1, transform3, idf = transforms
+ self.assertIsNotNone(transform1)
+ self.assertAlmostEqual(transform1.y[0], 1)
+ self.assertAlmostEqual(transform1.y[-1], 0, 5)
+ self.transformation = transforms
def extract_params(self):
- params = self.calculator.extract_parameters(self.transformation)
+ params = self.calculator.extract_parameters(self.transformation[0])
self.assertIsNotNone(params)
self.assertEqual(len(params), 6)
self.assertLess(abs(params['max']-75), 2.5) # L_p ~= 75
+ def check_transforms(self):
+ gamma1, gamma3, idf = self.transformation
+ gamma1_out, gamma3_out, idf_out = self.results
+ def compare(a, b):
+ return max(abs((a-b)/b))
+ #print("gamma1 diff", compare(gamma1.y[gamma1.x<=200.], gamma1_out))
+ #print("gamma3 diff", compare(gamma3.y[gamma3.x<=200.], gamma3_out))
+ #print("idf diff", compare(idf.y[idf.x<=200.], idf_out))
+ #self.assertLess(compare(gamma1.y[gamma1.x<=200.], gamma1_out), 1e-10)
+ #self.assertLess(compare(gamma3.y[gamma3.x<=200.], gamma3_out), 1e-10)
+ #self.assertLess(compare(idf.y[idf.x<=200.], idf_out), 1e-10)
# Ensure tests are ran in correct order;
# Each test depends on the one before it
def test_calculator(self):
- steps = [self.extrapolate, self.transform, self.extract_params]
+ steps = [self.extrapolate, self.transform, self.extract_params, self.check_transforms]
for test in steps:
try:
test()
except Exception as e:
+ raise
self.fail("{} failed ({}: {})".format(test, type(e), e))
def load_data(filename="98929.txt"):
- data = np.loadtxt(filename, dtype=np.float32)
+ data = np.loadtxt(filename, dtype=np.float64)
q = data[:,0]
iq = data[:,1]
return Data1D(x=q, y=iq)
diff --git a/src/sas/__init__.py b/test/fileconverter/__init__.py
similarity index 100%
copy from src/sas/__init__.py
copy to test/fileconverter/__init__.py
diff --git a/src/sas/__init__.py b/test/fileconverter/test/__init__.py
similarity index 100%
copy from src/sas/__init__.py
copy to test/fileconverter/test/__init__.py
diff --git a/test/fileconverter/test/cansas1d.xml b/test/fileconverter/test/cansas1d.xml
index bebb95b..4f2b969 100644
--- a/test/fileconverter/test/cansas1d.xml
+++ b/test/fileconverter/test/cansas1d.xml
@@ -25,6 +25,30 @@
<Qmean unit="1/A"><!-- Qmean is optional --></Qmean>
<Shadowfactor><!-- Shadowfactor is optional --></Shadowfactor>
</Idata>
+ <Idata>
+ <Q unit="1/A">0.04</Q>
+ <I unit="1/cm">1002</I>
+ <Idev unit="1/cm">4</Idev>
+ <Qdev unit="1/A">0.02</Qdev>
+ <Qmean unit="1/A"><!-- Qmean is optional --></Qmean>
+ <Shadowfactor><!-- Shadowfactor is optional --></Shadowfactor>
+ </Idata>
+ <Idata>
+ <Q unit="1/A">0.05</Q>
+ <I unit="1/cm">1003</I>
+ <Idev unit="1/cm">4</Idev>
+ <Qdev unit="1/A">0.02</Qdev>
+ <Qmean unit="1/A"><!-- Qmean is optional --></Qmean>
+ <Shadowfactor><!-- Shadowfactor is optional --></Shadowfactor>
+ </Idata>
+ <Idata>
+ <Q unit="1/A">0.06</Q>
+ <I unit="1/cm">1004</I>
+ <Idev unit="1/cm">4</Idev>
+ <Qdev unit="1/A">0.02</Qdev>
+ <Qmean unit="1/A"><!-- Qmean is optional --></Qmean>
+ <Shadowfactor><!-- Shadowfactor is optional --></Shadowfactor>
+ </Idata>
</SASdata>
<SASsample name='my sample'>
<ID>SI600-new-long</ID>
@@ -46,7 +70,7 @@
<details>
Some text here
</details>
-
+
</SASsample>
<SASinstrument>
<name>canSAS instrument</name>
diff --git a/test/fileconverter/test/export2d.h5 b/test/fileconverter/test/export2d.h5
deleted file mode 100644
index 38ebacf..0000000
Binary files a/test/fileconverter/test/export2d.h5 and /dev/null differ
diff --git a/test/fileconverter/test/utest_nxcansas_writer.py b/test/fileconverter/test/utest_nxcansas_writer.py
index 98a22e8..b8a77ae 100644
--- a/test/fileconverter/test/utest_nxcansas_writer.py
+++ b/test/fileconverter/test/utest_nxcansas_writer.py
@@ -1,7 +1,5 @@
from sas.sascalc.file_converter.nxcansas_writer import NXcanSASWriter
-from sas.sascalc.dataloader.readers.cansas_reader import Reader as XMLReader
-from sas.sascalc.dataloader.readers.red2d_reader import Reader as DATReader
-from sas.sascalc.dataloader.readers.cansas_reader_HDF5 import Reader as HDF5Reader
+from sas.sascalc.dataloader.loader import Loader
import os
import pylint
@@ -13,24 +11,22 @@ warnings.simplefilter("ignore")
class nxcansas_writer(unittest.TestCase):
def setUp(self):
+ self.loader = Loader()
self.writer = NXcanSASWriter()
self.read_file_1d = "cansas1d.xml"
self.write_file_1d = "export1d.h5"
self.read_file_2d = "exp18_14_igor_2dqxqy.dat"
self.write_file_2d = "export2d.h5"
- self.hdf5_reader = HDF5Reader()
- xml_reader = XMLReader()
- self.data_1d = xml_reader.read(self.read_file_1d)[0]
+ self.data_1d = self.loader.load(self.read_file_1d)[0]
- dat_reader = DATReader()
- self.data_2d = dat_reader.read(self.read_file_2d)
+ self.data_2d = self.loader.load(self.read_file_2d)[0]
self.data_2d.detector[0].name = ''
self.data_2d.source.radiation = 'neutron'
def test_write_1d(self):
self.writer.write([self.data_1d], self.write_file_1d)
- data = self.hdf5_reader.read(self.write_file_1d)
+ data = self.loader.load(self.write_file_1d)
self.assertTrue(len(data) == 1)
data = data[0]
self.assertTrue(len(data.x) == len(self.data_1d.x))
@@ -40,7 +36,7 @@ class nxcansas_writer(unittest.TestCase):
def test_write_2d(self):
self.writer.write([self.data_2d], self.write_file_2d)
- data = self.hdf5_reader.read(self.write_file_2d)
+ data = self.loader.load(self.write_file_2d)
self.assertTrue(len(data) == 1)
data = data[0]
self.assertTrue(len(data.data) == len(self.data_2d.data))
@@ -65,3 +61,5 @@ class nxcansas_writer(unittest.TestCase):
def tearDown(self):
if os.path.isfile(self.write_file_1d):
os.remove(self.write_file_1d)
+ if os.path.isfile(self.write_file_2d):
+ os.remove(self.write_file_2d)
diff --git a/test/logging.ini b/test/logging.ini
new file mode 100644
index 0000000..593a9d5
--- /dev/null
+++ b/test/logging.ini
@@ -0,0 +1,48 @@
+
+###############################################################################
+################################### LOGGING ###################################
+###############################################################################
+
+[formatters]
+keys=simple,detailed
+
+[formatter_simple]
+format=%(name)s: %(levelname)s: %(message)s
+
+[formatter_detailed]
+format=%(name)s: %(levelname)s %(module)s: %(lineno)d: %(message)s
+
+###############################################################################
+# Handlers
+
+[handlers]
+keys=console,log_file
+
+[handler_console]
+class=logging.StreamHandler
+formatter=simple
+level=DEBUG
+args=tuple()
+
+[handler_log_file]
+class=logging.FileHandler
+level=INFO
+formatter=detailed
+args=('tests.log','w')
+
+###############################################################################
+# Loggers
+
+[loggers]
+keys=root,sas
+
+[logger_root]
+level=DEBUG
+handlers=console,log_file
+propagate=0
+
+[logger_sas]
+level=INFO
+qualname=sas
+handlers=console,log_file
+propagate=0
\ No newline at end of file
diff --git a/src/sas/__init__.py b/test/pr_inversion/__init__.py
similarity index 100%
copy from src/sas/__init__.py
copy to test/pr_inversion/__init__.py
diff --git a/src/sas/__init__.py b/test/pr_inversion/test/__init__.py
similarity index 100%
copy from src/sas/__init__.py
copy to test/pr_inversion/test/__init__.py
diff --git a/test/pr_inversion/test/utest_explorer.py b/test/pr_inversion/test/utest_explorer.py
index ec0fa14..056488f 100644
--- a/test/pr_inversion/test/utest_explorer.py
+++ b/test/pr_inversion/test/utest_explorer.py
@@ -1,34 +1,34 @@
-"""
- Unit tests for DistExplorer class
-"""
-
-import unittest, math, numpy
-from utest_invertor import load
-from sas.sascalc.pr.invertor import Invertor
-from sas.sascalc.pr.distance_explorer import DistExplorer
-
-class TestExplorer(unittest.TestCase):
-
- def setUp(self):
- self.invertor = Invertor()
- x, y, err = load('sphere_80.txt')
-
- # Choose the right d_max...
- self.invertor.d_max = 160.0
- # Set a small alpha
- self.invertor.alpha = .0007
- # Set data
- self.invertor.x = x
- self.invertor.y = y
- self.invertor.err = err
- self.invertor.nfunc = 15
-
- self.explo = DistExplorer(self.invertor)
-
- def test_exploration(self):
- results = self.explo(120, 200, 25)
- self.assertEqual(len(results.errors), 0)
- self.assertEqual(len(results.chi2), 25)
-
-if __name__ == '__main__':
- unittest.main()
+"""
+ Unit tests for DistExplorer class
+"""
+
+import unittest, math, numpy
+from utest_invertor import load
+from sas.sascalc.pr.invertor import Invertor
+from sas.sascalc.pr.distance_explorer import DistExplorer
+
+class TestExplorer(unittest.TestCase):
+
+ def setUp(self):
+ self.invertor = Invertor()
+ x, y, err = load('sphere_80.txt')
+
+ # Choose the right d_max...
+ self.invertor.d_max = 160.0
+ # Set a small alpha
+ self.invertor.alpha = .0007
+ # Set data
+ self.invertor.x = x
+ self.invertor.y = y
+ self.invertor.err = err
+ self.invertor.nfunc = 15
+
+ self.explo = DistExplorer(self.invertor)
+
+ def test_exploration(self):
+ results = self.explo(120, 200, 25)
+ self.assertEqual(len(results.errors), 0)
+ self.assertEqual(len(results.chi2), 25)
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/test/pr_inversion/test/utest_invertor.py b/test/pr_inversion/test/utest_invertor.py
index f6f0145..4789bed 100644
--- a/test/pr_inversion/test/utest_invertor.py
+++ b/test/pr_inversion/test/utest_invertor.py
@@ -1,600 +1,610 @@
-"""
- Unit tests for Invertor class
-"""
-# Disable "missing docstring" complaint
-# pylint: disable-msg=C0111
-# Disable "too many methods" complaint
-# pylint: disable-msg=R0904
-
-
-import unittest, math, numpy
-from sas.sascalc.pr.invertor import Invertor
-
-class TestFiguresOfMerit(unittest.TestCase):
-
- def setUp(self):
- self.invertor = Invertor()
- self.invertor.d_max = 100.0
-
- # Test array
- self.ntest = 5
- self.x_in = numpy.ones(self.ntest)
- for i in range(self.ntest):
- self.x_in[i] = 1.0*(i+1)
-
- x, y, err = load("sphere_80.txt")
-
- # Choose the right d_max...
- self.invertor.d_max = 160.0
- # Set a small alpha
- self.invertor.alpha = .0007
- # Set data
- self.invertor.x = x
- self.invertor.y = y
- self.invertor.err = err
- # Perform inversion
- #out, cov = self.invertor.invert(10)
-
- self.out, self.cov = self.invertor.lstsq(10)
-
- def test_positive(self):
- """
- Test whether P(r) is positive
- """
- self.assertEqual(self.invertor.get_positive(self.out), 1)
-
- def test_positive_err(self):
- """
- Test whether P(r) is at least 1 sigma greater than zero
- for all r-values
- """
- self.assertTrue(self.invertor.get_pos_err(self.out, self.cov)>0.9)
-
-class TestBasicComponent(unittest.TestCase):
-
- def setUp(self):
- self.invertor = Invertor()
- self.invertor.d_max = 100.0
-
- # Test array
- self.ntest = 5
- self.x_in = numpy.ones(self.ntest)
- for i in range(self.ntest):
- self.x_in[i] = 1.0*(i+1)
-
- def test_has_bck_flag(self):
- """
- Tests the has_bck flag operations
- """
- self.assertEqual(self.invertor.has_bck, False)
- self.invertor.has_bck=True
- self.assertEqual(self.invertor.has_bck, True)
- def doit_float():
- self.invertor.has_bck = 2.0
- def doit_str():
- self.invertor.has_bck = 'a'
-
- self.assertRaises(ValueError, doit_float)
- self.assertRaises(ValueError, doit_str)
-
-
- def testset_dmax(self):
- """
- Set and read d_max
- """
- value = 15.0
- self.invertor.d_max = value
- self.assertEqual(self.invertor.d_max, value)
-
- def testset_alpha(self):
- """
- Set and read alpha
- """
- value = 15.0
- self.invertor.alpha = value
- self.assertEqual(self.invertor.alpha, value)
-
- def testset_x_1(self):
- """
- Setting and reading the x array the hard way
- """
- # Set x
- self.invertor.x = self.x_in
-
- # Read it back
- npts = self.invertor.get_nx()
- x_out = numpy.ones(npts)
-
- self.invertor.get_x(x_out)
-
- for i in range(self.ntest):
- self.assertEqual(self.x_in[i], x_out[i])
-
- def testset_x_2(self):
- """
- Setting and reading the x array the easy way
- """
- # Set x
- self.invertor.x = self.x_in
-
- # Read it back
- x_out = self.invertor.x
-
- for i in range(self.ntest):
- self.assertEqual(self.x_in[i], x_out[i])
-
- def testset_y(self):
- """
- Setting and reading the y array the easy way
- """
- # Set y
- self.invertor.y = self.x_in
-
- # Read it back
- y_out = self.invertor.y
-
- for i in range(self.ntest):
- self.assertEqual(self.x_in[i], y_out[i])
-
- def testset_err(self):
- """
- Setting and reading the err array the easy way
- """
- # Set err
- self.invertor.err = self.x_in
-
- # Read it back
- err_out = self.invertor.err
-
- for i in range(self.ntest):
- self.assertEqual(self.x_in[i], err_out[i])
-
- def test_iq(self):
- """
- Test iq calculation
- """
- q = 0.11
- v1 = 8.0*math.pi**2/q * self.invertor.d_max *math.sin(q*self.invertor.d_max)
- v1 /= ( math.pi**2 - (q*self.invertor.d_max)**2.0 )
-
- pars = numpy.ones(1)
- self.assertAlmostEqual(self.invertor.iq(pars, q), v1, 2)
-
- def test_pr(self):
- """
- Test pr calculation
- """
- r = 10.0
- v1 = 2.0*r*math.sin(math.pi*r/self.invertor.d_max)
- pars = numpy.ones(1)
- self.assertAlmostEqual(self.invertor.pr(pars, r), v1, 2)
-
- def test_getsetters(self):
- self.invertor.new_data = 1.0
- self.assertEqual(self.invertor.new_data, 1.0)
-
- self.assertEqual(self.invertor.test_no_data, None)
-
- def test_slitsettings(self):
- self.invertor.slit_width = 1.0
- self.assertEqual(self.invertor.slit_width, 1.0)
- self.invertor.slit_height = 2.0
- self.assertEqual(self.invertor.slit_height, 2.0)
-
-
- def test_inversion(self):
- """
- Test an inversion for which we know the answer
- """
- x, y, err = load("sphere_80.txt")
-
- # Choose the right d_max...
- self.invertor.d_max = 160.0
- # Set a small alpha
- self.invertor.alpha = 1e-7
- # Set data
- self.invertor.x = x
- self.invertor.y = y
- self.invertor.err = err
- # Perform inversion
- out, cov = self.invertor.invert_optimize(10)
- #out, cov = self.invertor.invert(10)
- # This is a very specific case
- # We should make sure it always passes
- self.assertTrue(self.invertor.chi2/len(x)<200.00)
-
- # Check the computed P(r) with the theory
- # for shpere of radius 80
- x = numpy.arange(0.01, self.invertor.d_max, self.invertor.d_max/51.0)
- y = numpy.zeros(len(x))
- dy = numpy.zeros(len(x))
- y_true = numpy.zeros(len(x))
-
- sum = 0.0
- sum_true = 0.0
- for i in range(len(x)):
- #y[i] = self.invertor.pr(out, x[i])
- (y[i], dy[i]) = self.invertor.pr_err(out, cov, x[i])
- sum += y[i]
- if x[i]<80.0:
- y_true[i] = pr_theory(x[i], 80.0)
- else:
- y_true[i] = 0
- sum_true += y_true[i]
-
- y = y/sum*self.invertor.d_max/len(x)
- dy = dy/sum*self.invertor.d_max/len(x)
- y_true = y_true/sum_true*self.invertor.d_max/len(x)
-
- chi2 = 0.0
- for i in range(len(x)):
- res = (y[i]-y_true[i])/dy[i]
- chi2 += res*res
-
- try:
- self.assertTrue(chi2/51.0<10.0)
- except:
- print "chi2 =", chi2/51.0
- raise
-
- def test_lstsq(self):
- """
- Test an inversion for which we know the answer
- """
- x, y, err = load("sphere_80.txt")
-
- # Choose the right d_max...
- self.invertor.d_max = 160.0
- # Set a small alpha
- self.invertor.alpha = .005
- # Set data
- self.invertor.x = x
- self.invertor.y = y
- self.invertor.err = err
- # Perform inversion
- #out, cov = self.invertor.invert(10)
-
- out, cov = self.invertor.lstsq(10)
-
-
- # This is a very specific case
- # We should make sure it always passes
- try:
- self.assertTrue(self.invertor.chi2/len(x)<200.00)
- except:
- print "Chi2(I(q)) =", self.invertor.chi2/len(x)
- raise
-
- # Check the computed P(r) with the theory
- # for shpere of radius 80
- x = numpy.arange(0.01, self.invertor.d_max, self.invertor.d_max/51.0)
- y = numpy.zeros(len(x))
- dy = numpy.zeros(len(x))
- y_true = numpy.zeros(len(x))
-
- sum = 0.0
- sum_true = 0.0
- for i in range(len(x)):
- #y[i] = self.invertor.pr(out, x[i])
- (y[i], dy[i]) = self.invertor.pr_err(out, cov, x[i])
- sum += y[i]
- if x[i]<80.0:
- y_true[i] = pr_theory(x[i], 80.0)
- else:
- y_true[i] = 0
- sum_true += y_true[i]
-
- y = y/sum*self.invertor.d_max/len(x)
- dy = dy/sum*self.invertor.d_max/len(x)
- y_true = y_true/sum_true*self.invertor.d_max/len(x)
-
- chi2 = 0.0
- for i in range(len(x)):
- res = (y[i]-y_true[i])/dy[i]
- chi2 += res*res
-
- try:
- self.assertTrue(chi2/51.0<50.0)
- except:
- print "chi2(P(r)) =", chi2/51.0
- raise
-
- # Test the number of peaks
- self.assertEqual(self.invertor.get_peaks(out), 1)
-
- def test_q_zero(self):
- """
- Test error condition where a point has q=0
- """
- x, y, err = load("sphere_80.txt")
- x[0] = 0.0
-
- # Choose the right d_max...
- self.invertor.d_max = 160.0
- # Set a small alpha
- self.invertor.alpha = 1e-7
- # Set data
- def doit():
- self.invertor.x = x
- self.assertRaises(ValueError, doit)
-
-
- def test_q_neg(self):
- """
- Test error condition where a point has q<0
- """
- x, y, err = load("sphere_80.txt")
- x[0] = -0.2
-
- # Choose the right d_max...
- self.invertor.d_max = 160.0
- # Set a small alpha
- self.invertor.alpha = 1e-7
- # Set data
- self.invertor.x = x
- self.invertor.y = y
- self.invertor.err = err
- # Perform inversion
- out, cov = self.invertor.invert(4)
-
- try:
- self.assertTrue(self.invertor.chi2>0)
- except:
- print "Chi2 =", self.invertor.chi2
- raise
-
- def test_Iq_zero(self):
- """
- Test error condition where a point has q<0
- """
- x, y, err = load("sphere_80.txt")
- y[0] = 0.0
-
- # Choose the right d_max...
- self.invertor.d_max = 160.0
- # Set a small alpha
- self.invertor.alpha = 1e-7
- # Set data
- self.invertor.x = x
- self.invertor.y = y
- self.invertor.err = err
- # Perform inversion
- out, cov = self.invertor.invert(4)
-
- try:
- self.assertTrue(self.invertor.chi2>0)
- except:
- print "Chi2 =", self.invertor.chi2
- raise
-
- def no_test_time(self):
- x, y, err = load("sphere_80.txt")
-
- # Choose the right d_max...
- self.invertor.d_max = 160.0
- # Set a small alpha
- self.invertor.alpha = 1e-7
- # Set data
- self.invertor.x = x
- self.invertor.y = y
- self.invertor.err = err
-
- # time scales like nfunc**2
- # on a Lenovo Intel Core 2 CPU T7400 @ 2.16GHz,
- # I get time/(nfunc)**2 = 0.022 sec
-
- out, cov = self.invertor.invert(15)
- t16 = self.invertor.elapsed
-
- out, cov = self.invertor.invert(30)
- t30 = self.invertor.elapsed
-
- t30s = t30/30.0**2
- self.assertTrue( (t30s-t16/16.0**2)/t30s <1.2 )
-
- def test_clone(self):
- self.invertor.x = self.x_in
- clone = self.invertor.clone()
-
- for i in range(len(self.x_in)):
- self.assertEqual(self.x_in[i], clone.x[i])
-
- def test_save(self):
- x, y, err = load("sphere_80.txt")
-
- # Choose the right d_max...
- self.invertor.d_max = 160.0
- # Set a small alpha
- self.invertor.alpha = .0007
- # Set data
- self.invertor.x = x
- self.invertor.y = y
- self.invertor.err = err
- # Perform inversion
-
- out, cov = self.invertor.lstsq(10)
-
- # Save
- self.invertor.to_file("test_output.txt")
-
- # Load
- self.invertor.from_file("test_output.txt")
- self.assertEqual(self.invertor.d_max, 160.0)
- self.assertEqual(self.invertor.alpha, 0.0007)
- self.assertEqual(self.invertor.chi2, 836.797)
- self.assertAlmostEqual(self.invertor.pr(self.invertor.out, 10.0), 903.31577041, 4)
-
- def test_qmin(self):
- self.invertor.q_min = 1.0
- self.assertEqual(self.invertor.q_min, 1.0)
-
- self.invertor.q_min = None
- self.assertEqual(self.invertor.q_min, None)
-
-
- def test_qmax(self):
- self.invertor.q_max = 1.0
- self.assertEqual(self.invertor.q_max, 1.0)
-
- self.invertor.q_max = None
- self.assertEqual(self.invertor.q_max, None)
-
-class TestErrorConditions(unittest.TestCase):
-
- def setUp(self):
- self.invertor = Invertor()
- self.invertor.d_max = 100.0
-
- # Test array
- self.ntest = 5
- self.x_in = numpy.ones(self.ntest)
- for i in range(self.ntest):
- self.x_in[i] = 1.0*(i+1)
-
- def test_negative_errs(self):
- """
- Test an inversion for which we know the answer
- """
- x, y, err = load("data_error_1.txt")
-
- # Choose the right d_max...
- self.invertor.d_max = 160.0
- # Set a small alpha
- self.invertor.alpha = .0007
- # Set data
- self.invertor.x = x
- self.invertor.y = y
- self.invertor.err = err
- # Perform inversion
-
- out, cov = self.invertor.lstsq(10)
-
- def test_zero_errs(self):
- """
- Have zero as an error should raise an exception
- """
- x, y, err = load("data_error_2.txt")
-
- # Set data
- self.invertor.x = x
- self.invertor.y = y
- self.invertor.err = err
- # Perform inversion
- self.assertRaises(RuntimeError, self.invertor.invert, 10)
-
- def test_invalid(self):
- """
- Test an inversion for which we know the answer
- """
- x, y, err = load("data_error_1.txt")
-
- # Set data
- self.invertor.x = x
- self.invertor.y = y
- err = numpy.zeros(len(x)-1)
- self.invertor.err = err
- # Perform inversion
- self.assertRaises(RuntimeError, self.invertor.invert, 10)
-
-
- def test_zero_q(self):
- """
- One of the q-values is zero.
- An exception should be raised.
- """
- x, y, err = load("data_error_3.txt")
-
- # Set data
- self.assertRaises(ValueError, self.invertor.__setattr__, 'x', x)
-
- def test_zero_Iq(self):
- """
- One of the I(q) points has a value of zero
- Should not complain or crash.
- """
- x, y, err = load("data_error_4.txt")
-
- # Set data
- self.invertor.x = x
- self.invertor.y = y
- self.invertor.err = err
- # Perform inversion
- out, cov = self.invertor.lstsq(10)
-
- def test_negative_q(self):
- """
- One q value is negative.
- Makes not sense, but should not complain or crash.
- """
- x, y, err = load("data_error_5.txt")
-
- # Set data
- self.invertor.x = x
- self.invertor.y = y
- self.invertor.err = err
- # Perform inversion
- out, cov = self.invertor.lstsq(10)
-
- def test_negative_Iq(self):
- """
- One I(q) value is negative.
- Makes not sense, but should not complain or crash.
- """
- x, y, err = load("data_error_6.txt")
-
- # Set data
- self.invertor.x = x
- self.invertor.y = y
- self.invertor.err = err
- # Perform inversion
- out, cov = self.invertor.lstsq(10)
-
- def test_nodata(self):
- """
- No data was loaded. Should not complain.
- """
- out, cov = self.invertor.lstsq(10)
-
-
-
-def pr_theory(r, R):
- """
- P(r) for a sphere
- """
- if r<=2*R:
- return 12.0* ((0.5*r/R)**2) * ((1.0-0.5*r/R)**2) * ( 2.0 + 0.5*r/R )
- else:
- return 0.0
-
-def load(path = "sphere_60_q0_2.txt"):
- import numpy, math, sys
- # Read the data from the data file
- data_x = numpy.zeros(0)
- data_y = numpy.zeros(0)
- data_err = numpy.zeros(0)
- scale = None
- if not path == None:
- input_f = open(path,'r')
- buff = input_f.read()
- lines = buff.split('\n')
- for line in lines:
- try:
- toks = line.split()
- x = float(toks[0])
- y = float(toks[1])
- if len(toks)>2:
- err = float(toks[2])
- else:
- if scale==None:
- scale = 0.15*math.sqrt(y)
- err = scale*math.sqrt(y)
- data_x = numpy.append(data_x, x)
- data_y = numpy.append(data_y, y)
- data_err = numpy.append(data_err, err)
- except:
- pass
-
- return data_x, data_y, data_err
-
-if __name__ == '__main__':
- unittest.main(testRunner=unittest.TextTestRunner(verbosity=2))
+"""
+ Unit tests for Invertor class
+"""
+# Disable "missing docstring" complaint
+# pylint: disable-msg=C0111
+# Disable "too many methods" complaint
+# pylint: disable-msg=R0904
+from __future__ import print_function
+
+
+import os
+import unittest
+import math
+import numpy
+from sas.sascalc.pr.invertor import Invertor
+
+
+class TestFiguresOfMerit(unittest.TestCase):
+
+ def setUp(self):
+ self.invertor = Invertor()
+ self.invertor.d_max = 100.0
+
+ # Test array
+ self.ntest = 5
+ self.x_in = numpy.ones(self.ntest)
+ for i in range(self.ntest):
+ self.x_in[i] = 1.0*(i+1)
+
+ x, y, err = load("sphere_80.txt")
+
+ # Choose the right d_max...
+ self.invertor.d_max = 160.0
+ # Set a small alpha
+ self.invertor.alpha = .0007
+ # Set data
+ self.invertor.x = x
+ self.invertor.y = y
+ self.invertor.err = err
+ # Perform inversion
+ #out, cov = self.invertor.invert(10)
+
+ self.out, self.cov = self.invertor.lstsq(10)
+
+ def test_positive(self):
+ """
+ Test whether P(r) is positive
+ """
+ self.assertEqual(self.invertor.get_positive(self.out), 1)
+
+ def test_positive_err(self):
+ """
+ Test whether P(r) is at least 1 sigma greater than zero
+ for all r-values
+ """
+ self.assertTrue(self.invertor.get_pos_err(self.out, self.cov)>0.9)
+
+class TestBasicComponent(unittest.TestCase):
+
+ def setUp(self):
+ self.invertor = Invertor()
+ self.invertor.d_max = 100.0
+
+ # Test array
+ self.ntest = 5
+ self.x_in = numpy.ones(self.ntest)
+ for i in range(self.ntest):
+ self.x_in[i] = 1.0*(i+1)
+
+ def test_est_bck_flag(self):
+ """
+ Tests the est_bck flag operations
+ """
+ self.assertEqual(self.invertor.est_bck, False)
+ self.invertor.est_bck=True
+ self.assertEqual(self.invertor.est_bck, True)
+ def doit_float():
+ self.invertor.est_bck = 2.0
+ def doit_str():
+ self.invertor.est_bck = 'a'
+
+ self.assertRaises(ValueError, doit_float)
+ self.assertRaises(ValueError, doit_str)
+
+
+ def testset_dmax(self):
+ """
+ Set and read d_max
+ """
+ value = 15.0
+ self.invertor.d_max = value
+ self.assertEqual(self.invertor.d_max, value)
+
+ def testset_alpha(self):
+ """
+ Set and read alpha
+ """
+ value = 15.0
+ self.invertor.alpha = value
+ self.assertEqual(self.invertor.alpha, value)
+
+ def testset_x_1(self):
+ """
+ Setting and reading the x array the hard way
+ """
+ # Set x
+ self.invertor.x = self.x_in
+
+ # Read it back
+ npts = self.invertor.get_nx()
+ x_out = numpy.ones(npts)
+
+ self.invertor.get_x(x_out)
+
+ for i in range(self.ntest):
+ self.assertEqual(self.x_in[i], x_out[i])
+
+ def testset_x_2(self):
+ """
+ Setting and reading the x array the easy way
+ """
+ # Set x
+ self.invertor.x = self.x_in
+
+ # Read it back
+ x_out = self.invertor.x
+
+ for i in range(self.ntest):
+ self.assertEqual(self.x_in[i], x_out[i])
+
+ def testset_y(self):
+ """
+ Setting and reading the y array the easy way
+ """
+ # Set y
+ self.invertor.y = self.x_in
+
+ # Read it back
+ y_out = self.invertor.y
+
+ for i in range(self.ntest):
+ self.assertEqual(self.x_in[i], y_out[i])
+
+ def testset_err(self):
+ """
+ Setting and reading the err array the easy way
+ """
+ # Set err
+ self.invertor.err = self.x_in
+
+ # Read it back
+ err_out = self.invertor.err
+
+ for i in range(self.ntest):
+ self.assertEqual(self.x_in[i], err_out[i])
+
+ def test_iq(self):
+ """
+ Test iq calculation
+ """
+ q = 0.11
+ v1 = 8.0*math.pi**2/q * self.invertor.d_max *math.sin(q*self.invertor.d_max)
+ v1 /= ( math.pi**2 - (q*self.invertor.d_max)**2.0 )
+
+ pars = numpy.ones(1)
+ self.assertAlmostEqual(self.invertor.iq(pars, q), v1, 2)
+
+ def test_pr(self):
+ """
+ Test pr calculation
+ """
+ r = 10.0
+ v1 = 2.0*r*math.sin(math.pi*r/self.invertor.d_max)
+ pars = numpy.ones(1)
+ self.assertAlmostEqual(self.invertor.pr(pars, r), v1, 2)
+
+ def test_getsetters(self):
+ self.invertor.new_data = 1.0
+ self.assertEqual(self.invertor.new_data, 1.0)
+
+ self.assertEqual(self.invertor.test_no_data, None)
+
+ def test_slitsettings(self):
+ self.invertor.slit_width = 1.0
+ self.assertEqual(self.invertor.slit_width, 1.0)
+ self.invertor.slit_height = 2.0
+ self.assertEqual(self.invertor.slit_height, 2.0)
+
+
+ def test_inversion(self):
+ """
+ Test an inversion for which we know the answer
+ """
+ x, y, err = load("sphere_80.txt")
+
+ # Choose the right d_max...
+ self.invertor.d_max = 160.0
+ # Set a small alpha
+ self.invertor.alpha = 1e-7
+ # Set data
+ self.invertor.x = x
+ self.invertor.y = y
+ self.invertor.err = err
+ # Perform inversion
+ out, cov = self.invertor.invert_optimize(10)
+ #out, cov = self.invertor.invert(10)
+ # This is a very specific case
+ # We should make sure it always passes
+ self.assertTrue(self.invertor.chi2/len(x)<200.00)
+
+ # Check the computed P(r) with the theory
+ # for shpere of radius 80
+ x = numpy.arange(0.01, self.invertor.d_max, self.invertor.d_max/51.0)
+ y = numpy.zeros(len(x))
+ dy = numpy.zeros(len(x))
+ y_true = numpy.zeros(len(x))
+
+ sum = 0.0
+ sum_true = 0.0
+ for i in range(len(x)):
+ #y[i] = self.invertor.pr(out, x[i])
+ (y[i], dy[i]) = self.invertor.pr_err(out, cov, x[i])
+ sum += y[i]
+ if x[i]<80.0:
+ y_true[i] = pr_theory(x[i], 80.0)
+ else:
+ y_true[i] = 0
+ sum_true += y_true[i]
+
+ y = y/sum*self.invertor.d_max/len(x)
+ dy = dy/sum*self.invertor.d_max/len(x)
+ y_true = y_true/sum_true*self.invertor.d_max/len(x)
+
+ chi2 = 0.0
+ for i in range(len(x)):
+ res = (y[i]-y_true[i])/dy[i]
+ chi2 += res*res
+
+ try:
+ self.assertTrue(chi2/51.0<10.0)
+ except:
+ print("chi2 =", chi2/51.0)
+ raise
+
+ def test_lstsq(self):
+ """
+ Test an inversion for which we know the answer
+ """
+ x, y, err = load("sphere_80.txt")
+
+ # Choose the right d_max...
+ self.invertor.d_max = 160.0
+ # Set a small alpha
+ self.invertor.alpha = .005
+ # Set data
+ self.invertor.x = x
+ self.invertor.y = y
+ self.invertor.err = err
+ # Perform inversion
+ #out, cov = self.invertor.invert(10)
+
+ out, cov = self.invertor.lstsq(10)
+
+
+ # This is a very specific case
+ # We should make sure it always passes
+ try:
+ self.assertTrue(self.invertor.chi2/len(x)<200.00)
+ except:
+ print("Chi2(I(q)) =", self.invertor.chi2/len(x))
+ raise
+
+ # Check the computed P(r) with the theory
+ # for shpere of radius 80
+ x = numpy.arange(0.01, self.invertor.d_max, self.invertor.d_max/51.0)
+ y = numpy.zeros(len(x))
+ dy = numpy.zeros(len(x))
+ y_true = numpy.zeros(len(x))
+
+ sum = 0.0
+ sum_true = 0.0
+ for i in range(len(x)):
+ #y[i] = self.invertor.pr(out, x[i])
+ (y[i], dy[i]) = self.invertor.pr_err(out, cov, x[i])
+ sum += y[i]
+ if x[i]<80.0:
+ y_true[i] = pr_theory(x[i], 80.0)
+ else:
+ y_true[i] = 0
+ sum_true += y_true[i]
+
+ y = y/sum*self.invertor.d_max/len(x)
+ dy = dy/sum*self.invertor.d_max/len(x)
+ y_true = y_true/sum_true*self.invertor.d_max/len(x)
+
+ chi2 = 0.0
+ for i in range(len(x)):
+ res = (y[i]-y_true[i])/dy[i]
+ chi2 += res*res
+
+ try:
+ self.assertTrue(chi2/51.0<50.0)
+ except:
+ print("chi2(P(r)) =", chi2/51.0)
+ raise
+
+ # Test the number of peaks
+ self.assertEqual(self.invertor.get_peaks(out), 1)
+
+ def test_q_zero(self):
+ """
+ Test error condition where a point has q=0
+ """
+ x, y, err = load("sphere_80.txt")
+ x[0] = 0.0
+
+ # Choose the right d_max...
+ self.invertor.d_max = 160.0
+ # Set a small alpha
+ self.invertor.alpha = 1e-7
+ # Set data
+ def doit():
+ self.invertor.x = x
+ self.assertRaises(ValueError, doit)
+
+
+ def test_q_neg(self):
+ """
+ Test error condition where a point has q<0
+ """
+ x, y, err = load("sphere_80.txt")
+ x[0] = -0.2
+
+ # Choose the right d_max...
+ self.invertor.d_max = 160.0
+ # Set a small alpha
+ self.invertor.alpha = 1e-7
+ # Set data
+ self.invertor.x = x
+ self.invertor.y = y
+ self.invertor.err = err
+ # Perform inversion
+ out, cov = self.invertor.invert(4)
+
+ try:
+ self.assertTrue(self.invertor.chi2>0)
+ except:
+ print("Chi2 =", self.invertor.chi2)
+ raise
+
+ def test_Iq_zero(self):
+ """
+ Test error condition where a point has q<0
+ """
+ x, y, err = load("sphere_80.txt")
+ y[0] = 0.0
+
+ # Choose the right d_max...
+ self.invertor.d_max = 160.0
+ # Set a small alpha
+ self.invertor.alpha = 1e-7
+ # Set data
+ self.invertor.x = x
+ self.invertor.y = y
+ self.invertor.err = err
+ # Perform inversion
+ out, cov = self.invertor.invert(4)
+
+ try:
+ self.assertTrue(self.invertor.chi2>0)
+ except:
+ print("Chi2 =", self.invertor.chi2)
+ raise
+
+ def no_test_time(self):
+ x, y, err = load("sphere_80.txt")
+
+ # Choose the right d_max...
+ self.invertor.d_max = 160.0
+ # Set a small alpha
+ self.invertor.alpha = 1e-7
+ # Set data
+ self.invertor.x = x
+ self.invertor.y = y
+ self.invertor.err = err
+
+ # time scales like nfunc**2
+ # on a Lenovo Intel Core 2 CPU T7400 @ 2.16GHz,
+ # I get time/(nfunc)**2 = 0.022 sec
+
+ out, cov = self.invertor.invert(15)
+ t16 = self.invertor.elapsed
+
+ out, cov = self.invertor.invert(30)
+ t30 = self.invertor.elapsed
+
+ t30s = t30/30.0**2
+ self.assertTrue( (t30s-t16/16.0**2)/t30s <1.2 )
+
+ def test_clone(self):
+ self.invertor.x = self.x_in
+ clone = self.invertor.clone()
+
+ for i in range(len(self.x_in)):
+ self.assertEqual(self.x_in[i], clone.x[i])
+
+ def test_save(self):
+ x, y, err = load("sphere_80.txt")
+
+ # Choose the right d_max...
+ self.invertor.d_max = 160.0
+ # Set a small alpha
+ self.invertor.alpha = .0007
+ # Set data
+ self.invertor.x = x
+ self.invertor.y = y
+ self.invertor.err = err
+ # Perform inversion
+
+ out, cov = self.invertor.lstsq(10)
+
+ # Save
+ f_name = "test_output.txt"
+ self.invertor.to_file(f_name)
+
+ # Load
+ self.invertor.from_file(f_name)
+ self.assertEqual(self.invertor.d_max, 160.0)
+ self.assertEqual(self.invertor.alpha, 0.0007)
+ self.assertEqual(self.invertor.chi2, 836.797)
+ self.assertAlmostEqual(self.invertor.pr(self.invertor.out, 10.0), 903.31577041, 4)
+ if os.path.isfile(f_name):
+ os.remove(f_name)
+
+ def test_qmin(self):
+ self.invertor.q_min = 1.0
+ self.assertEqual(self.invertor.q_min, 1.0)
+
+ self.invertor.q_min = None
+ self.assertEqual(self.invertor.q_min, None)
+
+
+ def test_qmax(self):
+ self.invertor.q_max = 1.0
+ self.assertEqual(self.invertor.q_max, 1.0)
+
+ self.invertor.q_max = None
+ self.assertEqual(self.invertor.q_max, None)
+
+class TestErrorConditions(unittest.TestCase):
+
+ def setUp(self):
+ self.invertor = Invertor()
+ self.invertor.d_max = 100.0
+
+ # Test array
+ self.ntest = 5
+ self.x_in = numpy.ones(self.ntest)
+ for i in range(self.ntest):
+ self.x_in[i] = 1.0*(i+1)
+
+ def test_negative_errs(self):
+ """
+ Test an inversion for which we know the answer
+ """
+ x, y, err = load("data_error_1.txt")
+
+ # Choose the right d_max...
+ self.invertor.d_max = 160.0
+ # Set a small alpha
+ self.invertor.alpha = .0007
+ # Set data
+ self.invertor.x = x
+ self.invertor.y = y
+ self.invertor.err = err
+ # Perform inversion
+
+ out, cov = self.invertor.lstsq(10)
+
+ def test_zero_errs(self):
+ """
+ Have zero as an error should raise an exception
+ """
+ x, y, err = load("data_error_2.txt")
+
+ # Set data
+ self.invertor.x = x
+ self.invertor.y = y
+ self.invertor.err = err
+ # Perform inversion
+ self.assertRaises(RuntimeError, self.invertor.invert, 10)
+
+ def test_invalid(self):
+ """
+ Test an inversion for which we know the answer
+ """
+ x, y, err = load("data_error_1.txt")
+
+ # Set data
+ self.invertor.x = x
+ self.invertor.y = y
+ err = numpy.zeros(len(x)-1)
+ self.invertor.err = err
+ # Perform inversion
+ self.assertRaises(RuntimeError, self.invertor.invert, 10)
+
+
+ def test_zero_q(self):
+ """
+ One of the q-values is zero.
+ An exception should be raised.
+ """
+ x, y, err = load("data_error_3.txt")
+
+ # Set data
+ self.assertRaises(ValueError, self.invertor.__setattr__, 'x', x)
+
+ def test_zero_Iq(self):
+ """
+ One of the I(q) points has a value of zero
+ Should not complain or crash.
+ """
+ x, y, err = load("data_error_4.txt")
+
+ # Set data
+ self.invertor.x = x
+ self.invertor.y = y
+ self.invertor.err = err
+ # Perform inversion
+ out, cov = self.invertor.lstsq(10)
+
+ def test_negative_q(self):
+ """
+ One q value is negative.
+ Makes not sense, but should not complain or crash.
+ """
+ x, y, err = load("data_error_5.txt")
+
+ # Set data
+ self.invertor.x = x
+ self.invertor.y = y
+ self.invertor.err = err
+ # Perform inversion
+ out, cov = self.invertor.lstsq(10)
+
+ def test_negative_Iq(self):
+ """
+ One I(q) value is negative.
+ Makes not sense, but should not complain or crash.
+ """
+ x, y, err = load("data_error_6.txt")
+
+ # Set data
+ self.invertor.x = x
+ self.invertor.y = y
+ self.invertor.err = err
+ # Perform inversion
+ out, cov = self.invertor.lstsq(10)
+
+ def test_nodata(self):
+ """
+ No data was loaded. Should not complain.
+ """
+ out, cov = self.invertor.lstsq(10)
+
+
+
+def pr_theory(r, R):
+ """
+ P(r) for a sphere
+ """
+ if r<=2*R:
+ return 12.0* ((0.5*r/R)**2) * ((1.0-0.5*r/R)**2) * ( 2.0 + 0.5*r/R )
+ else:
+ return 0.0
+
+def load(path = "sphere_60_q0_2.txt"):
+ import numpy as np
+ import math
+ import sys
+ # Read the data from the data file
+ data_x = np.zeros(0)
+ data_y = np.zeros(0)
+ data_err = np.zeros(0)
+ scale = None
+ if path is not None:
+ input_f = open(path,'r')
+ buff = input_f.read()
+ lines = buff.split('\n')
+ for line in lines:
+ try:
+ toks = line.split()
+ x = float(toks[0])
+ y = float(toks[1])
+ if len(toks)>2:
+ err = float(toks[2])
+ else:
+ if scale==None:
+ scale = 0.15*math.sqrt(y)
+ err = scale*math.sqrt(y)
+ data_x = np.append(data_x, x)
+ data_y = np.append(data_y, y)
+ data_err = np.append(data_err, err)
+ except:
+ pass
+
+ return data_x, data_y, data_err
+
+if __name__ == '__main__':
+ unittest.main(testRunner=unittest.TextTestRunner(verbosity=2))
diff --git a/test/run_one.py b/test/run_one.py
old mode 100644
new mode 100755
index 7094747..ac8e203
--- a/test/run_one.py
+++ b/test/run_one.py
@@ -1,4 +1,5 @@
#!/usr/bin/env python
+from __future__ import print_function
import os
import sys
@@ -7,12 +8,23 @@ import unittest
import imp
from os.path import abspath, dirname, split as splitpath, join as joinpath
+import logging
+logger = logging.getLogger(__name__)
+if not logger.root.handlers:
+ import logging.config
+ LOGGER_CONFIG_FILE = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'logging.ini')
+ logging.config.fileConfig(LOGGER_CONFIG_FILE, disable_existing_loggers=False)
+
+if len(sys.argv) < 2:
+ logger.error("Use %s <filename to test>",sys.argv[0])
+ sys.exit(-1)
+
run_py = joinpath(dirname(dirname(abspath(__file__))), 'run.py')
run = imp.load_source('sasview_run', run_py)
run.prepare()
#print "\n".join(sys.path)
test_path,test_file = splitpath(abspath(sys.argv[1]))
-print "=== testing:",sys.argv[1]
+print("=== testing:",sys.argv[1])
#print test_path, test_file
sys.argv = [sys.argv[0]]
os.chdir(test_path)
diff --git a/src/sas/__init__.py b/test/sascalculator/__init__.py
similarity index 100%
copy from src/sas/__init__.py
copy to test/sascalculator/__init__.py
diff --git a/src/sas/__init__.py b/test/sascalculator/test/__init__.py
similarity index 100%
copy from src/sas/__init__.py
copy to test/sascalculator/test/__init__.py
diff --git a/test/sascalculator/test/utest_resolution_calculator.py b/test/sascalculator/test/utest_resolution_calculator.py
index 378d646..0ec4287 100644
--- a/test/sascalculator/test/utest_resolution_calculator.py
+++ b/test/sascalculator/test/utest_resolution_calculator.py
@@ -1,38 +1,38 @@
-"""
- Unit test for resolution_calculator
-"""
-
-import unittest
-from sas.sascalc.calculator.resolution_calculator import ResolutionCalculator \
- as calculator
-
-class resolution_calculator(unittest.TestCase):
-
- def setUp(self):
-
- self.cal = calculator()
-
- def test_resolution_calculation(self):
- """
- Test resolution_calculator"
- """
- self.cal.set_wavelength(15)
- self.cal.set_source_aperture_size([2])
- self.cal.set_sample_aperture_size([1])
- self.cal.set_detector_pix_size([1])
- self.cal.set_source2sample_distance([1500])
- self.cal.set_sample2detector_distance([1500])
- self.cal.set_wavelength_spread(0.1)
- # all instr. params for cal
- self.cal.get_all_instrument_params()
- qr, phi, sigma_1, sigma_2, _, sigma_1d = self.cal.compute(15, 0.1,
- 0, 0, coord = 'polar')
- sigma_1d = self.cal.sigma_1d
-
- # The value "0.000213283" was obtained by manual calculation.
- self.assertAlmostEqual(sigma_1d, 0.000213283, 5)
-
-
-if __name__ == '__main__':
- unittest.main()
-
+"""
+ Unit test for resolution_calculator
+"""
+
+import unittest
+from sas.sascalc.calculator.resolution_calculator import ResolutionCalculator \
+ as calculator
+
+class resolution_calculator(unittest.TestCase):
+
+ def setUp(self):
+
+ self.cal = calculator()
+
+ def test_resolution_calculation(self):
+ """
+ Test resolution_calculator"
+ """
+ self.cal.set_wavelength(15)
+ self.cal.set_source_aperture_size([2])
+ self.cal.set_sample_aperture_size([1])
+ self.cal.set_detector_pix_size([1])
+ self.cal.set_source2sample_distance([1500])
+ self.cal.set_sample2detector_distance([1500])
+ self.cal.set_wavelength_spread(0.1)
+ # all instr. params for cal
+ self.cal.get_all_instrument_params()
+ qr, phi, sigma_1, sigma_2, _, sigma_1d = self.cal.compute(15, 0.1,
+ 0, 0, coord = 'polar')
+ sigma_1d = self.cal.sigma_1d
+
+ # The value "0.000213283" was obtained by manual calculation.
+ self.assertAlmostEqual(sigma_1d, 0.000213283, 5)
+
+
+if __name__ == '__main__':
+ unittest.main()
+
diff --git a/test/sascalculator/test/utest_sas_gen.py b/test/sascalculator/test/utest_sas_gen.py
index 6aaae15..26998e2 100644
--- a/test/sascalculator/test/utest_sas_gen.py
+++ b/test/sascalculator/test/utest_sas_gen.py
@@ -1,55 +1,53 @@
-"""
-Unit tests for the sas_gen
-"""
-import warnings
-warnings.simplefilter("ignore")
-
-import unittest
-from sas.sascalc.calculator import sas_gen
-
-import numpy
-
-import os.path
-
-class sas_gen_test(unittest.TestCase):
-
- def setUp(self):
- self.sldloader = sas_gen.SLDReader()
- self.pdbloader = sas_gen.PDBReader()
- self.omfloader = sas_gen.OMFReader()
-
- def test_sldreader(self):
- """
- Test .sld file loaded
- """
- f = self.sldloader.read("sld_file.sld")
- self.assertEqual(f.pos_x[0], -40.5)
- self.assertEqual(f.pos_y[0], -13.5)
- self.assertEqual(f.pos_z[0], -13.5)
-
- def test_pdbreader(self):
- """
- Test .pdb file loaded
- """
- f = self.pdbloader.read("c60.pdb")
- self.assertEqual(f.pos_x[0], -0.733)
- self.assertEqual(f.pos_y[0], -1.008)
- self.assertEqual(f.pos_z[0], 3.326)
-
- def test_omfreader(self):
- """
- Test .omf file loaded
- """
- f = self.omfloader.read("A_Raw_Example-1.omf")
- output = sas_gen.OMF2SLD()
- output.set_data(f)
- self.assertEqual(f.mx[0], 0)
- self.assertEqual(f.my[0], 0)
- self.assertEqual(f.mz[0], 0)
- self.assertEqual(output.pos_x[0], 0.0)
- self.assertEqual(output.pos_y[0], 0.0)
- self.assertEqual(output.pos_z[0], 0.0)
-
-if __name__ == '__main__':
- unittest.main()
-
+"""
+Unit tests for the sas_gen
+"""
+import warnings
+warnings.simplefilter("ignore")
+
+import unittest
+from sas.sascalc.calculator import sas_gen
+
+
+class sas_gen_test(unittest.TestCase):
+
+ def setUp(self):
+ self.sldloader = sas_gen.SLDReader()
+ self.pdbloader = sas_gen.PDBReader()
+ self.omfloader = sas_gen.OMFReader()
+
+ def test_sldreader(self):
+ """
+ Test .sld file loaded
+ """
+ f = self.sldloader.read("sld_file.sld")
+ self.assertEqual(f.pos_x[0], -40.5)
+ self.assertEqual(f.pos_y[0], -13.5)
+ self.assertEqual(f.pos_z[0], -13.5)
+
+ def test_pdbreader(self):
+ """
+ Test .pdb file loaded
+ """
+ f = self.pdbloader.read("c60.pdb")
+ self.assertEqual(f.pos_x[0], -0.733)
+ self.assertEqual(f.pos_y[0], -1.008)
+ self.assertEqual(f.pos_z[0], 3.326)
+
+ def test_omfreader(self):
+ """
+ Test .omf file loaded
+ """
+ f = self.omfloader.read("A_Raw_Example-1.omf")
+ output = sas_gen.OMF2SLD()
+ output.set_data(f)
+ self.assertEqual(f.mx[0], 0)
+ self.assertEqual(f.my[0], 0)
+ self.assertEqual(f.mz[0], 0)
+ self.assertEqual(output.pos_x[0], 0.0)
+ self.assertEqual(output.pos_y[0], 0.0)
+ self.assertEqual(output.pos_z[0], 0.0)
+
+
+if __name__ == '__main__':
+ unittest.main()
+
diff --git a/test/calculatorview/test/utest_sld.py b/test/sascalculator/test/utest_sld.py
similarity index 91%
rename from test/calculatorview/test/utest_sld.py
rename to test/sascalculator/test/utest_sld.py
index 99a0895..1f12cab 100644
--- a/test/calculatorview/test/utest_sld.py
+++ b/test/sascalculator/test/utest_sld.py
@@ -1,148 +1,148 @@
-
-import unittest
-
-_SCALE = 1e-6
-
-# the calculator default value for wavelength is 6
-import periodictable
-from periodictable import formula
-from periodictable.xsf import xray_energy, xray_sld_from_atoms
-from periodictable.constants import avogadro_number
-from periodictable.nsf import neutron_scattering, neutron_sld
-
-
-def calculate_xray_sld(element, density, molecule_formula):
- """
- Get an element and compute the corresponding SLD for a given formula
- :param element: elements a string of existing atom
- """
- element_formula = formula(str(element))
- if len(element_formula.atoms) != 1:
- return
- element = element_formula.atoms.keys()[0]
- energy = xray_energy(element.K_alpha)
- atom = molecule_formula.atoms
- return xray_sld_from_atoms(atom, density=density, energy=energy)
-
-
-class TestH2O(unittest.TestCase):
- """
- Sld calculator test for H2O
- """
-
- def setUp(self):
- """Inititialze variables"""
-
- self.compound = "H2O"
- self.density = 1.0
- self.wavelength = 6.0
- self.sld_formula = formula(self.compound, density=self.density)
-
- def test_neutron_sld(self):
- """
- test sld
- """
- #Compute incoherence , absorption, and incoherence
- (sld_real,sld_im,sld_inc), (coh,abs,incoh), length = neutron_scattering(self.compound,
- density=self.density, wavelength=self.wavelength)
- cu_real, cu_im = calculate_xray_sld(element="Cu", density=self.density,
- molecule_formula=self.sld_formula)
- mo_real, mo_im = calculate_xray_sld(element="Mo", density=self.density,
- molecule_formula=self.sld_formula)
- #test sld
- self.assertAlmostEquals(sld_real * _SCALE, -5.6e-7, 1)
- self.assertAlmostEquals(sld_im * _SCALE, 0)
- #test absorption value
- self.assertAlmostEquals(abs, 0.0741, 2)
- self.assertAlmostEquals(incoh, 5.62, 2)
- #Test length
- self.assertAlmostEquals(length, 0.1755, 3)
- #test Cu sld
- self.assertAlmostEquals(cu_real * _SCALE, 9.46e-6, 1)
- self.assertAlmostEquals(cu_im * _SCALE, 3.01e-8)
- # test Mo sld
- self.assertAlmostEquals(mo_real * _SCALE, 9.43e-6)
- self.assertAlmostEquals(mo_im * _SCALE, 5.65e-7,1)
-
-
-class TestD2O(unittest.TestCase):
- """
- Sld calculator test for D2O
- """
-
- def setUp(self):
- """Inititialze variables"""
-
- self.compound = "D2O"
- self.density = 1.1
- self.wavelength = 6.0
- self.sld_formula = formula(self.compound, density=self.density)
-
- def test_neutron_sld(self):
- """
- test sld
- """
- #Compute incoherence , absorption, and incoherence
- (sld_real,sld_im,sld_inc), (coh,abs,incoh), length = neutron_scattering(self.compound,
- density=self.density, wavelength=self.wavelength)
- cu_real, cu_im = calculate_xray_sld(element="Cu", density=self.density,
- molecule_formula=self.sld_formula)
- mo_real, mo_im = calculate_xray_sld(element="Mo", density=self.density,
- molecule_formula=self.sld_formula)
- #test sld
- self.assertAlmostEquals(sld_real * _SCALE, 6.33e-6, 1)
- self.assertAlmostEquals(sld_im * _SCALE, 0)
- #test absorption value
- self.assertAlmostEquals(abs, 1.35e-4, 2)
- self.assertAlmostEquals(incoh, 0.138, 2)
- #Test length
- self.assertAlmostEquals(length, 1.549, 3)
- #test Cu sld
- self.assertAlmostEquals(cu_real * _SCALE, 9.36e-6, 1)
- self.assertAlmostEquals(cu_im * _SCALE, 2.98e-8)
- # test Mo sld
- self.assertAlmostEquals(mo_real * _SCALE, 9.33e-6)
- self.assertAlmostEquals(mo_im * _SCALE, 5.59e-9,1)
-
-
-class TestCd(unittest.TestCase):
- """
- Sld calculator test for Cd
- """
-
- def setUp(self):
- """Inititialze variables"""
- # the calculator default value for wavelength is 6
- self.compound = "Cd"
- self.density = 4.0
- self.wavelength = 6.0
- self.sld_formula = formula(self.compound, density=self.density)
-
- def test_neutron_sld(self):
- """
- test sld
- """
- #Compute incoherence , absorption, and incoherence
- (sld_real,sld_im,sld_inc), (coh,abs,incoh), length = neutron_scattering(self.compound,
- density=self.density, wavelength=self.wavelength)
- cu_real, cu_im = calculate_xray_sld(element="Cu", density=self.density,
- molecule_formula=self.sld_formula)
- mo_real, mo_im = calculate_xray_sld(element="Mo", density=self.density,
- molecule_formula=self.sld_formula)
- #test sld
- self.assertAlmostEquals(sld_real * _SCALE, 1.04e-6, 1)
- self.assertAlmostEquals(sld_im * _SCALE, -1.5e-7, 1)
- #test absorption value
- self.assertAlmostEquals(abs, 180.0,0)
- self.assertAlmostEquals(incoh, 0.0754, 2)
- #Test length
- self.assertAlmostEquals(length, 0.005551, 4)
- #test Cu sld
- self.assertAlmostEquals(cu_real * _SCALE, 2.89e-5, 1)
- self.assertAlmostEquals(cu_im * _SCALE, 2.81e-6)
- # test Mo sld
- self.assertAlmostEquals(mo_real * _SCALE, 2.84e-5, 1)
- self.assertAlmostEquals(mo_im * _SCALE, 7.26e-7,1)
-
-if __name__ == '__main__':
- unittest.main()
+
+import unittest
+
+_SCALE = 1e-6
+
+# the calculator default value for wavelength is 6
+import periodictable
+from periodictable import formula
+from periodictable.xsf import xray_energy, xray_sld_from_atoms
+from periodictable.constants import avogadro_number
+from periodictable.nsf import neutron_scattering, neutron_sld
+
+
+def calculate_xray_sld(element, density, molecule_formula):
+ """
+ Get an element and compute the corresponding SLD for a given formula
+ :param element: elements a string of existing atom
+ """
+ element_formula = formula(str(element))
+ if len(element_formula.atoms) != 1:
+ return
+ element = next(iter(element_formula.atoms)) # only one element...
+ energy = xray_energy(element.K_alpha)
+ atom = molecule_formula.atoms
+ return xray_sld_from_atoms(atom, density=density, energy=energy)
+
+
+class TestH2O(unittest.TestCase):
+ """
+ Sld calculator test for H2O
+ """
+
+ def setUp(self):
+ """Inititialze variables"""
+
+ self.compound = "H2O"
+ self.density = 1.0
+ self.wavelength = 6.0
+ self.sld_formula = formula(self.compound, density=self.density)
+
+ def test_neutron_sld(self):
+ """
+ test sld
+ """
+ #Compute incoherence , absorption, and incoherence
+ (sld_real,sld_im,sld_inc), (coh,abs,incoh), length = neutron_scattering(self.compound,
+ density=self.density, wavelength=self.wavelength)
+ cu_real, cu_im = calculate_xray_sld(element="Cu", density=self.density,
+ molecule_formula=self.sld_formula)
+ mo_real, mo_im = calculate_xray_sld(element="Mo", density=self.density,
+ molecule_formula=self.sld_formula)
+ #test sld
+ self.assertAlmostEquals(sld_real * _SCALE, -5.6e-7, 1)
+ self.assertAlmostEquals(sld_im * _SCALE, 0)
+ #test absorption value
+ self.assertAlmostEquals(abs, 0.0741, 2)
+ self.assertAlmostEquals(incoh, 5.62, 2)
+ #Test length
+ self.assertAlmostEquals(length, 0.1755, 3)
+ #test Cu sld
+ self.assertAlmostEquals(cu_real * _SCALE, 9.46e-6, 1)
+ self.assertAlmostEquals(cu_im * _SCALE, 3.01e-8)
+ # test Mo sld
+ self.assertAlmostEquals(mo_real * _SCALE, 9.43e-6)
+ self.assertAlmostEquals(mo_im * _SCALE, 5.65e-7,1)
+
+
+class TestD2O(unittest.TestCase):
+ """
+ Sld calculator test for D2O
+ """
+
+ def setUp(self):
+ """Inititialze variables"""
+
+ self.compound = "D2O"
+ self.density = 1.1
+ self.wavelength = 6.0
+ self.sld_formula = formula(self.compound, density=self.density)
+
+ def test_neutron_sld(self):
+ """
+ test sld
+ """
+ #Compute incoherence , absorption, and incoherence
+ (sld_real,sld_im,sld_inc), (coh,abs,incoh), length = neutron_scattering(self.compound,
+ density=self.density, wavelength=self.wavelength)
+ cu_real, cu_im = calculate_xray_sld(element="Cu", density=self.density,
+ molecule_formula=self.sld_formula)
+ mo_real, mo_im = calculate_xray_sld(element="Mo", density=self.density,
+ molecule_formula=self.sld_formula)
+ #test sld
+ self.assertAlmostEquals(sld_real * _SCALE, 6.33e-6, 1)
+ self.assertAlmostEquals(sld_im * _SCALE, 0)
+ #test absorption value
+ self.assertAlmostEquals(abs, 1.35e-4, 2)
+ self.assertAlmostEquals(incoh, 0.138, 2)
+ #Test length
+ self.assertAlmostEquals(length, 1.549, 3)
+ #test Cu sld
+ self.assertAlmostEquals(cu_real * _SCALE, 9.36e-6, 1)
+ self.assertAlmostEquals(cu_im * _SCALE, 2.98e-8)
+ # test Mo sld
+ self.assertAlmostEquals(mo_real * _SCALE, 9.33e-6)
+ self.assertAlmostEquals(mo_im * _SCALE, 5.59e-9,1)
+
+
+class TestCd(unittest.TestCase):
+ """
+ Sld calculator test for Cd
+ """
+
+ def setUp(self):
+ """Inititialze variables"""
+ # the calculator default value for wavelength is 6
+ self.compound = "Cd"
+ self.density = 4.0
+ self.wavelength = 6.0
+ self.sld_formula = formula(self.compound, density=self.density)
+
+ def test_neutron_sld(self):
+ """
+ test sld
+ """
+ #Compute incoherence , absorption, and incoherence
+ (sld_real,sld_im,sld_inc), (coh,abs,incoh), length = neutron_scattering(self.compound,
+ density=self.density, wavelength=self.wavelength)
+ cu_real, cu_im = calculate_xray_sld(element="Cu", density=self.density,
+ molecule_formula=self.sld_formula)
+ mo_real, mo_im = calculate_xray_sld(element="Mo", density=self.density,
+ molecule_formula=self.sld_formula)
+ #test sld
+ self.assertAlmostEquals(sld_real * _SCALE, 1.04e-6, 1)
+ self.assertAlmostEquals(sld_im * _SCALE, -1.5e-7, 1)
+ #test absorption value
+ self.assertAlmostEquals(abs, 180.0,0)
+ self.assertAlmostEquals(incoh, 0.0754, 2)
+ #Test length
+ self.assertAlmostEquals(length, 0.005551, 4)
+ #test Cu sld
+ self.assertAlmostEquals(cu_real * _SCALE, 2.89e-5, 1)
+ self.assertAlmostEquals(cu_im * _SCALE, 2.81e-6)
+ # test Mo sld
+ self.assertAlmostEquals(mo_real * _SCALE, 2.84e-5, 1)
+ self.assertAlmostEquals(mo_im * _SCALE, 7.26e-7,1)
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/test/sascalculator/test/utest_slit_length_calculator.py b/test/sascalculator/test/utest_slit_length_calculator.py
index 8a8b284..77d0589 100644
--- a/test/sascalculator/test/utest_slit_length_calculator.py
+++ b/test/sascalculator/test/utest_slit_length_calculator.py
@@ -1,33 +1,35 @@
-"""
- Unit tests for slit_length_calculator
-"""
-
-import unittest
-from sas.sascalc.dataloader.readers.ascii_reader import Reader
-from sas.sascalc.calculator.slit_length_calculator import SlitlengthCalculator as calculator
-
-import os.path
-
-class slit_calculator(unittest.TestCase):
-
- def setUp(self):
-
- self.reader = Reader()
-
- def test_slitlength_calculation(self):
- """
- Test slit_length_calculator"
- """
- f = self.reader.read("beam profile.DAT")
- cal = calculator()
- cal.set_data(f.x,f.y)
- slitlength = cal.calculate_slit_length()
-
- # The value "5.5858" was obtained by manual calculation.
- # It turns out our slit length is FWHM/2
- self.assertAlmostEqual(slitlength,5.5858/2, 3)
-
-
-if __name__ == '__main__':
- unittest.main()
-
+"""
+ Unit tests for slit_length_calculator
+"""
+
+import unittest
+from sas.sascalc.dataloader.readers.ascii_reader import Reader
+from sas.sascalc.calculator.slit_length_calculator import SlitlengthCalculator \
+ as calculator
+
+
+class SlitCalculator(unittest.TestCase):
+
+ def setUp(self):
+
+ self.reader = Reader()
+
+ def test_slit_length_calculation(self):
+ """
+ Test slit_length_calculator"
+ """
+ list = self.reader.read("beam profile.DAT")
+ self.assertTrue(len(list) == 1)
+ f = list[0]
+ cal = calculator()
+ cal.set_data(f.x,f.y)
+ slit_length = cal.calculate_slit_length()
+
+ # The value "5.5858" was obtained by manual calculation.
+ # It turns out our slit length is FWHM/2
+ self.assertAlmostEqual(slit_length, 5.5858/2, 3)
+
+
+if __name__ == '__main__':
+ unittest.main()
+
diff --git a/src/sas/__init__.py b/test/sasdataloader/__init__.py
similarity index 100%
copy from src/sas/__init__.py
copy to test/sasdataloader/__init__.py
diff --git a/src/sas/__init__.py b/test/sasdataloader/plugins/__init__.py
similarity index 100%
copy from src/sas/__init__.py
copy to test/sasdataloader/plugins/__init__.py
diff --git a/test/sasdataloader/plugins/test_reader.py b/test/sasdataloader/plugins/test_reader.py
index 08defd0..6169bcd 100644
--- a/test/sasdataloader/plugins/test_reader.py
+++ b/test/sasdataloader/plugins/test_reader.py
@@ -1,63 +1,66 @@
-"""
-This software was developed by the University of Tennessee as part of the
-Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
-project funded by the US National Science Foundation.
-
-See the license text in license.txt
-
-copyright 2008, University of Tennessee
-"""
-import numpy, os
-from sas.sascalc.dataloader.data_info import Data1D
-
-
-class Reader:
- """
- Test reader to check plugin functionality
- """
- ## File type
- type = ["ASCII files (*.test)|*.test"]
- ## List of allowed extensions
- ext=['.test']
-
- def read(self, path):
- """
- Load data file
-
- @param path: file path
- @return: Data1D object, or None
- @raise RuntimeError: when the file can't be opened
- @raise ValueError: when the length of the data vectors are inconsistent
- """
- if os.path.isfile(path):
- basename = os.path.basename(path)
- root, extension = os.path.splitext(basename)
- if extension.lower() in self.ext:
- try:
- input_f = open(path,'r')
- except :
- raise RuntimeError, "ascii_reader: cannot open %s" % path
- buff = input_f.read()
- lines = buff.split('\n')
- x = numpy.zeros(0)
- y = numpy.zeros(0)
- dy = numpy.zeros(0)
- output = Data1D(x, y, dy=dy)
- self.filename = output.filename = basename
-
- for line in lines:
- x = numpy.append(x, float(line))
-
- output.x = x
- return output
- else:
- raise RuntimeError, "%s is not a file" % path
- return None
-
-if __name__ == "__main__":
- reader = Reader()
- output = reader.read("../test/test_data.test")
- print output.x
-
-
-
+"""
+This software was developed by the University of Tennessee as part of the
+Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
+project funded by the US National Science Foundation.
+
+See the license text in license.txt
+
+copyright 2008, University of Tennessee
+"""
+from __future__ import print_function
+
+import os
+import numpy as np
+from sas.sascalc.dataloader.data_info import Data1D
+
+
+class Reader:
+ """
+ Test reader to check plugin functionality
+ """
+ ## File type
+ type = ["ASCII files (*.test)|*.test"]
+ ## List of allowed extensions
+ ext=['.test']
+
+ def read(self, path):
+ """
+ Load data file
+
+ @param path: file path
+ @return: Data1D object, or None
+ @raise RuntimeError: when the file can't be opened
+ @raise ValueError: when the length of the data vectors are inconsistent
+ """
+ if os.path.isfile(path):
+ basename = os.path.basename(path)
+ root, extension = os.path.splitext(basename)
+ if extension.lower() in self.ext:
+ try:
+ input_f = open(path,'r')
+ except :
+ raise RuntimeError, "ascii_reader: cannot open %s" % path
+ buff = input_f.read()
+ lines = buff.split('\n')
+ x = np.zeros(0)
+ y = np.zeros(0)
+ dy = np.zeros(0)
+ output = Data1D(x, y, dy=dy)
+ self.filename = output.filename = basename
+
+ for line in lines:
+ x = np.append(x, float(line))
+
+ output.x = x
+ return output
+ else:
+ raise RuntimeError, "%s is not a file" % path
+ return None
+
+if __name__ == "__main__":
+ reader = Reader()
+ output = reader.read("../test/test_data.test")
+ print(output.x)
+
+
+
diff --git a/test/sasdataloader/test/AR07232_rest.ASC b/test/sasdataloader/test/AR07232_rest.ASC
deleted file mode 100644
index a7580df..0000000
--- a/test/sasdataloader/test/AR07232_rest.ASC
+++ /dev/null
@@ -1,16403 +0,0 @@
-FILE: MAR07232.SA3_LP _V948 CREATED: Tuesday, Mar 13, 2007 12:49:09 PM
-LABEL: 13m Rad 0.5Pa Fib1 Th 0.16 PH7.4 Ca 2.5mM
-MON CNT LAMBDA(A) DET_OFF(cm) DET_DIST(m) TRANS THICK(cm)
- 13.705 0.84357 0.2
-BCENT(X,Y) A1(mm) A2(mm) A1A2DIST(m) DL/L BSTOP(mm) DET_TYP
- 38 17.5 15.723 0.142 76.2 ORNL
-SAM: MAR07232.SA3_LP _V948
-BGD: MAR07171.SA3_LP_V887,
-EMP: MAR07060.SA3_LP_V776,MAR07061.SA3_LP_V777,
-DIV: PLEX_04JAN07_NG3.DIV,
-MASK: DEFAULT.MASK,
-ABS Parameters (3-6): TSTAND=1;DSTAND=1;IZERO=84.433;XSECT=1
-Average Choices: AVTYPE=2D_ASCII;SAVE=Yes;NAME=Auto;PLOT=Yes;
-
-*** Data written from ABS folder and may not be a fully corrected data file ***
-The detector image is a standard X-Y coordinate system
-Data is written by row, starting with Y=1 and X=(1->128)
-ASCII data created Tuesday, Mar 13, 2007 12:49:09 PM
-
-0.279783
-0.28951
-0.167634
-0.29697
--0.167797
-0.121896
-0.362248
-0.376043
-0.0919098
-0.0439741
--0.083055
-0.0881182
--0.164288
-0.0147787
-0.175687
-0.174224
-0.0979056
--0.156951
-0.557985
--0.114499
--0.251855
-0.253699
-0.149115
-0.0155941
--0.252127
-0.167588
-0.015413
-0.418395
--0.0335198
--0.0820611
-0.0494904
-0.0503993
-0.0528273
-0.253596
--0.183828
-0.271914
--0.170863
-0.396846
-0.57446
-0.103881
--0.0940455
-0.239388
--0.304823
-0.0191333
--0.156934
-0.186775
--0.0909297
-0.0159413
--0.186878
-0.597753
--0.0358526
--0.394771
--0.0724982
-0.441019
--0.0354168
--0.0353518
--0.0359621
-0.264975
--0.08766
--0.0352528
--0.090648
--0.262424
-0.0170211
-0.183366
-0.20904
--0.125102
--0.0363352
-0.237112
-0.188446
-0.23957
-0.406323
-0.0507246
-0.343797
--0.0834347
-0.201388
-0.214932
-0.350931
-0.104486
--0.1803
-0.383186
-0.1992
-0.180016
-0.173691
-0.131825
-0.14552
-0.134749
--0.08936
-0.14645
--0.0375393
--0.0153266
-0.440964
-0.492103
-0.0526702
-0.0944661
--0.0877996
-0.147739
-0.0542376
-0.0967474
-0.0531688
-0.220152
-0.182102
--0.0640662
--0.327062
-0.283083
-0.547303
-0.164272
--0.032581
-0.0459942
--0.255831
--0.153806
--0.160254
-0.0436688
-0.0618106
-0.326531
-0.0928606
-0.555209
--0.104815
-0.257707
--0.100459
-0.205518
--0.0984322
-0.0832656
--0.0725561
-0.448167
-0.307135
--0.0141939
-0.474091
-0.0733255
-0.195064
-0.470072
--0.191426
--0.25492
--0.0310248
-0.0515342
-0.577459
--0.0881458
--0.0652959
-0.111725
-0
-0.541318
--0.16013
--0.12093
--0.0957559
-0.1011
--0.0458865
-0.195229
--0.157412
--0.125624
-0.387456
-0.329536
-0
-0.0167227
-0.0502281
-0.277243
--0.0300157
-0.238097
-0.101385
-0.826522
-0.0170086
-0.0670988
--0.0880042
--0.258211
--0.0801972
-0.156425
-0.336147
-0.0164071
-0.0493535
-0.19716
-0.612121
-0.563308
-0.554292
-0.138882
-0.388876
-0.136965
-0.0525485
-0.100898
-0.128658
--0.121169
--0.197432
-0.156849
--0.257564
--0.0673925
--0.0341715
-0.273819
-0.0514637
-0.192092
--0.0174416
--0.0856666
-0.302464
-0.0518469
-0.481379
-0.236995
-0.137027
-0.306359
--0.297126
--0.148947
-0.18406
-0.135453
--0.0698851
-0.186615
-0.203974
-0.0187237
--0.0707838
-0.0518311
--0.116723
-0.0695504
-0.479693
-0.0517692
--0.0905254
--0.0940007
-0.473277
-0.0542775
-0.495363
-0.0518721
-0.282197
-0
-0.0164963
-0.0203851
--0.261746
--0.0847428
--0.0179269
-0.0727989
-0.201333
-0.186506
--0.0326757
--0.0358952
-0.0515054
-0.0494786
--0.0343714
-0.136892
--0.271116
-0.0998408
-0.438561
-0.179629
-0.287612
-0.215376
--0.161233
-0.206623
--0.0831427
--0.245055
--0.110128
--0.0648095
--0.19341
--0.0673662
--0.164288
-0.185106
-0.0511831
-0.10263
--0.11298
-0.436785
--0.0631916
--0.0320354
-0.146527
-0.41536
--0.165974
-0.207338
-0.107789
--0.0362728
--0.0822785
-0
-0.046993
-0.0706279
-0.047987
--0.0694318
-0.6018
--0.121227
-0.102456
-0.0504944
-0.187428
--0.0882855
-0.188181
-0.153037
-0.0945988
-0.103042
-0.016177
-0.191179
-0
-0.165292
-0.103566
-0.165219
-0.321367
-0.132172
-0.311128
--0.0342964
-0.145354
-0.0536876
-0.10519
-0
-0.186369
--0.123416
--0.0663798
-0.307311
--0.212299
-0.34708
-0.186896
-0.155023
-0.383968
-0.120715
-0.285378
--0.0370853
-0.330221
-0.0548237
-0.391962
-0.142113
--0.0185561
--0.0363078
-0.106996
-0.570079
-0.0207888
--0.0921178
-0.106664
-0
--0.124021
--0.0351004
--0.036644
--0.0372797
-0.419184
-0.144728
-0.0727044
-0.074682
-0.354236
-0.301444
--0.126702
-0.0521326
-0.0169325
-0.20726
-0.294423
--0.245302
-0.25637
-0.26312
--0.213108
-0.288959
--0.0910512
--0.0365647
-0.558344
--0.0727981
-0.714855
--0.0386763
-0.165929
-0.298122
-0.235029
-0.0168257
-0.0174465
--0.126203
--0.0388985
-0.361176
-0.109056
--0.124315
--0.0394607
--0.255881
--0.175909
-0.0184382
-0.0391982
-0.167513
-0.776692
-0.342858
--0.0897538
--0.103562
-0.286685
-0.111527
--0.0951249
--0.303125
-0.143504
-0.0532188
-0.0164725
-0.365862
--0.0890686
--0.119119
--0.19655
--0.0887305
--0.0673598
-0.284383
-0.514834
-0.34446
-0.0160179
-0.296141
-0.451596
--0.122214
-0.209323
-0.331738
-0.28165
--0.0875487
-0.465312
--0.230436
-0.127169
-0.0223573
-0.0746425
-0.31551
-0.143208
-0.196548
--0.0877919
--0.330369
--0.26905
-0.422835
-0.149049
-0.0574703
-0.0183067
-0
--0.135364
-0.573005
-0.194105
-0.0178807
--0.278206
-0.11535
-0.0199723
-0.517063
--0.0367543
-0.15406
-0.261188
-0.0553546
-0.509749
-0.309458
--0.0382304
-0.0556156
-0.212609
--0.333988
--0.133956
--0.124011
-0.0549999
-0.021285
--0.133531
-0.0564904
--0.0386935
-0.210263
--0.136643
-0.214256
--0.131333
-0.270127
-0.388116
-0.521764
--0.187662
--0.0374546
-0.208872
--0.169258
-0.498553
-0.279265
-0.0192602
--0.196934
-0.0552123
--0.193108
-0.301246
-0.0573291
--0.360047
-0.466332
-0.0186104
-0.178873
-0.111766
-0.458005
-0.31199
-0.301504
--0.199037
-0.354881
-0.49899
-0.494019
-0.0564844
--0.079276
-0.115899
-0.169963
-0.0568403
-0.115014
--0.0915927
--0.20318
-0.210281
--0.0398065
-0.056956
-0.21638
-0.114274
-0.218603
--0.131467
-0.532713
--0.0544458
-0.658977
-0.458802
-0.110524
-0.0581795
--0.273352
-0.0584456
-0.266003
-0.622931
-0.436997
-0.203162
-0
-0.261178
-0.0175099
--0.128294
--0.0380519
-0.269728
-0.268359
--0.038685
-0.0541296
--0.0894345
-0.199448
-0.336118
-0.254112
-0.397037
-0.345276
--0.0356204
-0.156835
-0.569294
--0.0356469
-0.544785
-0.144408
--0.268365
-0
--0.171709
--0.13086
-0.105875
-0.0567648
-0.208337
-0.0199901
-0.109496
-0.230764
-0.116285
--0.182181
-0.109183
--0.173365
-0.343367
-0.055195
-0.139994
-0
-0.0549656
--0.125932
-0.444555
-0.11275
-0.151926
-0.199259
--0.185975
--0.19065
-0.0536351
-0.750799
-0.0541727
-0.113206
-0.422236
--0.134614
-0.194572
-0.0571896
-0.0559307
-0.111352
-0.212706
--0.295375
-0.0187071
--0.0952203
-0.169351
-0.156182
-0.0185882
-0.350572
--0.0880064
-0.289131
--0.0378168
--0.0389621
--0.0970878
-0.197514
-0.173914
--0.0383883
--0.189172
-0.151574
-0.0214733
-0.11641
-0.15434
--0.0382161
-0.0747385
-0.412804
-0.166599
-0.292329
--0.234086
--0.135066
-0.433584
-0.527597
-0.454267
-0.330557
--0.192817
-0.310129
--0.281677
--0.0781102
--0.287423
-0.317306
-0.216515
-0.0585126
-0.221754
-0.451462
-0.321072
-0.0186246
-0.0584045
-0.114167
-0.214975
--0.171649
-0.114283
-0.11467
--0.498009
-0.15253
--0.101005
-0.115275
-0.154069
-0.153024
-0.304528
--0.440493
-0.0720875
--0.264913
-0.273506
-0.180572
--0.03928
-0.0773812
-0.14541
-0.165629
--0.293631
-0.270394
-0.0614461
-0.0556882
-0.0204039
--0.206729
-0.440415
-0.204517
-0.302059
-0
-0.019554
-0.425092
-0.176514
--0.186278
--0.178688
-0.018087
-0.0196926
-0.582753
-0.306494
--0.0894279
-0.0517724
-0.402794
-0.108341
-0.0203031
-0.107186
-0.150025
-0.458827
-0.0534037
-0.277182
-0.202156
-0.0539508
-0.0543198
--0.157421
-0.018446
--0.213086
-0.325391
--0.0970386
-0.161577
-0.0553049
-0
--0.180257
-0.107836
--0.0895391
--0.0928821
-0
-0.0576685
--0.03587
-0.29262
-0.579632
-0.443928
-0.293517
-0.259286
-0.0525832
-0.0552356
-0.201046
--0.268354
-0.249688
-0.458132
--0.0378113
--0.0373142
-0.0557504
-0.106873
-0.114374
-0.295467
-0.0573746
--0.0918388
-0.055531
--0.181344
-0.108788
-0.528048
--0.130866
--0.0933594
--0.0384143
-0.0537649
-0.104455
--0.131284
-0.208422
-0.144993
-0.505348
-0.133829
-0.252562
-0.163594
-0.361536
-0.0562687
-0.0563811
-0.0214393
-0.224406
--0.188487
-0.0737254
-0.0564256
-0.289817
-0.553122
--0.264499
-0.0569911
--0.421607
--0.0758643
--0.368223
-0.0216767
-0.295099
--0.186376
-0.21229
-0.133315
-0.741307
--0.0747347
--0.132158
-0.64526
-0.0185412
-0.203268
-0.606519
-0.601252
--0.316422
--0.0750464
-0.111942
-0.113615
--0.4073
-0.20549
-0.206115
-0.108241
-0
-0.422967
--0.274616
-0.198512
--0.0713649
-0
-0.114959
-0.44595
-0.165889
-0.344648
-0.118839
-0.145652
-0.109374
--0.129039
-0.596668
-0.284152
--0.037835
-0.242911
-0.198151
--0.192557
-0.754335
-0.14596
-0.310633
-0.136972
-0.146029
-0.0566288
--0.0352962
--0.182049
--0.0369717
-0.0529142
-0.187644
-0.0534403
-0.273639
-0.0160735
-0.0185701
-0.106411
-0.0497922
-0.460994
-0
-0.103095
-0.363208
-0.0164096
--0.0331603
--0.0156979
-0.0167544
--0.0971719
-0.120237
-0.0557694
--0.184951
--0.183866
--0.181783
--0.279454
-0.165539
-0.159879
--0.270341
--0.0383929
-0.146496
-0.0737824
-0.4767
-0.201031
-0.20883
-0.515547
-0.261348
-0.112873
-0.154626
-0.153566
-0.106069
-0.304739
--0.196326
-0.36218
-0.499118
--0.179031
--0.0374318
-0.362606
-0.474603
-0.119828
-0.148183
-0.494574
-0.144766
-0.420875
--0.0937817
-0.112899
--0.0724563
-0.155427
--0.0366235
-0.0183979
-0.458037
--0.132776
-0.060554
--0.134219
-0.303912
-0.205114
--0.0401992
--0.235156
-0.11266
-0.0196238
-0.450172
--0.22724
-0
-0.154465
-0.429664
--0.136643
-0.116782
-0.0774763
--0.267264
-0.180366
--0.0397221
-0.213702
-0.590344
-0.0560881
-0.0577453
-0.266539
-0.210036
-0.269195
--0.187304
-0.112497
-0.334838
-0.594525
-0
--0.133497
-0.0606952
-0.504013
-0.160828
-0.620551
-0.21473
-0.307885
--0.0945944
--0.26588
-0.431847
--0.0987006
-0.017478
--0.184183
-0.317953
--0.0391352
-0.0592071
-0.0797387
-0.0574883
-0.34597
-0.583959
-0.374853
-0.226853
-0.0185525
-0.171999
--0.136439
-0.340478
--0.0371
--0.223366
--0.221056
--0.0755385
--0.0972322
-0.0409551
-0.348486
--0.0363345
-0.294102
-0.197018
-0.2149
-0.257245
--0.130013
-0.0539858
-0.0549013
-0.114887
--0.0904069
-0.103525
-0.205181
-0.288163
-0.193717
--0.0361514
--0.0918237
--0.400303
-0.0552419
--0.180498
-0.466865
--0.0362494
-0.167087
-0.357664
-0.124179
-0.206751
-0.0184137
-0.152108
-0.424975
--0.0917055
-0.21446
-0.384343
--0.13715
-0.31579
-0.365791
-0.383592
-0.0586046
-0.468029
--0.388087
-0.111001
-0.355914
-0.280278
-0.213916
-0.334479
-0.117246
-0.261411
-0.521712
-0.442014
-0.446487
-0.172676
-0.0547874
-0.821156
-0.574903
-0.303881
--0.197498
--0.0365749
-0.119565
--0.195599
-0.360782
-0.117068
-0.369065
--0.0998191
-0.217471
-0.216205
-0.208382
-0.425444
-0.0592211
-0.236687
-0.620788
--0.140801
--0.0383928
-0.261874
--0.101021
-0.207095
-0.378709
-0.333465
-0.308242
-0.057476
-0.0545275
--0.139041
-0.0217862
-0.115238
-0.217535
--0.135741
-0.322233
-0.29307
--0.201547
--0.232848
-0.440511
-0.00404087
-0.0209673
-0.41612
-0.848938
--0.198872
-0.329967
-0.727235
-0.421574
--0.193946
-0.0612007
--0.230179
-0.123607
--0.140498
--0.193845
-0.231569
--0.13547
-0.0574952
--0.0923781
-0.0568277
-0.0186721
-0.0592958
-0.0188519
-0.18145
-0.0599806
--0.0773942
-0.209413
-0.738646
--0.0387496
--0.038712
-0.0594178
-0.201332
-0
-0
--0.0899932
-0.258791
-0.141962
-0.0573367
-0.0185744
-0.118721
--0.304562
-0.407021
--0.038067
-0.147952
--0.195164
-0.204067
--0.0722046
--0.0920596
-0.462059
--0.0341135
-0.0556844
--0.0729323
--0.0369366
-0.0183574
-0.599408
-0.194422
-0.190606
-0.0536743
-0
--0.0915746
-0.404643
--0.0365296
-0.402268
-0.0212344
--0.0352295
-0.0694085
-0.136273
--0.0853084
--0.0880596
-0.388493
--0.276007
--0.0336848
-0.198061
-0.103006
--0.0822872
-0.184657
--0.12645
--0.0709754
-0.38475
-0.0956829
--0.207979
-0.15711
--0.0910377
-0.0509554
-0.335678
-0.274083
-0.417306
-0.388149
-0.0520479
-0.161913
-0.0521358
--0.119995
--0.265507
-0.621059
-0.051816
-0.142459
--0.215249
-0.459425
-0.432299
-0.142233
-0.246655
-0.236971
-0.250819
-0.0759826
--0.123801
-0.867672
-0.10928
-0.490249
--0.218812
-0.204884
-0.157074
--0.370177
-0.314255
-0.348551
--0.132337
-0.456951
--0.121887
--0.105169
-0.216528
-0.733982
--0.124084
--0.0182936
-0.591454
-0.292531
-0.110135
-0.476954
--0.0696177
--0.0163183
--0.663222
--0.0764636
-0.128183
-0.416772
-0.403326
-0.0555748
-0.112848
-0.206128
-0.363748
-0.380977
-0.476912
--0.365265
--0.0385264
--0.0796314
-0.162882
-0.020222
--0.0354445
-0
-0.424815
-0.359412
-0.297512
-0.226265
-0.076903
-0.114951
-0.148181
-0.0554072
-0.108432
-0.114157
--0.231626
--0.165512
--0.188291
-0.195566
--0.191993
--0.0704653
--0.0163223
-0.0535836
--0.0906088
-0.0579019
-0.203728
--0.180864
-0.145089
--0.273858
-0.168343
-0.166238
-0.108328
-0.187517
-0.106403
--0.121368
-0.151037
-0.10574
-0.346535
-0.380557
--0.331739
-0.486888
-0
-0.582893
-0.0545838
--0.0352588
-0.242584
--0.429752
--0.176628
-0.0524924
--0.0987322
-0.219439
-0.151703
--0.0942518
-0.209049
--0.0367439
--0.0964207
-0.279896
--0.198565
--0.0931066
-0.269138
-0.111439
-0.112561
--0.0908877
-0.46015
--0.127174
-0.0192763
-0.249665
--0.134246
-0.349893
--0.140094
-0.10554
--0.135406
-0.0545318
-0.209441
--0.191297
-0.140258
-0.478162
-0.111785
-0.42313
--0.038836
--0.133267
-0.208687
-0.209847
-0.266343
-0.171583
--0.0965644
--0.130788
-0.0554387
-0.669707
--0.211267
-0.12352
-0.0575113
--0.195663
-0.294312
-0.0567893
--0.0379999
-0.478258
--0.102226
-0.0565199
-0.173684
-0.202925
-0.324298
-0.212151
--0.202759
--0.0739058
--0.230635
-0.597187
-0.0584006
--0.393596
--0.300943
--0.041329
--0.0939647
-0.179328
-0.80206
-0.216128
--0.0412325
-0.132469
-0.265018
-0.315506
-0.153816
-0.282785
-0.112739
--0.134569
-0.76972
-0.120483
-0.332892
-0.219141
-0.282223
-0.39369
-0.0564764
-0.018046
-0.371725
-0.446256
-0.111721
--0.130087
-0.113564
-0.200699
-0.477049
-0.313229
--0.0547216
--0.141252
--0.0937827
-0.674508
--0.409703
-0.174781
-0.367365
-0.406694
-0.114611
--0.0379386
-0.201115
--0.377406
--0.0934928
-0.263769
-0.0173428
-0.708965
-0.494301
-0.0172563
-0.0551681
-0.466352
--0.132263
--0.0377118
--0.0896793
--0.036371
-0.211039
-0.0169559
--0.0342056
--0.212451
-0
-0.106523
--0.218596
-0.290961
-0.110669
--0.106776
-0.11177
-0.432128
-0.20307
-0.0542837
--0.248612
-0
--0.0522866
-0.0521598
--0.0732919
--0.012306
-0.136698
-0.269726
-0.196612
--0.0882437
-0.147685
-0.162468
-0
-0.203063
-0.0174816
-0.0535914
-0.0539915
-0.162219
-0.196669
--0.243231
--0.161369
-0.277063
-0.258503
--0.166167
-0.279549
-0.0533594
-0.407132
-0.200682
--0.0365727
--0.124093
--0.0920094
-0.139162
-0.188624
-0.714388
--0.0377666
-0.208708
-0.450252
-0.296209
--0.272929
--0.273844
--0.125748
-0.292899
-0.262706
-0.391806
-0.284935
--0.0742801
-0.461436
-0.0177505
-0.150072
--0.0708334
--0.226258
--0.0365755
-0.113501
-0.344877
-0.150409
-0.4892
-0.148829
--0.191264
-0.487349
--0.125763
--0.217827
-0.4156
--0.09446
--0.266297
--0.360241
--0.330164
--0.132516
-0
-0.0174505
-0.14598
-0.0179348
-0.0579789
-0.259324
-0.492517
--0.357474
-0.208698
--0.227113
-0.055819
-0.36191
-0.0589715
-0.197113
-0.299865
-0.201378
-0.265601
--0.133812
--0.175811
-0.455952
-0.207523
-0.0179585
--0.0772096
-0.252406
-0.154244
-0.109676
--0.137251
-0.583775
-0.603642
--0.247133
--0.251309
-0.266027
-0.262702
-0.47596
-0.0539339
-0.0534807
-0.256829
-0.304398
--0.0948172
--0.154693
--0.262422
-0.438952
--0.036178
-0.0546914
--0.327509
-0.189296
--0.0362337
--0.129072
--0.276039
--0.362503
-0.192998
--0.0907182
--0.120746
-0.212149
-0.142679
-0.0167611
-0.242366
-0.332337
--0.17759
--0.2797
-0.150276
-0.0586332
--0.184172
-0.062245
-0.545248
-0.170081
--0.0386818
-0.518028
-0.293867
-0.414373
-0.215499
-0.4166
-0
-0.17305
-0.0609662
--0.300742
-0
--0.0439915
-0.348191
-0.699769
-0.0590238
-0.125398
-0.0208434
-0
--0.0395646
--0.22079
--0.0815567
--0.219712
--0.0402005
-0.185097
-0.379627
-0.0633275
--0.140959
-0.22819
--0.120815
--0.0420808
--0.394225
--0.0805244
-0.0602919
-0.477544
-0.162336
--0.0412753
--0.147962
-0.0849415
-0.121894
-0.0618546
-0.16522
-0.0605479
-0.230059
-0.234059
-0.157721
-0.322279
-0.122151
--0.0404846
-0.381666
--0.145349
-0.788295
-0.22623
-0.124874
-0.66129
-0.460832
-0.346476
-0.126836
-0.695175
--0.041013
-0.0779004
-0.386603
-0.0404326
--0.197469
-0.060296
-0.605775
-0.53794
-0.235317
--0.0389039
--0.514824
-0.0196972
-0.385777
--0.143526
--0.541985
-0.0801489
-0.0621099
--0.334968
-0.310305
--0.252007
-0.233942
-0.731474
--0.119772
-0.677918
-1.07391
--0.100506
-0.347065
--0.0992696
-0.649722
--0.33521
-0.0628951
-0.500898
-0.0230205
-0.599638
--0.228989
--0.323138
-0.433962
-0.0790042
-0
-0
-0.55518
-0.0602146
--0.0414422
--0.0730965
-0.268528
-0.21794
--0.186829
-0.231045
-0.0215445
--0.132439
--0.127877
-0.475996
-0.201278
--0.4032
-0
-0.15736
--0.0378615
-0.213706
-0.0559251
-0.325952
--0.22962
--0.0399838
-0.304279
-0.221317
-0.218715
-0.401951
--0.0697983
-0.194857
-0.26631
-0.379129
--0.0338284
-0.60043
-0.31608
-0.290312
--0.0853437
--0.0349362
--0.283357
-0.0500824
--0.0877399
--0.0348893
-0.475036
--0.082677
--0.0362762
-0.303429
--0.179314
--0.0346736
-0.0697513
-0.0166342
--0.0341757
--0.122497
--0.0909445
-0.135937
--0.121937
-0.187307
--0.038198
-0.143492
-0.0551234
--0.206692
-0.072739
-0.459591
--0.090158
-0.583167
-0.557256
-0.0167247
-0.0556175
-0.192374
-0.740896
-0.0514725
-0.108975
-0.199402
-0.11094
-0.193293
--0.180009
--0.123694
-0.197133
--0.0372434
-0.108464
-0.160378
-0.788834
--0.033963
-0.403852
-0
--0.0357996
--0.162369
-0.187977
-0.0169054
-0.142936
-0.28826
-0.11132
--0.250434
--0.0723358
-0.0529381
--0.255397
-0.310403
-0.200176
--0.0670397
--0.268069
--0.397109
-0.340951
-0.18494
--0.12883
--0.157214
-0.204805
-0.789961
-0.349027
-0.490911
-0.35742
-0.580215
-0.0551579
--0.218532
-0.170263
--0.299536
--0.0388381
--0.0899639
-0.0555867
-0.306344
-0.073455
-0.103811
-0.214123
--0.0373188
-0.148872
-0.561109
--0.0359616
--0.327568
-0.346133
--0.0155225
-0.428164
--0.211296
-0.128604
-0.16131
-0.0589043
-0.103158
-0.760816
-1.00511
--0.0355352
--0.0353161
--0.0369223
-0.0993813
-0.194728
-0.273739
--0.0366529
-0.536812
-0.102559
-0.195908
-0.181287
--0.259446
-0.139615
--0.087802
--0.120358
-0.0514215
--0.148438
-0.330707
-0.183766
-0.0545409
-0.409814
-0.368957
-0.417597
-0.312184
-0.0163337
--0.292434
-0.0971492
-0.222302
-0.104972
-0.220129
-0.858161
-0.721148
-0.283144
-0.210662
--0.0913693
--0.200002
-0.0512857
--0.227255
-0.154435
--0.0943476
-0.0168754
-0.332802
-0.28454
-0.145891
-0.401175
-0.112797
--0.0368298
-0.20616
-0.0187309
-0.149207
-0.148148
-0.3149
-0.209077
--0.094937
-0.441523
-0.0191891
-0
-0.115901
-0.0376804
--0.233131
-0.108507
-0.274585
--0.135658
-0.0591318
-0.0526179
--0.0781279
-0.210215
-0.61075
-0.107692
--0.135954
-0.147685
--0.282961
-0.0187595
--0.212038
-0.054155
-0
--0.0933419
--0.0901184
-0.466681
-0.366822
-0.529129
-0.21541
-0.0179133
-0.0564472
-0.113303
-0.0760897
-0.211153
--0.163086
--0.363559
--0.285116
-0.23525
-0.175464
--0.0384837
--0.329399
-0.262505
--0.181466
-0.294081
--0.0376841
-0.116379
-0.374554
-0.464013
-0.221305
-0.167366
-0.174566
--0.0362544
-0.570093
--0.0908461
--0.13582
-0.307635
-0.527055
-0.453776
--0.0382631
--0.183816
-0.0821946
-0.268848
--0.266263
--0.21109
-0.0601221
-0.202342
--0.132164
--0.0371146
--0.129313
--0.0372476
-0.506167
--0.0394849
-0.200224
-0.0348949
--0.27999
-0.288089
-0.115428
-0.315289
-0.164702
-0.332304
-0.0179844
-0.106393
-0.0562034
-0.192434
-0.214957
-0.137417
-0.261553
--0.0715311
--0.130802
-0.62444
--0.0924412
-0.144936
-0.0543827
-0.166177
--0.101966
-0.148861
-0.429363
-0.329665
-0.0502908
--0.255549
--0.121563
--0.193438
--0.123828
-0.0695103
--0.11361
-0.196939
-0.447045
--0.18114
--0.233404
-0.0170317
-0.239177
--0.0360839
-0
-0.523549
--0.0345404
-0.135239
-0.0693091
-0.247341
-0.0525446
-0.0543324
-0.0998071
-0.0727378
-0.265968
-0.639529
--0.126326
-0.246415
-0.237513
-0.329708
-0
-0.0528168
-0.306097
-0.017738
--0.207105
-0.346554
-0.104299
-0.26405
-0.215677
-0.392696
-0.112107
-0.267514
-0.158483
-0.401183
--0.121331
-0.0556818
-0.124005
-0.581719
--0.0894461
--0.375038
-0.0561479
-0.0183571
-0
-0.370814
--0.175872
-0.776506
--0.168598
--0.110514
--0.0192514
-0.286342
-0.14402
-0.722741
-0.0711726
-0.877075
-0.892537
-0.340569
--0.0364041
-0.302432
-0.148717
-0.252565
--0.106969
-0.415115
--0.181789
-0.252548
-0.337265
-0.172087
-0.0556783
-0.42827
-0.196621
-0.0177033
-0.211057
-0.0559359
-0.539615
-0.149191
-0.159046
-0.485935
-0.495674
-0.365083
-0.767177
-0.0553736
-0.586939
-0.326496
--0.0376977
--0.0723141
-0.347275
-0.58183
-0.163204
-0.141217
-0.325909
-0.147606
-0.247756
-0.0185931
--0.170596
-0.48185
-0.283055
--0.30295
-0.10976
-0.148524
-0.273135
-0.0527965
-0.536395
-0.199074
-0.191903
-0.442693
-0.188008
--0.119827
--0.210462
-0.425336
-0.261237
--0.0349503
-0.275863
--0.342829
-0.198275
-0.142757
-0.316017
-0.0608452
--0.207095
--0.280712
-0.657937
-0.409991
--0.136295
-0.0172362
--0.148111
--0.0372704
-0.317176
--0.0969259
--0.344803
-0.0176235
--0.0395947
-0.263256
--0.101218
--0.0343515
--0.141156
-0.393686
-0.224868
-0.26008
-0.118681
-0.202868
--0.204859
--0.374266
-0.20737
--0.0363428
--0.241785
-0.475263
-0.0586176
-0.445593
-0.0223559
-0.148176
-0.692358
--0.125335
-0.669521
-0.0577671
-0.234501
-0.519982
-0.362104
-0.262697
-0.176857
-0.173354
-0.467377
-0.109311
-0.319537
-0.380564
--0.520667
--0.0904873
--0.197889
--0.017201
-0.371208
-0.378926
--0.357368
-0.656265
--0.235032
-0.0592503
--0.368942
-0.773254
-0.378666
-0.757784
-0.11714
--0.404865
--0.366949
-0.27387
-0.779923
--0.131982
--0.115963
-0.520484
-0.160586
-0.535544
-0.504365
-0.386615
-0.644722
-0.581326
-0.166034
-0.320368
--0.0758876
-0.432142
-0.214955
-0.714194
-0.191915
-0.161341
--0.0999262
--0.124616
--0.0379684
-0.0174197
-0.217997
-0.473958
--0.0403857
-0.0212224
-0.219209
-0.117342
--0.145721
--0.193349
-0.33627
-0.0170091
-0.333969
-0.665451
--0.28367
--0.184155
-0.0768766
--0.187116
--0.302139
-0.383725
--0.231077
--0.284217
-0.0567223
--0.18631
--0.203485
-0.508854
-0.477831
-0.20424
-0.374853
-0
-0.110611
-0.425078
--0.190315
--0.0691021
-0.217646
-0.143009
-0.518396
-0.109039
--0.286692
-0.200369
-0.0561779
--0.179864
--0.0432262
--0.217018
-0.0561654
-0.149303
-0.104863
-0.412402
-0.686901
-0.306759
-0.105605
--0.0342401
--0.281358
-0.200367
-0.451914
--0.122368
--0.0848657
-0.571341
-0.187237
-0.424655
-0.531126
-0.0535697
--0.0345602
-0.325026
-0.0167868
-0.106224
-0.285157
--0.285144
-0.0189828
-0.190766
-0.476769
-0.53308
--0.122689
-0.218121
--0.515353
-0.0729733
-0.294576
-0.13917
--0.0884189
-0.0174078
--0.162526
-0.162269
-0.0173318
-0.0563131
-0.285396
-0
--0.0160603
-0.0176487
-0.249531
-0.643968
-0.831288
-0.930069
-0.108719
-0.799473
--0.163876
-0.017477
-0.106271
-0.125308
--0.125928
-0.146377
--0.0524416
-0.462051
-0.390398
-0.255427
--0.0360094
-0.427078
-0.105159
--0.128553
-0.167715
-0.0181803
--0.018506
-0.171119
-0.39853
-0.35349
-0.0700029
--0.0373077
--0.16274
--0.0191759
-0.735159
-0.248246
-0.273233
-0.33147
-0.285647
--0.0369515
-0.310291
-0.740138
-0.202566
-0
-0.0543007
-0.255222
-0.129292
-0.177277
-0
--0.0912817
-0.159718
-0.154966
-0.560122
-0.267499
-0.0541678
-0.053082
--0.0370892
-0.109298
-0
-0.244788
-0.0194694
-0.436095
-0.156675
--0.135553
--0.0364524
-0.487542
-0.108375
-0.390283
-0.167593
-0.400262
-0.107969
--0.314108
--0.0337799
-0.203348
-0.138478
-0.0517323
--0.17544
-0.213234
-0.345359
--0.0360268
--0.0879787
--0.182303
--0.171709
-0.275518
--0.0736496
--0.210421
--0.126587
-0.15598
-0.311927
-0.277813
-0.0564741
--0.258581
-0.0548109
--0.0356944
--0.0794783
-0.0200012
-0.608287
--0.21229
-0.112506
-0.0559776
-0.054247
--0.0361099
--0.0169664
-0.0537585
--0.0933374
-0.0562245
--0.29318
-0.348109
-0.114368
--0.0887995
--0.140439
-0.198757
-0.363381
-0.147273
--0.133617
--0.0998346
-0.651669
--0.487528
-0.325668
-0.260746
-0.213208
-0.342657
--0.134696
-0.207529
-0.0180335
--0.0919831
-0.518851
-0.595501
-0.208685
--0.228449
--0.0777164
-0.149921
-0.316815
--0.0383752
-0.158679
--0.164218
--0.562236
--0.126369
-0.303978
--0.171096
--0.0970828
-0.0177268
-0.0568104
-0.110351
--0.0927577
--0.0374559
--0.196115
--0.0905196
-0.307621
-0.018154
-0.172259
-0.427958
--0.193147
-0.165449
-0.149243
-0.880741
-0.29765
-0.450201
-0.113974
-0.0180642
-0.576968
-0.45852
-0.0180934
-0.168253
-0.300655
--0.0397308
-0.108908
-0.312959
-0.415848
-0.257347
-0.209233
-0.349054
-0.645303
-0.337881
-0.6022
-0.223507
-0.440007
-0.111585
-0.70444
-0
-0.156131
-0.532492
--0.189802
-0.457299
--0.31997
-0.0178104
--0.03577
-0.410612
-0.420687
-0.269898
-0.152372
-0.078229
-0.453225
-0.0534287
--0.0365869
--0.0867942
-0.647463
-0.243969
--0.188366
-0.017254
-0.267345
-0.469457
--0.130942
-0.107251
-0.110187
-0.143377
-0.256669
-0.0543014
--0.181605
--0.440598
--0.0355838
-0.106088
-0.349105
-0.209834
-0.224079
--0.132237
--0.185409
-0.29076
-0.203051
--0.0351591
-0.254791
-0.196196
--0.292044
-0.0560342
--0.0748648
-0.15033
-0.250815
-0
-0.606319
-0.250829
--0.0318718
-0.275455
--0.0675468
--0.130937
-0.0209258
--0.0374194
-0.0554215
-0.110629
-0.261042
-0.0562282
--0.212106
--0.0378565
-0.398178
-0.0587182
-0.165717
-0.600455
-0.254883
-0.364035
-0.10987
-0.518415
-0.311393
--0.117948
-0.0541371
-0.297463
-0
-0.87636
-0.149436
-0.329076
-1.1792
-0.219635
-0.573115
-0.27474
-0.15392
-0.0185104
-0.352301
-0.557703
-0.108456
-0.11939
-0.361792
--0.134424
-0.149803
-0.519911
-0.202347
-0.487084
--0.0759715
-0.171595
-0.171767
-0.228259
-0.644606
--0.481777
-0.0565602
-0.22471
-0.203198
-0.43421
-0.762074
-0.5331
--0.133902
-0.257758
-0.255101
-0.11299
-1.16083
-0.90739
-0.320273
-0.114053
--0.155167
-0.628638
--0.0749946
-0.0742225
--0.0384132
-0.0769886
--0.0378373
--0.188877
-0.171181
--0.196548
-0.162651
-0.275948
--0.0967741
--0.0390872
-0.199373
-0.211061
-0.198656
--0.222679
-0.136201
-0.501127
--0.222246
-0.290796
-0.220076
--0.290776
--0.168678
-0.0590619
--0.0703976
-0.439975
-0.443694
-0.606997
-0.153596
--0.369407
-0.190969
-0.150763
-0.165555
-0.298792
-0.0545547
-0.339277
-0.143251
-0.752338
--0.0368644
-0.107779
-0.0532196
-0.398238
--0.259838
--0.132043
-0.419094
-0.0206697
-0.0207836
-0.0790714
-0
-0.289126
--0.0941291
-0.0518132
--0.125936
-0.181934
-0.361214
-0.189411
-0.591351
-0.0737501
-0.222172
--0.0354887
--0.17948
-0.190722
--0.0719753
-0.10509
-0.194512
-0.552828
--0.0914708
-0.0996463
-0.0742118
--0.185944
-0.168789
--0.303602
--0.213599
-0.395376
-0.295455
-0.239921
-0.256976
-0.0171978
--0.293007
--0.268107
--0.272048
--0.129381
-0.427705
-0.400062
--0.0371766
-0.164242
--0.381881
-0.0564917
-0.188866
-0.0172726
-0.264558
--0.350296
-0.394594
--0.269371
-0.700548
--0.188566
-0.116324
--0.410218
-0.291769
--0.0362806
-0.294435
--0.128088
--0.22069
-0.299404
-0.0178581
-0.972098
-0.311846
-0.277658
-0.456426
-0.0573464
-0.361928
-0.495844
-0.579428
-0.0547944
-0.106512
--0.182667
--0.0370939
-0.312931
-0.287144
--0.18392
-0.299998
-0.369787
--0.0521047
-0.284576
-0.395039
--0.604686
-0.767767
-0.696378
--0.504687
-0.0545923
--0.0739482
--0.272215
-0.0542762
-0.149611
-0.111685
--0.036214
--0.075688
-0.0534586
--0.18738
-0.647012
--0.127893
-0.0771014
--0.176832
-0.342003
-0.109176
-0.212492
--0.212666
-0.196797
-0.475164
-0.165969
-0.0177917
-0.16635
-0.107508
--0.0365812
-0
-0.0191136
--0.315519
-0.0172259
--0.0854906
-0.538105
--0.186863
-0.328217
--0.307686
-0.0983711
-0.459919
-0.0359639
--0.128194
--0.347833
-0.461176
--0.207654
-0
-0
-0.198767
--0.126638
--0.189236
-0.211189
--0.177758
-0.412985
-0.391951
-0.0512901
--0.0653301
-0.133847
-0.0545623
-0.0531717
-0.104219
-0.37001
-0.18992
--0.184567
-0.185392
-0.651764
-0.0352222
-0.340628
-0.051517
--0.186505
--0.0340522
-0.346293
--0.122266
-0
--0.122383
-0.369144
-0.432898
-0.542809
-0.277103
-0.113908
-0.106498
-0.156319
-0.698047
--0.139591
-0.744959
-0.267613
--0.122182
-0.0178735
-0.212248
--0.166739
--0.125918
--0.0774799
-0.333058
-0.436272
--0.182913
--0.0754794
-0.19839
-0.362308
-0.296967
--0.0364109
-0.158272
--0.109661
-0.106844
-0.28184
--0.125762
-0.353806
-0.407131
--0.279129
-0.359109
-0.108371
--0.0372793
-0.280184
--0.13092
-0.109359
-0.34251
-0.452047
-0.362927
-0.34711
-0.0710449
-0.29584
-0.22657
-0.0768072
--0.0755498
-0.41031
-0.018263
-0.313575
-0.66567
-0.213393
-0.074694
-0.264561
-0.645264
-0.325088
-0.0734655
--0.179414
-0
-0.453866
-0.159085
-0.478965
-0.677439
-0.109944
-0.441528
-0.0570413
--0.0714128
-0.266246
-0.144442
--0.117772
-0.111624
-0.0742105
-0.070593
-0.514409
-0.0171054
-0.0534879
-0.33666
-0.157466
--0.0349629
-0.0792117
-0.235216
--0.161092
-0.255341
-0.0534179
--0.0905325
-0.499584
-0.13725
--0.108048
-0.401189
-0.572461
--0.0357821
--0.282758
-0.158661
-0.0519886
-0.191623
-0.196385
-0.637533
-0.241268
-0.281272
--0.262239
-0.361967
-0.191911
-0.200134
--0.132985
--0.0394878
-0.21346
-0.0555371
-0.361978
-0.0555519
--0.273704
-0.319441
-0.143547
--0.188143
--0.0940632
--0.0755602
--0.225689
-0.209801
-0.479364
--0.0395356
-0
-0.360237
-0.181542
--0.475061
-0.477375
-0.175458
-0.628305
-0.483174
-0.560792
-0.207812
-0.108597
-0.118396
-0.207186
-0.0569628
--0.0373667
-0.441998
-0.57068
-0.0770939
-0.282838
-0.267993
-0.163146
-0.112322
-0.208733
-0
-0.457752
--0.0388846
--0.0392984
-0.419617
-0.112241
--0.196047
--0.193738
-0.117434
-0.14841
-0.372286
-0.4938
--0.0776624
-0.255152
--0.0748738
-0.571271
-1.09346
--0.0384289
--0.193826
-0.629307
-0.0583726
--0.285177
-0.674222
-0.521928
-0.018518
-0.305887
-0.26742
-0.49769
-0.366757
-0.207538
-0.333005
-0.259847
--0.132433
--0.0373992
-0.202865
--0.268395
--0.286801
--0.136055
-0.354877
-0.116597
-0.133028
-0.329746
--0.139192
--0.05063
--0.0389316
-0.427464
-0.420212
-0.600404
-0.317326
--0.0735432
-0.364377
--0.0761466
--0.072875
--0.136307
-0.114963
--0.0205656
-0.455502
--0.218214
-0.60481
-0.221439
-0.25757
-0.161389
-0.110487
--0.132966
-0.256931
-0.373991
--0.129556
-0.442403
-0.51976
-0.0543521
-0.167322
-0.0180734
-0.0179623
-0.415816
-0
--0.173796
-0.672912
-0.0517685
-0.263574
--0.119327
--0.0376893
-0.244911
--0.17426
--0.0710649
-0.125974
-0.239698
--0.127738
--0.0348692
--0.0381415
--0.189702
-0.109118
-0
--0.206036
-0.0747648
--0.24259
--0.0348123
-0.141815
--0.153832
-0.050333
-0.306098
--0.117703
-0.0566887
-0.0986928
-0.108989
-0.331084
-0.0182862
--0.364244
-0.511902
-0.416075
-0.0175669
-0.242308
-0.396749
-0.104198
-0.0179414
--0.173166
--0.219005
--0.358702
-0.0557324
--0.288778
-0.106571
--0.125372
-0.303128
-0.250329
--0.0163691
-0.192618
-0.113933
-0.197194
--0.072605
-0
-0.414614
-0.145113
-0.133174
-0.0544275
--0.127971
--0.0716656
--0.132988
-0.191343
-0.270978
-0.124413
--0.12835
-0.369295
--0.109645
-0.110372
-0.162813
-0.317164
-1.13953
-0.0547919
-0.278377
--0.0364473
-0.167829
--0.0370565
-0.885304
-0.24994
--0.237584
-0.314847
-0.110136
-0.0169533
--0.0718455
-0.167698
--0.0778898
--0.0193656
--0.0959768
--0.0748325
-0.91863
--0.0927373
-0.485626
-0.326874
--0.0170646
-0.171618
--0.0390637
--0.204857
-0.112153
--0.0185617
-0.171964
-0.205579
-0.400295
--0.166908
-0.296387
-0.661068
-0.619664
-0.436273
--0.0385759
-0.404272
-0.235451
--0.0703364
-0.446292
-0.356457
-0.133066
--0.271939
-0.601099
-0.0550673
-0.322486
--0.0361297
-0.20963
-0.155759
-0.159111
-0.436775
-0.0534106
--0.129542
-0.251178
-0.272518
-0.279347
-0.108001
--0.124621
-0.016824
--0.276178
-0.319354
-0.276949
--0.122349
--0.267363
--0.159127
--0.094583
-0.0534005
-0.0177896
-0.0174334
-0
-0.192407
--0.268041
-0.29891
--0.0353479
-0.165876
--0.0350718
-0.495345
-0.272287
--0.0984897
-0.518197
-0.204884
-0.427386
-0.496349
--0.0358023
-0
--0.258761
-0.439884
-0.101673
-0
--0.209069
--0.0374417
-0.191749
-0.150821
-0.834053
-0.263697
-0.159547
-0.424865
-0.341554
-0.645945
-0.166275
-0.355347
-0.335499
-0.40197
--0.573009
-0.280831
-0.104145
-0.0571454
--0.134149
-0.19801
-0.298247
-0.30538
-0.313915
--0.180322
--0.274622
-0.510239
-0.106525
-0.419706
-0.27554
-0.14947
-0.305757
-0.161889
-0.255572
-0.485701
-0.409284
-0.589737
-0.400651
-0.219636
-0.0182698
--0.116679
-0.445022
-0.371346
-0.436913
-0.310133
-0.112623
-0.25056
-0.240997
--0.169231
-0.77182
-0.20849
--0.306741
--0.111608
-0.13093
-0.500852
-0.159304
-0.373579
-0.411917
-0.641729
--0.140766
-0.0534909
--0.076504
-0.170489
-1.13293
-0.51335
-0.295994
-0.348975
-0.330427
--0.417712
-0.340288
--0.0192221
-0.0567038
-0.615546
-0.0772203
-0.164258
-0.0181277
-0.206116
--0.132906
--0.13066
-0.0382923
-0.206444
--0.180539
-0.0763291
-0.0340912
-0.0727193
--0.076246
-0.201494
--0.0401524
-0.0182391
-0.107956
--0.283867
-0.443079
-0.428901
-0.0184889
--0.0348351
--0.178087
-0.252753
-0.0702608
--0.189527
--0.0348768
--0.0195058
-0.122295
-0
--0.0344962
--0.123067
-0.586711
--0.127384
--0.123429
-0.336872
--0.087234
--0.195537
-0.201623
--0.125747
-0.188073
-0.104933
-0.282559
-0.281616
-0.0535152
-0.146072
--0.130567
-0.148642
-0.419266
--0.12223
--0.130272
-0.398458
-0.300343
-0.107439
--0.0730786
-0.0517616
-0.0594776
-0.475687
--0.127201
--0.124091
-0.253009
--0.376451
--0.039227
-0.385396
--0.133704
-0.282503
-0.507584
-0.110464
-0.0182854
-0.384039
--0.0212463
--0.0359158
-0.264663
-0.285645
-0.210127
-0.759061
--0.129851
-0.556931
-0.449104
-0.337992
-0.168486
--0.18185
--0.28171
--0.0757655
-0.0187061
-0.463734
-0.26605
--0.110508
-0.417757
-0.113636
-0.202524
-0.073797
--0.241684
-0.794238
-0.0181728
-0.353534
--0.0553952
-0.267748
-0.513288
-0.544287
-0.451311
-0.313217
--0.137562
-0.258098
-0.25914
--0.164219
-0.0365139
-0.351722
-0.210509
-0.464905
-0.943914
-0.111153
--0.0199373
--0.215747
-0.541429
-0.0192751
-0.174193
-0.0178616
-0.968471
--0.0169324
-0.216866
-0.592631
--0.0165188
-0.159305
--0.138323
-0.574873
-0.166766
-0.303811
-0.0593625
-0.223415
-0.0214173
-0.251281
-0.0189529
--0.0384858
--0.132716
-0.0516149
--0.132769
-0.109895
--0.0199934
-0.128008
--0.23343
--0.298501
-0.174385
-0.070011
--0.179501
-0.6062
-0.0704606
--0.0931152
--0.370661
-0.19573
-0.107995
--0.0875846
-0.147761
-0.758054
-0.147972
-0.39097
-0.108106
--0.0359903
--0.0886588
-0.249044
--0.277711
--0.260234
-0.19475
--0.122726
-0.393935
--0.207682
--0.0683676
-0.0556848
-0
--0.0881496
-0.0505311
-0.251774
-0.0161457
-0.323241
-0.0165213
--0.187868
-0.569886
-0.111184
--0.181264
--0.127267
-0.0167367
-0.20232
-0.0496305
--0.125163
-0.112321
-0.058364
--0.0857982
--0.310714
-0.298182
-0.0572048
--0.209762
-0.0385733
-0.841721
-0.0185066
--0.036979
-0.351459
-0.247016
-0.422983
-0.0549242
-0.22625
-0.104269
--0.0362462
-0.281375
-0.423822
-0.645349
-0.145543
-0.0726093
-0.0559333
-0.222404
-0.152503
-0.299109
-0.320399
-0.0185332
-0.246276
--0.180784
-0.553233
-0.394405
-0.225038
--0.0738747
-0.354343
--0.358625
--0.365641
-0.224885
--0.0355314
-0.4556
-0.210586
-0.298931
-0.589694
-0.509144
-0.302492
--0.328328
--0.0363279
-0.518466
--0.267194
-0.457921
-1.17869
-0.203533
-0.198728
-0.174729
-0.254087
-0.0369161
-0.168006
--0.0160285
-0.219684
-0.111739
-0.461059
-0.200478
-0.264539
-0.381222
-0.266903
-0.119625
--0.0192647
-0.375463
-0.157736
-0.103151
-0.109399
-0.228482
-0.195906
-0.112223
-0.316107
-0.132033
-0.543889
--0.0745156
-0.116954
-0.3966
-0
-0.252561
--0.21457
-0.262705
-0.752712
-0.325012
--0.161118
-0.577082
-0.257653
-0.102531
-0.107236
-0.306245
--0.0366096
-0.10246
-0.254321
-0.0688543
-0.0552187
--0.0832505
-0.34774
-0.106395
-0.146601
-0.20002
-0.467343
-0.188282
--0.0927291
-0.240973
--0.255331
-0.0515338
--0.182741
-0.276599
-0.168095
-0
-0.175865
--0.20791
-0
--0.0852914
--0.0722279
-0.199702
--0.171932
--0.0376647
-0.19045
-0.468449
-0.249442
--0.0897418
-0.344208
--0.279005
-0
-0.0177255
-0.433579
-0.33378
-0.189571
-0.470888
-0.623983
-0.199305
-0.45781
-0.0176698
-0.56607
--0.0931295
--0.0715187
--0.0712795
--0.253326
--0.388728
--0.0182741
-0.204478
-0.213651
-0.204191
--0.0184861
-0.225182
--0.12599
-0.0752846
-0
-0.197519
-0.56556
-0.0740891
--0.160038
-0.519597
-0.552465
-0.480096
--0.165536
-0.11351
-0.393865
-0.46099
-0.749922
-0.072497
-0.364279
-0.58103
-0.450299
--0.112024
-0.514417
-0.90533
-0.402064
--0.221075
-0.279568
-0.312898
-0.0702344
--0.290499
--0.105319
--0.256856
-0.711867
-0.396357
--0.159792
-0.695986
-0.905383
--0.260966
-0.21094
-0.644242
-0.509988
--0.377853
-0.255016
-0.127864
--0.0721525
-0.348084
-0.59938
-0.434526
--0.0722293
-0.266074
-0.535258
-0.297652
-0.189787
-0.473428
-0.0531939
-0.0186886
-0.683482
-0.895266
--0.431871
-0.308649
-0.0172593
--0.481197
-0.0725513
-0.368897
--0.0890568
-0.263501
--0.0917929
-0.293606
-0.0511573
--0.178847
-0.344258
--0.0743183
-0.0535969
-0.107307
-0.343176
--0.362224
-0.214175
-0.111975
-0.612006
-0.198579
--0.26584
--0.0351604
-0.106781
--0.177522
-0.271417
-0.281445
--0.209173
--0.213227
-0.697245
-0.862189
-0.0348132
-0.0504364
--0.0850575
-0.32203
-0.0718883
-0.0500725
-0.0533174
-0.131704
--0.0369146
--0.204682
--0.0373121
-0.153561
-0
-0.42231
-0.110392
-0.10348
--0.0364402
--0.167122
-0.24944
-0.300672
-0.542313
-0.0680813
-0.0173854
--0.477954
--0.160756
-0.251055
-0.24471
-0.161425
--0.265818
--0.0355005
-0.105496
--0.221056
-0.240253
-0.853737
-0.252952
-0.482614
-0.294776
--0.154188
-0.810849
-0.516438
-0.0179008
-0.0539949
-0.294521
--0.0343122
-0.700537
-0.19391
--0.168199
-0.250539
--0.30014
-0.547225
-0.64061
--0.156568
-0.570718
-0.682014
-0.124624
-0.0200412
-0.709515
--0.0364458
-0.105624
-0.156965
-0.253388
--0.242607
-0.49952
-0.677706
-0.447621
-0.547358
-0.0539941
-0.161019
-0.0528142
-0.0170607
-0.106393
-0.0716991
--0.205441
-0.550304
-0.483471
-0.656809
-0.31522
-0.0163827
-0.537576
-0.76287
--0.124659
-0.0185046
-1.02486
--0.436878
-0.292577
-0.316056
-0.446167
-0.725481
-0.490509
--0.16634
-0.253129
-0.482838
-0.562316
-0.405831
-0.477755
-0.476503
-0.0181037
--0.0717676
-0.421871
-0.206837
-0.0534344
-0.191407
-0.0175163
--0.0722286
-0.283805
-0.408062
-0.10339
-0.0168016
-0.0173629
--0.0350078
-0.565108
-0.192172
-0.104195
-0.273409
--0.174291
-0.106082
-0.0172484
-0.016783
-0.0164651
-0.271136
--0.0355487
--0.253108
--0.0335261
-0.0664841
-0.141288
--0.119735
-0.0524521
-0.518685
--0.0641337
-0.300539
-0.105082
-0.311027
-0.210623
-0.305001
-0.111626
-0.339827
-0.0179894
-0.0532392
-0.0522399
-0.0584385
-0.156784
-0.509792
-0.204026
--0.0370365
-0
-0.30344
--0.0361672
-0.0558323
-0.0179821
-0.112129
--0.0358735
-0.16442
-0.322597
-0.0596234
--0.357892
-0.0179383
-0.0174403
-0.259992
--0.036038
--0.0391267
-0.261292
-0.372306
--0.0756177
-0.204245
-0.409275
-0.0180812
-0.163384
--0.0749276
-0.252727
-0.268675
-0.0174956
--0.0717472
-0.688457
-0.205113
-0.419618
--0.0199243
-0.315227
-0.291087
-0.0173888
-0.46783
--0.128111
-0.212272
-0.0712727
-0.0557198
-0.0570796
-0.0182888
-1.19204
-0
-1.16851
-0.262345
-0.704538
-0.816966
--0.0713608
-0.371967
-0.221618
-1.34945
-0.590179
--0.357917
--0.0764277
-0.323985
-0.0172154
-0.0394084
--0.245683
-0.092285
-0.318378
-0.935184
--0.427027
-0.206105
--0.129154
-0.469267
-0.407078
-0.409427
-0.232426
--0.0398558
-0.489559
--0.457782
-0.130743
-0.361666
-0.0182519
-0.257448
-0.24685
--0.0744812
-0.0547786
--0.134833
-0.453472
-0.421543
-0.204989
-0.206071
-0.336626
-0.0568687
-0.454907
-0.205983
--0.180791
-0.0596213
-0.105766
-0.111914
-0.57441
-0.292492
-0.437147
-0.203223
-0.0173341
-0.338432
-0.416864
--0.182317
--0.17504
-0.0193616
-0.106642
--0.0194419
-0.0527889
-0.0368542
-0
--0.0904727
-0.157204
-0.438216
-0.387778
-0.520565
--0.115189
-0.0715795
-0.345778
-0.1106
-0.301019
-0.27471
-0
-0.324024
-0.31944
--0.0347828
-0.462079
-0.596007
-0.0559797
-0.106552
--0.21715
--0.175667
-0.301808
-0.152657
--0.128875
--0.0907926
--0.189919
-0.234767
--0.188795
-0.343184
--0.140613
-0.133384
-0.212103
--0.308302
--0.227986
--0.169405
--0.0386368
-0.111517
-0.29745
-0.316709
-0.345526
-0.254752
-0.056652
-0.252189
--0.250331
--0.0371549
-0.662967
--0.0378517
-0.256384
-0.034418
-0.973929
-0
-0.62863
-0.0742082
-0.62663
-0.169543
-0.324411
--0.321796
--0.252716
-0.588321
-0
-0.407613
-0.228547
-0.280633
-0.773892
-0.278694
-0.31297
-0.171636
-0.710539
-0.638242
-0.297968
-1.02521
-0.329598
-1.04174
--0.0189878
-0.543809
-1.13394
-0.484711
--0.0191939
-0.240957
-0.774759
-0.693792
-0.608865
-0.342615
-0.231152
-0.109851
-0.0180997
-0.542976
--0.131625
-1.0252
-0.361583
--0.178306
-0.798574
-0.454359
-0.0183786
-0.453317
-0.763244
--0.039521
-0.0698744
-0.263908
-0.139741
-1.07925
-0.144767
-0.34996
-0.0555016
-0.607934
-0.394888
--0.0727461
-0.434939
--0.0369066
-0.247992
--0.0793793
-0.196866
-0.162682
-0.340532
-0.417047
-0.150986
-0.206912
--0.0373631
-0.475642
-0.306246
-0.169599
-0
-0.14924
-0.16653
--0.486958
-0.0551056
-0.103791
--0.0724296
-0.275632
-0.287549
--0.0686937
-0.142564
-0.0174429
--0.174392
-0.187505
-0.101565
-0.0530197
-0.0667331
--0.194768
--0.171452
-0.13783
--0.071629
--0.270534
--0.067592
-0.224549
-0.154947
--0.125493
--0.169792
--0.347477
-0.367547
-0.0546264
-0.235606
--0.162147
-0.102836
-0.295786
-0.0690907
--0.0357941
--0.120797
-0.30065
-0.370887
-0.104537
-0.15773
-0.271673
-0.250446
-0.412303
-0.157038
-0.189097
-0.799082
-0.421996
-0.68141
-0.309467
--0.153751
-0.606728
-0.256464
-0.109686
-0.483862
-0.506908
-0.40604
-0.358349
-0.618986
-0.522541
-0.213557
-0.0181843
--0.598391
-0.344239
--0.128789
-0.835366
-0.209549
--0.267055
-0.452851
-0.824882
-0.559454
-0.570816
--0.112131
-0.631271
-0.106652
--0.0190162
--0.0897115
-0.622373
-0.617802
-0.231508
-0.35819
-0.435046
--0.197161
-1.28686
-0.749599
-0.189657
-1.2187
--0.0763507
--0.182296
--0.481138
-0.305189
-0.866705
-0.658972
-0.616303
-0.356142
-0.845256
-0.0172345
-0.0543134
-0.465697
-0.761808
-0.157554
-0.0178044
-0.301966
-0.314844
-0.443877
--0.227804
-0.163299
-0.354672
--0.164371
-0.0191275
-0.410281
-0.114582
-0.107257
-0.0552375
--0.199332
--0.145137
-0.280145
-0.265681
-0.189669
-0.445767
-0.399448
-0.0168235
-0
-0.0542871
--0.331125
-0.0181115
-0.103727
-0.871175
-0.104653
-0.121516
-0.104035
-0.527572
-0.0730285
--0.205741
--0.0157639
-0.335177
-0.285948
-0.337769
-0.107042
--0.124054
-0.049979
-0.106719
-0.0181835
-0.276477
-0.311357
-0.274135
-0.351404
-0.305256
-0.203286
-0.0982761
-0.144126
-0.281489
--0.0361235
--0.0881534
-0.347748
--0.0884049
-0.0537204
-0.428754
-0.106089
-0.33123
-0.298458
-0.25813
-0.294055
-0.242013
--0.0374522
-0.264022
--0.342924
-0.255942
--0.191608
-0.104855
-0.209532
-0.0759789
-0.0523711
--0.0162049
-0.054056
-0.0171013
--0.0873252
--0.123263
-0.174358
-0.638285
-0.858195
-0.0177181
-0.34433
-0.370139
-0.940243
-0.127685
-0.587234
-0.195131
-0.128505
-0.592953
--0.0765436
-0.344468
-0.297393
-0.355429
-0.399006
-0.110427
-0.414646
-0.242099
-0.713778
-0.183862
-0.902352
-0.684615
-0.638269
-0.0173408
--0.251362
-0.969525
-0.222457
-0.75839
-0.577847
--0.112202
-0.390541
-0.957402
-0.521633
-0.428878
--0.0186271
-0.616271
--0.0548482
--0.0900823
-0.945704
-0.485275
-0.30942
-0.643715
-0.531856
-0.80294
-0.26449
-0.487495
-1.17108
-0.0187353
--0.0925949
-0.220864
-0.21669
-0.903931
-0.936219
-0.254646
-0.422847
-0.151976
-0.492172
-0.479822
-0.409533
-0
-0.771306
--0.0520028
-0.116051
-0.576076
--0.128202
-0.347461
--0.129893
--0.209893
--0.0367802
-0.189065
-0.142524
--0.0360845
-0.0508686
-0.349491
-0.0562782
-0.108201
-0.297271
-0.734938
-0.578012
-0.247963
-0.289697
-0.0508902
-0.198488
--0.34685
--0.0742642
--0.0677946
-0
-0.0505359
--0.182312
-0.543544
-0.0511102
-0.216874
--0.102826
--0.0356206
--0.203807
--0.259005
-0.19307
-0.100682
-0.016914
-0.146363
-0.0169638
--0.08856
-0
-0.0530123
--0.156089
-0.375132
-0.431769
-0.212824
-0.0504587
-0.123486
-0.330377
-0.144212
-0.282894
--0.0365382
--0.269652
--0.123527
-0.559456
--0.349421
-0.247673
-0.017355
--0.159794
-0.134425
--0.0696554
-0.703138
-0.0529519
--0.0361213
-0.304088
-0.346758
-0.358338
-0.784188
--0.0696342
-0.474546
-0.0751849
-0.733409
--0.0696401
-0.663168
-0.0518761
-0.108085
-0.401721
-0.471486
-0.182205
-0.36098
-0.299146
-0.876377
-0.74195
-0.537057
-0.392466
-0.490606
-0.835692
-0.846112
-0.632433
-0.864389
-0.367006
-0.402939
-1.84549
-0.227777
-0.568458
-0.830253
-1.006
-0.325497
--0.110214
-0.73441
-0.814459
-0.568344
--0.188164
-0.604977
-0.767317
-0.614543
-0.888719
--0.0533986
-0.662736
-0.377418
-1.41602
-0.991375
-0.370607
-0.419168
-0.237097
-0.526238
-0.0173172
-0.515145
-0.748061
-0.54418
--0.0178953
--0.113308
-1.12659
--0.1199
-0.460581
-0.206005
--0.166148
-0.175027
--0.325345
-0.475789
-0.412654
-0.446503
-0.250923
-0.124722
--0.0719604
-0.24181
--0.0186822
-0.185029
--0.0178421
--0.164728
-0.408347
-0.352583
-0.251121
-0.330121
-0.456171
--0.126019
-0.297105
--0.177021
-0.617802
-0.542289
--0.106121
-0.593089
--0.178326
-0.192838
-0.118559
--0.209884
-0.0740784
--0.215375
-0.145954
-0.48093
-0.514967
-0.138418
--0.239728
-0.147543
-0.111825
--0.282017
-0.476403
-0.498565
-0
-0.257562
--0.129386
--0.275651
-0.0534801
-0.26027
--0.110796
-0.196888
-0.449209
-0.141568
--0.228302
-0.0572242
--0.21461
-0.108512
--0.036287
-0.2949
-0.205498
-0.11435
--0.0373942
--0.0384947
-0.444509
-0.256098
--0.0946752
-0.0540691
-0.488229
-0.0754702
-0.25148
-0.737271
-0.88097
-0.257043
-0.615569
--0.214791
-0.439413
-0.599867
-0.159038
-0.0735819
-0.136233
-0.802016
-0.629674
-0.714466
-0.0344322
-0.221192
-0.66726
-0.648941
-0.923888
-0.256967
-0.858059
-1.352
-0.302258
-1.04821
-0.264535
-0.442954
-1.24716
-0.386916
-0.72598
-1.94655
-1.10994
-0.843991
-0.803899
-0.414793
--0.244099
-0.988538
-0.759342
-0.633393
--0.107999
-0.832395
--0.249872
--0.0568727
-0.822973
-0.651098
--0.0556262
-0.677167
-0.278815
-0.212295
-0.177213
-0.187341
-0.414022
-0.199034
--0.133504
--0.208448
-0.199643
-0.345133
-0.0181901
-0.290422
-0.101062
-0.0174147
-0.191044
-0.260318
--0.148291
-0.0552991
-0.053555
--0.500603
-0.438798
-0.208268
-0.275796
-0.340087
-0.339416
-0.251892
-0.180942
-0
-0.110375
--0.0718083
-0.270325
-0.0719882
-0.672488
-0.150098
-0.433412
--0.336789
-0.19157
-0.143674
-0.103453
-0.331059
-0.497186
-0.0171489
--0.174297
--0.0681343
-0.100446
--0.179766
--0.122707
--0.0351191
-0.42442
-0.575723
-0.0170433
-0.422002
-0.100766
-0.21049
--0.265843
--0.0698967
-0.486346
--0.179133
--0.266224
--0.0739129
--0.174531
--0.225211
--0.167341
-0.140618
--0.105607
-0.31196
-0.158002
--0.272525
-0.105155
--0.0900513
-0.24716
-0.143071
-0.434364
--0.0354876
-0.615683
-0.455709
-0.103549
-0.64827
-0.0927024
-0.0545198
-0.468913
--0.0580868
--0.0772899
-0.551034
-0.213198
-0.0738307
-0.441767
-0.529438
--0.0365061
-0.29711
-0.215048
-0.52784
-0.202807
-0.0752554
-0.694288
--0.372659
-0.639758
-0.114459
-1.34618
-0.13219
-0.507289
--0.0196375
-0.409115
-0.695714
-0.613252
-0.0348252
-0.937199
-1.66177
-0.67174
-0.680878
-0.326221
-1.04461
-1.56488
--0.142117
-0.253867
-0.712096
-1.58083
-0.733655
-1.19662
-0.517105
-0.373381
-0.957754
-0.331312
-0.58649
-0.742578
-0.261409
-0.87369
-0.211872
-0.420286
-0.424628
-0.131017
-0.134955
-0.617281
-0.093033
-0.725946
-0.303679
-0.780708
--0.0211188
-0.97909
--0.0172136
--0.190432
--0.131114
--0.289485
-0.221389
-0.0181987
-0.076111
--0.035647
-0.213191
-0.479884
-0.35574
-0.345462
--0.212221
-0.672287
-0.0178124
-0.204225
-0.306821
-0.424743
-0.343388
--0.0180946
--0.209623
-0.465379
--0.068489
-0.670311
-0.249792
--0.44424
--0.45479
--0.089413
-0.0388517
-0.146429
-0.0515548
-0.466419
-0.238691
--0.103976
--0.0335962
-0.0525432
--0.246922
--0.122646
--0.0663202
-0
--0.15109
--0.0190038
--0.123265
-0.133864
-0.290699
-0.0721069
--0.124457
--0.070337
--0.071459
-0.473049
-0.0746588
--0.199779
-0.339042
--0.258646
-0.0170486
-0.531193
-0.195159
-0.0529686
-0.0174284
-0.130929
-0.414094
-0.359513
-0.141193
-0.544352
--0.0376808
--0.168183
-0.392193
-0.245573
--0.0358756
--0.0356122
-0.707236
-0.427983
-0.179174
-0.24926
-0.0543877
-0.737083
-0.0732743
-0.487879
-0.63346
-0.644293
--0.194162
-0.288946
-0.0949037
-0.657554
-0.707754
-0.178453
-0.225737
-0.376925
-0.780439
-0.402404
-0.84883
-1.19392
-0.0882456
-1.00693
-0.564818
-0.139593
-0.896912
-0.871108
-0.743941
-0.441075
-1.36982
-1.22265
-1.04886
-0.692921
-1.64719
-0.199952
-0.84395
-0.56911
-0.919503
-0.78976
-0.192013
-0.760212
-0.789246
-0.312992
-0.911449
-0.473025
--0.0361319
-0.751132
-0.202022
-0.557474
--0.0188654
-0.690817
-0.356256
--0.0733721
-0.727327
-0.466088
-0.109655
-0.711964
--0.126412
-0.163038
-0.35975
--0.110459
-0.64615
-0.0541555
-0.112917
-0.292237
-0.329001
-0.222091
--0.174608
-0.107278
-0.139585
--0.215068
-0
-0.240139
-0.396033
--0.436221
-0.288505
-0.126025
--0.0337163
-0.245262
--0.172481
-0.0164544
-0.287541
-0.197371
-0
-0.103329
--0.157921
-0.19372
-0.18698
--0.0331577
-0.0998621
--0.167607
-0.245782
--0.0155442
-0.0522192
-0.46709
--0.0353407
-0.336214
-0.293594
-0.142531
--0.171644
-0.327576
-0.207076
-0.4156
-0.112384
--0.189529
--0.0968785
--0.0671365
--0.659231
-0.378876
-0.348472
--0.543104
-0.173361
-0.162442
-0.170054
-0.452788
-0.55863
-0.102537
-0
-0.0544288
-0.45969
-0.23612
-0.307298
-0.339942
-0.134719
-0.217149
--0.129383
-0.247448
-0.191031
-0.839217
-0.33161
--0.123118
--0.217334
-0.323133
-0.109056
-0.918444
-0.263117
-0.652928
-0.693108
-0.592864
-0.706027
-0.035853
-1.28858
-0.314162
-0.276867
--0.107538
-1.31115
-2.65181
-1.23138
-1.60907
-0.939378
-0.28987
-0.821646
-1.01117
-0.499972
-1.08122
-2.14292
-1.62555
-1.44902
-1.91818
-1.12672
-0.669243
-0.96233
-1.59094
-0.205015
-1.55908
-0.523631
-0.365512
-0.323453
-0.801281
-1.05257
-0.795025
-1.26168
-0.2252
--0.503718
-0.928147
-0.16694
-0.925715
-0.170904
-0.47534
-0.670447
-0.178244
-0.472462
--0.0189531
--0.0202836
-0.198243
-0.489964
-0.186879
--0.134911
--0.0194177
-0.335157
--0.13135
-0.163092
--0.382429
-0.362034
--0.202097
--0.155843
-0.359516
-0.821526
-0.363796
-0.416064
-0.246968
-0.348098
-0.573968
-0.253392
--0.0156856
-0.311015
-0.162128
-0.482768
-0.55969
-0.139546
-0.0170477
--0.0897686
--0.0880925
-0.187575
--0.17779
-0.103484
--0.0329473
-0.0531281
--0.125171
-0
-0.545371
-0.0174018
-0.111227
-0.0500133
-0.113662
-0.105442
--0.303364
-0.0531841
--0.128699
-0.0178764
--0.0947707
-0.35754
-0.10818
--0.283047
-0.280125
-0.107738
-0.108703
--0.0897438
-0.205061
--0.357641
-0.171638
-0.202046
-0.308817
--0.0738164
--0.073775
-0.750433
-0.166915
-0.342698
-0.404361
-0.428098
-0.126817
--0.0156934
--0.073463
-0.182076
-0.219052
-0.824309
-0.603857
-0.49888
-0.664475
-0.962637
-0.374082
-0.97672
--0.106729
-0.768617
-0.777742
-0.817214
-0.285177
-0.942292
-0.0730644
-1.33504
-0.936787
--0.0350634
-1.2302
-0.574612
-0.524746
-0.500377
-0.776914
-0.89702
-1.81895
-1.67479
-0.860123
-1.73979
-1.19441
-1.20904
-1.0883
-0.536018
-2.46073
-1.29428
-0.545044
-0.776724
-1.47524
-1.27627
-0.86887
-1.31283
-0.370319
-1.19054
-1.0746
-1.73353
-0.308869
-0.199194
-0.223658
-0.094519
-0.419328
-0.965376
--0.0190165
-1.08318
-0.113435
-0.258815
-0.254004
-0.275102
-0.48507
--0.0783445
-0.407632
-0.740755
-0.195042
-0.732359
-0.199912
-0.0524429
-0.109183
-0.559747
-0.103908
-0.414048
-0.809066
-0.0206657
-0.258122
-0.0178275
--0.0882959
--0.271758
--0.148337
-1.11265
-0.279983
-0.141558
-0.308807
-0.141114
-0.386185
-0.213924
-0.154709
--0.167968
-0.410266
--0.0356317
-0.173511
-0.100901
-0.323171
-0.0509982
-0.126433
-0.26785
-0.150628
-0.539737
--0.365078
-0.0503456
-0.0426041
-0.0507095
-0.0538352
--0.177046
-0.103366
-0.114195
--0.0358953
--0.089491
--0.0849643
--0.0964006
-0.253428
-0.0567924
-0.389429
-0.153079
-0.476444
--0.163059
-0.150822
--0.071602
--0.179525
-0.401049
-0.345922
--0.221912
-0.444141
-0.0179503
-0.266323
-0.0758207
-0.303357
--0.0385714
--0.21391
--0.0554427
-0.162039
-0.304231
--0.129442
-0.164227
-0.401734
--0.354806
-0.654457
-1.15727
-0.523586
-0.66914
-0.0350395
-0.370886
-0.687579
-0.83308
-0.452812
-0.740979
-0.965934
-1.70579
-1.72772
-0.207258
-1.43853
-0.355252
-0.286835
-1.25773
-0.953127
-0.758738
-1.62088
-1.61125
-1.16592
-0.678394
-1.44443
-0.780767
-1.56781
-1.14034
-1.89483
-0.802208
-2.14666
-1.25547
-2.07143
-1.8083
-1.12494
-0.42216
-0.773767
-0.754147
-0.551305
-1.30998
-0.326252
-0.601959
-0.554281
-0.58579
-0.942977
-0.367062
-0.222678
-0.419947
-0.214532
-0.413105
-0.537141
-0.150908
-0.799701
-0.367455
-0.491394
-0.79315
-0.238402
-0.377515
-0.0749481
-0.560289
-1.07202
-0.169052
-0.413312
-0.465241
-0.197135
-0.018071
--0.185118
--0.0362579
-0.263987
-0.289435
-0.333212
-0.504042
-0.196895
-0.304773
--0.0180585
--0.0526031
-0.466863
--0.174749
--0.0726822
-0.699317
-0.016822
-0.109353
-0.330442
-0.158029
-0.151231
-0.434712
-0.0945216
-0.199392
-0.0165852
-0.108795
-0.0536591
-0.341156
-0.0556563
--0.0833861
--0.0385234
-0.0172059
--0.0362555
-0.0206867
--0.112262
-0.167705
--0.179907
--0.0717702
-0.487036
-0.200538
-0.352209
-0.111588
-0.346146
-0.125401
-0.0559507
-0.287687
-0.126961
-0.250646
-0.197487
-0.186787
-0.0546642
-0.62178
-0.108
-0.428791
--0.226603
--0.0378969
-0.779469
-0.299014
-0.161981
-0.348543
-0.315902
-0.16525
-0.520326
--0.14993
-0.705551
-0.161449
--0.223482
-0.371068
-0.90101
-0.406489
-0.0356319
-1.1177
-1.24611
-1.17514
-0.755827
-0.171385
-0.857075
-0.755152
-1.45328
-1.03632
-0.921284
-0.628193
-0.465495
-1.61072
-1.21113
-1.05899
-1.70664
-1.95194
-0.38163
-3.06732
-2.8135
-1.8152
-1.66294
-1.09859
-0.586232
-1.75872
-2.35313
-0.805787
-0.770532
-1.73484
-2.05645
-1.65945
-0.444548
-1.41715
-0.433764
-0.453301
-1.41461
-0.0532502
-0.826248
-1.51641
-1.17756
-0.017229
-1.93257
--0.0369727
-0.900384
-0.818823
-0.806275
-0.526017
-0.388281
-0.318764
--0.301227
-0.278512
-0.30723
--0.128007
-0.105548
-0.793763
-0.0170893
-0.135945
-0.216466
-0.156261
-0.345825
-0.0706591
--0.0165737
-0.754085
-0.194814
--0.0723063
-0.102986
-0.578609
-0.198305
-0.189102
-0.110099
-0.325575
--0.036541
-0.191128
-0.207422
-0.0169361
-0.284721
-0.154684
-0.54476
-0.185713
-0.277134
-0.430056
-0.267291
--0.0852148
--0.0831418
-0.15681
-0.096083
-0.375273
--0.1544
--0.0709552
--0.207319
-0.493029
-0.192079
-0
-0.190401
-0.331911
-0.0161513
-0.0179828
-0.0158042
--0.0958623
-0.339128
-0.0748508
-0.0535619
-0.0171979
-0.102478
-0.445406
-0.0166235
--0.218216
--0.0859231
-0.251799
-0.208836
-0.106908
-0.0515208
-0.161943
-0.424721
-0.316719
-0.865671
-0.0176464
-0.269145
-0.107832
-0.635989
-0.397335
-0.152899
-0.336348
-0.871847
-0.390473
--0.424622
--0.0191254
-1.21724
-0.961816
-0.516828
-1.60801
-0.202205
-0.271045
-1.92117
-0.613938
-1.37133
-0.724179
-0.956752
-1.13375
-2.26499
-0.970506
-1.12463
-2.43346
-1.80229
-1.80475
-2.43062
-2.01099
-1.55599
-0.618667
-1.15951
-0.805895
-3.10836
-2.77854
-2.04576
-1.22898
-2.10368
-1.78189
-1.92773
-1.24296
-1.85868
-1.55717
-2.21114
-1.54828
--0.0906537
-0.641803
-0.710446
-0.793949
-0.502415
-0.130759
-0.850017
-0.326277
-1.16011
-0.127191
-0.343474
-1.14925
-0.340083
-0.348484
--0.085012
-0.0181834
-0.495573
-0.368238
-0.285563
-0.64764
-0.477247
-0.0569861
--0.175241
-0.0175639
-0.22082
-0.301528
--0.0730909
--0.0919557
--0.0672554
--0.125351
-0.527365
-0.477135
-0.412796
--0.091321
-0.196475
-0.194607
-0.381931
-0.25692
--0.170112
-0.287063
-0.102727
-0.100323
-0.45574
-0.598156
-0
-0.153566
-0.0200644
-0.198164
-0.201678
-0
--0.128576
--0.267253
-0.208607
--0.107512
-0.47939
-0.314451
-0.168181
-0.146136
-0.354095
-0.0554996
-0.0567287
--0.0163437
-0.276449
-0
-0.310354
-0.278163
-0.142236
-0.627702
--0.0734033
-0.171888
-0.16347
-0.0179054
--0.071626
--0.0367503
-0.296926
--0.0185355
--0.272739
--0.0781048
-0.540957
-0.300152
-0.405363
-0.550303
-0.223324
--0.0370981
--0.456845
--0.0375359
-0.972728
-0.20975
--0.221883
-0.234109
-0.708253
-0.713157
--0.054786
-0.134462
--0.315221
-0.131111
-0.886663
-0.473201
-1.16033
-0.680863
-0.883374
-2.48044
-0.764006
-1.66017
-1.92143
-2.43168
-2.83441
-1.25198
-3.23395
-1.24752
-1.05857
-4.7475
-3.59454
-3.69792
-3.1576
-1.97097
-2.44215
-2.40659
-3.77894
-1.81929
-2.29084
-2.58963
-1.5103
-1.73583
-2.57198
-0.592793
-1.42547
-2.35793
-0.4059
-0.898499
-0.383609
-0.543816
-0.529797
-0.493611
-0.427344
-0.649068
-0.174763
-0.438372
-0.281879
-1.00252
-0.945896
-0.136021
-0.50598
-0.600935
-0.453434
-0.37703
--0.128101
-0.21277
-0.189274
-0.165654
-0.238328
-0.297947
-0.195139
-0.251876
--0.0672342
-0.453199
-0.154068
--0.0360289
--0.218284
-0.248918
-0.238025
-0.46952
-0.194591
-0.101876
-0.568329
-0.103213
-0.0998497
-0.209499
-0.346962
-0.278955
--0.0347506
-0.145693
-0.146221
-0.352947
-0.138291
--0.0926901
--0.104696
-0.343799
-0.0521255
-0.0172401
--0.0352993
-0.204471
-0.421088
--0.0965303
-0.284879
--0.0382547
--0.130549
--0.185139
-0.207848
-0.14806
--0.0130034
-0.571217
-0.292057
--0.259982
--0.0745345
--0.127398
-0.0563572
-0.774805
--0.310702
-0.411585
--0.324844
-1.16182
-0.149991
-0.256757
-0.766477
--0.427463
-1.0521
--0.037075
-0.388937
-0.076583
-0.145856
--0.110265
-0.055531
-0.357344
-0.0731544
-0.61972
-1.02633
-0.116208
-0.415142
-0.234383
-1.21571
-1.61051
-0.7002
-0.720404
-0.839106
-1.19982
-0.927708
-0.837607
-1.4025
-1.32207
-2.96861
-1.30924
-2.62479
-1.8571
-3.35633
-3.08747
-2.51899
-3.7237
-1.9977
-3.42887
-2.89692
-2.8293
-2.21174
-3.65969
-3.14342
-3.08446
-3.34865
-2.95716
-2.10387
-3.04232
-2.31693
-0.796571
-2.73713
-1.6737
-1.09388
-2.23532
-0.66004
-1.01293
-0.879902
-0.592204
-0.862038
-0.457919
-1.4567
-1.1154
-0.850003
-0.0179448
--0.0191472
-0.176246
-0.537694
-0.0190799
-0.351015
-0.364505
-0.110642
-0.27298
--0.0755405
-0.163813
-0.0717892
-0.268236
-0.409484
--0.185057
-0.107256
-0.660508
-0.224697
-0.509821
-0.48663
--0.218793
-0.0183735
-0.131132
-0.295794
--0.125769
--0.0760435
-0.145568
-0.165735
-0.591325
--0.26811
-0.347434
--0.176174
-0.495918
-0.163886
-0.212189
-0.0485237
-0.282665
-0.051037
--0.116307
-0.0541699
-0.0489149
--0.0692556
--0.0330711
-0.146411
--0.152115
--0.122185
-0.0518613
--0.0673756
--0.125286
-0.19825
-0.195649
-0.277152
-0.0173193
-0.369999
-0.698353
-0.157834
-0.465714
--0.216658
-0.1336
-0.566844
--0.0362464
-0.0705362
--0.0370129
-0.389754
--0.215866
-0.308155
-0.249708
--0.12434
--0.130071
-0.106862
-0.258197
-0.703478
-0.310333
-1.04547
--0.0715841
-0.454414
-0.646116
-0.756064
-0.396631
-0.614638
-0.554074
-0.699146
-0.345686
-0.47869
-1.11143
-1.20114
--0.293268
-1.93434
-1.038
-1.81234
-1.68649
-0.9604
-1.90345
-1.60805
-1.06144
-2.82994
-3.71082
-3.23852
-3.29489
-5.93147
-2.59719
-4.12152
-4.18799
-2.41116
-5.06563
-2.32611
-3.25063
-3.92622
-3.29378
-3.66078
-2.845
-3.60894
-3.60301
-1.69249
-1.10013
-1.54758
-1.38229
-2.31363
-3.31133
-1.26404
-1.98125
-0.332649
-0.47556
-0.96446
-1.20702
-1.1616
-1.00547
-0.447574
-0.404227
-0.430676
-0.494511
-0.105155
-1.24051
-0.57825
-0.41268
-0.209507
-0.381419
-0.335573
-0.204849
--0.190491
-0.544541
-0.275806
-0.471988
--0.0878293
--0.0194501
-0.340492
--0.252419
-0.559681
--0.0190881
-0.0703921
-0.0174477
-0.193498
--0.216375
-0.242224
-0.233114
-0.0171045
-0.0171962
-0.1904
-0.190282
-0.108589
-0.189221
--0.117484
--0.0160911
--0.122367
--0.17428
--0.168842
--0.268679
--0.017601
-0.528291
--0.156541
-0.425209
-0.568946
-0.0680051
-0.293243
-0.47838
-0.0494598
--0.0917791
--0.153339
-0.439818
-0.0690638
--0.0938482
--0.0341709
-0.299975
-0.555735
-0.110574
--0.315929
-0.252045
--0.207199
-0.303297
-0.583042
-0.204126
--0.363001
--0.0188586
--0.123439
--0.409588
-0.760975
-0.371463
-0.472948
-0.152034
-0.591146
-0.465453
-0.0543204
-0.25858
-0.267205
-0.412941
-0.107615
-0.494977
-0.540153
-0.357765
-0.368364
-0.112058
-1.05408
-1.08323
-0.774691
-0.217415
-1.0443
-1.66679
-1.18786
-1.51638
-1.98364
-2.0199
-1.18609
-3.08048
-2.56226
-6.99097
-3.93812
-3.5867
-4.68861
-4.9868
-4.55091
-4.7941
-7.44387
-3.62996
-4.26688
-4.82994
-4.12815
-6.33271
-4.40442
-4.37476
-3.04363
-4.48821
-2.77939
-3.37577
-2.54065
-2.00998
-0.94825
-1.51066
-1.39203
-1.84938
-0.664377
-0.812437
-0.0340165
-1.35951
-0.124909
--0.200589
-0.572107
-0.763629
-0.747491
-0.433949
-0.225557
-0.33033
-1.01197
-0.733673
-1.22498
-0.216146
-0.503621
-0.586195
-0.510316
-0.637338
-0.156719
-0.301255
-0.0714947
-0.127304
-0.0539613
-0.308705
--0.174467
-0.703314
--0.0364093
--0.130197
-0.547309
-0.337381
-0.489761
-0.164229
-0.544124
-0.195084
-0.0186971
-0.0534805
-0.760972
-0.326512
-0.201153
-0.275395
-0.483945
--0.0343577
-0.108016
-0.185073
--0.0888323
-0
-0.302415
-0.0979328
-0.225384
--0.198188
--0.0337583
--0.0351213
-0.194569
--0.177162
-0.300585
-0.215998
--0.218529
-0.883308
-0.192664
-0.0537668
--0.260619
-0.337867
-0.546913
-0.103828
-0.489681
-0.296572
--0.0357127
-0.20763
--0.106417
--0.0721551
-0.386245
-0.259394
-0.402816
-0.833835
-0.0535826
-0.364989
-0.160076
-1.00818
--0.0363828
-0.539329
-0.764678
-0.233578
-0.300288
-0.788908
-1.1794
-0.415709
-1.51623
-0.592833
-0.832847
-1.38713
-0.912294
-0.775897
-0.231932
-2.01354
-2.54231
-2.19579
-2.05278
-2.25446
-2.51635
-3.74713
-2.92328
-4.40788
-5.75222
-5.03908
-5.97828
-7.43392
-7.1223
-7.66107
-6.16621
-7.62549
-6.20417
-6.51249
-5.59795
-5.99446
-5.71299
-3.50667
-5.92201
-2.63982
-5.34911
-3.18118
-3.90763
-2.0628
-2.59326
-1.77034
-1.80539
-1.42995
-1.24762
-0.395856
-1.76539
-0.926118
-0.992622
-1.06545
-1.07876
-0.388902
-0.427803
-0.8943
-1.19983
--0.161386
-0.637769
-0.434903
--0.0727504
-0.75012
-0.128851
-1.04976
-0.697331
-0.421825
-0.0887134
-0.861732
-0.519826
-0.0710024
-0.158663
-0.250217
--0.122322
-0.213364
-0.836511
-0.0177729
-0.308135
--0.15718
--0.125149
-0.0714014
-0.0517964
-0.113426
--0.126533
--0.215327
-0.192425
--0.265999
--0.0689322
-0.0984825
--0.162802
--0.0680017
--0.111363
-0.792156
-0.0168338
-0.109015
-0.0498447
-0.0503199
--0.179889
-0.428282
-0.473834
-0.203306
-0.0501048
-0.11138
-0.0531812
--0.189435
-0.42841
-0.304992
-0.016852
-0.586904
-0.406428
--0.321142
-0.192391
--0.0366956
--0.0356638
-0.448257
-0.194509
-0.256262
-0.401227
-0.257681
-0.253034
-0.0182183
-0.0172024
-0.587087
-0.251666
-0.114198
-0.594178
-0.374573
-0.390743
-0.205198
-0.313548
-0.470246
-0.802202
-0.396327
-0.830992
-0.982906
-1.92792
-0.582004
-1.15202
-1.49342
-2.47506
-1.99572
-1.78192
-1.59484
-2.45464
-1.48041
-3.25673
-2.94058
-2.75663
-3.70399
-3.04353
-4.65742
-7.24133
-8.81584
-6.31219
-10.5255
-7.09406
-10.6334
-9.49481
-11.0755
-7.92248
-8.82857
-8.85403
-7.23538
-7.35951
-8.77714
-7.14072
-2.98641
-6.12012
-3.31843
-4.28213
-2.12571
-2.38793
-2.35558
-0.534689
-1.44774
-1.18404
-1.02541
-2.16609
-0.847313
-1.14854
-1.40556
-0.566851
-0.333313
--0.419146
-1.23811
-0.940633
-0.537769
-0.794123
-0.254166
-0.833875
-0.610241
--0.1064
--0.0733692
-0.251033
-0.428734
-0.314173
--0.315791
-0.25168
-0.19281
-0.106734
--0.0735746
-0.0165172
--0.036827
-0.191684
-0.164969
--0.0720006
-0.148155
-0.0355085
-0.102759
-0.274717
-0.125813
--0.0835885
--0.0357822
-0.38053
--0.0187796
-0.140544
-0.28341
-0.0646426
-0.102358
-0.345117
-0.0558618
-0
--0.121672
-0.54083
-0.461533
-0.112385
-0.54763
-0.317513
-0.35351
-0.335154
-0.162584
-0.357754
-0.756571
-0.198634
--0.0749652
-0.0180644
--0.133588
-0.202227
-0.0557152
-0.296688
-0.10638
-0.269486
-0.710162
-0.450049
-0.0516824
-0.126375
--0.182837
-0.320091
-0.321415
-0.219876
-0.626093
-0.309015
--0.112293
-0.401895
--0.226988
--0.172601
-0.864396
-0.271138
-0.0738703
-0.619734
-0.555703
-0.252922
--0.0189194
-0.679543
-0.892378
-1.70541
-1.00578
-0.709688
-0.752812
-2.74783
-1.87663
-3.01246
-1.99801
-1.97971
-3.66553
-4.85141
-4.54891
-4.4309
-7.14856
-9.02021
-9.72848
-11.4781
-10.6307
-11.8339
-14.7783
-14.3227
-14.9173
-14.5267
-10.8836
-14.1066
-14.2987
-9.67959
-9.25508
-9.67775
-7.76785
-6.87136
-5.51969
-4.66695
-3.16622
-2.61507
-3.16932
-0.843581
-1.32189
-1.48126
-1.63469
-1.19657
-0.769912
-1.41104
-1.31487
-1.16385
-0.582191
-0.799055
-0.114198
-0.875957
-0.305691
--0.0189238
-0.313623
-0.347685
-0.341311
-1.11961
-0.368602
-0.97439
-0.767971
-0.390299
--0.0360801
--0.316135
-0.21504
-0.299278
-0.0376828
-0.291506
-0.442239
-0.0545845
--0.45196
--0.329416
-0.0183315
-0.0180658
-0.069967
-0.16356
-0.1933
-0.072144
--0.213299
--0.123977
-0.197152
-0.05226
-0.288439
-0.0986108
-0.493641
-0.0993347
--0.121938
-0.0500513
-0.510276
-0.245174
--0.175694
--0.0355528
-0.328691
-0.332468
--0.126248
--0.163981
-0.444887
-0.213661
-0.0539672
-0.182274
-0.0569537
-0.119763
-0.196084
--0.166073
--0.0880173
-0.265467
-0.329552
-0.0690311
-0.0174495
-0.0167115
--0.168974
-0.348481
-0.335865
-0.307235
-0.654294
--0.287585
--0.279582
-0.513296
-0.267101
-0.564634
-0.168991
-0.648243
-0.637508
-0.55296
-0.739468
-0.18187
-0.913414
-1.22599
-1.64598
-0.854333
-0.626253
-1.24064
-1.51379
-1.87453
-0.9572
-1.37372
-2.48049
-2.16455
-3.0389
-3.70996
-3.33661
-5.86879
-6.79741
-7.16878
-9.11224
-13.2758
-11.4371
-13.225
-14.7365
-14.7936
-17.4191
-18.4593
-19.0745
-16.926
-20.0385
-18.5518
-13.2249
-12.4899
-11.2511
-8.90312
-10.0924
-5.49743
-5.21076
-4.01326
-6.53204
-3.16187
-3.37753
-3.28158
-2.22183
-1.12238
-2.00552
-0.891229
-1.95961
-0.615243
-0.133886
-1.09018
-0.574464
-1.32978
-0.506618
-1.26163
-0.518715
-0.865711
-0.385852
--0.094652
--0.0754991
-0.262049
-0.158101
-0.56087
-0.119021
-0.121944
--0.071842
-0.143618
-0.107411
-0.308376
-0.498622
--0.0703792
-0.335314
-0.249997
--0.273355
-0.341562
-0.243151
-0.105816
--0.126609
--0.0361527
--0.129887
-0.240493
-0.0171731
-0.101164
-0.75026
-0.109026
--0.0361648
-0.0456069
-0.190851
--0.122934
-0.710792
-0.479736
-0.247578
-0.579349
-0.465964
-0.0563953
-0.416991
--0.0188001
--0.13228
-0.613883
-0.196916
-0.0376867
-0.0529897
-0
-0.11302
--0.525485
-0.0182775
--0.091341
--0.0185763
--0.0198605
-0.158091
-0.520109
-0.408967
-0.48778
-0.110718
-0.444505
-0.256122
-0.337619
-1.07418
-0.314692
-0.0377443
-0.589534
-0.223748
--0.273511
-0.0703394
-0.584634
-0.415098
-1.41825
-0.0359364
-0.799932
-0.58092
-0.218183
-0.974318
-0.659814
-0.24428
-1.14648
-0.873337
-0.672351
-2.03605
-2.19829
-3.81369
-2.92183
-3.31407
-3.65622
-7.78378
-6.32121
-8.76435
-11.164
-11.0988
-13.8481
-18.7361
-18.6947
-23.6278
-24.3781
-24.659
-33.2369
-31.728
-26.8545
-26.655
-27.0924
-21.77
-16.5606
-16.6461
-15.0815
-13.3521
-9.56307
-9.05598
-6.92991
-4.31033
-3.62245
-4.92781
-3.72216
-3.79989
-1.80776
-1.07414
-2.30424
-1.02617
-1.09018
-1.63222
-1.52014
-0.951035
--0.00143686
-0.220281
-1.0713
-1.48994
-0.583152
--0.0359272
-0.0723841
-0.0708743
-0.746911
-0.560345
--0.36619
--0.0758249
-0.151664
-0.310992
-0.283323
-0.334922
-0.428873
-0.157143
-0.641404
-0.197053
--0.173957
-0.595207
-0.0689121
-0.24242
-0.0171438
--0.12174
--0.0363849
--0.0882906
-0.325057
-0.247497
-0.115752
--0.0851441
-0.0510351
--0.173029
--0.0314114
--0.0651366
--0.254709
-0.0547579
--0.068979
-0.0173488
--0.30241
-0.104661
-0
-0.111
-0
--0.470449
-0.0535047
-0.0741372
-0.320512
-0.367029
--0.0196736
-0.32553
-0.592575
-0.228388
-0.161126
-0.195273
-0.338884
--0.220897
--0.212357
-0.298475
-0.124471
--0.0386891
--0.250964
-0.130004
--0.357249
--0.0390495
-0.186876
-0.37168
-0.399558
-0.176014
-1.20579
-0.224896
-0.132274
-0.0348087
-0.621654
-0.43157
-0.853351
-0.670048
--0.0183516
-0.288289
-1.61682
-0.804023
-1.66622
-1.62667
-2.17252
-1.93521
-3.37181
-3.27931
-2.62799
-5.99717
-4.092
-7.0955
-6.30106
-9.07032
-11.628
-17.401
-15.1575
-22.3171
-26.952
-31.4224
-36.8315
-38.1439
-43.4674
-39.7753
-41.002
-39.4018
-35.2858
-32.1694
-29.1312
-25.4045
-22.6485
-14.8544
-13.7846
-10.6581
-8.37893
-5.8728
-4.39763
-4.30527
-3.89875
-2.97676
-3.42874
-2.68121
-1.23372
-2.45969
-0.860746
-0.902117
-0.63982
-0.419978
-0.817305
-0.468947
-0.51749
-0.681533
-0.105861
-0.32726
-0.222196
-0.406817
--0.090818
-0.938073
--0.451104
-0.0792659
-0.178664
-0.72901
-0.641689
-0.198555
-0.134037
-0.605625
-0.329977
-0.722632
--0.617897
-0.657071
-0.104873
--0.458005
--0.126096
-0.438599
--0.0719207
-0.33335
-0.140135
--0.41053
-0.28842
-0.0532854
-0.179625
-0.329239
-0.224198
-0.533342
-0.276948
-0.143156
-0.142382
-0.0509387
-0.0391003
-0.375033
-0.341491
-0.3388
--0.0660417
-0.113527
-0.0512535
-0.324138
-0.292146
--0.09262
-0.347392
-0.0547656
-0.470971
--0.0370119
--0.0710607
-0.530872
--0.124767
--0.0357752
-0.735869
-0.14603
-0.252128
-0.597776
-0.283477
--0.125326
--0.215494
-0.108087
-0.732672
-0.568588
-0.605543
-0.840418
-0.127907
-0.289004
-0.441418
-1.14296
-0.745491
-0.760679
-1.11553
-1.26698
-0.484865
-1.07663
-0.138127
-1.64245
-1.23593
-1.41824
-1.52179
-2.74795
-2.09428
-3.97491
-3.51267
-4.98716
-7.31188
-6.38341
-13.6845
-11.845
-18.5652
-22.2558
-31.2651
-32.3828
-41.0251
-42.6791
-49.513
-54.1855
-54.8342
-58.0679
-62.6208
-54.7264
-48.4518
-48.0431
-39.1029
-30.1057
-27.3446
-20.701
-18.4759
-14.0386
-9.80178
-9.27778
-6.72013
-4.21356
-7.22751
-1.54796
-1.96304
-2.98661
-1.21645
-1.39505
-1.22537
-0.845075
-1.17082
-0.605853
-1.73313
-0.517793
-0.490685
-0.316132
-0.391142
-0.459587
-0.878729
-0.828462
-0.387384
-0.27145
-0.123849
-0.119206
--0.106187
-0.255987
-0.75705
-0.309618
-0.668777
-0.146421
--0.0665534
--0.0734884
-0.401138
--0.134369
-0.377475
-1.0051
-0.341495
-0.197857
--0.360076
-0.105203
-0.192378
-0.34737
-0.0172802
-0.19385
-1.00647
-0.203224
-0.424954
-0.623116
-0.0667844
-0.0522856
-0.0166042
--0.0347624
-0.14391
--0.256319
-0.685422
-0.681609
--0.416199
--0.0725748
-0.0161738
--0.324545
-0.0172433
--0.091727
--0.0699901
-0.112336
-0.51253
-0.211525
-0
-0.103624
-0.020901
-0.448275
-0.258135
-0.589873
-0.286835
-0.41497
-0.101174
--0.0743074
-0.726655
-0.544487
-0.289295
-0.383883
-0.214537
-0.570566
-0.211541
-0.263426
-0.578161
-0.379998
-0.340134
-0.676983
-0.633966
-0.657283
-0.767808
-0.07039
-0.44821
-0.448991
-1.2525
-1.22191
-2.68199
-3.01327
-3.82054
-3.47958
-3.35621
-3.88307
-7.6021
-10.3561
-11.6593
-15.0534
-22.9072
-25.2132
-36.1921
-42.0649
-56.3665
-63.3081
-72.2666
-85.4957
-85.4617
-80.1535
-89.9541
-81.4183
-71.2164
-64.0418
-49.2224
-40.5905
-34.802
-28.0792
-20.1988
-19.7378
-10.6176
-10.7172
-5.67498
-4.966
-2.19345
-4.32129
-3.70639
-3.37175
-2.11685
-1.7806
-1.47094
-0.993694
-1.10179
-1.11612
-1.11279
-0.761911
-0.829741
-1.14401
-0.209462
-0.213478
-0.626104
--0.111752
-0.374898
-0.214345
-0.392644
-0.470696
--0.437949
-0.501093
-0.256025
-0.0535353
-0.501926
--0.283118
-0.247336
-0.16519
-0.305899
-0.439893
-0.28738
-0.289836
-0.0170105
-0.268954
-0.131259
-0.568108
-0.668844
-0.343521
--0.217167
-0.276509
-0.416437
-0.108729
-0.171768
-0.505477
--0.29828
-0.533557
-0.281032
-0.445432
--0.0365001
--0.421116
-0.436482
-0.151846
-0.145058
-0.294543
-0.293751
-0.286702
-0.0708829
-0.145052
-0.722112
--0.488432
-0.63044
--0.17809
-0.197288
-0.156491
-0.216196
-0.146145
-0.20363
-0.198978
-0.117317
-0.103935
-0.317255
-0.437274
--0.0377502
-0.395079
-0.0693461
-0.560657
--0.159543
-0.670022
-0.513833
-0.0172968
-0.328179
-0.7931
-0.120859
-0.618037
-0.687139
-1.13597
-1.32729
-1.19798
-0.511772
-2.17105
-1.74324
-1.02476
-3.33939
-3.03781
-2.98143
-3.96246
-5.82926
-7.72285
-8.3764
-10.586
-13.9445
-22.3895
-30.5152
-37.2873
-45.8124
-58.8489
-71.1854
-88.434
-110.942
-114.37
-119.263
-121.86
-125.671
-115.593
-106.452
-94.2648
-74.8025
-62.3428
-44.6983
-34.3745
-27.9026
-23.3048
-17.6317
-9.18259
-8.56589
-7.02753
-4.04308
-4.41056
-2.85463
-3.32545
-1.9154
-1.81994
-2.65476
-1.80045
-1.5247
-0.918251
-0.480574
-2.36824
-0.270656
-0.681058
-0.0713162
-1.0071
-0.618075
--0.128903
-0.580996
--0.166903
-0.297724
-0.69889
--0.123728
-0.0532726
-0.363685
-0.517963
-0.896793
-0.0733411
-0.0173132
--0.277112
-0.341439
--0.35438
-0.105879
-0.0175868
-0.016878
--0.213517
--0.0882138
-0.0177447
-0.0205885
-0.224742
--0.0133747
-0.189704
-0.528273
-0.0533658
-0.195321
-0.45943
-0.125854
-0.422951
--0.0346707
-0.156941
-0.100621
-0.101063
-0.328272
-0.329052
-0.0687812
-0.151517
-0.153413
-0.145923
--0.0355252
-0.407193
-0.327982
-0.387335
-0.42136
-0.328077
-0.239798
-0.0533424
--0.126553
-0.107995
--0.0182763
-0.407212
--0.172071
-0.202967
-0.434531
--0.124014
-0.308547
--0.0187947
-0.424419
--0.0623468
-0.566195
-0.161218
-0.510587
-0.259919
-0.70684
-0.123971
-0.125796
--0.459655
-0.85633
-1.1697
-0.145032
-1.31658
-2.03361
-1.75492
-2.57307
-2.23607
-2.33317
-3.85697
-4.49903
-5.30587
-3.49365
-7.45978
-10.0563
-14.2037
-19.6439
-24.6499
-36.3691
-49.6675
-61.5409
-82.3838
-104.713
-125.705
-108.574
-77.2638
-53.3722
-54.5046
-62.2914
-95.0392
-124.146
-123.325
-108.816
-72.3151
-58.2831
-48.3018
-37.5351
-24.909
-16.7409
-15.7235
-9.53752
-8.9575
-4.92093
-4.63685
-3.8284
-1.42852
-2.86701
-1.95989
-2.98379
-0.87873
-2.86649
-0.38074
-1.18152
-0.821325
-0.524369
-0.973314
-0.979411
-0.136859
-0.0537476
-0.096758
-0.319464
-0.204329
-0.28267
-0.135492
-0.192958
-0.201862
-0.504098
-0.349097
-0.400504
--0.493706
-0.598617
-0.406861
-0.221282
-0.259628
--0.125499
-0.195426
-0.0527614
-0.423742
-0.0199696
-0.328662
-0.335718
--0.0715978
--0.0870616
--0.0846206
-0.0173802
-0.686522
-0.182164
--0.369931
-0.408333
-0.140304
--0.130173
-0.242848
-0.554584
--0.438376
-0.227798
--0.0353179
--0.0360852
--0.205054
-0.106672
-0.372625
-0.30979
--0.0921522
-0.0554169
-0.449551
-0.191414
-0.353469
-0.165834
--0.127027
--0.0766614
-0.34356
--0.0733645
--0.0370207
-0.527921
-0.371255
-0.431448
-0.892768
-0.422069
-0.424033
-0.345784
-0.0604388
-0.564124
--0.0362353
--0.687687
-0.542245
-0.40698
--0.266017
-0.842713
-0.858998
-0.650791
-0.272044
-0.845604
-1.09752
-1.87172
-1.71516
-1.28866
-3.07075
-2.51155
-1.79842
-2.98517
-3.98797
-5.77782
-8.66969
-10.1833
-15.2771
-22.9088
-36.5301
-38.6179
-52.5759
-77.1665
-110.065
-106.997
-50.881
-8.94304
-0.643552
--0.0908322
-0.151432
-0.217635
-2.76356
-24.2501
-88.0584
-126.316
-106.392
-73.5703
-54.1925
-47.0036
-29.1685
-18.8603
-17.0248
-13.7942
-8.36315
-6.53442
-6.86199
-3.78636
-2.8839
-2.02202
-1.81212
-2.44724
-0.805607
-1.67047
-0.746651
-0.700919
-1.36509
-0.747843
-0.703192
-0.290962
-0.420615
-0.677637
--0.0736844
-0.712994
-0.0181683
--0.036224
--0.129965
-0.248669
--0.019451
-0.461383
-0.336511
--0.163122
--0.196199
-0.454643
--0.307588
-0.153966
-0.0542602
-0.0195168
-0.261319
-0.253942
-0.330135
-0.488414
-0.108294
-0.495104
-0.197511
-0.253089
-0.0534762
-0.309854
-0.18997
--0.063887
-0.103164
-0.14015
--0.157254
-0.347076
--0.0679923
-0.288432
-0.277971
-0.0708685
-0.339537
-0.0522469
--0.354907
-0.400439
-0.401452
-0.105192
-0.339374
-0.0166755
--0.129005
--0.170151
--0.456339
-0.0529872
-0.0538359
-0.406655
-0.167254
--0.212186
-0.467266
--0.119904
--0.1672
-0.881872
-0.672277
--0.0695747
-0.0521976
-0.297471
-0.469162
-0.683122
-0.948533
--0.365571
-0.354376
-0.302696
-0.650401
-0.664103
-0.492452
--0.295701
-0.911782
-0.709823
-1.84364
-2.2094
-2.04663
-3.83683
-1.48495
-3.7586
-3.12062
-5.03785
-5.00575
-6.29252
-8.85068
-13.7549
-15.9891
-25.3296
-37.6115
-58.9613
-69.9077
-89.052
-94.1179
-20.8218
-0.856112
--0.160447
-0
-0.140963
-0.146911
-0.198069
-0.0211329
-0.14059
-3.87681
-59.9367
-119.511
-92.5841
-74.1467
-51.4637
-33.3852
-25.021
-15.8122
-11.6659
-11.1056
-6.28328
-3.19657
-3.96764
-3.83202
-2.66293
-2.78646
-2.47927
-2.80775
-2.55622
-1.74035
-0.413497
-1.53995
-1.24705
-0.389543
-0.488664
-0.337036
-0.661453
-0.417846
-0.63284
-0.691348
-0.068995
--0.202258
--0.106531
-0.470343
-0.113483
-0.646301
-0.515617
-0.172111
-0.16187
-0.337605
-0.593916
-0.222312
--0.0166058
-0.0181728
-0.634661
-0.0178866
--0.0367776
-0.107634
-0.0521608
-0.10566
-0.427897
-0.536012
-0.357102
--0.085565
-0.629632
-0.0480403
-0.0166739
--0.0849977
-0
--0.104592
-0.0549898
-0
-0.355571
-0.108762
-0.159074
-0.017612
-0.391053
--0.0364044
-0.0178399
-0.488707
--0.346829
-0.0753435
-0.342378
-0.258506
-0.52622
--0.0719488
--0.0719504
-0.201729
--0.269775
-0.404205
--0.124322
-0.255623
-0.891871
-0.340234
-0.972015
-0.360661
-0.360902
-0.183789
-0.106981
-0.165377
--0.234983
-0.585983
--0.0557124
-0.360156
-0.746702
-0.184644
--0.289505
-0.528698
-0.674876
-1.32982
-0.502848
-1.11119
-0.813212
-2.03354
-4.29155
-2.49829
-4.46399
-5.33103
-8.88864
-14.7739
-17.6145
-22.5769
-34.6103
-45.7756
-60.7473
-82.8161
-103.311
-22.5947
-0.406095
-0
-0.293643
-0.287867
-0
-0
-0.0521407
-0.0546082
-0
-0
-3.58127
-69.0903
-113.288
-88.5293
-62.7366
-44.86
-33.9379
-19.3004
-14.6167
-13.493
-7.31195
-4.32965
-6.53761
-2.17073
-3.45931
-0.908712
-2.72012
-0.701356
-0.485409
-0.865458
-1.32205
-0.387981
-0.581082
-0.467578
-0.387586
-0.696493
-0.188009
-0.697232
-0.26044
-0.406717
--0.0172948
-0.463935
-0.667234
-0.336068
--0.27301
-0.312126
--0.036765
-0.16062
-0.189995
-0.206161
-0.298383
-0.400217
-0.26881
-0.333933
-0.0712632
--0.175808
-0.45886
-0.356372
-0.0699012
-0.522966
-0.334749
--0.0338507
-0.4215
-0.10151
-0.0160248
-0.184727
-0.277248
--0.173077
--0.0696506
-0.316549
--0.0889787
-0.153047
-0.283651
--0.12517
--0.0712148
-0.804443
-0.470661
--0.280408
-0.490009
--0.279196
-0.529819
--0.237557
-0.0164554
--0.186146
-0.453744
-0.126778
-0
-0.222105
-0.708884
-0.817702
-0.42944
-0.110233
--0.0722925
--0.201946
-0.304431
-0.305697
-0.903122
-0.206539
-0.218342
-0.288834
-0.635679
-0.405648
-0.72168
--0.147482
-0.327501
-0.688453
-0.99485
--0.304329
-1.74818
-1.02902
-1.24246
-0.418776
-1.9452
-2.06527
-1.99088
-4.15998
-3.92528
-4.79849
-9.98809
-13.6061
-17.2928
-25.3216
-37.2367
-44.8365
-67.9681
-94.2849
-50.0362
-0.753071
-0
-0
--0.0915535
--0.100889
-0.1523
-0
--0.0953311
-0.144382
-0.117611
-0
-0.0554687
-13.9986
-97.9159
-97.9255
-66.1116
-45.5867
-31.0637
-33.1493
-15.4677
-13.8072
-6.4701
-6.79797
-4.23754
-5.04031
-2.40993
-3.32684
-2.88732
-1.91028
-0.992933
-1.92944
-1.29976
-0.736841
-1.27483
-0.914001
-0.115309
-0.742991
-0.566332
-0.793053
-0.479258
-0.351381
-0.413779
--0.164711
-0.429534
-0.709803
-0.1148
-0.385486
-0.118816
-0.152472
-0.785294
--0.0961053
-0.0547527
-0.570483
-0.108071
-0.161383
-0.249043
-0.446365
--0.110164
-0.0758414
--0.0724341
-0.288391
-0.0176152
--0.335905
--0.157503
-0.398107
--0.0332837
-0.181988
--0.119634
--0.0340298
-0.137956
-0.0991286
-0.187052
-0.148184
-0.68916
-0.264039
-0.0510993
-0.191959
--0.123965
--0.0352487
--0.0345355
-0.447016
-0.0852059
--0.036089
--0.117288
--0.105652
--0.168247
-0.234402
-0.380247
-0.378439
-0.829467
-0.228556
--0.204412
--0.304685
-0.229127
--0.195916
-0.286339
-0.105341
-0.304737
-0.0549912
--0.0693267
--0.0704923
-0.314139
-0.294852
-0.452716
-0.297277
-0.624364
-0.0352542
-0.673337
-1.18732
-0.664611
-0.598292
-2.59121
-2.2916
-2.17615
-1.76267
-4.53718
-4.30054
-5.33308
-7.89795
-9.32301
-10.8503
-13.2864
-26.1742
-37.8448
-52.6493
-75.5209
-90.5142
-18.8925
-0.283633
-0.148251
-0.140393
-0.0537586
-0
-0
-0
--0.0341989
--0.127425
-0.145384
-0.0527896
-0.144033
-0.824212
-65.8601
-107.407
-71.7511
-52.0732
-41.5081
-25.3234
-21.4897
-14.8095
-7.61446
-8.82004
-5.30809
-3.02554
-2.86101
-2.78139
-1.74242
-2.19964
-2.11888
-0.98333
-1.25033
-0.0906081
-0.643193
-0.666455
--0.287995
-0.720173
-0.125305
-0.590807
--0.0189223
-0.764892
-0.412404
-0.272002
-0.4171
--0.0163075
-0.0558523
-0.212353
-0.143597
--0.0355925
-1.29634
-0.192272
-0.069683
-0.354503
-0.0683675
-0.511889
-0.244918
-0.0170427
-0.185981
--0.0162038
-0.0163835
--0.0709735
-0.292522
--0.172701
-0.3831
--0.293286
--0.332889
-0.258702
-0.195121
-0.289083
-0.440394
-0.0871848
-0
-0.241755
-0.257124
-0.0168458
-0.448431
-0.44499
-0.0163607
-0.262583
-0.104324
-0.0180361
-0.0692298
-0.262105
-0.138711
-0.108201
-0.217495
--0.159093
-0.127229
--0.0357462
-0.0169819
-0.347627
-0.189092
-0.0180991
-0.239212
-1.06983
-0.233929
-0.183153
-0.572192
-0.210271
-0.724281
-0.0177739
-0.415354
-0.123575
-0.586827
--0.111742
-0.351526
-1.42391
-1.36088
-0.925314
-0.851184
-1.71103
-1.12582
-0.79933
-2.18332
-3.90411
-3.60403
-4.79603
-6.65894
-6.27312
-9.32791
-12.0998
-19.2394
-20.3396
-37.5408
-56.9349
-76.5237
-67.2874
-5.81281
-0
-0
-0
-0
--0.0920995
-0.138877
-0
--0.0349674
--0.0922684
--0.0866864
-0
-0.0535954
-0.154307
-31.7646
-101.661
-79.6929
-58.5534
-44.1189
-23.1626
-20.5079
-15.342
-8.89743
-7.95551
-4.18498
-4.75599
-3.65351
-2.13153
-2.66402
-2.64316
-1.88219
-1.23774
-1.44807
-0.397551
-1.06047
-1.17874
-0.236679
-1.25063
-0.396374
-0.0914409
--0.0733614
-0.386912
--0.00147651
--0.116905
-0.581502
-0.169456
-0.134705
-0.107384
-0.750599
--0.0776889
-0.0368283
-0.107426
-0.194019
-0.170805
-0.0728025
-0.266234
-0.0543795
-0.0179499
--0.126323
--0.184601
-0.0738871
--0.216003
-0.189047
-0.332016
-0.296196
--0.0353567
-0.148942
-0.270216
-0.0543109
-0.283764
--0.0716027
-0.0715148
-0.111102
--0.116729
-0.41609
-0.394682
--0.274676
-0.017598
-0.0179094
-0
--0.0361388
-0.343958
--0.0359259
--0.0367672
-0.341223
-0.237847
-0.0517339
-0.768612
-0.203076
-0.107351
-0.147082
-0.50674
-0.0728034
-0.695307
--0.10412
-0.165368
-0.396242
-0.477518
--0.0742751
-0.30787
-0.321376
-0.129543
-0.224051
-1.31612
-1.48582
-0.399098
-0.994851
-0.756997
-2.23204
-1.06917
-2.44791
-0.625682
-2.25164
-1.98221
-3.3162
-3.33963
-3.19389
-4.48059
-3.34386
-7.85423
-7.98686
-12.7424
-19.6435
-29.4412
-38.7151
-58.5631
-83.1859
-73.4251
-3.44259
-0.148094
-0.148605
--0.0953447
-0
--0.0918448
--0.0905585
--0.0363038
-0
--0.0894567
-0
-0.146667
-0
-0.298152
-21.0696
-108.87
-78.0379
-59.3239
-37.7352
-30.0628
-20.9116
-13.8528
-8.01519
-6.31127
-2.61084
-3.96616
-2.767
-3.69647
-2.01309
-1.32521
-2.59507
-1.13072
-0.945518
-0.589156
-0.793042
-0.300041
-0.840081
-0.600371
-0.576688
--0.234924
--0.0568638
--0.0368792
-0.155379
-0.582768
-0.281338
--0.0713163
-0.167345
-0.256876
-0.518592
-0.497378
-0.15692
--0.265624
-0.341372
--0.214526
-0.107972
-0.292116
-0.372038
-0.171752
--0.166287
-0.106468
-0.212825
-0.334687
-0.198906
--0.126838
--0.619474
-0
-0
-0.276824
--0.105073
--0.0702916
-0.325401
-0.186437
-0.0172156
-0.240736
-0.19299
-0.16119
-0.453977
-0.354744
-0.476198
-0.341008
--0.018858
--0.0355371
-0.103881
-0.311806
-0.131178
-0.152731
-0.192074
-0.282269
--0.0362894
--0.0376498
-0.386519
-0.166588
-0.27383
-0.457663
-0.0528648
-0
-0.179226
-0.0775784
-0.57515
-0.726619
-0.330505
-0.169628
-0.0350573
-0.515389
-0.583092
-0.169509
-0.755204
--0.115328
-1.21462
-1.08884
-0.730808
-1.19409
-1.76043
-2.8301
-1.58282
-3.57062
-3.93853
-4.47264
-5.66657
-8.32722
-12.2378
-13.1222
-18.4209
-32.3232
-41.4531
-62.3995
-81.895
-66.9679
-1.36049
-0.147653
--0.183228
-0
-0.0556436
-0
-0.152745
--0.0737313
-0
-0.154483
--0.186186
-0
-0.151874
-0.152283
-20.9167
-103.627
-81.5877
-59.9776
-37.5497
-28.2177
-18.0747
-14.5934
-7.70572
-6.31504
-4.20956
-5.27343
-2.85586
-3.3171
-1.42807
-1.86733
-1.86485
-1.03144
-2.16123
-0.638078
-0.148757
-1.60077
-0.358284
-0.965746
-1.2375
-0.188601
-0.317982
-0.429132
-0.409419
--0.113766
-0.106483
-0.209731
-0.402995
--0.0748352
-0.41286
-0.467394
-0
--0.0172566
--0.363578
--0.10942
-0.0390681
-0.215324
-0.255221
--0.214924
-0.624031
-0.164429
--0.126265
-0.201394
--0.187425
--0.093118
--0.0689105
-0.242542
-0.497666
--0.202415
-0.197264
-0.336894
-0.0549541
-0.0170015
-0.315002
-0
--0.0956575
--0.0940049
-0.0723959
-0.0542892
-0.343281
-0.0533735
-0.454784
-0.0555347
-0.483081
-0.0550195
-0.253401
--0.0384166
--0.170378
-0.0168586
-0.43254
--0.164732
-0.434671
-0.0727279
-0.0510447
-0.34092
-0.49101
-0.0714441
-0.169138
--0.0561387
-1.13393
-0.558724
-0.363149
-0.167928
-0.407911
-0.0348037
-0.270829
--0.0558027
-0.491484
-0.843398
-1.2646
-1.85268
-1.33391
-1.21589
-0.942605
-1.87713
-2.64782
-2.40245
-2.23784
-5.31096
-3.49785
-6.88352
-10.1648
-15.5412
-18.7323
-24.7691
-42.3947
-64.5863
-75.7846
-78.7438
-6.6865
-0.144849
-0.141803
-0
-0
--0.0354532
-0.0532748
-0
-0.143821
-0.0519651
-0
--0.0334403
-0.0199738
--0.086518
-25.9225
-119.997
-80.8928
-53.8214
-39.9276
-34.2985
-19.2925
-13.2456
-9.54579
-7.25787
-6.03225
-5.17878
-3.42907
-2.89575
-1.48356
-2.45411
-2.1891
-1.63051
-0.878132
-0.684075
-0.0162712
-0.837778
--0.0347208
-1.06679
-0.213972
-0.690111
-0.217854
-0.618807
--0.118321
--0.170187
--0.162286
--0.159266
-0.546915
-0.854332
--0.0371772
-0
-0.612129
--0.103997
-0.109815
--0.110563
-0.334799
--0.213656
-0.548563
-0.325922
-0.477917
--0.119785
--0.124094
-0.0544313
-0.155193
-0.292829
--0.0716857
-0.136279
--0.0341836
--0.117406
-0.370028
--0.267754
-0.129998
-0.229333
-0.329747
-0.188285
--0.0354325
-0.246065
-0.016106
-0.206051
-0.3065
-0.199152
-0.234315
-0.302546
-0.262748
--0.0939474
-0.0852152
-0.344508
-0.449738
--0.0367742
-0.154019
--0.0357844
-0.0637786
-0.426446
-0.808325
-0.559963
-0.151296
--0.0188347
-0.151037
-0.0179147
--0.0187371
-0.354522
-0.422598
-0.232172
-0.179299
-0.391299
-0.786157
--0.118416
--0.291333
-0.451102
-0.571928
-1.35523
-0.841286
-1.28852
-1.23628
-1.86949
-2.21703
-3.64859
-2.02667
-5.13427
-5.87181
-7.41736
-10.7306
-13.065
-15.6519
-22.1073
-36.3334
-48.0875
-70.4022
-95.5204
-21.7008
-0.152583
-0.574957
-0.151581
-0
-0
-0
-0
-0
--0.0967614
-0.147851
-0.153359
-0.423716
-1.06873
-58.5465
-100.571
-82.0754
-50.5826
-31.8275
-22.0229
-16.8445
-11.3526
-7.10499
-9.20481
-6.21287
-3.20155
-4.23581
-2.27471
-1.1991
-2.58592
-2.60515
-0.820755
-1.44181
-1.59624
-0.568554
-0.758663
-0.309277
-0.39626
-0.652025
-0.512527
-0.267109
-0.833158
-0.330526
-0.706446
-0.0169349
-0.195785
-0.349286
-0.0741789
-0.429362
-0.0732597
-0.247488
-0.532463
-0.194686
-0.470344
-0.392559
--0.0716333
-0.291724
-0.357305
--0.388612
-0.199108
-0.298589
-0.109877
-0.405697
-0.190717
-0.691324
-0.149095
-0.664672
-0.0491691
-0.0982457
-0.0504424
-0.185356
-0.514189
-0
-0.412437
--0.067414
-0.453104
-0.104954
-0.195686
-0.050525
--0.117318
-0.10638
-0.188908
-0.265884
-0.193583
--0.121355
-0.300864
-0.337505
-0.153737
-0.426807
-0.341088
-0.47514
-0.467303
-0.182127
-1.25076
--0.41574
--0.108529
-0.0544948
-0.156624
-1.16394
-0.481033
-0.755535
-0.623625
-0.600534
-0.138546
--0.0703918
-1.5296
-0.983573
-1.19529
-0.750463
-1.80541
-1.45163
-2.01687
-1.15562
-1.25826
-1.58516
-2.95129
-2.24446
-4.81673
-4.59354
-7.47579
-7.99885
-11.8319
-15.7237
-21.6205
-31.8039
-49.031
-66.4624
-100.053
-56.3703
-2.12952
-0.327555
--0.0885675
--0.0362494
-0
-0.139156
-0.144545
-0.150896
-0.112378
-0
-0.136394
-0
-15.591
-110.58
-91.1108
-67.8199
-46.0094
-33.81
-23.5601
-15.5194
-11.0044
-9.51983
-5.90266
-4.6146
-3.72964
-2.05302
-3.35774
-1.84486
-1.61551
-1.40732
-1.46194
-0.574953
-0.616427
-0.787353
-0.697033
-0.328959
-1.56395
-0.591325
-0.687976
-1.16795
-0.345449
--0.0716486
-0.269925
-0.82305
-0.0176038
-0.699425
--0.0687921
-0.123445
-0.337946
--0.066997
--0.0189537
--0.16172
-0.378626
-0.244305
-0.23548
-0.104725
-0.0167955
--0.122414
-0.330245
-0.150159
--0.0723071
--0.0903175
-0.182912
-0.420672
-0.188896
-0.260864
--0.0670322
-0.232264
-0.451439
-0.0517341
-0.0526741
--0.0718704
-0.102627
-0.258061
-0.106984
--0.125589
-0.640836
-0.107255
-0.357923
-0.0532028
-0.202313
--0.0362875
--0.135167
--0.349431
--0.0152527
-0.108945
-0.0176919
-0.31519
-0.0173292
-0.874334
-0.367972
-0.60293
-0.127909
-0.393556
--0.220838
--0.180259
-0.264699
-0.331478
-0.223464
--0.250474
-0.507814
-0.301151
-1.01378
-0.606569
-1.11487
-0.829966
-0.940248
--0.00142396
-0.983201
-1.11317
-1.49716
-1.93824
-2.40148
-1.92746
-2.57739
-2.18511
-4.17636
-4.42313
-5.69832
-8.16296
-13.5129
-16.667
-21.3957
-28.204
-39.788
-54.262
-73.3887
-96.2673
-27.3615
-0.430387
-0
-0
-0
-0.299101
-0.213447
-0.150158
-0
-0.147415
-0
-5.27931
-70.9056
-115.932
-84.5198
-56.742
-37.7741
-29.3423
-22.1226
-13.8526
-11.3452
-9.46954
-7.45688
-5.63618
-3.86033
-3.62704
-2.75979
-2.22426
-1.73058
-2.26829
-2.31945
-2.13712
-0.501324
-0.668276
-0.463699
-1.00162
-0.583394
-0.799548
-0.623608
-1.46217
-0.428931
--0.551343
-0.558096
--0.0722892
--0.071264
-0.218208
-0.400281
-0.490841
-0.300241
-0.154211
-0.398675
--0.0745156
--0.375411
-0.287851
-0.107929
--0.470791
-0.40595
-0.385025
-0.344616
--0.0555676
-0.0546783
--0.221619
--0.0362621
--0.0354219
-0.16289
-0.195105
-0.0512456
-0.0501232
--0.20953
-0.0496353
-0.313659
--0.271782
--0.0693657
--0.12643
--0.120029
-0.0731111
-0.26756
-0.194496
-0.290394
--0.160004
-0.110887
-0.196848
--0.387291
-0.105455
-0.465858
-0.187994
-0.10591
-0.548145
-0.405938
--0.0190342
-0.592773
-0.771599
-0.58124
--0.355118
-0.0731428
-0.178739
-0.219981
-0.213104
--0.201622
-0.619981
-0.213047
-0.255571
-0.671488
-0.017169
-0.563195
-0.167464
-0.660123
-0.436096
-1.02487
-1.24286
-0.784595
-1.79459
-2.9081
-1.928
-3.05773
-1.24058
-3.77587
-3.52055
-6.50095
-8.92752
-9.58114
-10.5145
-16.5727
-29.2358
-34.1363
-50.7992
-70.943
-95.2934
-93.9729
-28.1357
-2.21841
-0.45339
-0.29825
-0.139978
-0
-0.296329
-0
-0.146391
-4.97264
-62.9348
-121.645
-94.5953
-71.5838
-50.196
-34.5145
-24.1061
-20.5881
-11.8421
-11.6062
-5.29119
-6.57678
-3.92307
-4.09172
-1.77835
-3.07288
-2.1835
-1.32186
-1.3253
-1.46196
-1.66338
-0.500381
-1.22497
-0.819248
--0.44501
-1.44044
--0.0565153
-0.198554
-0.548231
--0.37447
-0.696985
-0.9515
-0.465507
-0.60693
--0.304112
-0.285821
-0.107337
-0.0558177
--0.125051
-0.311943
-0.106207
-0.111014
-0.0174074
-0.149691
--0.217741
-0.492407
-0.168501
-0.0172581
-0.14194
-0.0554051
--0.181694
--0.213702
-0.42352
--0.181775
-0.105781
--0.200927
-0.0950501
-0.493044
-0.319266
-0.270374
--0.0358653
-0.410303
--0.0341797
-0.0522731
-0.198318
-0.344285
--0.0642212
-0.101596
-0.0519686
-0.198597
-0.0711756
--0.187773
--0.346385
--0.0361803
-0.413743
--0.126517
--0.0358
-0.531469
-0.386351
-0.0535866
-0.069551
-0.484547
-0.194695
-0.44616
-0.123266
-0.797333
--0.0197925
-0.0760986
-0.312698
-0.0181396
-0.0728334
-0.124598
-0.430775
-0.162176
-0.365293
-1.13586
-0.651251
-2.00828
-1.85455
-1.73151
-1.84232
-1.04837
-2.00898
-0.379878
-2.25564
-2.77919
-5.79411
-5.97719
-4.47076
-10.2988
-12.3333
-16.3331
-20.7427
-31.5807
-36.1597
-53.8966
-73.4918
-103.1
-111.612
-51.5563
-18.3365
-3.39122
-1.32912
-0.433858
-1.65208
-6.2351
-34.3143
-87.782
-117.079
-99.1416
-76.4033
-57.5015
-39.2986
-27.2527
-21.0011
-15.8825
-11.5437
-8.97175
-7.00826
-4.80279
-2.92154
-1.88339
-1.9145
-2.23654
-1.07555
-1.60002
-0.594293
-0.286338
-1.27342
-0.636039
-0.964095
-1.39472
-0.585752
-0.00125873
-0.858149
--0.111703
-0.965146
-0.170057
-0.365427
-0.530063
-0.0536734
-0.00121494
-0.0537457
-0.0684639
-0.131456
-0.657699
-0.713035
-0.165161
-0.110119
-0.196597
--0.0733577
-0.836888
-0.0547049
-0.0555246
-0.625534
-0.487325
-0.195499
-0.0555502
-0.333198
--0.12552
-0.442628
-0.12789
-0.102025
-0
-0.287375
-0.136504
-0.246985
--0.300915
-0.0546414
--0.169536
-0.399169
-0.201791
--0.0729714
-0.588253
--0.22232
-0.110388
-0.592922
-0.255887
--0.0737115
-0.280346
-0.413611
-0.252612
-0.763962
-0.0707765
-0.776314
-0.104911
-0.489494
-0.942232
-0.129531
--0.260325
-0.410022
-0.105615
-0.220761
-0.234997
--0.130571
-0.532186
-0.104996
-0.158484
-0.443352
-0.956076
-0.37326
-0.462977
-0.917838
-0.728422
-0.0878797
-1.07907
-0.971586
-1.38288
-1.50824
-2.16758
-1.73075
-3.0052
-2.29413
-3.62256
-3.21178
-6.23499
-4.8317
-6.87136
-9.80691
-15.6712
-19.624
-26.2531
-30.5937
-45.5555
-60.6081
-77.5269
-99.2397
-132.305
-110.924
-95.0273
-70.9709
-64.8408
-84.7112
-98.2365
-130.534
-116.056
-104.003
-75.9195
-57.9329
-46.0284
-31.3843
-25.1766
-19.9161
-14.4199
-10.4232
-6.57772
-5.69324
-4.3772
-2.05938
-4.31349
-1.91889
-2.53942
-2.76215
-2.07995
-2.06982
-1.60646
-0.411714
-1.16576
-0.410951
-1.37598
-0.498454
-0.686547
--0.163978
-0.40898
--0.228177
-0.222005
-0.0369225
-0.231423
-0.415708
-0.24963
-0.0344429
-0.531288
--0.037958
-0.251285
--0.035198
-0.556874
-0.265975
-0.367508
-0.163703
--0.0190771
--0.22503
--0.0745869
-0.689062
-0.339169
-0.0170583
-0.722922
-0.303726
--0.12874
-0.270897
-0.242605
-0.101535
-0.0999827
--0.163348
-0.107816
-0.0506178
-0.506996
-0.244014
-0.101728
-0.295392
--0.0845442
-0.175849
-0.144335
-0.309001
--0.0894798
--0.358588
-0.0545992
-0.263549
-0.293919
-0.100753
-0.458498
-0.28931
--0.210964
--0.122877
-0
-0.357008
-0.364699
-0.472271
-0.259926
-0.715316
-0.200569
-0.305507
-0.911345
-0.427906
-0.348013
-0.201721
-0.348558
--0.0691106
-0.129309
-0.780708
-1.04702
-0.992497
-1.0553
-0.343891
-0.976476
-0.53581
-0.815833
-1.11596
--0.129704
-0.872313
-2.41474
-2.6535
-2.50183
-4.03814
-4.12483
-4.59003
-7.24641
-6.18678
-12.882
-12.7033
-19.7366
-26.8285
-29.8399
-48.4103
-57.4714
-70.4888
-95.8462
-92.1611
-104.105
-122.846
-128.456
-127.952
-124.908
-96.2528
-83.2134
-76.978
-57.6784
-48.1708
-35.352
-25.087
-19.917
-15.2913
-12.3679
-7.0151
-5.75238
-4.28407
-4.35167
-2.89112
-2.52249
-1.91012
-2.26511
-1.75203
-1.73224
-0.886944
-0.806105
-0.593405
-0.076652
-0.335675
-0.69499
-0.266438
-0.446699
-0.449491
-0.65509
-0.219349
-0.434385
-0.0693751
-0.843269
-0.107567
-0.130132
-0.475106
--0.0362852
-0.0181511
-0.363825
-0.0171248
-0.142269
-0.327828
-0.0562664
-0.106322
-0.145997
-0.246865
-0.423378
-0.346433
-0.490279
--0.174491
-0.256208
-0.209644
-0.351524
--0.0677337
-0.163388
--0.202361
-0.137425
--0.204815
--0.20751
--0.153712
--0.173055
-0.575485
-0.384967
-0.394431
-0.244853
-0.107396
--0.113201
--0.121266
-0.25392
-0.142795
--0.0937556
-0.504411
-0.0206124
-0.350639
--0.0967288
-0.427677
-0.0688255
-0.249041
-0.0541165
-0
-0.474671
-0.104415
-0.314236
-0.319881
-0.106656
-0.3633
-0.307589
-0.349735
-0.0184719
--0.0194112
-0.15949
-0.212119
-0.775391
-0.164625
-0.615725
-0.476356
-0.740082
-0.513698
-0.883652
-0.521377
-0.720252
-1.26636
-0.70136
-1.92994
-1.73308
-1.17962
-2.6585
-3.99567
-4.04132
-3.2717
-6.84903
-8.7661
-9.72078
-11.6143
-16.4161
-22.0591
-26.6384
-29.6779
-40.3123
-56.9718
-60.2799
-73.4769
-86.5527
-86.2621
-91.8981
-80.0294
-82.6904
-69.9249
-67.4717
-53.5754
-41.4389
-32.1441
-23.2573
-18.7532
-17.0091
-11.1502
-11.5133
-5.29765
-5.88707
-3.84198
-4.15902
-5.67159
-3.31417
-1.73663
-2.26765
-3.04849
-1.4703
-0.751284
-0.872324
-1.17943
-0.78245
-0.345223
-1.10964
-0.489773
-0.302394
-0.649226
--0.265008
-0.591541
-0.533777
-0.157098
-0.610975
--0.215131
-0.216634
-1.14103
-0.568312
--0.0191999
-0.481641
-0.237991
-0.554779
-0.197483
-0.339256
-0.294079
-0.196817
-0.0520339
--0.241723
--0.0746218
--0.124264
--0.036225
--0.251992
--0.345294
-0.135329
--0.123849
-0.764119
-0.0940897
-0.0499511
--0.0339402
-0.11737
-0.0499876
-0.209794
-0.019426
-0.655315
-0.575982
--0.247136
-0.294911
--0.49138
-0.291755
-0.190449
--0.118808
-0.0165261
-0.133856
--0.0743679
--0.295096
--0.191502
-0.0529252
-0.106788
-0
-0.0171412
-0.328362
--0.0188617
-0.0719247
-0.36747
-0.276126
-0.58661
--0.0720791
-0.0172674
-0.147037
-0.385606
-0.204983
-0.639267
-0.633684
--0.433925
--0.0546927
-0.0179527
-0.615229
-0.616014
-0.229522
-0.95884
-0.405602
-0.36386
-1.24422
-1.43199
-1.07294
-2.64465
-1.51688
-2.97096
-1.53306
-2.7804
-4.06614
-5.24979
-3.82071
-6.32595
-8.43015
-10.8368
-17.3166
-20.6334
-20.7687
-32.5565
-35.9276
-43.6693
-44.2187
-57.1756
-54.2788
-61.5865
-60.2921
-51.9451
-47.8699
-38.773
-42.924
-32.8534
-28.3236
-16.7572
-16.8177
-11.4954
-12.0219
-6.14961
-5.94567
-4.48553
-3.27927
-1.82864
-4.67704
-3.41641
-1.56607
-2.27556
-1.04943
-1.10468
-0.95635
-1.00135
--0.11009
--0.56738
-0.683542
-0.333876
-0.242014
-0.236068
--0.0543021
-0.600066
--0.316905
-0.386308
-0.801337
-0.619762
-0.266446
-0.175365
-0.377893
-0.406618
-0.216033
--0.0204061
-0.163337
--0.372513
--0.0359154
-0
-0.396931
-0.105415
-0.0172471
--0.199497
-0.158744
-0.475864
-0.539938
--0.0389973
-0.0554946
-0.0543117
-0.382798
-0.471982
--0.0664831
--0.0348931
--0.33778
-0.33748
-0.836304
-0.194471
-0.198481
-0.325712
-0.0551333
-0
-0.346035
-0.503831
--0.0156116
-0.579998
-0.141333
-0.360419
-0.30156
--0.163415
-0.0190465
--0.0165192
--0.0359888
-0.102347
--0.074743
-0.0530169
-0.460964
-0.3184
--0.0660795
-0.491666
-0.1447
-0.535542
--0.265666
-0.197728
-0.31539
--0.0543198
-0.32664
-0.12388
-0.366321
-0.271716
-0.759023
-0.82172
-0.892258
-0.1331
-0.429654
-0.245241
-1.42231
-0.886766
-0.47152
-1.02545
-1.69261
-1.66576
-0.451236
-2.25085
-2.50821
-3.12289
-3.52093
-3.33046
-2.93765
-5.36942
-8.56626
-8.89959
-13.5267
-12.2545
-18.6362
-21.4956
-24.5338
-30.7151
-37.8224
-37.6669
-38.6305
-43.7708
-40.0303
-37.6685
-33.3247
-32.0966
-29.5281
-24.4975
-19.4686
-14.7648
-9.75144
-8.60517
-7.23077
-7.26404
-5.88018
-3.94787
-2.20625
-3.69858
-2.7818
-1.2167
-1.03385
-2.29476
-1.0734
-0.756359
-1.17224
-1.06867
-0.861607
-0.655706
-0.518695
-0.0579879
-0.632346
-0.545526
-0.596985
--0.0185588
-0.0543306
-0.241488
--0.0714664
--0.036985
--0.247927
--0.403781
-0.260813
-0.734798
-0.208621
-0.40721
-0.164667
-0.783621
-0.353727
-0.25641
-0.345719
-0.297979
-0.16198
-0.400226
-0.198551
-0.573411
-0.19618
-0.433906
-0.109826
--0.12024
--0.212241
-0.357311
-0.242242
--0.0815128
-0.0480177
-0.235164
--0.113176
-0.866768
--0.258014
--0.154016
-0.219509
-0.235995
-0.019048
-0.0572225
--0.173943
-0.481388
-0.740801
-0.336111
-0.189748
-0.446073
-0.431177
-0.435744
--0.0360611
--0.0679422
-0.333436
-0
--0.165043
-0.327795
--0.0340005
-0.13716
--0.127576
-0.528732
--0.173634
-0.363476
--0.179498
-0.663881
-0.0535319
-0.533225
-0.342855
-0.738758
-0.496365
-0.452365
-0.660661
-0.188828
-0.71479
-0.552802
-0.914581
-0.892508
-0.17918
-0.633037
-2.05367
-1.96116
-0.697455
-1.92081
-2.82573
-2.16891
-3.53849
-4.24879
-3.66647
-5.38978
-8.74283
-6.67832
-8.14942
-9.54457
-13.3746
-14.9297
-17.5087
-22.2714
-25.1098
-27.711
-22.3257
-24.8829
-27.5411
-25.2851
-26.1281
-19.0455
-16.7939
-18.0282
-14.0557
-11.2772
-11.955
-7.5383
-6.34612
-5.26992
-5.03415
-3.62718
-3.69087
-1.74401
-1.18247
-2.16853
-0.974115
-0.966305
-0.947735
-0.126462
-1.24433
-0.817573
-1.60272
-0.965967
-0.267219
-0.288365
-1.02814
-0.414722
-0.0744362
--0.102885
-0.405083
-0.50622
-0.386981
-0.791632
--0.0183696
--0.037046
-0.162912
-0.108793
--0.545704
-0.218055
-0.530553
-0.414804
-0.206088
--0.180977
-0.105699
--0.364129
--0.0352786
--0.03567
-0.164622
-0.14712
-0.440013
-0.0171715
-0.248737
-0.137475
-0.289121
-0.332492
-0.0951741
-0.0511792
-0.0512241
--0.0359334
-0.416402
--0.0891416
-0.170733
-0.156881
-0.455567
-0.243085
--0.207552
--0.130004
-0.338029
-0.204626
-0.260698
-0.343866
--0.17507
-0.0564567
--0.122412
-0.0775506
-0.205214
-0.189789
-0.0560461
--0.450917
--0.0727219
-0.166089
-0.335412
-1.18598
-0.108351
--0.125136
-0.286818
--0.408229
-0.834874
-0.610223
-0.126137
-0.498998
-0.072395
-0.216889
-0.313962
-0.172284
-0.0708374
--0.0196319
-0.451021
-0.309083
-0.328815
-0.920683
-0.937218
-0.890841
-0.976619
-1.16337
-1.63937
-2.51641
-1.29598
-1.48311
-3.24475
-2.67608
-4.09098
-5.21471
-4.66296
-4.63199
-7.41376
-8.64746
-9.82995
-12.1812
-10.0262
-14.0292
-15.924
-15.9151
-18.6915
-21.7536
-18.1974
-18.1447
-16.9741
-15.4071
-12.3818
-16.5667
-9.98308
-8.41701
-10.6704
-6.18884
-4.53233
-4.0714
-3.41846
-2.65776
-2.71283
-3.87235
-1.76974
-1.06436
-1.40503
-2.19931
-0.0518188
-0.981005
-1.02487
-0.0940091
-0.868044
-0.181374
-0.209476
-0.645416
-0.0169801
--0.0192252
-0.510169
--0.036493
-0.215919
-0.199966
-0.204551
-0.170974
--0.303822
-0.455891
--0.0731966
--0.339207
-0.520547
-0.0530698
--0.125664
-0.107395
-0.549534
-0.166306
-0.0178012
-0.340733
-0.104175
-0.33588
--0.268945
-0
-0.539963
-0.0559437
-0.247879
-0.159126
--0.159254
-0.376375
-0.0184185
-0.240164
--0.0323774
-0.404676
-0.0524267
--0.119015
-0.184149
-0.565148
-0.0529254
--0.0331224
-0.520376
-0.0570204
--0.112777
--0.355111
-0.0163891
-0.345789
-0.311068
--0.0896939
--0.122708
-0.330733
-0.0163109
-0.0518764
-0.303951
--0.218806
--0.362804
-0.423771
-0.186677
-0.18326
-0.918827
-0.161725
-0.107109
--0.0729207
-0.501784
-0.502706
-0.910762
-0.0179943
-0.35271
-0.272465
-0.0344077
-0.690866
-0.538722
--0.0202886
-0.873206
-0.897917
-0.895482
-0.396309
-0.773053
-0.687765
-0.790092
-0.885991
-1.67947
-0.351902
-2.07318
-1.71146
-2.45722
-3.27517
-2.54054
-3.82495
-4.78992
-6.29712
-5.57297
-7.22156
-8.45689
-10.1709
-9.94816
-11.1237
-11.3214
-14.3259
-13.0033
-12.8377
-14.7576
-14.2411
-12.4835
-10.2217
-10.266
-9.47694
-7.52647
-6.3986
-5.54326
-5.00906
-4.56817
-4.89808
-2.97645
-1.60311
-1.97944
-2.26302
-2.74285
-0.968564
-1.56982
-0.868337
-0.943529
-1.44914
-0.232735
-0.284673
-0.0350813
-0.976062
-0.235933
-1.12833
-0.629856
-0.905711
-0.570669
-0.510922
-0.496253
-0.554318
-0.355851
-0.16998
-0.352565
--0.189111
-0.199626
-0.273559
-0.0713217
--0.0196181
-0.155611
-0.319766
--0.0714113
-0.370466
-0.339299
-0.110203
-0.052607
--0.264125
-0.342133
--0.0363034
-0.103545
-0.166725
-0.196023
-0.0508217
-0.195029
-0.017231
-0.268997
-0.316521
-0.0554127
-0.339852
-0.0207625
-0.0392909
-0.203411
-0.133164
-0.211183
-0.43113
--0.0374235
--0.0365833
--0.0366394
-0.282055
-0.0741213
--0.132075
-0.017975
-0.638943
-0.195273
-0.0180106
-0.30874
-0.136135
-0.665402
-0.524307
-0.225222
-0.455212
-0.0207833
--0.0364735
-0.10727
-0.500122
--0.0139412
-0.314513
-0.27053
-0.177836
-0.10735
-0.176655
-0.539792
-0.272469
-0.700198
-0.51871
-0.351704
--0.249336
-0.875161
-0.432019
--0.0740042
-0.680495
-0.81673
-0.321798
-1.99728
-1.06101
-1.88415
-0.980661
-1.75738
-1.86689
-2.74581
-1.61666
-2.09785
-2.98114
-5.0566
-3.50702
-3.74572
-6.1789
-4.10334
-5.25529
-8.25708
-8.31403
-6.1646
-7.26641
-13.1411
-8.72961
-12.677
-12.8399
-9.45018
-6.83741
-7.75354
-8.56392
-6.58914
-4.91209
-4.61865
-2.96242
-4.56074
-2.11782
-5.25933
-2.89895
-2.7636
-1.21895
-1.02176
-1.04768
-0.282589
-0.0903517
-1.25043
-0.602514
-0.437612
-0.589595
-0.999635
-0.0533391
-0.870742
-0.934709
-0.467058
-0.222837
--0.264403
-0.193707
-0.970969
-0.0172935
-0.790849
-0.616996
-0.611096
--0.0354657
-0.31516
--0.358325
-0.148457
-0.320421
-0.470245
--0.178412
--0.0363568
--0.0877986
-0.142644
-0.0524097
-0.397949
-0.377768
-0.309844
--0.449489
--0.0739711
-0.194922
-0.838295
-0.181797
-0.610169
-0.186476
-0.132256
-0
-0.456353
-0.145432
--0.332265
-0.338109
-0.0709857
-0.184437
--0.0334314
--0.0729635
--0.070053
-0.549775
--0.116816
-0.342327
-0.327041
--0.193598
-0.016984
-0.413497
-0.136836
-0.208399
--0.173725
-0.105264
-0.0538105
-0.479166
-0.571951
-0.172955
--0.301836
-0.26467
--0.2535
-0.480609
-0.111796
-0.401237
-0.211026
-0.0190684
-0.400934
--0.0756282
-0.541363
-0.467045
-0.375322
-0.538946
-0.818088
-0.0176142
-0.588667
-1.62406
-0.746709
-0.26886
-0.275707
-0.635582
-0.822995
-0.984388
-0.443432
-1.8992
-1.98651
-0.994685
-1.22043
-0.872254
-2.21553
-3.41493
-2.87114
-2.52975
-3.09457
-3.48135
-4.09181
-4.82689
-6.55912
-5.69695
-5.49628
-3.94394
-6.96081
-7.88041
-7.60822
-6.19787
-5.71533
-5.60975
-4.04245
-5.02805
-5.90776
-4.55268
-1.12996
-3.84421
-1.79025
-2.34958
-1.95427
-2.24778
-0.562156
-1.93668
-1.43556
-0.980043
-1.00609
-1.53143
-1.51651
-1.7321
-0.779429
-0.605496
-0.220103
-0.377841
-0.40525
-1.0874
-0.657893
-0.173792
-0.206725
-0.0179097
-0.442052
-0.19577
-0.158146
-0.11049
-0.194179
--0.314419
-0.465747
-0.204401
-0.0358452
-0.173964
-0.185632
-0.501332
-0.401274
--0.170488
-0.1636
-0.115735
-0.0543917
-0.0167297
-0.0536244
-0.54854
-0.32577
-0.872509
-0.140568
-0.530062
--0.290741
--0.212554
-0.154731
-0.0679886
-0.05597
-0.15526
--0.0715382
--0.0364618
-0.440245
-0.345866
--0.135462
--0.120313
-0.0559475
--0.370046
-0.470982
-0.282659
-0.395341
-0.493123
--0.0737183
-0.200419
-0.357062
--0.31401
--0.133041
--0.271389
-0
-0.380062
-0.112773
-0.0548728
-0.107522
--0.275542
-0.303207
--0.124059
-0.903859
-0.163088
-0.48862
-0.262418
-0.314437
-0.559669
-0.38168
-0.45942
-0.304564
-0.452951
-0.710571
--0.487886
-0.277331
-0.640855
-0.828891
-1.01022
-0.549986
-1.03093
-0.15494
-0.9115
-0.408605
-2.10114
-0.632061
-0.853478
-1.43838
-1.5589
-3.12486
-3.39256
-2.88488
-3.48173
-3.15901
-2.82039
-4.26519
-2.19327
-5.1559
-3.38999
-5.09999
-6.11803
-6.44148
-6.03296
-4.79218
-5.37591
-4.23428
-5.83938
-4.16852
-3.00753
-4.96979
-3.54399
-3.56257
-4.26608
-2.30309
-2.4085
-1.45216
-1.46308
-1.83219
-0.493652
-1.38163
-0.0162561
-1.91794
-0.744574
-1.36382
-0.264039
-0.601148
-0.701292
-1.07805
-0.723109
-0.691654
-0.0347586
-0.545429
--0.211688
-0.124165
-0.615773
-0.314248
-0.283577
-0.34096
-0.74491
-0.66969
-0.755994
-0.417801
--0.123552
-0.111836
-0.342846
--0.0710999
-0.547701
-0.321309
-0.249601
--0.161576
--0.151687
-0.258368
-0.201663
-0.301554
--0.0706661
-0.137608
-0.0173055
--0.0747797
-0
-0.44274
-0.187223
--0.119142
-0.55067
--0.185215
-0.296201
-0.455016
-0.460149
-0
-0.44956
-0.184433
--0.0359005
-0.0979029
-0.55094
-0.565466
-0.293166
-0.177947
-0.551846
-0.186257
--0.0366196
-0.255751
--0.0375508
-0.102957
--0.359841
-0.0167827
-0.424421
--0.0882676
--0.0360004
--0.205808
-0.743024
-0.343981
-0.680038
-0.199048
-0.0733266
--0.11905
--0.491015
-0.609308
-0.0734455
-0.349534
-0.148517
-0.347358
-0.969242
-0.207668
-0.106983
--0.0185773
-0.169955
-0.267658
-0.557049
-0.968976
-0.504407
-0.976429
-1.02819
-1.54916
--0.17615
-0.515693
-0.460801
-1.47099
-1.07891
-2.08608
-2.46832
-2.20232
-1.48907
-2.68928
-2.57013
-4.8747
-3.02773
-3.68478
-3.75407
-3.62246
-2.82323
-4.69495
-2.25949
-4.22367
-4.81349
-4.65138
-4.72587
-4.14931
-4.30467
-2.7388
-2.46364
-2.93846
-1.80832
-1.97659
-1.82758
-1.57408
-1.55904
-1.31596
-1.58213
-1.65295
-2.12321
-1.58376
-1.23672
-0.291778
-1.19609
-1.17338
-0.710518
-0.78242
-0.596622
-0.206287
-0.697671
-0.0164221
-0.576665
-0.207565
-0.403753
-0.130948
-0.351535
-0.156256
-0.366982
-0.0374268
-0.560273
-0.349888
--0.170321
-0.0559039
-0.213828
-0.610529
-0.869373
-0.0548665
--0.321184
--0.0374683
-0.110317
--0.0364552
-0.49811
-0.4943
-0.165242
-0.0715701
-0.152011
-0.0173453
-0.0537088
-0.0529427
-0.472381
-0.419552
-0.233495
-0.255524
--0.0688954
-0.112446
-0.101667
-0.25258
--0.0890197
-0.45202
-0.322602
-0.0516559
-0.169667
-0.197826
--0.0672537
--0.213059
-0.0555446
--0.0371548
-0.255905
-0.037486
--0.294096
-0.245449
--0.0325801
-0.504769
-0.486686
-0.255404
--0.0371262
-0.574702
-0.0536616
-0.0185369
-0.256343
-0.464169
-0.212176
-0.393545
--0.0364368
--0.0765515
-0.34844
--0.279817
-0.618971
-0.319607
-0.575932
-0.169127
-0.350744
-0.447623
-0.825771
-0.0378146
-0.224993
-0.770147
-0.883569
-1.07588
-0.804018
-0.684239
-0.991614
-1.31061
-0.84802
-2.06209
-0.681581
-0.716925
-1.56104
-1.09207
-2.76709
-3.07476
-2.3455
-2.74382
-2.42468
-3.26054
-2.40369
-2.38275
-3.99315
-1.81929
-4.06199
-4.02289
-2.80146
-2.11412
-2.96225
-3.18198
-3.43918
-2.70289
-1.84164
-1.37057
-2.46602
-2.10046
-2.1261
-1.40171
-1.36801
-1.79237
-1.53135
-0.373752
-0.558135
-0.183656
-1.08814
-0.338026
--0.304509
-0.166919
-0.918064
-0.47034
-0.109559
-0.334194
-1.17837
-0.124243
--0.193914
-0.642961
-0.425741
-0.112627
--0.0375703
-0.0179325
-0.0185666
-0.310088
--0.0916112
-0.531325
-0.964645
-0.59118
-0.193469
-0.147415
--0.19991
-0.164565
--0.0742622
--0.165582
-0.497405
-0.25753
-0
-0.744359
-0.0530988
--0.216431
--0.0364135
-0
-0.427479
-0.290932
--0.0361652
--0.297889
-0.324272
--0.238005
-0.2912
-0.238103
-0.186936
-0.406402
-0.282667
-0.790227
-0.45385
-0.307993
-0.319221
-0.019766
--0.0372708
--0.260808
--0.0916902
-0.0194823
-0.604238
--0.0344053
-0.40913
-0.571991
-0.0701969
-0.658919
-0.440991
-0.393147
--0.038386
-0.340491
--0.218619
--0.0741428
-0.866517
-0.219593
-1.1859
-0.389891
-0.302526
-0.20295
--0.0368052
-0.196799
-0.285639
-0.421971
-0.518643
-0.781158
-0.224297
-0.0170226
-0.979934
--0.252768
-0.311088
--0.213853
-0.682343
-1.77192
-1.37827
-0.965231
-0.442154
-0.398973
-0.82938
-0.667461
-0.957418
-1.60824
-1.71768
-1.23675
-0.957843
-1.67472
-2.90933
-2.62701
-1.004
-2.06959
-1.75701
-2.15618
-2.89622
-3.80777
-1.15508
-1.94855
-1.7524
-3.01679
-2.92374
-2.2125
-1.7452
-2.87042
-2.42412
-2.25677
-0.418885
-1.33654
-1.70894
-1.51336
-0.972745
-1.79125
-0.756052
-0.922072
-0.852856
-0.902908
-0.248372
-0.8763
-0.235821
-0.992092
-0.390516
-1.01149
-0.164532
--0.223041
-0.0772523
-1.13592
-0.291969
-0.206825
-0.802451
-0.420078
-0.353707
-0.163634
-0.295152
-0.0186752
-0
-0.666053
-0.0176654
-0.199835
-0.0526181
-0.0407638
-0.349499
-0.595021
-0.311714
-0.0526235
-0.399942
-0.341227
-0.146474
-0.339209
-0.740621
-0.601542
-0.0178878
-0.160431
-0.107638
-0.017572
-0.250054
-0.271966
--0.282842
-0
-0.249238
-0.0173551
-0.372446
-0.196613
-0.247272
--0.125754
--0.0883823
--0.398
-0.532686
--0.213777
--0.090818
-0.710809
--0.22026
-0.0182308
--0.0724271
-0.456168
--0.038236
-0.0543559
--0.0359227
-0.262893
-0.390338
-0.500037
-0.900238
--0.137772
-0.448561
-0.163952
--0.204605
-0.0204217
-0.287173
-0.588354
-0.229601
--0.0931922
-0.249254
-0.209347
-0.411548
-0.627763
-0.930967
-0.401829
--0.076063
--0.0193761
-0.989206
-0.0175466
-0.671761
-0.813301
--0.264844
-0.609074
-0.540443
-0.53171
-1.49657
-0.925401
-0.796234
-0.166847
-0.829395
-0.633147
-0.877505
-0.471137
-2.14171
-1.71261
-0.600284
-0.623224
-2.38236
-1.44545
-0.83551
-2.21195
-1.91603
-1.29045
-2.1401
-2.08041
-2.89083
-1.21828
-1.39322
-2.06614
-1.84927
-2.21769
-1.6431
-1.40795
-1.56359
-0.436921
-0.877353
-1.13594
-1.42032
-1.08925
-1.12967
-0.142348
-0.947357
-0.38494
--0.216425
-0.0172618
-1.2037
-0.748288
-0.636227
-0.847098
-0.556185
-0.0688565
-0.0347109
-0.159464
-0.163536
-0.306827
-0.137545
-0.201671
--0.0139835
-0.889058
-0.735252
-0.103045
-0.452233
-0.148428
--0.0347318
-0.0729905
-0.540455
-0.268076
--0.167289
--0.0363741
-0.196583
--0.0689347
-0.193204
-0.483895
-0.324974
-0.0714411
-0.105987
-0.480393
-0.106058
-0.0533697
-0.0172265
--0.0900008
-0
-0.176005
-0.158858
--0.0321642
-0
-0.238676
-0.139577
-0.0164355
-0.232667
-0
-0.529969
--0.0684381
-0.442434
-0.374449
-0.125527
-0.274087
-0.110407
-0.336185
--0.191163
--0.0349587
--0.0377611
--0.248148
-0.169581
--0.0689
-0.417116
-0.527221
--0.0757612
-0.338177
-0.0183069
-0.28394
--0.0746083
-0.162842
-0.140192
-0.248122
--0.1369
-0.662125
--0.134361
--0.03567
-0.606011
--0.316099
-0.196466
--0.108951
-0.129069
-0.17175
-0.259834
-0.400284
-0.189377
-0.534197
-0.213992
-0.50099
-0.183837
-0.709987
-0.575382
-1.10294
-0.748741
-1.52518
-0.834053
-1.65989
-1.33765
-1.26089
-1.29464
-1.89674
-2.03463
-2.11711
-2.09391
-1.65157
-1.44335
-1.16815
-1.29467
-1.70697
-1.02895
-2.13048
-1.70164
-0.542749
-3.06676
-0.803073
-2.14555
-1.53887
-0.633052
-1.5791
-1.74418
-1.11908
-1.65113
-0.907834
-0.265215
-0.776315
-0.362886
-0.875921
-0.761187
-1.75255
-0.0192066
-0.393851
-0.0585904
-0.535377
-0.829356
-0.267256
-0.417103
-0.579126
--0.109766
-0.148835
--0.0763168
-0.260044
-0.350295
--0.169518
--0.12712
-0.297085
-0.743214
-0.253233
--0.250235
-0.620679
--0.0899871
-0.469588
-0.0555073
-0.504138
-0.881714
-0.197663
--0.0967856
-0.108883
-0.202245
-0.655556
-0.536363
--0.0903141
-0.109251
-0.256342
--0.126745
--0.351864
-0.275442
-0.104844
-0.194183
--0.0849909
--0.115686
-0.244817
-0.280669
--0.0923479
--0.0332104
-0.429065
-0.231709
--0.18233
-0.385536
-0.145705
--0.0356669
-0.589395
-0.194211
-0.169692
-0.59814
-0.344436
--0.0354617
-0.619208
--0.0380515
-0.485967
-0.0166027
-0.108807
-0.343909
-0.168689
--0.0930168
--0.180924
-0.170779
--0.258793
-0.306589
-0.0205948
-0.0169999
-0.534296
-0.0561059
--0.0363702
-0.720656
-0.539912
-0.112577
-0.0729154
-0.288365
-0.679034
-0.217369
-0.467832
-0.110551
-0.0187565
--0.0512024
-0.374736
-1.15872
-1.22928
-1.06828
-0.241766
-0.939918
-1.00047
-0.467555
-0.41689
-1.48851
-0.336125
-0.359144
-1.50793
-0.696953
-1.00745
-2.30959
-0.882448
-1.467
-1.90255
-1.68765
-0.189402
-1.31352
-1.91626
-1.42532
-0.77741
-0.682604
-0.788602
-1.753
-1.5196
-0.814983
-1.41833
-1.18892
-0.841058
-0.180779
-1.10695
-0.936087
-1.42551
-0.583905
-0.597147
-0.207558
-0.559906
-0.455043
-0.159834
-0.62019
-0.475034
-0.123815
-1.40227
-0.21961
-0.166053
-0.0762557
-0.401402
-0.0691629
--0.0365983
-0.16668
-0.195984
--0.252906
-0.404828
-0.471228
-0.0531588
-0.519234
--0.307975
-0.198183
--0.0377396
-0.198978
-0.0551779
--0.349386
-0.124519
--0.299584
-0.49235
-0.137292
--0.0368323
--0.0899081
-0.141721
--0.240041
-0.413806
--0.0182749
-0
-0.395691
-0.146151
-0.105702
-0.192155
-0.335995
-0.241715
-0.0165406
--0.13938
-0.193102
-0.0166496
-0.244598
-0.105446
--0.0345101
-0.106095
-0.0171412
-0.195128
--0.1305
--0.0148195
-0.730301
--0.0343507
-0.2024
-0.237452
-0
-0.049351
-0
-0.19352
-0.161775
-0.193244
-0.258066
-0.491058
-0.376723
-0.326089
--0.0706779
--0.0925517
--0.0368619
--0.40114
--0.113898
--0.0162666
-0.0188565
-0.249077
-0.109932
-0.106849
-0.159629
-0.516258
--0.306505
--0.33498
-0.368157
--0.161186
-0.880607
-0.624757
-0.864631
-0.193849
-0.625529
-0.429953
-0.517542
-0.241458
-0.967535
-1.40699
-0.62482
-0.498485
--0.0188668
-0.767836
-0.719242
--0.281144
-0.716387
-0.294392
-1.19469
-1.00675
-2.31494
-1.38529
-0.723187
-1.37367
-2.26545
-2.07534
-0.982177
-1.55272
-1.64652
-0.810013
-0.439931
-1.32839
-1.31394
-1.13714
-0.314976
-1.13712
-0.382674
-0.0713354
-0.365317
-1.53299
-0.500456
-0.647735
-1.00895
-0.111001
-0.343827
-0.371304
-0.457038
-0.314577
-0.424716
-0.307326
-0.110924
-0.165856
-0.133871
-0.218217
-0.64289
-0.46163
-0.286753
-0.461919
-0.413883
--0.358016
-0.26729
-0.240142
-0.168505
-0.351101
--0.0370436
-0.0529486
-0.446342
-0.0694708
-0.486982
--0.0341272
--0.0761166
--0.179561
-0.258514
-0.329531
-0.291208
--0.0368566
-0.334588
-0.0371794
--0.0376204
--0.210044
-0.249109
-0.107364
-0.248591
--0.170926
-0.0855445
-0.230752
--0.113285
-0.199129
-0
-0.254641
--0.0344077
-0.106555
--0.0354434
-0.25696
-0.236058
--0.0372039
-0.173104
--0.175878
-0.697553
-0.253899
-0.0540701
--0.271062
-0.340943
-0.190175
--0.180207
-0.290163
-0.282714
-0.438421
-0.2904
-0.0721679
--0.39669
-0.626852
--0.409298
-0.209099
-0.605489
-0.035048
-0.548023
-0.0347293
--0.17075
-0.0170385
-0.793346
-0.345538
-0.319136
--0.037492
-0.780181
-0.112727
-0.53931
-0.375367
--0.0737131
-0.388033
-0.212898
-0.843492
-0.197302
-0.0178144
-0.447019
-0.228268
-0.188662
-0.422343
-0.313488
-0.147813
-1.26529
-0.88737
-1.02377
-0.570176
-0.587383
-0.667722
-0.775096
-0.976431
-0.55598
-0.72269
-0.7435
-0.429572
-1.00225
-0.926657
-2.41483
-1.03244
-0.517392
-0.146814
--0.0382288
-1.49323
-1.19466
-2.00249
-1.1886
-0.739379
-1.37615
-0.329372
-0.783548
-0.471369
-1.03523
-0.443958
-0.882485
-0.170025
-0.438717
--0.0354357
-0.642402
--0.247616
-0.215215
--0.395616
-0.399636
-0.274691
-0.795425
-0.586553
-0.0367351
--0.127391
-0.163839
-0.55868
-0.105417
-0.285904
-0.553589
-0.332832
--0.130446
-0.50989
-0.180764
-0.199173
-0.401154
-0.182155
-0
-0.329606
-0.107693
-0.107468
-0.399584
-0.187878
-0.194013
--0.0369009
-0.531249
-0.253072
--0.129736
-0.400865
--0.125067
-0.0166013
--0.119776
-0.106409
--0.159854
--0.0364178
-0.314979
-0.167474
-0.630765
-0.193607
--0.120328
-0.274669
--0.0689993
-0.162187
--0.0353764
-0.246932
-0.148179
--0.124502
--0.121972
--0.209058
-0.0545631
-0.0170172
-0.116139
--0.15039
-0.118685
-0.0208278
--0.342305
--0.216311
-0.293826
-0.156302
--0.0371453
-0.0170354
--0.112478
--0.333049
-0.0185292
-0.0938339
-0.342927
-0.633999
-0.750631
-0.444257
-0.0185967
--0.179355
-0.357966
-0.515704
--0.297771
-0.871879
--0.187792
-0.0738733
-0.113738
-0.35855
-0.587673
-0.804401
-0.811784
-0.0180598
-0.323643
-0.3668
-0.436924
-0.667973
-0.800967
-1.14691
-0.28101
-0.175575
-1.02641
-0.990171
-0.469081
-1.38857
-1.29111
-1.2545
-0.810329
-1.86656
-0.976807
-1.01362
-0.811239
-0.788216
-0.578797
-2.41282
-0.837258
-0.0862908
-0.545678
-1.1865
-0.422781
-0.485894
-1.10366
-0.952447
-0.943124
-0.934142
-0.667444
-0.852377
-0.384216
-0.0874413
-0.318493
-0.291687
-0.584875
--0.160407
-0.344857
-0.125307
-0.335185
-0.0199601
-0.805842
--0.0192398
-0.546848
-0.202789
-0.209256
-0.525337
--0.0379529
--0.126857
-0.259664
--0.128245
--0.257767
-0.407794
-0.0184009
-0.286248
-0.753606
-0.0536166
-0.393857
--0.17067
-0.555916
-0.0168684
--0.0370633
--0.173933
--0.0379704
-0.406794
--0.210761
-0.104891
--0.0883773
--0.0677601
-0.378059
-0.930293
-0.423954
-0.291564
--0.0907479
-0.72953
-0.304611
-0.321091
-0.155069
-0.105338
-0.0176238
--0.20798
-0.0166212
-0.0175962
-0.232019
-0.0215495
-0
-0.0514269
-0.438777
--0.448185
-0.0167129
--0.118832
--0.181507
--0.263856
-0.456488
-0.645081
--0.037378
--0.354961
--0.119145
-0.270105
-0.532686
-0.288745
-0.801027
-0.0168035
-0.60714
-0.203502
-0.1954
-0.0183052
-0.716584
-0.193994
-0.385836
-0.254239
-0.0173506
-0.294141
-0.361146
-0.0545849
-0.362287
--0.0157764
--0.0189783
-0.106173
--0.0677319
-0.330436
-0.331696
-0.352892
-0.534595
--0.0185761
--0.144853
-0.274393
-0.0353987
--0.0186529
-0.103727
-0.602113
-0.56016
-0.276585
-0.990706
-0.648725
--0.315269
-0.634959
--0.165032
-0.0353277
-0.982475
-1.86421
-0.515294
-0.975518
-0.590736
-0.125628
-0.954686
-0.0357757
-0.819252
-1.55864
-0.854701
-0.186465
-0.885047
-1.10948
-0.670719
-1.02384
--0.0191536
-0.217484
-0.15764
-0.263548
-0.397438
-0.221364
-0.454639
-0.502307
-1.23396
-1.00203
-0.617795
-0.163262
-0.643697
--0.170824
--0.260424
-0.493782
-0.105774
-0.81497
-0.074258
--0.130749
-0.298621
-0.0208166
-0.163509
-0.318246
-0.069381
-0.243396
-0.405042
-0.488226
-0.0534004
-0.0168416
-0.144653
-0.150835
-0.163135
-0.0172601
-0.216495
-0.467067
--0.088088
-0.103462
-0.0172227
-0.105983
--0.204987
-0.489795
-0.0536259
-0.139427
-0.599598
-0.34391
--0.251222
-0.0722894
--0.0132524
--0.121936
-0
-0.280136
--0.0385038
--0.0340917
--0.0341234
-0.189934
--0.159498
-0.0535638
--0.084728
-0.132382
-0.340775
-0.187767
-0.0546701
-0.100955
-0.138189
--0.118275
--0.0376879
-0.102263
-0.196962
--0.120125
--0.0726267
--0.159172
-0.158535
-0.324982
-0.290117
-0.212224
-0.205632
-0.274948
-0.39956
-0.147086
-0.0173712
-0.15542
-0.510478
-0.328532
-0.465153
-0.750997
--0.216939
-0.40052
-0.318137
-0.755928
-1.09625
-0.332654
-0.407634
-0.45068
-0.915355
--0.127311
-0.383893
-0.964434
-0.168117
-0.216077
-0.277416
-1.14598
-0.159498
-0.6386
-0.108728
-1.14329
--0.07571
-0.531044
-0.641128
-0.297914
-0.959879
-0.124955
-0.703623
-0.644392
-0.0899382
-0.293514
-1.29978
-0.31403
-0.725964
-1.52255
-1.01731
--0.14874
-0.595186
-1.08163
-0.538563
-0.821427
-0.164528
-0.333384
-0.739263
-0.317762
-0.325588
-1.64677
-0.267786
-0.735105
--0.314522
-0.39366
--0.0732626
-0.0686713
-0.254621
--0.254999
--0.259666
-0.198398
-0.310123
-0.666748
--0.131948
-0.10914
-0.49118
-0.746293
-0.659715
-0.450968
-0.446731
--0.199873
-0.248864
--0.0659404
-0.0575381
-0.0517405
-0.193657
-0.0545491
--0.162053
--0.0890028
-0.347272
-0.194497
-0.0179937
--0.216501
--0.399752
--0.0356124
--0.0383345
--0.335833
-0.0724347
-0.0169756
--0.126025
-0.296721
--0.0883202
-0.253257
--0.0158012
-0.563857
-0.0176757
-0.33061
-0.133249
-0.197538
-0.247642
--0.180877
-0.0658777
--0.209262
-0.131252
-0.307706
--0.0353747
--0.0142002
-0.0179267
-0.437374
-0.125058
-0.197011
-0.107035
--0.215431
-0.258709
-0.107061
--0.071967
-0.356967
--0.17211
-0.13031
-0.0170234
-0.501928
-0.0182871
-0.479037
--0.0369923
--0.448387
-0.258766
-0.144653
--0.0364188
-0.0174908
--0.0900174
-0.444927
-0.350903
-0.257159
-0.106084
-0.264941
-0.310022
-0.889574
-0.44759
-0.294244
-0.194484
-0.858983
-0.421183
-0.258568
-0.261243
--0.246743
-0.474111
-0.272091
-1.32953
-0.251346
-0.230751
-0.168617
-0.699067
-0.222865
-0.0744445
-0.653865
-0.326876
-0.0361257
-0.126031
-1.0706
-0.595112
-0.59219
-0.395266
-0.672173
-1.01659
-1.39319
-0.405863
-0.829932
-1.14904
-1.81722
-0.120927
--0.036167
-0.69995
-0.705744
-0.551422
-0.676648
-0.359052
-0.866228
-0.191618
-0.365179
-0.247366
-0.28629
-0.722067
-0.632495
-0.017368
-0.0742885
-0.0174071
-0.895838
-0.349834
-0.497196
-0.106665
-0.653837
-0.391733
--0.127786
-0.222725
-0.121479
-0.311335
-0.26174
--0.246651
-0.0574959
--0.0352867
-0.235292
-0.0188615
-0.0167277
-0.251232
-0.277552
--0.214687
-0.616179
--0.122696
-0.189853
--0.0719423
-0.486139
-0.576616
--0.0154973
-0.108156
-0.0557736
-0.709559
-0.193067
-0.160402
--0.018614
-0.417799
-0.193951
-0.289086
-0.198888
--0.173856
-0.134013
-0.156923
-0.147888
-0.110295
-0.468957
-0.29106
-0.104408
-0.0166945
-0.143637
-0.0175638
-0.146015
-0.311077
--0.206014
-0.0173207
--0.26383
-0.248741
-0.292555
-0.057912
--0.123174
-0.269944
-0.0528314
-0.395075
-0.435051
-0.207004
-0.648443
--0.294176
-0.244037
-0.0776869
-0.299732
--0.0543246
-0.376283
-0.499297
--0.0364322
--0.0948148
--0.165457
-0.412701
-0.124009
--0.172847
-0.0181655
-0.348612
-0.545607
-0.324529
-0.310639
-0.140503
-0.511452
-0.0177709
-0.157982
--0.263714
-0.168655
-0.137548
-0.184444
-0.518953
-0.633184
-0.536947
-0.700031
-0.156831
-0.273733
-0.603647
-0.823983
-0.322473
-0.427168
-0.18879
--0.166424
-0.530718
--0.0578538
--0.150914
-0.167468
-0.910741
-0.657636
-0.947699
-0.54858
-1.33772
-0.961394
-1.22442
-0.70402
-0.383684
-0.449954
--0.120756
-0.333581
-0.462293
-0.678929
-0.75729
-0.683774
-0.391007
-0.903539
-0.145684
-0.388251
-0.262495
-0.545728
-0.690906
--0.305438
-0.999566
-0.195175
-0.729577
--0.074314
-0.324961
--0.254486
-0.018767
-0.0676495
-0.0180729
-0.127258
--0.230158
-0.164105
-0.0338826
-0.0166671
-0.546429
--0.122718
--0.183885
-0.108287
--0.160008
-0.265245
-0.392086
-0.233286
--0.0734927
-0.198331
--0.252283
--0.440145
-0.020387
-0.253964
-0.0195592
-0.51346
--0.0691468
--0.0351544
-0.400945
-0.0189164
-0.0531008
-0.0179421
-0.158867
-0.149098
--0.0352789
--0.0161663
-0.0506395
--0.0745027
-0.567333
-0.548358
-0
-0.289726
-0.320876
-0.318071
--0.0724109
-0.33558
-0.331523
--0.091332
--0.0911281
-0.0541565
-0.284414
-0.136311
-0.159905
-0.281294
-0.433656
-0.115034
-0.0354898
-0.108713
-0.107106
--0.181133
--0.38648
-0.113548
-0.0170607
-0.115229
-0.173498
--0.403048
-0.104356
-0.307724
-0.136054
-0.0566499
-0.0172298
--0.0368607
-0.0172991
--0.205329
-0.0528198
-0.0690788
-0.468877
-0.327801
-0.643514
-0.105597
-0.361022
-0.0365873
--0.254112
-0.464685
--0.0183755
-0.973598
--0.158384
-0.125667
--0.226521
-0.301277
-0.407746
-0.249626
-0.240377
-1.02495
-0.879185
-0.315607
-0.157021
-0.582077
-0.227186
-0.878556
-0.0722381
-0.467558
-0.853775
-1.34049
-1.25179
-0.622276
-0.455307
-0.421258
-0.69281
-0.423357
-0.281981
-0.950056
-0.590258
-1.06779
--0.264398
-0.22398
--0.109986
-0.344011
-0.0367736
-0.447579
-0.159477
-0.0180483
-0.737131
-0.105214
-0.884955
--0.127913
-0.373364
--0.125344
-0.0186333
-0.0166422
-0.658266
-0.193527
-0.110237
-0.203015
-0.0170476
-0.293942
-0.386468
-0.971938
--0.0392189
-0.435976
-0.299432
--0.016234
-0.337798
-0.253476
--0.210026
-0.430828
-0.294254
-0.300128
-0.0170602
-0.145771
-0.0169476
-0.296402
-0.160301
--0.350443
-0.154878
-0.670966
--0.0356324
--0.12401
-0.103011
-0.334366
-0.105075
-0.581592
-0.602685
-0.132278
-0.0534402
-0.100479
-0
-0.269776
-0.105219
-0.103938
-0.619768
--0.117438
-0.253039
--0.327154
-1.10313
--0.033729
-0.139822
-0.135676
--0.0926366
-0.0686864
-0.209348
--0.214125
-0.0176742
-0.200051
--0.0916664
-0.331522
-0.0185378
--0.0342976
--0.0760495
-0.105915
-0.199471
--0.394594
-0.317678
-0.471666
--0.185076
-0.0737141
-0.625493
-0.0178751
--0.166862
-0.717935
-0.809155
-0.0169299
-0.315921
-0.193859
-0.469683
-0.429995
-0.581251
-0.389409
-0.112092
--0.345708
-0.183267
-0.784581
--0.0366594
-0.534338
--0.0164929
--0.249752
-0.433255
-0.175575
-0.360094
-0.106571
-0.863484
-0.109627
-0.75647
-0.552122
-0.424255
-0.596999
-0.4767
--0.0702105
--0.0581715
-0.900761
-0.558539
-0.161841
-0.258532
-0.1599
-0.479428
-0.33185
-0.542343
-0.0935116
--0.158484
-0.596737
-0.939245
-0.823731
-0.230241
-0.537382
-0.45323
--0.0149798
-0.680938
-0.251553
-0.169139
-0.709518
--0.110846
-0.108657
-0.018445
-0.12946
--0.0945314
-0.523934
-0.110827
-0.249674
-0.614543
-0.0173285
-0.404441
-0.161207
-0.198088
-0.151309
-0.241371
-0.104892
-0.399881
--0.241731
-0.191936
-0.34949
-0.160347
-0.39293
-0.339302
-0.416005
--0.0690458
--0.345223
-0.257785
-0.190645
-0.456084
-0.142565
-0
-0.105845
--0.034814
--0.149292
-0
--0.152299
-0.185138
-0.10649
--0.119611
-0.189163
--0.0874219
-0.0558589
--0.0352562
-0.217965
--0.0862721
--0.0369852
-0.0171563
--0.1406
-0.35751
-0.293355
-0.595888
-0.596269
--0.262954
-0.328504
-0.0173595
-0.3036
-0.0513357
-0.0547508
-0.0202243
-0.0787518
-0.196328
--0.318617
-0.192307
-0.747213
--0.0894584
--0.383384
-0.425337
--0.0771479
-0.349449
-0.446017
-0.545687
-0.19487
-0.0542883
-0.309026
-0.124815
--0.0374811
-0.0201449
-0.0532769
-0.255289
-0.694865
-0.0743489
-0.546431
--0.0166579
-0.311409
--0.0379699
-0.112724
-0.22563
--0.297539
-0.420401
-0.31608
-0.617501
--0.131176
-1.08615
-0.478376
-0.0696543
-0.220271
--0.49487
-0.701237
-0.455908
-0.527172
--0.309773
-0.54566
-0.746833
-0.216299
-0.26085
-0.462097
--0.0181904
--0.106574
-0.218067
-1.02738
-0.583205
-0.0372002
--0.198069
-0.405984
-0.438772
--0.245596
--0.0192385
-0.415733
--0.201738
-0.306445
-0.194188
-0.204358
-0.103136
-0.523242
--0.261685
-0.829361
-0.365636
-0.276065
--0.264287
-0.612888
-0.197666
--0.0168388
-0.491264
-0.1656
-0.0562109
-0.0725031
--0.036543
-0.33422
--0.185994
-0.506359
-0.260874
--0.183264
--0.411415
--0.21343
-0.0182598
-0.202066
-0.619872
-0.230509
-0.329211
--0.127684
--0.311427
-0.120636
--0.307354
--0.268454
-0.352282
-0.26578
-0.282604
-0.20439
--0.174668
-0.249091
-0.159547
-0.416815
--0.0888347
-0.279817
-0.185211
-0.194026
--0.0689132
-0.342388
-0.102044
-0
--0.0341405
--0.0349809
-0.192951
-0.241485
-0.269499
-0.187393
--0.0864263
-0.245033
-0.201269
--0.0349962
-0.05382
--0.10152
-0.143339
-0.10752
-0.0414288
--0.0904103
-0.359202
-0.484858
-0.0527837
--0.359145
--0.035473
-0.643385
--0.0389931
-0.253204
-0.213472
-0.332417
-0.106577
--0.128671
--0.128461
-0.338408
--0.660014
-0.217767
-0.401903
-0.192891
-0.204849
-0.247849
-0.537542
-0.596798
-0.0584758
-0.0557035
--0.315482
--0.0167541
--0.0874557
--0.0727781
-0.170055
-0.395669
-0.0374617
-0.512524
-0.0376392
-0.249622
-0.518571
-0.463963
--0.0195096
-0.0561797
--0.170602
-1.07885
--0.0376813
-0.508273
-0.501233
-0.943346
-0.513403
--0.0387118
-0.11086
-0.483686
-0.134051
-0.411863
-0.602432
-0.174085
-0.0186766
-0.44618
-0.220631
-0.0179811
-1.06767
-0.555071
-0.173305
-0.549914
-0.633554
-0.793961
-0.952742
-0.412268
-0.306383
-0.339607
-0.38044
-0.340919
-0.650006
-0.353113
--0.263421
-0.497562
-0.538759
--0.0377694
--0.288338
-0.146559
--0.0998809
-0.109269
--0.371725
-0.305716
-0.683657
--0.267734
-0.219955
-0.311543
-0.64435
-0.597694
-0.106873
--0.0760838
-0.117507
--0.072213
--0.216145
-0.16674
-0.266323
--0.0160834
--0.134608
-0.205518
-0.0705333
-0.250161
--0.0371737
-0.0753421
-0.0202112
--0.0367477
--0.309299
-0.248274
--0.092789
-0.411664
-0.161955
--0.133649
-0.171093
--0.0989985
-0.268465
-0.249578
-0.0520327
-0.0186101
--0.132999
-0.0191399
-0.129427
-0.353537
--0.034194
-0.256149
--0.0165641
-0.204969
-0.194123
-0.245385
--0.0895923
--0.180882
-0.16268
--0.0365012
-0.0540298
-0.284995
-0.159401
-0.494351
-0.0721022
-0.0540265
-0.145293
-0.138916
-0.243312
-0.213092
--0.036923
-0.239645
-0.0537967
-0.299011
-0.62545
-0.503278
-0.0174428
-0.444027
--0.221025
-0.47128
--0.451234
-0.107496
--0.0712465
--0.456727
-0.036349
-0.479343
-0.318698
--0.0372605
-0.0184969
-0.157687
-0.154592
-0.183804
-0.623694
-0.575987
--0.15935
--0.0166472
-0.296874
-0.375667
-0.420864
-0.0545346
-0.252932
-0.0186557
-0.860969
-0.610982
-0.4573
-0.29839
-0.724711
-0.220972
-0.393302
-0.630495
-0.017256
--0.261118
-0.269632
--0.174549
-0.59914
-0.645373
-0.316039
-0.893066
--0.0351894
-0.209425
--0.0739741
-0.346671
-0.126992
-0.99132
-0.389946
-0.0383671
-0.299541
-0.220192
-0.25641
-0.493634
-0.212043
-0.0173796
--0.13135
-0.695636
-0.57765
-0.0873037
-0.163355
-0.161052
-0.531303
-0.210866
--0.0757022
-0.257931
--0.0725878
--0.186662
-0.0170907
-0.333092
-0.0172145
-0.102368
-0.0493546
-0.639225
--0.0706266
-0.164712
-0.105455
-0.276634
-0.445351
-0.399685
-0.0718307
-0.106301
-0.0171526
--0.0356622
-0.476957
-0.429521
--0.0694264
-0.0677609
-0
-0.305373
-0.137074
-0.139968
-0.274166
-0.108715
--0.035792
--0.123822
--0.267531
-0.0735391
--0.121708
-0.190598
--0.165959
-0.0530413
-0.331969
--0.319113
-0.144592
--0.015334
-0.201153
-0.290492
--0.102116
--0.154406
-0.258595
--0.0345217
--0.075199
-0.145003
-0.24407
--0.185171
-0.0700721
-0.330027
--0.130115
--0.128032
-0.148757
--0.0350141
-0.447551
--0.0926657
--0.129673
-0.20907
-0.0177273
-0.0699135
-0.248513
-0.19959
--0.0369648
--0.130604
-0.109688
-0.31759
-0.26657
-0.416905
-0.382632
-0.30758
--0.0370123
-0.106368
-0.172284
-0.072975
-0.617498
-0.194614
-0.0175169
-0.205227
-0.810329
-0.416346
-0.29854
--0.110289
-0.167647
-0.156503
-1.06901
-0.184557
--0.133487
-0.320531
-0.629524
-0.762665
-0.830478
-0.0721309
-0.203597
--0.12988
--0.157127
-1.02737
-0.573557
-0.219077
-0.413598
-0.0712381
-0.360065
-0.38173
--0.252977
-0.11095
-0.412101
-0.247615
-0.260973
-0.647307
-0.411199
--0.251543
-0.21745
--0.355203
-0.948623
-0.258637
-0.162071
-0.521309
--0.128869
-0.251666
-0.174618
-0.377535
-0.165489
--0.0721835
-0.174865
-0.246847
--0.0138493
--0.0372844
--0.394141
-0.107814
-0.24982
--0.278596
--0.362902
-0.161825
-0.345838
-0.390101
--0.179785
-0.50552
--0.0722954
-0.192985
-0.521468
-0.01835
--0.371047
-0.106795
--0.127393
-0.107377
-0.0171248
-0.194715
-0.202843
-0.0513725
-0.0171146
-0.0172929
-0.531877
-0.251213
-0.0392385
-0.110737
-0.0517569
-0.148803
-0.0520116
--0.0365531
--0.207901
--0.223747
--0.12131
-0.110444
-0.0194337
--0.0392722
-0.351574
--0.0709441
-0.39823
--0.434532
--0.130789
-0.471622
-0.200993
--0.109371
-0.12602
-0.286861
-0.333553
-0.439713
-0.160668
-0.249419
-0.294564
-0.261049
--0.106184
-0.165845
--0.0909675
--0.186541
-0.144166
-0.3855
--0.0936618
-0.257485
-0.623304
-0.20122
-0.856327
-0.68704
--0.0378285
-0.769374
-0.288802
--0.0751954
-0.274685
-0.230687
--0.180437
-0.538211
-0.19236
-0.0562022
-0.471299
-0.906635
-0.108157
-0.130732
-0.217619
-0.49488
--0.163629
--0.130457
-0.0180497
-0.0169386
-0.365956
-0.317021
-0.162615
-0.108464
-0.765086
--0.363403
-0.125488
-0.150422
-0.396589
-0.107082
-0.168392
--0.0395115
-0.652915
-0.259345
-0.184707
-0.247716
--0.0355815
-1.28779
-0.16163
-0.530001
--0.378869
-0.110367
-0.757493
-0
-0.25533
-0.270022
-0.26398
-0.309881
-0.291841
--0.110779
-0.252546
--0.181624
-0.171751
-0.852816
-0.540249
--0.13423
-0.198257
--0.189401
--0.368224
-0.716672
-0.209864
-0.112478
-0.255036
-0.0185825
-0.240272
--0.425872
--0.129405
--0.220998
-0.163543
--0.0362806
-0.113131
-0.114047
-0.312576
-0.403296
--0.262694
--0.0722307
-0.20229
-0.438922
-0.190508
-0.331832
-0.10236
--0.160417
--0.0370241
-0.0540014
-0.191364
-0.0178809
-0.402886
-0.108213
-0.202653
--0.0514926
--0.123334
--0.25781
-0.42658
-0.729144
-0.245876
-0.0171051
--0.0337291
-0.312622
-0.0524668
--0.303754
-0.302525
--0.250768
-0.232733
-0.62433
--0.276961
--0.157315
--0.318119
-0.189572
--0.0384825
-0.0720465
-0.0532983
-0.0554099
--0.0165509
--0.0375367
--0.0390906
-0.252767
-0.0591742
-0.21183
-0.293568
-0.464383
-0.0176627
-0.481879
--0.341098
-0.202306
--0.0396846
-0.15231
-0.319517
--0.0375244
--0.0771853
-0.051835
-0.116144
-0.110617
-0.202929
-0.588749
-0.264785
-0.338867
--0.33769
--0.319348
-0.0567038
-0.018224
-0.210596
-0.108084
-0.244
-0.219939
-0.308472
-0.0180876
-0.15151
-0.245508
-0.621968
-0.309572
--0.0190596
-0.0759786
--0.36923
-0.513774
-0.73616
-0.110665
-0.663856
-0.0408471
-0.602715
-0.257125
-0.297815
-0.60309
-0.42098
--0.0380077
-0.148031
-0.018198
--0.304586
-0.110374
-0.225331
-0.108207
-0.252088
-0.0549509
--0.0164247
--0.11006
-0.50387
-0.112045
-0.0596339
--0.251495
-0.47167
-0.528752
-0.21744
-0.302193
-0.0569321
-0.0749437
-0.219593
-0.171435
-0.403583
-0.361472
-0.267779
--0.14112
-0.247233
--0.161498
-0.481003
-0.23379
--0.132129
-0.192569
-0.164969
--0.128946
--0.0170753
-0.247037
--0.128214
--0.0360706
--0.0699252
-0.368546
-0.470669
-0.248831
-0.716773
-0.536694
-0.0528532
-0.147575
--0.0889781
-0.206315
--0.125185
-0.0539546
-0.138032
-0.295569
-0
-0.0543683
-0.186463
--0.0943453
--0.273918
-0.112971
-0.270532
-0.150839
--0.170265
-0.30118
--0.122015
-0.360169
-0.245945
-0.160166
-0.752979
-0.0568409
-0.0536603
-0.110518
-0.0514029
-0.207312
-0.0524343
--0.0384649
--0.0867526
--0.174769
-0.0525351
-0.203962
-0.348383
-0.0177522
--0.222836
-0.263858
--0.0162992
-0.018781
-0.106928
--0.0161908
-0.200769
--0.128022
-0.0176173
-0.417481
--0.129002
-0
-0.197631
-0.412085
-0.109537
-0.470378
--0.159817
-0.152289
--0.174512
-0.112882
-0.212226
-0.22573
--0.0385641
--0.0204422
--0.277481
--0.095432
--0.0356465
-0.110187
-0.0557433
-0.284086
--0.0781803
-0.938278
-0.351168
-0.206052
-0.2213
-0.813178
-0.310892
-0.670753
-0.466889
--0.137611
-0.401271
-0.463653
-0.0719825
-0.171886
-0.166563
--0.257893
-0.202597
-0.443705
-0.127274
-0.440292
--0.128939
-0.0182522
-0.84616
-0.513024
-0.213417
--0.128788
--0.262932
-0.416967
-0.288261
-0.163396
-1.0485
-0.270832
-0.257988
-0.0183887
-0.110681
-0.501199
-0.199735
-0.170055
-0.277003
-0.387747
-0.0738501
-0.110427
--0.0356442
--0.133308
-0.0176163
-0.499448
-0.105671
-0.361457
--0.175673
-0.243707
--0.0355877
-0.262494
-0.162398
-0.150583
-0.459024
--0.119061
-0.106792
--0.253662
-0.017602
-0.107233
--0.266671
--0.275697
-0.294715
-0.145474
-0.251344
-0.140382
--0.435182
-0.152764
-0.303644
--0.220718
--0.0909463
-0.116147
-0.0514383
--0.0892479
--0.17895
-0.33003
--0.06628
-0.0515823
-0.5348
-0.15438
-0.162943
-0.236207
-0.10648
-0.237286
--0.176706
--0.122423
-0.188642
--0.166825
-0.2494
-0.213451
-0.0207505
-0.238757
-0.0519594
-0.187437
--0.157968
-0.470958
-0.14664
-0.101165
-0.550768
-0.0527434
--0.0358611
-0.193435
-0.341855
-0.204252
--0.218054
-0.342574
-0.112072
-0.15425
--0.128246
-0.0524033
-0.0174515
--0.271769
-0.111225
-0.21724
-0.0182476
-0.279848
--0.0898203
--0.0753807
--0.131723
--0.0724823
--0.30736
-0.681847
--0.0711156
--0.174635
-0.236663
-0.441468
-0.385683
-0.169919
-0.11225
-0.439413
-0.336833
--0.0196291
-0.196512
-0.291121
-0.151199
-0.11091
--0.133161
-0.0708464
-0.0352269
-0.788134
-0.0353561
--0.347798
-0.564057
-0.904887
-0.34425
--0.125103
--0.356874
-0.346036
-0.309615
-0.627528
-0.111784
-0.19737
-0.547878
-0.125124
-0.484283
-0.410149
--0.10723
-0.253486
-0.36592
-0.583747
-0.640233
-0.158844
-0.256145
-0.204967
-0.0188866
--0.421517
-0.739855
--0.0917398
--0.0916492
-0.105405
-0.444335
-0.323712
-0.371941
-0.198757
-0.356454
--0.0692559
-0.315932
-0
-0.0173775
-0.289385
--0.0352592
-0.719333
-0.0520836
-0.135954
-0.332441
-0.0176698
-0.281492
--0.159821
-0.206244
-0.0555393
--0.03699
-0.352729
--0.0701325
-0.0166106
-0.0522365
-0.286252
-0.050982
--0.215139
-0.104424
-0.251375
-0.285501
-0.207298
-0.773116
-0
--0.0865895
-0.255388
-0.049945
-0.217769
-0.185229
-0.261367
--0.0361286
-0.0715631
--0.0359644
--0.13818
-0.194343
-0.368376
--0.0384415
-0.0553595
-0.732407
-0.447569
-0.0516946
-0.0536023
--0.284071
--0.0370799
-0.109991
-0.152207
-0.200803
-0
--0.131751
--0.132391
-0.0734378
-0.641476
-0.0194489
-0.256597
--0.0362367
-0.259618
-0.05519
-0.505884
--0.0372575
--0.0375453
-0.353116
-0.425371
-0.190701
-0.364577
-0.0190784
-0.316297
-0.168452
-0.360801
-0.483709
-0.417884
-0.0729004
-0.0710879
--0.0722022
-0.511006
-0.428998
-0.712266
-0.109512
-0.613606
-0.258294
-0.133324
-0.212128
-0.578963
-0.267404
-0.601609
-0.429552
--0.164874
-0.493553
--0.274153
-0.192157
-0.213049
-0.649317
-0.129761
-0.503713
--0.0388825
-0.109508
-1.00941
-0.323896
-0.0184436
-0.11348
-0.121571
--0.0168531
-0.109274
-0.45463
-0.412467
--0.109719
--0.0756891
-0.788641
-0.398541
--0.0371632
-0.465202
--0.0711959
-0.0181183
--0.12972
-0.269789
-0.205754
-0.357942
-0.577914
-0.0531013
--0.131765
-0.619807
--0.163535
--0.280969
--0.262607
-0.106134
--0.03708
-0.193471
-0.285401
-0.111363
-0.0169936
-0.327486
-0.307627
-0.667988
-0.285465
--0.12946
-0.285329
--0.0924342
--0.181816
-0.0175817
-0.505654
-0.0726785
-0.423361
-0.200418
--0.0339957
-0.116222
-0.136697
--0.124218
-0.106447
--0.0969441
--0.0923108
--0.0908538
-0.286245
-0
-0.241687
--0.178316
-0.133471
--0.0907124
--0.154357
-0.191283
-0.247073
--0.0872909
-0.161146
--0.124348
-0.29723
-0.194577
-0.16077
-0.0936268
--0.186311
-0.10743
-0.424684
-0.201695
-0.0542965
-0.284112
--0.12491
-0.0525482
--0.275045
--0.0363315
--0.211587
-0.450093
-0.0541074
--0.088609
-0.204895
-0.357542
-0.443947
--0.125141
--0.0888563
-0.644928
-0.109049
-0.577833
--0.266103
--0.311478
-0.110514
--0.0714802
-0.30071
-0.190827
-0
-0.527889
-0.187477
-0.205713
-0.639058
-0.202505
-0.163866
-0.294791
-0.268044
--0.109225
--0.106607
-0.107881
-0.0180926
-0.0175145
-0.261667
--0.162807
-0.158239
-0.359375
-0.0183739
-0.0733269
-0.212896
-0.0537455
-0.353697
-0.222426
-0.557092
--0.165656
-0.164009
--0.307524
-0.318192
-0.349237
--0.281567
-0.209546
-0.499724
-0.0740095
--0.402564
-0.295718
-0.0176134
-0.105114
-0.106341
-0.484724
--0.131651
-0.163975
--0.266303
-0.163747
-0.249329
-0.344695
-0.410221
-0.255407
-0.723091
-0.246948
--0.130132
-0.108878
-0.403154
-0.49162
--0.0164521
-0.32611
--0.123673
-0.249665
-0.112535
-0.05439
-0.248317
-0.203326
--0.124612
-0.148606
-0.3309
-0.517117
-0.0536239
-0.208794
--0.10836
-0.0176305
-0.340089
-0.40152
--0.170922
-0
--0.15655
-0.33027
-0.254904
--0.128401
-0.137051
--0.176855
-0.402392
-0
-0.136084
-0.145975
--0.0876247
--0.0737881
--0.0847856
-0.349415
--0.0347888
-0.156592
-0.31427
-0
-0.435648
-0.200567
-0.0540913
-0.141093
--0.0132916
-0.355779
-0.278613
-0.147646
-0.286336
-0
-0.145354
-0.153258
-0.0524003
--0.186506
--0.036693
-0.257697
-0.27148
--0.189211
-0.0179824
-0.362816
-0.0544982
-0
-0.0541835
--0.0960213
-0.333761
--0.2828
-0.34325
--0.0719697
-0.345903
-0.155511
-0.201938
--0.0376693
--0.090212
-0.203179
-0.486342
--0.221172
-0.610093
-0.0558686
--0.161509
--0.127442
--0.220052
-0.0177054
-0
-0.547538
-0.0537872
-0.417931
-0.0547461
-0.511048
-0.335782
--0.0739819
-0.0175737
--0.18886
--0.182369
-0.169658
-0.108616
-0.265772
--0.31451
--0.367007
-0.351355
-0.0200981
-0.769805
-0.505476
-0.459032
-0.1111
--0.0762388
--0.282957
-0.110863
-0.290724
-0.454707
-0.296986
-0.525868
-0.202553
-0.15729
--0.0383597
-0.59401
-0.0193889
-0.0172717
-0.364118
-0.31419
--0.0377877
-0.16747
-0.316262
-0.131423
-0.353467
-0.11374
-0.149696
--0.0365111
-0.26217
-0.259328
-0.398723
-0.717798
-0.296038
-0.887839
-0.106482
--0.0723612
-0.44774
-0.0193732
-0.683953
-0.420205
-0.120544
-0.052429
-0.242806
-0.689786
--0.0199078
--0.0355649
-0.160239
-0.25212
-0.21653
--0.211674
--0.036181
--0.127865
-0.107157
-0.287912
--0.162738
-0.66368
--0.0931065
--0.357622
-0.122256
-0.0176132
-0.145991
-0.293928
--0.0181299
-0.0376836
--0.0695472
-0.189185
-0.253285
-0.26969
-0.190888
-0.203387
-0.138687
--0.180282
-0.346716
-0.333679
--0.0894176
-0.195958
-0.0531213
-0.18824
-0.190968
-0.378624
-0.13953
-0.0530293
--0.036943
-0.380626
-0.286244
--0.036289
--0.0748731
-0.109274
-0.129121
--0.076537
-0.110999
-0.298912
--0.0370874
--0.204179
--0.283413
--0.161986
-0.107386
--0.18151
-0.0524652
-0.945515
-0.476306
--0.352229
--0.0930468
-0.256286
-0.481406
-0.608432
-0.298915
-0.447273
-0.0180696
-0.017383
--0.0190413
-0.341679
-0.361017
-0.0682917
-0.321217
-0.627285
--0.0724969
--0.0724043
-0.351536
-0.14921
-0.559102
-0.31361
--0.133613
-0.364286
-0.363162
-0.286707
-0.125059
-0.500285
-0.4624
-0.16948
-0.355835
-0.505764
-0.111283
-0.550298
-0.017692
-0.201059
--0.189375
-0.118449
-0.202108
-0.172489
-0.262533
-0.393343
-0.167562
-0.292495
--0.0365962
--0.224959
--0.0926904
-0.462457
-0.0179896
--0.0779433
--0.0366095
-0.634992
--0.0915443
-0.402361
-0.0188045
--0.224325
-0.35774
-0.20578
-0.0199205
-0.162176
--0.184946
--0.124332
--0.297422
-0.0180838
-0.373364
-0.350856
--0.093368
-0.198431
-0.340245
--0.356387
-0.526826
-0.241948
--0.176875
-0.193454
-0.0513107
-0.210685
-0.0530144
--0.447842
--0.0358525
--0.0372254
-0.098505
-0.391083
-0.488468
-0.106348
-0.243908
-0.442089
-0.157009
--0.128196
-0.511684
--0.0356516
--0.0930231
-0.180862
-0.149198
-0.0188658
--0.0403692
-0.293662
-0.0584164
-0.102804
-0.0581474
-0.279113
--0.167099
--0.035431
-0.499367
--0.0850504
--0.038065
-0.584756
--0.0368723
-0.0495247
-0.347751
-0.155359
-0.056718
--0.0362935
-0.208257
--0.0690606
-0.259814
-0.146793
-0.679231
-0.0530131
-0.203742
-0.165337
--0.130402
-0.0733714
--0.19085
--0.219323
-0
-0.449664
-0.0742661
-0.855436
--0.0899017
--0.186136
-0.502432
-0
-0.072865
-0.368881
-0.721818
--0.352283
--0.134969
--0.0369505
-0.454921
-0.197705
-0.72377
-0.303521
-0.504945
--0.0371415
-0.341497
-0.612524
-0.134402
-0.637712
--0.129618
--0.324777
--0.26177
-0.0742165
-0.214484
-0.0693372
-0.0177945
-0.146599
-0.164061
-0.0175923
--0.0933812
-0.165212
--0.0965206
-0.114748
-0.755668
-0.0529696
-0.056523
-0.599546
--0.282247
--0.395987
--0.0393337
-0.755168
-0.413185
--0.120997
--0.0361449
--0.18221
--0.365663
--0.215183
-0.171676
--0.125427
-0.167386
-0.108897
-0.155035
--0.27945
-0.0182256
--0.0689771
-0.114757
--0.18502
-0.134794
--0.0341056
-0.655583
-0.1036
--0.123277
--0.185414
--0.218475
--0.0184654
-0.205978
-0.104649
--0.0369523
-0.0175807
-0.104855
-0.0521788
--0.0367342
--0.032501
-0.355983
-0.397913
--0.177761
--0.217899
-0.279228
-0.331374
-0.145732
--0.0688133
-0
-0.0526505
-0.0573768
--0.183779
-0.0226758
-0.147075
-0.149809
-0.16138
-0.330373
-0.16004
-0.426809
--0.175785
-0.57142
--0.0361278
--0.256991
--0.0911238
-0.0387783
-0.211445
-0.0161125
-0.0533492
-0.389172
-0.15087
-0.142775
-0.0542692
--0.124847
-0.676557
--0.18445
-0.311034
-0.291098
-0.412097
-0.754019
-0.67063
--0.184016
-0.206351
-0.350556
--0.0378191
-0.29215
-0.663151
-0.299386
--0.0375052
--0.0378355
-0.111622
-0.349734
-0.249966
-0.0556974
--0.27317
-0.108916
-0.262862
-0.34355
--0.128653
-0.201083
-0.0579166
-0.464153
-0.0199892
-0.316207
-0.250314
-0.108813
-0.403217
-0.107201
-0.0542738
-0.235919
-0.4684
-0.560139
--0.171325
-0.509692
--0.178004
-0.687365
-0.257733
--0.447764
-0.53528
-0.0382749
--0.17377
-0.646618
-0.0737538
--0.0770176
-0.116512
--0.396562
-0.206508
-0.361003
-0.110935
-0.318308
-0.171615
-0.05669
-0.211537
-0.110988
-0.89563
-0.399776
-0.0542392
-0.0756139
--0.0365157
--0.036798
--0.0760445
-0.440928
-0.160494
-0.0548106
-0.195896
--0.180439
-0.359234
-0.2578
-0.932979
-0.0566059
-0.506982
-0.491008
-0.432778
--0.0922874
-0.359246
-0.438779
--0.0738174
-0.411079
-0
-0.24067
-0.0170614
-0.381941
-0.111409
--0.0368677
-0.565889
-0.102456
-0.370717
--0.129535
-0
-0.107503
--0.0356135
-0.217192
--0.0361777
--0.0357898
--0.124715
-0.470127
--0.0349657
-0.0561067
-0.0520779
-0.0537695
-0.050286
-0.277723
-0
-0.261679
-0.380912
-0.355124
--0.0339418
--0.0747265
-0.0502215
-0.165512
-0.0496257
-0.0185627
--0.212222
-0.150601
--0.0351195
-0.0214502
-0
-0.759255
-0.592623
--0.202013
-0.0527027
--0.0952296
-0.0502236
-0.45949
--0.0348901
-0.114522
-0.419292
-0.055679
--0.128873
--0.135095
--0.0370799
-0.118884
-0.323552
-0.113716
-0.481266
-0.219277
-0.414482
-0
-0.542487
--0.0385741
-0.0208405
-0.258986
-0.518424
--0.0383547
--0.089454
-0.300487
--0.311454
-0.113035
-0.466736
-0.354897
--0.167241
-0.175675
-0.108388
-0.0389206
-0.137246
--0.0371168
-0.217864
-0.151108
-0.0551644
-0.0565646
--0.0377671
--0.16685
-0.269346
-0.111249
--0.16221
--0.0945213
-0.403943
-0.210836
-0.187619
-0.0187903
-0.168035
-0.172852
-0.304229
--0.0756026
-0.220943
-0.266049
-0.0181193
-0.56072
--0.184841
-0.303655
-0.077264
-0.108601
-0.0379711
--0.343498
-0.290467
-0.242774
-0.25417
-0.270371
--0.162801
-0.117032
-0.131426
-0
-0.111118
--0.227154
-0.356746
-0.463643
--0.132466
-0.511231
--0.033119
--0.0408066
-0.0725786
--0.0980755
--0.0692355
-0.208593
-0.0170355
--0.0369658
--0.266645
-0.209606
-0.109026
-0.372408
--0.0360403
-0.0183361
--0.0932984
--0.413262
--0.0713901
--0.190695
-0.338131
--0.131067
--0.0683146
--0.0402306
-0.0204388
-0.608625
-0.195349
-0.0740843
-0.14021
-0.462882
--0.213208
--0.390057
-0.436867
-0.0662166
-0
-0.0561224
-0.199531
-0.0169612
--0.258069
-0.0169869
-0.183572
-0.339781
--0.227177
-0.241452
-0.108771
-0.184929
-0.0541353
-0.0994316
-0.396557
-0.0522601
--0.0381009
-0.0523217
--0.13117
--0.0342455
--0.0926973
--0.0731622
-0.437201
--0.0367315
-0.0567719
-0.196049
--0.192453
--0.0901098
--0.036503
-0.0709011
-0.335378
--0.0736452
-0.136185
--0.0164555
--0.186534
-0.295625
-0.257956
-0.215363
-0.115902
-0.0549238
-0.0177104
-0.171338
--0.190392
-0.0539441
-0
-0.0202264
--0.0364048
-0.204301
-0.256287
--0.13045
--0.223731
-0.128606
-0.0559229
-0.151002
-0.398854
--0.0778683
-0.501633
-0.21174
-0.0526159
-0.354483
-0.203684
--0.0388254
-0.0177209
--0.196598
-0.29551
--0.0923025
-0.110926
-0.111188
-0.0203736
-0.67196
-0.571127
-0.225627
-0
-0.269861
-0.963778
--0.61155
-0.410602
-0.299794
--0.0169052
-0.35425
--0.224309
-0.052602
-0.104958
--0.16257
-0.303423
-0.0199979
-0.0576844
-0.289805
-0.0761856
-0.107192
--0.190404
--0.188113
--0.144684
--0.0947161
-0.0591591
-0.257616
-0.0208272
-0
-0.50621
-0.163799
-0.294171
-0.209918
-0.105774
-0.0515067
--0.0959072
--0.123648
-0.0196846
--0.129449
-0.017202
-0.268998
-0.110947
-0.294559
--0.173768
--0.190262
--0.257104
--0.0911843
--0.0358505
-0.190231
--0.0348103
-0
-0.194036
-0.389789
-0.0569833
-0.108416
-0.386005
--0.132108
-0.0530874
-0
-0.210767
--0.103305
--0.133216
-0.0601053
-0.244641
-0.162545
--0.20644
-0.160063
-0.300419
-0.334265
-0.191733
--0.132052
--0.126863
-0
-0.240153
--0.226658
--0.152483
--0.39174
--0.0364742
-0.270819
--0.185642
-0.0615472
-0.253316
-0.425071
-0.206237
-0.0767895
-0.343009
--0.141586
-0.361551
-0.15719
--0.189915
--0.199207
-0.124312
-0.514747
-0.250308
-0.118876
-0.0544033
-0.317119
-0
-0.37987
--0.314539
--0.228059
-0.11161
-0.0600763
-0.106623
-0.211365
-0.152292
-0.275771
--0.0366303
-0.492514
--0.0884187
--0.0737258
-0.306112
-0.549794
-0.146401
-0.223415
--0.135356
-0.528482
--0.130097
-0.151066
-0.432248
-0.139179
--0.129061
-0.120233
-0.812402
-0.173989
-0.143962
-0.314489
-0.497022
--0.193626
-0.755848
-0.282306
-0.519687
-0.0185059
--0.467987
-0.114998
-0.343602
-0.217999
-0.466204
-0.273988
-0.634338
-0.343065
-0.373034
-0.019237
-0.196913
--0.0393586
-0.202607
--0.413279
--0.0945103
-0.0189104
-0.595941
-0.309124
-0.40733
--0.187367
-0.730143
-0.216242
--0.0367607
-0.0597263
-0.146638
-0.60588
-0.144495
-0.116616
--0.1856
-0.330997
--0.097214
-0.448868
-0.291706
-0.161755
-0.0549439
-0
--0.131958
-0.071723
-0.302864
-0.0562229
-0.0739202
--0.334563
--0.128076
--0.132336
--0.175064
--0.168016
-0.201841
-0.0569132
--0.0374904
-0.302977
-0.28539
-0.207461
-0.205766
--0.220132
-0
-0.0537539
--0.0835718
-0.0529158
--0.0816254
--0.071545
--0.164361
-0.417835
-0.192506
-0.184694
-0.104512
--0.0354584
-0.334761
-0.197654
-0
-0.48008
-0.19826
-0
-0
--0.307451
-0.63005
--0.036607
-0.016509
--0.122809
-0.249968
-0.145159
-0.104359
-0.1407
-0.450178
--0.38254
-0.276404
-0.245795
-0.0728955
-0.286089
-0.263391
--0.26681
-0.251682
--0.215495
-0.0709746
--0.166919
-0.649248
-0.201061
-0.210806
-0.196026
--0.105789
-0.368144
--0.484509
-0.286635
--0.0383632
--0.271115
--0.16638
-0.251179
-0.138737
-0.361593
-0.145097
-0.225563
-0.141391
--0.0370157
--0.127482
-0.0177962
-0.430743
--0.075116
--0.542908
-0.501885
--0.0715234
--0.127682
--0.164449
-0.147921
-0.018186
--0.47067
-0.0973121
--0.0938896
-0.24643
-0.29047
-0.302824
--0.0369223
-0.589399
-0.266497
--0.0380168
-0.127101
-0.30361
--0.0749306
--0.21858
-0.16213
-0.443223
--0.279291
-0.0597701
-0.0741015
--0.22083
-0.107433
--0.135987
-0.194867
--0.0381969
-0.165248
--0.0383361
-0.60231
-0.380501
-0.194731
--0.0742704
-0
-0.104039
--0.226987
-0.242021
--0.167349
-0.0180279
-0.141984
-0.142525
-0.0532703
-0.0168746
-0.113655
--0.0367251
-0.0693936
--0.209639
-0.204506
-0.259085
-0.628923
-0.193818
-0.290417
-0.303517
-0.200241
-0.0536009
--0.034805
--0.124035
--0.0364183
-0.0503132
--0.12326
-0.0538471
-0.161983
--0.0140384
-0.152548
-0.136175
--0.0946344
-0.434411
-0.0560995
-0.190572
--0.20003
-0.193265
-0.149775
-0.0167418
-0.116843
-0.272177
-0.151136
-0.250885
-0.111008
--0.03543
-0.133211
-0.347195
--0.0388014
-0.470184
-0
-0
-0.114761
-0.70571
-0.570355
--0.0722924
-0.447084
-0.0567471
-0.1186
-0.439957
--0.188531
-0.644955
-0.305174
-0.395037
--0.133199
-0.484832
--0.0966014
-0.348462
-0.214156
--0.0933738
-0.510057
--0.12853
-0.055967
-0.0187277
-0.265371
--0.0388733
--0.0168509
-0
-0.0211298
-0.779383
-0.208539
-0.650855
-0.783534
--0.22172
-0.298476
-0.30707
-0.215542
-0.442078
-0.115496
-0.409499
-0.5063
-0.258026
-0.375243
-0.2269
-0.901623
--0.213026
-0.207461
--0.413406
-0.152914
-0.314454
-0.262594
-0.0550841
-0.0566809
-0.172727
--0.28188
-0.409744
-0.269221
--0.184146
--0.136481
-0.0176722
--0.236282
-0.29385
-0.115895
-0.109265
-0
-0.377448
--0.223318
--0.0378183
-0.321079
-0.502694
--0.291497
-0.284084
-0.223024
-0.0184984
-0.265178
--0.037252
-0.444814
-0.657939
-0.356245
--0.131388
-0.0554835
-0.352442
-0.14118
--0.168277
--0.189926
-0.018349
-0.269611
--0.269846
-0.180418
-0.0522948
--0.130493
-0.19401
-0.172198
-0.140696
-0.307594
--0.0709709
--0.194331
--0.0924026
-0.111706
-0.146261
-0.304794
--0.0361347
-0.360222
-0.433018
-0.0189821
--0.275741
--0.107643
-0.208582
-0.158987
-0.139815
-0.0562741
-0.334685
-0.197243
--0.17169
--0.185393
-0.102319
-0.291648
--0.0928985
-0.106987
-0.357687
-0.167504
--0.22672
-0.346146
--0.0380714
-0.200877
--0.0385426
-0.199557
--0.0355369
-0.201561
-0.108506
-0.107134
-0.263442
--0.0926839
-0.464401
-0.151703
-0.518967
-0
--0.221471
--0.0972167
-0.120159
-0.0572032
-0.15778
--0.0990916
-0.569029
-0.0559187
-0.150285
-0.0188279
-0.0566314
-0.0559701
--0.0379037
-0.0581622
--0.0927115
-0.209717
-0.433666
-0.225257
-0.344334
-0.367695
-0.19668
-0.151334
--0.186842
-0.257814
-0
-0.0220279
-0.199584
--0.18602
-0.309854
-0.53001
-0.263972
-0.346411
-0.0560602
-0.496474
--0.131842
-0.205978
-0.0180306
-0.390118
-0.349835
-0.356915
-0.262668
-0.370239
-0.112854
-0.310159
-0.482582
-0.733504
--0.184731
-0.611306
--0.0739347
--0.190262
--0.0160264
-0.128178
--0.2088
--0.0730525
-0.395072
-0.108058
--0.130771
-0.11313
--0.0745896
-0.106874
--0.0947029
--0.130177
-0.266176
-0.310878
-0.276302
--0.0884598
-0.0170909
-0.148367
--0.0946645
-0.625485
-0.054175
-0.25969
-0.242837
-0.235688
-0.144485
-0.0761417
--0.181067
-0.107025
-0.196346
-0.204064
-0.639744
-0.302352
-0.0538399
-0.403022
--0.277281
-0.192118
-0.141913
-0.0537639
-0.391289
--0.125342
-0.142212
--0.182124
-0.294162
-1.07284
--0.0349101
-0.342883
-0.162238
--0.203546
-0.295525
--0.0390417
-0
-0.146716
-0.401769
--0.275327
--0.0338484
-0.0536936
-0.016913
-0.146589
-0.244864
-0.476878
--0.267557
-0.206627
--0.174746
-0.053872
-0.152008
-0.260052
-0.107463
-0.169422
-0.0521075
-0.422738
-0.700929
-0.252773
--0.0376452
-0.0214392
--0.235183
-0.0187596
--0.124908
-0.155756
-0.289227
-0.36311
-0.204534
-0.0585353
-0.0556921
-0.56996
--0.0352713
--0.0383854
--0.189144
--0.131914
-0
--0.195907
-0.344893
-0.0824879
--0.293415
-0.0575161
--0.0737565
--0.0370977
-0.164676
--0.0955882
-0.205655
--0.0386885
--0.0918111
-0.0186157
--0.208678
-0.203075
-0.0566281
-0.149679
-0.072892
-0.0593579
-0.200716
-0.0180554
-0.272046
-0.379297
-0.307485
-0.409934
-0.107817
-0.519419
-0.641139
-0.457129
-0.0178058
--0.13484
-0.357437
-0.25968
--0.131849
-0.218341
-0.592131
-0.110913
-1.12662
-0.606445
-0.437951
-0.206536
-0.0745396
-0.215477
--0.177943
-0.268815
--0.473113
--0.380324
-0.147382
-0.114626
-0.316056
--0.0377044
--0.127557
-0
-0.255577
-0.508964
--0.0696945
-0.176091
-0.29771
-0.0565097
-0.187896
--0.411759
-0.2987
-0.435276
-0.265365
-0.459158
-0.0547575
--0.0938287
-0.293124
-0.0592447
-0.347085
-0.143203
-0.0521496
-0.293459
--0.361105
--0.0375611
-0.0520958
-0.204039
-0.56031
-0
-0.287635
-0.212593
--0.0377069
-0.491148
-0.0514593
--0.195139
--0.039043
-0.0624846
-0.109127
-0.301085
-0
-0.341888
-0.294667
--0.0871976
--0.0344153
-0.0555963
-0.0526041
-0.335978
-0.164786
-0.0168683
-0.0693505
-0.0521437
-0.0549988
-0.26009
-0.282158
-0.147959
-0.285483
-0
-0.0539396
-0.207158
-0.334904
-0
-0.231094
-0.208695
-0
-0.106544
-0.157706
--0.0376313
--0.0328547
--0.0916127
-0.11045
--0.0383796
-0.537232
-0.432644
--0.0359793
-0.224018
-0.0540123
--0.0793083
-0.511983
-0.176049
-0.262954
--0.09396
-0.147636
-0.266572
-0.0725187
-0.263765
--0.223047
-0.412579
--0.285419
-0.168939
-0.0540695
--0.140212
-0.10965
-0.370177
-0.203245
--0.0378253
-0.260085
-0.0189994
-0.290362
--0.323911
-0.105138
-0.210635
-0.0559601
-0.113002
-0.29548
-0.336634
-0.162847
--0.0387527
-0.110265
-0.148163
-0.0566031
-0.0556328
-0.22598
--0.306518
-0.43472
--0.192411
--0.123746
-0.110102
-0.202354
--0.131327
-0.017851
-0.332234
-0.191755
--0.0727562
--0.199044
--0.0915568
-0.110686
-0.287642
-0.0724655
-0.0578567
--0.135391
-0.354608
-0.318036
--0.130999
-0.0557686
--0.223515
-0.50212
--0.0169577
-0.555073
-0.108779
--0.126973
--0.0352946
-0.527938
-0.105838
-0.0507927
-0.0560027
-0.142076
-0.151101
-0.055654
--0.0356291
-0.251634
--0.129703
-0
-0.161928
-0.108391
-0.584697
--0.177602
-0.152972
-0.0537133
--0.180335
-0.59213
-0.104112
-0.105945
-0.203301
-0.0513157
-0.170621
--0.0937461
--0.407356
--0.209511
-0.153352
--0.168621
--0.134047
-0
--0.187679
--0.0355989
-0.17909
-0.196176
-0.45338
-0.113103
-0.209561
-0.146682
-0.0578898
-0.0525205
-0
-0.0529381
--0.093159
--0.287189
--0.0382893
-0.328338
--0.0384848
-0.262496
-0.157998
-0.0544075
-0.0553466
-0.259763
-0.0551473
-0.196976
--0.133917
--0.220535
--0.0970395
-0.0542527
-0.362511
-0.284515
--0.0942681
-0.112748
-0.492847
-0.15343
-0.112859
-0.204298
--0.0397227
-0.413767
-0.372385
-0.27012
-0.563244
-0.160978
-0.121026
-0.439391
--0.0169118
-0.0519622
--0.1916
--0.0371911
-0.41563
--0.0167979
-0
--0.0936232
-0.370043
-0.107526
-0.112903
-0.0179335
-0.203315
-0.0526893
-0.174234
-0.111498
--0.0396524
-0.204934
-0.200809
-0.778464
-0.379359
-0.0759505
-0.112389
-0.114282
-0.111458
-0.180746
-0.11608
--0.037691
--0.0383838
-0.10618
--0.0192075
--0.0701589
--0.312636
-0.400197
--0.0380631
-0.408376
-0.211805
--0.0369757
--0.29243
-0.512703
-0.107474
-0.285782
--0.0380514
--0.0367871
-0.305253
-0.346898
-0.110318
-0.584265
-0.0575477
-0.0173792
-0.265219
--0.12276
-0.251943
-0.0566212
-0.166477
-0.163656
-0.108627
--0.0881703
-0.0544588
-0.0555295
-0.664816
-0.209203
--0.181911
--0.0859628
-0.286636
--0.0160148
-0.0561254
-0.143711
-0.288485
-0.143711
-0.0567389
-0.158424
--0.0381703
-0.287518
--0.377974
-0.486495
-0.220415
--0.0895781
-0.113173
--0.278847
--0.129786
-0.0520535
--0.187889
-0.0521184
--0.0965375
-0.053486
-0.327834
-0.149782
-0.0175125
--0.0380313
-0
--0.179938
-0.157552
-0.0178761
--0.0355054
--0.0163114
-0.0574
--0.179883
--0.160435
-0.220902
--0.0387294
--0.0710236
--0.0767055
-0.0187291
-0
-0.148156
-0.267032
-0.0560565
-0.362131
--0.0945234
-0.317842
-0.295181
-0.213039
-0
-0.0560024
--0.190141
-0.0582819
-0.0185046
-0.161064
--0.192093
-0.671981
--0.125297
--0.287078
--0.135541
-0.058087
-0.354126
--0.189419
-0.111244
-0.0589498
--0.0756877
--0.134838
-0.226754
--0.377954
-0.0553705
-0.295114
--0.129814
-0.6157
-0.0566464
-0.0756537
-0.0545127
-0.749266
-0.200279
-0.34367
-0.0743446
-0.0548797
--0.226575
-0.317405
-0.152252
-0.111736
--0.0920127
-0.0190041
--0.313257
-0.479029
--0.167215
-0.113438
-0
-0.269254
--0.317497
-0.15196
-0.305542
-0.0583447
-0.164837
-0.290029
-0.0571661
--0.0721997
--0.0375974
-0.21787
-0.0583722
-0.204231
-0.327722
-0.447995
-0.445345
--0.135222
--0.131068
--0.290083
-0.0184758
-0.451414
--0.21806
-0.0557723
--0.361105
-0.168762
-0.205799
-0.110712
-0.190937
-0.199525
--0.0366869
-0.20815
--0.160911
-0.201884
--0.0353681
-0.0172427
-0.0738241
--0.0375522
-0.0532859
--0.18435
-0.278634
-0.144958
-0.0533966
-0.197968
--0.0854217
-0.15099
-0.193677
--0.0336838
-0.0560732
--0.10476
-0.45209
-0.165397
-0.32972
-0.208694
-0.635139
-0.653843
-0.237071
-0.168493
-0.483721
-0.0573111
-0.0543619
-0.149472
-0.340182
--0.131627
-0.0211769
-0.21195
--0.0721283
-0.30339
-0.117665
-0.46893
--0.0160321
-0.15794
-0.0199685
-0.3592
--0.182921
-0.210724
-0.370071
--0.038624
-0.0765721
-0
--0.105672
-0.0559825
-0.0742484
-0.0226787
--0.0371248
-0.152931
--0.0712118
--0.283358
--0.0918624
-0.114223
-0.447549
-0.149528
-0.106633
-0.114982
-0.311643
--0.0979827
--0.18889
--0.0382035
-0.0551878
--0.19292
-0.20049
-0.435623
-0.298083
--0.0389624
-0.412973
--0.0753163
-0.151751
--0.13511
--0.0912868
-0.309638
-0.108216
-0.0218913
-0.112267
-0.581493
-0.260753
-0.428946
-0.0181347
-0.21331
-0.292506
-0.204283
--0.218525
-0.113772
--0.0382902
-0.297293
--0.0366975
--0.274821
-0.108573
-0.453212
-0.213646
--0.280483
--0.0372199
-0.0217275
-0.160336
--0.0951611
--0.0365595
--0.0173997
--0.0906175
-0.0375771
-0.147197
--0.0385067
-0.0536781
--0.0776115
--0.0368809
-0.111998
-0.321611
-0.110317
-0.195853
-0.772425
-0.209514
-0.910184
-0.127383
-0.341582
-0.343969
--0.0361863
-0.111295
-0.150008
-0.0719371
-0.170664
-0.164122
-0.112037
--0.0747991
-0.148623
--0.121674
-0.144008
-0.0175658
-0.198452
-0.248793
-0.0728232
-0.0530867
--0.091506
-0.105734
-0.144062
--0.0355207
-0.0210666
-0.0999908
-0.294903
-0.426054
-0.0620058
-0.445505
-0.0574705
-0.189958
--0.176482
-0
-0.339615
--0.0852011
-0.340038
-0.103508
-0.30938
-0.103661
-0.10565
--0.0354787
-0.0554342
--0.174603
--0.0868466
-0.13814
--0.173186
--0.0862068
-0.356104
-0.0992328
-0.14648
-0.152683
-0.0557239
--0.0377119
-0.43707
-0.198734
-0.152017
--0.306395
--0.18891
--0.0367526
-0.0568279
-0.339684
-0.113069
-0.103195
-0.0567902
--0.181121
--0.128441
-0.0525482
-0.110143
-0.39634
-0.55872
-0.106078
-0.114018
-0.196167
-0.316971
-0.41363
-0.151079
-0.449552
-0.114689
-0.0721879
--0.174456
--0.0352268
--0.227259
-0.054418
--0.0928136
-0.165001
--0.309961
-0.150152
-0.308743
-0.116885
-0.0558391
-0.47584
-0.204359
-0.0533833
--0.037858
--0.21299
-0.205922
-0.823024
-0.203991
-0.110947
--0.189143
-0.109938
-0.299721
-0.265338
-0.077286
--0.0359959
-0.0578066
-0.274813
--0.153676
-0.142272
-0.36474
-0.0510887
--0.19154
-0.103183
-0.0186622
-0.249163
-0.103278
--0.0736592
-0.0177736
-0.725546
-0.622129
-0.26154
-0.132422
-0.0563359
-0.300901
-0.333193
-0.231017
-0.0536179
--0.0366031
-0.0536995
--0.134747
--0.31243
--0.0159807
-0.204593
-0.443919
-0.450626
--0.070145
-0.10965
--0.195616
-0.250924
-0.0554783
-0.0535969
-0.114672
-0.0513647
-0.366914
-0.354017
-0.420485
-0.106496
--0.0372508
--0.0726505
--0.366549
-0.148351
-0.338204
--0.427958
--0.186509
-0.336186
-0.13523
--0.0404207
-0
-0.466328
-0
-0.0555755
--0.0978084
--0.0163055
-0.1628
-0.210877
-0.186087
-0.307441
--0.395569
--0.0385817
-0.549993
--0.201184
--0.315813
--0.128448
--0.1885
--0.0384467
-0.155891
-0.0537739
-0.164872
-0
--0.0395714
-0.299725
--0.203547
--0.100804
--0.13671
--0.391864
-0.328569
-0.367921
-0.393482
-0.149512
-0.66725
-0.076188
-0.331475
-0.210668
-0.213665
-0.11757
--0.240115
-0.41969
-0.163197
-0.209431
-0.187816
--0.199529
-0.324846
--0.204428
-0.130616
-0.110664
-0.274488
-0.459875
-0.470191
-0.112664
-0.0581697
--0.384164
-0.0596991
-0.0604618
--0.0180281
-0.477557
--0.14652
--0.0961388
--0.095785
-0.690449
--0.198643
-0.0573324
-0.573515
--0.226263
-0.165405
--0.0399532
--0.0171409
-0.0792931
--0.0409682
-0.0586755
-0.860004
-0.0609537
-0.223001
--0.0398171
-0.0612975
--0.290981
-0.0577869
-0.120588
-0.120354
-0.0572989
--0.0419445
-0
-0.0596848
-0.155998
--0.0384772
--0.13505
--0.0400638
-0.0190133
-0.326223
-0.435628
-0.394452
--0.293799
--0.143667
-0.326958
-0.629887
-0.0580752
-0.155194
--0.230992
-0.161627
-0.145477
--0.137294
-0.0185593
-0
--0.096046
-0.022978
-0.297281
-0.585951
-0.0208212
-0.207923
-0.0538383
-0.605886
-0.109965
-0.116627
--0.28291
-0.172816
-0.509022
-0.409099
-0.201726
-0.0586598
-0.0770991
-0.0798128
-0.0572219
-0.268607
-0.0576481
-0.0722175
--0.169305
--0.0919382
--0.0792629
-0.316946
-0.248846
--0.0831264
--0.149222
-0.0977218
-0.302615
-0.0497849
-0.0671566
-0.173807
-0.0487994
-0
-0.194335
--0.20529
-0.129852
-0
-0.231724
-0.131253
--0.330405
--0.0349695
--0.146498
-0.338374
-0.137418
-0.270978
--0.153834
-0.273177
--0.0683281
-0.0185371
--0.197214
-0.0503772
-0.295295
-0.259595
-0.387715
-0.0498917
-0.0995159
-0.328922
-0.185227
-0.243474
-0.468672
-0.230862
--0.0837367
-0.120684
-0.274358
-0.373929
--0.0736573
-0.482987
--0.0342321
-0.195392
--0.0831372
-0.194755
-0.403598
--0.0691661
-0.43026
-0.102692
-0.272478
-0.0528277
--0.203212
-0.0507589
--0.0673171
-0.340619
-0.016797
--0.360647
-0.191883
-0.469391
-0.241997
--0.125713
-0.19227
-0.053789
-0
-0.427397
--0.0336073
-0.0680931
-0.591552
-0.162714
-0.331537
-0.250794
--0.304173
--0.0359267
-0.102787
-0.357457
-0.0511759
-0.458812
-0.190671
--0.123225
--0.25934
--0.298798
-0.105268
--0.0859297
-0.245244
--0.0365956
--0.0885764
-0.192596
-0.625054
--0.0356663
-0.190448
-0.531675
--0.301558
--0.0712922
-0.322608
--0.0935282
--0.116103
-0.0999712
-0.245616
-0.103562
--0.120834
--0.0336319
-0.792321
-0.360402
--0.0486089
-0.0518575
--0.163277
--0.21478
-0.325185
-0.122493
-0.18772
--0.0349313
-0.130946
--0.265262
--0.0316528
-0.419377
--0.0332464
-0.0159928
--0.0153042
-0.349345
-0.554685
-0.633955
-0
-0.169292
--0.129305
--0.104012
-0.199903
-0.222315
-0.052662
--0.306915
-0.107585
-0.452842
-0.681793
--0.0376822
-0.356134
-0.059346
-0.171384
-0.174294
--0.120493
-0.224329
-0.688986
--0.0792182
-0.29279
-0.384418
--0.0936543
-0.219857
-0.433595
-0.803053
-0.209892
-0.158474
-0.24946
-0.391953
--0.18373
-0.318612
-0.261644
--0.105269
-0.113585
-0.287072
-0.439537
-0
-0.359555
-0.322793
--0.193993
-0.0584546
-0.14424
-0.674962
-0.116931
--0.100368
-0.305121
-0.0597931
-0.308481
-0.181708
-0.25247
-0.140144
-0.113155
-0.160682
-0.134583
-0.230104
-0.16105
--0.293248
-0.211351
-0.0193564
--0.0926827
-0.337883
-0.135719
-0.0601875
-0
-0.161029
--0.132816
-0.316672
-0.207541
-0.160499
--0.0396385
--0.29105
--0.0390427
--0.138845
--0.142881
-0.271886
-0.373263
--0.0419963
-0.48821
-0.0188107
--0.0381586
--0.393416
-0.3411
-0.434927
-0.15718
-0.148729
-0.256206
--0.0949966
-0.356178
-0.0185259
--0.0385496
-0
--0.316281
-0.157013
--0.165594
-0.319349
--0.241382
-0.122424
--0.0952606
-0.265896
-0.254846
-0.316948
-0
-0.295076
-0.0565095
-0
-0.0733697
-0.157138
--0.265322
--0.0994464
-0.698739
-0.0210561
--0.0349334
--0.0938039
--0.124059
-0.295149
-0.192751
--0.131439
--0.182168
-0.209559
-0.279712
-0.445955
-0.337876
--0.0940808
--0.0867651
-0.114927
-0.485988
-0
--0.0963638
-0
-0.188583
--0.243094
-0.42509
-0.0191101
--0.231105
-0.252223
-0.164494
--0.0865747
-0.289367
--0.122101
-0.0535119
--0.124474
-0.147892
-0.239771
-0.196767
-0.190833
-0.297364
--0.0880381
-0.482432
--0.21898
-0.200596
-0.107791
--0.281604
--0.26292
-0.0183217
-0.558556
-0.289648
-0.055601
-0.0171857
-0.0559659
-0.429524
-0.570117
--0.128336
--0.182478
-0.4759
-0.487629
--0.0355215
-0.288874
-0.0531997
-0.285829
-0.486621
--0.202709
-0.44559
-0.076946
-0.219672
--0.0891779
-0.0534762
-0.108074
-0.503888
--0.0361481
-0.275432
-0.448725
-0.0178519
-0.110708
-0.106911
--0.216487
-0.0544285
-0.581416
-0.109406
-0.353822
-0
-0.0539464
--0.0359488
-0.0179318
-0
-0.503488
-0.298803
-0.44771
-0.0387238
--0.091378
-0.557356
-0.15747
-0.107783
-0.221239
-0.470372
-0.357152
-0.266493
-0.161699
-0.149993
--0.176113
--0.30229
-0.595759
--0.12371
--0.0915308
--0.0720118
--0.303162
-0.540635
-0.0505806
--0.0386752
--0.125231
--0.0386531
-0.217905
-0.0712855
-0.0535902
--0.126061
-0.0549965
-0.346895
-0.106358
--0.177826
--0.13305
--0.120683
-0.182702
-0.0549344
--0.153305
-0.366185
-0.0696042
-0.140471
-0.020235
-0
-0.279874
--0.172744
-0.137176
-0.235573
-0.104239
-0.325531
-0.259032
-0.0511575
--0.035451
-0.160596
-0.278318
-0.0519109
--0.0340443
--0.173923
--0.126663
-0.0731991
-0.151998
--0.0338043
--0.0889193
-0.488664
--0.24464
--0.0590789
--0.152431
-0.088974
--0.0336257
-0.180409
-0.186286
-0.29826
-0.130733
--0.252351
-0.0497213
-0.329986
-0.13556
-0.0446915
--0.309442
-0.214567
-0.0497547
-0.0888765
-0
-0.220677
--0.324128
-0.049562
-0.268967
--0.0320675
-0.136647
--0.081064
--0.034935
--0.244248
--0.116721
-0.299088
-0.219763
-0.370135
--0.259717
-0.275506
--0.0331603
-0.249659
-0.324403
-0.275763
--0.0344493
-0.34662
-0.189131
-0.146964
-0.460975
--0.113715
--0.117118
-0.127241
-0.203148
-0.228788
-0.522174
-0.0963815
-0.0514989
-0.228812
-0.28604
--0.0791005
--0.120039
--0.0329595
-0.38812
--0.145778
-0.189331
-0.258514
-0.963431
--0.115535
-0.563334
--0.142277
-0.10238
-0.495785
--0.0343335
-0.098746
--0.063288
--0.257835
-0.445475
--0.112344
-0.104544
--0.115539
-0.0506701
--0.0342702
-0.394124
-0.3502
-0.188938
--0.0316736
--0.199031
-0.0957035
-0
--0.147622
-0
-0.412189
-0.0503234
-0.264182
--0.084882
-0.331038
-0.017287
-0.0161042
-0.267934
--0.0141649
--0.175969
-0.261272
-0.0517662
-0.142644
-0.0507355
-0.314126
-0.335136
-0.101068
-0.179677
-0.0990069
-0.270412
--0.11718
-0.192941
--0.242981
-0.127487
-0.168516
--0.0867636
--0.0949681
--0.0656131
--0.193304
-0.153177
-0.0473412
-0.314918
-0.0477817
--0.118494
-0.359414
-0.0998398
--0.031117
-0.0499724
-0.521482
-0.163144
-0.186203
-0.0518008
-0
-0.188959
-0.326368
-0.147286
--0.249377
-0.0521367
-0.106671
--0.03371
-0.192943
-0.272098
-0.101068
-0.0174383
-0.622364
-0.142459
--0.0166833
-0.417539
-0.109244
--0.206776
-0.891423
--0.256289
--0.128274
-0.429467
-0.0170512
--0.0359092
-0
--0.0380228
-0.660005
-0.0560982
--0.0328145
--0.190481
--0.0836826
-0.359069
-0.0569764
-0.14677
--0.18877
--0.133365
-0.203673
-0.0547872
--0.0387088
-0.146065
--0.129845
-0
-0
-0.213201
-0.175001
--0.101355
-0.0581237
--0.37354
-0.351305
-0.330297
--0.0712143
-0.28842
-0.109303
-0.0565303
-0.0548173
-0.356717
-0.486218
-0.211268
-0
-0.279755
--0.278512
-0.175523
--0.181675
--0.0730119
-0.0569224
--0.0373163
-0.112925
--0.0360223
-0.20837
-0.059035
-0.569228
-0.258881
--0.0381614
--0.0712612
--0.0354023
-0.456825
-0.439136
-0.161899
-0.107057
-0.195924
-0.0551121
--0.0690335
-0.0166915
-0.107225
--0.0903168
-0.0522613
-0.193096
-0.0166462
-0.0541923
--0.159881
-0.344299
--0.0878657
-0.196545
-0.373539
--0.0714657
-0.253924
--0.354294
-0.254671
-0.23471
--0.154428
-0.450433
-0.0159522
-0.160236
-0
--0.0866409
-0.152237
-0.0672291
--0.169568
-0.154009
-0.0498143
--0.0322492
-0.0473507
--0.0658763
-0.0154559
-0.198847
-0
-0.264694
-0.146955
--0.160051
-0.0469055
-0.309456
-0.0607201
-0.174828
--0.116483
-0.143794
-0.190961
-0.666741
--0.0982172
-0.0162443
-0.527446
-0
--0.124003
-0.0652925
-0.224971
--0.11722
-0.255535
--0.031775
-0
-0.314257
-0.62955
-0.327366
--0.0910215
-0.051042
--0.422975
-0.10696
-0.016711
-0.0485049
--0.0174222
-0.0184166
-0.140101
-0
-0.145073
-0.577371
-0.297606
-0.382225
-0.0208021
-0.248549
-0
-0.439375
-0.357877
--0.125339
-0.260691
--0.0157115
--0.130412
--0.090949
-0.439179
-0.258642
-0.255595
-0.29296
--0.0390182
--0.18032
-0.168827
-0.0184368
-0
--0.293266
--0.0951028
-0.0198145
--0.271084
--0.0873103
-0.166982
-0.204539
-0.170565
-0.111022
-0.056493
--0.0379535
-0.15082
--0.275577
-0.0217818
-0.359517
--0.0935297
-0.107381
-0.205076
--0.0365387
-0.211074
-0.110538
--0.133708
-0.196898
-0.154318
-0.109798
-0.500312
-0.485894
-0.300786
-0.430485
-0.255672
--0.0361383
-0.148051
-0.050911
--0.0964059
-0.207996
-0.110588
-0.339068
-0.0541874
-0.682652
--0.122942
-0.164212
--0.096355
--0.0373621
-0.145986
-0.520589
--0.225869
-0.350932
--0.351536
-0.328678
--0.0373391
-0.0553562
-0.297851
-0.0511972
-0.199673
-0.466525
--0.0869905
--0.0896449
-0.323633
-0.31796
-0.052544
--0.0866467
--0.0355165
-0
-0.530815
-0.312985
-0.0527644
-0.175672
-0.101287
-0.186875
--0.0867421
--0.0331166
--0.170423
-0.449012
-0.135471
--0.0804284
--0.344996
--0.0798361
-0.0520685
-0.0160177
--0.140007
\ No newline at end of file
diff --git a/test/sasdataloader/test/MAR07232_rest.ASC b/test/sasdataloader/test/MAR07232_rest.ASC
deleted file mode 100644
index 1d6720b..0000000
--- a/test/sasdataloader/test/MAR07232_rest.ASC
+++ /dev/null
@@ -1,16403 +0,0 @@
-FILE: MAR07232.SA3_LP _V948 CREATED: Tuesday, Mar 13, 2007 12:49:09 PM
-LABEL: 13m Rad 0.5Pa Fib1 Th 0.16 PH7.4 Ca 2.5mM
-MON CNT LAMBDA(A) DET_OFF(cm) DET_DIST(m) TRANS THICK(cm)
-1e+08 8.4 0 13.705 0.84357 0.2
-BCENT(X,Y) A1(mm) A2(mm) A1A2DIST(m) DL/L BSTOP(mm) DET_TYP
-68.76 62.47 38 17.5 15.723 0.142 76.2 ORNL
-SAM: MAR07232.SA3_LP _V948
-BGD: MAR07171.SA3_LP_V887,
-EMP: MAR07060.SA3_LP_V776,MAR07061.SA3_LP_V777,
-DIV: PLEX_04JAN07_NG3.DIV,
-MASK: DEFAULT.MASK,
-ABS Parameters (3-6): TSTAND=1;DSTAND=1;IZERO=84.433;XSECT=1
-Average Choices: AVTYPE=2D_ASCII;SAVE=Yes;NAME=Auto;PLOT=Yes;
-
-*** Data written from ABS folder and may not be a fully corrected data file ***
-The detector image is a standard X-Y coordinate system
-Data is written by row, starting with Y=1 and X=(1->128)
-ASCII data created Tuesday, Mar 13, 2007 12:49:09 PM
-
-0.279783
-0.28951
-0.167634
-0.29697
--0.167797
-0.121896
-0.362248
-0.376043
-0.0919098
-0.0439741
--0.083055
-0.0881182
--0.164288
-0.0147787
-0.175687
-0.174224
-0.0979056
--0.156951
-0.557985
--0.114499
--0.251855
-0.253699
-0.149115
-0.0155941
--0.252127
-0.167588
-0.015413
-0.418395
--0.0335198
--0.0820611
-0.0494904
-0.0503993
-0.0528273
-0.253596
--0.183828
-0.271914
--0.170863
-0.396846
-0.57446
-0.103881
--0.0940455
-0.239388
--0.304823
-0.0191333
--0.156934
-0.186775
--0.0909297
-0.0159413
--0.186878
-0.597753
--0.0358526
--0.394771
--0.0724982
-0.441019
--0.0354168
--0.0353518
--0.0359621
-0.264975
--0.08766
--0.0352528
--0.090648
--0.262424
-0.0170211
-0.183366
-0.20904
--0.125102
--0.0363352
-0.237112
-0.188446
-0.23957
-0.406323
-0.0507246
-0.343797
--0.0834347
-0.201388
-0.214932
-0.350931
-0.104486
--0.1803
-0.383186
-0.1992
-0.180016
-0.173691
-0.131825
-0.14552
-0.134749
--0.08936
-0.14645
--0.0375393
--0.0153266
-0.440964
-0.492103
-0.0526702
-0.0944661
--0.0877996
-0.147739
-0.0542376
-0.0967474
-0.0531688
-0.220152
-0.182102
--0.0640662
--0.327062
-0.283083
-0.547303
-0.164272
--0.032581
-0.0459942
--0.255831
--0.153806
--0.160254
-0.0436688
-0.0618106
-0.326531
-0.0928606
-0.555209
--0.104815
-0.257707
--0.100459
-0.205518
--0.0984322
-0.0832656
--0.0725561
-0.448167
-0.307135
--0.0141939
-0.474091
-0.0733255
-0.195064
-0.470072
--0.191426
--0.25492
--0.0310248
-0.0515342
-0.577459
--0.0881458
--0.0652959
-0.111725
-0
-0.541318
--0.16013
--0.12093
--0.0957559
-0.1011
--0.0458865
-0.195229
--0.157412
--0.125624
-0.387456
-0.329536
-0
-0.0167227
-0.0502281
-0.277243
--0.0300157
-0.238097
-0.101385
-0.826522
-0.0170086
-0.0670988
--0.0880042
--0.258211
--0.0801972
-0.156425
-0.336147
-0.0164071
-0.0493535
-0.19716
-0.612121
-0.563308
-0.554292
-0.138882
-0.388876
-0.136965
-0.0525485
-0.100898
-0.128658
--0.121169
--0.197432
-0.156849
--0.257564
--0.0673925
--0.0341715
-0.273819
-0.0514637
-0.192092
--0.0174416
--0.0856666
-0.302464
-0.0518469
-0.481379
-0.236995
-0.137027
-0.306359
--0.297126
--0.148947
-0.18406
-0.135453
--0.0698851
-0.186615
-0.203974
-0.0187237
--0.0707838
-0.0518311
--0.116723
-0.0695504
-0.479693
-0.0517692
--0.0905254
--0.0940007
-0.473277
-0.0542775
-0.495363
-0.0518721
-0.282197
-0
-0.0164963
-0.0203851
--0.261746
--0.0847428
--0.0179269
-0.0727989
-0.201333
-0.186506
--0.0326757
--0.0358952
-0.0515054
-0.0494786
--0.0343714
-0.136892
--0.271116
-0.0998408
-0.438561
-0.179629
-0.287612
-0.215376
--0.161233
-0.206623
--0.0831427
--0.245055
--0.110128
--0.0648095
--0.19341
--0.0673662
--0.164288
-0.185106
-0.0511831
-0.10263
--0.11298
-0.436785
--0.0631916
--0.0320354
-0.146527
-0.41536
--0.165974
-0.207338
-0.107789
--0.0362728
--0.0822785
-0
-0.046993
-0.0706279
-0.047987
--0.0694318
-0.6018
--0.121227
-0.102456
-0.0504944
-0.187428
--0.0882855
-0.188181
-0.153037
-0.0945988
-0.103042
-0.016177
-0.191179
-0
-0.165292
-0.103566
-0.165219
-0.321367
-0.132172
-0.311128
--0.0342964
-0.145354
-0.0536876
-0.10519
-0
-0.186369
--0.123416
--0.0663798
-0.307311
--0.212299
-0.34708
-0.186896
-0.155023
-0.383968
-0.120715
-0.285378
--0.0370853
-0.330221
-0.0548237
-0.391962
-0.142113
--0.0185561
--0.0363078
-0.106996
-0.570079
-0.0207888
--0.0921178
-0.106664
-0
--0.124021
--0.0351004
--0.036644
--0.0372797
-0.419184
-0.144728
-0.0727044
-0.074682
-0.354236
-0.301444
--0.126702
-0.0521326
-0.0169325
-0.20726
-0.294423
--0.245302
-0.25637
-0.26312
--0.213108
-0.288959
--0.0910512
--0.0365647
-0.558344
--0.0727981
-0.714855
--0.0386763
-0.165929
-0.298122
-0.235029
-0.0168257
-0.0174465
--0.126203
--0.0388985
-0.361176
-0.109056
--0.124315
--0.0394607
--0.255881
--0.175909
-0.0184382
-0.0391982
-0.167513
-0.776692
-0.342858
--0.0897538
--0.103562
-0.286685
-0.111527
--0.0951249
--0.303125
-0.143504
-0.0532188
-0.0164725
-0.365862
--0.0890686
--0.119119
--0.19655
--0.0887305
--0.0673598
-0.284383
-0.514834
-0.34446
-0.0160179
-0.296141
-0.451596
--0.122214
-0.209323
-0.331738
-0.28165
--0.0875487
-0.465312
--0.230436
-0.127169
-0.0223573
-0.0746425
-0.31551
-0.143208
-0.196548
--0.0877919
--0.330369
--0.26905
-0.422835
-0.149049
-0.0574703
-0.0183067
-0
--0.135364
-0.573005
-0.194105
-0.0178807
--0.278206
-0.11535
-0.0199723
-0.517063
--0.0367543
-0.15406
-0.261188
-0.0553546
-0.509749
-0.309458
--0.0382304
-0.0556156
-0.212609
--0.333988
--0.133956
--0.124011
-0.0549999
-0.021285
--0.133531
-0.0564904
--0.0386935
-0.210263
--0.136643
-0.214256
--0.131333
-0.270127
-0.388116
-0.521764
--0.187662
--0.0374546
-0.208872
--0.169258
-0.498553
-0.279265
-0.0192602
--0.196934
-0.0552123
--0.193108
-0.301246
-0.0573291
--0.360047
-0.466332
-0.0186104
-0.178873
-0.111766
-0.458005
-0.31199
-0.301504
--0.199037
-0.354881
-0.49899
-0.494019
-0.0564844
--0.079276
-0.115899
-0.169963
-0.0568403
-0.115014
--0.0915927
--0.20318
-0.210281
--0.0398065
-0.056956
-0.21638
-0.114274
-0.218603
--0.131467
-0.532713
--0.0544458
-0.658977
-0.458802
-0.110524
-0.0581795
--0.273352
-0.0584456
-0.266003
-0.622931
-0.436997
-0.203162
-0
-0.261178
-0.0175099
--0.128294
--0.0380519
-0.269728
-0.268359
--0.038685
-0.0541296
--0.0894345
-0.199448
-0.336118
-0.254112
-0.397037
-0.345276
--0.0356204
-0.156835
-0.569294
--0.0356469
-0.544785
-0.144408
--0.268365
-0
--0.171709
--0.13086
-0.105875
-0.0567648
-0.208337
-0.0199901
-0.109496
-0.230764
-0.116285
--0.182181
-0.109183
--0.173365
-0.343367
-0.055195
-0.139994
-0
-0.0549656
--0.125932
-0.444555
-0.11275
-0.151926
-0.199259
--0.185975
--0.19065
-0.0536351
-0.750799
-0.0541727
-0.113206
-0.422236
--0.134614
-0.194572
-0.0571896
-0.0559307
-0.111352
-0.212706
--0.295375
-0.0187071
--0.0952203
-0.169351
-0.156182
-0.0185882
-0.350572
--0.0880064
-0.289131
--0.0378168
--0.0389621
--0.0970878
-0.197514
-0.173914
--0.0383883
--0.189172
-0.151574
-0.0214733
-0.11641
-0.15434
--0.0382161
-0.0747385
-0.412804
-0.166599
-0.292329
--0.234086
--0.135066
-0.433584
-0.527597
-0.454267
-0.330557
--0.192817
-0.310129
--0.281677
--0.0781102
--0.287423
-0.317306
-0.216515
-0.0585126
-0.221754
-0.451462
-0.321072
-0.0186246
-0.0584045
-0.114167
-0.214975
--0.171649
-0.114283
-0.11467
--0.498009
-0.15253
--0.101005
-0.115275
-0.154069
-0.153024
-0.304528
--0.440493
-0.0720875
--0.264913
-0.273506
-0.180572
--0.03928
-0.0773812
-0.14541
-0.165629
--0.293631
-0.270394
-0.0614461
-0.0556882
-0.0204039
--0.206729
-0.440415
-0.204517
-0.302059
-0
-0.019554
-0.425092
-0.176514
--0.186278
--0.178688
-0.018087
-0.0196926
-0.582753
-0.306494
--0.0894279
-0.0517724
-0.402794
-0.108341
-0.0203031
-0.107186
-0.150025
-0.458827
-0.0534037
-0.277182
-0.202156
-0.0539508
-0.0543198
--0.157421
-0.018446
--0.213086
-0.325391
--0.0970386
-0.161577
-0.0553049
-0
--0.180257
-0.107836
--0.0895391
--0.0928821
-0
-0.0576685
--0.03587
-0.29262
-0.579632
-0.443928
-0.293517
-0.259286
-0.0525832
-0.0552356
-0.201046
--0.268354
-0.249688
-0.458132
--0.0378113
--0.0373142
-0.0557504
-0.106873
-0.114374
-0.295467
-0.0573746
--0.0918388
-0.055531
--0.181344
-0.108788
-0.528048
--0.130866
--0.0933594
--0.0384143
-0.0537649
-0.104455
--0.131284
-0.208422
-0.144993
-0.505348
-0.133829
-0.252562
-0.163594
-0.361536
-0.0562687
-0.0563811
-0.0214393
-0.224406
--0.188487
-0.0737254
-0.0564256
-0.289817
-0.553122
--0.264499
-0.0569911
--0.421607
--0.0758643
--0.368223
-0.0216767
-0.295099
--0.186376
-0.21229
-0.133315
-0.741307
--0.0747347
--0.132158
-0.64526
-0.0185412
-0.203268
-0.606519
-0.601252
--0.316422
--0.0750464
-0.111942
-0.113615
--0.4073
-0.20549
-0.206115
-0.108241
-0
-0.422967
--0.274616
-0.198512
--0.0713649
-0
-0.114959
-0.44595
-0.165889
-0.344648
-0.118839
-0.145652
-0.109374
--0.129039
-0.596668
-0.284152
--0.037835
-0.242911
-0.198151
--0.192557
-0.754335
-0.14596
-0.310633
-0.136972
-0.146029
-0.0566288
--0.0352962
--0.182049
--0.0369717
-0.0529142
-0.187644
-0.0534403
-0.273639
-0.0160735
-0.0185701
-0.106411
-0.0497922
-0.460994
-0
-0.103095
-0.363208
-0.0164096
--0.0331603
--0.0156979
-0.0167544
--0.0971719
-0.120237
-0.0557694
--0.184951
--0.183866
--0.181783
--0.279454
-0.165539
-0.159879
--0.270341
--0.0383929
-0.146496
-0.0737824
-0.4767
-0.201031
-0.20883
-0.515547
-0.261348
-0.112873
-0.154626
-0.153566
-0.106069
-0.304739
--0.196326
-0.36218
-0.499118
--0.179031
--0.0374318
-0.362606
-0.474603
-0.119828
-0.148183
-0.494574
-0.144766
-0.420875
--0.0937817
-0.112899
--0.0724563
-0.155427
--0.0366235
-0.0183979
-0.458037
--0.132776
-0.060554
--0.134219
-0.303912
-0.205114
--0.0401992
--0.235156
-0.11266
-0.0196238
-0.450172
--0.22724
-0
-0.154465
-0.429664
--0.136643
-0.116782
-0.0774763
--0.267264
-0.180366
--0.0397221
-0.213702
-0.590344
-0.0560881
-0.0577453
-0.266539
-0.210036
-0.269195
--0.187304
-0.112497
-0.334838
-0.594525
-0
--0.133497
-0.0606952
-0.504013
-0.160828
-0.620551
-0.21473
-0.307885
--0.0945944
--0.26588
-0.431847
--0.0987006
-0.017478
--0.184183
-0.317953
--0.0391352
-0.0592071
-0.0797387
-0.0574883
-0.34597
-0.583959
-0.374853
-0.226853
-0.0185525
-0.171999
--0.136439
-0.340478
--0.0371
--0.223366
--0.221056
--0.0755385
--0.0972322
-0.0409551
-0.348486
--0.0363345
-0.294102
-0.197018
-0.2149
-0.257245
--0.130013
-0.0539858
-0.0549013
-0.114887
--0.0904069
-0.103525
-0.205181
-0.288163
-0.193717
--0.0361514
--0.0918237
--0.400303
-0.0552419
--0.180498
-0.466865
--0.0362494
-0.167087
-0.357664
-0.124179
-0.206751
-0.0184137
-0.152108
-0.424975
--0.0917055
-0.21446
-0.384343
--0.13715
-0.31579
-0.365791
-0.383592
-0.0586046
-0.468029
--0.388087
-0.111001
-0.355914
-0.280278
-0.213916
-0.334479
-0.117246
-0.261411
-0.521712
-0.442014
-0.446487
-0.172676
-0.0547874
-0.821156
-0.574903
-0.303881
--0.197498
--0.0365749
-0.119565
--0.195599
-0.360782
-0.117068
-0.369065
--0.0998191
-0.217471
-0.216205
-0.208382
-0.425444
-0.0592211
-0.236687
-0.620788
--0.140801
--0.0383928
-0.261874
--0.101021
-0.207095
-0.378709
-0.333465
-0.308242
-0.057476
-0.0545275
--0.139041
-0.0217862
-0.115238
-0.217535
--0.135741
-0.322233
-0.29307
--0.201547
--0.232848
-0.440511
-0.00404087
-0.0209673
-0.41612
-0.848938
--0.198872
-0.329967
-0.727235
-0.421574
--0.193946
-0.0612007
--0.230179
-0.123607
--0.140498
--0.193845
-0.231569
--0.13547
-0.0574952
--0.0923781
-0.0568277
-0.0186721
-0.0592958
-0.0188519
-0.18145
-0.0599806
--0.0773942
-0.209413
-0.738646
--0.0387496
--0.038712
-0.0594178
-0.201332
-0
-0
--0.0899932
-0.258791
-0.141962
-0.0573367
-0.0185744
-0.118721
--0.304562
-0.407021
--0.038067
-0.147952
--0.195164
-0.204067
--0.0722046
--0.0920596
-0.462059
--0.0341135
-0.0556844
--0.0729323
--0.0369366
-0.0183574
-0.599408
-0.194422
-0.190606
-0.0536743
-0
--0.0915746
-0.404643
--0.0365296
-0.402268
-0.0212344
--0.0352295
-0.0694085
-0.136273
--0.0853084
--0.0880596
-0.388493
--0.276007
--0.0336848
-0.198061
-0.103006
--0.0822872
-0.184657
--0.12645
--0.0709754
-0.38475
-0.0956829
--0.207979
-0.15711
--0.0910377
-0.0509554
-0.335678
-0.274083
-0.417306
-0.388149
-0.0520479
-0.161913
-0.0521358
--0.119995
--0.265507
-0.621059
-0.051816
-0.142459
--0.215249
-0.459425
-0.432299
-0.142233
-0.246655
-0.236971
-0.250819
-0.0759826
--0.123801
-0.867672
-0.10928
-0.490249
--0.218812
-0.204884
-0.157074
--0.370177
-0.314255
-0.348551
--0.132337
-0.456951
--0.121887
--0.105169
-0.216528
-0.733982
--0.124084
--0.0182936
-0.591454
-0.292531
-0.110135
-0.476954
--0.0696177
--0.0163183
--0.663222
--0.0764636
-0.128183
-0.416772
-0.403326
-0.0555748
-0.112848
-0.206128
-0.363748
-0.380977
-0.476912
--0.365265
--0.0385264
--0.0796314
-0.162882
-0.020222
--0.0354445
-0
-0.424815
-0.359412
-0.297512
-0.226265
-0.076903
-0.114951
-0.148181
-0.0554072
-0.108432
-0.114157
--0.231626
--0.165512
--0.188291
-0.195566
--0.191993
--0.0704653
--0.0163223
-0.0535836
--0.0906088
-0.0579019
-0.203728
--0.180864
-0.145089
--0.273858
-0.168343
-0.166238
-0.108328
-0.187517
-0.106403
--0.121368
-0.151037
-0.10574
-0.346535
-0.380557
--0.331739
-0.486888
-0
-0.582893
-0.0545838
--0.0352588
-0.242584
--0.429752
--0.176628
-0.0524924
--0.0987322
-0.219439
-0.151703
--0.0942518
-0.209049
--0.0367439
--0.0964207
-0.279896
--0.198565
--0.0931066
-0.269138
-0.111439
-0.112561
--0.0908877
-0.46015
--0.127174
-0.0192763
-0.249665
--0.134246
-0.349893
--0.140094
-0.10554
--0.135406
-0.0545318
-0.209441
--0.191297
-0.140258
-0.478162
-0.111785
-0.42313
--0.038836
--0.133267
-0.208687
-0.209847
-0.266343
-0.171583
--0.0965644
--0.130788
-0.0554387
-0.669707
--0.211267
-0.12352
-0.0575113
--0.195663
-0.294312
-0.0567893
--0.0379999
-0.478258
--0.102226
-0.0565199
-0.173684
-0.202925
-0.324298
-0.212151
--0.202759
--0.0739058
--0.230635
-0.597187
-0.0584006
--0.393596
--0.300943
--0.041329
--0.0939647
-0.179328
-0.80206
-0.216128
--0.0412325
-0.132469
-0.265018
-0.315506
-0.153816
-0.282785
-0.112739
--0.134569
-0.76972
-0.120483
-0.332892
-0.219141
-0.282223
-0.39369
-0.0564764
-0.018046
-0.371725
-0.446256
-0.111721
--0.130087
-0.113564
-0.200699
-0.477049
-0.313229
--0.0547216
--0.141252
--0.0937827
-0.674508
--0.409703
-0.174781
-0.367365
-0.406694
-0.114611
--0.0379386
-0.201115
--0.377406
--0.0934928
-0.263769
-0.0173428
-0.708965
-0.494301
-0.0172563
-0.0551681
-0.466352
--0.132263
--0.0377118
--0.0896793
--0.036371
-0.211039
-0.0169559
--0.0342056
--0.212451
-0
-0.106523
--0.218596
-0.290961
-0.110669
--0.106776
-0.11177
-0.432128
-0.20307
-0.0542837
--0.248612
-0
--0.0522866
-0.0521598
--0.0732919
--0.012306
-0.136698
-0.269726
-0.196612
--0.0882437
-0.147685
-0.162468
-0
-0.203063
-0.0174816
-0.0535914
-0.0539915
-0.162219
-0.196669
--0.243231
--0.161369
-0.277063
-0.258503
--0.166167
-0.279549
-0.0533594
-0.407132
-0.200682
--0.0365727
--0.124093
--0.0920094
-0.139162
-0.188624
-0.714388
--0.0377666
-0.208708
-0.450252
-0.296209
--0.272929
--0.273844
--0.125748
-0.292899
-0.262706
-0.391806
-0.284935
--0.0742801
-0.461436
-0.0177505
-0.150072
--0.0708334
--0.226258
--0.0365755
-0.113501
-0.344877
-0.150409
-0.4892
-0.148829
--0.191264
-0.487349
--0.125763
--0.217827
-0.4156
--0.09446
--0.266297
--0.360241
--0.330164
--0.132516
-0
-0.0174505
-0.14598
-0.0179348
-0.0579789
-0.259324
-0.492517
--0.357474
-0.208698
--0.227113
-0.055819
-0.36191
-0.0589715
-0.197113
-0.299865
-0.201378
-0.265601
--0.133812
--0.175811
-0.455952
-0.207523
-0.0179585
--0.0772096
-0.252406
-0.154244
-0.109676
--0.137251
-0.583775
-0.603642
--0.247133
--0.251309
-0.266027
-0.262702
-0.47596
-0.0539339
-0.0534807
-0.256829
-0.304398
--0.0948172
--0.154693
--0.262422
-0.438952
--0.036178
-0.0546914
--0.327509
-0.189296
--0.0362337
--0.129072
--0.276039
--0.362503
-0.192998
--0.0907182
--0.120746
-0.212149
-0.142679
-0.0167611
-0.242366
-0.332337
--0.17759
--0.2797
-0.150276
-0.0586332
--0.184172
-0.062245
-0.545248
-0.170081
--0.0386818
-0.518028
-0.293867
-0.414373
-0.215499
-0.4166
-0
-0.17305
-0.0609662
--0.300742
-0
--0.0439915
-0.348191
-0.699769
-0.0590238
-0.125398
-0.0208434
-0
--0.0395646
--0.22079
--0.0815567
--0.219712
--0.0402005
-0.185097
-0.379627
-0.0633275
--0.140959
-0.22819
--0.120815
--0.0420808
--0.394225
--0.0805244
-0.0602919
-0.477544
-0.162336
--0.0412753
--0.147962
-0.0849415
-0.121894
-0.0618546
-0.16522
-0.0605479
-0.230059
-0.234059
-0.157721
-0.322279
-0.122151
--0.0404846
-0.381666
--0.145349
-0.788295
-0.22623
-0.124874
-0.66129
-0.460832
-0.346476
-0.126836
-0.695175
--0.041013
-0.0779004
-0.386603
-0.0404326
--0.197469
-0.060296
-0.605775
-0.53794
-0.235317
--0.0389039
--0.514824
-0.0196972
-0.385777
--0.143526
--0.541985
-0.0801489
-0.0621099
--0.334968
-0.310305
--0.252007
-0.233942
-0.731474
--0.119772
-0.677918
-1.07391
--0.100506
-0.347065
--0.0992696
-0.649722
--0.33521
-0.0628951
-0.500898
-0.0230205
-0.599638
--0.228989
--0.323138
-0.433962
-0.0790042
-0
-0
-0.55518
-0.0602146
--0.0414422
--0.0730965
-0.268528
-0.21794
--0.186829
-0.231045
-0.0215445
--0.132439
--0.127877
-0.475996
-0.201278
--0.4032
-0
-0.15736
--0.0378615
-0.213706
-0.0559251
-0.325952
--0.22962
--0.0399838
-0.304279
-0.221317
-0.218715
-0.401951
--0.0697983
-0.194857
-0.26631
-0.379129
--0.0338284
-0.60043
-0.31608
-0.290312
--0.0853437
--0.0349362
--0.283357
-0.0500824
--0.0877399
--0.0348893
-0.475036
--0.082677
--0.0362762
-0.303429
--0.179314
--0.0346736
-0.0697513
-0.0166342
--0.0341757
--0.122497
--0.0909445
-0.135937
--0.121937
-0.187307
--0.038198
-0.143492
-0.0551234
--0.206692
-0.072739
-0.459591
--0.090158
-0.583167
-0.557256
-0.0167247
-0.0556175
-0.192374
-0.740896
-0.0514725
-0.108975
-0.199402
-0.11094
-0.193293
--0.180009
--0.123694
-0.197133
--0.0372434
-0.108464
-0.160378
-0.788834
--0.033963
-0.403852
-0
--0.0357996
--0.162369
-0.187977
-0.0169054
-0.142936
-0.28826
-0.11132
--0.250434
--0.0723358
-0.0529381
--0.255397
-0.310403
-0.200176
--0.0670397
--0.268069
--0.397109
-0.340951
-0.18494
--0.12883
--0.157214
-0.204805
-0.789961
-0.349027
-0.490911
-0.35742
-0.580215
-0.0551579
--0.218532
-0.170263
--0.299536
--0.0388381
--0.0899639
-0.0555867
-0.306344
-0.073455
-0.103811
-0.214123
--0.0373188
-0.148872
-0.561109
--0.0359616
--0.327568
-0.346133
--0.0155225
-0.428164
--0.211296
-0.128604
-0.16131
-0.0589043
-0.103158
-0.760816
-1.00511
--0.0355352
--0.0353161
--0.0369223
-0.0993813
-0.194728
-0.273739
--0.0366529
-0.536812
-0.102559
-0.195908
-0.181287
--0.259446
-0.139615
--0.087802
--0.120358
-0.0514215
--0.148438
-0.330707
-0.183766
-0.0545409
-0.409814
-0.368957
-0.417597
-0.312184
-0.0163337
--0.292434
-0.0971492
-0.222302
-0.104972
-0.220129
-0.858161
-0.721148
-0.283144
-0.210662
--0.0913693
--0.200002
-0.0512857
--0.227255
-0.154435
--0.0943476
-0.0168754
-0.332802
-0.28454
-0.145891
-0.401175
-0.112797
--0.0368298
-0.20616
-0.0187309
-0.149207
-0.148148
-0.3149
-0.209077
--0.094937
-0.441523
-0.0191891
-0
-0.115901
-0.0376804
--0.233131
-0.108507
-0.274585
--0.135658
-0.0591318
-0.0526179
--0.0781279
-0.210215
-0.61075
-0.107692
--0.135954
-0.147685
--0.282961
-0.0187595
--0.212038
-0.054155
-0
--0.0933419
--0.0901184
-0.466681
-0.366822
-0.529129
-0.21541
-0.0179133
-0.0564472
-0.113303
-0.0760897
-0.211153
--0.163086
--0.363559
--0.285116
-0.23525
-0.175464
--0.0384837
--0.329399
-0.262505
--0.181466
-0.294081
--0.0376841
-0.116379
-0.374554
-0.464013
-0.221305
-0.167366
-0.174566
--0.0362544
-0.570093
--0.0908461
--0.13582
-0.307635
-0.527055
-0.453776
--0.0382631
--0.183816
-0.0821946
-0.268848
--0.266263
--0.21109
-0.0601221
-0.202342
--0.132164
--0.0371146
--0.129313
--0.0372476
-0.506167
--0.0394849
-0.200224
-0.0348949
--0.27999
-0.288089
-0.115428
-0.315289
-0.164702
-0.332304
-0.0179844
-0.106393
-0.0562034
-0.192434
-0.214957
-0.137417
-0.261553
--0.0715311
--0.130802
-0.62444
--0.0924412
-0.144936
-0.0543827
-0.166177
--0.101966
-0.148861
-0.429363
-0.329665
-0.0502908
--0.255549
--0.121563
--0.193438
--0.123828
-0.0695103
--0.11361
-0.196939
-0.447045
--0.18114
--0.233404
-0.0170317
-0.239177
--0.0360839
-0
-0.523549
--0.0345404
-0.135239
-0.0693091
-0.247341
-0.0525446
-0.0543324
-0.0998071
-0.0727378
-0.265968
-0.639529
--0.126326
-0.246415
-0.237513
-0.329708
-0
-0.0528168
-0.306097
-0.017738
--0.207105
-0.346554
-0.104299
-0.26405
-0.215677
-0.392696
-0.112107
-0.267514
-0.158483
-0.401183
--0.121331
-0.0556818
-0.124005
-0.581719
--0.0894461
--0.375038
-0.0561479
-0.0183571
-0
-0.370814
--0.175872
-0.776506
--0.168598
--0.110514
--0.0192514
-0.286342
-0.14402
-0.722741
-0.0711726
-0.877075
-0.892537
-0.340569
--0.0364041
-0.302432
-0.148717
-0.252565
--0.106969
-0.415115
--0.181789
-0.252548
-0.337265
-0.172087
-0.0556783
-0.42827
-0.196621
-0.0177033
-0.211057
-0.0559359
-0.539615
-0.149191
-0.159046
-0.485935
-0.495674
-0.365083
-0.767177
-0.0553736
-0.586939
-0.326496
--0.0376977
--0.0723141
-0.347275
-0.58183
-0.163204
-0.141217
-0.325909
-0.147606
-0.247756
-0.0185931
--0.170596
-0.48185
-0.283055
--0.30295
-0.10976
-0.148524
-0.273135
-0.0527965
-0.536395
-0.199074
-0.191903
-0.442693
-0.188008
--0.119827
--0.210462
-0.425336
-0.261237
--0.0349503
-0.275863
--0.342829
-0.198275
-0.142757
-0.316017
-0.0608452
--0.207095
--0.280712
-0.657937
-0.409991
--0.136295
-0.0172362
--0.148111
--0.0372704
-0.317176
--0.0969259
--0.344803
-0.0176235
--0.0395947
-0.263256
--0.101218
--0.0343515
--0.141156
-0.393686
-0.224868
-0.26008
-0.118681
-0.202868
--0.204859
--0.374266
-0.20737
--0.0363428
--0.241785
-0.475263
-0.0586176
-0.445593
-0.0223559
-0.148176
-0.692358
--0.125335
-0.669521
-0.0577671
-0.234501
-0.519982
-0.362104
-0.262697
-0.176857
-0.173354
-0.467377
-0.109311
-0.319537
-0.380564
--0.520667
--0.0904873
--0.197889
--0.017201
-0.371208
-0.378926
--0.357368
-0.656265
--0.235032
-0.0592503
--0.368942
-0.773254
-0.378666
-0.757784
-0.11714
--0.404865
--0.366949
-0.27387
-0.779923
--0.131982
--0.115963
-0.520484
-0.160586
-0.535544
-0.504365
-0.386615
-0.644722
-0.581326
-0.166034
-0.320368
--0.0758876
-0.432142
-0.214955
-0.714194
-0.191915
-0.161341
--0.0999262
--0.124616
--0.0379684
-0.0174197
-0.217997
-0.473958
--0.0403857
-0.0212224
-0.219209
-0.117342
--0.145721
--0.193349
-0.33627
-0.0170091
-0.333969
-0.665451
--0.28367
--0.184155
-0.0768766
--0.187116
--0.302139
-0.383725
--0.231077
--0.284217
-0.0567223
--0.18631
--0.203485
-0.508854
-0.477831
-0.20424
-0.374853
-0
-0.110611
-0.425078
--0.190315
--0.0691021
-0.217646
-0.143009
-0.518396
-0.109039
--0.286692
-0.200369
-0.0561779
--0.179864
--0.0432262
--0.217018
-0.0561654
-0.149303
-0.104863
-0.412402
-0.686901
-0.306759
-0.105605
--0.0342401
--0.281358
-0.200367
-0.451914
--0.122368
--0.0848657
-0.571341
-0.187237
-0.424655
-0.531126
-0.0535697
--0.0345602
-0.325026
-0.0167868
-0.106224
-0.285157
--0.285144
-0.0189828
-0.190766
-0.476769
-0.53308
--0.122689
-0.218121
--0.515353
-0.0729733
-0.294576
-0.13917
--0.0884189
-0.0174078
--0.162526
-0.162269
-0.0173318
-0.0563131
-0.285396
-0
--0.0160603
-0.0176487
-0.249531
-0.643968
-0.831288
-0.930069
-0.108719
-0.799473
--0.163876
-0.017477
-0.106271
-0.125308
--0.125928
-0.146377
--0.0524416
-0.462051
-0.390398
-0.255427
--0.0360094
-0.427078
-0.105159
--0.128553
-0.167715
-0.0181803
--0.018506
-0.171119
-0.39853
-0.35349
-0.0700029
--0.0373077
--0.16274
--0.0191759
-0.735159
-0.248246
-0.273233
-0.33147
-0.285647
--0.0369515
-0.310291
-0.740138
-0.202566
-0
-0.0543007
-0.255222
-0.129292
-0.177277
-0
--0.0912817
-0.159718
-0.154966
-0.560122
-0.267499
-0.0541678
-0.053082
--0.0370892
-0.109298
-0
-0.244788
-0.0194694
-0.436095
-0.156675
--0.135553
--0.0364524
-0.487542
-0.108375
-0.390283
-0.167593
-0.400262
-0.107969
--0.314108
--0.0337799
-0.203348
-0.138478
-0.0517323
--0.17544
-0.213234
-0.345359
--0.0360268
--0.0879787
--0.182303
--0.171709
-0.275518
--0.0736496
--0.210421
--0.126587
-0.15598
-0.311927
-0.277813
-0.0564741
--0.258581
-0.0548109
--0.0356944
--0.0794783
-0.0200012
-0.608287
--0.21229
-0.112506
-0.0559776
-0.054247
--0.0361099
--0.0169664
-0.0537585
--0.0933374
-0.0562245
--0.29318
-0.348109
-0.114368
--0.0887995
--0.140439
-0.198757
-0.363381
-0.147273
--0.133617
--0.0998346
-0.651669
--0.487528
-0.325668
-0.260746
-0.213208
-0.342657
--0.134696
-0.207529
-0.0180335
--0.0919831
-0.518851
-0.595501
-0.208685
--0.228449
--0.0777164
-0.149921
-0.316815
--0.0383752
-0.158679
--0.164218
--0.562236
--0.126369
-0.303978
--0.171096
--0.0970828
-0.0177268
-0.0568104
-0.110351
--0.0927577
--0.0374559
--0.196115
--0.0905196
-0.307621
-0.018154
-0.172259
-0.427958
--0.193147
-0.165449
-0.149243
-0.880741
-0.29765
-0.450201
-0.113974
-0.0180642
-0.576968
-0.45852
-0.0180934
-0.168253
-0.300655
--0.0397308
-0.108908
-0.312959
-0.415848
-0.257347
-0.209233
-0.349054
-0.645303
-0.337881
-0.6022
-0.223507
-0.440007
-0.111585
-0.70444
-0
-0.156131
-0.532492
--0.189802
-0.457299
--0.31997
-0.0178104
--0.03577
-0.410612
-0.420687
-0.269898
-0.152372
-0.078229
-0.453225
-0.0534287
--0.0365869
--0.0867942
-0.647463
-0.243969
--0.188366
-0.017254
-0.267345
-0.469457
--0.130942
-0.107251
-0.110187
-0.143377
-0.256669
-0.0543014
--0.181605
--0.440598
--0.0355838
-0.106088
-0.349105
-0.209834
-0.224079
--0.132237
--0.185409
-0.29076
-0.203051
--0.0351591
-0.254791
-0.196196
--0.292044
-0.0560342
--0.0748648
-0.15033
-0.250815
-0
-0.606319
-0.250829
--0.0318718
-0.275455
--0.0675468
--0.130937
-0.0209258
--0.0374194
-0.0554215
-0.110629
-0.261042
-0.0562282
--0.212106
--0.0378565
-0.398178
-0.0587182
-0.165717
-0.600455
-0.254883
-0.364035
-0.10987
-0.518415
-0.311393
--0.117948
-0.0541371
-0.297463
-0
-0.87636
-0.149436
-0.329076
-1.1792
-0.219635
-0.573115
-0.27474
-0.15392
-0.0185104
-0.352301
-0.557703
-0.108456
-0.11939
-0.361792
--0.134424
-0.149803
-0.519911
-0.202347
-0.487084
--0.0759715
-0.171595
-0.171767
-0.228259
-0.644606
--0.481777
-0.0565602
-0.22471
-0.203198
-0.43421
-0.762074
-0.5331
--0.133902
-0.257758
-0.255101
-0.11299
-1.16083
-0.90739
-0.320273
-0.114053
--0.155167
-0.628638
--0.0749946
-0.0742225
--0.0384132
-0.0769886
--0.0378373
--0.188877
-0.171181
--0.196548
-0.162651
-0.275948
--0.0967741
--0.0390872
-0.199373
-0.211061
-0.198656
--0.222679
-0.136201
-0.501127
--0.222246
-0.290796
-0.220076
--0.290776
--0.168678
-0.0590619
--0.0703976
-0.439975
-0.443694
-0.606997
-0.153596
--0.369407
-0.190969
-0.150763
-0.165555
-0.298792
-0.0545547
-0.339277
-0.143251
-0.752338
--0.0368644
-0.107779
-0.0532196
-0.398238
--0.259838
--0.132043
-0.419094
-0.0206697
-0.0207836
-0.0790714
-0
-0.289126
--0.0941291
-0.0518132
--0.125936
-0.181934
-0.361214
-0.189411
-0.591351
-0.0737501
-0.222172
--0.0354887
--0.17948
-0.190722
--0.0719753
-0.10509
-0.194512
-0.552828
--0.0914708
-0.0996463
-0.0742118
--0.185944
-0.168789
--0.303602
--0.213599
-0.395376
-0.295455
-0.239921
-0.256976
-0.0171978
--0.293007
--0.268107
--0.272048
--0.129381
-0.427705
-0.400062
--0.0371766
-0.164242
--0.381881
-0.0564917
-0.188866
-0.0172726
-0.264558
--0.350296
-0.394594
--0.269371
-0.700548
--0.188566
-0.116324
--0.410218
-0.291769
--0.0362806
-0.294435
--0.128088
--0.22069
-0.299404
-0.0178581
-0.972098
-0.311846
-0.277658
-0.456426
-0.0573464
-0.361928
-0.495844
-0.579428
-0.0547944
-0.106512
--0.182667
--0.0370939
-0.312931
-0.287144
--0.18392
-0.299998
-0.369787
--0.0521047
-0.284576
-0.395039
--0.604686
-0.767767
-0.696378
--0.504687
-0.0545923
--0.0739482
--0.272215
-0.0542762
-0.149611
-0.111685
--0.036214
--0.075688
-0.0534586
--0.18738
-0.647012
--0.127893
-0.0771014
--0.176832
-0.342003
-0.109176
-0.212492
--0.212666
-0.196797
-0.475164
-0.165969
-0.0177917
-0.16635
-0.107508
--0.0365812
-0
-0.0191136
--0.315519
-0.0172259
--0.0854906
-0.538105
--0.186863
-0.328217
--0.307686
-0.0983711
-0.459919
-0.0359639
--0.128194
--0.347833
-0.461176
--0.207654
-0
-0
-0.198767
--0.126638
--0.189236
-0.211189
--0.177758
-0.412985
-0.391951
-0.0512901
--0.0653301
-0.133847
-0.0545623
-0.0531717
-0.104219
-0.37001
-0.18992
--0.184567
-0.185392
-0.651764
-0.0352222
-0.340628
-0.051517
--0.186505
--0.0340522
-0.346293
--0.122266
-0
--0.122383
-0.369144
-0.432898
-0.542809
-0.277103
-0.113908
-0.106498
-0.156319
-0.698047
--0.139591
-0.744959
-0.267613
--0.122182
-0.0178735
-0.212248
--0.166739
--0.125918
--0.0774799
-0.333058
-0.436272
--0.182913
--0.0754794
-0.19839
-0.362308
-0.296967
--0.0364109
-0.158272
--0.109661
-0.106844
-0.28184
--0.125762
-0.353806
-0.407131
--0.279129
-0.359109
-0.108371
--0.0372793
-0.280184
--0.13092
-0.109359
-0.34251
-0.452047
-0.362927
-0.34711
-0.0710449
-0.29584
-0.22657
-0.0768072
--0.0755498
-0.41031
-0.018263
-0.313575
-0.66567
-0.213393
-0.074694
-0.264561
-0.645264
-0.325088
-0.0734655
--0.179414
-0
-0.453866
-0.159085
-0.478965
-0.677439
-0.109944
-0.441528
-0.0570413
--0.0714128
-0.266246
-0.144442
--0.117772
-0.111624
-0.0742105
-0.070593
-0.514409
-0.0171054
-0.0534879
-0.33666
-0.157466
--0.0349629
-0.0792117
-0.235216
--0.161092
-0.255341
-0.0534179
--0.0905325
-0.499584
-0.13725
--0.108048
-0.401189
-0.572461
--0.0357821
--0.282758
-0.158661
-0.0519886
-0.191623
-0.196385
-0.637533
-0.241268
-0.281272
--0.262239
-0.361967
-0.191911
-0.200134
--0.132985
--0.0394878
-0.21346
-0.0555371
-0.361978
-0.0555519
--0.273704
-0.319441
-0.143547
--0.188143
--0.0940632
--0.0755602
--0.225689
-0.209801
-0.479364
--0.0395356
-0
-0.360237
-0.181542
--0.475061
-0.477375
-0.175458
-0.628305
-0.483174
-0.560792
-0.207812
-0.108597
-0.118396
-0.207186
-0.0569628
--0.0373667
-0.441998
-0.57068
-0.0770939
-0.282838
-0.267993
-0.163146
-0.112322
-0.208733
-0
-0.457752
--0.0388846
--0.0392984
-0.419617
-0.112241
--0.196047
--0.193738
-0.117434
-0.14841
-0.372286
-0.4938
--0.0776624
-0.255152
--0.0748738
-0.571271
-1.09346
--0.0384289
--0.193826
-0.629307
-0.0583726
--0.285177
-0.674222
-0.521928
-0.018518
-0.305887
-0.26742
-0.49769
-0.366757
-0.207538
-0.333005
-0.259847
--0.132433
--0.0373992
-0.202865
--0.268395
--0.286801
--0.136055
-0.354877
-0.116597
-0.133028
-0.329746
--0.139192
--0.05063
--0.0389316
-0.427464
-0.420212
-0.600404
-0.317326
--0.0735432
-0.364377
--0.0761466
--0.072875
--0.136307
-0.114963
--0.0205656
-0.455502
--0.218214
-0.60481
-0.221439
-0.25757
-0.161389
-0.110487
--0.132966
-0.256931
-0.373991
--0.129556
-0.442403
-0.51976
-0.0543521
-0.167322
-0.0180734
-0.0179623
-0.415816
-0
--0.173796
-0.672912
-0.0517685
-0.263574
--0.119327
--0.0376893
-0.244911
--0.17426
--0.0710649
-0.125974
-0.239698
--0.127738
--0.0348692
--0.0381415
--0.189702
-0.109118
-0
--0.206036
-0.0747648
--0.24259
--0.0348123
-0.141815
--0.153832
-0.050333
-0.306098
--0.117703
-0.0566887
-0.0986928
-0.108989
-0.331084
-0.0182862
--0.364244
-0.511902
-0.416075
-0.0175669
-0.242308
-0.396749
-0.104198
-0.0179414
--0.173166
--0.219005
--0.358702
-0.0557324
--0.288778
-0.106571
--0.125372
-0.303128
-0.250329
--0.0163691
-0.192618
-0.113933
-0.197194
--0.072605
-0
-0.414614
-0.145113
-0.133174
-0.0544275
--0.127971
--0.0716656
--0.132988
-0.191343
-0.270978
-0.124413
--0.12835
-0.369295
--0.109645
-0.110372
-0.162813
-0.317164
-1.13953
-0.0547919
-0.278377
--0.0364473
-0.167829
--0.0370565
-0.885304
-0.24994
--0.237584
-0.314847
-0.110136
-0.0169533
--0.0718455
-0.167698
--0.0778898
--0.0193656
--0.0959768
--0.0748325
-0.91863
--0.0927373
-0.485626
-0.326874
--0.0170646
-0.171618
--0.0390637
--0.204857
-0.112153
--0.0185617
-0.171964
-0.205579
-0.400295
--0.166908
-0.296387
-0.661068
-0.619664
-0.436273
--0.0385759
-0.404272
-0.235451
--0.0703364
-0.446292
-0.356457
-0.133066
--0.271939
-0.601099
-0.0550673
-0.322486
--0.0361297
-0.20963
-0.155759
-0.159111
-0.436775
-0.0534106
--0.129542
-0.251178
-0.272518
-0.279347
-0.108001
--0.124621
-0.016824
--0.276178
-0.319354
-0.276949
--0.122349
--0.267363
--0.159127
--0.094583
-0.0534005
-0.0177896
-0.0174334
-0
-0.192407
--0.268041
-0.29891
--0.0353479
-0.165876
--0.0350718
-0.495345
-0.272287
--0.0984897
-0.518197
-0.204884
-0.427386
-0.496349
--0.0358023
-0
--0.258761
-0.439884
-0.101673
-0
--0.209069
--0.0374417
-0.191749
-0.150821
-0.834053
-0.263697
-0.159547
-0.424865
-0.341554
-0.645945
-0.166275
-0.355347
-0.335499
-0.40197
--0.573009
-0.280831
-0.104145
-0.0571454
--0.134149
-0.19801
-0.298247
-0.30538
-0.313915
--0.180322
--0.274622
-0.510239
-0.106525
-0.419706
-0.27554
-0.14947
-0.305757
-0.161889
-0.255572
-0.485701
-0.409284
-0.589737
-0.400651
-0.219636
-0.0182698
--0.116679
-0.445022
-0.371346
-0.436913
-0.310133
-0.112623
-0.25056
-0.240997
--0.169231
-0.77182
-0.20849
--0.306741
--0.111608
-0.13093
-0.500852
-0.159304
-0.373579
-0.411917
-0.641729
--0.140766
-0.0534909
--0.076504
-0.170489
-1.13293
-0.51335
-0.295994
-0.348975
-0.330427
--0.417712
-0.340288
--0.0192221
-0.0567038
-0.615546
-0.0772203
-0.164258
-0.0181277
-0.206116
--0.132906
--0.13066
-0.0382923
-0.206444
--0.180539
-0.0763291
-0.0340912
-0.0727193
--0.076246
-0.201494
--0.0401524
-0.0182391
-0.107956
--0.283867
-0.443079
-0.428901
-0.0184889
--0.0348351
--0.178087
-0.252753
-0.0702608
--0.189527
--0.0348768
--0.0195058
-0.122295
-0
--0.0344962
--0.123067
-0.586711
--0.127384
--0.123429
-0.336872
--0.087234
--0.195537
-0.201623
--0.125747
-0.188073
-0.104933
-0.282559
-0.281616
-0.0535152
-0.146072
--0.130567
-0.148642
-0.419266
--0.12223
--0.130272
-0.398458
-0.300343
-0.107439
--0.0730786
-0.0517616
-0.0594776
-0.475687
--0.127201
--0.124091
-0.253009
--0.376451
--0.039227
-0.385396
--0.133704
-0.282503
-0.507584
-0.110464
-0.0182854
-0.384039
--0.0212463
--0.0359158
-0.264663
-0.285645
-0.210127
-0.759061
--0.129851
-0.556931
-0.449104
-0.337992
-0.168486
--0.18185
--0.28171
--0.0757655
-0.0187061
-0.463734
-0.26605
--0.110508
-0.417757
-0.113636
-0.202524
-0.073797
--0.241684
-0.794238
-0.0181728
-0.353534
--0.0553952
-0.267748
-0.513288
-0.544287
-0.451311
-0.313217
--0.137562
-0.258098
-0.25914
--0.164219
-0.0365139
-0.351722
-0.210509
-0.464905
-0.943914
-0.111153
--0.0199373
--0.215747
-0.541429
-0.0192751
-0.174193
-0.0178616
-0.968471
--0.0169324
-0.216866
-0.592631
--0.0165188
-0.159305
--0.138323
-0.574873
-0.166766
-0.303811
-0.0593625
-0.223415
-0.0214173
-0.251281
-0.0189529
--0.0384858
--0.132716
-0.0516149
--0.132769
-0.109895
--0.0199934
-0.128008
--0.23343
--0.298501
-0.174385
-0.070011
--0.179501
-0.6062
-0.0704606
--0.0931152
--0.370661
-0.19573
-0.107995
--0.0875846
-0.147761
-0.758054
-0.147972
-0.39097
-0.108106
--0.0359903
--0.0886588
-0.249044
--0.277711
--0.260234
-0.19475
--0.122726
-0.393935
--0.207682
--0.0683676
-0.0556848
-0
--0.0881496
-0.0505311
-0.251774
-0.0161457
-0.323241
-0.0165213
--0.187868
-0.569886
-0.111184
--0.181264
--0.127267
-0.0167367
-0.20232
-0.0496305
--0.125163
-0.112321
-0.058364
--0.0857982
--0.310714
-0.298182
-0.0572048
--0.209762
-0.0385733
-0.841721
-0.0185066
--0.036979
-0.351459
-0.247016
-0.422983
-0.0549242
-0.22625
-0.104269
--0.0362462
-0.281375
-0.423822
-0.645349
-0.145543
-0.0726093
-0.0559333
-0.222404
-0.152503
-0.299109
-0.320399
-0.0185332
-0.246276
--0.180784
-0.553233
-0.394405
-0.225038
--0.0738747
-0.354343
--0.358625
--0.365641
-0.224885
--0.0355314
-0.4556
-0.210586
-0.298931
-0.589694
-0.509144
-0.302492
--0.328328
--0.0363279
-0.518466
--0.267194
-0.457921
-1.17869
-0.203533
-0.198728
-0.174729
-0.254087
-0.0369161
-0.168006
--0.0160285
-0.219684
-0.111739
-0.461059
-0.200478
-0.264539
-0.381222
-0.266903
-0.119625
--0.0192647
-0.375463
-0.157736
-0.103151
-0.109399
-0.228482
-0.195906
-0.112223
-0.316107
-0.132033
-0.543889
--0.0745156
-0.116954
-0.3966
-0
-0.252561
--0.21457
-0.262705
-0.752712
-0.325012
--0.161118
-0.577082
-0.257653
-0.102531
-0.107236
-0.306245
--0.0366096
-0.10246
-0.254321
-0.0688543
-0.0552187
--0.0832505
-0.34774
-0.106395
-0.146601
-0.20002
-0.467343
-0.188282
--0.0927291
-0.240973
--0.255331
-0.0515338
--0.182741
-0.276599
-0.168095
-0
-0.175865
--0.20791
-0
--0.0852914
--0.0722279
-0.199702
--0.171932
--0.0376647
-0.19045
-0.468449
-0.249442
--0.0897418
-0.344208
--0.279005
-0
-0.0177255
-0.433579
-0.33378
-0.189571
-0.470888
-0.623983
-0.199305
-0.45781
-0.0176698
-0.56607
--0.0931295
--0.0715187
--0.0712795
--0.253326
--0.388728
--0.0182741
-0.204478
-0.213651
-0.204191
--0.0184861
-0.225182
--0.12599
-0.0752846
-0
-0.197519
-0.56556
-0.0740891
--0.160038
-0.519597
-0.552465
-0.480096
--0.165536
-0.11351
-0.393865
-0.46099
-0.749922
-0.072497
-0.364279
-0.58103
-0.450299
--0.112024
-0.514417
-0.90533
-0.402064
--0.221075
-0.279568
-0.312898
-0.0702344
--0.290499
--0.105319
--0.256856
-0.711867
-0.396357
--0.159792
-0.695986
-0.905383
--0.260966
-0.21094
-0.644242
-0.509988
--0.377853
-0.255016
-0.127864
--0.0721525
-0.348084
-0.59938
-0.434526
--0.0722293
-0.266074
-0.535258
-0.297652
-0.189787
-0.473428
-0.0531939
-0.0186886
-0.683482
-0.895266
--0.431871
-0.308649
-0.0172593
--0.481197
-0.0725513
-0.368897
--0.0890568
-0.263501
--0.0917929
-0.293606
-0.0511573
--0.178847
-0.344258
--0.0743183
-0.0535969
-0.107307
-0.343176
--0.362224
-0.214175
-0.111975
-0.612006
-0.198579
--0.26584
--0.0351604
-0.106781
--0.177522
-0.271417
-0.281445
--0.209173
--0.213227
-0.697245
-0.862189
-0.0348132
-0.0504364
--0.0850575
-0.32203
-0.0718883
-0.0500725
-0.0533174
-0.131704
--0.0369146
--0.204682
--0.0373121
-0.153561
-0
-0.42231
-0.110392
-0.10348
--0.0364402
--0.167122
-0.24944
-0.300672
-0.542313
-0.0680813
-0.0173854
--0.477954
--0.160756
-0.251055
-0.24471
-0.161425
--0.265818
--0.0355005
-0.105496
--0.221056
-0.240253
-0.853737
-0.252952
-0.482614
-0.294776
--0.154188
-0.810849
-0.516438
-0.0179008
-0.0539949
-0.294521
--0.0343122
-0.700537
-0.19391
--0.168199
-0.250539
--0.30014
-0.547225
-0.64061
--0.156568
-0.570718
-0.682014
-0.124624
-0.0200412
-0.709515
--0.0364458
-0.105624
-0.156965
-0.253388
--0.242607
-0.49952
-0.677706
-0.447621
-0.547358
-0.0539941
-0.161019
-0.0528142
-0.0170607
-0.106393
-0.0716991
--0.205441
-0.550304
-0.483471
-0.656809
-0.31522
-0.0163827
-0.537576
-0.76287
--0.124659
-0.0185046
-1.02486
--0.436878
-0.292577
-0.316056
-0.446167
-0.725481
-0.490509
--0.16634
-0.253129
-0.482838
-0.562316
-0.405831
-0.477755
-0.476503
-0.0181037
--0.0717676
-0.421871
-0.206837
-0.0534344
-0.191407
-0.0175163
--0.0722286
-0.283805
-0.408062
-0.10339
-0.0168016
-0.0173629
--0.0350078
-0.565108
-0.192172
-0.104195
-0.273409
--0.174291
-0.106082
-0.0172484
-0.016783
-0.0164651
-0.271136
--0.0355487
--0.253108
--0.0335261
-0.0664841
-0.141288
--0.119735
-0.0524521
-0.518685
--0.0641337
-0.300539
-0.105082
-0.311027
-0.210623
-0.305001
-0.111626
-0.339827
-0.0179894
-0.0532392
-0.0522399
-0.0584385
-0.156784
-0.509792
-0.204026
--0.0370365
-0
-0.30344
--0.0361672
-0.0558323
-0.0179821
-0.112129
--0.0358735
-0.16442
-0.322597
-0.0596234
--0.357892
-0.0179383
-0.0174403
-0.259992
--0.036038
--0.0391267
-0.261292
-0.372306
--0.0756177
-0.204245
-0.409275
-0.0180812
-0.163384
--0.0749276
-0.252727
-0.268675
-0.0174956
--0.0717472
-0.688457
-0.205113
-0.419618
--0.0199243
-0.315227
-0.291087
-0.0173888
-0.46783
--0.128111
-0.212272
-0.0712727
-0.0557198
-0.0570796
-0.0182888
-1.19204
-0
-1.16851
-0.262345
-0.704538
-0.816966
--0.0713608
-0.371967
-0.221618
-1.34945
-0.590179
--0.357917
--0.0764277
-0.323985
-0.0172154
-0.0394084
--0.245683
-0.092285
-0.318378
-0.935184
--0.427027
-0.206105
--0.129154
-0.469267
-0.407078
-0.409427
-0.232426
--0.0398558
-0.489559
--0.457782
-0.130743
-0.361666
-0.0182519
-0.257448
-0.24685
--0.0744812
-0.0547786
--0.134833
-0.453472
-0.421543
-0.204989
-0.206071
-0.336626
-0.0568687
-0.454907
-0.205983
--0.180791
-0.0596213
-0.105766
-0.111914
-0.57441
-0.292492
-0.437147
-0.203223
-0.0173341
-0.338432
-0.416864
--0.182317
--0.17504
-0.0193616
-0.106642
--0.0194419
-0.0527889
-0.0368542
-0
--0.0904727
-0.157204
-0.438216
-0.387778
-0.520565
--0.115189
-0.0715795
-0.345778
-0.1106
-0.301019
-0.27471
-0
-0.324024
-0.31944
--0.0347828
-0.462079
-0.596007
-0.0559797
-0.106552
--0.21715
--0.175667
-0.301808
-0.152657
--0.128875
--0.0907926
--0.189919
-0.234767
--0.188795
-0.343184
--0.140613
-0.133384
-0.212103
--0.308302
--0.227986
--0.169405
--0.0386368
-0.111517
-0.29745
-0.316709
-0.345526
-0.254752
-0.056652
-0.252189
--0.250331
--0.0371549
-0.662967
--0.0378517
-0.256384
-0.034418
-0.973929
-0
-0.62863
-0.0742082
-0.62663
-0.169543
-0.324411
--0.321796
--0.252716
-0.588321
-0
-0.407613
-0.228547
-0.280633
-0.773892
-0.278694
-0.31297
-0.171636
-0.710539
-0.638242
-0.297968
-1.02521
-0.329598
-1.04174
--0.0189878
-0.543809
-1.13394
-0.484711
--0.0191939
-0.240957
-0.774759
-0.693792
-0.608865
-0.342615
-0.231152
-0.109851
-0.0180997
-0.542976
--0.131625
-1.0252
-0.361583
--0.178306
-0.798574
-0.454359
-0.0183786
-0.453317
-0.763244
--0.039521
-0.0698744
-0.263908
-0.139741
-1.07925
-0.144767
-0.34996
-0.0555016
-0.607934
-0.394888
--0.0727461
-0.434939
--0.0369066
-0.247992
--0.0793793
-0.196866
-0.162682
-0.340532
-0.417047
-0.150986
-0.206912
--0.0373631
-0.475642
-0.306246
-0.169599
-0
-0.14924
-0.16653
--0.486958
-0.0551056
-0.103791
--0.0724296
-0.275632
-0.287549
--0.0686937
-0.142564
-0.0174429
--0.174392
-0.187505
-0.101565
-0.0530197
-0.0667331
--0.194768
--0.171452
-0.13783
--0.071629
--0.270534
--0.067592
-0.224549
-0.154947
--0.125493
--0.169792
--0.347477
-0.367547
-0.0546264
-0.235606
--0.162147
-0.102836
-0.295786
-0.0690907
--0.0357941
--0.120797
-0.30065
-0.370887
-0.104537
-0.15773
-0.271673
-0.250446
-0.412303
-0.157038
-0.189097
-0.799082
-0.421996
-0.68141
-0.309467
--0.153751
-0.606728
-0.256464
-0.109686
-0.483862
-0.506908
-0.40604
-0.358349
-0.618986
-0.522541
-0.213557
-0.0181843
--0.598391
-0.344239
--0.128789
-0.835366
-0.209549
--0.267055
-0.452851
-0.824882
-0.559454
-0.570816
--0.112131
-0.631271
-0.106652
--0.0190162
--0.0897115
-0.622373
-0.617802
-0.231508
-0.35819
-0.435046
--0.197161
-1.28686
-0.749599
-0.189657
-1.2187
--0.0763507
--0.182296
--0.481138
-0.305189
-0.866705
-0.658972
-0.616303
-0.356142
-0.845256
-0.0172345
-0.0543134
-0.465697
-0.761808
-0.157554
-0.0178044
-0.301966
-0.314844
-0.443877
--0.227804
-0.163299
-0.354672
--0.164371
-0.0191275
-0.410281
-0.114582
-0.107257
-0.0552375
--0.199332
--0.145137
-0.280145
-0.265681
-0.189669
-0.445767
-0.399448
-0.0168235
-0
-0.0542871
--0.331125
-0.0181115
-0.103727
-0.871175
-0.104653
-0.121516
-0.104035
-0.527572
-0.0730285
--0.205741
--0.0157639
-0.335177
-0.285948
-0.337769
-0.107042
--0.124054
-0.049979
-0.106719
-0.0181835
-0.276477
-0.311357
-0.274135
-0.351404
-0.305256
-0.203286
-0.0982761
-0.144126
-0.281489
--0.0361235
--0.0881534
-0.347748
--0.0884049
-0.0537204
-0.428754
-0.106089
-0.33123
-0.298458
-0.25813
-0.294055
-0.242013
--0.0374522
-0.264022
--0.342924
-0.255942
--0.191608
-0.104855
-0.209532
-0.0759789
-0.0523711
--0.0162049
-0.054056
-0.0171013
--0.0873252
--0.123263
-0.174358
-0.638285
-0.858195
-0.0177181
-0.34433
-0.370139
-0.940243
-0.127685
-0.587234
-0.195131
-0.128505
-0.592953
--0.0765436
-0.344468
-0.297393
-0.355429
-0.399006
-0.110427
-0.414646
-0.242099
-0.713778
-0.183862
-0.902352
-0.684615
-0.638269
-0.0173408
--0.251362
-0.969525
-0.222457
-0.75839
-0.577847
--0.112202
-0.390541
-0.957402
-0.521633
-0.428878
--0.0186271
-0.616271
--0.0548482
--0.0900823
-0.945704
-0.485275
-0.30942
-0.643715
-0.531856
-0.80294
-0.26449
-0.487495
-1.17108
-0.0187353
--0.0925949
-0.220864
-0.21669
-0.903931
-0.936219
-0.254646
-0.422847
-0.151976
-0.492172
-0.479822
-0.409533
-0
-0.771306
--0.0520028
-0.116051
-0.576076
--0.128202
-0.347461
--0.129893
--0.209893
--0.0367802
-0.189065
-0.142524
--0.0360845
-0.0508686
-0.349491
-0.0562782
-0.108201
-0.297271
-0.734938
-0.578012
-0.247963
-0.289697
-0.0508902
-0.198488
--0.34685
--0.0742642
--0.0677946
-0
-0.0505359
--0.182312
-0.543544
-0.0511102
-0.216874
--0.102826
--0.0356206
--0.203807
--0.259005
-0.19307
-0.100682
-0.016914
-0.146363
-0.0169638
--0.08856
-0
-0.0530123
--0.156089
-0.375132
-0.431769
-0.212824
-0.0504587
-0.123486
-0.330377
-0.144212
-0.282894
--0.0365382
--0.269652
--0.123527
-0.559456
--0.349421
-0.247673
-0.017355
--0.159794
-0.134425
--0.0696554
-0.703138
-0.0529519
--0.0361213
-0.304088
-0.346758
-0.358338
-0.784188
--0.0696342
-0.474546
-0.0751849
-0.733409
--0.0696401
-0.663168
-0.0518761
-0.108085
-0.401721
-0.471486
-0.182205
-0.36098
-0.299146
-0.876377
-0.74195
-0.537057
-0.392466
-0.490606
-0.835692
-0.846112
-0.632433
-0.864389
-0.367006
-0.402939
-1.84549
-0.227777
-0.568458
-0.830253
-1.006
-0.325497
--0.110214
-0.73441
-0.814459
-0.568344
--0.188164
-0.604977
-0.767317
-0.614543
-0.888719
--0.0533986
-0.662736
-0.377418
-1.41602
-0.991375
-0.370607
-0.419168
-0.237097
-0.526238
-0.0173172
-0.515145
-0.748061
-0.54418
--0.0178953
--0.113308
-1.12659
--0.1199
-0.460581
-0.206005
--0.166148
-0.175027
--0.325345
-0.475789
-0.412654
-0.446503
-0.250923
-0.124722
--0.0719604
-0.24181
--0.0186822
-0.185029
--0.0178421
--0.164728
-0.408347
-0.352583
-0.251121
-0.330121
-0.456171
--0.126019
-0.297105
--0.177021
-0.617802
-0.542289
--0.106121
-0.593089
--0.178326
-0.192838
-0.118559
--0.209884
-0.0740784
--0.215375
-0.145954
-0.48093
-0.514967
-0.138418
--0.239728
-0.147543
-0.111825
--0.282017
-0.476403
-0.498565
-0
-0.257562
--0.129386
--0.275651
-0.0534801
-0.26027
--0.110796
-0.196888
-0.449209
-0.141568
--0.228302
-0.0572242
--0.21461
-0.108512
--0.036287
-0.2949
-0.205498
-0.11435
--0.0373942
--0.0384947
-0.444509
-0.256098
--0.0946752
-0.0540691
-0.488229
-0.0754702
-0.25148
-0.737271
-0.88097
-0.257043
-0.615569
--0.214791
-0.439413
-0.599867
-0.159038
-0.0735819
-0.136233
-0.802016
-0.629674
-0.714466
-0.0344322
-0.221192
-0.66726
-0.648941
-0.923888
-0.256967
-0.858059
-1.352
-0.302258
-1.04821
-0.264535
-0.442954
-1.24716
-0.386916
-0.72598
-1.94655
-1.10994
-0.843991
-0.803899
-0.414793
--0.244099
-0.988538
-0.759342
-0.633393
--0.107999
-0.832395
--0.249872
--0.0568727
-0.822973
-0.651098
--0.0556262
-0.677167
-0.278815
-0.212295
-0.177213
-0.187341
-0.414022
-0.199034
--0.133504
--0.208448
-0.199643
-0.345133
-0.0181901
-0.290422
-0.101062
-0.0174147
-0.191044
-0.260318
--0.148291
-0.0552991
-0.053555
--0.500603
-0.438798
-0.208268
-0.275796
-0.340087
-0.339416
-0.251892
-0.180942
-0
-0.110375
--0.0718083
-0.270325
-0.0719882
-0.672488
-0.150098
-0.433412
--0.336789
-0.19157
-0.143674
-0.103453
-0.331059
-0.497186
-0.0171489
--0.174297
--0.0681343
-0.100446
--0.179766
--0.122707
--0.0351191
-0.42442
-0.575723
-0.0170433
-0.422002
-0.100766
-0.21049
--0.265843
--0.0698967
-0.486346
--0.179133
--0.266224
--0.0739129
--0.174531
--0.225211
--0.167341
-0.140618
--0.105607
-0.31196
-0.158002
--0.272525
-0.105155
--0.0900513
-0.24716
-0.143071
-0.434364
--0.0354876
-0.615683
-0.455709
-0.103549
-0.64827
-0.0927024
-0.0545198
-0.468913
--0.0580868
--0.0772899
-0.551034
-0.213198
-0.0738307
-0.441767
-0.529438
--0.0365061
-0.29711
-0.215048
-0.52784
-0.202807
-0.0752554
-0.694288
--0.372659
-0.639758
-0.114459
-1.34618
-0.13219
-0.507289
--0.0196375
-0.409115
-0.695714
-0.613252
-0.0348252
-0.937199
-1.66177
-0.67174
-0.680878
-0.326221
-1.04461
-1.56488
--0.142117
-0.253867
-0.712096
-1.58083
-0.733655
-1.19662
-0.517105
-0.373381
-0.957754
-0.331312
-0.58649
-0.742578
-0.261409
-0.87369
-0.211872
-0.420286
-0.424628
-0.131017
-0.134955
-0.617281
-0.093033
-0.725946
-0.303679
-0.780708
--0.0211188
-0.97909
--0.0172136
--0.190432
--0.131114
--0.289485
-0.221389
-0.0181987
-0.076111
--0.035647
-0.213191
-0.479884
-0.35574
-0.345462
--0.212221
-0.672287
-0.0178124
-0.204225
-0.306821
-0.424743
-0.343388
--0.0180946
--0.209623
-0.465379
--0.068489
-0.670311
-0.249792
--0.44424
--0.45479
--0.089413
-0.0388517
-0.146429
-0.0515548
-0.466419
-0.238691
--0.103976
--0.0335962
-0.0525432
--0.246922
--0.122646
--0.0663202
-0
--0.15109
--0.0190038
--0.123265
-0.133864
-0.290699
-0.0721069
--0.124457
--0.070337
--0.071459
-0.473049
-0.0746588
--0.199779
-0.339042
--0.258646
-0.0170486
-0.531193
-0.195159
-0.0529686
-0.0174284
-0.130929
-0.414094
-0.359513
-0.141193
-0.544352
--0.0376808
--0.168183
-0.392193
-0.245573
--0.0358756
--0.0356122
-0.707236
-0.427983
-0.179174
-0.24926
-0.0543877
-0.737083
-0.0732743
-0.487879
-0.63346
-0.644293
--0.194162
-0.288946
-0.0949037
-0.657554
-0.707754
-0.178453
-0.225737
-0.376925
-0.780439
-0.402404
-0.84883
-1.19392
-0.0882456
-1.00693
-0.564818
-0.139593
-0.896912
-0.871108
-0.743941
-0.441075
-1.36982
-1.22265
-1.04886
-0.692921
-1.64719
-0.199952
-0.84395
-0.56911
-0.919503
-0.78976
-0.192013
-0.760212
-0.789246
-0.312992
-0.911449
-0.473025
--0.0361319
-0.751132
-0.202022
-0.557474
--0.0188654
-0.690817
-0.356256
--0.0733721
-0.727327
-0.466088
-0.109655
-0.711964
--0.126412
-0.163038
-0.35975
--0.110459
-0.64615
-0.0541555
-0.112917
-0.292237
-0.329001
-0.222091
--0.174608
-0.107278
-0.139585
--0.215068
-0
-0.240139
-0.396033
--0.436221
-0.288505
-0.126025
--0.0337163
-0.245262
--0.172481
-0.0164544
-0.287541
-0.197371
-0
-0.103329
--0.157921
-0.19372
-0.18698
--0.0331577
-0.0998621
--0.167607
-0.245782
--0.0155442
-0.0522192
-0.46709
--0.0353407
-0.336214
-0.293594
-0.142531
--0.171644
-0.327576
-0.207076
-0.4156
-0.112384
--0.189529
--0.0968785
--0.0671365
--0.659231
-0.378876
-0.348472
--0.543104
-0.173361
-0.162442
-0.170054
-0.452788
-0.55863
-0.102537
-0
-0.0544288
-0.45969
-0.23612
-0.307298
-0.339942
-0.134719
-0.217149
--0.129383
-0.247448
-0.191031
-0.839217
-0.33161
--0.123118
--0.217334
-0.323133
-0.109056
-0.918444
-0.263117
-0.652928
-0.693108
-0.592864
-0.706027
-0.035853
-1.28858
-0.314162
-0.276867
--0.107538
-1.31115
-2.65181
-1.23138
-1.60907
-0.939378
-0.28987
-0.821646
-1.01117
-0.499972
-1.08122
-2.14292
-1.62555
-1.44902
-1.91818
-1.12672
-0.669243
-0.96233
-1.59094
-0.205015
-1.55908
-0.523631
-0.365512
-0.323453
-0.801281
-1.05257
-0.795025
-1.26168
-0.2252
--0.503718
-0.928147
-0.16694
-0.925715
-0.170904
-0.47534
-0.670447
-0.178244
-0.472462
--0.0189531
--0.0202836
-0.198243
-0.489964
-0.186879
--0.134911
--0.0194177
-0.335157
--0.13135
-0.163092
--0.382429
-0.362034
--0.202097
--0.155843
-0.359516
-0.821526
-0.363796
-0.416064
-0.246968
-0.348098
-0.573968
-0.253392
--0.0156856
-0.311015
-0.162128
-0.482768
-0.55969
-0.139546
-0.0170477
--0.0897686
--0.0880925
-0.187575
--0.17779
-0.103484
--0.0329473
-0.0531281
--0.125171
-0
-0.545371
-0.0174018
-0.111227
-0.0500133
-0.113662
-0.105442
--0.303364
-0.0531841
--0.128699
-0.0178764
--0.0947707
-0.35754
-0.10818
--0.283047
-0.280125
-0.107738
-0.108703
--0.0897438
-0.205061
--0.357641
-0.171638
-0.202046
-0.308817
--0.0738164
--0.073775
-0.750433
-0.166915
-0.342698
-0.404361
-0.428098
-0.126817
--0.0156934
--0.073463
-0.182076
-0.219052
-0.824309
-0.603857
-0.49888
-0.664475
-0.962637
-0.374082
-0.97672
--0.106729
-0.768617
-0.777742
-0.817214
-0.285177
-0.942292
-0.0730644
-1.33504
-0.936787
--0.0350634
-1.2302
-0.574612
-0.524746
-0.500377
-0.776914
-0.89702
-1.81895
-1.67479
-0.860123
-1.73979
-1.19441
-1.20904
-1.0883
-0.536018
-2.46073
-1.29428
-0.545044
-0.776724
-1.47524
-1.27627
-0.86887
-1.31283
-0.370319
-1.19054
-1.0746
-1.73353
-0.308869
-0.199194
-0.223658
-0.094519
-0.419328
-0.965376
--0.0190165
-1.08318
-0.113435
-0.258815
-0.254004
-0.275102
-0.48507
--0.0783445
-0.407632
-0.740755
-0.195042
-0.732359
-0.199912
-0.0524429
-0.109183
-0.559747
-0.103908
-0.414048
-0.809066
-0.0206657
-0.258122
-0.0178275
--0.0882959
--0.271758
--0.148337
-1.11265
-0.279983
-0.141558
-0.308807
-0.141114
-0.386185
-0.213924
-0.154709
--0.167968
-0.410266
--0.0356317
-0.173511
-0.100901
-0.323171
-0.0509982
-0.126433
-0.26785
-0.150628
-0.539737
--0.365078
-0.0503456
-0.0426041
-0.0507095
-0.0538352
--0.177046
-0.103366
-0.114195
--0.0358953
--0.089491
--0.0849643
--0.0964006
-0.253428
-0.0567924
-0.389429
-0.153079
-0.476444
--0.163059
-0.150822
--0.071602
--0.179525
-0.401049
-0.345922
--0.221912
-0.444141
-0.0179503
-0.266323
-0.0758207
-0.303357
--0.0385714
--0.21391
--0.0554427
-0.162039
-0.304231
--0.129442
-0.164227
-0.401734
--0.354806
-0.654457
-1.15727
-0.523586
-0.66914
-0.0350395
-0.370886
-0.687579
-0.83308
-0.452812
-0.740979
-0.965934
-1.70579
-1.72772
-0.207258
-1.43853
-0.355252
-0.286835
-1.25773
-0.953127
-0.758738
-1.62088
-1.61125
-1.16592
-0.678394
-1.44443
-0.780767
-1.56781
-1.14034
-1.89483
-0.802208
-2.14666
-1.25547
-2.07143
-1.8083
-1.12494
-0.42216
-0.773767
-0.754147
-0.551305
-1.30998
-0.326252
-0.601959
-0.554281
-0.58579
-0.942977
-0.367062
-0.222678
-0.419947
-0.214532
-0.413105
-0.537141
-0.150908
-0.799701
-0.367455
-0.491394
-0.79315
-0.238402
-0.377515
-0.0749481
-0.560289
-1.07202
-0.169052
-0.413312
-0.465241
-0.197135
-0.018071
--0.185118
--0.0362579
-0.263987
-0.289435
-0.333212
-0.504042
-0.196895
-0.304773
--0.0180585
--0.0526031
-0.466863
--0.174749
--0.0726822
-0.699317
-0.016822
-0.109353
-0.330442
-0.158029
-0.151231
-0.434712
-0.0945216
-0.199392
-0.0165852
-0.108795
-0.0536591
-0.341156
-0.0556563
--0.0833861
--0.0385234
-0.0172059
--0.0362555
-0.0206867
--0.112262
-0.167705
--0.179907
--0.0717702
-0.487036
-0.200538
-0.352209
-0.111588
-0.346146
-0.125401
-0.0559507
-0.287687
-0.126961
-0.250646
-0.197487
-0.186787
-0.0546642
-0.62178
-0.108
-0.428791
--0.226603
--0.0378969
-0.779469
-0.299014
-0.161981
-0.348543
-0.315902
-0.16525
-0.520326
--0.14993
-0.705551
-0.161449
--0.223482
-0.371068
-0.90101
-0.406489
-0.0356319
-1.1177
-1.24611
-1.17514
-0.755827
-0.171385
-0.857075
-0.755152
-1.45328
-1.03632
-0.921284
-0.628193
-0.465495
-1.61072
-1.21113
-1.05899
-1.70664
-1.95194
-0.38163
-3.06732
-2.8135
-1.8152
-1.66294
-1.09859
-0.586232
-1.75872
-2.35313
-0.805787
-0.770532
-1.73484
-2.05645
-1.65945
-0.444548
-1.41715
-0.433764
-0.453301
-1.41461
-0.0532502
-0.826248
-1.51641
-1.17756
-0.017229
-1.93257
--0.0369727
-0.900384
-0.818823
-0.806275
-0.526017
-0.388281
-0.318764
--0.301227
-0.278512
-0.30723
--0.128007
-0.105548
-0.793763
-0.0170893
-0.135945
-0.216466
-0.156261
-0.345825
-0.0706591
--0.0165737
-0.754085
-0.194814
--0.0723063
-0.102986
-0.578609
-0.198305
-0.189102
-0.110099
-0.325575
--0.036541
-0.191128
-0.207422
-0.0169361
-0.284721
-0.154684
-0.54476
-0.185713
-0.277134
-0.430056
-0.267291
--0.0852148
--0.0831418
-0.15681
-0.096083
-0.375273
--0.1544
--0.0709552
--0.207319
-0.493029
-0.192079
-0
-0.190401
-0.331911
-0.0161513
-0.0179828
-0.0158042
--0.0958623
-0.339128
-0.0748508
-0.0535619
-0.0171979
-0.102478
-0.445406
-0.0166235
--0.218216
--0.0859231
-0.251799
-0.208836
-0.106908
-0.0515208
-0.161943
-0.424721
-0.316719
-0.865671
-0.0176464
-0.269145
-0.107832
-0.635989
-0.397335
-0.152899
-0.336348
-0.871847
-0.390473
--0.424622
--0.0191254
-1.21724
-0.961816
-0.516828
-1.60801
-0.202205
-0.271045
-1.92117
-0.613938
-1.37133
-0.724179
-0.956752
-1.13375
-2.26499
-0.970506
-1.12463
-2.43346
-1.80229
-1.80475
-2.43062
-2.01099
-1.55599
-0.618667
-1.15951
-0.805895
-3.10836
-2.77854
-2.04576
-1.22898
-2.10368
-1.78189
-1.92773
-1.24296
-1.85868
-1.55717
-2.21114
-1.54828
--0.0906537
-0.641803
-0.710446
-0.793949
-0.502415
-0.130759
-0.850017
-0.326277
-1.16011
-0.127191
-0.343474
-1.14925
-0.340083
-0.348484
--0.085012
-0.0181834
-0.495573
-0.368238
-0.285563
-0.64764
-0.477247
-0.0569861
--0.175241
-0.0175639
-0.22082
-0.301528
--0.0730909
--0.0919557
--0.0672554
--0.125351
-0.527365
-0.477135
-0.412796
--0.091321
-0.196475
-0.194607
-0.381931
-0.25692
--0.170112
-0.287063
-0.102727
-0.100323
-0.45574
-0.598156
-0
-0.153566
-0.0200644
-0.198164
-0.201678
-0
--0.128576
--0.267253
-0.208607
--0.107512
-0.47939
-0.314451
-0.168181
-0.146136
-0.354095
-0.0554996
-0.0567287
--0.0163437
-0.276449
-0
-0.310354
-0.278163
-0.142236
-0.627702
--0.0734033
-0.171888
-0.16347
-0.0179054
--0.071626
--0.0367503
-0.296926
--0.0185355
--0.272739
--0.0781048
-0.540957
-0.300152
-0.405363
-0.550303
-0.223324
--0.0370981
--0.456845
--0.0375359
-0.972728
-0.20975
--0.221883
-0.234109
-0.708253
-0.713157
--0.054786
-0.134462
--0.315221
-0.131111
-0.886663
-0.473201
-1.16033
-0.680863
-0.883374
-2.48044
-0.764006
-1.66017
-1.92143
-2.43168
-2.83441
-1.25198
-3.23395
-1.24752
-1.05857
-4.7475
-3.59454
-3.69792
-3.1576
-1.97097
-2.44215
-2.40659
-3.77894
-1.81929
-2.29084
-2.58963
-1.5103
-1.73583
-2.57198
-0.592793
-1.42547
-2.35793
-0.4059
-0.898499
-0.383609
-0.543816
-0.529797
-0.493611
-0.427344
-0.649068
-0.174763
-0.438372
-0.281879
-1.00252
-0.945896
-0.136021
-0.50598
-0.600935
-0.453434
-0.37703
--0.128101
-0.21277
-0.189274
-0.165654
-0.238328
-0.297947
-0.195139
-0.251876
--0.0672342
-0.453199
-0.154068
--0.0360289
--0.218284
-0.248918
-0.238025
-0.46952
-0.194591
-0.101876
-0.568329
-0.103213
-0.0998497
-0.209499
-0.346962
-0.278955
--0.0347506
-0.145693
-0.146221
-0.352947
-0.138291
--0.0926901
--0.104696
-0.343799
-0.0521255
-0.0172401
--0.0352993
-0.204471
-0.421088
--0.0965303
-0.284879
--0.0382547
--0.130549
--0.185139
-0.207848
-0.14806
--0.0130034
-0.571217
-0.292057
--0.259982
--0.0745345
--0.127398
-0.0563572
-0.774805
--0.310702
-0.411585
--0.324844
-1.16182
-0.149991
-0.256757
-0.766477
--0.427463
-1.0521
--0.037075
-0.388937
-0.076583
-0.145856
--0.110265
-0.055531
-0.357344
-0.0731544
-0.61972
-1.02633
-0.116208
-0.415142
-0.234383
-1.21571
-1.61051
-0.7002
-0.720404
-0.839106
-1.19982
-0.927708
-0.837607
-1.4025
-1.32207
-2.96861
-1.30924
-2.62479
-1.8571
-3.35633
-3.08747
-2.51899
-3.7237
-1.9977
-3.42887
-2.89692
-2.8293
-2.21174
-3.65969
-3.14342
-3.08446
-3.34865
-2.95716
-2.10387
-3.04232
-2.31693
-0.796571
-2.73713
-1.6737
-1.09388
-2.23532
-0.66004
-1.01293
-0.879902
-0.592204
-0.862038
-0.457919
-1.4567
-1.1154
-0.850003
-0.0179448
--0.0191472
-0.176246
-0.537694
-0.0190799
-0.351015
-0.364505
-0.110642
-0.27298
--0.0755405
-0.163813
-0.0717892
-0.268236
-0.409484
--0.185057
-0.107256
-0.660508
-0.224697
-0.509821
-0.48663
--0.218793
-0.0183735
-0.131132
-0.295794
--0.125769
--0.0760435
-0.145568
-0.165735
-0.591325
--0.26811
-0.347434
--0.176174
-0.495918
-0.163886
-0.212189
-0.0485237
-0.282665
-0.051037
--0.116307
-0.0541699
-0.0489149
--0.0692556
--0.0330711
-0.146411
--0.152115
--0.122185
-0.0518613
--0.0673756
--0.125286
-0.19825
-0.195649
-0.277152
-0.0173193
-0.369999
-0.698353
-0.157834
-0.465714
--0.216658
-0.1336
-0.566844
--0.0362464
-0.0705362
--0.0370129
-0.389754
--0.215866
-0.308155
-0.249708
--0.12434
--0.130071
-0.106862
-0.258197
-0.703478
-0.310333
-1.04547
--0.0715841
-0.454414
-0.646116
-0.756064
-0.396631
-0.614638
-0.554074
-0.699146
-0.345686
-0.47869
-1.11143
-1.20114
--0.293268
-1.93434
-1.038
-1.81234
-1.68649
-0.9604
-1.90345
-1.60805
-1.06144
-2.82994
-3.71082
-3.23852
-3.29489
-5.93147
-2.59719
-4.12152
-4.18799
-2.41116
-5.06563
-2.32611
-3.25063
-3.92622
-3.29378
-3.66078
-2.845
-3.60894
-3.60301
-1.69249
-1.10013
-1.54758
-1.38229
-2.31363
-3.31133
-1.26404
-1.98125
-0.332649
-0.47556
-0.96446
-1.20702
-1.1616
-1.00547
-0.447574
-0.404227
-0.430676
-0.494511
-0.105155
-1.24051
-0.57825
-0.41268
-0.209507
-0.381419
-0.335573
-0.204849
--0.190491
-0.544541
-0.275806
-0.471988
--0.0878293
--0.0194501
-0.340492
--0.252419
-0.559681
--0.0190881
-0.0703921
-0.0174477
-0.193498
--0.216375
-0.242224
-0.233114
-0.0171045
-0.0171962
-0.1904
-0.190282
-0.108589
-0.189221
--0.117484
--0.0160911
--0.122367
--0.17428
--0.168842
--0.268679
--0.017601
-0.528291
--0.156541
-0.425209
-0.568946
-0.0680051
-0.293243
-0.47838
-0.0494598
--0.0917791
--0.153339
-0.439818
-0.0690638
--0.0938482
--0.0341709
-0.299975
-0.555735
-0.110574
--0.315929
-0.252045
--0.207199
-0.303297
-0.583042
-0.204126
--0.363001
--0.0188586
--0.123439
--0.409588
-0.760975
-0.371463
-0.472948
-0.152034
-0.591146
-0.465453
-0.0543204
-0.25858
-0.267205
-0.412941
-0.107615
-0.494977
-0.540153
-0.357765
-0.368364
-0.112058
-1.05408
-1.08323
-0.774691
-0.217415
-1.0443
-1.66679
-1.18786
-1.51638
-1.98364
-2.0199
-1.18609
-3.08048
-2.56226
-6.99097
-3.93812
-3.5867
-4.68861
-4.9868
-4.55091
-4.7941
-7.44387
-3.62996
-4.26688
-4.82994
-4.12815
-6.33271
-4.40442
-4.37476
-3.04363
-4.48821
-2.77939
-3.37577
-2.54065
-2.00998
-0.94825
-1.51066
-1.39203
-1.84938
-0.664377
-0.812437
-0.0340165
-1.35951
-0.124909
--0.200589
-0.572107
-0.763629
-0.747491
-0.433949
-0.225557
-0.33033
-1.01197
-0.733673
-1.22498
-0.216146
-0.503621
-0.586195
-0.510316
-0.637338
-0.156719
-0.301255
-0.0714947
-0.127304
-0.0539613
-0.308705
--0.174467
-0.703314
--0.0364093
--0.130197
-0.547309
-0.337381
-0.489761
-0.164229
-0.544124
-0.195084
-0.0186971
-0.0534805
-0.760972
-0.326512
-0.201153
-0.275395
-0.483945
--0.0343577
-0.108016
-0.185073
--0.0888323
-0
-0.302415
-0.0979328
-0.225384
--0.198188
--0.0337583
--0.0351213
-0.194569
--0.177162
-0.300585
-0.215998
--0.218529
-0.883308
-0.192664
-0.0537668
--0.260619
-0.337867
-0.546913
-0.103828
-0.489681
-0.296572
--0.0357127
-0.20763
--0.106417
--0.0721551
-0.386245
-0.259394
-0.402816
-0.833835
-0.0535826
-0.364989
-0.160076
-1.00818
--0.0363828
-0.539329
-0.764678
-0.233578
-0.300288
-0.788908
-1.1794
-0.415709
-1.51623
-0.592833
-0.832847
-1.38713
-0.912294
-0.775897
-0.231932
-2.01354
-2.54231
-2.19579
-2.05278
-2.25446
-2.51635
-3.74713
-2.92328
-4.40788
-5.75222
-5.03908
-5.97828
-7.43392
-7.1223
-7.66107
-6.16621
-7.62549
-6.20417
-6.51249
-5.59795
-5.99446
-5.71299
-3.50667
-5.92201
-2.63982
-5.34911
-3.18118
-3.90763
-2.0628
-2.59326
-1.77034
-1.80539
-1.42995
-1.24762
-0.395856
-1.76539
-0.926118
-0.992622
-1.06545
-1.07876
-0.388902
-0.427803
-0.8943
-1.19983
--0.161386
-0.637769
-0.434903
--0.0727504
-0.75012
-0.128851
-1.04976
-0.697331
-0.421825
-0.0887134
-0.861732
-0.519826
-0.0710024
-0.158663
-0.250217
--0.122322
-0.213364
-0.836511
-0.0177729
-0.308135
--0.15718
--0.125149
-0.0714014
-0.0517964
-0.113426
--0.126533
--0.215327
-0.192425
--0.265999
--0.0689322
-0.0984825
--0.162802
--0.0680017
--0.111363
-0.792156
-0.0168338
-0.109015
-0.0498447
-0.0503199
--0.179889
-0.428282
-0.473834
-0.203306
-0.0501048
-0.11138
-0.0531812
--0.189435
-0.42841
-0.304992
-0.016852
-0.586904
-0.406428
--0.321142
-0.192391
--0.0366956
--0.0356638
-0.448257
-0.194509
-0.256262
-0.401227
-0.257681
-0.253034
-0.0182183
-0.0172024
-0.587087
-0.251666
-0.114198
-0.594178
-0.374573
-0.390743
-0.205198
-0.313548
-0.470246
-0.802202
-0.396327
-0.830992
-0.982906
-1.92792
-0.582004
-1.15202
-1.49342
-2.47506
-1.99572
-1.78192
-1.59484
-2.45464
-1.48041
-3.25673
-2.94058
-2.75663
-3.70399
-3.04353
-4.65742
-7.24133
-8.81584
-6.31219
-10.5255
-7.09406
-10.6334
-9.49481
-11.0755
-7.92248
-8.82857
-8.85403
-7.23538
-7.35951
-8.77714
-7.14072
-2.98641
-6.12012
-3.31843
-4.28213
-2.12571
-2.38793
-2.35558
-0.534689
-1.44774
-1.18404
-1.02541
-2.16609
-0.847313
-1.14854
-1.40556
-0.566851
-0.333313
--0.419146
-1.23811
-0.940633
-0.537769
-0.794123
-0.254166
-0.833875
-0.610241
--0.1064
--0.0733692
-0.251033
-0.428734
-0.314173
--0.315791
-0.25168
-0.19281
-0.106734
--0.0735746
-0.0165172
--0.036827
-0.191684
-0.164969
--0.0720006
-0.148155
-0.0355085
-0.102759
-0.274717
-0.125813
--0.0835885
--0.0357822
-0.38053
--0.0187796
-0.140544
-0.28341
-0.0646426
-0.102358
-0.345117
-0.0558618
-0
--0.121672
-0.54083
-0.461533
-0.112385
-0.54763
-0.317513
-0.35351
-0.335154
-0.162584
-0.357754
-0.756571
-0.198634
--0.0749652
-0.0180644
--0.133588
-0.202227
-0.0557152
-0.296688
-0.10638
-0.269486
-0.710162
-0.450049
-0.0516824
-0.126375
--0.182837
-0.320091
-0.321415
-0.219876
-0.626093
-0.309015
--0.112293
-0.401895
--0.226988
--0.172601
-0.864396
-0.271138
-0.0738703
-0.619734
-0.555703
-0.252922
--0.0189194
-0.679543
-0.892378
-1.70541
-1.00578
-0.709688
-0.752812
-2.74783
-1.87663
-3.01246
-1.99801
-1.97971
-3.66553
-4.85141
-4.54891
-4.4309
-7.14856
-9.02021
-9.72848
-11.4781
-10.6307
-11.8339
-14.7783
-14.3227
-14.9173
-14.5267
-10.8836
-14.1066
-14.2987
-9.67959
-9.25508
-9.67775
-7.76785
-6.87136
-5.51969
-4.66695
-3.16622
-2.61507
-3.16932
-0.843581
-1.32189
-1.48126
-1.63469
-1.19657
-0.769912
-1.41104
-1.31487
-1.16385
-0.582191
-0.799055
-0.114198
-0.875957
-0.305691
--0.0189238
-0.313623
-0.347685
-0.341311
-1.11961
-0.368602
-0.97439
-0.767971
-0.390299
--0.0360801
--0.316135
-0.21504
-0.299278
-0.0376828
-0.291506
-0.442239
-0.0545845
--0.45196
--0.329416
-0.0183315
-0.0180658
-0.069967
-0.16356
-0.1933
-0.072144
--0.213299
--0.123977
-0.197152
-0.05226
-0.288439
-0.0986108
-0.493641
-0.0993347
--0.121938
-0.0500513
-0.510276
-0.245174
--0.175694
--0.0355528
-0.328691
-0.332468
--0.126248
--0.163981
-0.444887
-0.213661
-0.0539672
-0.182274
-0.0569537
-0.119763
-0.196084
--0.166073
--0.0880173
-0.265467
-0.329552
-0.0690311
-0.0174495
-0.0167115
--0.168974
-0.348481
-0.335865
-0.307235
-0.654294
--0.287585
--0.279582
-0.513296
-0.267101
-0.564634
-0.168991
-0.648243
-0.637508
-0.55296
-0.739468
-0.18187
-0.913414
-1.22599
-1.64598
-0.854333
-0.626253
-1.24064
-1.51379
-1.87453
-0.9572
-1.37372
-2.48049
-2.16455
-3.0389
-3.70996
-3.33661
-5.86879
-6.79741
-7.16878
-9.11224
-13.2758
-11.4371
-13.225
-14.7365
-14.7936
-17.4191
-18.4593
-19.0745
-16.926
-20.0385
-18.5518
-13.2249
-12.4899
-11.2511
-8.90312
-10.0924
-5.49743
-5.21076
-4.01326
-6.53204
-3.16187
-3.37753
-3.28158
-2.22183
-1.12238
-2.00552
-0.891229
-1.95961
-0.615243
-0.133886
-1.09018
-0.574464
-1.32978
-0.506618
-1.26163
-0.518715
-0.865711
-0.385852
--0.094652
--0.0754991
-0.262049
-0.158101
-0.56087
-0.119021
-0.121944
--0.071842
-0.143618
-0.107411
-0.308376
-0.498622
--0.0703792
-0.335314
-0.249997
--0.273355
-0.341562
-0.243151
-0.105816
--0.126609
--0.0361527
--0.129887
-0.240493
-0.0171731
-0.101164
-0.75026
-0.109026
--0.0361648
-0.0456069
-0.190851
--0.122934
-0.710792
-0.479736
-0.247578
-0.579349
-0.465964
-0.0563953
-0.416991
--0.0188001
--0.13228
-0.613883
-0.196916
-0.0376867
-0.0529897
-0
-0.11302
--0.525485
-0.0182775
--0.091341
--0.0185763
--0.0198605
-0.158091
-0.520109
-0.408967
-0.48778
-0.110718
-0.444505
-0.256122
-0.337619
-1.07418
-0.314692
-0.0377443
-0.589534
-0.223748
--0.273511
-0.0703394
-0.584634
-0.415098
-1.41825
-0.0359364
-0.799932
-0.58092
-0.218183
-0.974318
-0.659814
-0.24428
-1.14648
-0.873337
-0.672351
-2.03605
-2.19829
-3.81369
-2.92183
-3.31407
-3.65622
-7.78378
-6.32121
-8.76435
-11.164
-11.0988
-13.8481
-18.7361
-18.6947
-23.6278
-24.3781
-24.659
-33.2369
-31.728
-26.8545
-26.655
-27.0924
-21.77
-16.5606
-16.6461
-15.0815
-13.3521
-9.56307
-9.05598
-6.92991
-4.31033
-3.62245
-4.92781
-3.72216
-3.79989
-1.80776
-1.07414
-2.30424
-1.02617
-1.09018
-1.63222
-1.52014
-0.951035
--0.00143686
-0.220281
-1.0713
-1.48994
-0.583152
--0.0359272
-0.0723841
-0.0708743
-0.746911
-0.560345
--0.36619
--0.0758249
-0.151664
-0.310992
-0.283323
-0.334922
-0.428873
-0.157143
-0.641404
-0.197053
--0.173957
-0.595207
-0.0689121
-0.24242
-0.0171438
--0.12174
--0.0363849
--0.0882906
-0.325057
-0.247497
-0.115752
--0.0851441
-0.0510351
--0.173029
--0.0314114
--0.0651366
--0.254709
-0.0547579
--0.068979
-0.0173488
--0.30241
-0.104661
-0
-0.111
-0
--0.470449
-0.0535047
-0.0741372
-0.320512
-0.367029
--0.0196736
-0.32553
-0.592575
-0.228388
-0.161126
-0.195273
-0.338884
--0.220897
--0.212357
-0.298475
-0.124471
--0.0386891
--0.250964
-0.130004
--0.357249
--0.0390495
-0.186876
-0.37168
-0.399558
-0.176014
-1.20579
-0.224896
-0.132274
-0.0348087
-0.621654
-0.43157
-0.853351
-0.670048
--0.0183516
-0.288289
-1.61682
-0.804023
-1.66622
-1.62667
-2.17252
-1.93521
-3.37181
-3.27931
-2.62799
-5.99717
-4.092
-7.0955
-6.30106
-9.07032
-11.628
-17.401
-15.1575
-22.3171
-26.952
-31.4224
-36.8315
-38.1439
-43.4674
-39.7753
-41.002
-39.4018
-35.2858
-32.1694
-29.1312
-25.4045
-22.6485
-14.8544
-13.7846
-10.6581
-8.37893
-5.8728
-4.39763
-4.30527
-3.89875
-2.97676
-3.42874
-2.68121
-1.23372
-2.45969
-0.860746
-0.902117
-0.63982
-0.419978
-0.817305
-0.468947
-0.51749
-0.681533
-0.105861
-0.32726
-0.222196
-0.406817
--0.090818
-0.938073
--0.451104
-0.0792659
-0.178664
-0.72901
-0.641689
-0.198555
-0.134037
-0.605625
-0.329977
-0.722632
--0.617897
-0.657071
-0.104873
--0.458005
--0.126096
-0.438599
--0.0719207
-0.33335
-0.140135
--0.41053
-0.28842
-0.0532854
-0.179625
-0.329239
-0.224198
-0.533342
-0.276948
-0.143156
-0.142382
-0.0509387
-0.0391003
-0.375033
-0.341491
-0.3388
--0.0660417
-0.113527
-0.0512535
-0.324138
-0.292146
--0.09262
-0.347392
-0.0547656
-0.470971
--0.0370119
--0.0710607
-0.530872
--0.124767
--0.0357752
-0.735869
-0.14603
-0.252128
-0.597776
-0.283477
--0.125326
--0.215494
-0.108087
-0.732672
-0.568588
-0.605543
-0.840418
-0.127907
-0.289004
-0.441418
-1.14296
-0.745491
-0.760679
-1.11553
-1.26698
-0.484865
-1.07663
-0.138127
-1.64245
-1.23593
-1.41824
-1.52179
-2.74795
-2.09428
-3.97491
-3.51267
-4.98716
-7.31188
-6.38341
-13.6845
-11.845
-18.5652
-22.2558
-31.2651
-32.3828
-41.0251
-42.6791
-49.513
-54.1855
-54.8342
-58.0679
-62.6208
-54.7264
-48.4518
-48.0431
-39.1029
-30.1057
-27.3446
-20.701
-18.4759
-14.0386
-9.80178
-9.27778
-6.72013
-4.21356
-7.22751
-1.54796
-1.96304
-2.98661
-1.21645
-1.39505
-1.22537
-0.845075
-1.17082
-0.605853
-1.73313
-0.517793
-0.490685
-0.316132
-0.391142
-0.459587
-0.878729
-0.828462
-0.387384
-0.27145
-0.123849
-0.119206
--0.106187
-0.255987
-0.75705
-0.309618
-0.668777
-0.146421
--0.0665534
--0.0734884
-0.401138
--0.134369
-0.377475
-1.0051
-0.341495
-0.197857
--0.360076
-0.105203
-0.192378
-0.34737
-0.0172802
-0.19385
-1.00647
-0.203224
-0.424954
-0.623116
-0.0667844
-0.0522856
-0.0166042
--0.0347624
-0.14391
--0.256319
-0.685422
-0.681609
--0.416199
--0.0725748
-0.0161738
--0.324545
-0.0172433
--0.091727
--0.0699901
-0.112336
-0.51253
-0.211525
-0
-0.103624
-0.020901
-0.448275
-0.258135
-0.589873
-0.286835
-0.41497
-0.101174
--0.0743074
-0.726655
-0.544487
-0.289295
-0.383883
-0.214537
-0.570566
-0.211541
-0.263426
-0.578161
-0.379998
-0.340134
-0.676983
-0.633966
-0.657283
-0.767808
-0.07039
-0.44821
-0.448991
-1.2525
-1.22191
-2.68199
-3.01327
-3.82054
-3.47958
-3.35621
-3.88307
-7.6021
-10.3561
-11.6593
-15.0534
-22.9072
-25.2132
-36.1921
-42.0649
-56.3665
-63.3081
-72.2666
-85.4957
-85.4617
-80.1535
-89.9541
-81.4183
-71.2164
-64.0418
-49.2224
-40.5905
-34.802
-28.0792
-20.1988
-19.7378
-10.6176
-10.7172
-5.67498
-4.966
-2.19345
-4.32129
-3.70639
-3.37175
-2.11685
-1.7806
-1.47094
-0.993694
-1.10179
-1.11612
-1.11279
-0.761911
-0.829741
-1.14401
-0.209462
-0.213478
-0.626104
--0.111752
-0.374898
-0.214345
-0.392644
-0.470696
--0.437949
-0.501093
-0.256025
-0.0535353
-0.501926
--0.283118
-0.247336
-0.16519
-0.305899
-0.439893
-0.28738
-0.289836
-0.0170105
-0.268954
-0.131259
-0.568108
-0.668844
-0.343521
--0.217167
-0.276509
-0.416437
-0.108729
-0.171768
-0.505477
--0.29828
-0.533557
-0.281032
-0.445432
--0.0365001
--0.421116
-0.436482
-0.151846
-0.145058
-0.294543
-0.293751
-0.286702
-0.0708829
-0.145052
-0.722112
--0.488432
-0.63044
--0.17809
-0.197288
-0.156491
-0.216196
-0.146145
-0.20363
-0.198978
-0.117317
-0.103935
-0.317255
-0.437274
--0.0377502
-0.395079
-0.0693461
-0.560657
--0.159543
-0.670022
-0.513833
-0.0172968
-0.328179
-0.7931
-0.120859
-0.618037
-0.687139
-1.13597
-1.32729
-1.19798
-0.511772
-2.17105
-1.74324
-1.02476
-3.33939
-3.03781
-2.98143
-3.96246
-5.82926
-7.72285
-8.3764
-10.586
-13.9445
-22.3895
-30.5152
-37.2873
-45.8124
-58.8489
-71.1854
-88.434
-110.942
-114.37
-119.263
-121.86
-125.671
-115.593
-106.452
-94.2648
-74.8025
-62.3428
-44.6983
-34.3745
-27.9026
-23.3048
-17.6317
-9.18259
-8.56589
-7.02753
-4.04308
-4.41056
-2.85463
-3.32545
-1.9154
-1.81994
-2.65476
-1.80045
-1.5247
-0.918251
-0.480574
-2.36824
-0.270656
-0.681058
-0.0713162
-1.0071
-0.618075
--0.128903
-0.580996
--0.166903
-0.297724
-0.69889
--0.123728
-0.0532726
-0.363685
-0.517963
-0.896793
-0.0733411
-0.0173132
--0.277112
-0.341439
--0.35438
-0.105879
-0.0175868
-0.016878
--0.213517
--0.0882138
-0.0177447
-0.0205885
-0.224742
--0.0133747
-0.189704
-0.528273
-0.0533658
-0.195321
-0.45943
-0.125854
-0.422951
--0.0346707
-0.156941
-0.100621
-0.101063
-0.328272
-0.329052
-0.0687812
-0.151517
-0.153413
-0.145923
--0.0355252
-0.407193
-0.327982
-0.387335
-0.42136
-0.328077
-0.239798
-0.0533424
--0.126553
-0.107995
--0.0182763
-0.407212
--0.172071
-0.202967
-0.434531
--0.124014
-0.308547
--0.0187947
-0.424419
--0.0623468
-0.566195
-0.161218
-0.510587
-0.259919
-0.70684
-0.123971
-0.125796
--0.459655
-0.85633
-1.1697
-0.145032
-1.31658
-2.03361
-1.75492
-2.57307
-2.23607
-2.33317
-3.85697
-4.49903
-5.30587
-3.49365
-7.45978
-10.0563
-14.2037
-19.6439
-24.6499
-36.3691
-49.6675
-61.5409
-82.3838
-104.713
-125.705
-108.574
-77.2638
-53.3722
-54.5046
-62.2914
-95.0392
-124.146
-123.325
-108.816
-72.3151
-58.2831
-48.3018
-37.5351
-24.909
-16.7409
-15.7235
-9.53752
-8.9575
-4.92093
-4.63685
-3.8284
-1.42852
-2.86701
-1.95989
-2.98379
-0.87873
-2.86649
-0.38074
-1.18152
-0.821325
-0.524369
-0.973314
-0.979411
-0.136859
-0.0537476
-0.096758
-0.319464
-0.204329
-0.28267
-0.135492
-0.192958
-0.201862
-0.504098
-0.349097
-0.400504
--0.493706
-0.598617
-0.406861
-0.221282
-0.259628
--0.125499
-0.195426
-0.0527614
-0.423742
-0.0199696
-0.328662
-0.335718
--0.0715978
--0.0870616
--0.0846206
-0.0173802
-0.686522
-0.182164
--0.369931
-0.408333
-0.140304
--0.130173
-0.242848
-0.554584
--0.438376
-0.227798
--0.0353179
--0.0360852
--0.205054
-0.106672
-0.372625
-0.30979
--0.0921522
-0.0554169
-0.449551
-0.191414
-0.353469
-0.165834
--0.127027
--0.0766614
-0.34356
--0.0733645
--0.0370207
-0.527921
-0.371255
-0.431448
-0.892768
-0.422069
-0.424033
-0.345784
-0.0604388
-0.564124
--0.0362353
--0.687687
-0.542245
-0.40698
--0.266017
-0.842713
-0.858998
-0.650791
-0.272044
-0.845604
-1.09752
-1.87172
-1.71516
-1.28866
-3.07075
-2.51155
-1.79842
-2.98517
-3.98797
-5.77782
-8.66969
-10.1833
-15.2771
-22.9088
-36.5301
-38.6179
-52.5759
-77.1665
-110.065
-106.997
-50.881
-8.94304
-0.643552
--0.0908322
-0.151432
-0.217635
-2.76356
-24.2501
-88.0584
-126.316
-106.392
-73.5703
-54.1925
-47.0036
-29.1685
-18.8603
-17.0248
-13.7942
-8.36315
-6.53442
-6.86199
-3.78636
-2.8839
-2.02202
-1.81212
-2.44724
-0.805607
-1.67047
-0.746651
-0.700919
-1.36509
-0.747843
-0.703192
-0.290962
-0.420615
-0.677637
--0.0736844
-0.712994
-0.0181683
--0.036224
--0.129965
-0.248669
--0.019451
-0.461383
-0.336511
--0.163122
--0.196199
-0.454643
--0.307588
-0.153966
-0.0542602
-0.0195168
-0.261319
-0.253942
-0.330135
-0.488414
-0.108294
-0.495104
-0.197511
-0.253089
-0.0534762
-0.309854
-0.18997
--0.063887
-0.103164
-0.14015
--0.157254
-0.347076
--0.0679923
-0.288432
-0.277971
-0.0708685
-0.339537
-0.0522469
--0.354907
-0.400439
-0.401452
-0.105192
-0.339374
-0.0166755
--0.129005
--0.170151
--0.456339
-0.0529872
-0.0538359
-0.406655
-0.167254
--0.212186
-0.467266
--0.119904
--0.1672
-0.881872
-0.672277
--0.0695747
-0.0521976
-0.297471
-0.469162
-0.683122
-0.948533
--0.365571
-0.354376
-0.302696
-0.650401
-0.664103
-0.492452
--0.295701
-0.911782
-0.709823
-1.84364
-2.2094
-2.04663
-3.83683
-1.48495
-3.7586
-3.12062
-5.03785
-5.00575
-6.29252
-8.85068
-13.7549
-15.9891
-25.3296
-37.6115
-58.9613
-69.9077
-89.052
-94.1179
-20.8218
-0.856112
--0.160447
-0
-0.140963
-0.146911
-0.198069
-0.0211329
-0.14059
-3.87681
-59.9367
-119.511
-92.5841
-74.1467
-51.4637
-33.3852
-25.021
-15.8122
-11.6659
-11.1056
-6.28328
-3.19657
-3.96764
-3.83202
-2.66293
-2.78646
-2.47927
-2.80775
-2.55622
-1.74035
-0.413497
-1.53995
-1.24705
-0.389543
-0.488664
-0.337036
-0.661453
-0.417846
-0.63284
-0.691348
-0.068995
--0.202258
--0.106531
-0.470343
-0.113483
-0.646301
-0.515617
-0.172111
-0.16187
-0.337605
-0.593916
-0.222312
--0.0166058
-0.0181728
-0.634661
-0.0178866
--0.0367776
-0.107634
-0.0521608
-0.10566
-0.427897
-0.536012
-0.357102
--0.085565
-0.629632
-0.0480403
-0.0166739
--0.0849977
-0
--0.104592
-0.0549898
-0
-0.355571
-0.108762
-0.159074
-0.017612
-0.391053
--0.0364044
-0.0178399
-0.488707
--0.346829
-0.0753435
-0.342378
-0.258506
-0.52622
--0.0719488
--0.0719504
-0.201729
--0.269775
-0.404205
--0.124322
-0.255623
-0.891871
-0.340234
-0.972015
-0.360661
-0.360902
-0.183789
-0.106981
-0.165377
--0.234983
-0.585983
--0.0557124
-0.360156
-0.746702
-0.184644
--0.289505
-0.528698
-0.674876
-1.32982
-0.502848
-1.11119
-0.813212
-2.03354
-4.29155
-2.49829
-4.46399
-5.33103
-8.88864
-14.7739
-17.6145
-22.5769
-34.6103
-45.7756
-60.7473
-82.8161
-103.311
-22.5947
-0.406095
-0
-0.293643
-0.287867
-0
-0
-0.0521407
-0.0546082
-0
-0
-3.58127
-69.0903
-113.288
-88.5293
-62.7366
-44.86
-33.9379
-19.3004
-14.6167
-13.493
-7.31195
-4.32965
-6.53761
-2.17073
-3.45931
-0.908712
-2.72012
-0.701356
-0.485409
-0.865458
-1.32205
-0.387981
-0.581082
-0.467578
-0.387586
-0.696493
-0.188009
-0.697232
-0.26044
-0.406717
--0.0172948
-0.463935
-0.667234
-0.336068
--0.27301
-0.312126
--0.036765
-0.16062
-0.189995
-0.206161
-0.298383
-0.400217
-0.26881
-0.333933
-0.0712632
--0.175808
-0.45886
-0.356372
-0.0699012
-0.522966
-0.334749
--0.0338507
-0.4215
-0.10151
-0.0160248
-0.184727
-0.277248
--0.173077
--0.0696506
-0.316549
--0.0889787
-0.153047
-0.283651
--0.12517
--0.0712148
-0.804443
-0.470661
--0.280408
-0.490009
--0.279196
-0.529819
--0.237557
-0.0164554
--0.186146
-0.453744
-0.126778
-0
-0.222105
-0.708884
-0.817702
-0.42944
-0.110233
--0.0722925
--0.201946
-0.304431
-0.305697
-0.903122
-0.206539
-0.218342
-0.288834
-0.635679
-0.405648
-0.72168
--0.147482
-0.327501
-0.688453
-0.99485
--0.304329
-1.74818
-1.02902
-1.24246
-0.418776
-1.9452
-2.06527
-1.99088
-4.15998
-3.92528
-4.79849
-9.98809
-13.6061
-17.2928
-25.3216
-37.2367
-44.8365
-67.9681
-94.2849
-50.0362
-0.753071
-0
-0
--0.0915535
--0.100889
-0.1523
-0
--0.0953311
-0.144382
-0.117611
-0
-0.0554687
-13.9986
-97.9159
-97.9255
-66.1116
-45.5867
-31.0637
-33.1493
-15.4677
-13.8072
-6.4701
-6.79797
-4.23754
-5.04031
-2.40993
-3.32684
-2.88732
-1.91028
-0.992933
-1.92944
-1.29976
-0.736841
-1.27483
-0.914001
-0.115309
-0.742991
-0.566332
-0.793053
-0.479258
-0.351381
-0.413779
--0.164711
-0.429534
-0.709803
-0.1148
-0.385486
-0.118816
-0.152472
-0.785294
--0.0961053
-0.0547527
-0.570483
-0.108071
-0.161383
-0.249043
-0.446365
--0.110164
-0.0758414
--0.0724341
-0.288391
-0.0176152
--0.335905
--0.157503
-0.398107
--0.0332837
-0.181988
--0.119634
--0.0340298
-0.137956
-0.0991286
-0.187052
-0.148184
-0.68916
-0.264039
-0.0510993
-0.191959
--0.123965
--0.0352487
--0.0345355
-0.447016
-0.0852059
--0.036089
--0.117288
--0.105652
--0.168247
-0.234402
-0.380247
-0.378439
-0.829467
-0.228556
--0.204412
--0.304685
-0.229127
--0.195916
-0.286339
-0.105341
-0.304737
-0.0549912
--0.0693267
--0.0704923
-0.314139
-0.294852
-0.452716
-0.297277
-0.624364
-0.0352542
-0.673337
-1.18732
-0.664611
-0.598292
-2.59121
-2.2916
-2.17615
-1.76267
-4.53718
-4.30054
-5.33308
-7.89795
-9.32301
-10.8503
-13.2864
-26.1742
-37.8448
-52.6493
-75.5209
-90.5142
-18.8925
-0.283633
-0.148251
-0.140393
-0.0537586
-0
-0
-0
--0.0341989
--0.127425
-0.145384
-0.0527896
-0.144033
-0.824212
-65.8601
-107.407
-71.7511
-52.0732
-41.5081
-25.3234
-21.4897
-14.8095
-7.61446
-8.82004
-5.30809
-3.02554
-2.86101
-2.78139
-1.74242
-2.19964
-2.11888
-0.98333
-1.25033
-0.0906081
-0.643193
-0.666455
--0.287995
-0.720173
-0.125305
-0.590807
--0.0189223
-0.764892
-0.412404
-0.272002
-0.4171
--0.0163075
-0.0558523
-0.212353
-0.143597
--0.0355925
-1.29634
-0.192272
-0.069683
-0.354503
-0.0683675
-0.511889
-0.244918
-0.0170427
-0.185981
--0.0162038
-0.0163835
--0.0709735
-0.292522
--0.172701
-0.3831
--0.293286
--0.332889
-0.258702
-0.195121
-0.289083
-0.440394
-0.0871848
-0
-0.241755
-0.257124
-0.0168458
-0.448431
-0.44499
-0.0163607
-0.262583
-0.104324
-0.0180361
-0.0692298
-0.262105
-0.138711
-0.108201
-0.217495
--0.159093
-0.127229
--0.0357462
-0.0169819
-0.347627
-0.189092
-0.0180991
-0.239212
-1.06983
-0.233929
-0.183153
-0.572192
-0.210271
-0.724281
-0.0177739
-0.415354
-0.123575
-0.586827
--0.111742
-0.351526
-1.42391
-1.36088
-0.925314
-0.851184
-1.71103
-1.12582
-0.79933
-2.18332
-3.90411
-3.60403
-4.79603
-6.65894
-6.27312
-9.32791
-12.0998
-19.2394
-20.3396
-37.5408
-56.9349
-76.5237
-67.2874
-5.81281
-0
-0
-0
-0
--0.0920995
-0.138877
-0
--0.0349674
--0.0922684
--0.0866864
-0
-0.0535954
-0.154307
-31.7646
-101.661
-79.6929
-58.5534
-44.1189
-23.1626
-20.5079
-15.342
-8.89743
-7.95551
-4.18498
-4.75599
-3.65351
-2.13153
-2.66402
-2.64316
-1.88219
-1.23774
-1.44807
-0.397551
-1.06047
-1.17874
-0.236679
-1.25063
-0.396374
-0.0914409
--0.0733614
-0.386912
--0.00147651
--0.116905
-0.581502
-0.169456
-0.134705
-0.107384
-0.750599
--0.0776889
-0.0368283
-0.107426
-0.194019
-0.170805
-0.0728025
-0.266234
-0.0543795
-0.0179499
--0.126323
--0.184601
-0.0738871
--0.216003
-0.189047
-0.332016
-0.296196
--0.0353567
-0.148942
-0.270216
-0.0543109
-0.283764
--0.0716027
-0.0715148
-0.111102
--0.116729
-0.41609
-0.394682
--0.274676
-0.017598
-0.0179094
-0
--0.0361388
-0.343958
--0.0359259
--0.0367672
-0.341223
-0.237847
-0.0517339
-0.768612
-0.203076
-0.107351
-0.147082
-0.50674
-0.0728034
-0.695307
--0.10412
-0.165368
-0.396242
-0.477518
--0.0742751
-0.30787
-0.321376
-0.129543
-0.224051
-1.31612
-1.48582
-0.399098
-0.994851
-0.756997
-2.23204
-1.06917
-2.44791
-0.625682
-2.25164
-1.98221
-3.3162
-3.33963
-3.19389
-4.48059
-3.34386
-7.85423
-7.98686
-12.7424
-19.6435
-29.4412
-38.7151
-58.5631
-83.1859
-73.4251
-3.44259
-0.148094
-0.148605
--0.0953447
-0
--0.0918448
--0.0905585
--0.0363038
-0
--0.0894567
-0
-0.146667
-0
-0.298152
-21.0696
-108.87
-78.0379
-59.3239
-37.7352
-30.0628
-20.9116
-13.8528
-8.01519
-6.31127
-2.61084
-3.96616
-2.767
-3.69647
-2.01309
-1.32521
-2.59507
-1.13072
-0.945518
-0.589156
-0.793042
-0.300041
-0.840081
-0.600371
-0.576688
--0.234924
--0.0568638
--0.0368792
-0.155379
-0.582768
-0.281338
--0.0713163
-0.167345
-0.256876
-0.518592
-0.497378
-0.15692
--0.265624
-0.341372
--0.214526
-0.107972
-0.292116
-0.372038
-0.171752
--0.166287
-0.106468
-0.212825
-0.334687
-0.198906
--0.126838
--0.619474
-0
-0
-0.276824
--0.105073
--0.0702916
-0.325401
-0.186437
-0.0172156
-0.240736
-0.19299
-0.16119
-0.453977
-0.354744
-0.476198
-0.341008
--0.018858
--0.0355371
-0.103881
-0.311806
-0.131178
-0.152731
-0.192074
-0.282269
--0.0362894
--0.0376498
-0.386519
-0.166588
-0.27383
-0.457663
-0.0528648
-0
-0.179226
-0.0775784
-0.57515
-0.726619
-0.330505
-0.169628
-0.0350573
-0.515389
-0.583092
-0.169509
-0.755204
--0.115328
-1.21462
-1.08884
-0.730808
-1.19409
-1.76043
-2.8301
-1.58282
-3.57062
-3.93853
-4.47264
-5.66657
-8.32722
-12.2378
-13.1222
-18.4209
-32.3232
-41.4531
-62.3995
-81.895
-66.9679
-1.36049
-0.147653
--0.183228
-0
-0.0556436
-0
-0.152745
--0.0737313
-0
-0.154483
--0.186186
-0
-0.151874
-0.152283
-20.9167
-103.627
-81.5877
-59.9776
-37.5497
-28.2177
-18.0747
-14.5934
-7.70572
-6.31504
-4.20956
-5.27343
-2.85586
-3.3171
-1.42807
-1.86733
-1.86485
-1.03144
-2.16123
-0.638078
-0.148757
-1.60077
-0.358284
-0.965746
-1.2375
-0.188601
-0.317982
-0.429132
-0.409419
--0.113766
-0.106483
-0.209731
-0.402995
--0.0748352
-0.41286
-0.467394
-0
--0.0172566
--0.363578
--0.10942
-0.0390681
-0.215324
-0.255221
--0.214924
-0.624031
-0.164429
--0.126265
-0.201394
--0.187425
--0.093118
--0.0689105
-0.242542
-0.497666
--0.202415
-0.197264
-0.336894
-0.0549541
-0.0170015
-0.315002
-0
--0.0956575
--0.0940049
-0.0723959
-0.0542892
-0.343281
-0.0533735
-0.454784
-0.0555347
-0.483081
-0.0550195
-0.253401
--0.0384166
--0.170378
-0.0168586
-0.43254
--0.164732
-0.434671
-0.0727279
-0.0510447
-0.34092
-0.49101
-0.0714441
-0.169138
--0.0561387
-1.13393
-0.558724
-0.363149
-0.167928
-0.407911
-0.0348037
-0.270829
--0.0558027
-0.491484
-0.843398
-1.2646
-1.85268
-1.33391
-1.21589
-0.942605
-1.87713
-2.64782
-2.40245
-2.23784
-5.31096
-3.49785
-6.88352
-10.1648
-15.5412
-18.7323
-24.7691
-42.3947
-64.5863
-75.7846
-78.7438
-6.6865
-0.144849
-0.141803
-0
-0
--0.0354532
-0.0532748
-0
-0.143821
-0.0519651
-0
--0.0334403
-0.0199738
--0.086518
-25.9225
-119.997
-80.8928
-53.8214
-39.9276
-34.2985
-19.2925
-13.2456
-9.54579
-7.25787
-6.03225
-5.17878
-3.42907
-2.89575
-1.48356
-2.45411
-2.1891
-1.63051
-0.878132
-0.684075
-0.0162712
-0.837778
--0.0347208
-1.06679
-0.213972
-0.690111
-0.217854
-0.618807
--0.118321
--0.170187
--0.162286
--0.159266
-0.546915
-0.854332
--0.0371772
-0
-0.612129
--0.103997
-0.109815
--0.110563
-0.334799
--0.213656
-0.548563
-0.325922
-0.477917
--0.119785
--0.124094
-0.0544313
-0.155193
-0.292829
--0.0716857
-0.136279
--0.0341836
--0.117406
-0.370028
--0.267754
-0.129998
-0.229333
-0.329747
-0.188285
--0.0354325
-0.246065
-0.016106
-0.206051
-0.3065
-0.199152
-0.234315
-0.302546
-0.262748
--0.0939474
-0.0852152
-0.344508
-0.449738
--0.0367742
-0.154019
--0.0357844
-0.0637786
-0.426446
-0.808325
-0.559963
-0.151296
--0.0188347
-0.151037
-0.0179147
--0.0187371
-0.354522
-0.422598
-0.232172
-0.179299
-0.391299
-0.786157
--0.118416
--0.291333
-0.451102
-0.571928
-1.35523
-0.841286
-1.28852
-1.23628
-1.86949
-2.21703
-3.64859
-2.02667
-5.13427
-5.87181
-7.41736
-10.7306
-13.065
-15.6519
-22.1073
-36.3334
-48.0875
-70.4022
-95.5204
-21.7008
-0.152583
-0.574957
-0.151581
-0
-0
-0
-0
-0
--0.0967614
-0.147851
-0.153359
-0.423716
-1.06873
-58.5465
-100.571
-82.0754
-50.5826
-31.8275
-22.0229
-16.8445
-11.3526
-7.10499
-9.20481
-6.21287
-3.20155
-4.23581
-2.27471
-1.1991
-2.58592
-2.60515
-0.820755
-1.44181
-1.59624
-0.568554
-0.758663
-0.309277
-0.39626
-0.652025
-0.512527
-0.267109
-0.833158
-0.330526
-0.706446
-0.0169349
-0.195785
-0.349286
-0.0741789
-0.429362
-0.0732597
-0.247488
-0.532463
-0.194686
-0.470344
-0.392559
--0.0716333
-0.291724
-0.357305
--0.388612
-0.199108
-0.298589
-0.109877
-0.405697
-0.190717
-0.691324
-0.149095
-0.664672
-0.0491691
-0.0982457
-0.0504424
-0.185356
-0.514189
-0
-0.412437
--0.067414
-0.453104
-0.104954
-0.195686
-0.050525
--0.117318
-0.10638
-0.188908
-0.265884
-0.193583
--0.121355
-0.300864
-0.337505
-0.153737
-0.426807
-0.341088
-0.47514
-0.467303
-0.182127
-1.25076
--0.41574
--0.108529
-0.0544948
-0.156624
-1.16394
-0.481033
-0.755535
-0.623625
-0.600534
-0.138546
--0.0703918
-1.5296
-0.983573
-1.19529
-0.750463
-1.80541
-1.45163
-2.01687
-1.15562
-1.25826
-1.58516
-2.95129
-2.24446
-4.81673
-4.59354
-7.47579
-7.99885
-11.8319
-15.7237
-21.6205
-31.8039
-49.031
-66.4624
-100.053
-56.3703
-2.12952
-0.327555
--0.0885675
--0.0362494
-0
-0.139156
-0.144545
-0.150896
-0.112378
-0
-0.136394
-0
-15.591
-110.58
-91.1108
-67.8199
-46.0094
-33.81
-23.5601
-15.5194
-11.0044
-9.51983
-5.90266
-4.6146
-3.72964
-2.05302
-3.35774
-1.84486
-1.61551
-1.40732
-1.46194
-0.574953
-0.616427
-0.787353
-0.697033
-0.328959
-1.56395
-0.591325
-0.687976
-1.16795
-0.345449
--0.0716486
-0.269925
-0.82305
-0.0176038
-0.699425
--0.0687921
-0.123445
-0.337946
--0.066997
--0.0189537
--0.16172
-0.378626
-0.244305
-0.23548
-0.104725
-0.0167955
--0.122414
-0.330245
-0.150159
--0.0723071
--0.0903175
-0.182912
-0.420672
-0.188896
-0.260864
--0.0670322
-0.232264
-0.451439
-0.0517341
-0.0526741
--0.0718704
-0.102627
-0.258061
-0.106984
--0.125589
-0.640836
-0.107255
-0.357923
-0.0532028
-0.202313
--0.0362875
--0.135167
--0.349431
--0.0152527
-0.108945
-0.0176919
-0.31519
-0.0173292
-0.874334
-0.367972
-0.60293
-0.127909
-0.393556
--0.220838
--0.180259
-0.264699
-0.331478
-0.223464
--0.250474
-0.507814
-0.301151
-1.01378
-0.606569
-1.11487
-0.829966
-0.940248
--0.00142396
-0.983201
-1.11317
-1.49716
-1.93824
-2.40148
-1.92746
-2.57739
-2.18511
-4.17636
-4.42313
-5.69832
-8.16296
-13.5129
-16.667
-21.3957
-28.204
-39.788
-54.262
-73.3887
-96.2673
-27.3615
-0.430387
-0
-0
-0
-0.299101
-0.213447
-0.150158
-0
-0.147415
-0
-5.27931
-70.9056
-115.932
-84.5198
-56.742
-37.7741
-29.3423
-22.1226
-13.8526
-11.3452
-9.46954
-7.45688
-5.63618
-3.86033
-3.62704
-2.75979
-2.22426
-1.73058
-2.26829
-2.31945
-2.13712
-0.501324
-0.668276
-0.463699
-1.00162
-0.583394
-0.799548
-0.623608
-1.46217
-0.428931
--0.551343
-0.558096
--0.0722892
--0.071264
-0.218208
-0.400281
-0.490841
-0.300241
-0.154211
-0.398675
--0.0745156
--0.375411
-0.287851
-0.107929
--0.470791
-0.40595
-0.385025
-0.344616
--0.0555676
-0.0546783
--0.221619
--0.0362621
--0.0354219
-0.16289
-0.195105
-0.0512456
-0.0501232
--0.20953
-0.0496353
-0.313659
--0.271782
--0.0693657
--0.12643
--0.120029
-0.0731111
-0.26756
-0.194496
-0.290394
--0.160004
-0.110887
-0.196848
--0.387291
-0.105455
-0.465858
-0.187994
-0.10591
-0.548145
-0.405938
--0.0190342
-0.592773
-0.771599
-0.58124
--0.355118
-0.0731428
-0.178739
-0.219981
-0.213104
--0.201622
-0.619981
-0.213047
-0.255571
-0.671488
-0.017169
-0.563195
-0.167464
-0.660123
-0.436096
-1.02487
-1.24286
-0.784595
-1.79459
-2.9081
-1.928
-3.05773
-1.24058
-3.77587
-3.52055
-6.50095
-8.92752
-9.58114
-10.5145
-16.5727
-29.2358
-34.1363
-50.7992
-70.943
-95.2934
-93.9729
-28.1357
-2.21841
-0.45339
-0.29825
-0.139978
-0
-0.296329
-0
-0.146391
-4.97264
-62.9348
-121.645
-94.5953
-71.5838
-50.196
-34.5145
-24.1061
-20.5881
-11.8421
-11.6062
-5.29119
-6.57678
-3.92307
-4.09172
-1.77835
-3.07288
-2.1835
-1.32186
-1.3253
-1.46196
-1.66338
-0.500381
-1.22497
-0.819248
--0.44501
-1.44044
--0.0565153
-0.198554
-0.548231
--0.37447
-0.696985
-0.9515
-0.465507
-0.60693
--0.304112
-0.285821
-0.107337
-0.0558177
--0.125051
-0.311943
-0.106207
-0.111014
-0.0174074
-0.149691
--0.217741
-0.492407
-0.168501
-0.0172581
-0.14194
-0.0554051
--0.181694
--0.213702
-0.42352
--0.181775
-0.105781
--0.200927
-0.0950501
-0.493044
-0.319266
-0.270374
--0.0358653
-0.410303
--0.0341797
-0.0522731
-0.198318
-0.344285
--0.0642212
-0.101596
-0.0519686
-0.198597
-0.0711756
--0.187773
--0.346385
--0.0361803
-0.413743
--0.126517
--0.0358
-0.531469
-0.386351
-0.0535866
-0.069551
-0.484547
-0.194695
-0.44616
-0.123266
-0.797333
--0.0197925
-0.0760986
-0.312698
-0.0181396
-0.0728334
-0.124598
-0.430775
-0.162176
-0.365293
-1.13586
-0.651251
-2.00828
-1.85455
-1.73151
-1.84232
-1.04837
-2.00898
-0.379878
-2.25564
-2.77919
-5.79411
-5.97719
-4.47076
-10.2988
-12.3333
-16.3331
-20.7427
-31.5807
-36.1597
-53.8966
-73.4918
-103.1
-111.612
-51.5563
-18.3365
-3.39122
-1.32912
-0.433858
-1.65208
-6.2351
-34.3143
-87.782
-117.079
-99.1416
-76.4033
-57.5015
-39.2986
-27.2527
-21.0011
-15.8825
-11.5437
-8.97175
-7.00826
-4.80279
-2.92154
-1.88339
-1.9145
-2.23654
-1.07555
-1.60002
-0.594293
-0.286338
-1.27342
-0.636039
-0.964095
-1.39472
-0.585752
-0.00125873
-0.858149
--0.111703
-0.965146
-0.170057
-0.365427
-0.530063
-0.0536734
-0.00121494
-0.0537457
-0.0684639
-0.131456
-0.657699
-0.713035
-0.165161
-0.110119
-0.196597
--0.0733577
-0.836888
-0.0547049
-0.0555246
-0.625534
-0.487325
-0.195499
-0.0555502
-0.333198
--0.12552
-0.442628
-0.12789
-0.102025
-0
-0.287375
-0.136504
-0.246985
--0.300915
-0.0546414
--0.169536
-0.399169
-0.201791
--0.0729714
-0.588253
--0.22232
-0.110388
-0.592922
-0.255887
--0.0737115
-0.280346
-0.413611
-0.252612
-0.763962
-0.0707765
-0.776314
-0.104911
-0.489494
-0.942232
-0.129531
--0.260325
-0.410022
-0.105615
-0.220761
-0.234997
--0.130571
-0.532186
-0.104996
-0.158484
-0.443352
-0.956076
-0.37326
-0.462977
-0.917838
-0.728422
-0.0878797
-1.07907
-0.971586
-1.38288
-1.50824
-2.16758
-1.73075
-3.0052
-2.29413
-3.62256
-3.21178
-6.23499
-4.8317
-6.87136
-9.80691
-15.6712
-19.624
-26.2531
-30.5937
-45.5555
-60.6081
-77.5269
-99.2397
-132.305
-110.924
-95.0273
-70.9709
-64.8408
-84.7112
-98.2365
-130.534
-116.056
-104.003
-75.9195
-57.9329
-46.0284
-31.3843
-25.1766
-19.9161
-14.4199
-10.4232
-6.57772
-5.69324
-4.3772
-2.05938
-4.31349
-1.91889
-2.53942
-2.76215
-2.07995
-2.06982
-1.60646
-0.411714
-1.16576
-0.410951
-1.37598
-0.498454
-0.686547
--0.163978
-0.40898
--0.228177
-0.222005
-0.0369225
-0.231423
-0.415708
-0.24963
-0.0344429
-0.531288
--0.037958
-0.251285
--0.035198
-0.556874
-0.265975
-0.367508
-0.163703
--0.0190771
--0.22503
--0.0745869
-0.689062
-0.339169
-0.0170583
-0.722922
-0.303726
--0.12874
-0.270897
-0.242605
-0.101535
-0.0999827
--0.163348
-0.107816
-0.0506178
-0.506996
-0.244014
-0.101728
-0.295392
--0.0845442
-0.175849
-0.144335
-0.309001
--0.0894798
--0.358588
-0.0545992
-0.263549
-0.293919
-0.100753
-0.458498
-0.28931
--0.210964
--0.122877
-0
-0.357008
-0.364699
-0.472271
-0.259926
-0.715316
-0.200569
-0.305507
-0.911345
-0.427906
-0.348013
-0.201721
-0.348558
--0.0691106
-0.129309
-0.780708
-1.04702
-0.992497
-1.0553
-0.343891
-0.976476
-0.53581
-0.815833
-1.11596
--0.129704
-0.872313
-2.41474
-2.6535
-2.50183
-4.03814
-4.12483
-4.59003
-7.24641
-6.18678
-12.882
-12.7033
-19.7366
-26.8285
-29.8399
-48.4103
-57.4714
-70.4888
-95.8462
-92.1611
-104.105
-122.846
-128.456
-127.952
-124.908
-96.2528
-83.2134
-76.978
-57.6784
-48.1708
-35.352
-25.087
-19.917
-15.2913
-12.3679
-7.0151
-5.75238
-4.28407
-4.35167
-2.89112
-2.52249
-1.91012
-2.26511
-1.75203
-1.73224
-0.886944
-0.806105
-0.593405
-0.076652
-0.335675
-0.69499
-0.266438
-0.446699
-0.449491
-0.65509
-0.219349
-0.434385
-0.0693751
-0.843269
-0.107567
-0.130132
-0.475106
--0.0362852
-0.0181511
-0.363825
-0.0171248
-0.142269
-0.327828
-0.0562664
-0.106322
-0.145997
-0.246865
-0.423378
-0.346433
-0.490279
--0.174491
-0.256208
-0.209644
-0.351524
--0.0677337
-0.163388
--0.202361
-0.137425
--0.204815
--0.20751
--0.153712
--0.173055
-0.575485
-0.384967
-0.394431
-0.244853
-0.107396
--0.113201
--0.121266
-0.25392
-0.142795
--0.0937556
-0.504411
-0.0206124
-0.350639
--0.0967288
-0.427677
-0.0688255
-0.249041
-0.0541165
-0
-0.474671
-0.104415
-0.314236
-0.319881
-0.106656
-0.3633
-0.307589
-0.349735
-0.0184719
--0.0194112
-0.15949
-0.212119
-0.775391
-0.164625
-0.615725
-0.476356
-0.740082
-0.513698
-0.883652
-0.521377
-0.720252
-1.26636
-0.70136
-1.92994
-1.73308
-1.17962
-2.6585
-3.99567
-4.04132
-3.2717
-6.84903
-8.7661
-9.72078
-11.6143
-16.4161
-22.0591
-26.6384
-29.6779
-40.3123
-56.9718
-60.2799
-73.4769
-86.5527
-86.2621
-91.8981
-80.0294
-82.6904
-69.9249
-67.4717
-53.5754
-41.4389
-32.1441
-23.2573
-18.7532
-17.0091
-11.1502
-11.5133
-5.29765
-5.88707
-3.84198
-4.15902
-5.67159
-3.31417
-1.73663
-2.26765
-3.04849
-1.4703
-0.751284
-0.872324
-1.17943
-0.78245
-0.345223
-1.10964
-0.489773
-0.302394
-0.649226
--0.265008
-0.591541
-0.533777
-0.157098
-0.610975
--0.215131
-0.216634
-1.14103
-0.568312
--0.0191999
-0.481641
-0.237991
-0.554779
-0.197483
-0.339256
-0.294079
-0.196817
-0.0520339
--0.241723
--0.0746218
--0.124264
--0.036225
--0.251992
--0.345294
-0.135329
--0.123849
-0.764119
-0.0940897
-0.0499511
--0.0339402
-0.11737
-0.0499876
-0.209794
-0.019426
-0.655315
-0.575982
--0.247136
-0.294911
--0.49138
-0.291755
-0.190449
--0.118808
-0.0165261
-0.133856
--0.0743679
--0.295096
--0.191502
-0.0529252
-0.106788
-0
-0.0171412
-0.328362
--0.0188617
-0.0719247
-0.36747
-0.276126
-0.58661
--0.0720791
-0.0172674
-0.147037
-0.385606
-0.204983
-0.639267
-0.633684
--0.433925
--0.0546927
-0.0179527
-0.615229
-0.616014
-0.229522
-0.95884
-0.405602
-0.36386
-1.24422
-1.43199
-1.07294
-2.64465
-1.51688
-2.97096
-1.53306
-2.7804
-4.06614
-5.24979
-3.82071
-6.32595
-8.43015
-10.8368
-17.3166
-20.6334
-20.7687
-32.5565
-35.9276
-43.6693
-44.2187
-57.1756
-54.2788
-61.5865
-60.2921
-51.9451
-47.8699
-38.773
-42.924
-32.8534
-28.3236
-16.7572
-16.8177
-11.4954
-12.0219
-6.14961
-5.94567
-4.48553
-3.27927
-1.82864
-4.67704
-3.41641
-1.56607
-2.27556
-1.04943
-1.10468
-0.95635
-1.00135
--0.11009
--0.56738
-0.683542
-0.333876
-0.242014
-0.236068
--0.0543021
-0.600066
--0.316905
-0.386308
-0.801337
-0.619762
-0.266446
-0.175365
-0.377893
-0.406618
-0.216033
--0.0204061
-0.163337
--0.372513
--0.0359154
-0
-0.396931
-0.105415
-0.0172471
--0.199497
-0.158744
-0.475864
-0.539938
--0.0389973
-0.0554946
-0.0543117
-0.382798
-0.471982
--0.0664831
--0.0348931
--0.33778
-0.33748
-0.836304
-0.194471
-0.198481
-0.325712
-0.0551333
-0
-0.346035
-0.503831
--0.0156116
-0.579998
-0.141333
-0.360419
-0.30156
--0.163415
-0.0190465
--0.0165192
--0.0359888
-0.102347
--0.074743
-0.0530169
-0.460964
-0.3184
--0.0660795
-0.491666
-0.1447
-0.535542
--0.265666
-0.197728
-0.31539
--0.0543198
-0.32664
-0.12388
-0.366321
-0.271716
-0.759023
-0.82172
-0.892258
-0.1331
-0.429654
-0.245241
-1.42231
-0.886766
-0.47152
-1.02545
-1.69261
-1.66576
-0.451236
-2.25085
-2.50821
-3.12289
-3.52093
-3.33046
-2.93765
-5.36942
-8.56626
-8.89959
-13.5267
-12.2545
-18.6362
-21.4956
-24.5338
-30.7151
-37.8224
-37.6669
-38.6305
-43.7708
-40.0303
-37.6685
-33.3247
-32.0966
-29.5281
-24.4975
-19.4686
-14.7648
-9.75144
-8.60517
-7.23077
-7.26404
-5.88018
-3.94787
-2.20625
-3.69858
-2.7818
-1.2167
-1.03385
-2.29476
-1.0734
-0.756359
-1.17224
-1.06867
-0.861607
-0.655706
-0.518695
-0.0579879
-0.632346
-0.545526
-0.596985
--0.0185588
-0.0543306
-0.241488
--0.0714664
--0.036985
--0.247927
--0.403781
-0.260813
-0.734798
-0.208621
-0.40721
-0.164667
-0.783621
-0.353727
-0.25641
-0.345719
-0.297979
-0.16198
-0.400226
-0.198551
-0.573411
-0.19618
-0.433906
-0.109826
--0.12024
--0.212241
-0.357311
-0.242242
--0.0815128
-0.0480177
-0.235164
--0.113176
-0.866768
--0.258014
--0.154016
-0.219509
-0.235995
-0.019048
-0.0572225
--0.173943
-0.481388
-0.740801
-0.336111
-0.189748
-0.446073
-0.431177
-0.435744
--0.0360611
--0.0679422
-0.333436
-0
--0.165043
-0.327795
--0.0340005
-0.13716
--0.127576
-0.528732
--0.173634
-0.363476
--0.179498
-0.663881
-0.0535319
-0.533225
-0.342855
-0.738758
-0.496365
-0.452365
-0.660661
-0.188828
-0.71479
-0.552802
-0.914581
-0.892508
-0.17918
-0.633037
-2.05367
-1.96116
-0.697455
-1.92081
-2.82573
-2.16891
-3.53849
-4.24879
-3.66647
-5.38978
-8.74283
-6.67832
-8.14942
-9.54457
-13.3746
-14.9297
-17.5087
-22.2714
-25.1098
-27.711
-22.3257
-24.8829
-27.5411
-25.2851
-26.1281
-19.0455
-16.7939
-18.0282
-14.0557
-11.2772
-11.955
-7.5383
-6.34612
-5.26992
-5.03415
-3.62718
-3.69087
-1.74401
-1.18247
-2.16853
-0.974115
-0.966305
-0.947735
-0.126462
-1.24433
-0.817573
-1.60272
-0.965967
-0.267219
-0.288365
-1.02814
-0.414722
-0.0744362
--0.102885
-0.405083
-0.50622
-0.386981
-0.791632
--0.0183696
--0.037046
-0.162912
-0.108793
--0.545704
-0.218055
-0.530553
-0.414804
-0.206088
--0.180977
-0.105699
--0.364129
--0.0352786
--0.03567
-0.164622
-0.14712
-0.440013
-0.0171715
-0.248737
-0.137475
-0.289121
-0.332492
-0.0951741
-0.0511792
-0.0512241
--0.0359334
-0.416402
--0.0891416
-0.170733
-0.156881
-0.455567
-0.243085
--0.207552
--0.130004
-0.338029
-0.204626
-0.260698
-0.343866
--0.17507
-0.0564567
--0.122412
-0.0775506
-0.205214
-0.189789
-0.0560461
--0.450917
--0.0727219
-0.166089
-0.335412
-1.18598
-0.108351
--0.125136
-0.286818
--0.408229
-0.834874
-0.610223
-0.126137
-0.498998
-0.072395
-0.216889
-0.313962
-0.172284
-0.0708374
--0.0196319
-0.451021
-0.309083
-0.328815
-0.920683
-0.937218
-0.890841
-0.976619
-1.16337
-1.63937
-2.51641
-1.29598
-1.48311
-3.24475
-2.67608
-4.09098
-5.21471
-4.66296
-4.63199
-7.41376
-8.64746
-9.82995
-12.1812
-10.0262
-14.0292
-15.924
-15.9151
-18.6915
-21.7536
-18.1974
-18.1447
-16.9741
-15.4071
-12.3818
-16.5667
-9.98308
-8.41701
-10.6704
-6.18884
-4.53233
-4.0714
-3.41846
-2.65776
-2.71283
-3.87235
-1.76974
-1.06436
-1.40503
-2.19931
-0.0518188
-0.981005
-1.02487
-0.0940091
-0.868044
-0.181374
-0.209476
-0.645416
-0.0169801
--0.0192252
-0.510169
--0.036493
-0.215919
-0.199966
-0.204551
-0.170974
--0.303822
-0.455891
--0.0731966
--0.339207
-0.520547
-0.0530698
--0.125664
-0.107395
-0.549534
-0.166306
-0.0178012
-0.340733
-0.104175
-0.33588
--0.268945
-0
-0.539963
-0.0559437
-0.247879
-0.159126
--0.159254
-0.376375
-0.0184185
-0.240164
--0.0323774
-0.404676
-0.0524267
--0.119015
-0.184149
-0.565148
-0.0529254
--0.0331224
-0.520376
-0.0570204
--0.112777
--0.355111
-0.0163891
-0.345789
-0.311068
--0.0896939
--0.122708
-0.330733
-0.0163109
-0.0518764
-0.303951
--0.218806
--0.362804
-0.423771
-0.186677
-0.18326
-0.918827
-0.161725
-0.107109
--0.0729207
-0.501784
-0.502706
-0.910762
-0.0179943
-0.35271
-0.272465
-0.0344077
-0.690866
-0.538722
--0.0202886
-0.873206
-0.897917
-0.895482
-0.396309
-0.773053
-0.687765
-0.790092
-0.885991
-1.67947
-0.351902
-2.07318
-1.71146
-2.45722
-3.27517
-2.54054
-3.82495
-4.78992
-6.29712
-5.57297
-7.22156
-8.45689
-10.1709
-9.94816
-11.1237
-11.3214
-14.3259
-13.0033
-12.8377
-14.7576
-14.2411
-12.4835
-10.2217
-10.266
-9.47694
-7.52647
-6.3986
-5.54326
-5.00906
-4.56817
-4.89808
-2.97645
-1.60311
-1.97944
-2.26302
-2.74285
-0.968564
-1.56982
-0.868337
-0.943529
-1.44914
-0.232735
-0.284673
-0.0350813
-0.976062
-0.235933
-1.12833
-0.629856
-0.905711
-0.570669
-0.510922
-0.496253
-0.554318
-0.355851
-0.16998
-0.352565
--0.189111
-0.199626
-0.273559
-0.0713217
--0.0196181
-0.155611
-0.319766
--0.0714113
-0.370466
-0.339299
-0.110203
-0.052607
--0.264125
-0.342133
--0.0363034
-0.103545
-0.166725
-0.196023
-0.0508217
-0.195029
-0.017231
-0.268997
-0.316521
-0.0554127
-0.339852
-0.0207625
-0.0392909
-0.203411
-0.133164
-0.211183
-0.43113
--0.0374235
--0.0365833
--0.0366394
-0.282055
-0.0741213
--0.132075
-0.017975
-0.638943
-0.195273
-0.0180106
-0.30874
-0.136135
-0.665402
-0.524307
-0.225222
-0.455212
-0.0207833
--0.0364735
-0.10727
-0.500122
--0.0139412
-0.314513
-0.27053
-0.177836
-0.10735
-0.176655
-0.539792
-0.272469
-0.700198
-0.51871
-0.351704
--0.249336
-0.875161
-0.432019
--0.0740042
-0.680495
-0.81673
-0.321798
-1.99728
-1.06101
-1.88415
-0.980661
-1.75738
-1.86689
-2.74581
-1.61666
-2.09785
-2.98114
-5.0566
-3.50702
-3.74572
-6.1789
-4.10334
-5.25529
-8.25708
-8.31403
-6.1646
-7.26641
-13.1411
-8.72961
-12.677
-12.8399
-9.45018
-6.83741
-7.75354
-8.56392
-6.58914
-4.91209
-4.61865
-2.96242
-4.56074
-2.11782
-5.25933
-2.89895
-2.7636
-1.21895
-1.02176
-1.04768
-0.282589
-0.0903517
-1.25043
-0.602514
-0.437612
-0.589595
-0.999635
-0.0533391
-0.870742
-0.934709
-0.467058
-0.222837
--0.264403
-0.193707
-0.970969
-0.0172935
-0.790849
-0.616996
-0.611096
--0.0354657
-0.31516
--0.358325
-0.148457
-0.320421
-0.470245
--0.178412
--0.0363568
--0.0877986
-0.142644
-0.0524097
-0.397949
-0.377768
-0.309844
--0.449489
--0.0739711
-0.194922
-0.838295
-0.181797
-0.610169
-0.186476
-0.132256
-0
-0.456353
-0.145432
--0.332265
-0.338109
-0.0709857
-0.184437
--0.0334314
--0.0729635
--0.070053
-0.549775
--0.116816
-0.342327
-0.327041
--0.193598
-0.016984
-0.413497
-0.136836
-0.208399
--0.173725
-0.105264
-0.0538105
-0.479166
-0.571951
-0.172955
--0.301836
-0.26467
--0.2535
-0.480609
-0.111796
-0.401237
-0.211026
-0.0190684
-0.400934
--0.0756282
-0.541363
-0.467045
-0.375322
-0.538946
-0.818088
-0.0176142
-0.588667
-1.62406
-0.746709
-0.26886
-0.275707
-0.635582
-0.822995
-0.984388
-0.443432
-1.8992
-1.98651
-0.994685
-1.22043
-0.872254
-2.21553
-3.41493
-2.87114
-2.52975
-3.09457
-3.48135
-4.09181
-4.82689
-6.55912
-5.69695
-5.49628
-3.94394
-6.96081
-7.88041
-7.60822
-6.19787
-5.71533
-5.60975
-4.04245
-5.02805
-5.90776
-4.55268
-1.12996
-3.84421
-1.79025
-2.34958
-1.95427
-2.24778
-0.562156
-1.93668
-1.43556
-0.980043
-1.00609
-1.53143
-1.51651
-1.7321
-0.779429
-0.605496
-0.220103
-0.377841
-0.40525
-1.0874
-0.657893
-0.173792
-0.206725
-0.0179097
-0.442052
-0.19577
-0.158146
-0.11049
-0.194179
--0.314419
-0.465747
-0.204401
-0.0358452
-0.173964
-0.185632
-0.501332
-0.401274
--0.170488
-0.1636
-0.115735
-0.0543917
-0.0167297
-0.0536244
-0.54854
-0.32577
-0.872509
-0.140568
-0.530062
--0.290741
--0.212554
-0.154731
-0.0679886
-0.05597
-0.15526
--0.0715382
--0.0364618
-0.440245
-0.345866
--0.135462
--0.120313
-0.0559475
--0.370046
-0.470982
-0.282659
-0.395341
-0.493123
--0.0737183
-0.200419
-0.357062
--0.31401
--0.133041
--0.271389
-0
-0.380062
-0.112773
-0.0548728
-0.107522
--0.275542
-0.303207
--0.124059
-0.903859
-0.163088
-0.48862
-0.262418
-0.314437
-0.559669
-0.38168
-0.45942
-0.304564
-0.452951
-0.710571
--0.487886
-0.277331
-0.640855
-0.828891
-1.01022
-0.549986
-1.03093
-0.15494
-0.9115
-0.408605
-2.10114
-0.632061
-0.853478
-1.43838
-1.5589
-3.12486
-3.39256
-2.88488
-3.48173
-3.15901
-2.82039
-4.26519
-2.19327
-5.1559
-3.38999
-5.09999
-6.11803
-6.44148
-6.03296
-4.79218
-5.37591
-4.23428
-5.83938
-4.16852
-3.00753
-4.96979
-3.54399
-3.56257
-4.26608
-2.30309
-2.4085
-1.45216
-1.46308
-1.83219
-0.493652
-1.38163
-0.0162561
-1.91794
-0.744574
-1.36382
-0.264039
-0.601148
-0.701292
-1.07805
-0.723109
-0.691654
-0.0347586
-0.545429
--0.211688
-0.124165
-0.615773
-0.314248
-0.283577
-0.34096
-0.74491
-0.66969
-0.755994
-0.417801
--0.123552
-0.111836
-0.342846
--0.0710999
-0.547701
-0.321309
-0.249601
--0.161576
--0.151687
-0.258368
-0.201663
-0.301554
--0.0706661
-0.137608
-0.0173055
--0.0747797
-0
-0.44274
-0.187223
--0.119142
-0.55067
--0.185215
-0.296201
-0.455016
-0.460149
-0
-0.44956
-0.184433
--0.0359005
-0.0979029
-0.55094
-0.565466
-0.293166
-0.177947
-0.551846
-0.186257
--0.0366196
-0.255751
--0.0375508
-0.102957
--0.359841
-0.0167827
-0.424421
--0.0882676
--0.0360004
--0.205808
-0.743024
-0.343981
-0.680038
-0.199048
-0.0733266
--0.11905
--0.491015
-0.609308
-0.0734455
-0.349534
-0.148517
-0.347358
-0.969242
-0.207668
-0.106983
--0.0185773
-0.169955
-0.267658
-0.557049
-0.968976
-0.504407
-0.976429
-1.02819
-1.54916
--0.17615
-0.515693
-0.460801
-1.47099
-1.07891
-2.08608
-2.46832
-2.20232
-1.48907
-2.68928
-2.57013
-4.8747
-3.02773
-3.68478
-3.75407
-3.62246
-2.82323
-4.69495
-2.25949
-4.22367
-4.81349
-4.65138
-4.72587
-4.14931
-4.30467
-2.7388
-2.46364
-2.93846
-1.80832
-1.97659
-1.82758
-1.57408
-1.55904
-1.31596
-1.58213
-1.65295
-2.12321
-1.58376
-1.23672
-0.291778
-1.19609
-1.17338
-0.710518
-0.78242
-0.596622
-0.206287
-0.697671
-0.0164221
-0.576665
-0.207565
-0.403753
-0.130948
-0.351535
-0.156256
-0.366982
-0.0374268
-0.560273
-0.349888
--0.170321
-0.0559039
-0.213828
-0.610529
-0.869373
-0.0548665
--0.321184
--0.0374683
-0.110317
--0.0364552
-0.49811
-0.4943
-0.165242
-0.0715701
-0.152011
-0.0173453
-0.0537088
-0.0529427
-0.472381
-0.419552
-0.233495
-0.255524
--0.0688954
-0.112446
-0.101667
-0.25258
--0.0890197
-0.45202
-0.322602
-0.0516559
-0.169667
-0.197826
--0.0672537
--0.213059
-0.0555446
--0.0371548
-0.255905
-0.037486
--0.294096
-0.245449
--0.0325801
-0.504769
-0.486686
-0.255404
--0.0371262
-0.574702
-0.0536616
-0.0185369
-0.256343
-0.464169
-0.212176
-0.393545
--0.0364368
--0.0765515
-0.34844
--0.279817
-0.618971
-0.319607
-0.575932
-0.169127
-0.350744
-0.447623
-0.825771
-0.0378146
-0.224993
-0.770147
-0.883569
-1.07588
-0.804018
-0.684239
-0.991614
-1.31061
-0.84802
-2.06209
-0.681581
-0.716925
-1.56104
-1.09207
-2.76709
-3.07476
-2.3455
-2.74382
-2.42468
-3.26054
-2.40369
-2.38275
-3.99315
-1.81929
-4.06199
-4.02289
-2.80146
-2.11412
-2.96225
-3.18198
-3.43918
-2.70289
-1.84164
-1.37057
-2.46602
-2.10046
-2.1261
-1.40171
-1.36801
-1.79237
-1.53135
-0.373752
-0.558135
-0.183656
-1.08814
-0.338026
--0.304509
-0.166919
-0.918064
-0.47034
-0.109559
-0.334194
-1.17837
-0.124243
--0.193914
-0.642961
-0.425741
-0.112627
--0.0375703
-0.0179325
-0.0185666
-0.310088
--0.0916112
-0.531325
-0.964645
-0.59118
-0.193469
-0.147415
--0.19991
-0.164565
--0.0742622
--0.165582
-0.497405
-0.25753
-0
-0.744359
-0.0530988
--0.216431
--0.0364135
-0
-0.427479
-0.290932
--0.0361652
--0.297889
-0.324272
--0.238005
-0.2912
-0.238103
-0.186936
-0.406402
-0.282667
-0.790227
-0.45385
-0.307993
-0.319221
-0.019766
--0.0372708
--0.260808
--0.0916902
-0.0194823
-0.604238
--0.0344053
-0.40913
-0.571991
-0.0701969
-0.658919
-0.440991
-0.393147
--0.038386
-0.340491
--0.218619
--0.0741428
-0.866517
-0.219593
-1.1859
-0.389891
-0.302526
-0.20295
--0.0368052
-0.196799
-0.285639
-0.421971
-0.518643
-0.781158
-0.224297
-0.0170226
-0.979934
--0.252768
-0.311088
--0.213853
-0.682343
-1.77192
-1.37827
-0.965231
-0.442154
-0.398973
-0.82938
-0.667461
-0.957418
-1.60824
-1.71768
-1.23675
-0.957843
-1.67472
-2.90933
-2.62701
-1.004
-2.06959
-1.75701
-2.15618
-2.89622
-3.80777
-1.15508
-1.94855
-1.7524
-3.01679
-2.92374
-2.2125
-1.7452
-2.87042
-2.42412
-2.25677
-0.418885
-1.33654
-1.70894
-1.51336
-0.972745
-1.79125
-0.756052
-0.922072
-0.852856
-0.902908
-0.248372
-0.8763
-0.235821
-0.992092
-0.390516
-1.01149
-0.164532
--0.223041
-0.0772523
-1.13592
-0.291969
-0.206825
-0.802451
-0.420078
-0.353707
-0.163634
-0.295152
-0.0186752
-0
-0.666053
-0.0176654
-0.199835
-0.0526181
-0.0407638
-0.349499
-0.595021
-0.311714
-0.0526235
-0.399942
-0.341227
-0.146474
-0.339209
-0.740621
-0.601542
-0.0178878
-0.160431
-0.107638
-0.017572
-0.250054
-0.271966
--0.282842
-0
-0.249238
-0.0173551
-0.372446
-0.196613
-0.247272
--0.125754
--0.0883823
--0.398
-0.532686
--0.213777
--0.090818
-0.710809
--0.22026
-0.0182308
--0.0724271
-0.456168
--0.038236
-0.0543559
--0.0359227
-0.262893
-0.390338
-0.500037
-0.900238
--0.137772
-0.448561
-0.163952
--0.204605
-0.0204217
-0.287173
-0.588354
-0.229601
--0.0931922
-0.249254
-0.209347
-0.411548
-0.627763
-0.930967
-0.401829
--0.076063
--0.0193761
-0.989206
-0.0175466
-0.671761
-0.813301
--0.264844
-0.609074
-0.540443
-0.53171
-1.49657
-0.925401
-0.796234
-0.166847
-0.829395
-0.633147
-0.877505
-0.471137
-2.14171
-1.71261
-0.600284
-0.623224
-2.38236
-1.44545
-0.83551
-2.21195
-1.91603
-1.29045
-2.1401
-2.08041
-2.89083
-1.21828
-1.39322
-2.06614
-1.84927
-2.21769
-1.6431
-1.40795
-1.56359
-0.436921
-0.877353
-1.13594
-1.42032
-1.08925
-1.12967
-0.142348
-0.947357
-0.38494
--0.216425
-0.0172618
-1.2037
-0.748288
-0.636227
-0.847098
-0.556185
-0.0688565
-0.0347109
-0.159464
-0.163536
-0.306827
-0.137545
-0.201671
--0.0139835
-0.889058
-0.735252
-0.103045
-0.452233
-0.148428
--0.0347318
-0.0729905
-0.540455
-0.268076
--0.167289
--0.0363741
-0.196583
--0.0689347
-0.193204
-0.483895
-0.324974
-0.0714411
-0.105987
-0.480393
-0.106058
-0.0533697
-0.0172265
--0.0900008
-0
-0.176005
-0.158858
--0.0321642
-0
-0.238676
-0.139577
-0.0164355
-0.232667
-0
-0.529969
--0.0684381
-0.442434
-0.374449
-0.125527
-0.274087
-0.110407
-0.336185
--0.191163
--0.0349587
--0.0377611
--0.248148
-0.169581
--0.0689
-0.417116
-0.527221
--0.0757612
-0.338177
-0.0183069
-0.28394
--0.0746083
-0.162842
-0.140192
-0.248122
--0.1369
-0.662125
--0.134361
--0.03567
-0.606011
--0.316099
-0.196466
--0.108951
-0.129069
-0.17175
-0.259834
-0.400284
-0.189377
-0.534197
-0.213992
-0.50099
-0.183837
-0.709987
-0.575382
-1.10294
-0.748741
-1.52518
-0.834053
-1.65989
-1.33765
-1.26089
-1.29464
-1.89674
-2.03463
-2.11711
-2.09391
-1.65157
-1.44335
-1.16815
-1.29467
-1.70697
-1.02895
-2.13048
-1.70164
-0.542749
-3.06676
-0.803073
-2.14555
-1.53887
-0.633052
-1.5791
-1.74418
-1.11908
-1.65113
-0.907834
-0.265215
-0.776315
-0.362886
-0.875921
-0.761187
-1.75255
-0.0192066
-0.393851
-0.0585904
-0.535377
-0.829356
-0.267256
-0.417103
-0.579126
--0.109766
-0.148835
--0.0763168
-0.260044
-0.350295
--0.169518
--0.12712
-0.297085
-0.743214
-0.253233
--0.250235
-0.620679
--0.0899871
-0.469588
-0.0555073
-0.504138
-0.881714
-0.197663
--0.0967856
-0.108883
-0.202245
-0.655556
-0.536363
--0.0903141
-0.109251
-0.256342
--0.126745
--0.351864
-0.275442
-0.104844
-0.194183
--0.0849909
--0.115686
-0.244817
-0.280669
--0.0923479
--0.0332104
-0.429065
-0.231709
--0.18233
-0.385536
-0.145705
--0.0356669
-0.589395
-0.194211
-0.169692
-0.59814
-0.344436
--0.0354617
-0.619208
--0.0380515
-0.485967
-0.0166027
-0.108807
-0.343909
-0.168689
--0.0930168
--0.180924
-0.170779
--0.258793
-0.306589
-0.0205948
-0.0169999
-0.534296
-0.0561059
--0.0363702
-0.720656
-0.539912
-0.112577
-0.0729154
-0.288365
-0.679034
-0.217369
-0.467832
-0.110551
-0.0187565
--0.0512024
-0.374736
-1.15872
-1.22928
-1.06828
-0.241766
-0.939918
-1.00047
-0.467555
-0.41689
-1.48851
-0.336125
-0.359144
-1.50793
-0.696953
-1.00745
-2.30959
-0.882448
-1.467
-1.90255
-1.68765
-0.189402
-1.31352
-1.91626
-1.42532
-0.77741
-0.682604
-0.788602
-1.753
-1.5196
-0.814983
-1.41833
-1.18892
-0.841058
-0.180779
-1.10695
-0.936087
-1.42551
-0.583905
-0.597147
-0.207558
-0.559906
-0.455043
-0.159834
-0.62019
-0.475034
-0.123815
-1.40227
-0.21961
-0.166053
-0.0762557
-0.401402
-0.0691629
--0.0365983
-0.16668
-0.195984
--0.252906
-0.404828
-0.471228
-0.0531588
-0.519234
--0.307975
-0.198183
--0.0377396
-0.198978
-0.0551779
--0.349386
-0.124519
--0.299584
-0.49235
-0.137292
--0.0368323
--0.0899081
-0.141721
--0.240041
-0.413806
--0.0182749
-0
-0.395691
-0.146151
-0.105702
-0.192155
-0.335995
-0.241715
-0.0165406
--0.13938
-0.193102
-0.0166496
-0.244598
-0.105446
--0.0345101
-0.106095
-0.0171412
-0.195128
--0.1305
--0.0148195
-0.730301
--0.0343507
-0.2024
-0.237452
-0
-0.049351
-0
-0.19352
-0.161775
-0.193244
-0.258066
-0.491058
-0.376723
-0.326089
--0.0706779
--0.0925517
--0.0368619
--0.40114
--0.113898
--0.0162666
-0.0188565
-0.249077
-0.109932
-0.106849
-0.159629
-0.516258
--0.306505
--0.33498
-0.368157
--0.161186
-0.880607
-0.624757
-0.864631
-0.193849
-0.625529
-0.429953
-0.517542
-0.241458
-0.967535
-1.40699
-0.62482
-0.498485
--0.0188668
-0.767836
-0.719242
--0.281144
-0.716387
-0.294392
-1.19469
-1.00675
-2.31494
-1.38529
-0.723187
-1.37367
-2.26545
-2.07534
-0.982177
-1.55272
-1.64652
-0.810013
-0.439931
-1.32839
-1.31394
-1.13714
-0.314976
-1.13712
-0.382674
-0.0713354
-0.365317
-1.53299
-0.500456
-0.647735
-1.00895
-0.111001
-0.343827
-0.371304
-0.457038
-0.314577
-0.424716
-0.307326
-0.110924
-0.165856
-0.133871
-0.218217
-0.64289
-0.46163
-0.286753
-0.461919
-0.413883
--0.358016
-0.26729
-0.240142
-0.168505
-0.351101
--0.0370436
-0.0529486
-0.446342
-0.0694708
-0.486982
--0.0341272
--0.0761166
--0.179561
-0.258514
-0.329531
-0.291208
--0.0368566
-0.334588
-0.0371794
--0.0376204
--0.210044
-0.249109
-0.107364
-0.248591
--0.170926
-0.0855445
-0.230752
--0.113285
-0.199129
-0
-0.254641
--0.0344077
-0.106555
--0.0354434
-0.25696
-0.236058
--0.0372039
-0.173104
--0.175878
-0.697553
-0.253899
-0.0540701
--0.271062
-0.340943
-0.190175
--0.180207
-0.290163
-0.282714
-0.438421
-0.2904
-0.0721679
--0.39669
-0.626852
--0.409298
-0.209099
-0.605489
-0.035048
-0.548023
-0.0347293
--0.17075
-0.0170385
-0.793346
-0.345538
-0.319136
--0.037492
-0.780181
-0.112727
-0.53931
-0.375367
--0.0737131
-0.388033
-0.212898
-0.843492
-0.197302
-0.0178144
-0.447019
-0.228268
-0.188662
-0.422343
-0.313488
-0.147813
-1.26529
-0.88737
-1.02377
-0.570176
-0.587383
-0.667722
-0.775096
-0.976431
-0.55598
-0.72269
-0.7435
-0.429572
-1.00225
-0.926657
-2.41483
-1.03244
-0.517392
-0.146814
--0.0382288
-1.49323
-1.19466
-2.00249
-1.1886
-0.739379
-1.37615
-0.329372
-0.783548
-0.471369
-1.03523
-0.443958
-0.882485
-0.170025
-0.438717
--0.0354357
-0.642402
--0.247616
-0.215215
--0.395616
-0.399636
-0.274691
-0.795425
-0.586553
-0.0367351
--0.127391
-0.163839
-0.55868
-0.105417
-0.285904
-0.553589
-0.332832
--0.130446
-0.50989
-0.180764
-0.199173
-0.401154
-0.182155
-0
-0.329606
-0.107693
-0.107468
-0.399584
-0.187878
-0.194013
--0.0369009
-0.531249
-0.253072
--0.129736
-0.400865
--0.125067
-0.0166013
--0.119776
-0.106409
--0.159854
--0.0364178
-0.314979
-0.167474
-0.630765
-0.193607
--0.120328
-0.274669
--0.0689993
-0.162187
--0.0353764
-0.246932
-0.148179
--0.124502
--0.121972
--0.209058
-0.0545631
-0.0170172
-0.116139
--0.15039
-0.118685
-0.0208278
--0.342305
--0.216311
-0.293826
-0.156302
--0.0371453
-0.0170354
--0.112478
--0.333049
-0.0185292
-0.0938339
-0.342927
-0.633999
-0.750631
-0.444257
-0.0185967
--0.179355
-0.357966
-0.515704
--0.297771
-0.871879
--0.187792
-0.0738733
-0.113738
-0.35855
-0.587673
-0.804401
-0.811784
-0.0180598
-0.323643
-0.3668
-0.436924
-0.667973
-0.800967
-1.14691
-0.28101
-0.175575
-1.02641
-0.990171
-0.469081
-1.38857
-1.29111
-1.2545
-0.810329
-1.86656
-0.976807
-1.01362
-0.811239
-0.788216
-0.578797
-2.41282
-0.837258
-0.0862908
-0.545678
-1.1865
-0.422781
-0.485894
-1.10366
-0.952447
-0.943124
-0.934142
-0.667444
-0.852377
-0.384216
-0.0874413
-0.318493
-0.291687
-0.584875
--0.160407
-0.344857
-0.125307
-0.335185
-0.0199601
-0.805842
--0.0192398
-0.546848
-0.202789
-0.209256
-0.525337
--0.0379529
--0.126857
-0.259664
--0.128245
--0.257767
-0.407794
-0.0184009
-0.286248
-0.753606
-0.0536166
-0.393857
--0.17067
-0.555916
-0.0168684
--0.0370633
--0.173933
--0.0379704
-0.406794
--0.210761
-0.104891
--0.0883773
--0.0677601
-0.378059
-0.930293
-0.423954
-0.291564
--0.0907479
-0.72953
-0.304611
-0.321091
-0.155069
-0.105338
-0.0176238
--0.20798
-0.0166212
-0.0175962
-0.232019
-0.0215495
-0
-0.0514269
-0.438777
--0.448185
-0.0167129
--0.118832
--0.181507
--0.263856
-0.456488
-0.645081
--0.037378
--0.354961
--0.119145
-0.270105
-0.532686
-0.288745
-0.801027
-0.0168035
-0.60714
-0.203502
-0.1954
-0.0183052
-0.716584
-0.193994
-0.385836
-0.254239
-0.0173506
-0.294141
-0.361146
-0.0545849
-0.362287
--0.0157764
--0.0189783
-0.106173
--0.0677319
-0.330436
-0.331696
-0.352892
-0.534595
--0.0185761
--0.144853
-0.274393
-0.0353987
--0.0186529
-0.103727
-0.602113
-0.56016
-0.276585
-0.990706
-0.648725
--0.315269
-0.634959
--0.165032
-0.0353277
-0.982475
-1.86421
-0.515294
-0.975518
-0.590736
-0.125628
-0.954686
-0.0357757
-0.819252
-1.55864
-0.854701
-0.186465
-0.885047
-1.10948
-0.670719
-1.02384
--0.0191536
-0.217484
-0.15764
-0.263548
-0.397438
-0.221364
-0.454639
-0.502307
-1.23396
-1.00203
-0.617795
-0.163262
-0.643697
--0.170824
--0.260424
-0.493782
-0.105774
-0.81497
-0.074258
--0.130749
-0.298621
-0.0208166
-0.163509
-0.318246
-0.069381
-0.243396
-0.405042
-0.488226
-0.0534004
-0.0168416
-0.144653
-0.150835
-0.163135
-0.0172601
-0.216495
-0.467067
--0.088088
-0.103462
-0.0172227
-0.105983
--0.204987
-0.489795
-0.0536259
-0.139427
-0.599598
-0.34391
--0.251222
-0.0722894
--0.0132524
--0.121936
-0
-0.280136
--0.0385038
--0.0340917
--0.0341234
-0.189934
--0.159498
-0.0535638
--0.084728
-0.132382
-0.340775
-0.187767
-0.0546701
-0.100955
-0.138189
--0.118275
--0.0376879
-0.102263
-0.196962
--0.120125
--0.0726267
--0.159172
-0.158535
-0.324982
-0.290117
-0.212224
-0.205632
-0.274948
-0.39956
-0.147086
-0.0173712
-0.15542
-0.510478
-0.328532
-0.465153
-0.750997
--0.216939
-0.40052
-0.318137
-0.755928
-1.09625
-0.332654
-0.407634
-0.45068
-0.915355
--0.127311
-0.383893
-0.964434
-0.168117
-0.216077
-0.277416
-1.14598
-0.159498
-0.6386
-0.108728
-1.14329
--0.07571
-0.531044
-0.641128
-0.297914
-0.959879
-0.124955
-0.703623
-0.644392
-0.0899382
-0.293514
-1.29978
-0.31403
-0.725964
-1.52255
-1.01731
--0.14874
-0.595186
-1.08163
-0.538563
-0.821427
-0.164528
-0.333384
-0.739263
-0.317762
-0.325588
-1.64677
-0.267786
-0.735105
--0.314522
-0.39366
--0.0732626
-0.0686713
-0.254621
--0.254999
--0.259666
-0.198398
-0.310123
-0.666748
--0.131948
-0.10914
-0.49118
-0.746293
-0.659715
-0.450968
-0.446731
--0.199873
-0.248864
--0.0659404
-0.0575381
-0.0517405
-0.193657
-0.0545491
--0.162053
--0.0890028
-0.347272
-0.194497
-0.0179937
--0.216501
--0.399752
--0.0356124
--0.0383345
--0.335833
-0.0724347
-0.0169756
--0.126025
-0.296721
--0.0883202
-0.253257
--0.0158012
-0.563857
-0.0176757
-0.33061
-0.133249
-0.197538
-0.247642
--0.180877
-0.0658777
--0.209262
-0.131252
-0.307706
--0.0353747
--0.0142002
-0.0179267
-0.437374
-0.125058
-0.197011
-0.107035
--0.215431
-0.258709
-0.107061
--0.071967
-0.356967
--0.17211
-0.13031
-0.0170234
-0.501928
-0.0182871
-0.479037
--0.0369923
--0.448387
-0.258766
-0.144653
--0.0364188
-0.0174908
--0.0900174
-0.444927
-0.350903
-0.257159
-0.106084
-0.264941
-0.310022
-0.889574
-0.44759
-0.294244
-0.194484
-0.858983
-0.421183
-0.258568
-0.261243
--0.246743
-0.474111
-0.272091
-1.32953
-0.251346
-0.230751
-0.168617
-0.699067
-0.222865
-0.0744445
-0.653865
-0.326876
-0.0361257
-0.126031
-1.0706
-0.595112
-0.59219
-0.395266
-0.672173
-1.01659
-1.39319
-0.405863
-0.829932
-1.14904
-1.81722
-0.120927
--0.036167
-0.69995
-0.705744
-0.551422
-0.676648
-0.359052
-0.866228
-0.191618
-0.365179
-0.247366
-0.28629
-0.722067
-0.632495
-0.017368
-0.0742885
-0.0174071
-0.895838
-0.349834
-0.497196
-0.106665
-0.653837
-0.391733
--0.127786
-0.222725
-0.121479
-0.311335
-0.26174
--0.246651
-0.0574959
--0.0352867
-0.235292
-0.0188615
-0.0167277
-0.251232
-0.277552
--0.214687
-0.616179
--0.122696
-0.189853
--0.0719423
-0.486139
-0.576616
--0.0154973
-0.108156
-0.0557736
-0.709559
-0.193067
-0.160402
--0.018614
-0.417799
-0.193951
-0.289086
-0.198888
--0.173856
-0.134013
-0.156923
-0.147888
-0.110295
-0.468957
-0.29106
-0.104408
-0.0166945
-0.143637
-0.0175638
-0.146015
-0.311077
--0.206014
-0.0173207
--0.26383
-0.248741
-0.292555
-0.057912
--0.123174
-0.269944
-0.0528314
-0.395075
-0.435051
-0.207004
-0.648443
--0.294176
-0.244037
-0.0776869
-0.299732
--0.0543246
-0.376283
-0.499297
--0.0364322
--0.0948148
--0.165457
-0.412701
-0.124009
--0.172847
-0.0181655
-0.348612
-0.545607
-0.324529
-0.310639
-0.140503
-0.511452
-0.0177709
-0.157982
--0.263714
-0.168655
-0.137548
-0.184444
-0.518953
-0.633184
-0.536947
-0.700031
-0.156831
-0.273733
-0.603647
-0.823983
-0.322473
-0.427168
-0.18879
--0.166424
-0.530718
--0.0578538
--0.150914
-0.167468
-0.910741
-0.657636
-0.947699
-0.54858
-1.33772
-0.961394
-1.22442
-0.70402
-0.383684
-0.449954
--0.120756
-0.333581
-0.462293
-0.678929
-0.75729
-0.683774
-0.391007
-0.903539
-0.145684
-0.388251
-0.262495
-0.545728
-0.690906
--0.305438
-0.999566
-0.195175
-0.729577
--0.074314
-0.324961
--0.254486
-0.018767
-0.0676495
-0.0180729
-0.127258
--0.230158
-0.164105
-0.0338826
-0.0166671
-0.546429
--0.122718
--0.183885
-0.108287
--0.160008
-0.265245
-0.392086
-0.233286
--0.0734927
-0.198331
--0.252283
--0.440145
-0.020387
-0.253964
-0.0195592
-0.51346
--0.0691468
--0.0351544
-0.400945
-0.0189164
-0.0531008
-0.0179421
-0.158867
-0.149098
--0.0352789
--0.0161663
-0.0506395
--0.0745027
-0.567333
-0.548358
-0
-0.289726
-0.320876
-0.318071
--0.0724109
-0.33558
-0.331523
--0.091332
--0.0911281
-0.0541565
-0.284414
-0.136311
-0.159905
-0.281294
-0.433656
-0.115034
-0.0354898
-0.108713
-0.107106
--0.181133
--0.38648
-0.113548
-0.0170607
-0.115229
-0.173498
--0.403048
-0.104356
-0.307724
-0.136054
-0.0566499
-0.0172298
--0.0368607
-0.0172991
--0.205329
-0.0528198
-0.0690788
-0.468877
-0.327801
-0.643514
-0.105597
-0.361022
-0.0365873
--0.254112
-0.464685
--0.0183755
-0.973598
--0.158384
-0.125667
--0.226521
-0.301277
-0.407746
-0.249626
-0.240377
-1.02495
-0.879185
-0.315607
-0.157021
-0.582077
-0.227186
-0.878556
-0.0722381
-0.467558
-0.853775
-1.34049
-1.25179
-0.622276
-0.455307
-0.421258
-0.69281
-0.423357
-0.281981
-0.950056
-0.590258
-1.06779
--0.264398
-0.22398
--0.109986
-0.344011
-0.0367736
-0.447579
-0.159477
-0.0180483
-0.737131
-0.105214
-0.884955
--0.127913
-0.373364
--0.125344
-0.0186333
-0.0166422
-0.658266
-0.193527
-0.110237
-0.203015
-0.0170476
-0.293942
-0.386468
-0.971938
--0.0392189
-0.435976
-0.299432
--0.016234
-0.337798
-0.253476
--0.210026
-0.430828
-0.294254
-0.300128
-0.0170602
-0.145771
-0.0169476
-0.296402
-0.160301
--0.350443
-0.154878
-0.670966
--0.0356324
--0.12401
-0.103011
-0.334366
-0.105075
-0.581592
-0.602685
-0.132278
-0.0534402
-0.100479
-0
-0.269776
-0.105219
-0.103938
-0.619768
--0.117438
-0.253039
--0.327154
-1.10313
--0.033729
-0.139822
-0.135676
--0.0926366
-0.0686864
-0.209348
--0.214125
-0.0176742
-0.200051
--0.0916664
-0.331522
-0.0185378
--0.0342976
--0.0760495
-0.105915
-0.199471
--0.394594
-0.317678
-0.471666
--0.185076
-0.0737141
-0.625493
-0.0178751
--0.166862
-0.717935
-0.809155
-0.0169299
-0.315921
-0.193859
-0.469683
-0.429995
-0.581251
-0.389409
-0.112092
--0.345708
-0.183267
-0.784581
--0.0366594
-0.534338
--0.0164929
--0.249752
-0.433255
-0.175575
-0.360094
-0.106571
-0.863484
-0.109627
-0.75647
-0.552122
-0.424255
-0.596999
-0.4767
--0.0702105
--0.0581715
-0.900761
-0.558539
-0.161841
-0.258532
-0.1599
-0.479428
-0.33185
-0.542343
-0.0935116
--0.158484
-0.596737
-0.939245
-0.823731
-0.230241
-0.537382
-0.45323
--0.0149798
-0.680938
-0.251553
-0.169139
-0.709518
--0.110846
-0.108657
-0.018445
-0.12946
--0.0945314
-0.523934
-0.110827
-0.249674
-0.614543
-0.0173285
-0.404441
-0.161207
-0.198088
-0.151309
-0.241371
-0.104892
-0.399881
--0.241731
-0.191936
-0.34949
-0.160347
-0.39293
-0.339302
-0.416005
--0.0690458
--0.345223
-0.257785
-0.190645
-0.456084
-0.142565
-0
-0.105845
--0.034814
--0.149292
-0
--0.152299
-0.185138
-0.10649
--0.119611
-0.189163
--0.0874219
-0.0558589
--0.0352562
-0.217965
--0.0862721
--0.0369852
-0.0171563
--0.1406
-0.35751
-0.293355
-0.595888
-0.596269
--0.262954
-0.328504
-0.0173595
-0.3036
-0.0513357
-0.0547508
-0.0202243
-0.0787518
-0.196328
--0.318617
-0.192307
-0.747213
--0.0894584
--0.383384
-0.425337
--0.0771479
-0.349449
-0.446017
-0.545687
-0.19487
-0.0542883
-0.309026
-0.124815
--0.0374811
-0.0201449
-0.0532769
-0.255289
-0.694865
-0.0743489
-0.546431
--0.0166579
-0.311409
--0.0379699
-0.112724
-0.22563
--0.297539
-0.420401
-0.31608
-0.617501
--0.131176
-1.08615
-0.478376
-0.0696543
-0.220271
--0.49487
-0.701237
-0.455908
-0.527172
--0.309773
-0.54566
-0.746833
-0.216299
-0.26085
-0.462097
--0.0181904
--0.106574
-0.218067
-1.02738
-0.583205
-0.0372002
--0.198069
-0.405984
-0.438772
--0.245596
--0.0192385
-0.415733
--0.201738
-0.306445
-0.194188
-0.204358
-0.103136
-0.523242
--0.261685
-0.829361
-0.365636
-0.276065
--0.264287
-0.612888
-0.197666
--0.0168388
-0.491264
-0.1656
-0.0562109
-0.0725031
--0.036543
-0.33422
--0.185994
-0.506359
-0.260874
--0.183264
--0.411415
--0.21343
-0.0182598
-0.202066
-0.619872
-0.230509
-0.329211
--0.127684
--0.311427
-0.120636
--0.307354
--0.268454
-0.352282
-0.26578
-0.282604
-0.20439
--0.174668
-0.249091
-0.159547
-0.416815
--0.0888347
-0.279817
-0.185211
-0.194026
--0.0689132
-0.342388
-0.102044
-0
--0.0341405
--0.0349809
-0.192951
-0.241485
-0.269499
-0.187393
--0.0864263
-0.245033
-0.201269
--0.0349962
-0.05382
--0.10152
-0.143339
-0.10752
-0.0414288
--0.0904103
-0.359202
-0.484858
-0.0527837
--0.359145
--0.035473
-0.643385
--0.0389931
-0.253204
-0.213472
-0.332417
-0.106577
--0.128671
--0.128461
-0.338408
--0.660014
-0.217767
-0.401903
-0.192891
-0.204849
-0.247849
-0.537542
-0.596798
-0.0584758
-0.0557035
--0.315482
--0.0167541
--0.0874557
--0.0727781
-0.170055
-0.395669
-0.0374617
-0.512524
-0.0376392
-0.249622
-0.518571
-0.463963
--0.0195096
-0.0561797
--0.170602
-1.07885
--0.0376813
-0.508273
-0.501233
-0.943346
-0.513403
--0.0387118
-0.11086
-0.483686
-0.134051
-0.411863
-0.602432
-0.174085
-0.0186766
-0.44618
-0.220631
-0.0179811
-1.06767
-0.555071
-0.173305
-0.549914
-0.633554
-0.793961
-0.952742
-0.412268
-0.306383
-0.339607
-0.38044
-0.340919
-0.650006
-0.353113
--0.263421
-0.497562
-0.538759
--0.0377694
--0.288338
-0.146559
--0.0998809
-0.109269
--0.371725
-0.305716
-0.683657
--0.267734
-0.219955
-0.311543
-0.64435
-0.597694
-0.106873
--0.0760838
-0.117507
--0.072213
--0.216145
-0.16674
-0.266323
--0.0160834
--0.134608
-0.205518
-0.0705333
-0.250161
--0.0371737
-0.0753421
-0.0202112
--0.0367477
--0.309299
-0.248274
--0.092789
-0.411664
-0.161955
--0.133649
-0.171093
--0.0989985
-0.268465
-0.249578
-0.0520327
-0.0186101
--0.132999
-0.0191399
-0.129427
-0.353537
--0.034194
-0.256149
--0.0165641
-0.204969
-0.194123
-0.245385
--0.0895923
--0.180882
-0.16268
--0.0365012
-0.0540298
-0.284995
-0.159401
-0.494351
-0.0721022
-0.0540265
-0.145293
-0.138916
-0.243312
-0.213092
--0.036923
-0.239645
-0.0537967
-0.299011
-0.62545
-0.503278
-0.0174428
-0.444027
--0.221025
-0.47128
--0.451234
-0.107496
--0.0712465
--0.456727
-0.036349
-0.479343
-0.318698
--0.0372605
-0.0184969
-0.157687
-0.154592
-0.183804
-0.623694
-0.575987
--0.15935
--0.0166472
-0.296874
-0.375667
-0.420864
-0.0545346
-0.252932
-0.0186557
-0.860969
-0.610982
-0.4573
-0.29839
-0.724711
-0.220972
-0.393302
-0.630495
-0.017256
--0.261118
-0.269632
--0.174549
-0.59914
-0.645373
-0.316039
-0.893066
--0.0351894
-0.209425
--0.0739741
-0.346671
-0.126992
-0.99132
-0.389946
-0.0383671
-0.299541
-0.220192
-0.25641
-0.493634
-0.212043
-0.0173796
--0.13135
-0.695636
-0.57765
-0.0873037
-0.163355
-0.161052
-0.531303
-0.210866
--0.0757022
-0.257931
--0.0725878
--0.186662
-0.0170907
-0.333092
-0.0172145
-0.102368
-0.0493546
-0.639225
--0.0706266
-0.164712
-0.105455
-0.276634
-0.445351
-0.399685
-0.0718307
-0.106301
-0.0171526
--0.0356622
-0.476957
-0.429521
--0.0694264
-0.0677609
-0
-0.305373
-0.137074
-0.139968
-0.274166
-0.108715
--0.035792
--0.123822
--0.267531
-0.0735391
--0.121708
-0.190598
--0.165959
-0.0530413
-0.331969
--0.319113
-0.144592
--0.015334
-0.201153
-0.290492
--0.102116
--0.154406
-0.258595
--0.0345217
--0.075199
-0.145003
-0.24407
--0.185171
-0.0700721
-0.330027
--0.130115
--0.128032
-0.148757
--0.0350141
-0.447551
--0.0926657
--0.129673
-0.20907
-0.0177273
-0.0699135
-0.248513
-0.19959
--0.0369648
--0.130604
-0.109688
-0.31759
-0.26657
-0.416905
-0.382632
-0.30758
--0.0370123
-0.106368
-0.172284
-0.072975
-0.617498
-0.194614
-0.0175169
-0.205227
-0.810329
-0.416346
-0.29854
--0.110289
-0.167647
-0.156503
-1.06901
-0.184557
--0.133487
-0.320531
-0.629524
-0.762665
-0.830478
-0.0721309
-0.203597
--0.12988
--0.157127
-1.02737
-0.573557
-0.219077
-0.413598
-0.0712381
-0.360065
-0.38173
--0.252977
-0.11095
-0.412101
-0.247615
-0.260973
-0.647307
-0.411199
--0.251543
-0.21745
--0.355203
-0.948623
-0.258637
-0.162071
-0.521309
--0.128869
-0.251666
-0.174618
-0.377535
-0.165489
--0.0721835
-0.174865
-0.246847
--0.0138493
--0.0372844
--0.394141
-0.107814
-0.24982
--0.278596
--0.362902
-0.161825
-0.345838
-0.390101
--0.179785
-0.50552
--0.0722954
-0.192985
-0.521468
-0.01835
--0.371047
-0.106795
--0.127393
-0.107377
-0.0171248
-0.194715
-0.202843
-0.0513725
-0.0171146
-0.0172929
-0.531877
-0.251213
-0.0392385
-0.110737
-0.0517569
-0.148803
-0.0520116
--0.0365531
--0.207901
--0.223747
--0.12131
-0.110444
-0.0194337
--0.0392722
-0.351574
--0.0709441
-0.39823
--0.434532
--0.130789
-0.471622
-0.200993
--0.109371
-0.12602
-0.286861
-0.333553
-0.439713
-0.160668
-0.249419
-0.294564
-0.261049
--0.106184
-0.165845
--0.0909675
--0.186541
-0.144166
-0.3855
--0.0936618
-0.257485
-0.623304
-0.20122
-0.856327
-0.68704
--0.0378285
-0.769374
-0.288802
--0.0751954
-0.274685
-0.230687
--0.180437
-0.538211
-0.19236
-0.0562022
-0.471299
-0.906635
-0.108157
-0.130732
-0.217619
-0.49488
--0.163629
--0.130457
-0.0180497
-0.0169386
-0.365956
-0.317021
-0.162615
-0.108464
-0.765086
--0.363403
-0.125488
-0.150422
-0.396589
-0.107082
-0.168392
--0.0395115
-0.652915
-0.259345
-0.184707
-0.247716
--0.0355815
-1.28779
-0.16163
-0.530001
--0.378869
-0.110367
-0.757493
-0
-0.25533
-0.270022
-0.26398
-0.309881
-0.291841
--0.110779
-0.252546
--0.181624
-0.171751
-0.852816
-0.540249
--0.13423
-0.198257
--0.189401
--0.368224
-0.716672
-0.209864
-0.112478
-0.255036
-0.0185825
-0.240272
--0.425872
--0.129405
--0.220998
-0.163543
--0.0362806
-0.113131
-0.114047
-0.312576
-0.403296
--0.262694
--0.0722307
-0.20229
-0.438922
-0.190508
-0.331832
-0.10236
--0.160417
--0.0370241
-0.0540014
-0.191364
-0.0178809
-0.402886
-0.108213
-0.202653
--0.0514926
--0.123334
--0.25781
-0.42658
-0.729144
-0.245876
-0.0171051
--0.0337291
-0.312622
-0.0524668
--0.303754
-0.302525
--0.250768
-0.232733
-0.62433
--0.276961
--0.157315
--0.318119
-0.189572
--0.0384825
-0.0720465
-0.0532983
-0.0554099
--0.0165509
--0.0375367
--0.0390906
-0.252767
-0.0591742
-0.21183
-0.293568
-0.464383
-0.0176627
-0.481879
--0.341098
-0.202306
--0.0396846
-0.15231
-0.319517
--0.0375244
--0.0771853
-0.051835
-0.116144
-0.110617
-0.202929
-0.588749
-0.264785
-0.338867
--0.33769
--0.319348
-0.0567038
-0.018224
-0.210596
-0.108084
-0.244
-0.219939
-0.308472
-0.0180876
-0.15151
-0.245508
-0.621968
-0.309572
--0.0190596
-0.0759786
--0.36923
-0.513774
-0.73616
-0.110665
-0.663856
-0.0408471
-0.602715
-0.257125
-0.297815
-0.60309
-0.42098
--0.0380077
-0.148031
-0.018198
--0.304586
-0.110374
-0.225331
-0.108207
-0.252088
-0.0549509
--0.0164247
--0.11006
-0.50387
-0.112045
-0.0596339
--0.251495
-0.47167
-0.528752
-0.21744
-0.302193
-0.0569321
-0.0749437
-0.219593
-0.171435
-0.403583
-0.361472
-0.267779
--0.14112
-0.247233
--0.161498
-0.481003
-0.23379
--0.132129
-0.192569
-0.164969
--0.128946
--0.0170753
-0.247037
--0.128214
--0.0360706
--0.0699252
-0.368546
-0.470669
-0.248831
-0.716773
-0.536694
-0.0528532
-0.147575
--0.0889781
-0.206315
--0.125185
-0.0539546
-0.138032
-0.295569
-0
-0.0543683
-0.186463
--0.0943453
--0.273918
-0.112971
-0.270532
-0.150839
--0.170265
-0.30118
--0.122015
-0.360169
-0.245945
-0.160166
-0.752979
-0.0568409
-0.0536603
-0.110518
-0.0514029
-0.207312
-0.0524343
--0.0384649
--0.0867526
--0.174769
-0.0525351
-0.203962
-0.348383
-0.0177522
--0.222836
-0.263858
--0.0162992
-0.018781
-0.106928
--0.0161908
-0.200769
--0.128022
-0.0176173
-0.417481
--0.129002
-0
-0.197631
-0.412085
-0.109537
-0.470378
--0.159817
-0.152289
--0.174512
-0.112882
-0.212226
-0.22573
--0.0385641
--0.0204422
--0.277481
--0.095432
--0.0356465
-0.110187
-0.0557433
-0.284086
--0.0781803
-0.938278
-0.351168
-0.206052
-0.2213
-0.813178
-0.310892
-0.670753
-0.466889
--0.137611
-0.401271
-0.463653
-0.0719825
-0.171886
-0.166563
--0.257893
-0.202597
-0.443705
-0.127274
-0.440292
--0.128939
-0.0182522
-0.84616
-0.513024
-0.213417
--0.128788
--0.262932
-0.416967
-0.288261
-0.163396
-1.0485
-0.270832
-0.257988
-0.0183887
-0.110681
-0.501199
-0.199735
-0.170055
-0.277003
-0.387747
-0.0738501
-0.110427
--0.0356442
--0.133308
-0.0176163
-0.499448
-0.105671
-0.361457
--0.175673
-0.243707
--0.0355877
-0.262494
-0.162398
-0.150583
-0.459024
--0.119061
-0.106792
--0.253662
-0.017602
-0.107233
--0.266671
--0.275697
-0.294715
-0.145474
-0.251344
-0.140382
--0.435182
-0.152764
-0.303644
--0.220718
--0.0909463
-0.116147
-0.0514383
--0.0892479
--0.17895
-0.33003
--0.06628
-0.0515823
-0.5348
-0.15438
-0.162943
-0.236207
-0.10648
-0.237286
--0.176706
--0.122423
-0.188642
--0.166825
-0.2494
-0.213451
-0.0207505
-0.238757
-0.0519594
-0.187437
--0.157968
-0.470958
-0.14664
-0.101165
-0.550768
-0.0527434
--0.0358611
-0.193435
-0.341855
-0.204252
--0.218054
-0.342574
-0.112072
-0.15425
--0.128246
-0.0524033
-0.0174515
--0.271769
-0.111225
-0.21724
-0.0182476
-0.279848
--0.0898203
--0.0753807
--0.131723
--0.0724823
--0.30736
-0.681847
--0.0711156
--0.174635
-0.236663
-0.441468
-0.385683
-0.169919
-0.11225
-0.439413
-0.336833
--0.0196291
-0.196512
-0.291121
-0.151199
-0.11091
--0.133161
-0.0708464
-0.0352269
-0.788134
-0.0353561
--0.347798
-0.564057
-0.904887
-0.34425
--0.125103
--0.356874
-0.346036
-0.309615
-0.627528
-0.111784
-0.19737
-0.547878
-0.125124
-0.484283
-0.410149
--0.10723
-0.253486
-0.36592
-0.583747
-0.640233
-0.158844
-0.256145
-0.204967
-0.0188866
--0.421517
-0.739855
--0.0917398
--0.0916492
-0.105405
-0.444335
-0.323712
-0.371941
-0.198757
-0.356454
--0.0692559
-0.315932
-0
-0.0173775
-0.289385
--0.0352592
-0.719333
-0.0520836
-0.135954
-0.332441
-0.0176698
-0.281492
--0.159821
-0.206244
-0.0555393
--0.03699
-0.352729
--0.0701325
-0.0166106
-0.0522365
-0.286252
-0.050982
--0.215139
-0.104424
-0.251375
-0.285501
-0.207298
-0.773116
-0
--0.0865895
-0.255388
-0.049945
-0.217769
-0.185229
-0.261367
--0.0361286
-0.0715631
--0.0359644
--0.13818
-0.194343
-0.368376
--0.0384415
-0.0553595
-0.732407
-0.447569
-0.0516946
-0.0536023
--0.284071
--0.0370799
-0.109991
-0.152207
-0.200803
-0
--0.131751
--0.132391
-0.0734378
-0.641476
-0.0194489
-0.256597
--0.0362367
-0.259618
-0.05519
-0.505884
--0.0372575
--0.0375453
-0.353116
-0.425371
-0.190701
-0.364577
-0.0190784
-0.316297
-0.168452
-0.360801
-0.483709
-0.417884
-0.0729004
-0.0710879
--0.0722022
-0.511006
-0.428998
-0.712266
-0.109512
-0.613606
-0.258294
-0.133324
-0.212128
-0.578963
-0.267404
-0.601609
-0.429552
--0.164874
-0.493553
--0.274153
-0.192157
-0.213049
-0.649317
-0.129761
-0.503713
--0.0388825
-0.109508
-1.00941
-0.323896
-0.0184436
-0.11348
-0.121571
--0.0168531
-0.109274
-0.45463
-0.412467
--0.109719
--0.0756891
-0.788641
-0.398541
--0.0371632
-0.465202
--0.0711959
-0.0181183
--0.12972
-0.269789
-0.205754
-0.357942
-0.577914
-0.0531013
--0.131765
-0.619807
--0.163535
--0.280969
--0.262607
-0.106134
--0.03708
-0.193471
-0.285401
-0.111363
-0.0169936
-0.327486
-0.307627
-0.667988
-0.285465
--0.12946
-0.285329
--0.0924342
--0.181816
-0.0175817
-0.505654
-0.0726785
-0.423361
-0.200418
--0.0339957
-0.116222
-0.136697
--0.124218
-0.106447
--0.0969441
--0.0923108
--0.0908538
-0.286245
-0
-0.241687
--0.178316
-0.133471
--0.0907124
--0.154357
-0.191283
-0.247073
--0.0872909
-0.161146
--0.124348
-0.29723
-0.194577
-0.16077
-0.0936268
--0.186311
-0.10743
-0.424684
-0.201695
-0.0542965
-0.284112
--0.12491
-0.0525482
--0.275045
--0.0363315
--0.211587
-0.450093
-0.0541074
--0.088609
-0.204895
-0.357542
-0.443947
--0.125141
--0.0888563
-0.644928
-0.109049
-0.577833
--0.266103
--0.311478
-0.110514
--0.0714802
-0.30071
-0.190827
-0
-0.527889
-0.187477
-0.205713
-0.639058
-0.202505
-0.163866
-0.294791
-0.268044
--0.109225
--0.106607
-0.107881
-0.0180926
-0.0175145
-0.261667
--0.162807
-0.158239
-0.359375
-0.0183739
-0.0733269
-0.212896
-0.0537455
-0.353697
-0.222426
-0.557092
--0.165656
-0.164009
--0.307524
-0.318192
-0.349237
--0.281567
-0.209546
-0.499724
-0.0740095
--0.402564
-0.295718
-0.0176134
-0.105114
-0.106341
-0.484724
--0.131651
-0.163975
--0.266303
-0.163747
-0.249329
-0.344695
-0.410221
-0.255407
-0.723091
-0.246948
--0.130132
-0.108878
-0.403154
-0.49162
--0.0164521
-0.32611
--0.123673
-0.249665
-0.112535
-0.05439
-0.248317
-0.203326
--0.124612
-0.148606
-0.3309
-0.517117
-0.0536239
-0.208794
--0.10836
-0.0176305
-0.340089
-0.40152
--0.170922
-0
--0.15655
-0.33027
-0.254904
--0.128401
-0.137051
--0.176855
-0.402392
-0
-0.136084
-0.145975
--0.0876247
--0.0737881
--0.0847856
-0.349415
--0.0347888
-0.156592
-0.31427
-0
-0.435648
-0.200567
-0.0540913
-0.141093
--0.0132916
-0.355779
-0.278613
-0.147646
-0.286336
-0
-0.145354
-0.153258
-0.0524003
--0.186506
--0.036693
-0.257697
-0.27148
--0.189211
-0.0179824
-0.362816
-0.0544982
-0
-0.0541835
--0.0960213
-0.333761
--0.2828
-0.34325
--0.0719697
-0.345903
-0.155511
-0.201938
--0.0376693
--0.090212
-0.203179
-0.486342
--0.221172
-0.610093
-0.0558686
--0.161509
--0.127442
--0.220052
-0.0177054
-0
-0.547538
-0.0537872
-0.417931
-0.0547461
-0.511048
-0.335782
--0.0739819
-0.0175737
--0.18886
--0.182369
-0.169658
-0.108616
-0.265772
--0.31451
--0.367007
-0.351355
-0.0200981
-0.769805
-0.505476
-0.459032
-0.1111
--0.0762388
--0.282957
-0.110863
-0.290724
-0.454707
-0.296986
-0.525868
-0.202553
-0.15729
--0.0383597
-0.59401
-0.0193889
-0.0172717
-0.364118
-0.31419
--0.0377877
-0.16747
-0.316262
-0.131423
-0.353467
-0.11374
-0.149696
--0.0365111
-0.26217
-0.259328
-0.398723
-0.717798
-0.296038
-0.887839
-0.106482
--0.0723612
-0.44774
-0.0193732
-0.683953
-0.420205
-0.120544
-0.052429
-0.242806
-0.689786
--0.0199078
--0.0355649
-0.160239
-0.25212
-0.21653
--0.211674
--0.036181
--0.127865
-0.107157
-0.287912
--0.162738
-0.66368
--0.0931065
--0.357622
-0.122256
-0.0176132
-0.145991
-0.293928
--0.0181299
-0.0376836
--0.0695472
-0.189185
-0.253285
-0.26969
-0.190888
-0.203387
-0.138687
--0.180282
-0.346716
-0.333679
--0.0894176
-0.195958
-0.0531213
-0.18824
-0.190968
-0.378624
-0.13953
-0.0530293
--0.036943
-0.380626
-0.286244
--0.036289
--0.0748731
-0.109274
-0.129121
--0.076537
-0.110999
-0.298912
--0.0370874
--0.204179
--0.283413
--0.161986
-0.107386
--0.18151
-0.0524652
-0.945515
-0.476306
--0.352229
--0.0930468
-0.256286
-0.481406
-0.608432
-0.298915
-0.447273
-0.0180696
-0.017383
--0.0190413
-0.341679
-0.361017
-0.0682917
-0.321217
-0.627285
--0.0724969
--0.0724043
-0.351536
-0.14921
-0.559102
-0.31361
--0.133613
-0.364286
-0.363162
-0.286707
-0.125059
-0.500285
-0.4624
-0.16948
-0.355835
-0.505764
-0.111283
-0.550298
-0.017692
-0.201059
--0.189375
-0.118449
-0.202108
-0.172489
-0.262533
-0.393343
-0.167562
-0.292495
--0.0365962
--0.224959
--0.0926904
-0.462457
-0.0179896
--0.0779433
--0.0366095
-0.634992
--0.0915443
-0.402361
-0.0188045
--0.224325
-0.35774
-0.20578
-0.0199205
-0.162176
--0.184946
--0.124332
--0.297422
-0.0180838
-0.373364
-0.350856
--0.093368
-0.198431
-0.340245
--0.356387
-0.526826
-0.241948
--0.176875
-0.193454
-0.0513107
-0.210685
-0.0530144
--0.447842
--0.0358525
--0.0372254
-0.098505
-0.391083
-0.488468
-0.106348
-0.243908
-0.442089
-0.157009
--0.128196
-0.511684
--0.0356516
--0.0930231
-0.180862
-0.149198
-0.0188658
--0.0403692
-0.293662
-0.0584164
-0.102804
-0.0581474
-0.279113
--0.167099
--0.035431
-0.499367
--0.0850504
--0.038065
-0.584756
--0.0368723
-0.0495247
-0.347751
-0.155359
-0.056718
--0.0362935
-0.208257
--0.0690606
-0.259814
-0.146793
-0.679231
-0.0530131
-0.203742
-0.165337
--0.130402
-0.0733714
--0.19085
--0.219323
-0
-0.449664
-0.0742661
-0.855436
--0.0899017
--0.186136
-0.502432
-0
-0.072865
-0.368881
-0.721818
--0.352283
--0.134969
--0.0369505
-0.454921
-0.197705
-0.72377
-0.303521
-0.504945
--0.0371415
-0.341497
-0.612524
-0.134402
-0.637712
--0.129618
--0.324777
--0.26177
-0.0742165
-0.214484
-0.0693372
-0.0177945
-0.146599
-0.164061
-0.0175923
--0.0933812
-0.165212
--0.0965206
-0.114748
-0.755668
-0.0529696
-0.056523
-0.599546
--0.282247
--0.395987
--0.0393337
-0.755168
-0.413185
--0.120997
--0.0361449
--0.18221
--0.365663
--0.215183
-0.171676
--0.125427
-0.167386
-0.108897
-0.155035
--0.27945
-0.0182256
--0.0689771
-0.114757
--0.18502
-0.134794
--0.0341056
-0.655583
-0.1036
--0.123277
--0.185414
--0.218475
--0.0184654
-0.205978
-0.104649
--0.0369523
-0.0175807
-0.104855
-0.0521788
--0.0367342
--0.032501
-0.355983
-0.397913
--0.177761
--0.217899
-0.279228
-0.331374
-0.145732
--0.0688133
-0
-0.0526505
-0.0573768
--0.183779
-0.0226758
-0.147075
-0.149809
-0.16138
-0.330373
-0.16004
-0.426809
--0.175785
-0.57142
--0.0361278
--0.256991
--0.0911238
-0.0387783
-0.211445
-0.0161125
-0.0533492
-0.389172
-0.15087
-0.142775
-0.0542692
--0.124847
-0.676557
--0.18445
-0.311034
-0.291098
-0.412097
-0.754019
-0.67063
--0.184016
-0.206351
-0.350556
--0.0378191
-0.29215
-0.663151
-0.299386
--0.0375052
--0.0378355
-0.111622
-0.349734
-0.249966
-0.0556974
--0.27317
-0.108916
-0.262862
-0.34355
--0.128653
-0.201083
-0.0579166
-0.464153
-0.0199892
-0.316207
-0.250314
-0.108813
-0.403217
-0.107201
-0.0542738
-0.235919
-0.4684
-0.560139
--0.171325
-0.509692
--0.178004
-0.687365
-0.257733
--0.447764
-0.53528
-0.0382749
--0.17377
-0.646618
-0.0737538
--0.0770176
-0.116512
--0.396562
-0.206508
-0.361003
-0.110935
-0.318308
-0.171615
-0.05669
-0.211537
-0.110988
-0.89563
-0.399776
-0.0542392
-0.0756139
--0.0365157
--0.036798
--0.0760445
-0.440928
-0.160494
-0.0548106
-0.195896
--0.180439
-0.359234
-0.2578
-0.932979
-0.0566059
-0.506982
-0.491008
-0.432778
--0.0922874
-0.359246
-0.438779
--0.0738174
-0.411079
-0
-0.24067
-0.0170614
-0.381941
-0.111409
--0.0368677
-0.565889
-0.102456
-0.370717
--0.129535
-0
-0.107503
--0.0356135
-0.217192
--0.0361777
--0.0357898
--0.124715
-0.470127
--0.0349657
-0.0561067
-0.0520779
-0.0537695
-0.050286
-0.277723
-0
-0.261679
-0.380912
-0.355124
--0.0339418
--0.0747265
-0.0502215
-0.165512
-0.0496257
-0.0185627
--0.212222
-0.150601
--0.0351195
-0.0214502
-0
-0.759255
-0.592623
--0.202013
-0.0527027
--0.0952296
-0.0502236
-0.45949
--0.0348901
-0.114522
-0.419292
-0.055679
--0.128873
--0.135095
--0.0370799
-0.118884
-0.323552
-0.113716
-0.481266
-0.219277
-0.414482
-0
-0.542487
--0.0385741
-0.0208405
-0.258986
-0.518424
--0.0383547
--0.089454
-0.300487
--0.311454
-0.113035
-0.466736
-0.354897
--0.167241
-0.175675
-0.108388
-0.0389206
-0.137246
--0.0371168
-0.217864
-0.151108
-0.0551644
-0.0565646
--0.0377671
--0.16685
-0.269346
-0.111249
--0.16221
--0.0945213
-0.403943
-0.210836
-0.187619
-0.0187903
-0.168035
-0.172852
-0.304229
--0.0756026
-0.220943
-0.266049
-0.0181193
-0.56072
--0.184841
-0.303655
-0.077264
-0.108601
-0.0379711
--0.343498
-0.290467
-0.242774
-0.25417
-0.270371
--0.162801
-0.117032
-0.131426
-0
-0.111118
--0.227154
-0.356746
-0.463643
--0.132466
-0.511231
--0.033119
--0.0408066
-0.0725786
--0.0980755
--0.0692355
-0.208593
-0.0170355
--0.0369658
--0.266645
-0.209606
-0.109026
-0.372408
--0.0360403
-0.0183361
--0.0932984
--0.413262
--0.0713901
--0.190695
-0.338131
--0.131067
--0.0683146
--0.0402306
-0.0204388
-0.608625
-0.195349
-0.0740843
-0.14021
-0.462882
--0.213208
--0.390057
-0.436867
-0.0662166
-0
-0.0561224
-0.199531
-0.0169612
--0.258069
-0.0169869
-0.183572
-0.339781
--0.227177
-0.241452
-0.108771
-0.184929
-0.0541353
-0.0994316
-0.396557
-0.0522601
--0.0381009
-0.0523217
--0.13117
--0.0342455
--0.0926973
--0.0731622
-0.437201
--0.0367315
-0.0567719
-0.196049
--0.192453
--0.0901098
--0.036503
-0.0709011
-0.335378
--0.0736452
-0.136185
--0.0164555
--0.186534
-0.295625
-0.257956
-0.215363
-0.115902
-0.0549238
-0.0177104
-0.171338
--0.190392
-0.0539441
-0
-0.0202264
--0.0364048
-0.204301
-0.256287
--0.13045
--0.223731
-0.128606
-0.0559229
-0.151002
-0.398854
--0.0778683
-0.501633
-0.21174
-0.0526159
-0.354483
-0.203684
--0.0388254
-0.0177209
--0.196598
-0.29551
--0.0923025
-0.110926
-0.111188
-0.0203736
-0.67196
-0.571127
-0.225627
-0
-0.269861
-0.963778
--0.61155
-0.410602
-0.299794
--0.0169052
-0.35425
--0.224309
-0.052602
-0.104958
--0.16257
-0.303423
-0.0199979
-0.0576844
-0.289805
-0.0761856
-0.107192
--0.190404
--0.188113
--0.144684
--0.0947161
-0.0591591
-0.257616
-0.0208272
-0
-0.50621
-0.163799
-0.294171
-0.209918
-0.105774
-0.0515067
--0.0959072
--0.123648
-0.0196846
--0.129449
-0.017202
-0.268998
-0.110947
-0.294559
--0.173768
--0.190262
--0.257104
--0.0911843
--0.0358505
-0.190231
--0.0348103
-0
-0.194036
-0.389789
-0.0569833
-0.108416
-0.386005
--0.132108
-0.0530874
-0
-0.210767
--0.103305
--0.133216
-0.0601053
-0.244641
-0.162545
--0.20644
-0.160063
-0.300419
-0.334265
-0.191733
--0.132052
--0.126863
-0
-0.240153
--0.226658
--0.152483
--0.39174
--0.0364742
-0.270819
--0.185642
-0.0615472
-0.253316
-0.425071
-0.206237
-0.0767895
-0.343009
--0.141586
-0.361551
-0.15719
--0.189915
--0.199207
-0.124312
-0.514747
-0.250308
-0.118876
-0.0544033
-0.317119
-0
-0.37987
--0.314539
--0.228059
-0.11161
-0.0600763
-0.106623
-0.211365
-0.152292
-0.275771
--0.0366303
-0.492514
--0.0884187
--0.0737258
-0.306112
-0.549794
-0.146401
-0.223415
--0.135356
-0.528482
--0.130097
-0.151066
-0.432248
-0.139179
--0.129061
-0.120233
-0.812402
-0.173989
-0.143962
-0.314489
-0.497022
--0.193626
-0.755848
-0.282306
-0.519687
-0.0185059
--0.467987
-0.114998
-0.343602
-0.217999
-0.466204
-0.273988
-0.634338
-0.343065
-0.373034
-0.019237
-0.196913
--0.0393586
-0.202607
--0.413279
--0.0945103
-0.0189104
-0.595941
-0.309124
-0.40733
--0.187367
-0.730143
-0.216242
--0.0367607
-0.0597263
-0.146638
-0.60588
-0.144495
-0.116616
--0.1856
-0.330997
--0.097214
-0.448868
-0.291706
-0.161755
-0.0549439
-0
--0.131958
-0.071723
-0.302864
-0.0562229
-0.0739202
--0.334563
--0.128076
--0.132336
--0.175064
--0.168016
-0.201841
-0.0569132
--0.0374904
-0.302977
-0.28539
-0.207461
-0.205766
--0.220132
-0
-0.0537539
--0.0835718
-0.0529158
--0.0816254
--0.071545
--0.164361
-0.417835
-0.192506
-0.184694
-0.104512
--0.0354584
-0.334761
-0.197654
-0
-0.48008
-0.19826
-0
-0
--0.307451
-0.63005
--0.036607
-0.016509
--0.122809
-0.249968
-0.145159
-0.104359
-0.1407
-0.450178
--0.38254
-0.276404
-0.245795
-0.0728955
-0.286089
-0.263391
--0.26681
-0.251682
--0.215495
-0.0709746
--0.166919
-0.649248
-0.201061
-0.210806
-0.196026
--0.105789
-0.368144
--0.484509
-0.286635
--0.0383632
--0.271115
--0.16638
-0.251179
-0.138737
-0.361593
-0.145097
-0.225563
-0.141391
--0.0370157
--0.127482
-0.0177962
-0.430743
--0.075116
--0.542908
-0.501885
--0.0715234
--0.127682
--0.164449
-0.147921
-0.018186
--0.47067
-0.0973121
--0.0938896
-0.24643
-0.29047
-0.302824
--0.0369223
-0.589399
-0.266497
--0.0380168
-0.127101
-0.30361
--0.0749306
--0.21858
-0.16213
-0.443223
--0.279291
-0.0597701
-0.0741015
--0.22083
-0.107433
--0.135987
-0.194867
--0.0381969
-0.165248
--0.0383361
-0.60231
-0.380501
-0.194731
--0.0742704
-0
-0.104039
--0.226987
-0.242021
--0.167349
-0.0180279
-0.141984
-0.142525
-0.0532703
-0.0168746
-0.113655
--0.0367251
-0.0693936
--0.209639
-0.204506
-0.259085
-0.628923
-0.193818
-0.290417
-0.303517
-0.200241
-0.0536009
--0.034805
--0.124035
--0.0364183
-0.0503132
--0.12326
-0.0538471
-0.161983
--0.0140384
-0.152548
-0.136175
--0.0946344
-0.434411
-0.0560995
-0.190572
--0.20003
-0.193265
-0.149775
-0.0167418
-0.116843
-0.272177
-0.151136
-0.250885
-0.111008
--0.03543
-0.133211
-0.347195
--0.0388014
-0.470184
-0
-0
-0.114761
-0.70571
-0.570355
--0.0722924
-0.447084
-0.0567471
-0.1186
-0.439957
--0.188531
-0.644955
-0.305174
-0.395037
--0.133199
-0.484832
--0.0966014
-0.348462
-0.214156
--0.0933738
-0.510057
--0.12853
-0.055967
-0.0187277
-0.265371
--0.0388733
--0.0168509
-0
-0.0211298
-0.779383
-0.208539
-0.650855
-0.783534
--0.22172
-0.298476
-0.30707
-0.215542
-0.442078
-0.115496
-0.409499
-0.5063
-0.258026
-0.375243
-0.2269
-0.901623
--0.213026
-0.207461
--0.413406
-0.152914
-0.314454
-0.262594
-0.0550841
-0.0566809
-0.172727
--0.28188
-0.409744
-0.269221
--0.184146
--0.136481
-0.0176722
--0.236282
-0.29385
-0.115895
-0.109265
-0
-0.377448
--0.223318
--0.0378183
-0.321079
-0.502694
--0.291497
-0.284084
-0.223024
-0.0184984
-0.265178
--0.037252
-0.444814
-0.657939
-0.356245
--0.131388
-0.0554835
-0.352442
-0.14118
--0.168277
--0.189926
-0.018349
-0.269611
--0.269846
-0.180418
-0.0522948
--0.130493
-0.19401
-0.172198
-0.140696
-0.307594
--0.0709709
--0.194331
--0.0924026
-0.111706
-0.146261
-0.304794
--0.0361347
-0.360222
-0.433018
-0.0189821
--0.275741
--0.107643
-0.208582
-0.158987
-0.139815
-0.0562741
-0.334685
-0.197243
--0.17169
--0.185393
-0.102319
-0.291648
--0.0928985
-0.106987
-0.357687
-0.167504
--0.22672
-0.346146
--0.0380714
-0.200877
--0.0385426
-0.199557
--0.0355369
-0.201561
-0.108506
-0.107134
-0.263442
--0.0926839
-0.464401
-0.151703
-0.518967
-0
--0.221471
--0.0972167
-0.120159
-0.0572032
-0.15778
--0.0990916
-0.569029
-0.0559187
-0.150285
-0.0188279
-0.0566314
-0.0559701
--0.0379037
-0.0581622
--0.0927115
-0.209717
-0.433666
-0.225257
-0.344334
-0.367695
-0.19668
-0.151334
--0.186842
-0.257814
-0
-0.0220279
-0.199584
--0.18602
-0.309854
-0.53001
-0.263972
-0.346411
-0.0560602
-0.496474
--0.131842
-0.205978
-0.0180306
-0.390118
-0.349835
-0.356915
-0.262668
-0.370239
-0.112854
-0.310159
-0.482582
-0.733504
--0.184731
-0.611306
--0.0739347
--0.190262
--0.0160264
-0.128178
--0.2088
--0.0730525
-0.395072
-0.108058
--0.130771
-0.11313
--0.0745896
-0.106874
--0.0947029
--0.130177
-0.266176
-0.310878
-0.276302
--0.0884598
-0.0170909
-0.148367
--0.0946645
-0.625485
-0.054175
-0.25969
-0.242837
-0.235688
-0.144485
-0.0761417
--0.181067
-0.107025
-0.196346
-0.204064
-0.639744
-0.302352
-0.0538399
-0.403022
--0.277281
-0.192118
-0.141913
-0.0537639
-0.391289
--0.125342
-0.142212
--0.182124
-0.294162
-1.07284
--0.0349101
-0.342883
-0.162238
--0.203546
-0.295525
--0.0390417
-0
-0.146716
-0.401769
--0.275327
--0.0338484
-0.0536936
-0.016913
-0.146589
-0.244864
-0.476878
--0.267557
-0.206627
--0.174746
-0.053872
-0.152008
-0.260052
-0.107463
-0.169422
-0.0521075
-0.422738
-0.700929
-0.252773
--0.0376452
-0.0214392
--0.235183
-0.0187596
--0.124908
-0.155756
-0.289227
-0.36311
-0.204534
-0.0585353
-0.0556921
-0.56996
--0.0352713
--0.0383854
--0.189144
--0.131914
-0
--0.195907
-0.344893
-0.0824879
--0.293415
-0.0575161
--0.0737565
--0.0370977
-0.164676
--0.0955882
-0.205655
--0.0386885
--0.0918111
-0.0186157
--0.208678
-0.203075
-0.0566281
-0.149679
-0.072892
-0.0593579
-0.200716
-0.0180554
-0.272046
-0.379297
-0.307485
-0.409934
-0.107817
-0.519419
-0.641139
-0.457129
-0.0178058
--0.13484
-0.357437
-0.25968
--0.131849
-0.218341
-0.592131
-0.110913
-1.12662
-0.606445
-0.437951
-0.206536
-0.0745396
-0.215477
--0.177943
-0.268815
--0.473113
--0.380324
-0.147382
-0.114626
-0.316056
--0.0377044
--0.127557
-0
-0.255577
-0.508964
--0.0696945
-0.176091
-0.29771
-0.0565097
-0.187896
--0.411759
-0.2987
-0.435276
-0.265365
-0.459158
-0.0547575
--0.0938287
-0.293124
-0.0592447
-0.347085
-0.143203
-0.0521496
-0.293459
--0.361105
--0.0375611
-0.0520958
-0.204039
-0.56031
-0
-0.287635
-0.212593
--0.0377069
-0.491148
-0.0514593
--0.195139
--0.039043
-0.0624846
-0.109127
-0.301085
-0
-0.341888
-0.294667
--0.0871976
--0.0344153
-0.0555963
-0.0526041
-0.335978
-0.164786
-0.0168683
-0.0693505
-0.0521437
-0.0549988
-0.26009
-0.282158
-0.147959
-0.285483
-0
-0.0539396
-0.207158
-0.334904
-0
-0.231094
-0.208695
-0
-0.106544
-0.157706
--0.0376313
--0.0328547
--0.0916127
-0.11045
--0.0383796
-0.537232
-0.432644
--0.0359793
-0.224018
-0.0540123
--0.0793083
-0.511983
-0.176049
-0.262954
--0.09396
-0.147636
-0.266572
-0.0725187
-0.263765
--0.223047
-0.412579
--0.285419
-0.168939
-0.0540695
--0.140212
-0.10965
-0.370177
-0.203245
--0.0378253
-0.260085
-0.0189994
-0.290362
--0.323911
-0.105138
-0.210635
-0.0559601
-0.113002
-0.29548
-0.336634
-0.162847
--0.0387527
-0.110265
-0.148163
-0.0566031
-0.0556328
-0.22598
--0.306518
-0.43472
--0.192411
--0.123746
-0.110102
-0.202354
--0.131327
-0.017851
-0.332234
-0.191755
--0.0727562
--0.199044
--0.0915568
-0.110686
-0.287642
-0.0724655
-0.0578567
--0.135391
-0.354608
-0.318036
--0.130999
-0.0557686
--0.223515
-0.50212
--0.0169577
-0.555073
-0.108779
--0.126973
--0.0352946
-0.527938
-0.105838
-0.0507927
-0.0560027
-0.142076
-0.151101
-0.055654
--0.0356291
-0.251634
--0.129703
-0
-0.161928
-0.108391
-0.584697
--0.177602
-0.152972
-0.0537133
--0.180335
-0.59213
-0.104112
-0.105945
-0.203301
-0.0513157
-0.170621
--0.0937461
--0.407356
--0.209511
-0.153352
--0.168621
--0.134047
-0
--0.187679
--0.0355989
-0.17909
-0.196176
-0.45338
-0.113103
-0.209561
-0.146682
-0.0578898
-0.0525205
-0
-0.0529381
--0.093159
--0.287189
--0.0382893
-0.328338
--0.0384848
-0.262496
-0.157998
-0.0544075
-0.0553466
-0.259763
-0.0551473
-0.196976
--0.133917
--0.220535
--0.0970395
-0.0542527
-0.362511
-0.284515
--0.0942681
-0.112748
-0.492847
-0.15343
-0.112859
-0.204298
--0.0397227
-0.413767
-0.372385
-0.27012
-0.563244
-0.160978
-0.121026
-0.439391
--0.0169118
-0.0519622
--0.1916
--0.0371911
-0.41563
--0.0167979
-0
--0.0936232
-0.370043
-0.107526
-0.112903
-0.0179335
-0.203315
-0.0526893
-0.174234
-0.111498
--0.0396524
-0.204934
-0.200809
-0.778464
-0.379359
-0.0759505
-0.112389
-0.114282
-0.111458
-0.180746
-0.11608
--0.037691
--0.0383838
-0.10618
--0.0192075
--0.0701589
--0.312636
-0.400197
--0.0380631
-0.408376
-0.211805
--0.0369757
--0.29243
-0.512703
-0.107474
-0.285782
--0.0380514
--0.0367871
-0.305253
-0.346898
-0.110318
-0.584265
-0.0575477
-0.0173792
-0.265219
--0.12276
-0.251943
-0.0566212
-0.166477
-0.163656
-0.108627
--0.0881703
-0.0544588
-0.0555295
-0.664816
-0.209203
--0.181911
--0.0859628
-0.286636
--0.0160148
-0.0561254
-0.143711
-0.288485
-0.143711
-0.0567389
-0.158424
--0.0381703
-0.287518
--0.377974
-0.486495
-0.220415
--0.0895781
-0.113173
--0.278847
--0.129786
-0.0520535
--0.187889
-0.0521184
--0.0965375
-0.053486
-0.327834
-0.149782
-0.0175125
--0.0380313
-0
--0.179938
-0.157552
-0.0178761
--0.0355054
--0.0163114
-0.0574
--0.179883
--0.160435
-0.220902
--0.0387294
--0.0710236
--0.0767055
-0.0187291
-0
-0.148156
-0.267032
-0.0560565
-0.362131
--0.0945234
-0.317842
-0.295181
-0.213039
-0
-0.0560024
--0.190141
-0.0582819
-0.0185046
-0.161064
--0.192093
-0.671981
--0.125297
--0.287078
--0.135541
-0.058087
-0.354126
--0.189419
-0.111244
-0.0589498
--0.0756877
--0.134838
-0.226754
--0.377954
-0.0553705
-0.295114
--0.129814
-0.6157
-0.0566464
-0.0756537
-0.0545127
-0.749266
-0.200279
-0.34367
-0.0743446
-0.0548797
--0.226575
-0.317405
-0.152252
-0.111736
--0.0920127
-0.0190041
--0.313257
-0.479029
--0.167215
-0.113438
-0
-0.269254
--0.317497
-0.15196
-0.305542
-0.0583447
-0.164837
-0.290029
-0.0571661
--0.0721997
--0.0375974
-0.21787
-0.0583722
-0.204231
-0.327722
-0.447995
-0.445345
--0.135222
--0.131068
--0.290083
-0.0184758
-0.451414
--0.21806
-0.0557723
--0.361105
-0.168762
-0.205799
-0.110712
-0.190937
-0.199525
--0.0366869
-0.20815
--0.160911
-0.201884
--0.0353681
-0.0172427
-0.0738241
--0.0375522
-0.0532859
--0.18435
-0.278634
-0.144958
-0.0533966
-0.197968
--0.0854217
-0.15099
-0.193677
--0.0336838
-0.0560732
--0.10476
-0.45209
-0.165397
-0.32972
-0.208694
-0.635139
-0.653843
-0.237071
-0.168493
-0.483721
-0.0573111
-0.0543619
-0.149472
-0.340182
--0.131627
-0.0211769
-0.21195
--0.0721283
-0.30339
-0.117665
-0.46893
--0.0160321
-0.15794
-0.0199685
-0.3592
--0.182921
-0.210724
-0.370071
--0.038624
-0.0765721
-0
--0.105672
-0.0559825
-0.0742484
-0.0226787
--0.0371248
-0.152931
--0.0712118
--0.283358
--0.0918624
-0.114223
-0.447549
-0.149528
-0.106633
-0.114982
-0.311643
--0.0979827
--0.18889
--0.0382035
-0.0551878
--0.19292
-0.20049
-0.435623
-0.298083
--0.0389624
-0.412973
--0.0753163
-0.151751
--0.13511
--0.0912868
-0.309638
-0.108216
-0.0218913
-0.112267
-0.581493
-0.260753
-0.428946
-0.0181347
-0.21331
-0.292506
-0.204283
--0.218525
-0.113772
--0.0382902
-0.297293
--0.0366975
--0.274821
-0.108573
-0.453212
-0.213646
--0.280483
--0.0372199
-0.0217275
-0.160336
--0.0951611
--0.0365595
--0.0173997
--0.0906175
-0.0375771
-0.147197
--0.0385067
-0.0536781
--0.0776115
--0.0368809
-0.111998
-0.321611
-0.110317
-0.195853
-0.772425
-0.209514
-0.910184
-0.127383
-0.341582
-0.343969
--0.0361863
-0.111295
-0.150008
-0.0719371
-0.170664
-0.164122
-0.112037
--0.0747991
-0.148623
--0.121674
-0.144008
-0.0175658
-0.198452
-0.248793
-0.0728232
-0.0530867
--0.091506
-0.105734
-0.144062
--0.0355207
-0.0210666
-0.0999908
-0.294903
-0.426054
-0.0620058
-0.445505
-0.0574705
-0.189958
--0.176482
-0
-0.339615
--0.0852011
-0.340038
-0.103508
-0.30938
-0.103661
-0.10565
--0.0354787
-0.0554342
--0.174603
--0.0868466
-0.13814
--0.173186
--0.0862068
-0.356104
-0.0992328
-0.14648
-0.152683
-0.0557239
--0.0377119
-0.43707
-0.198734
-0.152017
--0.306395
--0.18891
--0.0367526
-0.0568279
-0.339684
-0.113069
-0.103195
-0.0567902
--0.181121
--0.128441
-0.0525482
-0.110143
-0.39634
-0.55872
-0.106078
-0.114018
-0.196167
-0.316971
-0.41363
-0.151079
-0.449552
-0.114689
-0.0721879
--0.174456
--0.0352268
--0.227259
-0.054418
--0.0928136
-0.165001
--0.309961
-0.150152
-0.308743
-0.116885
-0.0558391
-0.47584
-0.204359
-0.0533833
--0.037858
--0.21299
-0.205922
-0.823024
-0.203991
-0.110947
--0.189143
-0.109938
-0.299721
-0.265338
-0.077286
--0.0359959
-0.0578066
-0.274813
--0.153676
-0.142272
-0.36474
-0.0510887
--0.19154
-0.103183
-0.0186622
-0.249163
-0.103278
--0.0736592
-0.0177736
-0.725546
-0.622129
-0.26154
-0.132422
-0.0563359
-0.300901
-0.333193
-0.231017
-0.0536179
--0.0366031
-0.0536995
--0.134747
--0.31243
--0.0159807
-0.204593
-0.443919
-0.450626
--0.070145
-0.10965
--0.195616
-0.250924
-0.0554783
-0.0535969
-0.114672
-0.0513647
-0.366914
-0.354017
-0.420485
-0.106496
--0.0372508
--0.0726505
--0.366549
-0.148351
-0.338204
--0.427958
--0.186509
-0.336186
-0.13523
--0.0404207
-0
-0.466328
-0
-0.0555755
--0.0978084
--0.0163055
-0.1628
-0.210877
-0.186087
-0.307441
--0.395569
--0.0385817
-0.549993
--0.201184
--0.315813
--0.128448
--0.1885
--0.0384467
-0.155891
-0.0537739
-0.164872
-0
--0.0395714
-0.299725
--0.203547
--0.100804
--0.13671
--0.391864
-0.328569
-0.367921
-0.393482
-0.149512
-0.66725
-0.076188
-0.331475
-0.210668
-0.213665
-0.11757
--0.240115
-0.41969
-0.163197
-0.209431
-0.187816
--0.199529
-0.324846
--0.204428
-0.130616
-0.110664
-0.274488
-0.459875
-0.470191
-0.112664
-0.0581697
--0.384164
-0.0596991
-0.0604618
--0.0180281
-0.477557
--0.14652
--0.0961388
--0.095785
-0.690449
--0.198643
-0.0573324
-0.573515
--0.226263
-0.165405
--0.0399532
--0.0171409
-0.0792931
--0.0409682
-0.0586755
-0.860004
-0.0609537
-0.223001
--0.0398171
-0.0612975
--0.290981
-0.0577869
-0.120588
-0.120354
-0.0572989
--0.0419445
-0
-0.0596848
-0.155998
--0.0384772
--0.13505
--0.0400638
-0.0190133
-0.326223
-0.435628
-0.394452
--0.293799
--0.143667
-0.326958
-0.629887
-0.0580752
-0.155194
--0.230992
-0.161627
-0.145477
--0.137294
-0.0185593
-0
--0.096046
-0.022978
-0.297281
-0.585951
-0.0208212
-0.207923
-0.0538383
-0.605886
-0.109965
-0.116627
--0.28291
-0.172816
-0.509022
-0.409099
-0.201726
-0.0586598
-0.0770991
-0.0798128
-0.0572219
-0.268607
-0.0576481
-0.0722175
--0.169305
--0.0919382
--0.0792629
-0.316946
-0.248846
--0.0831264
--0.149222
-0.0977218
-0.302615
-0.0497849
-0.0671566
-0.173807
-0.0487994
-0
-0.194335
--0.20529
-0.129852
-0
-0.231724
-0.131253
--0.330405
--0.0349695
--0.146498
-0.338374
-0.137418
-0.270978
--0.153834
-0.273177
--0.0683281
-0.0185371
--0.197214
-0.0503772
-0.295295
-0.259595
-0.387715
-0.0498917
-0.0995159
-0.328922
-0.185227
-0.243474
-0.468672
-0.230862
--0.0837367
-0.120684
-0.274358
-0.373929
--0.0736573
-0.482987
--0.0342321
-0.195392
--0.0831372
-0.194755
-0.403598
--0.0691661
-0.43026
-0.102692
-0.272478
-0.0528277
--0.203212
-0.0507589
--0.0673171
-0.340619
-0.016797
--0.360647
-0.191883
-0.469391
-0.241997
--0.125713
-0.19227
-0.053789
-0
-0.427397
--0.0336073
-0.0680931
-0.591552
-0.162714
-0.331537
-0.250794
--0.304173
--0.0359267
-0.102787
-0.357457
-0.0511759
-0.458812
-0.190671
--0.123225
--0.25934
--0.298798
-0.105268
--0.0859297
-0.245244
--0.0365956
--0.0885764
-0.192596
-0.625054
--0.0356663
-0.190448
-0.531675
--0.301558
--0.0712922
-0.322608
--0.0935282
--0.116103
-0.0999712
-0.245616
-0.103562
--0.120834
--0.0336319
-0.792321
-0.360402
--0.0486089
-0.0518575
--0.163277
--0.21478
-0.325185
-0.122493
-0.18772
--0.0349313
-0.130946
--0.265262
--0.0316528
-0.419377
--0.0332464
-0.0159928
--0.0153042
-0.349345
-0.554685
-0.633955
-0
-0.169292
--0.129305
--0.104012
-0.199903
-0.222315
-0.052662
--0.306915
-0.107585
-0.452842
-0.681793
--0.0376822
-0.356134
-0.059346
-0.171384
-0.174294
--0.120493
-0.224329
-0.688986
--0.0792182
-0.29279
-0.384418
--0.0936543
-0.219857
-0.433595
-0.803053
-0.209892
-0.158474
-0.24946
-0.391953
--0.18373
-0.318612
-0.261644
--0.105269
-0.113585
-0.287072
-0.439537
-0
-0.359555
-0.322793
--0.193993
-0.0584546
-0.14424
-0.674962
-0.116931
--0.100368
-0.305121
-0.0597931
-0.308481
-0.181708
-0.25247
-0.140144
-0.113155
-0.160682
-0.134583
-0.230104
-0.16105
--0.293248
-0.211351
-0.0193564
--0.0926827
-0.337883
-0.135719
-0.0601875
-0
-0.161029
--0.132816
-0.316672
-0.207541
-0.160499
--0.0396385
--0.29105
--0.0390427
--0.138845
--0.142881
-0.271886
-0.373263
--0.0419963
-0.48821
-0.0188107
--0.0381586
--0.393416
-0.3411
-0.434927
-0.15718
-0.148729
-0.256206
--0.0949966
-0.356178
-0.0185259
--0.0385496
-0
--0.316281
-0.157013
--0.165594
-0.319349
--0.241382
-0.122424
--0.0952606
-0.265896
-0.254846
-0.316948
-0
-0.295076
-0.0565095
-0
-0.0733697
-0.157138
--0.265322
--0.0994464
-0.698739
-0.0210561
--0.0349334
--0.0938039
--0.124059
-0.295149
-0.192751
--0.131439
--0.182168
-0.209559
-0.279712
-0.445955
-0.337876
--0.0940808
--0.0867651
-0.114927
-0.485988
-0
--0.0963638
-0
-0.188583
--0.243094
-0.42509
-0.0191101
--0.231105
-0.252223
-0.164494
--0.0865747
-0.289367
--0.122101
-0.0535119
--0.124474
-0.147892
-0.239771
-0.196767
-0.190833
-0.297364
--0.0880381
-0.482432
--0.21898
-0.200596
-0.107791
--0.281604
--0.26292
-0.0183217
-0.558556
-0.289648
-0.055601
-0.0171857
-0.0559659
-0.429524
-0.570117
--0.128336
--0.182478
-0.4759
-0.487629
--0.0355215
-0.288874
-0.0531997
-0.285829
-0.486621
--0.202709
-0.44559
-0.076946
-0.219672
--0.0891779
-0.0534762
-0.108074
-0.503888
--0.0361481
-0.275432
-0.448725
-0.0178519
-0.110708
-0.106911
--0.216487
-0.0544285
-0.581416
-0.109406
-0.353822
-0
-0.0539464
--0.0359488
-0.0179318
-0
-0.503488
-0.298803
-0.44771
-0.0387238
--0.091378
-0.557356
-0.15747
-0.107783
-0.221239
-0.470372
-0.357152
-0.266493
-0.161699
-0.149993
--0.176113
--0.30229
-0.595759
--0.12371
--0.0915308
--0.0720118
--0.303162
-0.540635
-0.0505806
--0.0386752
--0.125231
--0.0386531
-0.217905
-0.0712855
-0.0535902
--0.126061
-0.0549965
-0.346895
-0.106358
--0.177826
--0.13305
--0.120683
-0.182702
-0.0549344
--0.153305
-0.366185
-0.0696042
-0.140471
-0.020235
-0
-0.279874
--0.172744
-0.137176
-0.235573
-0.104239
-0.325531
-0.259032
-0.0511575
--0.035451
-0.160596
-0.278318
-0.0519109
--0.0340443
--0.173923
--0.126663
-0.0731991
-0.151998
--0.0338043
--0.0889193
-0.488664
--0.24464
--0.0590789
--0.152431
-0.088974
--0.0336257
-0.180409
-0.186286
-0.29826
-0.130733
--0.252351
-0.0497213
-0.329986
-0.13556
-0.0446915
--0.309442
-0.214567
-0.0497547
-0.0888765
-0
-0.220677
--0.324128
-0.049562
-0.268967
--0.0320675
-0.136647
--0.081064
--0.034935
--0.244248
--0.116721
-0.299088
-0.219763
-0.370135
--0.259717
-0.275506
--0.0331603
-0.249659
-0.324403
-0.275763
--0.0344493
-0.34662
-0.189131
-0.146964
-0.460975
--0.113715
--0.117118
-0.127241
-0.203148
-0.228788
-0.522174
-0.0963815
-0.0514989
-0.228812
-0.28604
--0.0791005
--0.120039
--0.0329595
-0.38812
--0.145778
-0.189331
-0.258514
-0.963431
--0.115535
-0.563334
--0.142277
-0.10238
-0.495785
--0.0343335
-0.098746
--0.063288
--0.257835
-0.445475
--0.112344
-0.104544
--0.115539
-0.0506701
--0.0342702
-0.394124
-0.3502
-0.188938
--0.0316736
--0.199031
-0.0957035
-0
--0.147622
-0
-0.412189
-0.0503234
-0.264182
--0.084882
-0.331038
-0.017287
-0.0161042
-0.267934
--0.0141649
--0.175969
-0.261272
-0.0517662
-0.142644
-0.0507355
-0.314126
-0.335136
-0.101068
-0.179677
-0.0990069
-0.270412
--0.11718
-0.192941
--0.242981
-0.127487
-0.168516
--0.0867636
--0.0949681
--0.0656131
--0.193304
-0.153177
-0.0473412
-0.314918
-0.0477817
--0.118494
-0.359414
-0.0998398
--0.031117
-0.0499724
-0.521482
-0.163144
-0.186203
-0.0518008
-0
-0.188959
-0.326368
-0.147286
--0.249377
-0.0521367
-0.106671
--0.03371
-0.192943
-0.272098
-0.101068
-0.0174383
-0.622364
-0.142459
--0.0166833
-0.417539
-0.109244
--0.206776
-0.891423
--0.256289
--0.128274
-0.429467
-0.0170512
--0.0359092
-0
--0.0380228
-0.660005
-0.0560982
--0.0328145
--0.190481
--0.0836826
-0.359069
-0.0569764
-0.14677
--0.18877
--0.133365
-0.203673
-0.0547872
--0.0387088
-0.146065
--0.129845
-0
-0
-0.213201
-0.175001
--0.101355
-0.0581237
--0.37354
-0.351305
-0.330297
--0.0712143
-0.28842
-0.109303
-0.0565303
-0.0548173
-0.356717
-0.486218
-0.211268
-0
-0.279755
--0.278512
-0.175523
--0.181675
--0.0730119
-0.0569224
--0.0373163
-0.112925
--0.0360223
-0.20837
-0.059035
-0.569228
-0.258881
--0.0381614
--0.0712612
--0.0354023
-0.456825
-0.439136
-0.161899
-0.107057
-0.195924
-0.0551121
--0.0690335
-0.0166915
-0.107225
--0.0903168
-0.0522613
-0.193096
-0.0166462
-0.0541923
--0.159881
-0.344299
--0.0878657
-0.196545
-0.373539
--0.0714657
-0.253924
--0.354294
-0.254671
-0.23471
--0.154428
-0.450433
-0.0159522
-0.160236
-0
--0.0866409
-0.152237
-0.0672291
--0.169568
-0.154009
-0.0498143
--0.0322492
-0.0473507
--0.0658763
-0.0154559
-0.198847
-0
-0.264694
-0.146955
--0.160051
-0.0469055
-0.309456
-0.0607201
-0.174828
--0.116483
-0.143794
-0.190961
-0.666741
--0.0982172
-0.0162443
-0.527446
-0
--0.124003
-0.0652925
-0.224971
--0.11722
-0.255535
--0.031775
-0
-0.314257
-0.62955
-0.327366
--0.0910215
-0.051042
--0.422975
-0.10696
-0.016711
-0.0485049
--0.0174222
-0.0184166
-0.140101
-0
-0.145073
-0.577371
-0.297606
-0.382225
-0.0208021
-0.248549
-0
-0.439375
-0.357877
--0.125339
-0.260691
--0.0157115
--0.130412
--0.090949
-0.439179
-0.258642
-0.255595
-0.29296
--0.0390182
--0.18032
-0.168827
-0.0184368
-0
--0.293266
--0.0951028
-0.0198145
--0.271084
--0.0873103
-0.166982
-0.204539
-0.170565
-0.111022
-0.056493
--0.0379535
-0.15082
--0.275577
-0.0217818
-0.359517
--0.0935297
-0.107381
-0.205076
--0.0365387
-0.211074
-0.110538
--0.133708
-0.196898
-0.154318
-0.109798
-0.500312
-0.485894
-0.300786
-0.430485
-0.255672
--0.0361383
-0.148051
-0.050911
--0.0964059
-0.207996
-0.110588
-0.339068
-0.0541874
-0.682652
--0.122942
-0.164212
--0.096355
--0.0373621
-0.145986
-0.520589
--0.225869
-0.350932
--0.351536
-0.328678
--0.0373391
-0.0553562
-0.297851
-0.0511972
-0.199673
-0.466525
--0.0869905
--0.0896449
-0.323633
-0.31796
-0.052544
--0.0866467
--0.0355165
-0
-0.530815
-0.312985
-0.0527644
-0.175672
-0.101287
-0.186875
--0.0867421
--0.0331166
--0.170423
-0.449012
-0.135471
--0.0804284
--0.344996
--0.0798361
-0.0520685
-0.0160177
--0.140007
\ No newline at end of file
diff --git a/test/sasdataloader/test/MAR07232_rest.h5 b/test/sasdataloader/test/MAR07232_rest.h5
new file mode 100644
index 0000000..d9c899d
Binary files /dev/null and b/test/sasdataloader/test/MAR07232_rest.h5 differ
diff --git a/src/sas/__init__.py b/test/sasdataloader/test/__init__.py
similarity index 100%
copy from src/sas/__init__.py
copy to test/sasdataloader/test/__init__.py
diff --git a/test/sasdataloader/test/error_conditions.py b/test/sasdataloader/test/error_conditions.py
index 528a3ce..a2508f1 100644
--- a/test/sasdataloader/test/error_conditions.py
+++ b/test/sasdataloader/test/error_conditions.py
@@ -1,31 +1,31 @@
-from sas.sascalc.dataloader.loader import Loader
-import unittest
-
-class testLoader(unittest.TestCase):
- def setUp(self):
- self.s = Loader()
-
- def test_load_unknown(self):
- """
- self.s.load('blah.mat') on an unknown type
- should raise a ValueError exception (thrown by data_util.registry)
- """
- self.assertRaises(ValueError, self.s.load, 'angles_flat.mat')
-
- def test_corrupt(self):
- """
- Loading a corrupted file with a known extension
- should raise a runtime exception.
- The error condition is similar to an unknown
- type (file extension). When a reader is identified as
- knowing the file extension, it tries to load. If it
- raises an exception, the system should try to identify
- another reader that knows about that file extension.
- If they all fail, we raise a runtime exception stating
- that no reader was found for this file.
- """
- self.assertRaises(RuntimeError, self.s.load, 'corrupt.png')
-
-
-if __name__ == '__main__':
- unittest.main()
+from sas.sascalc.dataloader.loader import Loader
+import unittest
+
+class testLoader(unittest.TestCase):
+ def setUp(self):
+ self.s = Loader()
+
+ def test_load_unknown(self):
+ """
+ self.s.load('blah.mat') on an unknown type
+ should raise a ValueError exception (thrown by data_util.registry)
+ """
+ self.assertRaises(ValueError, self.s.load, 'angles_flat.mat')
+
+ def test_corrupt(self):
+ """
+ Loading a corrupted file with a known extension
+ should raise a runtime exception.
+ The error condition is similar to an unknown
+ type (file extension). When a reader is identified as
+ knowing the file extension, it tries to load. If it
+ raises an exception, the system should try to identify
+ another reader that knows about that file extension.
+ If they all fail, we raise a runtime exception stating
+ that no reader was found for this file.
+ """
+ self.assertRaises(RuntimeError, self.s.load, 'corrupt.png')
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/test/sasdataloader/test/isis_1_0_write_test.xml b/test/sasdataloader/test/isis_1_0_write_test.xml
deleted file mode 100644
index e69de29..0000000
diff --git a/test/sasdataloader/test/isis_1_1_write_test.xml b/test/sasdataloader/test/isis_1_1_write_test.xml
deleted file mode 100644
index e69de29..0000000
diff --git a/test/sasdataloader/test/sequence_tests.py b/test/sasdataloader/test/sequence_tests.py
index 30343f8..b47e43b 100644
--- a/test/sasdataloader/test/sequence_tests.py
+++ b/test/sasdataloader/test/sequence_tests.py
@@ -1,31 +1,33 @@
-from DataLoader.loader import Loader
-from DataLoader.readers.IgorReader import Reader as igor_reader
-from DataLoader.readers.abs_reader import Reader as abs_reader
-
-
-def consecutive_loader():
- out1 = Loader().load("jan08002.ABS")
- out2 = Loader().load("MAR07232_rest.ASC")
- if len(out2.detector)>1:
- print "Consecutive reads using Loader failed"
-
-def consecutive_reader():
- out1 = abs_reader().read("jan08002.ABS")
- out2 = igor_reader().read("MAR07232_rest.ASC")
- if len(out2.detector)>1:
- print "Consecutive reads using Readers failed"
- print out1
- print out2
-
-def single_abs():
- out1 = abs_reader().read("jan08002.ABS")
-
-def single_igor():
- out1 = igor_reader().read("MAR07232_rest.ASC")
-
-if __name__ == "__main__":
- #consecutive_loader()
- #consecutive_reader()
- single_igor()
- single_abs()
- print "Test passed"
+from __future__ import print_function
+
+from DataLoader.loader import Loader
+from DataLoader.readers.IgorReader import Reader as igor_reader
+from DataLoader.readers.abs_reader import Reader as abs_reader
+
+
+def consecutive_loader():
+ out1 = Loader().load("jan08002.ABS")
+ out2 = Loader().load("MAR07232_rest.ASC")
+ if len(out2.detector)>1:
+ print("Consecutive reads using Loader failed")
+
+def consecutive_reader():
+ out1 = abs_reader().read("jan08002.ABS")
+ out2 = igor_reader().read("MAR07232_rest.ASC")
+ if len(out2.detector)>1:
+ print("Consecutive reads using Readers failed")
+ print(out1)
+ print(out2)
+
+def single_abs():
+ out1 = abs_reader().read("jan08002.ABS")
+
+def single_igor():
+ out1 = igor_reader().read("MAR07232_rest.ASC")
+
+if __name__ == "__main__":
+ #consecutive_loader()
+ #consecutive_reader()
+ single_igor()
+ single_abs()
+ print("Test passed")
diff --git a/test/sasdataloader/test/sesans_examples/next_gen.ses b/test/sasdataloader/test/sesans_examples/next_gen.ses
new file mode 100644
index 0000000..22eb1f2
--- /dev/null
+++ b/test/sasdataloader/test/sesans_examples/next_gen.ses
@@ -0,0 +1,73 @@
+FileFormatVersion 2.0
+DataFileTitle PMMA in Mixed Deuterated decalin
+Sample Ostensibly 40$ 100nm radius PMMA hard spheres in mixed deuterarted decalin.
+Thickness 2
+Thickness_unit mm
+Theta_zmax 0.09
+Theta_zmax_unit radians
+Theta_ymax 0.09
+Theta_ymax_unit radians
+Orientation Z
+SpinEchoLength_unit A
+Depolarisation_unit A-2 cm-1
+Wavelength_unit A
+
+BEGIN_DATA
+SpinEchoLength Depolarisation Depolarisation_error Wavelength
+260.0 -1.42E-3 2.04E-3 1.612452
+280.8 -1.45E-3 1.87E-3 1.675709
+303.264 -1.64E-3 1.23E-3 1.741448
+327.525 -1.69E-3 1.17E-3 1.809765
+353.727 -2.23E-3 9.09E-4 1.880763
+382.025 -2.26E-3 8.58E-4 1.954546
+412.587 -2.41E-3 7.29E-4 2.031224
+445.594 -2.58E-3 6.75E-4 2.11091
+481.242 -2.88E-3 6.04E-4 2.193723
+519.741 -3.35E-3 5.56E-4 2.279783
+561.32 -3.60E-3 5.22E-4 2.369219
+606.226 -3.92E-3 4.91E-4 2.462166
+654.724 -4.36E-3 4.73E-4 2.558758
+707.102 -4.67E-3 4.54E-4 2.659139
+763.67 -4.91E-3 4.22E-4 2.763458
+824.764 -5.32E-3 3.88E-4 2.87187
+890.745 -5.43E-3 3.53E-4 2.984535
+962.005 -5.61E-3 3.28E-4 3.101621
+1038.97 -5.83E-3 3.07E-4 3.223306
+1122.08 -5.88E-3 2.91E-4 3.349746
+1211.85 -5.91E-3 2.73E-4 3.481164
+1308.8 -5.71E-3 2.61E-4 3.617734
+1413.5 -5.40E-3 2.49E-4 3.759654
+1526.58 -5.10E-3 2.41E-4 3.907147
+1648.71 -4.77E-3 2.34E-4 4.060431
+1780.6 -4.34E-3 2.26E-4 4.219716
+1923.05 -4.18E-3 2.20E-4 4.385259
+2076.9 -4.08E-3 2.16E-4 4.557302
+2243.05 -4.37E-3 2.13E-4 4.736085
+2422.49 -4.66E-3 2.10E-4 4.92188
+2616.29 -4.96E-3 2.06E-4 5.114968
+2825.59 -5.04E-3 2.03E-4 5.315628
+3051.64 -4.96E-3 1.99E-4 5.524165
+3295.77 -4.72E-3 1.97E-4 5.74088
+3559.43 -4.52E-3 1.92E-4 5.966096
+3844.19 -4.65E-3 1.93E-4 6.200153
+4151.72 -4.74E-3 1.96E-4 6.443384
+4483.86 -4.87E-3 1.99E-4 6.696163
+4842.57 -4.81E-3 2.05E-4 6.958858
+5229.98 -4.57E-3 2.09E-4 7.23186
+5648.38 -4.72E-3 2.17E-4 7.515571
+6100.25 -4.79E-3 2.23E-4 7.81041
+6588.27 -4.68E-3 2.28E-4 8.116816
+7115.33 -4.61E-3 2.32E-4 8.435242
+7684.55 -4.78E-3 2.46E-4 8.766157
+8299.32 -4.74E-3 2.46E-4 9.11006
+8963.26 -4.56E-3 2.50E-4 9.467449
+9680.32 -4.70E-3 2.58E-4 9.838862
+10454.7 -4.81E-3 2.64E-4 10.224823
+11291.1 -4.65E-3 2.69E-4 10.625959
+12194.4 -4.43E-3 2.79E-4 11.042826
+13170.0 -4.55E-3 3.01E-4 11.476062
+14223.6 -4.35E-3 3.20E-4 11.926274
+15361.5 -4.24E-3 3.51E-4 12.394152
+16590.4 -4.68E-3 4.12E-4 12.880373
+17917.6 -4.96E-3 4.98E-4 13.385664
+19303.4 -4.56E-3 5.98E-4 13.893668
diff --git a/test/sasdataloader/test/sesans_examples/no_spin_echo_unit.ses b/test/sasdataloader/test/sesans_examples/no_spin_echo_unit.ses
new file mode 100644
index 0000000..41818f4
--- /dev/null
+++ b/test/sasdataloader/test/sesans_examples/no_spin_echo_unit.ses
@@ -0,0 +1,72 @@
+FileFormatVersion 1.0
+DataFileTitle PMMA in Mixed Deuterated decalin
+Sample Ostensibly 40$ 100nm radius PMMA hard spheres in mixed deuterarted decalin.
+Thickness 2
+Thickness_unit mm
+Theta_zmax 0.09
+Theta_zmax_unit radians
+Theta_ymax 0.09
+Theta_ymax_unit radians
+Orientation Z
+Depolarisation_unit A-2 cm-1
+Wavelength_unit A
+
+BEGIN_DATA
+SpinEchoLength Depolarisation Depolarisation_error Wavelength
+260.0 -1.42E-3 2.04E-3 1.612452
+280.8 -1.45E-3 1.87E-3 1.675709
+303.264 -1.64E-3 1.23E-3 1.741448
+327.525 -1.69E-3 1.17E-3 1.809765
+353.727 -2.23E-3 9.09E-4 1.880763
+382.025 -2.26E-3 8.58E-4 1.954546
+412.587 -2.41E-3 7.29E-4 2.031224
+445.594 -2.58E-3 6.75E-4 2.11091
+481.242 -2.88E-3 6.04E-4 2.193723
+519.741 -3.35E-3 5.56E-4 2.279783
+561.32 -3.60E-3 5.22E-4 2.369219
+606.226 -3.92E-3 4.91E-4 2.462166
+654.724 -4.36E-3 4.73E-4 2.558758
+707.102 -4.67E-3 4.54E-4 2.659139
+763.67 -4.91E-3 4.22E-4 2.763458
+824.764 -5.32E-3 3.88E-4 2.87187
+890.745 -5.43E-3 3.53E-4 2.984535
+962.005 -5.61E-3 3.28E-4 3.101621
+1038.97 -5.83E-3 3.07E-4 3.223306
+1122.08 -5.88E-3 2.91E-4 3.349746
+1211.85 -5.91E-3 2.73E-4 3.481164
+1308.8 -5.71E-3 2.61E-4 3.617734
+1413.5 -5.40E-3 2.49E-4 3.759654
+1526.58 -5.10E-3 2.41E-4 3.907147
+1648.71 -4.77E-3 2.34E-4 4.060431
+1780.6 -4.34E-3 2.26E-4 4.219716
+1923.05 -4.18E-3 2.20E-4 4.385259
+2076.9 -4.08E-3 2.16E-4 4.557302
+2243.05 -4.37E-3 2.13E-4 4.736085
+2422.49 -4.66E-3 2.10E-4 4.92188
+2616.29 -4.96E-3 2.06E-4 5.114968
+2825.59 -5.04E-3 2.03E-4 5.315628
+3051.64 -4.96E-3 1.99E-4 5.524165
+3295.77 -4.72E-3 1.97E-4 5.74088
+3559.43 -4.52E-3 1.92E-4 5.966096
+3844.19 -4.65E-3 1.93E-4 6.200153
+4151.72 -4.74E-3 1.96E-4 6.443384
+4483.86 -4.87E-3 1.99E-4 6.696163
+4842.57 -4.81E-3 2.05E-4 6.958858
+5229.98 -4.57E-3 2.09E-4 7.23186
+5648.38 -4.72E-3 2.17E-4 7.515571
+6100.25 -4.79E-3 2.23E-4 7.81041
+6588.27 -4.68E-3 2.28E-4 8.116816
+7115.33 -4.61E-3 2.32E-4 8.435242
+7684.55 -4.78E-3 2.46E-4 8.766157
+8299.32 -4.74E-3 2.46E-4 9.11006
+8963.26 -4.56E-3 2.50E-4 9.467449
+9680.32 -4.70E-3 2.58E-4 9.838862
+10454.7 -4.81E-3 2.64E-4 10.224823
+11291.1 -4.65E-3 2.69E-4 10.625959
+12194.4 -4.43E-3 2.79E-4 11.042826
+13170.0 -4.55E-3 3.01E-4 11.476062
+14223.6 -4.35E-3 3.20E-4 11.926274
+15361.5 -4.24E-3 3.51E-4 12.394152
+16590.4 -4.68E-3 4.12E-4 12.880373
+17917.6 -4.96E-3 4.98E-4 13.385664
+19303.4 -4.56E-3 5.98E-4 13.893668
diff --git a/test/sasdataloader/test/sesans_examples/no_wavelength.ses b/test/sasdataloader/test/sesans_examples/no_wavelength.ses
new file mode 100644
index 0000000..9f9296c
--- /dev/null
+++ b/test/sasdataloader/test/sesans_examples/no_wavelength.ses
@@ -0,0 +1,73 @@
+FileFormatVersion 1.0
+DataFileTitle PMMA in Mixed Deuterated decalin
+Sample Ostensibly 40$ 100nm radius PMMA hard spheres in mixed deuterarted decalin.
+Thickness 2
+Thickness_unit mm
+Theta_zmax 0.09
+Theta_zmax_unit radians
+Theta_ymax 0.09
+Theta_ymax_unit radians
+Orientation Z
+SpinEchoLength_unit A
+Depolarisation_unit A-2 cm-1
+Wavelength_unit A
+
+BEGIN_DATA
+SpinEchoLength Depolarisation Depolarisation_error
+260.0 -1.42E-3 2.04E-3 1.612452
+280.8 -1.45E-3 1.87E-3 1.675709
+303.264 -1.64E-3 1.23E-3 1.741448
+327.525 -1.69E-3 1.17E-3 1.809765
+353.727 -2.23E-3 9.09E-4 1.880763
+382.025 -2.26E-3 8.58E-4 1.954546
+412.587 -2.41E-3 7.29E-4 2.031224
+445.594 -2.58E-3 6.75E-4 2.11091
+481.242 -2.88E-3 6.04E-4 2.193723
+519.741 -3.35E-3 5.56E-4 2.279783
+561.32 -3.60E-3 5.22E-4 2.369219
+606.226 -3.92E-3 4.91E-4 2.462166
+654.724 -4.36E-3 4.73E-4 2.558758
+707.102 -4.67E-3 4.54E-4 2.659139
+763.67 -4.91E-3 4.22E-4 2.763458
+824.764 -5.32E-3 3.88E-4 2.87187
+890.745 -5.43E-3 3.53E-4 2.984535
+962.005 -5.61E-3 3.28E-4 3.101621
+1038.97 -5.83E-3 3.07E-4 3.223306
+1122.08 -5.88E-3 2.91E-4 3.349746
+1211.85 -5.91E-3 2.73E-4 3.481164
+1308.8 -5.71E-3 2.61E-4 3.617734
+1413.5 -5.40E-3 2.49E-4 3.759654
+1526.58 -5.10E-3 2.41E-4 3.907147
+1648.71 -4.77E-3 2.34E-4 4.060431
+1780.6 -4.34E-3 2.26E-4 4.219716
+1923.05 -4.18E-3 2.20E-4 4.385259
+2076.9 -4.08E-3 2.16E-4 4.557302
+2243.05 -4.37E-3 2.13E-4 4.736085
+2422.49 -4.66E-3 2.10E-4 4.92188
+2616.29 -4.96E-3 2.06E-4 5.114968
+2825.59 -5.04E-3 2.03E-4 5.315628
+3051.64 -4.96E-3 1.99E-4 5.524165
+3295.77 -4.72E-3 1.97E-4 5.74088
+3559.43 -4.52E-3 1.92E-4 5.966096
+3844.19 -4.65E-3 1.93E-4 6.200153
+4151.72 -4.74E-3 1.96E-4 6.443384
+4483.86 -4.87E-3 1.99E-4 6.696163
+4842.57 -4.81E-3 2.05E-4 6.958858
+5229.98 -4.57E-3 2.09E-4 7.23186
+5648.38 -4.72E-3 2.17E-4 7.515571
+6100.25 -4.79E-3 2.23E-4 7.81041
+6588.27 -4.68E-3 2.28E-4 8.116816
+7115.33 -4.61E-3 2.32E-4 8.435242
+7684.55 -4.78E-3 2.46E-4 8.766157
+8299.32 -4.74E-3 2.46E-4 9.11006
+8963.26 -4.56E-3 2.50E-4 9.467449
+9680.32 -4.70E-3 2.58E-4 9.838862
+10454.7 -4.81E-3 2.64E-4 10.224823
+11291.1 -4.65E-3 2.69E-4 10.625959
+12194.4 -4.43E-3 2.79E-4 11.042826
+13170.0 -4.55E-3 3.01E-4 11.476062
+14223.6 -4.35E-3 3.20E-4 11.926274
+15361.5 -4.24E-3 3.51E-4 12.394152
+16590.4 -4.68E-3 4.12E-4 12.880373
+17917.6 -4.96E-3 4.98E-4 13.385664
+19303.4 -4.56E-3 5.98E-4 13.893668
diff --git a/test/sasdataloader/test/sesans_examples/sesans_no_data.ses b/test/sasdataloader/test/sesans_examples/sesans_no_data.ses
new file mode 100644
index 0000000..907cad2
--- /dev/null
+++ b/test/sasdataloader/test/sesans_examples/sesans_no_data.ses
@@ -0,0 +1,15 @@
+FileFormatVersion 1.0
+DataFileTitle PMMA in Mixed Deuterated decalin
+Sample Ostensibly 40$ 100nm radius PMMA hard spheres in mixed deuterarted decalin.
+Thickness 2
+Thickness_unit mm
+Theta_zmax 0.09
+Theta_zmax_unit radians
+Theta_ymax 0.09
+Theta_ymax_unit radians
+Orientation Z
+SpinEchoLength_unit A
+Depolarisation_unit A-2 cm-1
+Wavelength_unit A
+
+BEGIN_DATA
diff --git a/test/sasdataloader/test/sesans_examples/sphere2micron.ses b/test/sasdataloader/test/sesans_examples/sphere2micron.ses
new file mode 100644
index 0000000..568e252
--- /dev/null
+++ b/test/sasdataloader/test/sesans_examples/sphere2micron.ses
@@ -0,0 +1,60 @@
+FileFormatVersion 1.0
+DataFileTitle Polystyrene of Markus Strobl, Full Sine, ++ only
+Sample Polystyrene 2 um in 53% H2O, 47% D2O
+Settings D1=D2=20x8 mm,Ds = 16x10 mm (WxH), GF1 =scanning, GF2 = 2.5 A. 2 um polystyrene in 53% H2O, 47% D2O; 8.55% contrast
+Operator CPD
+Date do 10 jul 2014 16:37:30
+ScanType sine one element scan
+Thickness 2.00E-01
+Thickness_unit cm
+Theta_zmax 0.0168
+Theta_zmax_unit radians
+Theta_ymax 0.0168
+Theta_ymax_unit radians
+Orientation Z
+SpinEchoLength_unit A
+Depolarisation_unit A-2 cm-1
+Wavelength_unit A
+
+BEGIN_DATA
+SpinEchoLength Depolarisation Depolarisation_error SpinEchoLength_error Wavelength Wavelength_error Polarisation Polarisation_error
+391.56 0.0041929 0.0036894 19.578 2.11 0.1055 1.0037 0.0032974
+1564 -0.0046571 0.0038185 78.2 2.11 0.1055 0.99586 0.003386
+2735.6 -0.017007 0.0038132 136.78 2.11 0.1055 0.98497 0.0033444
+3907.9 -0.033462 0.0035068 195.39 2.11 0.1055 0.97064 0.0030309
+5080.2 -0.047483 0.0038208 254.01 2.11 0.1055 0.9586 0.0032613
+6251.8 -0.070375 0.00376 312.59 2.11 0.1055 0.93926 0.0031446
+7423.2 -0.092217 0.0037927 371.16 2.11 0.1055 0.92117 0.0031108
+8595.5 -0.10238 0.004006 429.77 2.11 0.1055 0.91287 0.0032562
+9767.7 -0.12672 0.0038534 488.39 2.11 0.1055 0.8933 0.0030651
+10940 -0.1374 0.004243 546.98 2.11 0.1055 0.88484 0.003343
+12112 -0.16072 0.0045837 605.58 2.11 0.1055 0.86666 0.0035372
+13284 -0.16623 0.0045613 664.2 2.11 0.1055 0.86242 0.0035027
+14456 -0.18468 0.0044918 722.79 2.11 0.1055 0.84837 0.0033931
+15628 -0.19143 0.0048967 781.38 2.11 0.1055 0.84328 0.0036768
+16800 -0.20029 0.0045421 840.02 2.11 0.1055 0.83666 0.0033837
+17971 -0.19798 0.0046642 898.56 2.11 0.1055 0.83838 0.0034819
+19143 -0.21442 0.0047052 957.17 2.11 0.1055 0.82619 0.0034614
+20316 -0.20885 0.0044931 1015.8 2.11 0.1055 0.8303 0.0033218
+21488 -0.21393 0.0049186 1074.4 2.11 0.1055 0.82655 0.00362
+22660 -0.20685 0.004423 1133 2.11 0.1055 0.83179 0.0032758
+23832 -0.20802 0.0046979 1191.6 2.11 0.1055 0.83092 0.0034758
+25003 -0.19848 0.0045953 1250.2 2.11 0.1055 0.838 0.0034289
+26175 -0.21117 0.0044567 1308.8 2.11 0.1055 0.82859 0.0032881
+27347 -0.21283 0.004137 1367.4 2.11 0.1055 0.82736 0.0030477
+28520 -0.2042 0.0044587 1426 2.11 0.1055 0.83375 0.0033101
+29692 -0.2112 0.0042852 1484.6 2.11 0.1055 0.82857 0.0031615
+30864 -0.20319 0.0043483 1543.2 2.11 0.1055 0.8345 0.003231
+32036 -0.20752 0.0044297 1601.8 2.11 0.1055 0.83129 0.0032788
+33207 -0.20654 0.0043188 1660.4 2.11 0.1055 0.83201 0.0031995
+34380 -0.20126 0.0046375 1719 2.11 0.1055 0.83593 0.0034518
+35551 -0.20924 0.0042871 1777.6 2.11 0.1055 0.83001 0.0031684
+36724 -0.21323 0.0045471 1836.2 2.11 0.1055 0.82707 0.0033487
+37895 -0.21324 0.0045354 1894.7 2.11 0.1055 0.82706 0.00334
+39067 -0.19905 0.0044141 1953.4 2.11 0.1055 0.83758 0.003292
+40239 -0.1991 0.0047441 2012 2.11 0.1055 0.83754 0.003538
+41411 -0.20359 0.0050136 2070.5 2.11 0.1055 0.8342 0.003724
+42583 -0.21032 0.0049474 2129.1 2.11 0.1055 0.82922 0.0036529
+43755 -0.20689 0.0048203 2187.8 2.11 0.1055 0.83176 0.00357
+44927 -0.21075 0.0052337 2246.4 2.11 0.1055 0.8289 0.0038628
+46099 -0.19956 0.0047827 2304.9 2.11 0.1055 0.8372 0.0035653
diff --git a/test/sasdataloader/test/sesans_examples/sphere_isis.ses b/test/sasdataloader/test/sesans_examples/sphere_isis.ses
new file mode 100644
index 0000000..58545a6
--- /dev/null
+++ b/test/sasdataloader/test/sesans_examples/sphere_isis.ses
@@ -0,0 +1,73 @@
+FileFormatVersion 1.0
+DataFileTitle PMMA in Mixed Deuterated decalin
+Sample Ostensibly 40$ 100nm radius PMMA hard spheres in mixed deuterarted decalin.
+Thickness 2
+Thickness_unit mm
+Theta_zmax 0.09
+Theta_zmax_unit radians
+Theta_ymax 0.09
+Theta_ymax_unit radians
+Orientation Z
+SpinEchoLength_unit A
+Depolarisation_unit A-2 cm-1
+Wavelength_unit A
+
+BEGIN_DATA
+SpinEchoLength Depolarisation Depolarisation_error Wavelength
+260.0 -1.42E-3 2.04E-3 1.612452
+280.8 -1.45E-3 1.87E-3 1.675709
+303.264 -1.64E-3 1.23E-3 1.741448
+327.525 -1.69E-3 1.17E-3 1.809765
+353.727 -2.23E-3 9.09E-4 1.880763
+382.025 -2.26E-3 8.58E-4 1.954546
+412.587 -2.41E-3 7.29E-4 2.031224
+445.594 -2.58E-3 6.75E-4 2.11091
+481.242 -2.88E-3 6.04E-4 2.193723
+519.741 -3.35E-3 5.56E-4 2.279783
+561.32 -3.60E-3 5.22E-4 2.369219
+606.226 -3.92E-3 4.91E-4 2.462166
+654.724 -4.36E-3 4.73E-4 2.558758
+707.102 -4.67E-3 4.54E-4 2.659139
+763.67 -4.91E-3 4.22E-4 2.763458
+824.764 -5.32E-3 3.88E-4 2.87187
+890.745 -5.43E-3 3.53E-4 2.984535
+962.005 -5.61E-3 3.28E-4 3.101621
+1038.97 -5.83E-3 3.07E-4 3.223306
+1122.08 -5.88E-3 2.91E-4 3.349746
+1211.85 -5.91E-3 2.73E-4 3.481164
+1308.8 -5.71E-3 2.61E-4 3.617734
+1413.5 -5.40E-3 2.49E-4 3.759654
+1526.58 -5.10E-3 2.41E-4 3.907147
+1648.71 -4.77E-3 2.34E-4 4.060431
+1780.6 -4.34E-3 2.26E-4 4.219716
+1923.05 -4.18E-3 2.20E-4 4.385259
+2076.9 -4.08E-3 2.16E-4 4.557302
+2243.05 -4.37E-3 2.13E-4 4.736085
+2422.49 -4.66E-3 2.10E-4 4.92188
+2616.29 -4.96E-3 2.06E-4 5.114968
+2825.59 -5.04E-3 2.03E-4 5.315628
+3051.64 -4.96E-3 1.99E-4 5.524165
+3295.77 -4.72E-3 1.97E-4 5.74088
+3559.43 -4.52E-3 1.92E-4 5.966096
+3844.19 -4.65E-3 1.93E-4 6.200153
+4151.72 -4.74E-3 1.96E-4 6.443384
+4483.86 -4.87E-3 1.99E-4 6.696163
+4842.57 -4.81E-3 2.05E-4 6.958858
+5229.98 -4.57E-3 2.09E-4 7.23186
+5648.38 -4.72E-3 2.17E-4 7.515571
+6100.25 -4.79E-3 2.23E-4 7.81041
+6588.27 -4.68E-3 2.28E-4 8.116816
+7115.33 -4.61E-3 2.32E-4 8.435242
+7684.55 -4.78E-3 2.46E-4 8.766157
+8299.32 -4.74E-3 2.46E-4 9.11006
+8963.26 -4.56E-3 2.50E-4 9.467449
+9680.32 -4.70E-3 2.58E-4 9.838862
+10454.7 -4.81E-3 2.64E-4 10.224823
+11291.1 -4.65E-3 2.69E-4 10.625959
+12194.4 -4.43E-3 2.79E-4 11.042826
+13170.0 -4.55E-3 3.01E-4 11.476062
+14223.6 -4.35E-3 3.20E-4 11.926274
+15361.5 -4.24E-3 3.51E-4 12.394152
+16590.4 -4.68E-3 4.12E-4 12.880373
+17917.6 -4.96E-3 4.98E-4 13.385664
+19303.4 -4.56E-3 5.98E-4 13.893668
diff --git a/test/sasdataloader/test/sesans_examples/too_many_headers.ses b/test/sasdataloader/test/sesans_examples/too_many_headers.ses
new file mode 100644
index 0000000..0d73944
--- /dev/null
+++ b/test/sasdataloader/test/sesans_examples/too_many_headers.ses
@@ -0,0 +1,73 @@
+FileFormatVersion 1.0
+DataFileTitle PMMA in Mixed Deuterated decalin
+Sample Ostensibly 40$ 100nm radius PMMA hard spheres in mixed deuterarted decalin.
+Thickness 2
+Thickness_unit mm
+Theta_zmax 0.09
+Theta_zmax_unit radians
+Theta_ymax 0.09
+Theta_ymax_unit radians
+Orientation Z
+SpinEchoLength_unit A
+Depolarisation_unit A-2 cm-1
+Wavelength_unit A
+
+BEGIN_DATA
+SpinEchoLength Depolarisation Depolarisation_error Wavelength SpinEchoLength_error
+260.0 -1.42E-3 2.04E-3 1.612452
+280.8 -1.45E-3 1.87E-3 1.675709
+303.264 -1.64E-3 1.23E-3 1.741448
+327.525 -1.69E-3 1.17E-3 1.809765
+353.727 -2.23E-3 9.09E-4 1.880763
+382.025 -2.26E-3 8.58E-4 1.954546
+412.587 -2.41E-3 7.29E-4 2.031224
+445.594 -2.58E-3 6.75E-4 2.11091
+481.242 -2.88E-3 6.04E-4 2.193723
+519.741 -3.35E-3 5.56E-4 2.279783
+561.32 -3.60E-3 5.22E-4 2.369219
+606.226 -3.92E-3 4.91E-4 2.462166
+654.724 -4.36E-3 4.73E-4 2.558758
+707.102 -4.67E-3 4.54E-4 2.659139
+763.67 -4.91E-3 4.22E-4 2.763458
+824.764 -5.32E-3 3.88E-4 2.87187
+890.745 -5.43E-3 3.53E-4 2.984535
+962.005 -5.61E-3 3.28E-4 3.101621
+1038.97 -5.83E-3 3.07E-4 3.223306
+1122.08 -5.88E-3 2.91E-4 3.349746
+1211.85 -5.91E-3 2.73E-4 3.481164
+1308.8 -5.71E-3 2.61E-4 3.617734
+1413.5 -5.40E-3 2.49E-4 3.759654
+1526.58 -5.10E-3 2.41E-4 3.907147
+1648.71 -4.77E-3 2.34E-4 4.060431
+1780.6 -4.34E-3 2.26E-4 4.219716
+1923.05 -4.18E-3 2.20E-4 4.385259
+2076.9 -4.08E-3 2.16E-4 4.557302
+2243.05 -4.37E-3 2.13E-4 4.736085
+2422.49 -4.66E-3 2.10E-4 4.92188
+2616.29 -4.96E-3 2.06E-4 5.114968
+2825.59 -5.04E-3 2.03E-4 5.315628
+3051.64 -4.96E-3 1.99E-4 5.524165
+3295.77 -4.72E-3 1.97E-4 5.74088
+3559.43 -4.52E-3 1.92E-4 5.966096
+3844.19 -4.65E-3 1.93E-4 6.200153
+4151.72 -4.74E-3 1.96E-4 6.443384
+4483.86 -4.87E-3 1.99E-4 6.696163
+4842.57 -4.81E-3 2.05E-4 6.958858
+5229.98 -4.57E-3 2.09E-4 7.23186
+5648.38 -4.72E-3 2.17E-4 7.515571
+6100.25 -4.79E-3 2.23E-4 7.81041
+6588.27 -4.68E-3 2.28E-4 8.116816
+7115.33 -4.61E-3 2.32E-4 8.435242
+7684.55 -4.78E-3 2.46E-4 8.766157
+8299.32 -4.74E-3 2.46E-4 9.11006
+8963.26 -4.56E-3 2.50E-4 9.467449
+9680.32 -4.70E-3 2.58E-4 9.838862
+10454.7 -4.81E-3 2.64E-4 10.224823
+11291.1 -4.65E-3 2.69E-4 10.625959
+12194.4 -4.43E-3 2.79E-4 11.042826
+13170.0 -4.55E-3 3.01E-4 11.476062
+14223.6 -4.35E-3 3.20E-4 11.926274
+15361.5 -4.24E-3 3.51E-4 12.394152
+16590.4 -4.68E-3 4.12E-4 12.880373
+17917.6 -4.96E-3 4.98E-4 13.385664
+19303.4 -4.56E-3 5.98E-4 13.893668
diff --git a/test/sasdataloader/test/testLoad.py b/test/sasdataloader/test/testLoad.py
deleted file mode 100644
index dfa71a9..0000000
--- a/test/sasdataloader/test/testLoad.py
+++ /dev/null
@@ -1,171 +0,0 @@
-"""
- Unit tests for DataLoader module
- log file "test_log.txt" contains all errors when running loader
- It is create in the folder where test is runned
-"""
-import logging
-logging.basicConfig(level=logging.DEBUG,
- format='%(asctime)s %(levelname)s %(message)s',
- filename='test_log.txt',
- filemode='w')
-
-
-
-import unittest
-import math
-import sas.sascalc.dataloader
-from sas.sascalc.dataloader.loader import Loader
-
-# Check whether we should test image loading on this system
-HAS_IMAGE = False
-try:
- import Image
- HAS_IMAGE = True
-except:
- print "IMAGE TESTS WILL NOT BE PERFORMED: MISSING PIL MODULE"
-
-import os.path
-
-class designtest(unittest.TestCase):
-
- def setUp(self):
- self.loader = Loader()
-
- def test_singleton(self):
- """
- Testing whether Loader is truly a singleton
- """
- # Create a 'new' Loader
- b = Loader()
- self.assertEqual(self.loader._get_registry_creation_time(),
- b._get_registry_creation_time())
-
-class testLoader(unittest.TestCase):
- logging.debug("Inside testLoad module")
-
- """ test fitting """
- def setUp(self):
- """
- Set up the initial conditions before _each_ test
- so that they all start from the same well-defined state.
- """
- #Creating a loader
- self.L=Loader()
-
-
- def testLoad0(self):
- """test reading empty file"""
- self.assertRaises(RuntimeError, self.L.load, 'empty.txt')
-
- def testLoad1(self):
- """test reading 2 columns"""
-
- #Testing loading a txt file of 2 columns, the only reader should be read1
- output=self.L.load('test_2_columns.txt')
- x=[2.83954,0.204082,0.408163,0.612245,0.816327,1.02041,1.22449,1.42857,1.63265]
- y=[0.6,3.44938, 5.82026,5.27591,5.2781,5.22531,7.47487,7.85852,10.2278]
- dx=[]
- dy=[]
- self.assertEqual(len(output.x),len(x))
- self.assertEqual(len(output.y),len(y))
-
- for i in range(len(x)):
- self.assertEqual(output.x[i],x[i])
- self.assertEqual(output.y[i],y[i])
-
-
- def testLoad2(self):
- """Testing loading a txt file of 3 columns"""
- output= self.L.load('test_3_columns.txt')
- x=[0,0.204082,0.408163,0.612245,0.816327,1.02041,1.22449]
- y=[2.83954,3.44938,5.82026,5.27591,5.2781,5.22531,7.47487]
- dx=[]
- dy=[0.6,0.676531,0.753061,0.829592,0.906122,0.982653,1.05918]
- self.assertEqual(len(output.x),len(x))
- self.assertEqual(len(output.y),len(y))
- self.assertEqual(len(output.dy),len(dy))
- for i in range(len(x)):
- self.assertEqual(output.x[i],x[i])
- self.assertEqual(output.y[i],y[i])
- self.assertEqual(output.dy[i],dy[i])
-
- def testLoad2_uppercase(self):
- """Testing loading a txt file of 3 columns"""
- output= self.L.load('test_3_columns.TXT')
- x=[0,0.204082,0.408163,0.612245,0.816327,1.02041,1.22449]
- y=[2.83954,3.44938,5.82026,5.27591,5.2781,5.22531,7.47487]
- dx=[]
- dy=[0.6,0.676531,0.753061,0.829592,0.906122,0.982653,1.05918]
- self.assertEqual(len(output.x),len(x))
- self.assertEqual(len(output.y),len(y))
- self.assertEqual(len(output.dy),len(dy))
- for i in range(len(x)):
- self.assertEqual(output.x[i],x[i])
- self.assertEqual(output.y[i],y[i])
- self.assertEqual(output.dy[i],dy[i])
-
-
- def testload3(self):
- """ Testing loading Igor data"""
- #tested good file.asc
- output= self.L.load('MAR07232_rest.ASC')
- self.assertEqual(output.xmin,-0.018558945804750416)
- self.assertEqual(output.xmax, 0.016234058202440633,)
- self.assertEqual(output.ymin,-0.01684257151702391)
- self.assertEqual(output.ymax,0.017950440578015116)
-
- #tested corrupted file.asc
- try:self.L.load('AR07232_rest.ASC')
- except ValueError,msg:
- #logging.log(10,str(msg))
- logging.error(str(msg))
-
- def testload3_lowercase(self):
- """ Testing loading Igor data"""
- #tested good file.asc
- output= self.L.load('MAR07232_rest.asc')
- self.assertEqual(output.xmin,-0.018558945804750416)
- self.assertEqual(output.xmax, 0.016234058202440633,)
- self.assertEqual(output.ymin,-0.01684257151702391)
- self.assertEqual(output.ymax,0.017950440578015116)
-
- #tested corrupted file.asc
- try:self.L.load('AR07232_rest.ASC')
- except ValueError,msg:
- #logging.log(10,str(msg))
- logging.error(str(msg))
- def testload4(self):
- """ Testing loading danse file"""
- #tested good file.sans
- output=self.L.load('MP_New.sans')
-
- self.assertEqual(output.source.wavelength,7.5)
-
- #tested corrupted file.sans
- try: self.L.load('P_New.sans')
- except ValueError,msg:
- #logging.log(40,str(msg))
- logging.error(str(msg))
- #else: raise ValueError,"No error raised for missing extension"
-
- def testload5(self):
- """ Testing loading image file"""
- if HAS_IMAGE:
- output=self.L.load('angles_flat.png')
- self.assertEqual(output.xbins ,200)
-
- def testload6(self):
- """test file with unknown extension"""
- self.assertRaises(RuntimeError, self.L.load, 'hello.missing')
-
- # Lookup is not supported as a public method
- #self.assertRaises(ValueError, self.L.lookup, 'hello.missing')
-
-
- def testload7(self):
- """ test file containing an image but as extension .txt"""
- self.assertRaises(RuntimeError, self.L.load, 'angles_flat.txt')
-
-if __name__ == '__main__':
- unittest.main()
-
\ No newline at end of file
diff --git a/test/sasdataloader/test/testplugings.py b/test/sasdataloader/test/testplugings.py
deleted file mode 100644
index 1008422..0000000
--- a/test/sasdataloader/test/testplugings.py
+++ /dev/null
@@ -1,67 +0,0 @@
-"""
- Unit tests for DataLoader module
-"""
-
-import unittest
-from sas.sascalc.dataloader.loader import Loader, Registry
-class testLoader(unittest.TestCase):
-
- def setUp(self):
- self.L=Loader()
- self.L.find_plugins('../plugins')
-
- def testplugin(self):
- """
- test loading with a test reader only
- found in the plugins directory
- """
- output = self.L.load('test_data.test')
- self.assertEqual(output.x[0], 1234.)
-
-class testRegistry(unittest.TestCase):
-
- def setUp(self):
- self.L=Registry()
- self.L.find_plugins('../plugins')
-
- def testplugin(self):
- """
- test loading with a test reader only
- found in the plugins directory
- """
- output = self.L.load('test_data.test')
- self.assertEqual(output.x[0], 1234.)
- self.assertTrue(self.L.loaders.has_key('.test'))
-
-class testZip(unittest.TestCase):
-
- def setUp(self):
- self.L=Registry()
-
- # Create module
- import zipfile
- z = zipfile.PyZipFile("plugins.zip", 'w')
- z.writepy("../plugins", "")
- z.close()
-
- def testplugin_checksetup(self):
- """
- Check that the test is valid by confirming
- that the file can't be loaded without the
- plugins
- """
- self.assertRaises(ValueError, self.L.load, 'test_data.test')
-
- def testplugin(self):
- """
- test loading with a test reader only
- found in the plugins directory
- """
- self.L.find_plugins('.')
- output = self.L.load('test_data.test')
- self.assertEqual(output.x[0], 1234.)
- self.assertTrue(self.L.loaders.has_key('.test'))
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/test/sasdataloader/test/utest_abs_reader.py b/test/sasdataloader/test/utest_abs_reader.py
index c099cfd..984cf62 100644
--- a/test/sasdataloader/test/utest_abs_reader.py
+++ b/test/sasdataloader/test/utest_abs_reader.py
@@ -1,23 +1,30 @@
"""
Unit tests for data manipulations
"""
+from __future__ import print_function
import unittest
-import numpy, math
-from sas.sascalc.dataloader.loader import Loader
+import numpy as np
+from sas.sascalc.dataloader.loader import Loader
+from sas.sascalc.dataloader.readers.abs_reader import Reader as AbsReader
+from sas.sascalc.dataloader.readers.danse_reader import Reader as DANSEReader
+from sas.sascalc.dataloader.readers.cansas_reader import Reader as CANSASReader
+
from sas.sascalc.dataloader.data_info import Data1D
-
+
import os.path
+
class abs_reader(unittest.TestCase):
-
+
def setUp(self):
- from sas.sascalc.dataloader.readers.abs_reader import Reader
- self.data = Reader().read("jan08002.ABS")
-
+ reader = AbsReader()
+ self.data_list = reader.read("jan08002.ABS")
+ self.data = self.data_list[0]
+
def test_abs_checkdata(self):
"""
- Check the data content to see whether
+ Check the data content to see whether
it matches the specific file we loaded.
Check the units too to see whether the
Data1D defaults changed. Otherwise the
@@ -25,126 +32,76 @@ class abs_reader(unittest.TestCase):
"""
self.assertEqual(self.data.filename, "jan08002.ABS")
self.assertEqual(self.data.meta_data['loader'], "IGOR 1D")
-
+
self.assertEqual(self.data.source.wavelength_unit, 'A')
self.assertEqual(self.data.source.wavelength, 6.0)
-
+
self.assertEqual(self.data.detector[0].distance_unit, 'mm')
self.assertEqual(self.data.detector[0].distance, 1000.0)
-
+
self.assertEqual(self.data.sample.transmission, 0.5667)
-
+
self.assertEqual(self.data.detector[0].beam_center_unit, 'mm')
- center_x = 114.58*5.0
- center_y = 64.22*5.0
+ center_x = 114.58*5.08
+ center_y = 64.22*5.08
self.assertEqual(self.data.detector[0].beam_center.x, center_x)
self.assertEqual(self.data.detector[0].beam_center.y, center_y)
-
- self.assertEqual(self.data.y_unit, '1/cm')
+
+ self.assertEqual(self.data.y_unit, 'cm^{-1}')
self.assertEqual(self.data.x[0], 0.002618)
self.assertEqual(self.data.x[1], 0.007854)
self.assertEqual(self.data.x[2], 0.01309)
self.assertEqual(self.data.x[126], 0.5828)
-
+
self.assertEqual(self.data.y[0], 0.02198)
self.assertEqual(self.data.y[1], 0.02201)
self.assertEqual(self.data.y[2], 0.02695)
self.assertEqual(self.data.y[126], 0.2958)
-
+
self.assertEqual(self.data.dy[0], 0.002704)
self.assertEqual(self.data.dy[1], 0.001643)
self.assertEqual(self.data.dy[2], 0.002452)
self.assertEqual(self.data.dy[126], 1)
-
+
def test_checkdata2(self):
self.assertEqual(self.data.dy[126], 1)
-
-class hfir_reader(unittest.TestCase):
-
- def setUp(self):
- self.data = Loader().load("S2-30dq.d1d")
-
- def test_hfir_checkdata(self):
- """
- Check the data content to see whether
- it matches the specific file we loaded.
- """
- self.assertEqual(self.data.filename, "S2-30dq.d1d")
- # THIS FILE FORMAT IS CURRENTLY READ BY THE ASCII READER
- self.assertEqual(self.data.meta_data['loader'], "HFIR 1D")
- self.assertEqual(len(self.data.x), 134)
- self.assertEqual(len(self.data.y), 134)
- # Q I dI dQ
- # Point 1: 0.003014 0.003010 0.000315 0.008249
- self.assertEqual(self.data.x[1], 0.003014)
- self.assertEqual(self.data.y[1], 0.003010)
- self.assertEqual(self.data.dy[1], 0.000315)
- self.assertEqual(self.data.dx[1], 0.008249)
-
-
-class igor_reader(unittest.TestCase):
-
- def setUp(self):
- self.data = Loader().load("MAR07232_rest.ASC")
-
- def test_igor_checkdata(self):
- """
- Check the data content to see whether
- it matches the specific file we loaded.
- Check the units too to see whether the
- Data1D defaults changed. Otherwise the
- tests won't pass
- """
- self.assertEqual(self.data.filename, "MAR07232_rest.ASC")
- self.assertEqual(self.data.meta_data['loader'], "IGOR 2D")
-
- self.assertEqual(self.data.source.wavelength_unit, 'A')
- self.assertEqual(self.data.source.wavelength, 8.4)
-
- self.assertEqual(self.data.detector[0].distance_unit, 'mm')
- self.assertEqual(self.data.detector[0].distance, 13705)
-
- self.assertEqual(self.data.sample.transmission, 0.84357)
-
- self.assertEqual(self.data.detector[0].beam_center_unit, 'mm')
- center_x = (68.76-1)*5.0
- center_y = (62.47-1)*5.0
- self.assertEqual(self.data.detector[0].beam_center.x, center_x)
- self.assertEqual(self.data.detector[0].beam_center.y, center_y)
-
- self.assertEqual(self.data.I_unit, '1/cm')
- self.assertEqual(self.data.data[0], 0.279783)
- self.assertEqual(self.data.data[1], 0.28951)
- self.assertEqual(self.data.data[2], 0.167634)
-
-class danse_reader(unittest.TestCase):
-
+
+ def test_generic_loader(self):
+ # the generic loader should work as well
+ data = Loader().load("jan08002.ABS")
+ self.assertEqual(data[0].meta_data['loader'], "IGOR 1D")
+
+class DanseReaderTests(unittest.TestCase):
+
def setUp(self):
- self.data = Loader().load("MP_New.sans")
+ reader = DANSEReader()
+ self.data_list = reader.read("MP_New.sans")
+ self.data = self.data_list[0]
def test_checkdata(self):
"""
- Check the data content to see whether
+ Check the data content to see whether
it matches the specific file we loaded.
Check the units too to see whether the
Data1D defaults changed. Otherwise the
tests won't pass
"""
+ self.assertEqual(len(self.data_list), 1)
self.assertEqual(self.data.filename, "MP_New.sans")
self.assertEqual(self.data.meta_data['loader'], "DANSE")
-
+
self.assertEqual(self.data.source.wavelength_unit, 'A')
self.assertEqual(self.data.source.wavelength, 7.5)
-
+
self.assertEqual(self.data.detector[0].distance_unit, 'mm')
self.assertAlmostEqual(self.data.detector[0].distance, 5414.99, 3)
-
+
self.assertEqual(self.data.detector[0].beam_center_unit, 'mm')
center_x = 68.74*5.0
center_y = 64.77*5.0
self.assertEqual(self.data.detector[0].beam_center.x, center_x)
self.assertEqual(self.data.detector[0].beam_center.y, center_y)
-
+
self.assertEqual(self.data.I_unit, '1/cm')
self.assertEqual(self.data.data[0], 1.57831)
self.assertEqual(self.data.data[1], 2.70983)
@@ -154,33 +111,46 @@ class danse_reader(unittest.TestCase):
self.assertEqual(self.data.err_data[1], 1.77569)
self.assertEqual(self.data.err_data[2], 2.06313)
-
+ def test_generic_loader(self):
+ # the generic loader should work as well
+ data = Loader().load("MP_New.sans")
+ self.assertEqual(len(data), 1)
+ self.assertEqual(data[0].meta_data['loader'], "DANSE")
+
+
class cansas_reader(unittest.TestCase):
-
+
def setUp(self):
+ reader = CANSASReader()
+ self.data_list = reader.read("cansas1d.xml")
+ self.data = self.data_list[0]
+
+ def test_generic_loader(self):
+ # the generic loader should work as well
data = Loader().load("cansas1d.xml")
- self.data = data[0]
-
+ self.assertEqual(len(data), 1)
+ self.assertEqual(data[0].meta_data['loader'], "CanSAS XML 1D")
+
def test_cansas_checkdata(self):
self.assertEqual(self.data.filename, "cansas1d.xml")
self._checkdata()
-
+
def _checkdata(self):
"""
- Check the data content to see whether
+ Check the data content to see whether
it matches the specific file we loaded.
Check the units too to see whether the
Data1D defaults changed. Otherwise the
tests won't pass
"""
-
+ self.assertEqual(len(self.data_list), 1)
self.assertEqual(self.data.run[0], "1234")
self.assertEqual(self.data.meta_data['loader'], "CanSAS XML 1D")
-
+
# Data
self.assertEqual(len(self.data.x), 2)
- self.assertEqual(self.data.x_unit, '1/A')
- self.assertEqual(self.data.y_unit, '1/cm')
+ self.assertEqual(self.data.x_unit, 'A^{-1}')
+ self.assertEqual(self.data.y_unit, 'cm^{-1}')
self.assertAlmostEqual(self.data.x[0], 0.02, 6)
self.assertAlmostEqual(self.data.y[0], 1000, 6)
self.assertAlmostEqual(self.data.dx[0], 0.01, 6)
@@ -191,15 +161,15 @@ class cansas_reader(unittest.TestCase):
self.assertAlmostEqual(self.data.dy[1], 4, 6)
self.assertEqual(self.data.run_name['1234'], 'run name')
self.assertEqual(self.data.title, "Test title")
-
+
# Sample info
self.assertEqual(self.data.sample.ID, "SI600-new-long")
self.assertEqual(self.data.sample.name, "my sample")
self.assertEqual(self.data.sample.thickness_unit, 'mm')
self.assertAlmostEqual(self.data.sample.thickness, 1.03)
-
+
self.assertAlmostEqual(self.data.sample.transmission, 0.327)
-
+
self.assertEqual(self.data.sample.temperature_unit, 'C')
self.assertEqual(self.data.sample.temperature, 0)
@@ -211,80 +181,81 @@ class cansas_reader(unittest.TestCase):
self.assertAlmostEqual(self.data.sample.orientation.x, 22.5, 6)
self.assertAlmostEqual(self.data.sample.orientation.y, 0.02, 6)
- self.assertEqual(self.data.sample.details[0], "http://chemtools.chem.soton.ac.uk/projects/blog/blogs.php/bit_id/2720")
- self.assertEqual(self.data.sample.details[1], "Some text here")
-
+ self.assertEqual(self.data.sample.details[0], "http://chemtools.chem.soton.ac.uk/projects/blog/blogs.php/bit_id/2720")
+ self.assertEqual(self.data.sample.details[1], "Some text here")
+
# Instrument info
self.assertEqual(self.data.instrument, "canSAS instrument")
-
+
# Source
self.assertEqual(self.data.source.radiation, "neutron")
-
+
self.assertEqual(self.data.source.beam_size_unit, "mm")
self.assertEqual(self.data.source.beam_size_name, "bm")
self.assertEqual(self.data.source.beam_size.x, 12)
self.assertEqual(self.data.source.beam_size.y, 13)
-
+
self.assertEqual(self.data.source.beam_shape, "disc")
-
+
self.assertEqual(self.data.source.wavelength_unit, "A")
self.assertEqual(self.data.source.wavelength, 6)
-
+
self.assertEqual(self.data.source.wavelength_max_unit, "nm")
self.assertAlmostEqual(self.data.source.wavelength_max, 1.0)
self.assertEqual(self.data.source.wavelength_min_unit, "nm")
self.assertAlmostEqual(self.data.source.wavelength_min, 0.22)
self.assertEqual(self.data.source.wavelength_spread_unit, "percent")
self.assertEqual(self.data.source.wavelength_spread, 14.3)
-
+
# Collimation
_found1 = False
_found2 = False
self.assertEqual(self.data.collimation[0].length, 123.)
self.assertEqual(self.data.collimation[0].name, 'test coll name')
-
+
for item in self.data.collimation[0].aperture:
self.assertEqual(item.size_unit,'mm')
self.assertEqual(item.distance_unit,'mm')
- if item.size.x==50 \
- and item.distance==11000.0 \
- and item.name=='source' \
- and item.type=='radius':
+ if item.size.x == 50 \
+ and item.distance == 11000.0 \
+ and item.name == 'source' \
+ and item.type == 'radius':
_found1 = True
- elif item.size.x==1.0 \
- and item.name=='sample' \
- and item.type=='radius':
+ elif item.size.x == 1.0 \
+ and item.name == 'sample' \
+ and item.type == 'radius':
_found2 = True
-
- if _found1==False or _found2==False:
- raise RuntimeError, "Could not find all data %s %s" % (_found1, _found2)
-
+
+ if not _found1 or not _found2:
+ raise RuntimeError("Could not find all data %s %s"
+ % (_found1, _found2))
+
# Detector
self.assertEqual(self.data.detector[0].name, "fictional hybrid")
self.assertEqual(self.data.detector[0].distance_unit, "mm")
self.assertEqual(self.data.detector[0].distance, 4150)
-
+
self.assertEqual(self.data.detector[0].orientation_unit, "degree")
self.assertAlmostEqual(self.data.detector[0].orientation.x, 1.0, 6)
self.assertEqual(self.data.detector[0].orientation.y, 0.0)
self.assertEqual(self.data.detector[0].orientation.z, 0.0)
-
+
self.assertEqual(self.data.detector[0].offset_unit, "m")
self.assertEqual(self.data.detector[0].offset.x, .001)
self.assertEqual(self.data.detector[0].offset.y, .002)
self.assertEqual(self.data.detector[0].offset.z, None)
-
+
self.assertEqual(self.data.detector[0].beam_center_unit, "mm")
self.assertEqual(self.data.detector[0].beam_center.x, 322.64)
self.assertEqual(self.data.detector[0].beam_center.y, 327.68)
self.assertEqual(self.data.detector[0].beam_center.z, None)
-
+
self.assertEqual(self.data.detector[0].pixel_size_unit, "mm")
self.assertEqual(self.data.detector[0].pixel_size.x, 5)
self.assertEqual(self.data.detector[0].pixel_size.y, 5)
self.assertEqual(self.data.detector[0].pixel_size.z, None)
-
+
# Process
_found_term1 = False
_found_term2 = False
@@ -292,81 +263,79 @@ class cansas_reader(unittest.TestCase):
self.assertTrue(item.name in ['NCNR-IGOR', 'spol'])
self.assertTrue(item.date in ['04-Sep-2007 18:35:02',
'03-SEP-2006 11:42:47'])
- print item.term
for t in item.term:
- if t['name']=="ABS:DSTAND" \
- and t['unit']=='mm' \
- and float(t['value'])==1.0:
+ if (t['name'] == "ABS:DSTAND"
+ and t['unit'] == 'mm'
+ and float(t['value']) == 1.0):
_found_term2 = True
- elif t['name']=="radialstep" \
- and t['unit']=='mm' \
- and float(t['value'])==10.0:
+ elif (t['name'] == "radialstep"
+ and t['unit'] == 'mm'
+ and float(t['value']) == 10.0):
_found_term1 = True
-
- if _found_term1==False or _found_term2==False:
- raise RuntimeError, "Could not find all process terms %s %s" % (_found_term1, _found_term2)
-
-
-
-
+
+ if not _found_term1 or not _found_term2:
+ raise RuntimeError("Could not find all process terms %s %s"
+ % (_found_term1, _found_term2))
+
def test_writer(self):
- from sas.sascalc.dataloader.readers.cansas_reader import Reader
- r = Reader()
- x = numpy.ones(5)
- y = numpy.ones(5)
- dy = numpy.ones(5)
-
+ r = CANSASReader()
+
filename = "write_test.xml"
r.write(filename, self.data)
data = Loader().load(filename)
self.data = data[0]
+ self.assertEqual(len(data), 1)
self.assertEqual(self.data.filename, filename)
self._checkdata()
-
+ if os.path.isfile(filename):
+ os.remove(filename)
+
def test_units(self):
"""
Check units.
Note that not all units are available.
"""
filename = "cansas1d_units.xml"
- data = Loader().load(filename)
+ data = CANSASReader().read(filename)
self.data = data[0]
+ self.assertEqual(len(data), 1)
self.assertEqual(self.data.filename, filename)
self._checkdata()
-
+
def test_badunits(self):
"""
Check units.
Note that not all units are available.
"""
filename = "cansas1d_badunits.xml"
- data = Loader().load(filename)
+ data = CANSASReader().read(filename)
self.data = data[0]
+ self.assertEqual(len(data), 1)
self.assertEqual(self.data.filename, filename)
# The followed should not have been loaded
self.assertAlmostEqual(self.data.sample.thickness, 0.00103)
# This one should
self.assertAlmostEqual(self.data.sample.transmission, 0.327)
-
+
self.assertEqual(self.data.meta_data['loader'], "CanSAS XML 1D")
- print self.data.errors
- self.assertEqual(len(self.data.errors), 1)
-
-
+ self.assertEqual(len(self.data.errors), 0)
+
def test_slits(self):
"""
Check slit data
"""
filename = "cansas1d_slit.xml"
- data = Loader().load(filename)
+ data = CANSASReader().read(filename)
self.data = data[0]
+ self.assertEqual(len(data), 1)
+ self.assertEqual(len(self.data_list), 1)
self.assertEqual(self.data.filename, filename)
self.assertEqual(self.data.run[0], "1234")
-
+
# Data
self.assertEqual(len(self.data.x), 2)
- self.assertEqual(self.data.x_unit, '1/A')
- self.assertEqual(self.data.y_unit, '1/cm')
+ self.assertEqual(self.data.x_unit, 'A^{-1}')
+ self.assertEqual(self.data.y_unit, 'cm^{-1}')
self.assertEqual(self.data.x[0], 0.02)
self.assertEqual(self.data.y[0], 1000)
self.assertEqual(self.data.dxl[0], 0.005)
@@ -374,14 +343,12 @@ class cansas_reader(unittest.TestCase):
self.assertEqual(self.data.dy[0], 3)
self.assertEqual(self.data.x[1], 0.03)
self.assertAlmostEquals(self.data.y[1], 1001.0)
- self.assertEqual(self.data.dx, None)
self.assertEqual(self.data.dxl[1], 0.005)
self.assertEqual(self.data.dxw[1], 0.001)
self.assertEqual(self.data.dy[1], 4)
self.assertEqual(self.data.run_name['1234'], 'run name')
self.assertEqual(self.data.title, "Test title")
-
-
+
if __name__ == '__main__':
unittest.main()
diff --git a/test/sasdataloader/test/utest_ascii.py b/test/sasdataloader/test/utest_ascii.py
index f61c02f..6f3abd8 100644
--- a/test/sasdataloader/test/utest_ascii.py
+++ b/test/sasdataloader/test/utest_ascii.py
@@ -1,103 +1,108 @@
-"""
- Unit tests for the ascii (n-column) reader
-"""
-import warnings
-warnings.simplefilter("ignore")
-
-import unittest
-from sas.sascalc.dataloader.loader import Loader
-
-import os.path
-
-class abs_reader(unittest.TestCase):
-
- def setUp(self):
- self.loader = Loader()
-
- def test_checkdata(self):
- """
- Test .ABS file loaded as ascii
- """
- f = self.loader.load("ascii_test_1.txt")
- # The length of the data is 10
- self.assertEqual(len(f.x), 10)
- self.assertEqual(f.x[0],0.002618)
- self.assertEqual(f.x[9],0.0497)
- self.assertEqual(f.x_unit, '1/A')
- self.assertEqual(f.y_unit, '1/cm')
-
- self.assertEqual(f.meta_data['loader'],"ASCII")
-
- def test_truncated_1(self):
- """
- Test an ascii file with header and a
- comment line in the middle of the data section.
- The business rule says that we should stop
- reading at the first comment once the data
- section has started (and treat the comment
- as though it were the start of a footer).
- """
- # Test .ABS file loaded as ascii
- f = self.loader.load("ascii_test_2.txt")
- # The length of the data is 10
- self.assertEqual(len(f.x), 5)
- self.assertEqual(f.x[0],0.002618)
- self.assertEqual(f.x[4],0.02356)
-
- def test_truncated_2(self):
- """
- Test a 6-col ascii file with header and a
- line with only 2 columns in the middle of the data section.
- The business rule says that we should stop
- reading at the first inconsitent line.
- """
- # Test .ABS file loaded as ascii
- f = self.loader.load("ascii_test_3.txt")
- # The length of the data is 5
- self.assertEqual(len(f.x), 5)
- self.assertEqual(f.x[0],0.002618)
- self.assertEqual(f.x[4],0.02356)
-
- def test_truncated_3(self):
- """
- Test a 6-col ascii file with complex header and
- many lines with 2 or 2 columns in the middle of the data section.
- The business rule says that we should stop
- reading at the last line of header.
- """
- # Test .ABS file loaded as ascii
- f = self.loader.load("ascii_test_4.abs")
- # The length of the data is 5
- self.assertEqual(len(f.x), 5)
- self.assertEqual(f.x[0],0.012654)
- self.assertEqual(f.x[4],0.02654)
-
- def test_truncated_4(self):
- """
- Test mix of 6-col and 2-col.
- Only the last 5 2-col lines should be read.
- """
- # Test .ABS file loaded as ascii
- f = self.loader.load("ascii_test_5.txt")
- # The length of the data is 5
- self.assertEqual(len(f.x), 5)
- self.assertEqual(f.x[0],0.02879)
- self.assertEqual(f.x[4],0.0497)
-
- def test_truncated_5(self):
- """
- Test a 6-col ascii file with complex header where one of them has a letter and
- many lines with 2 or 2 columns in the middle of the data section.
- Only last four lines should be read.
- """
- # Test .ABS file loaded as ascii
- f = None
- try:
- f = self.loader.load("ascii_test_6.txt")
- # The length of the data is 5
- except:
- self.assertEqual(f, None)
-
-if __name__ == '__main__':
- unittest.main()
-
+"""
+ Unit tests for the ascii (n-column) reader
+"""
+import warnings
+warnings.simplefilter("ignore")
+
+import unittest
+from sas.sascalc.dataloader.loader import Loader
+
+
+class ABSReaderTests(unittest.TestCase):
+
+ def setUp(self):
+ self.loader = Loader()
+ self.f1_list = self.loader.load("ascii_test_1.txt")
+ self.f1 = self.f1_list[0]
+ self.f2_list = self.loader.load("ascii_test_2.txt")
+ self.f2 = self.f2_list[0]
+ self.f3_list = self.loader.load("ascii_test_3.txt")
+ self.f3 = self.f3_list[0]
+ self.f4_list = self.loader.load("ascii_test_4.abs")
+ self.f4 = self.f4_list[0]
+ self.f5_list = self.loader.load("ascii_test_5.txt")
+ self.f5 = self.f5_list[0]
+
+ def test_checkdata(self):
+ """
+ Test .ABS file loaded as ascii
+ """
+ # The length of the data is 10
+ self.assertEqual(len(self.f1_list), 1)
+ self.assertEqual(len(self.f2_list), 1)
+ self.assertEqual(len(self.f3_list), 1)
+ self.assertEqual(len(self.f4_list), 1)
+ self.assertEqual(len(self.f5_list), 1)
+ self.assertEqual(len(self.f1.x), 10)
+ self.assertEqual(self.f1.x[0],0.002618)
+ self.assertEqual(self.f1.x[9],0.0497)
+ self.assertTrue(self.f1.x_unit == 'A^{-1}')
+ self.assertTrue(self.f1.y_unit == 'cm^{-1}')
+
+ self.assertEqual(self.f1.meta_data['loader'],"ASCII")
+
+ def test_truncated_1(self):
+ """
+ Test an ascii file with header and a
+ comment line in the middle of the data section.
+ The business rule says that we should stop
+ reading at the first comment once the data
+ section has started (and treat the comment
+ as though it were the start of a footer).
+ """
+ # The length of the data is 5
+ self.assertEqual(len(self.f2.x), 5)
+ self.assertEqual(self.f2.x[0],0.002618)
+ self.assertEqual(self.f2.x[4],0.02356)
+
+ def test_truncated_2(self):
+ """
+ Test a 6-col ascii file with header and a
+ line with only 2 columns in the middle of the data section.
+ The business rule says that we should stop
+ reading at the first inconsitent line.
+ """
+ # The length of the data is 5
+ self.assertEqual(len(self.f3.x), 5)
+ self.assertEqual(self.f3.x[0],0.002618)
+ self.assertEqual(self.f3.x[4],0.02356)
+
+ def test_truncated_3(self):
+ """
+ Test a 6-col ascii file with complex header and
+ many lines with 2 or 2 columns in the middle of the data section.
+ The business rule says that we should stop
+ reading at the last line of header.
+ """
+ # The length of the data is 5
+ self.assertEqual(len(self.f4.x), 5)
+ self.assertEqual(self.f4.x[0],0.012654)
+ self.assertEqual(self.f4.x[4],0.02654)
+
+ def test_truncated_4(self):
+ """
+ Test mix of 6-col and 2-col.
+ Only the last 5 2-col lines should be read.
+ """
+ # The length of the data is 5
+ self.assertEqual(len(self.f5.x), 5)
+ self.assertEqual(self.f5.x[0],0.02879)
+ self.assertEqual(self.f5.x[4],0.0497)
+
+ def test_truncated_5(self):
+ """
+ Test a 6-col ascii file with complex header where one of them has a
+ letter and many lines with 2 or 2 columns in the middle of the data
+ section. Will be rejected because fewer than 5 lines.
+ """
+ # Test .ABS file loaded as ascii
+ f = None
+ try:
+ f = self.loader.load("ascii_test_6.txt")
+ # The length of the data is 5
+ except:
+ self.assertEqual(f, None)
+
+if __name__ == '__main__':
+ unittest.main()
+
diff --git a/test/sasdataloader/test/utest_averaging.py b/test/sasdataloader/test/utest_averaging.py
index 76cf495..3a62bf4 100644
--- a/test/sasdataloader/test/utest_averaging.py
+++ b/test/sasdataloader/test/utest_averaging.py
@@ -1,88 +1,94 @@
+import math
+import os
import unittest
+from scipy.stats import binned_statistic_2d
+import numpy as np
-from sas.sascalc.dataloader.loader import Loader
-from sas.sascalc.dataloader.manipulations import Ring, CircularAverage, SectorPhi, get_q,reader2D_converter
-
-import os.path
-import numpy, math
import sas.sascalc.dataloader.data_info as data_info
+from sas.sascalc.dataloader.loader import Loader
+from sas.sascalc.dataloader.manipulations import (Boxavg, Boxsum,
+ CircularAverage, Ring,
+ SectorPhi, SectorQ, SlabX,
+ SlabY, get_q,
+ reader2D_converter)
+
class Averaging(unittest.TestCase):
"""
Test averaging manipulations on a flat distribution
"""
+
def setUp(self):
"""
Create a flat 2D distribution. All averaging results
should return the predefined height of the distribution (1.0).
"""
- x_0 = numpy.ones([100,100])
- dx_0 = numpy.ones([100,100])
-
+ x_0 = np.ones([100, 100])
+ dx_0 = np.ones([100, 100])
+
self.data = data_info.Data2D(data=x_0, err_data=dx_0)
detector = data_info.Detector()
- detector.distance = 1000.0 #mm
- detector.pixel_size.x = 1.0 #mm
- detector.pixel_size.y = 1.0 #mm
-
+ detector.distance = 1000.0 # mm
+ detector.pixel_size.x = 1.0 # mm
+ detector.pixel_size.y = 1.0 # mm
+
# center in pixel position = (len(x_0)-1)/2
- detector.beam_center.x = (len(x_0)-1)/2 #pixel number
- detector.beam_center.y = (len(x_0)-1)/2 #pixel number
+ detector.beam_center.x = (len(x_0) - 1) / 2 # pixel number
+ detector.beam_center.y = (len(x_0) - 1) / 2 # pixel number
self.data.detector.append(detector)
-
+
source = data_info.Source()
- source.wavelength = 10.0 #A
+ source.wavelength = 10.0 # A
self.data.source = source
-
- # get_q(dx, dy, det_dist, wavelength) where units are mm,mm,mm,and A respectively.
- self.qmin = get_q(1.0, 1.0, detector.distance, source.wavelength)
+ # get_q(dx, dy, det_dist, wavelength) where units are mm,mm,mm,and A
+ # respectively.
+ self.qmin = get_q(1.0, 1.0, detector.distance, source.wavelength)
self.qmax = get_q(49.5, 49.5, detector.distance, source.wavelength)
-
+
self.qstep = len(x_0)
- x= numpy.linspace(start= -1*self.qmax,
- stop= self.qmax,
- num= self.qstep,
- endpoint=True )
- y = numpy.linspace(start= -1*self.qmax,
- stop= self.qmax,
- num= self.qstep,
- endpoint=True )
- self.data.x_bins=x
- self.data.y_bins=y
+ x = np.linspace(start=-1 * self.qmax,
+ stop=self.qmax,
+ num=self.qstep,
+ endpoint=True)
+ y = np.linspace(start=-1 * self.qmax,
+ stop=self.qmax,
+ num=self.qstep,
+ endpoint=True)
+ self.data.x_bins = x
+ self.data.y_bins = y
self.data = reader2D_converter(self.data)
-
+
def test_ring_flat_distribution(self):
"""
Test ring averaging
"""
- r = Ring(r_min=2*self.qmin, r_max=5*self.qmin,
- center_x=self.data.detector[0].beam_center.x,
+ r = Ring(r_min=2 * self.qmin, r_max=5 * self.qmin,
+ center_x=self.data.detector[0].beam_center.x,
center_y=self.data.detector[0].beam_center.y)
r.nbins_phi = 20
-
+
o = r(self.data)
for i in range(20):
self.assertEqual(o.y[i], 1.0)
-
+
def test_sectorphi_full(self):
"""
Test sector averaging
"""
- r = SectorPhi(r_min=self.qmin, r_max=3*self.qmin,
- phi_min=0, phi_max=math.pi*2.0)
+ r = SectorPhi(r_min=self.qmin, r_max=3 * self.qmin,
+ phi_min=0, phi_max=math.pi * 2.0)
r.nbins_phi = 20
o = r(self.data)
for i in range(7):
self.assertEqual(o.y[i], 1.0)
-
-
+
def test_sectorphi_partial(self):
"""
"""
phi_max = math.pi * 1.5
- r = SectorPhi(r_min=self.qmin, r_max=3*self.qmin,
+ r = SectorPhi(r_min=self.qmin, r_max=3 * self.qmin,
phi_min=0, phi_max=phi_max)
self.assertEqual(r.phi_max, phi_max)
r.nbins_phi = 20
@@ -90,115 +96,124 @@ class Averaging(unittest.TestCase):
self.assertEqual(r.phi_max, phi_max)
for i in range(17):
self.assertEqual(o.y[i], 1.0)
-
-
-class data_info_tests(unittest.TestCase):
-
+
+class DataInfoTests(unittest.TestCase):
+
def setUp(self):
- self.data = Loader().load('MAR07232_rest.ASC')
-
+ filepath = os.path.join(os.path.dirname(
+ os.path.realpath(__file__)), 'MAR07232_rest.h5')
+ self.data_list = Loader().load(filepath)
+ self.data = self.data_list[0]
+
def test_ring(self):
"""
Test ring averaging
"""
- r = Ring(r_min=.005, r_max=.01,
- center_x=self.data.detector[0].beam_center.x,
+ r = Ring(r_min=.005, r_max=.01,
+ center_x=self.data.detector[0].beam_center.x,
center_y=self.data.detector[0].beam_center.y,
- nbins = 20)
+ nbins=20)
##r.nbins_phi = 20
-
+
o = r(self.data)
- answer = Loader().load('ring_testdata.txt')
-
+ filepath = os.path.join(os.path.dirname(
+ os.path.realpath(__file__)), 'ring_testdata.txt')
+ answer_list = Loader().load(filepath)
+ answer = answer_list[0]
+
+ self.assertEqual(len(answer_list), 1)
for i in range(r.nbins_phi - 1):
self.assertAlmostEqual(o.x[i + 1], answer.x[i], 4)
self.assertAlmostEqual(o.y[i + 1], answer.y[i], 4)
self.assertAlmostEqual(o.dy[i + 1], answer.dy[i], 4)
-
+
def test_circularavg(self):
"""
- Test circular averaging
- The test data was not generated by IGOR.
+ Test circular averaging
+ The test data was not generated by IGOR.
"""
- r = CircularAverage(r_min=.00, r_max=.025,
- bin_width=0.0003)
+ r = CircularAverage(r_min=.00, r_max=.025,
+ bin_width=0.0003)
r.nbins_phi = 20
-
+
o = r(self.data)
- answer = Loader().load('avg_testdata.txt')
+ filepath = os.path.join(os.path.dirname(
+ os.path.realpath(__file__)), 'avg_testdata.txt')
+ answer = Loader().load(filepath)[0]
for i in range(r.nbins_phi):
self.assertAlmostEqual(o.x[i], answer.x[i], 4)
self.assertAlmostEqual(o.y[i], answer.y[i], 4)
self.assertAlmostEqual(o.dy[i], answer.dy[i], 4)
-
+
def test_box(self):
"""
Test circular averaging
The test data was not generated by IGOR.
"""
- from sas.sascalc.dataloader.manipulations import Boxsum, Boxavg
-
+
r = Boxsum(x_min=.01, x_max=.015, y_min=0.01, y_max=0.015)
s, ds, npoints = r(self.data)
self.assertAlmostEqual(s, 34.278990899999997, 4)
self.assertAlmostEqual(ds, 7.8007981835194293, 4)
- self.assertAlmostEqual(npoints, 324.0000, 4)
-
+ self.assertAlmostEqual(npoints, 324.0000, 4)
+
r = Boxavg(x_min=.01, x_max=.015, y_min=0.01, y_max=0.015)
s, ds = r(self.data)
self.assertAlmostEqual(s, 0.10579935462962962, 4)
self.assertAlmostEqual(ds, 0.024076537603455028, 4)
-
+
def test_slabX(self):
"""
Test slab in X
The test data was not generated by IGOR.
"""
- from sas.sascalc.dataloader.manipulations import SlabX
-
- r = SlabX(x_min=-.01, x_max=.01, y_min=-0.0002, y_max=0.0002, bin_width=0.0004)
+
+ r = SlabX(x_min=-.01, x_max=.01, y_min=-0.0002,
+ y_max=0.0002, bin_width=0.0004)
r.fold = False
o = r(self.data)
- answer = Loader().load('slabx_testdata.txt')
+ filepath = os.path.join(os.path.dirname(
+ os.path.realpath(__file__)), 'slabx_testdata.txt')
+ answer = Loader().load(filepath)[0]
for i in range(len(o.x)):
self.assertAlmostEqual(o.x[i], answer.x[i], 4)
self.assertAlmostEqual(o.y[i], answer.y[i], 4)
self.assertAlmostEqual(o.dy[i], answer.dy[i], 4)
-
+
def test_slabY(self):
"""
Test slab in Y
The test data was not generated by IGOR.
"""
- from sas.sascalc.dataloader.manipulations import SlabY
-
- r = SlabY(x_min=.005, x_max=.01, y_min=-0.01, y_max=0.01, bin_width=0.0004)
+
+ r = SlabY(x_min=.005, x_max=.01, y_min=-
+ 0.01, y_max=0.01, bin_width=0.0004)
r.fold = False
o = r(self.data)
- answer = Loader().load('slaby_testdata.txt')
+ filepath = os.path.join(os.path.dirname(
+ os.path.realpath(__file__)), 'slaby_testdata.txt')
+ answer = Loader().load(filepath)[0]
for i in range(len(o.x)):
self.assertAlmostEqual(o.x[i], answer.x[i], 4)
self.assertAlmostEqual(o.y[i], answer.y[i], 4)
self.assertAlmostEqual(o.dy[i], answer.dy[i], 4)
-
+
def test_sectorphi_full(self):
"""
Test sector averaging I(phi)
- When considering the whole azimuthal range (2pi),
+ When considering the whole azimuthal range (2pi),
the answer should be the same as ring averaging.
The test data was not generated by IGOR.
"""
- from sas.sascalc.dataloader.manipulations import SectorPhi
- import math
-
+
nbins = 19
phi_min = math.pi / (nbins + 1)
phi_max = math.pi * 2 - phi_min
-
+
r = SectorPhi(r_min=.005,
r_max=.01,
phi_min=phi_min,
@@ -206,48 +221,81 @@ class data_info_tests(unittest.TestCase):
nbins=nbins)
o = r(self.data)
- answer = Loader().load('ring_testdata.txt')
+ filepath = os.path.join(os.path.dirname(
+ os.path.realpath(__file__)), 'ring_testdata.txt')
+ answer = Loader().load(filepath)[0]
for i in range(len(o.x)):
self.assertAlmostEqual(o.x[i], answer.x[i], 4)
self.assertAlmostEqual(o.y[i], answer.y[i], 4)
self.assertAlmostEqual(o.dy[i], answer.dy[i], 4)
-
+
def test_sectorphi_quarter(self):
"""
Test sector averaging I(phi)
The test data was not generated by IGOR.
"""
- from sas.sascalc.dataloader.manipulations import SectorPhi
- import math
-
- r = SectorPhi(r_min=.005, r_max=.01, phi_min=0, phi_max=math.pi/2.0)
+
+ r = SectorPhi(r_min=.005, r_max=.01, phi_min=0, phi_max=math.pi / 2.0)
r.nbins_phi = 20
o = r(self.data)
- answer = Loader().load('sectorphi_testdata.txt')
+ filepath = os.path.join(os.path.dirname(
+ os.path.realpath(__file__)), 'sectorphi_testdata.txt')
+ answer = Loader().load(filepath)[0]
for i in range(len(o.x)):
self.assertAlmostEqual(o.x[i], answer.x[i], 4)
self.assertAlmostEqual(o.y[i], answer.y[i], 4)
self.assertAlmostEqual(o.dy[i], answer.dy[i], 4)
-
+
def test_sectorq_full(self):
"""
Test sector averaging I(q)
The test data was not generated by IGOR.
"""
- from sas.sascalc.dataloader.manipulations import SectorQ
- import math
-
- r = SectorQ(r_min=.005, r_max=.01, phi_min=0, phi_max=math.pi/2.0)
+
+ r = SectorQ(r_min=.005, r_max=.01, phi_min=0, phi_max=math.pi / 2.0)
r.nbins_phi = 20
o = r(self.data)
- answer = Loader().load('sectorq_testdata.txt')
+ filepath = os.path.join(os.path.dirname(
+ os.path.realpath(__file__)), 'sectorq_testdata.txt')
+ answer = Loader().load(filepath)[0]
for i in range(len(o.x)):
self.assertAlmostEqual(o.x[i], answer.x[i], 4)
self.assertAlmostEqual(o.y[i], answer.y[i], 4)
self.assertAlmostEqual(o.dy[i], answer.dy[i], 4)
-
+
+ def test_sectorq_log(self):
+ """
+ Test sector averaging I(q)
+ The test data was not generated by IGOR.
+ """
+
+ r = SectorQ(r_min=.005, r_max=.01, phi_min=0, phi_max=math.pi / 2.0, base=10)
+ r.nbins_phi = 20
+ o = r(self.data)
+
+ expected_binning = np.logspace(np.log10(0.005), np.log10(0.01), 20, base=10)
+ for i in range(len(o.x)):
+ self.assertAlmostEqual(o.x[i], expected_binning[i], 3)
+
+ # TODO: Test for Y values (o.y)
+ # print len(self.data.x_bins)
+ # print len(self.data.y_bins)
+ # print self.data.q_data.shape
+ # data_to_bin = np.array(self.data.q_data)
+ # data_to_bin = data_to_bin.reshape(len(self.data.x_bins), len(self.data.y_bins))
+ # H, xedges, yedges, binnumber = binned_statistic_2d(self.data.x_bins, self.data.y_bins, data_to_bin,
+ # bins=[[0, math.pi / 2.0], expected_binning], statistic='mean')
+ # xedges_width = (xedges[1] - xedges[0])
+ # xedges_center = xedges[1:] - xedges_width / 2
+
+ # yedges_width = (yedges[1] - yedges[0])
+ # yedges_center = yedges[1:] - yedges_width / 2
+
+ # print H.flatten().shape
+ # print o.y.shape
+
if __name__ == '__main__':
unittest.main()
diff --git a/test/sasdataloader/test/utest_cansas.py b/test/sasdataloader/test/utest_cansas.py
index b57c591..0dacb2c 100644
--- a/test/sasdataloader/test/utest_cansas.py
+++ b/test/sasdataloader/test/utest_cansas.py
@@ -1,323 +1,312 @@
-"""
- Unit tests for the new recursive cansas reader
-"""
-import sas.sascalc.dataloader.readers.cansas_reader as cansas
-from sas.sascalc.dataloader.loader import Loader
-from sas.sascalc.dataloader.data_info import Data1D, Data2D
-from sas.sascalc.dataloader.readers.xml_reader import XMLreader
-from sas.sascalc.dataloader.readers.cansas_reader import Reader
-from sas.sascalc.dataloader.readers.cansas_constants import CansasConstants
-
-import os
-import sys
-import urllib2
-import StringIO
-import pylint as pylint
-import unittest
-import numpy
-import logging
-import warnings
-
-from lxml import etree
-from xml.dom import minidom
-
-warnings.simplefilter("ignore")
-
-CANSAS_FORMAT = CansasConstants.CANSAS_FORMAT
-CANSAS_NS = CansasConstants.CANSAS_NS
-
-class cansas_reader_xml(unittest.TestCase):
-
- def setUp(self):
- self.loader = Loader()
- self.xml_valid = "cansas_test_modified.xml"
- self.xml_invalid = "cansas_test.xml"
- self.cansas1d_badunits = "cansas1d_badunits.xml"
- self.cansas1d = "cansas1d.xml"
- self.cansas1d_slit = "cansas1d_slit.xml"
- self.cansas1d_units = "cansas1d_units.xml"
- self.cansas1d_notitle = "cansas1d_notitle.xml"
- self.isis_1_0 = "ISIS_1_0.xml"
- self.isis_1_1 = "ISIS_1_1.xml"
- self.isis_1_1_notrans = "ISIS_1_1_notrans.xml"
- self.isis_1_1_doubletrans = "ISIS_1_1_doubletrans.xml"
- self.schema_1_0 = "cansas1d_v1_0.xsd"
- self.schema_1_1 = "cansas1d_v1_1.xsd"
-
-
- def get_number_of_entries(self, dictionary, name, i):
- if dictionary.get(name) is not None:
- i += 1
- name = name.split("_")[0]
- name += "_{0}".format(i)
- name = self.get_number_of_entries(dictionary, name, i)
- return name
-
-
- def test_invalid_xml(self):
- """
- Should fail gracefully and send a message to logging.info()
- """
- invalid = StringIO.StringIO('<a><c></b></a>')
- reader = XMLreader(invalid)
-
-
- def test_xml_validate(self):
- string = "<xsd:schema xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">\n"
- string += "\t<xsd:element name=\"a\" type=\"AType\"/>\n"
- string += "\t<xsd:complexType name=\"AType\">\n"
- string += "\t\t<xsd:sequence>\n"
- string += "\t\t\t<xsd:element name=\"b\" type=\"xsd:string\" />\n"
- string += "\t\t</xsd:sequence>\n"
- string += "\t</xsd:complexType>\n"
- string += "</xsd:schema>"
- f = StringIO.StringIO(string)
- xmlschema_doc = etree.parse(f)
- xmlschema = etree.XMLSchema(xmlschema_doc)
- valid = etree.parse(StringIO.StringIO('<a><b></b></a>'))
- invalid = etree.parse(StringIO.StringIO('<a><c></c></a>'))
- self.assertTrue(xmlschema.validate(valid))
- self.assertFalse(xmlschema.validate(invalid))
-
-
- def test_real_xml(self):
- reader = XMLreader(self.xml_valid, self.schema_1_0)
- valid = reader.validate_xml()
- if valid:
- self.assertTrue(valid)
- else:
- self.assertFalse(valid)
-
-
- def _check_data(self, data):
- self.assertTrue(data.title == "TK49 c10_SANS")
- self.assertTrue(data.x.size == 138)
- self.assertTrue(len(data.meta_data) == 3)
- self.assertTrue(data.detector[0].distance_unit == "mm")
- self.assertTrue(data.detector[1].distance_unit == "mm")
- self.assertTrue(data.detector[0].name == "HAB")
- self.assertTrue(data.detector[1].name == "main-detector-bank")
- self.assertTrue(data.detector[0].distance == 575.0)
- self.assertAlmostEqual(data.detector[1].distance, 4145.02)
- self.assertTrue(data.process[0].name == "Mantid generated CanSAS1D XML")
- self.assertTrue(data.meta_data["xmlpreprocess"] != None)
-
-
- def _check_data_1_1(self, data):
- spectrum = data.trans_spectrum[0]
- self.assertTrue(len(spectrum.wavelength) == 138)
-
-
- def test_cansas_xml(self):
- filename = "isis_1_1_write_test.xml"
- xmlreader = XMLreader(self.isis_1_1, self.schema_1_1)
- valid = xmlreader.validate_xml()
- xmlreader.set_processing_instructions()
- self.assertTrue(valid)
- fo = open(self.isis_1_1)
- str = fo.read()
- reader_generic = Loader()
- dataloader = reader_generic.load(self.isis_1_1)
- reader_cansas = Reader()
- cansasreader = reader_cansas.read(self.isis_1_1)
- for i in range(len(dataloader)):
- self._check_data(dataloader[i])
- self._check_data_1_1(dataloader[i])
- self._check_data(cansasreader[i])
- self._check_data_1_1(cansasreader[i])
- reader_generic.save(filename, dataloader[i], None)
- fo = open(filename)
- str = fo.read()
- reader2 = Loader()
- return_data = reader2.load(filename)
- written_data = return_data[0]
- self._check_data(written_data)
-
-
- def test_double_trans_spectra(self):
- xmlreader = XMLreader(self.isis_1_1_doubletrans, self.schema_1_1)
- self.assertTrue(xmlreader.validate_xml())
- reader = Loader()
- data = reader.load(self.isis_1_1_doubletrans)
- for item in data:
- self._check_data(item)
-
-
- def test_entry_name_recurse(self):
- test_values = [1,2,3,4,5,6]
- base_key = "key"
- d = {}
- for value in test_values:
- new_key = self.get_number_of_entries(d, base_key, i = 0)
- d[new_key] = value
- self.assertTrue(len(d) == 6)
-
-
- def test_load_cansas_file(self):
- valid = []
- reader1 = XMLreader(self.xml_valid, self.schema_1_0)
- self.assertTrue(reader1.validate_xml())
- reader2 = XMLreader(self.xml_invalid, self.schema_1_0)
- self.assertFalse(reader2.validate_xml())
- reader3 = XMLreader(self.xml_valid, self.schema_1_1)
- self.assertFalse(reader3.validate_xml())
- reader4 = XMLreader(self.xml_invalid, self.schema_1_1)
- self.assertFalse(reader4.validate_xml())
- reader5 = XMLreader(self.isis_1_0, self.schema_1_0)
- self.assertTrue(reader5.validate_xml())
- reader6 = XMLreader(self.isis_1_1, self.schema_1_1)
- self.assertTrue(reader6.validate_xml())
- reader7 = XMLreader(self.isis_1_1, self.schema_1_0)
- self.assertFalse(reader7.validate_xml())
-
-
- def test_invalid_cansas(self):
- list = self.loader.load(self.cansas1d_notitle)
- data = list[0]
- self.assertTrue(data.x.size == 2)
- self.assertTrue(len(data.meta_data) == 2)
- self.assertTrue(len(data.errors) == 1)
- self.assertTrue(data.detector[0].distance_unit == "mm")
- self.assertTrue(data.detector[0].name == "fictional hybrid")
- self.assertTrue(data.detector[0].distance == 4150)
-
-
- def test_old_cansas_files(self):
- reader1 = XMLreader(self.cansas1d, self.schema_1_0)
- self.assertTrue(reader1.validate_xml())
- file_loader = Loader()
- file1 = file_loader.load(self.cansas1d)
- reader2 = XMLreader(self.cansas1d_units, self.schema_1_0)
- self.assertTrue(reader2.validate_xml())
- reader3 = XMLreader(self.cansas1d_badunits, self.schema_1_0)
- self.assertTrue(reader3.validate_xml())
- reader4 = XMLreader(self.cansas1d_slit, self.schema_1_0)
- self.assertTrue(reader4.validate_xml())
-
-
- def test_save_cansas_v1_0(self):
- filename = "isis_1_0_write_test.xml"
- xmlreader = XMLreader(self.isis_1_0, self.schema_1_0)
- valid = xmlreader.validate_xml()
- self.assertTrue(valid)
- reader_generic = Loader()
- dataloader = reader_generic.load(self.isis_1_0)
- reader_cansas = Reader()
- cansasreader = reader_cansas.read(self.isis_1_0)
- for i in range(len(dataloader)):
- self._check_data(dataloader[i])
- self._check_data(cansasreader[i])
- reader_generic.save(filename, dataloader[i], None)
- reader2 = Reader()
- return_data = reader2.read(filename)
- written_data = return_data[0]
- xmlwrite = XMLreader(filename, self.schema_1_0)
- valid = xmlreader.validate_xml()
- self.assertTrue(valid)
- self._check_data(written_data)
-
-
- def test_processing_instructions(self):
- reader = XMLreader(self.isis_1_1, self.schema_1_1)
- valid = reader.validate_xml()
- if valid:
- ## find the processing instructions and make into a dictionary
- dic = self.get_processing_instructions(reader)
- self.assertTrue(dic == {'xml-stylesheet': \
- 'type="text/xsl" href="cansas1d.xsl" '})
-
- xml = "<test><a><b><c></c></b></a></test>"
- xmldoc = minidom.parseString(xml)
-
- ## take the processing instructions and put them back in
- xmldoc = self.set_processing_instructions(xmldoc, dic)
- xml_output = xmldoc.toprettyxml()
-
-
- def set_processing_instructions(self, minidom_object, dic):
- xmlroot = minidom_object.firstChild
- for item in dic:
- pi = minidom_object.createProcessingInstruction(item, dic[item])
- minidom_object.insertBefore(pi, xmlroot)
- return minidom_object
-
-
- def get_processing_instructions(self, xml_reader_object):
- dict = {}
- pi = xml_reader_object.xmlroot.getprevious()
- i = 0
- while pi is not None:
- attr = {}
- pi_name = ""
- pi_string = etree.tostring(pi)
- if isinstance(pi_string, str):
- pi_string = pi_string.replace("<?", "").replace("?>", "")
- split = pi_string.split(" ", 1)
- pi_name = split[0]
- attr = split[1]
- dict[pi_name] = attr
- pi = pi.getprevious()
- return dict
-
-
-class cansas_reader_hdf5(unittest.TestCase):
-
- def setUp(self):
- self.loader = Loader()
- self.datafile_basic = "simpleexamplefile.h5"
- self.datafile_multiplesasentry = "cansas_1Dand2D_samedatafile.h5"
- self.datafile_multiplesasdata = "cansas_1Dand2D_samesasentry.h5"
- self.datafile_multiplesasdata_multiplesasentry = "cansas_1Dand2D_multiplesasentry_multiplesasdata.h5"
-
- def test_real_data(self):
- self.data = self.loader.load(self.datafile_basic)
- self._check_example_data(self.data[0])
-
- def test_multiple_sasentries(self):
- self.data = self.loader.load(self.datafile_multiplesasentry)
- self.assertTrue(len(self.data) == 2)
- self._check_multiple_data(self.data[0])
- self._check_multiple_data(self.data[1])
- self._check_1d_data(self.data[0])
-
- def _check_multiple_data(self, data):
- self.assertTrue(data.title == "MH4_5deg_16T_SLOW")
- self.assertTrue(data.run[0] == '33837')
- self.assertTrue(len(data.run) == 1)
- self.assertTrue(data.instrument == "SANS2D")
- self.assertTrue(data.source.radiation == "Spallation Neutron Source")
- self.assertTrue(len(data.detector) == 1)
- self.assertTrue(data.detector[0].name == "rear-detector")
- self.assertTrue(data.detector[0].distance == 4.385281)
- self.assertTrue(data.detector[0].distance_unit == 'm')
- self.assertTrue(len(data.trans_spectrum) == 1)
-
- def _check_1d_data(self, data):
- self.assertTrue(isinstance(data, Data1D))
- self.assertTrue(len(data.x) == 66)
- self.assertTrue(len(data.x) == len(data.y))
- self.assertTrue(data.dy[10] == 0.20721350111248701)
- self.assertTrue(data.y[10] == 24.193889608153476)
- self.assertTrue(data.x[10] == 0.008981127988654792)
-
- def _check_2d_data(self, data):
- self.assertTrue(isinstance(data, Data2D))
- self.assertTrue(len(data.x) == 66)
- self.assertTrue(len(data.x) == len(data.y))
- self.assertTrue(data.dy[10] == 0.20721350111248701)
- self.assertTrue(data.y[10] == 24.193889608153476)
- self.assertTrue(data.x[10] == 0.008981127988654792)
-
- def _check_example_data(self, data):
- self.assertTrue(data.title == "")
- self.assertTrue(data.x.size == 100)
- self.assertTrue(data._xunit == "A^{-1}")
- self.assertTrue(data._yunit == "cm^{-1}")
- self.assertTrue(data.y.size == 100)
- self.assertAlmostEqual(data.y[9], 0.952749011516985)
- self.assertAlmostEqual(data.x[9], 0.3834415188257777)
- self.assertAlmostEqual(len(data.meta_data), 0)
-
-
-if __name__ == '__main__':
- unittest.main()
\ No newline at end of file
+"""
+ Unit tests for the new recursive cansas reader
+"""
+import os
+import sys
+import unittest
+import logging
+import warnings
+if sys.version_info[0] >= 3:
+ from io import StringIO
+else:
+ from StringIO import StringIO
+
+from lxml import etree
+from lxml.etree import XMLSyntaxError
+from xml.dom import minidom
+
+import sas.sascalc.dataloader.readers.cansas_reader as cansas
+from sas.sascalc.dataloader.file_reader_base_class import decode
+from sas.sascalc.dataloader.loader import Loader
+from sas.sascalc.dataloader.data_info import Data1D, Data2D
+from sas.sascalc.dataloader.readers.xml_reader import XMLreader
+from sas.sascalc.dataloader.readers.cansas_reader import Reader
+from sas.sascalc.dataloader.readers.cansas_constants import CansasConstants
+
+logger = logging.getLogger(__name__)
+
+warnings.simplefilter("ignore")
+
+CANSAS_FORMAT = CansasConstants.CANSAS_FORMAT
+CANSAS_NS = CansasConstants.CANSAS_NS
+
+class cansas_reader_xml(unittest.TestCase):
+
+ def setUp(self):
+ self.loader = Loader()
+ self.xml_valid = "cansas_test_modified.xml"
+ self.xml_invalid = "cansas_test.xml"
+ self.cansas1d_badunits = "cansas1d_badunits.xml"
+ self.cansas1d = "cansas1d.xml"
+ self.cansas1d_slit = "cansas1d_slit.xml"
+ self.cansas1d_units = "cansas1d_units.xml"
+ self.cansas1d_notitle = "cansas1d_notitle.xml"
+ self.isis_1_0 = "ISIS_1_0.xml"
+ self.isis_1_1 = "ISIS_1_1.xml"
+ self.isis_1_1_notrans = "ISIS_1_1_notrans.xml"
+ self.isis_1_1_doubletrans = "ISIS_1_1_doubletrans.xml"
+ self.schema_1_0 = "cansas1d_v1_0.xsd"
+ self.schema_1_1 = "cansas1d_v1_1.xsd"
+ self.write_1_0_filename = "isis_1_0_write_test.xml"
+ self.write_1_1_filename = "isis_1_1_write_test.xml"
+
+ def get_number_of_entries(self, dictionary, name, i):
+ if dictionary.get(name) is not None:
+ i += 1
+ name = name.split("_")[0]
+ name += "_{0}".format(i)
+ name = self.get_number_of_entries(dictionary, name, i)
+ return name
+
+ def test_invalid_xml(self):
+ """
+ Should fail gracefully and send a message to logger.info()
+ """
+ invalid = StringIO('<a><c></b></a>')
+ self.assertRaises(XMLSyntaxError, lambda: XMLreader(invalid))
+
+ def test_xml_validate(self):
+ string = "<xsd:schema xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">\n"
+ string += "\t<xsd:element name=\"a\" type=\"AType\"/>\n"
+ string += "\t<xsd:complexType name=\"AType\">\n"
+ string += "\t\t<xsd:sequence>\n"
+ string += "\t\t\t<xsd:element name=\"b\" type=\"xsd:string\" />\n"
+ string += "\t\t</xsd:sequence>\n"
+ string += "\t</xsd:complexType>\n"
+ string += "</xsd:schema>"
+ f = StringIO(string)
+ xmlschema_doc = etree.parse(f)
+ xmlschema = etree.XMLSchema(xmlschema_doc)
+ valid = etree.parse(StringIO('<a><b></b></a>'))
+ invalid = etree.parse(StringIO('<a><c></c></a>'))
+ self.assertTrue(xmlschema.validate(valid))
+ self.assertFalse(xmlschema.validate(invalid))
+
+ def test_real_xml(self):
+ reader = XMLreader(self.xml_valid, self.schema_1_0)
+ valid = reader.validate_xml()
+ if valid:
+ self.assertTrue(valid)
+ else:
+ self.assertFalse(valid)
+
+ def _check_data(self, data):
+ self.assertTrue(data.title == "TK49 c10_SANS")
+ self.assertTrue(data.x.size == 138)
+ self.assertTrue(len(data.meta_data) == 3)
+ self.assertTrue(data.detector[0].distance_unit == "mm")
+ self.assertTrue(data.detector[1].distance_unit == "mm")
+ self.assertTrue(data.detector[0].name == "HAB")
+ self.assertTrue(data.detector[1].name == "main-detector-bank")
+ self.assertTrue(data.detector[0].distance == 575.0)
+ self.assertAlmostEqual(data.detector[1].distance, 4145.02)
+ self.assertTrue(data.process[0].name == "Mantid generated CanSAS1D XML")
+ self.assertTrue(data.meta_data["xmlpreprocess"] is not None)
+
+ def _check_data_1_1(self, data):
+ spectrum = data.trans_spectrum[0]
+ self.assertTrue(len(spectrum.wavelength) == 138)
+
+ def test_cansas_xml(self):
+ xmlreader = XMLreader(self.isis_1_1, self.schema_1_1)
+ valid = xmlreader.validate_xml()
+ xmlreader.set_processing_instructions()
+ self.assertTrue(valid)
+ reader_generic = Loader()
+ dataloader = reader_generic.load(self.isis_1_1)
+ reader_cansas = Reader()
+ cansasreader = reader_cansas.read(self.isis_1_1)
+ for i in range(len(dataloader)):
+ self._check_data(dataloader[i])
+ self._check_data_1_1(dataloader[i])
+ self._check_data(cansasreader[i])
+ self._check_data_1_1(cansasreader[i])
+ reader_generic.save(self.write_1_1_filename, dataloader[i], None)
+ reader2 = Loader()
+ self.assertTrue(os.path.isfile(self.write_1_1_filename))
+ return_data = reader2.load(self.write_1_1_filename)
+ written_data = return_data[0]
+ self._check_data(written_data)
+ if os.path.isfile(self.write_1_1_filename):
+ os.remove(self.write_1_1_filename)
+
+ def test_double_trans_spectra(self):
+ xmlreader = XMLreader(self.isis_1_1_doubletrans, self.schema_1_1)
+ self.assertTrue(xmlreader.validate_xml())
+ reader = Loader()
+ data = reader.load(self.isis_1_1_doubletrans)
+ for item in data:
+ self._check_data(item)
+
+ def test_entry_name_recurse(self):
+ test_values = [1,2,3,4,5,6]
+ base_key = "key"
+ d = {}
+ for value in test_values:
+ new_key = self.get_number_of_entries(d, base_key, i = 0)
+ d[new_key] = value
+ self.assertTrue(len(d) == 6)
+
+ def test_load_cansas_file(self):
+ reader1 = XMLreader(self.xml_valid, self.schema_1_0)
+ self.assertTrue(reader1.validate_xml())
+ reader2 = XMLreader(self.xml_invalid, self.schema_1_0)
+ self.assertFalse(reader2.validate_xml())
+ reader3 = XMLreader(self.xml_valid, self.schema_1_1)
+ self.assertFalse(reader3.validate_xml())
+ reader4 = XMLreader(self.xml_invalid, self.schema_1_1)
+ self.assertFalse(reader4.validate_xml())
+ reader5 = XMLreader(self.isis_1_0, self.schema_1_0)
+ self.assertTrue(reader5.validate_xml())
+ reader6 = XMLreader(self.isis_1_1, self.schema_1_1)
+ self.assertTrue(reader6.validate_xml())
+ reader7 = XMLreader(self.isis_1_1, self.schema_1_0)
+ self.assertFalse(reader7.validate_xml())
+
+ def test_invalid_cansas(self):
+ list = self.loader.load(self.cansas1d_notitle)
+ data = list[0]
+ self.assertTrue(data.x.size == 2)
+ self.assertTrue(len(data.meta_data) == 2)
+ self.assertTrue(len(data.errors) == 1)
+ self.assertTrue(data.detector[0].distance_unit == "mm")
+ self.assertTrue(data.detector[0].name == "fictional hybrid")
+ self.assertTrue(data.detector[0].distance == 4150)
+
+ def test_old_cansas_files(self):
+ reader1 = XMLreader(self.cansas1d, self.schema_1_0)
+ self.assertTrue(reader1.validate_xml())
+ file_loader = Loader()
+ file_loader.load(self.cansas1d)
+ reader2 = XMLreader(self.cansas1d_units, self.schema_1_0)
+ self.assertTrue(reader2.validate_xml())
+ reader3 = XMLreader(self.cansas1d_badunits, self.schema_1_0)
+ self.assertTrue(reader3.validate_xml())
+ reader4 = XMLreader(self.cansas1d_slit, self.schema_1_0)
+ self.assertTrue(reader4.validate_xml())
+
+ def test_save_cansas_v1_0(self):
+ xmlreader = XMLreader(self.isis_1_0, self.schema_1_0)
+ valid = xmlreader.validate_xml()
+ self.assertTrue(valid)
+ reader_generic = Loader()
+ dataloader = reader_generic.load(self.isis_1_0)
+ reader_cansas = Reader()
+ cansasreader = reader_cansas.read(self.isis_1_0)
+ for i in range(len(dataloader)):
+ self._check_data(dataloader[i])
+ self._check_data(cansasreader[i])
+ reader_generic.save(self.write_1_0_filename, dataloader[i], None)
+ reader2 = Reader()
+ self.assertTrue(os.path.isfile(self.write_1_0_filename))
+ return_data = reader2.read(self.write_1_0_filename)
+ written_data = return_data[0]
+ XMLreader(self.write_1_0_filename, self.schema_1_0)
+ valid = xmlreader.validate_xml()
+ self.assertTrue(valid)
+ self._check_data(written_data)
+ if os.path.isfile(self.write_1_0_filename):
+ os.remove(self.write_1_0_filename)
+
+ def test_processing_instructions(self):
+ reader = XMLreader(self.isis_1_1, self.schema_1_1)
+ valid = reader.validate_xml()
+ if valid:
+ # find the processing instructions and make into a dictionary
+ dic = self.get_processing_instructions(reader)
+ self.assertEqual(dic, {'xml-stylesheet':
+ 'type="text/xsl" href="cansas1d.xsl" '})
+
+ xml = "<test><a><b><c></c></b></a></test>"
+ xmldoc = minidom.parseString(xml)
+
+ # take the processing instructions and put them back in
+ xmldoc = self.set_processing_instructions(xmldoc, dic)
+ xmldoc.toprettyxml()
+
+ def set_processing_instructions(self, minidom_object, dic):
+ xmlroot = minidom_object.firstChild
+ for item in dic:
+ pi = minidom_object.createProcessingInstruction(item, dic[item])
+ minidom_object.insertBefore(pi, xmlroot)
+ return minidom_object
+
+ def get_processing_instructions(self, xml_reader_object):
+ dict = {}
+ pi = xml_reader_object.xmlroot.getprevious()
+ i = 0
+ while pi is not None:
+ attr = {}
+ pi_name = ""
+ pi_string = decode(etree.tostring(pi))
+ if isinstance(pi_string, str):
+ pi_string = pi_string.replace("<?", "").replace("?>", "")
+ split = pi_string.split(" ", 1)
+ pi_name = split[0]
+ attr = split[1]
+ dict[pi_name] = attr
+ pi = pi.getprevious()
+ return dict
+
+
+class cansas_reader_hdf5(unittest.TestCase):
+
+ def setUp(self):
+ self.loader = Loader()
+ self.datafile_basic = "simpleexamplefile.h5"
+ self.datafile_multiplesasentry = "cansas_1Dand2D_samedatafile.h5"
+ self.datafile_multiplesasdata = "cansas_1Dand2D_samesasentry.h5"
+ self.datafile_multiplesasdata_multiplesasentry = "cansas_1Dand2D_multiplesasentry_multiplesasdata.h5"
+
+ def test_real_data(self):
+ self.data = self.loader.load(self.datafile_basic)
+ self._check_example_data(self.data[0])
+
+ def test_multiple_sasentries(self):
+ self.data = self.loader.load(self.datafile_multiplesasentry)
+ self.assertTrue(len(self.data) == 2)
+ self._check_multiple_data(self.data[0])
+ self._check_multiple_data(self.data[1])
+ self._check_1d_data(self.data[0])
+
+ def _check_multiple_data(self, data):
+ self.assertTrue(data.title == "MH4_5deg_16T_SLOW")
+ self.assertTrue(data.run[0] == '33837')
+ self.assertTrue(len(data.run) == 1)
+ self.assertTrue(data.instrument == "SANS2D")
+ self.assertTrue(data.source.radiation == "Spallation Neutron Source")
+ self.assertTrue(len(data.detector) == 1)
+ self.assertTrue(data.detector[0].name == "rear-detector")
+ self.assertTrue(data.detector[0].distance == 4.385281)
+ self.assertTrue(data.detector[0].distance_unit == 'm')
+ self.assertTrue(len(data.trans_spectrum) == 1)
+
+ def _check_1d_data(self, data):
+ self.assertTrue(isinstance(data, Data1D))
+ self.assertTrue(len(data.x) == 66)
+ self.assertTrue(len(data.x) == len(data.y))
+ self.assertTrue(data.dy[10] == 0.20721350111248701)
+ self.assertTrue(data.y[10] == 24.193889608153476)
+ self.assertTrue(data.x[10] == 0.008981127988654792)
+
+ def _check_2d_data(self, data):
+ self.assertTrue(isinstance(data, Data2D))
+ self.assertTrue(len(data.x) == 66)
+ self.assertTrue(len(data.x) == len(data.y))
+ self.assertTrue(data.dy[10] == 0.20721350111248701)
+ self.assertTrue(data.y[10] == 24.193889608153476)
+ self.assertTrue(data.x[10] == 0.008981127988654792)
+
+ def _check_example_data(self, data):
+ self.assertTrue(data.title == "")
+ self.assertTrue(data.x.size == 100)
+ self.assertTrue(data._xunit == "A^{-1}")
+ self.assertTrue(data._yunit == "cm^{-1}")
+ self.assertTrue(data.y.size == 100)
+ self.assertAlmostEqual(data.y[40], 0.952749011516985)
+ self.assertAlmostEqual(data.x[40], 0.3834415188257777)
+ self.assertAlmostEqual(len(data.meta_data), 0)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/test/sasdataloader/test/utest_extension_registry.py b/test/sasdataloader/test/utest_extension_registry.py
new file mode 100644
index 0000000..0734dd7
--- /dev/null
+++ b/test/sasdataloader/test/utest_extension_registry.py
@@ -0,0 +1,78 @@
+"""
+ Unit tests for loading data files using the extension registry
+"""
+
+import logging
+import unittest
+import os
+import shutil
+import numpy as np
+
+from sas.sascalc.dataloader.loader import Registry as Loader
+
+logger = logging.getLogger(__name__)
+
+class ExtensionRegistryTests(unittest.TestCase):
+
+ def setUp(self):
+ self.valid_file = "valid_cansas_xml.xml"
+ self.valid_file_wrong_known_ext = "valid_cansas_xml.txt"
+ self.valid_file_wrong_unknown_ext = "valid_cansas_xml.xyz"
+ shutil.copyfile(self.valid_file, self.valid_file_wrong_known_ext)
+ shutil.copyfile(self.valid_file, self.valid_file_wrong_unknown_ext)
+ self.invalid_file = "cansas1d_notitle.xml"
+
+ self.loader = Loader()
+
+ def test_wrong_known_ext(self):
+ """
+ Load a valid CanSAS XML file that has the extension '.txt', which is in
+ the extension registry. Compare the results to loading the same file
+ with the extension '.xml'
+ """
+ correct = self.loader.load(self.valid_file)
+ wrong_ext = self.loader.load(self.valid_file_wrong_known_ext)
+ self.assertEqual(len(correct), 1)
+ self.assertEqual(len(wrong_ext), 1)
+ correct = correct[0]
+ wrong_ext = wrong_ext[0]
+
+ self.assertTrue(np.all(correct.x == wrong_ext.x))
+ self.assertTrue(np.all(correct.y == wrong_ext.y))
+ self.assertTrue(np.all(correct.dy == wrong_ext.dy))
+
+ def test_wrong_unknown_ext(self):
+ """
+ Load a valid CanSAS XML file that has the extension '.xyz', which isn't
+ in the extension registry. Compare the results to loading the same file
+ with the extension '.xml'
+ """
+ correct = self.loader.load(self.valid_file)
+ wrong_ext = self.loader.load(self.valid_file_wrong_unknown_ext)
+ self.assertEqual(len(correct), 1)
+ self.assertEqual(len(wrong_ext), 1)
+ correct = correct[0]
+ wrong_ext = wrong_ext[0]
+
+ self.assertTrue(np.all(correct.x == wrong_ext.x))
+ self.assertTrue(np.all(correct.y == wrong_ext.y))
+ self.assertTrue(np.all(correct.dy == wrong_ext.dy))
+
+ def test_data_reader_exception(self):
+ """
+ Load a CanSAS XML file that doesn't meet the schema, and check errors
+ are set correctly
+ """
+ data = self.loader.load(self.invalid_file)
+ self.assertEqual(len(data), 1)
+ data = data[0]
+ self.assertEqual(len(data.errors), 1)
+
+ err_msg = data.errors[0]
+ self.assertTrue("does not fully meet the CanSAS v1.x specification" in err_msg)
+
+ def tearDown(self):
+ if os.path.isfile(self.valid_file_wrong_known_ext):
+ os.remove(self.valid_file_wrong_known_ext)
+ if os.path.isfile(self.valid_file_wrong_unknown_ext):
+ os.remove(self.valid_file_wrong_unknown_ext)
diff --git a/test/sasdataloader/test/utest_generic_file_reader_class.py b/test/sasdataloader/test/utest_generic_file_reader_class.py
new file mode 100644
index 0000000..061eb48
--- /dev/null
+++ b/test/sasdataloader/test/utest_generic_file_reader_class.py
@@ -0,0 +1,52 @@
+"""
+ Unit tests for the generic file reader class
+"""
+
+import os
+import unittest
+import logging
+import numpy as np
+
+from sas.sascalc.dataloader.data_info import DataInfo, plottable_1D
+from sas.sascalc.dataloader.file_reader_base_class import FileReader
+
+logger = logging.getLogger(__name__)
+
+
+class GenericFileReaderTests(unittest.TestCase):
+
+ def setUp(self):
+ self.reader = TestFileReader()
+ self.bad_file = "ACB123.txt"
+ self.good_file = "123ABC.txt"
+
+ def test_bad_file_path(self):
+ output = self.reader.read(self.bad_file)
+ self.assertEqual(output, [])
+
+ def test_good_file_path(self):
+ f = open(self.good_file, 'w')
+ f.write('123ABC exists!')
+ f.close()
+ output = self.reader.read(self.good_file)
+ self.assertEqual(len(output), 1)
+ self.assertEqual(output[0].meta_data["blah"], '123ABC exists!')
+
+ def tearDown(self):
+ if os.path.isfile(self.bad_file):
+ os.remove(self.bad_file)
+ if os.path.isfile(self.good_file):
+ os.remove(self.good_file)
+
+class TestFileReader(FileReader):
+ def get_file_contents(self):
+ """
+ Reader specific class to access the contents of the file
+ All reader classes that inherit from FileReader must implement
+ """
+ x = np.zeros(0)
+ y = np.zeros(0)
+ self.current_dataset = plottable_1D(x,y)
+ self.current_datainfo = DataInfo()
+ self.current_datainfo.meta_data["blah"] = self.nextline()
+ self.send_to_output()
\ No newline at end of file
diff --git a/test/sasdataloader/test/utest_red2d_reader.py b/test/sasdataloader/test/utest_red2d_reader.py
index f02ede2..ae80e09 100644
--- a/test/sasdataloader/test/utest_red2d_reader.py
+++ b/test/sasdataloader/test/utest_red2d_reader.py
@@ -1,34 +1,35 @@
-"""
- Unit tests for the red2d (3-7-column) reader
-"""
-import warnings
-warnings.simplefilter("ignore")
-
-import unittest
-from sas.sascalc.dataloader.loader import Loader
-
-import os.path
-
-class abs_reader(unittest.TestCase):
-
- def setUp(self):
- self.loader = Loader()
-
- def test_checkdata(self):
- """
- Test .DAT file loaded as IGOR/DAT 2D Q_map
- """
- f = self.loader.load("exp18_14_igor_2dqxqy.dat")
- # The length of the data is 10
- self.assertEqual(len(f.qx_data), 36864)
- self.assertEqual(f.qx_data[0],-0.03573497)
- self.assertEqual(f.qx_data[36863],0.2908819)
- self.assertEqual(f.Q_unit, '1/A')
- self.assertEqual(f.I_unit, '1/cm')
-
- self.assertEqual(f.meta_data['loader'],"IGOR/DAT 2D Q_map")
-
-
-if __name__ == '__main__':
- unittest.main()
-
+"""
+ Unit tests for the red2d (3-7-column) reader
+"""
+import warnings
+warnings.simplefilter("ignore")
+
+import unittest
+from sas.sascalc.dataloader.loader import Loader
+
+import os.path
+
+class abs_reader(unittest.TestCase):
+
+ def setUp(self):
+ self.loader = Loader()
+ self.data_list = self.loader.load("exp18_14_igor_2dqxqy.dat")
+
+ def test_checkdata(self):
+ """
+ Test .DAT file loaded as IGOR/DAT 2D Q_map
+ """
+ f = self.data_list[0]
+ # The length of the data is 10
+ self.assertEqual(len(self.data_list), 1)
+ self.assertEqual(len(f.qx_data), 36864)
+ self.assertEqual(f.qx_data[0],-0.03573497)
+ self.assertEqual(f.qx_data[36863],0.2908819)
+ self.assertEqual(f.Q_unit, '1/A')
+ self.assertEqual(f.I_unit, '1/cm')
+
+ self.assertEqual(f.meta_data['loader'],"IGOR/DAT 2D Q_map")
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/test/sasdataloader/test/utest_sesans.py b/test/sasdataloader/test/utest_sesans.py
new file mode 100644
index 0000000..8e41e37
--- /dev/null
+++ b/test/sasdataloader/test/utest_sesans.py
@@ -0,0 +1,97 @@
+"""
+ Unit tests for the SESANS .ses reader
+"""
+
+import unittest
+from sas.sascalc.dataloader.loader_exceptions import FileContentsException,\
+ DefaultReaderException
+from sas.sascalc.dataloader.readers.sesans_reader import Reader
+from sas.sascalc.dataloader.loader import Loader
+
+class sesans_reader(unittest.TestCase):
+
+ def setUp(self):
+ reader = Reader()
+ self.loader = reader.read
+
+ def test_full_load(self):
+ """
+ Test .SES in the full loader to make sure that the file type is correctly accepted
+ """
+ file = Loader().load("sesans_examples/sphere2micron.ses")
+ f = file[0]
+ # self.assertEqual(f, 5)
+ self.assertEqual(len(file), 1)
+ self.assertEqual(len(f.x), 40)
+ self.assertEqual(f.x[0], 391.56)
+ self.assertEqual(f.x[-1], 46099)
+ self.assertEqual(f.y[-1], -0.19956)
+ self.assertEqual(f.x_unit, "A")
+ self.assertEqual(f.y_unit, "A-2 cm-1")
+ self.assertEqual(f.sample.name, "Polystyrene 2 um in 53% H2O, 47% D2O")
+ self.assertEqual(f.sample.thickness, 0.2)
+ self.assertEqual(f.sample.zacceptance, (0.0168, "radians"))
+ self.assertEqual(f.isSesans, True)
+
+ def test_sesans_tof(self):
+ """
+ Test .SES loading on a TOF dataset
+ """
+ file = self.loader("sesans_examples/sphere_isis.ses")
+ f = file[0]
+ self.assertEqual(len(file), 1)
+ self.assertEqual(len(f.x), 57)
+ self.assertEqual(f.x[-1], 19303.4)
+ self.assertEqual(f.source.wavelength[-1], 13.893668)
+ self.assertEqual(f.source.wavelength[0], 1.612452)
+ self.assertEqual(f.sample.yacceptance, (0.09, "radians"))
+ self.assertEqual(f.sample.zacceptance, (0.09, "radians"))
+ self.assertEqual(f.sample.thickness, 0.2)
+
+ def test_sesans_no_data(self):
+ """
+ Confirm that sesans files with no actual data won't load.
+ """
+ self.assertRaises(
+ FileContentsException,
+ self.loader,
+ "sesans_examples/sesans_no_data.ses")
+
+ def test_sesans_no_spin_echo_unit(self):
+ """
+ Confirm that sesans files with no units from the spin echo length raise an appropriate error
+ """
+ self.assertRaises(
+ FileContentsException,
+ self.loader,
+ "sesans_examples/no_spin_echo_unit.ses")
+
+ def test_sesans_future_version(self):
+ """
+ Confirm that sesans files that, according to semantic version, are from a future, backwards-incompatible version of the SES file format throw an exception.
+ """
+ self.assertRaises(
+ FileContentsException,
+ self.loader,
+ "sesans_examples/next_gen.ses")
+
+ def test_sesans_mandatory_headers(self):
+ """
+ Confirm that sesans files throw an exception if one of the mandator headers is missing.
+ """
+ self.assertRaises(
+ FileContentsException,
+ self.loader,
+ "sesans_examples/no_wavelength.ses")
+
+ def test_sesans_columns_match_headers(self):
+ """
+ Confirm that sesans files throw an exception if one of the mandator headers is missing.
+ """
+ self.assertRaises(
+ FileContentsException,
+ self.loader,
+ "sesans_examples/too_many_headers.ses")
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/sasview/test/1d_data/ISIS_Polymer_Blend_TK49.xml b/test/sasdataloader/test/valid_cansas_xml.xml
similarity index 100%
rename from sasview/test/1d_data/ISIS_Polymer_Blend_TK49.xml
rename to test/sasdataloader/test/valid_cansas_xml.xml
diff --git a/test/sasdataloader/test/write_test.xml b/test/sasdataloader/test/write_test.xml
deleted file mode 100644
index e69de29..0000000
diff --git a/src/sas/__init__.py b/test/sasguiframe/__init__.py
similarity index 100%
copy from src/sas/__init__.py
copy to test/sasguiframe/__init__.py
diff --git a/src/sas/__init__.py b/test/sasguiframe/test/__init__.py
similarity index 100%
copy from src/sas/__init__.py
copy to test/sasguiframe/test/__init__.py
diff --git a/test/sasguiframe/test/utest_manipulations.py b/test/sasguiframe/test/utest_manipulations.py
index 2f7fcad..3d1c294 100644
--- a/test/sasguiframe/test/utest_manipulations.py
+++ b/test/sasguiframe/test/utest_manipulations.py
@@ -1,371 +1,383 @@
-"""
- Unit tests for data manipulations
-"""
-#TODO: what happens if you add a Data1D to a Data2D?
-
-import unittest
-import numpy, math
-from sas.sascalc.dataloader.loader import Loader
-from sas.sasgui.guiframe.dataFitting import Data1D, Data2D
-from sas.sasgui.guiframe.dataFitting import Data1D as Theory1D
-
-import os.path
-
-class data_info_tests(unittest.TestCase):
-
- def setUp(self):
- data = Loader().load("cansas1d.xml")
- self.data = data[0]
-
- def test_clone1D(self):
- """
- Test basic cloning
- """
- clone = self.data.clone_without_data()
-
- for i in range(len(self.data.detector)):
- self.assertEqual(self.data.detector[i].distance, clone.detector[i].distance)
-
-class theory1d_tests(unittest.TestCase):
-
- def setUp(self):
- data = Loader().load("cansas1d.xml")
- self.data = data[0]
-
- def test_clone_theory1D(self):
- """
- Test basic cloning
- """
- theory = Theory1D(x=[], y=[], dy=None)
- theory.clone_without_data(clone=self.data)
- theory.copy_from_datainfo(data1d=self.data)
- for i in range(len(self.data.detector)):
- self.assertEqual(self.data.detector[i].distance, theory.detector[i].distance)
-
- for i in range(len(self.data.x)):
- self.assertEqual(self.data.x[i], theory.x[i])
- self.assertEqual(self.data.y[i], theory.y[i])
- self.assertEqual(self.data.dy[i], theory.dy[i])
-
-class manip_tests(unittest.TestCase):
-
- def setUp(self):
- # Create two data sets to play with
- x_0 = numpy.ones(5)
- for i in range(5):
- x_0[i] = x_0[i]*(i+1.0)
-
- y_0 = 2.0*numpy.ones(5)
- dy_0 = 0.5*numpy.ones(5)
- self.data = Data1D(x_0, y_0, dy=dy_0)
-
- x = self.data.x
- y = numpy.ones(5)
- dy = numpy.ones(5)
- self.data2 = Data1D(x, y, dy=dy)
-
-
- def test_load(self):
- """
- Test whether the test file was loaded properly
- """
- # There should be 5 entries in the file
- self.assertEqual(len(self.data.x), 5)
-
- for i in range(5):
- # The x values should be from 1 to 5
- self.assertEqual(self.data.x[i], float(i+1))
-
- # All y-error values should be 0.5
- self.assertEqual(self.data.dy[i], 0.5)
-
- # All y values should be 2.0
- self.assertEqual(self.data.y[i], 2.0)
-
- def test_add(self):
- result = self.data2+self.data
- for i in range(5):
- self.assertEqual(result.y[i], 3.0)
- self.assertEqual(result.dy[i], math.sqrt(0.5**2+1.0))
-
- def test_sub(self):
- result = self.data2-self.data
- for i in range(5):
- self.assertEqual(result.y[i], -1.0)
- self.assertEqual(result.dy[i], math.sqrt(0.5**2+1.0))
-
- def test_mul(self):
- result = self.data2*self.data
- for i in range(5):
- self.assertEqual(result.y[i], 2.0)
- self.assertEqual(result.dy[i], math.sqrt((0.5*1.0)**2+(1.0*2.0)**2))
-
- def test_div(self):
- result = self.data2/self.data
- for i in range(5):
- self.assertEqual(result.y[i], 0.5)
- self.assertEqual(result.dy[i], math.sqrt((1.0/2.0)**2+(0.5*1.0/4.0)**2))
-
- def test_radd(self):
- result = self.data+3.0
- for i in range(5):
- self.assertEqual(result.y[i], 5.0)
- self.assertEqual(result.dy[i], 0.5)
-
- result = 3.0+self.data
- for i in range(5):
- self.assertEqual(result.y[i], 5.0)
- self.assertEqual(result.dy[i], 0.5)
-
- def test_rsub(self):
- result = self.data-3.0
- for i in range(5):
- self.assertEqual(result.y[i], -1.0)
- self.assertEqual(result.dy[i], 0.5)
-
- result = 3.0-self.data
- for i in range(5):
- self.assertEqual(result.y[i], 1.0)
- self.assertEqual(result.dy[i], 0.5)
-
- def test_rmul(self):
- result = self.data*3.0
- for i in range(5):
- self.assertEqual(result.y[i], 6.0)
- self.assertEqual(result.dy[i], 1.5)
-
- result = 3.0*self.data
- for i in range(5):
- self.assertEqual(result.y[i], 6.0)
- self.assertEqual(result.dy[i], 1.5)
-
- def test_rdiv(self):
- result = self.data/4.0
- for i in range(5):
- self.assertEqual(result.y[i], 0.5)
- self.assertEqual(result.dy[i], 0.125)
-
- result = 6.0/self.data
- for i in range(5):
- self.assertEqual(result.y[i], 3.0)
- self.assertEqual(result.dy[i], 6.0*0.5/4.0)
-
-class manip_2D(unittest.TestCase):
-
- def setUp(self):
- # Create two data sets to play with
- x_0 = 2.0*numpy.ones(25)
- dx_0 = 0.5*numpy.ones(25)
- qx_0 = numpy.arange(25)
- qy_0 = numpy.arange(25)
- mask_0 = numpy.zeros(25)
- dqx_0 = numpy.arange(25)/100
- dqy_0 = numpy.arange(25)/100
- q_0 = numpy.sqrt(qx_0 * qx_0 + qy_0 * qy_0)
- self.data = Data2D(image=x_0, err_image=dx_0, qx_data=qx_0,
- qy_data=qy_0, q_data=q_0, mask=mask_0,
- dqx_data=dqx_0, dqy_data=dqy_0)
-
- y = numpy.ones(25)
- dy = numpy.ones(25)
- qx = numpy.arange(25)
- qy = numpy.arange(25)
- mask = numpy.zeros(25)
- q = numpy.sqrt(qx * qx + qy * qy)
- self.data2 = Data2D(image=y, err_image=dy, qx_data=qx, qy_data=qy,
- q_data=q, mask=mask)
-
-
- def test_load(self):
- """
- Test whether the test file was loaded properly
- """
- # There should be 5 entries in the file
- self.assertEqual(numpy.size(self.data.data), 25)
-
- for i in range(25):
- # All y-error values should be 0.5
- self.assertEqual(self.data.err_data[i], 0.5)
-
- # All y values should be 2.0
- self.assertEqual(self.data.data[i], 2.0)
-
- def test_add(self):
- result = self.data2+self.data
- for i in range(25):
- self.assertEqual(result.data[i], 3.0)
- self.assertEqual(result.err_data[i], math.sqrt(0.5**2+1.0))
-
- def test_sub(self):
- result = self.data2-self.data
- for i in range(25):
- self.assertEqual(result.data[i], -1.0)
- self.assertEqual(result.err_data[i], math.sqrt(0.5**2+1.0))
-
- def test_mul(self):
- result = self.data2*self.data
- for i in range(25):
- self.assertEqual(result.data[i], 2.0)
- self.assertEqual(result.err_data[i], math.sqrt((0.5*1.0)**2+(1.0*2.0)**2))
-
- def test_div(self):
- result = self.data2/self.data
- for i in range(25):
- self.assertEqual(result.data[i], 0.5)
- self.assertEqual(result.err_data[i], math.sqrt((1.0/2.0)**2+(0.5*1.0/4.0)**2))
-
- def test_radd(self):
- result = self.data+3.0
- for i in range(25):
- self.assertEqual(result.data[i], 5.0)
- self.assertEqual(result.err_data[i], 0.5)
-
- result = 3.0+self.data
- for i in range(25):
- self.assertEqual(result.data[i], 5.0)
- self.assertEqual(result.err_data[i], 0.5)
-
- def test_rsub(self):
- result = self.data-3.0
- for i in range(25):
- self.assertEqual(result.data[i], -1.0)
- self.assertEqual(result.err_data[i], 0.5)
-
- result = 3.0-self.data
- for i in range(25):
- self.assertEqual(result.data[i], 1.0)
- self.assertEqual(result.err_data[i], 0.5)
-
- def test_rmul(self):
- result = self.data*3.0
- for i in range(25):
- self.assertEqual(result.data[i], 6.0)
- self.assertEqual(result.err_data[i], 1.5)
-
- result = 3.0*self.data
- for i in range(25):
- self.assertEqual(result.data[i], 6.0)
- self.assertEqual(result.err_data[i], 1.5)
-
- def test_rdiv(self):
- result = self.data/4.0
- for i in range(25):
- self.assertEqual(result.data[i], 0.5)
- self.assertEqual(result.err_data[i], 0.125)
-
- result = 6.0/self.data
- for i in range(25):
- self.assertEqual(result.data[i], 3.0)
- self.assertEqual(result.err_data[i], 6.0*0.5/4.0)
-
-class extra_manip_2D(unittest.TestCase):
-
- def setUp(self):
- # Create two data sets to play with
- x_0 = 2.0*numpy.ones(25)
- dx_0 = 0.5*numpy.ones(25)
- qx_0 = numpy.arange(25)
- qy_0 = numpy.arange(25)
- mask_0 = numpy.zeros(25)
- dqx_0 = numpy.arange(25)/100
- dqy_0 = numpy.arange(25)/100
- q_0 = numpy.sqrt(qx_0 * qx_0 + qy_0 * qy_0)
- self.data = Data2D(image=x_0, err_image=dx_0, qx_data=qx_0,
- qy_data=qy_0, q_data=q_0, mask=mask_0,
- dqx_data=dqx_0, dqy_data=dqy_0)
-
- y = numpy.ones(25)
- dy = numpy.ones(25)
- qx = numpy.arange(25)
- qy = numpy.arange(25)
- mask = numpy.zeros(25)
- q = numpy.sqrt(qx * qx + qy * qy)
- self.data2 = Data2D(image=y, err_image=dy, qx_data=qx, qy_data=qy,
- q_data=q, mask=mask)
-
-
- def test_load(self):
- """
- Test whether the test file was loaded properly
- """
- # There should be 5 entries in the file
- self.assertEqual(numpy.size(self.data.data), 25)
-
- for i in range(25):
- # All y-error values should be 0.5
- self.assertEqual(self.data.err_data[i], 0.5)
-
- # All y values should be 2.0
- self.assertEqual(self.data.data[i], 2.0)
-
- def test_add(self):
- result = self.data2+self.data
- for i in range(25):
- self.assertEqual(result.data[i], 3.0)
- self.assertEqual(result.err_data[i], math.sqrt(0.5**2+1.0))
-
- def test_sub(self):
- result = self.data2-self.data
- for i in range(25):
- self.assertEqual(result.data[i], -1.0)
- self.assertEqual(result.err_data[i], math.sqrt(0.5**2+1.0))
-
- def test_mul(self):
- result = self.data2*self.data
- for i in range(25):
- self.assertEqual(result.data[i], 2.0)
- self.assertEqual(result.err_data[i], math.sqrt((0.5*1.0)**2+(1.0*2.0)**2))
-
- def test_div(self):
- result = self.data2/self.data
- for i in range(25):
- self.assertEqual(result.data[i], 0.5)
- self.assertEqual(result.err_data[i], math.sqrt((1.0/2.0)**2+(0.5*1.0/4.0)**2))
-
- def test_radd(self):
- result = self.data+3.0
- for i in range(25):
- self.assertEqual(result.data[i], 5.0)
- self.assertEqual(result.err_data[i], 0.5)
-
- result = 3.0+self.data
- for i in range(25):
- self.assertEqual(result.data[i], 5.0)
- self.assertEqual(result.err_data[i], 0.5)
-
- def test_rsub(self):
- result = self.data-3.0
- for i in range(25):
- self.assertEqual(result.data[i], -1.0)
- self.assertEqual(result.err_data[i], 0.5)
-
- result = 3.0-self.data
- for i in range(25):
- self.assertEqual(result.data[i], 1.0)
- self.assertEqual(result.err_data[i], 0.5)
-
- def test_rmul(self):
- result = self.data*3.0
- for i in range(25):
- self.assertEqual(result.data[i], 6.0)
- self.assertEqual(result.err_data[i], 1.5)
-
- result = 3.0*self.data
- for i in range(25):
- self.assertEqual(result.data[i], 6.0)
- self.assertEqual(result.err_data[i], 1.5)
-
- def test_rdiv(self):
- result = self.data/4.0
- for i in range(25):
- self.assertEqual(result.data[i], 0.5)
- self.assertEqual(result.err_data[i], 0.125)
-
- result = 6.0/self.data
- for i in range(25):
- self.assertEqual(result.data[i], 3.0)
- self.assertEqual(result.err_data[i], 6.0*0.5/4.0)
-
-if __name__ == '__main__':
- unittest.main()
-
+"""
+ Unit tests for data manipulations
+"""
+# TODO: what happens if you add a Data1D to a Data2D?
+
+import math
+import os.path
+import unittest
+
+import numpy as np
+
+from sas.sascalc.dataloader.loader import Loader
+from sas.sasgui.guiframe.dataFitting import Data1D
+from sas.sasgui.guiframe.dataFitting import Data2D
+
+
+class DataInfoTests(unittest.TestCase):
+
+ def setUp(self):
+ data = Loader().load("cansas1d.xml")
+ self.data = data[0]
+
+ def test_clone1D(self):
+ """
+ Test basic cloning
+ """
+ clone = self.data.clone_without_data()
+
+ for i in range(len(self.data.detector)):
+ self.assertEqual(
+ self.data.detector[i].distance, clone.detector[i].distance)
+
+
+class Theory1DTests(unittest.TestCase):
+
+ def setUp(self):
+ data = Loader().load("cansas1d.xml")
+ self.data = data[0]
+
+ def test_clone_theory1D(self):
+ """
+ Test basic cloning
+ """
+ theory = Data1D(x=[], y=[], dy=None)
+ theory.clone_without_data(clone=self.data)
+ theory.copy_from_datainfo(data1d=self.data)
+ for i in range(len(self.data.detector)):
+ self.assertEqual(
+ self.data.detector[i].distance, theory.detector[i].distance)
+
+ for i in range(len(self.data.x)):
+ self.assertEqual(self.data.x[i], theory.x[i])
+ self.assertEqual(self.data.y[i], theory.y[i])
+ self.assertEqual(self.data.dy[i], theory.dy[i])
+
+
+class ManipTests(unittest.TestCase):
+
+ def setUp(self):
+ # Create two data sets to play with
+ x_0 = np.ones(5)
+ for i in range(5):
+ x_0[i] = x_0[i] * (i + 1.0)
+
+ y_0 = 2.0 * np.ones(5)
+ dy_0 = 0.5 * np.ones(5)
+ self.data = Data1D(x_0, y_0, dy=dy_0)
+
+ x = self.data.x
+ y = np.ones(5)
+ dy = np.ones(5)
+ self.data2 = Data1D(x, y, dy=dy)
+
+ def test_load(self):
+ """
+ Test whether the test file was loaded properly
+ """
+ # There should be 5 entries in the file
+ self.assertEqual(len(self.data.x), 5)
+
+ for i in range(5):
+ # The x values should be from 1 to 5
+ self.assertEqual(self.data.x[i], float(i + 1))
+
+ # All y-error values should be 0.5
+ self.assertEqual(self.data.dy[i], 0.5)
+
+ # All y values should be 2.0
+ self.assertEqual(self.data.y[i], 2.0)
+
+ def test_add(self):
+ result = self.data2 + self.data
+ for i in range(5):
+ self.assertEqual(result.y[i], 3.0)
+ self.assertEqual(result.dy[i], math.sqrt(0.5**2 + 1.0))
+
+ def test_sub(self):
+ result = self.data2 - self.data
+ for i in range(5):
+ self.assertEqual(result.y[i], -1.0)
+ self.assertEqual(result.dy[i], math.sqrt(0.5**2 + 1.0))
+
+ def test_mul(self):
+ result = self.data2 * self.data
+ for i in range(5):
+ self.assertEqual(result.y[i], 2.0)
+ self.assertEqual(result.dy[i], math.sqrt(
+ (0.5 * 1.0)**2 + (1.0 * 2.0)**2))
+
+ def test_div(self):
+ result = self.data2 / self.data
+ for i in range(5):
+ self.assertEqual(result.y[i], 0.5)
+ self.assertEqual(result.dy[i], math.sqrt(
+ (1.0 / 2.0)**2 + (0.5 * 1.0 / 4.0)**2))
+
+ def test_radd(self):
+ result = self.data + 3.0
+ for i in range(5):
+ self.assertEqual(result.y[i], 5.0)
+ self.assertEqual(result.dy[i], 0.5)
+
+ result = 3.0 + self.data
+ for i in range(5):
+ self.assertEqual(result.y[i], 5.0)
+ self.assertEqual(result.dy[i], 0.5)
+
+ def test_rsub(self):
+ result = self.data - 3.0
+ for i in range(5):
+ self.assertEqual(result.y[i], -1.0)
+ self.assertEqual(result.dy[i], 0.5)
+
+ result = 3.0 - self.data
+ for i in range(5):
+ self.assertEqual(result.y[i], 1.0)
+ self.assertEqual(result.dy[i], 0.5)
+
+ def test_rmul(self):
+ result = self.data * 3.0
+ for i in range(5):
+ self.assertEqual(result.y[i], 6.0)
+ self.assertEqual(result.dy[i], 1.5)
+
+ result = 3.0 * self.data
+ for i in range(5):
+ self.assertEqual(result.y[i], 6.0)
+ self.assertEqual(result.dy[i], 1.5)
+
+ def test_rdiv(self):
+ result = self.data / 4.0
+ for i in range(5):
+ self.assertEqual(result.y[i], 0.5)
+ self.assertEqual(result.dy[i], 0.125)
+
+ result = 6.0 / self.data
+ for i in range(5):
+ self.assertEqual(result.y[i], 3.0)
+ self.assertEqual(result.dy[i], 6.0 * 0.5 / 4.0)
+
+
+class Manin2DTests(unittest.TestCase):
+
+ def setUp(self):
+ # Create two data sets to play with
+ x_0 = 2.0 * np.ones(25)
+ dx_0 = 0.5 * np.ones(25)
+ qx_0 = np.arange(25)
+ qy_0 = np.arange(25)
+ mask_0 = np.zeros(25)
+ dqx_0 = np.arange(25) / 100
+ dqy_0 = np.arange(25) / 100
+ q_0 = np.sqrt(qx_0 * qx_0 + qy_0 * qy_0)
+ self.data = Data2D(image=x_0, err_image=dx_0, qx_data=qx_0,
+ qy_data=qy_0, q_data=q_0, mask=mask_0,
+ dqx_data=dqx_0, dqy_data=dqy_0)
+
+ y = np.ones(25)
+ dy = np.ones(25)
+ qx = np.arange(25)
+ qy = np.arange(25)
+ mask = np.zeros(25)
+ q = np.sqrt(qx * qx + qy * qy)
+ self.data2 = Data2D(image=y, err_image=dy, qx_data=qx, qy_data=qy,
+ q_data=q, mask=mask)
+
+ def test_load(self):
+ """
+ Test whether the test file was loaded properly
+ """
+ # There should be 5 entries in the file
+ self.assertEqual(np.size(self.data.data), 25)
+
+ for i in range(25):
+ # All y-error values should be 0.5
+ self.assertEqual(self.data.err_data[i], 0.5)
+
+ # All y values should be 2.0
+ self.assertEqual(self.data.data[i], 2.0)
+
+ def test_add(self):
+ result = self.data2 + self.data
+ for i in range(25):
+ self.assertEqual(result.data[i], 3.0)
+ self.assertEqual(result.err_data[i], math.sqrt(0.5**2 + 1.0))
+
+ def test_sub(self):
+ result = self.data2 - self.data
+ for i in range(25):
+ self.assertEqual(result.data[i], -1.0)
+ self.assertEqual(result.err_data[i], math.sqrt(0.5**2 + 1.0))
+
+ def test_mul(self):
+ result = self.data2 * self.data
+ for i in range(25):
+ self.assertEqual(result.data[i], 2.0)
+ self.assertEqual(result.err_data[i], math.sqrt(
+ (0.5 * 1.0)**2 + (1.0 * 2.0)**2))
+
+ def test_div(self):
+ result = self.data2 / self.data
+ for i in range(25):
+ self.assertEqual(result.data[i], 0.5)
+ self.assertEqual(result.err_data[i], math.sqrt(
+ (1.0 / 2.0)**2 + (0.5 * 1.0 / 4.0)**2))
+
+ def test_radd(self):
+ result = self.data + 3.0
+ for i in range(25):
+ self.assertEqual(result.data[i], 5.0)
+ self.assertEqual(result.err_data[i], 0.5)
+
+ result = 3.0 + self.data
+ for i in range(25):
+ self.assertEqual(result.data[i], 5.0)
+ self.assertEqual(result.err_data[i], 0.5)
+
+ def test_rsub(self):
+ result = self.data - 3.0
+ for i in range(25):
+ self.assertEqual(result.data[i], -1.0)
+ self.assertEqual(result.err_data[i], 0.5)
+
+ result = 3.0 - self.data
+ for i in range(25):
+ self.assertEqual(result.data[i], 1.0)
+ self.assertEqual(result.err_data[i], 0.5)
+
+ def test_rmul(self):
+ result = self.data * 3.0
+ for i in range(25):
+ self.assertEqual(result.data[i], 6.0)
+ self.assertEqual(result.err_data[i], 1.5)
+
+ result = 3.0 * self.data
+ for i in range(25):
+ self.assertEqual(result.data[i], 6.0)
+ self.assertEqual(result.err_data[i], 1.5)
+
+ def test_rdiv(self):
+ result = self.data / 4.0
+ for i in range(25):
+ self.assertEqual(result.data[i], 0.5)
+ self.assertEqual(result.err_data[i], 0.125)
+
+ result = 6.0 / self.data
+ for i in range(25):
+ self.assertEqual(result.data[i], 3.0)
+ self.assertEqual(result.err_data[i], 6.0 * 0.5 / 4.0)
+
+
+class ExtraManip2DTests(unittest.TestCase):
+
+ def setUp(self):
+ # Create two data sets to play with
+ x_0 = 2.0 * np.ones(25)
+ dx_0 = 0.5 * np.ones(25)
+ qx_0 = np.arange(25)
+ qy_0 = np.arange(25)
+ mask_0 = np.zeros(25)
+ dqx_0 = np.arange(25) / 100
+ dqy_0 = np.arange(25) / 100
+ q_0 = np.sqrt(qx_0 * qx_0 + qy_0 * qy_0)
+ self.data = Data2D(image=x_0, err_image=dx_0, qx_data=qx_0,
+ qy_data=qy_0, q_data=q_0, mask=mask_0,
+ dqx_data=dqx_0, dqy_data=dqy_0)
+
+ y = np.ones(25)
+ dy = np.ones(25)
+ qx = np.arange(25)
+ qy = np.arange(25)
+ mask = np.zeros(25)
+ q = np.sqrt(qx * qx + qy * qy)
+ self.data2 = Data2D(image=y, err_image=dy, qx_data=qx, qy_data=qy,
+ q_data=q, mask=mask)
+
+ def test_load(self):
+ """
+ Test whether the test file was loaded properly
+ """
+ # There should be 5 entries in the file
+ self.assertEqual(np.size(self.data.data), 25)
+
+ for i in range(25):
+ # All y-error values should be 0.5
+ self.assertEqual(self.data.err_data[i], 0.5)
+
+ # All y values should be 2.0
+ self.assertEqual(self.data.data[i], 2.0)
+
+ def test_add(self):
+ result = self.data2 + self.data
+ for i in range(25):
+ self.assertEqual(result.data[i], 3.0)
+ self.assertEqual(result.err_data[i], math.sqrt(0.5**2 + 1.0))
+
+ def test_sub(self):
+ result = self.data2 - self.data
+ for i in range(25):
+ self.assertEqual(result.data[i], -1.0)
+ self.assertEqual(result.err_data[i], math.sqrt(0.5**2 + 1.0))
+
+ def test_mul(self):
+ result = self.data2 * self.data
+ for i in range(25):
+ self.assertEqual(result.data[i], 2.0)
+ self.assertEqual(result.err_data[i], math.sqrt(
+ (0.5 * 1.0)**2 + (1.0 * 2.0)**2))
+
+ def test_div(self):
+ result = self.data2 / self.data
+ for i in range(25):
+ self.assertEqual(result.data[i], 0.5)
+ self.assertEqual(result.err_data[i], math.sqrt(
+ (1.0 / 2.0)**2 + (0.5 * 1.0 / 4.0)**2))
+
+ def test_radd(self):
+ result = self.data + 3.0
+ for i in range(25):
+ self.assertEqual(result.data[i], 5.0)
+ self.assertEqual(result.err_data[i], 0.5)
+
+ result = 3.0 + self.data
+ for i in range(25):
+ self.assertEqual(result.data[i], 5.0)
+ self.assertEqual(result.err_data[i], 0.5)
+
+ def test_rsub(self):
+ result = self.data - 3.0
+ for i in range(25):
+ self.assertEqual(result.data[i], -1.0)
+ self.assertEqual(result.err_data[i], 0.5)
+
+ result = 3.0 - self.data
+ for i in range(25):
+ self.assertEqual(result.data[i], 1.0)
+ self.assertEqual(result.err_data[i], 0.5)
+
+ def test_rmul(self):
+ result = self.data * 3.0
+ for i in range(25):
+ self.assertEqual(result.data[i], 6.0)
+ self.assertEqual(result.err_data[i], 1.5)
+
+ result = 3.0 * self.data
+ for i in range(25):
+ self.assertEqual(result.data[i], 6.0)
+ self.assertEqual(result.err_data[i], 1.5)
+
+ def test_rdiv(self):
+ result = self.data / 4.0
+ for i in range(25):
+ self.assertEqual(result.data[i], 0.5)
+ self.assertEqual(result.err_data[i], 0.125)
+
+ result = 6.0 / self.data
+ for i in range(25):
+ self.assertEqual(result.data[i], 3.0)
+ self.assertEqual(result.err_data[i], 6.0 * 0.5 / 4.0)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/src/sas/__init__.py b/test/sasinvariant/__init__.py
similarity index 100%
copy from src/sas/__init__.py
copy to test/sasinvariant/__init__.py
diff --git a/src/sas/__init__.py b/test/sasinvariant/test/__init__.py
similarity index 100%
copy from src/sas/__init__.py
copy to test/sasinvariant/test/__init__.py
diff --git a/test/sasinvariant/test/utest_data_handling.py b/test/sasinvariant/test/utest_data_handling.py
index 010606b..c05c9e7 100644
--- a/test/sasinvariant/test/utest_data_handling.py
+++ b/test/sasinvariant/test/utest_data_handling.py
@@ -8,7 +8,8 @@ See the license text in license.txt
copyright 2010, University of Tennessee
"""
import unittest
-import numpy, math
+import math
+import numpy as np
from sas.sascalc.dataloader.loader import Loader
from sas.sascalc.dataloader.data_info import Data1D
@@ -19,8 +20,8 @@ class TestLinearFit(unittest.TestCase):
Test Line fit
"""
def setUp(self):
- x = numpy.asarray([1.,2.,3.,4.,5.,6.,7.,8.,9.])
- y = numpy.asarray([1.,2.,3.,4.,5.,6.,7.,8.,9.])
+ x = np.asarray([1.,2.,3.,4.,5.,6.,7.,8.,9.])
+ y = np.asarray([1.,2.,3.,4.,5.,6.,7.,8.,9.])
dy = y/10.0
self.data = Data1D(x=x,y=y,dy=dy)
@@ -134,8 +135,8 @@ class TestInvariantCalculator(unittest.TestCase):
self.assertRaises(ValueError, invariant.InvariantCalculator, Incompatible())
def test_error_treatment(self):
- x = numpy.asarray(numpy.asarray([0,1,2,3]))
- y = numpy.asarray(numpy.asarray([1,1,1,1]))
+ x = np.asarray(np.asarray([0,1,2,3]))
+ y = np.asarray(np.asarray([1,1,1,1]))
# These are all the values of the dy array that would cause
# us to set all dy values to 1.0 at __init__ time.
@@ -339,8 +340,8 @@ class TestGuinierExtrapolation(unittest.TestCase):
"""
self.scale = 1.5
self.rg = 30.0
- x = numpy.arange(0.0001, 0.1, 0.0001)
- y = numpy.asarray([self.scale * math.exp( -(q*self.rg)**2 / 3.0 ) for q in x])
+ x = np.arange(0.0001, 0.1, 0.0001)
+ y = np.asarray([self.scale * math.exp( -(q*self.rg)**2 / 3.0 ) for q in x])
dy = y*.1
self.data = Data1D(x=x, y=y, dy=dy)
@@ -382,8 +383,8 @@ class TestPowerLawExtrapolation(unittest.TestCase):
"""
self.scale = 1.5
self.m = 3.0
- x = numpy.arange(0.0001, 0.1, 0.0001)
- y = numpy.asarray([self.scale * math.pow(q ,-1.0*self.m) for q in x])
+ x = np.arange(0.0001, 0.1, 0.0001)
+ y = np.asarray([self.scale * math.pow(q ,-1.0*self.m) for q in x])
dy = y*.1
self.data = Data1D(x=x, y=y, dy=dy)
@@ -426,8 +427,8 @@ class TestLinearization(unittest.TestCase):
Check that the linearization process filters out points
that can't be transformed
"""
- x = numpy.asarray(numpy.asarray([0,1,2,3]))
- y = numpy.asarray(numpy.asarray([1,1,1,1]))
+ x = np.asarray(np.asarray([0,1,2,3]))
+ y = np.asarray(np.asarray([1,1,1,1]))
g = invariant.Guinier()
data_in = Data1D(x=x, y=y)
data_out = g.linearize_data(data_in)
@@ -437,9 +438,9 @@ class TestLinearization(unittest.TestCase):
self.assertEqual(len(dy_out), 3)
def test_allowed_bins(self):
- x = numpy.asarray(numpy.asarray([0,1,2,3]))
- y = numpy.asarray(numpy.asarray([1,1,1,1]))
- dy = numpy.asarray(numpy.asarray([1,1,1,1]))
+ x = np.asarray(np.asarray([0,1,2,3]))
+ y = np.asarray(np.asarray([1,1,1,1]))
+ dy = np.asarray(np.asarray([1,1,1,1]))
g = invariant.Guinier()
data = Data1D(x=x, y=y, dy=dy)
self.assertEqual(g.get_allowed_bins(data), [False, True, True, True])
@@ -464,8 +465,8 @@ class TestDataExtraLow(unittest.TestCase):
"""
self.scale = 1.5
self.rg = 30.0
- x = numpy.arange(0.0001, 0.1, 0.0001)
- y = numpy.asarray([self.scale * math.exp( -(q*self.rg)**2 / 3.0 ) for q in x])
+ x = np.arange(0.0001, 0.1, 0.0001)
+ y = np.asarray([self.scale * math.exp( -(q*self.rg)**2 / 3.0 ) for q in x])
dy = y*.1
self.data = Data1D(x=x, y=y, dy=dy)
@@ -512,8 +513,8 @@ class TestDataExtraLowSlitGuinier(unittest.TestCase):
"""
self.scale = 1.5
self.rg = 30.0
- x = numpy.arange(0.0001, 0.1, 0.0001)
- y = numpy.asarray([self.scale * math.exp( -(q*self.rg)**2 / 3.0 ) for q in x])
+ x = np.arange(0.0001, 0.1, 0.0001)
+ y = np.asarray([self.scale * math.exp( -(q*self.rg)**2 / 3.0 ) for q in x])
dy = y*.1
self.data = Data1D(x=x, y=y, dy=dy)
self.npts = len(x)-10
@@ -599,8 +600,8 @@ class TestDataExtraHighSlitPowerLaw(unittest.TestCase):
"""
self.scale = 1.5
self.m = 3.0
- x = numpy.arange(0.0001, 0.1, 0.0001)
- y = numpy.asarray([self.scale * math.pow(q ,-1.0*self.m) for q in x])
+ x = np.arange(0.0001, 0.1, 0.0001)
+ y = np.asarray([self.scale * math.pow(q ,-1.0*self.m) for q in x])
dy = y*.1
self.data = Data1D(x=x, y=y, dy=dy)
self.npts = 20
diff --git a/test/sasinvariant/test/utest_use_cases.py b/test/sasinvariant/test/utest_use_cases.py
index bb2af5c..07399fb 100644
--- a/test/sasinvariant/test/utest_use_cases.py
+++ b/test/sasinvariant/test/utest_use_cases.py
@@ -1,378 +1,375 @@
-"""
- Implementation of the use-case from a usage perspective.
-
-"""
-#TODO: there's no test for smeared extrapolation
-import unittest
-import numpy
-from sas.sascalc.dataloader.loader import Loader
-
-from sas.sascalc.invariant import invariant
-
-class Data1D:
- pass
-
-class TestLineFit(unittest.TestCase):
- """
- Test Line fit
- """
- def setUp(self):
- self.data = Loader().load("linefittest.txt")
-
- def test_fit_line_data(self):
- """
- Fit_Test_1: test linear fit, ax +b, without fixed
- """
-
- # Create invariant object. Background and scale left as defaults.
- fit = invariant.Extrapolator(data=self.data)
-
- ##Without holding
- p, dp = fit.fit(power=None)
-
- # Test results
- self.assertAlmostEquals(p[0], 2.3983,3)
- self.assertAlmostEquals(p[1], 0.87833,3)
-
-
- def test_fit_line_data_fixed(self):
- """
- Fit_Test_2: test linear fit, ax +b, with 'a' fixed
- """
-
- # Create invariant object. Background and scale left as defaults.
- fit = invariant.Extrapolator(data=self.data)
-
- #With holding a = -power =4
- p, dp = fit.fit(power=-4)
-
- # Test results
- self.assertAlmostEquals(p[0], 4)
- self.assertAlmostEquals(p[1], -4.0676,3)
-
-class TestLineFitNoweight(unittest.TestCase):
- """
- Test Line fit without weight(dy data)
- """
- def setUp(self):
- self.data = Loader().load("linefittest_no_weight.txt")
-
- def skip_test_fit_line_data_no_weight(self):
- """
- Fit_Test_1: test linear fit, ax +b, without fixed
- """
-
- # Create invariant object. Background and scale left as defaults.
- fit = invariant.Extrapolator(data=self.data)
-
- ##Without holding
- p, dp = fit.fit(power=None)
-
- # Test results
- self.assertAlmostEquals(p[0], 2.4727,3)
- self.assertAlmostEquals(p[1], 0.6,3)
-
-
- def test_fit_line_data_fixed_no_weight(self):
- """
- Fit_Test_2: test linear fit, ax +b, with 'a' fixed
- """
-
- # Create invariant object. Background and scale left as defaults.
- fit = invariant.Extrapolator(data=self.data)
-
- #With holding a = -power =4
- p, dp = fit.fit(power=-4)
-
- # Test results
- self.assertAlmostEquals(p[0], 4)
- self.assertAlmostEquals(p[1], -7.8,3)
-
-class TestInvPolySphere(unittest.TestCase):
- """
- Test unsmeared data for invariant computation
- """
- def setUp(self):
- self.data = Loader().load("PolySpheres.txt")
-
- def test_wrong_data(self):
- """ test receiving Data1D not of type loader"""
-
-
- self.assertRaises(ValueError,invariant.InvariantCalculator, Data1D())
-
- def test_use_case_1(self):
- """
- Invariant without extrapolation
- """
- # Create invariant object. Background and scale left as defaults.
- inv = invariant.InvariantCalculator(data=self.data)
-
- # We have to be able to tell the InvariantCalculator whether we want the
- # extrapolation or not. By default, when the user doesn't specify, we
- # should compute Q* without extrapolation. That's what should be done in __init__.
-
- # We call get_qstar() with no argument, which signifies that we do NOT
- # want extrapolation.
- qstar = inv.get_qstar()
-
- # The volume fraction and surface use Q*. That means that the following
- # methods should check that Q* has been computed. If not, it should
- # compute it by calling get_qstare(), leaving the parameters as default.
- v, dv = inv.get_volume_fraction_with_error(contrast=2.6e-6)
- s, ds = inv.get_surface_with_error(contrast=2.6e-6, porod_const=2)
-
- # Test results
- self.assertAlmostEquals(qstar, 7.48959e-5,2)
- self.assertAlmostEquals(v, 0.005644689, 4)
- self.assertAlmostEquals(s , 941.7452, 3)
-
- def test_use_case_2(self):
- """
- Invariant without extrapolation. Invariant, volume fraction and surface
- are given with errors.
- """
- # Create invariant object. Background and scale left as defaults.
- inv = invariant.InvariantCalculator(data=self.data)
-
- # Get the invariant with errors
- qstar, qstar_err = inv.get_qstar_with_error()
-
- # The volume fraction and surface use Q*. That means that the following
- # methods should check that Q* has been computed. If not, it should
- # compute it by calling get_qstare(), leaving the parameters as default.
- v, dv = inv.get_volume_fraction_with_error(contrast=2.6e-6)
- s, ds = inv.get_surface_with_error(contrast=2.6e-6, porod_const=2)
- # Test results
- self.assertAlmostEquals(qstar, 7.48959e-5,2)
- self.assertAlmostEquals(v, 0.005644689, 1)
- self.assertAlmostEquals(s , 941.7452, 3)
-
-
- def test_use_case_3(self):
- """
- Invariant with low-Q extrapolation
- """
- # Create invariant object. Background and scale left as defaults.
- inv = invariant.InvariantCalculator(data=self.data)
-
- # Set the extrapolation parameters for the low-Q range
-
- # The npts parameter should have a good default.
- # The range parameter should be 'high' or 'low'
- # The function parameter should default to None. If it is None,
- # the method should pick a good default (Guinier at low-Q and 1/q^4 at high-Q).
- # The method should also check for consistency of the extrapolation and function
- # parameters. For instance, you might not want to allow 'high' and 'guinier'.
- # The power parameter (not shown below) should default to 4.
- inv.set_extrapolation(range='low', npts=10, function='guinier')
-
- # The version of the call without error
- # At this point, we could still compute Q* without extrapolation by calling
- # get_qstar with arguments, or with extrapolation=None.
- qstar = inv.get_qstar(extrapolation='low')
-
- # The version of the call with error
- qstar, qstar_err = inv.get_qstar_with_error(extrapolation='low')
-
- # Get the volume fraction and surface
- v, dv = inv.get_volume_fraction_with_error(contrast=2.6e-6)
- s, ds = inv.get_surface_with_error(contrast=2.6e-6, porod_const=2)
-
- # Test results
- self.assertAlmostEquals(qstar, 7.49e-5, 1)
- self.assertAlmostEquals(v, 0.005648401, 4)
- self.assertAlmostEquals(s , 941.7452, 3)
-
- def test_use_case_4(self):
- """
- Invariant with high-Q extrapolation
- """
- # Create invariant object. Background and scale left as defaults.
- inv = invariant.InvariantCalculator(data=self.data)
-
- # Set the extrapolation parameters for the high-Q range
- inv.set_extrapolation(range='high', npts=10, function='power_law', power=4)
-
- # The version of the call without error
- # The function parameter defaults to None, then is picked to be 'power_law' for extrapolation='high'
- qstar = inv.get_qstar(extrapolation='high')
-
- # The version of the call with error
- qstar, qstar_err = inv.get_qstar_with_error(extrapolation='high')
-
- # Get the volume fraction and surface
- v, dv = inv.get_volume_fraction_with_error(contrast=2.6e-6)
- s, ds = inv.get_surface_with_error(contrast=2.6e-6, porod_const=2)
-
- # Test results
- self.assertAlmostEquals(qstar, 7.49e-5,2)
- self.assertAlmostEquals(v, 0.005952674, 3)
- self.assertAlmostEquals(s , 941.7452, 3)
-
- def test_use_case_5(self):
- """
- Invariant with both high- and low-Q extrapolation
- """
- # Create invariant object. Background and scale left as defaults.
- inv = invariant.InvariantCalculator(data=self.data)
-
- # Set the extrapolation parameters for the low- and high-Q ranges
- inv.set_extrapolation(range='low', npts=10, function='guinier')
- inv.set_extrapolation(range='high', npts=10, function='power_law', power=4)
-
- # The version of the call without error
- # The function parameter defaults to None, then is picked to be 'power_law' for extrapolation='high'
- qstar = inv.get_qstar(extrapolation='both')
-
- # The version of the call with error
- qstar, qstar_err = inv.get_qstar_with_error(extrapolation='both')
-
- # Get the volume fraction and surface
- v, dv = inv.get_volume_fraction_with_error(contrast=2.6e-6)
- s, ds = inv.get_surface_with_error(contrast=2.6e-6, porod_const=2)
-
- # Test results
- self.assertAlmostEquals(qstar, 7.88981e-5,2)
- self.assertAlmostEquals(v, 0.005952674, 3)
- self.assertAlmostEquals(s , 941.7452, 3)
-
- def test_use_case_6(self):
- """
- Invariant with high-Q extrapolation
- """
- # Create invariant object. Background and scale left as defaults.
- inv = invariant.InvariantCalculator(data=self.data)
-
- # Set the extrapolation parameters for the high-Q range
- inv.set_extrapolation(range='low', npts=10, function='power_law', power=4)
-
- # The version of the call without error
- # The function parameter defaults to None, then is picked to be 'power_law' for extrapolation='high'
- qstar = inv.get_qstar(extrapolation='low')
-
- # The version of the call with error
- qstar, qstar_err = inv.get_qstar_with_error(extrapolation='low')
-
- # Get the volume fraction and surface
- v, dv = inv.get_volume_fraction_with_error(contrast=2.6e-6)
- s, ds = inv.get_surface_with_error(contrast=2.6e-6, porod_const=2)
-
- # Test results
- self.assertAlmostEquals(qstar, 7.49e-5,2)
- self.assertAlmostEquals(v, 0.005952674, 3)
- self.assertAlmostEquals(s , 941.7452, 3)
-
-class TestInvPinholeSmear(unittest.TestCase):
- """
- Test pinhole smeared data for invariant computation
- """
- def setUp(self):
- # data with smear info
- list = Loader().load("latex_smeared.xml")
- self.data_q_smear = list[0]
-
- def test_use_case_1(self):
- """
- Invariant without extrapolation
- """
- inv = invariant.InvariantCalculator(data=self.data_q_smear)
- qstar = inv.get_qstar()
-
- v = inv.get_volume_fraction(contrast=2.6e-6)
- s = inv.get_surface(contrast=2.6e-6, porod_const=2)
- # Test results
- self.assertAlmostEquals(qstar, 1.361677e-3, 4)
- self.assertAlmostEquals(v, 0.115352622, 2)
- self.assertAlmostEquals(s , 941.7452, 3 )
-
- def test_use_case_2(self):
- """
- Invariant without extrapolation. Invariant, volume fraction and surface
- are given with errors.
- """
- # Create invariant object. Background and scale left as defaults.
- inv = invariant.InvariantCalculator(data=self.data_q_smear)
-
- # Get the invariant with errors
- qstar, qstar_err = inv.get_qstar_with_error()
- # Get the volume fraction and surface
- v, dv = inv.get_volume_fraction_with_error(contrast=2.6e-6)
- s, ds = inv.get_surface_with_error(contrast=2.6e-6, porod_const=2)
- # Test results
- self.assertAlmostEquals(qstar, 1.361677e-3, 4)
- self.assertAlmostEquals(v, 0.115352622, 2)
- self.assertAlmostEquals(s , 941.7452, 3 )
-
- def test_use_case_3(self):
- """
- Invariant with low-Q extrapolation
- """
- # Create invariant object. Background and scale left as defaults.
- inv = invariant.InvariantCalculator(data=self.data_q_smear)
- # Set the extrapolation parameters for the low-Q range
- inv.set_extrapolation(range='low', npts=20, function='guinier')
- # The version of the call without error
- qstar = inv.get_qstar(extrapolation='low')
- # The version of the call with error
- qstar, qstar_err = inv.get_qstar_with_error(extrapolation='low')
- # Get the volume fraction and surface
- v, dv = inv.get_volume_fraction_with_error(contrast=2.6e-6)
- s, ds = inv.get_surface_with_error(contrast=2.6e-6, porod_const=2)
-
- # Test results
- self.assertAlmostEquals(qstar, 0.00138756,2)
- self.assertAlmostEquals(v, 0.117226896,2)
- self.assertAlmostEquals(s ,941.7452, 3)
-
- def test_use_case_4(self):
- """
- Invariant with high-Q extrapolation
- """
- # Create invariant object. Background and scale left as defaults.
- inv = invariant.InvariantCalculator(data=self.data_q_smear)
- # Set the extrapolation parameters for the high-Q range
- inv.set_extrapolation(range='high', npts=10, function='power_law', power=4)
- # The version of the call without error
- qstar = inv.get_qstar(extrapolation='high')
- # The version of the call with error
- qstar, qstar_err = inv.get_qstar_with_error(extrapolation='high')
-
- # Get the volume fraction and surface
- # WHY SHOULD THIS FAIL?
- #self.assertRaises(RuntimeError, inv.get_volume_fraction_with_error, 2.6e-6)
-
- # Check that an exception is raised when the 'surface' is not defined
- # WHY SHOULD THIS FAIL?
- #self.assertRaises(RuntimeError, inv.get_surface_with_error, 2.6e-6, 2)
-
- # Test results
- self.assertAlmostEquals(qstar, 0.0045773,2)
-
- def test_use_case_5(self):
- """
- Invariant with both high- and low-Q extrapolation
- """
- # Create invariant object. Background and scale left as defaults.
- inv = invariant.InvariantCalculator(data=self.data_q_smear)
- # Set the extrapolation parameters for the low- and high-Q ranges
- inv.set_extrapolation(range='low', npts=10, function='guinier')
- inv.set_extrapolation(range='high', npts=10, function='power_law', power=4)
- # The version of the call without error
- # The function parameter defaults to None, then is picked to be 'power_law' for extrapolation='high'
- qstar = inv.get_qstar(extrapolation='both')
- # The version of the call with error
- qstar, qstar_err = inv.get_qstar_with_error(extrapolation='both')
-
- # Get the volume fraction and surface
- # WHY SHOULD THIS FAIL?
- #self.assertRaises(RuntimeError, inv.get_volume_fraction_with_error, 2.6e-6)
- #self.assertRaises(RuntimeError, inv.get_surface_with_error, 2.6e-6, 2)
-
- # Test results
- self.assertAlmostEquals(qstar, 0.00460319,3)
-
-
-if __name__ == '__main__':
- unittest.main(testRunner=unittest.TextTestRunner(verbosity=2))
-
+"""
+ Implementation of the use-case from a usage perspective.
+
+"""
+#TODO: there's no test for smeared extrapolation
+import unittest
+from sas.sascalc.dataloader.loader import Loader
+from sas.sascalc.invariant import invariant
+
+
+class Data1D:
+ pass
+
+
+class TestLineFit(unittest.TestCase):
+ """
+ Test Line fit
+ """
+ def setUp(self):
+ self.data_list = Loader().load("linefittest.txt")
+ self.data = self.data_list[0]
+
+ def test_fit_line_data(self):
+ """
+ Fit_Test_1: test linear fit, ax +b, without fixed
+ """
+
+ # Create invariant object. Background and scale left as defaults.
+ fit = invariant.Extrapolator(data=self.data)
+
+ # Without holding
+ p, dp = fit.fit(power=None)
+
+ # Test results
+ self.assertAlmostEquals(p[0], 2.3983,3)
+ self.assertAlmostEquals(p[1], 0.87833,3)
+
+ def test_fit_line_data_fixed(self):
+ """
+ Fit_Test_2: test linear fit, ax +b, with 'a' fixed
+ """
+
+ # Create invariant object. Background and scale left as defaults.
+ fit = invariant.Extrapolator(data=self.data)
+
+ # With holding a = -power =4
+ p, dp = fit.fit(power=-4)
+
+ # Test results
+ self.assertAlmostEquals(p[0], 4)
+ self.assertAlmostEquals(p[1], -4.0676,3)
+
+
+class TestLineFitNoweight(unittest.TestCase):
+ """
+ Test Line fit without weight(dy data)
+ """
+ def setUp(self):
+ self.data_list = Loader().load("linefittest_no_weight.txt")
+ self.data = self.data_list[0]
+
+ def skip_test_fit_line_data_no_weight(self):
+ """
+ Fit_Test_1: test linear fit, ax +b, without fixed
+ """
+
+ # Create invariant object. Background and scale left as defaults.
+ fit = invariant.Extrapolator(data=self.data)
+
+ # Without holding
+ p, dp = fit.fit(power=None)
+
+ # Test results
+ self.assertAlmostEquals(p[0], 2.4727,3)
+ self.assertAlmostEquals(p[1], 0.6,3)
+
+ def test_fit_line_data_fixed_no_weight(self):
+ """
+ Fit_Test_2: test linear fit, ax +b, with 'a' fixed
+ """
+
+ # Create invariant object. Background and scale left as defaults.
+ fit = invariant.Extrapolator(data=self.data)
+
+ #With holding a = -power =4
+ p, dp = fit.fit(power=-4)
+
+ # Test results
+ self.assertAlmostEquals(p[0], 4)
+ self.assertAlmostEquals(p[1], -7.8,3)
+
+
+class TestInvPolySphere(unittest.TestCase):
+ """
+ Test unsmeared data for invariant computation
+ """
+ def setUp(self):
+ self.data_list = Loader().load("PolySpheres.txt")
+ self.data = self.data_list[0]
+
+ def test_wrong_data(self):
+ """ test receiving Data1D not of type loader"""
+ self.assertRaises(ValueError,invariant.InvariantCalculator, Data1D())
+
+ def test_use_case_1(self):
+ """
+ Invariant without extrapolation
+ """
+ # Create invariant object. Background and scale left as defaults.
+ inv = invariant.InvariantCalculator(data=self.data)
+
+ # We have to be able to tell the InvariantCalculator whether we want the
+ # extrapolation or not. By default, when the user doesn't specify, we
+ # should compute Q* without extrapolation. That's what should be done
+ # in __init__.
+
+ # We call get_qstar() with no argument, which signifies that we do NOT
+ # want extrapolation.
+ qstar = inv.get_qstar()
+
+ # The volume fraction and surface use Q*. That means that the following
+ # methods should check that Q* has been computed. If not, it should
+ # compute it by calling get_qstare(), leaving the parameters as default.
+ v, dv = inv.get_volume_fraction_with_error(contrast=2.6e-6)
+ s, ds = inv.get_surface_with_error(contrast=2.6e-6, porod_const=2)
+
+ # Test results
+ self.assertAlmostEquals(qstar, 7.48959e-5,2)
+ self.assertAlmostEquals(v, 0.005644689, 4)
+ self.assertAlmostEquals(s , 941.7452, 3)
+
+ def test_use_case_2(self):
+ """
+ Invariant without extrapolation. Invariant, volume fraction and surface
+ are given with errors.
+ """
+ # Create invariant object. Background and scale left as defaults.
+ inv = invariant.InvariantCalculator(data=self.data)
+
+ # Get the invariant with errors
+ qstar, qstar_err = inv.get_qstar_with_error()
+
+ # The volume fraction and surface use Q*. That means that the following
+ # methods should check that Q* has been computed. If not, it should
+ # compute it by calling get_qstare(), leaving the parameters as default.
+ v, dv = inv.get_volume_fraction_with_error(contrast=2.6e-6)
+ s, ds = inv.get_surface_with_error(contrast=2.6e-6, porod_const=2)
+ # Test results
+ self.assertAlmostEquals(qstar, 7.48959e-5,2)
+ self.assertAlmostEquals(v, 0.005644689, 1)
+ self.assertAlmostEquals(s , 941.7452, 3)
+
+ def test_use_case_3(self):
+ """
+ Invariant with low-Q extrapolation
+ """
+ # Create invariant object. Background and scale left as defaults.
+ inv = invariant.InvariantCalculator(data=self.data)
+
+ # Set the extrapolation parameters for the low-Q range
+
+ # The npts parameter should have a good default.
+ # The range parameter should be 'high' or 'low'
+ # The function parameter should default to None. If it is None,
+ # the method should pick a good default
+ # (Guinier at low-Q and 1/q^4 at high-Q).
+ # The method should also check for consistency of the extrapolation
+ # and function parameters. For instance, you might not want to allow
+ # 'high' and 'guinier'.
+ # The power parameter (not shown below) should default to 4.
+ inv.set_extrapolation(range='low', npts=10, function='guinier')
+
+ # The version of the call without error
+ # At this point, we could still compute Q* without extrapolation by
+ # calling get_qstar with arguments, or with extrapolation=None.
+ qstar = inv.get_qstar(extrapolation='low')
+
+ # The version of the call with error
+ qstar, qstar_err = inv.get_qstar_with_error(extrapolation='low')
+
+ # Get the volume fraction and surface
+ v, dv = inv.get_volume_fraction_with_error(contrast=2.6e-6)
+ s, ds = inv.get_surface_with_error(contrast=2.6e-6, porod_const=2)
+
+ # Test results
+ self.assertAlmostEquals(qstar, 7.49e-5, 1)
+ self.assertAlmostEquals(v, 0.005648401, 4)
+ self.assertAlmostEquals(s , 941.7452, 3)
+
+ def test_use_case_4(self):
+ """
+ Invariant with high-Q extrapolation
+ """
+ # Create invariant object. Background and scale left as defaults.
+ inv = invariant.InvariantCalculator(data=self.data)
+
+ # Set the extrapolation parameters for the high-Q range
+ inv.set_extrapolation(range='high', npts=10, function='power_law',
+ power=4)
+
+ # The version of the call without error
+ # The function parameter defaults to None, then is picked to be
+ # 'power_law' for extrapolation='high'
+ qstar = inv.get_qstar(extrapolation='high')
+
+ # The version of the call with error
+ qstar, qstar_err = inv.get_qstar_with_error(extrapolation='high')
+
+ # Get the volume fraction and surface
+ v, dv = inv.get_volume_fraction_with_error(contrast=2.6e-6)
+ s, ds = inv.get_surface_with_error(contrast=2.6e-6, porod_const=2)
+
+ # Test results
+ self.assertAlmostEquals(qstar, 7.49e-5,2)
+ self.assertAlmostEquals(v, 0.005952674, 3)
+ self.assertAlmostEquals(s , 941.7452, 3)
+
+ def test_use_case_5(self):
+ """
+ Invariant with both high- and low-Q extrapolation
+ """
+ # Create invariant object. Background and scale left as defaults.
+ inv = invariant.InvariantCalculator(data=self.data)
+
+ # Set the extrapolation parameters for the low- and high-Q ranges
+ inv.set_extrapolation(range='low', npts=10, function='guinier')
+ inv.set_extrapolation(range='high', npts=10, function='power_law',
+ power=4)
+
+ # The version of the call without error
+ # The function parameter defaults to None, then is picked to be
+ # 'power_law' for extrapolation='high'
+ qstar = inv.get_qstar(extrapolation='both')
+
+ # The version of the call with error
+ qstar, qstar_err = inv.get_qstar_with_error(extrapolation='both')
+
+ # Get the volume fraction and surface
+ v, dv = inv.get_volume_fraction_with_error(contrast=2.6e-6)
+ s, ds = inv.get_surface_with_error(contrast=2.6e-6, porod_const=2)
+
+ # Test results
+ self.assertAlmostEquals(qstar, 7.88981e-5,2)
+ self.assertAlmostEquals(v, 0.005952674, 3)
+ self.assertAlmostEquals(s , 941.7452, 3)
+
+ def test_use_case_6(self):
+ """
+ Invariant with high-Q extrapolation
+ """
+ # Create invariant object. Background and scale left as defaults.
+ inv = invariant.InvariantCalculator(data=self.data)
+
+ # Set the extrapolation parameters for the high-Q range
+ inv.set_extrapolation(range='low', npts=10, function='power_law', power=4)
+
+ # The version of the call without error
+ # The function parameter defaults to None, then is picked to be 'power_law' for extrapolation='high'
+ qstar = inv.get_qstar(extrapolation='low')
+
+ # The version of the call with error
+ qstar, qstar_err = inv.get_qstar_with_error(extrapolation='low')
+
+ # Get the volume fraction and surface
+ v, dv = inv.get_volume_fraction_with_error(contrast=2.6e-6)
+ s, ds = inv.get_surface_with_error(contrast=2.6e-6, porod_const=2)
+
+ # Test results
+ self.assertAlmostEquals(qstar, 7.49e-5,2)
+ self.assertAlmostEquals(v, 0.005952674, 3)
+ self.assertAlmostEquals(s , 941.7452, 3)
+
+
+class TestInvPinholeSmear(unittest.TestCase):
+ """
+ Test pinhole smeared data for invariant computation
+ """
+ def setUp(self):
+ # data with smear info
+ list = Loader().load("latex_smeared.xml")
+ self.data_q_smear = list[0]
+
+ def test_use_case_1(self):
+ """
+ Invariant without extrapolation
+ """
+ inv = invariant.InvariantCalculator(data=self.data_q_smear)
+ qstar = inv.get_qstar()
+
+ v = inv.get_volume_fraction(contrast=2.6e-6)
+ s = inv.get_surface(contrast=2.6e-6, porod_const=2)
+ # Test results
+ self.assertAlmostEquals(qstar, 1.361677e-3, 4)
+ self.assertAlmostEquals(v, 0.115352622, 2)
+ self.assertAlmostEquals(s , 941.7452, 3 )
+
+ def test_use_case_2(self):
+ """
+ Invariant without extrapolation. Invariant, volume fraction and surface
+ are given with errors.
+ """
+ # Create invariant object. Background and scale left as defaults.
+ inv = invariant.InvariantCalculator(data=self.data_q_smear)
+
+ # Get the invariant with errors
+ qstar, qstar_err = inv.get_qstar_with_error()
+ # Get the volume fraction and surface
+ v, dv = inv.get_volume_fraction_with_error(contrast=2.6e-6)
+ s, ds = inv.get_surface_with_error(contrast=2.6e-6, porod_const=2)
+ # Test results
+ self.assertAlmostEquals(qstar, 1.361677e-3, 4)
+ self.assertAlmostEquals(v, 0.115352622, 2)
+ self.assertAlmostEquals(s , 941.7452, 3 )
+
+ def test_use_case_3(self):
+ """
+ Invariant with low-Q extrapolation
+ """
+ # Create invariant object. Background and scale left as defaults.
+ inv = invariant.InvariantCalculator(data=self.data_q_smear)
+ # Set the extrapolation parameters for the low-Q range
+ inv.set_extrapolation(range='low', npts=20, function='guinier')
+ # The version of the call without error
+ qstar = inv.get_qstar(extrapolation='low')
+ # The version of the call with error
+ qstar, qstar_err = inv.get_qstar_with_error(extrapolation='low')
+ # Get the volume fraction and surface
+ v, dv = inv.get_volume_fraction_with_error(contrast=2.6e-6)
+ s, ds = inv.get_surface_with_error(contrast=2.6e-6, porod_const=2)
+
+ # Test results
+ self.assertAlmostEquals(qstar, 0.00138756,2)
+ self.assertAlmostEquals(v, 0.117226896,2)
+ self.assertAlmostEquals(s ,941.7452, 3)
+
+ def test_use_case_4(self):
+ """
+ Invariant with high-Q extrapolation
+ """
+ # Create invariant object. Background and scale left as defaults.
+ inv = invariant.InvariantCalculator(data=self.data_q_smear)
+ # Set the extrapolation parameters for the high-Q range
+ inv.set_extrapolation(range='high', npts=10, function='power_law', power=4)
+ # The version of the call without error
+ qstar = inv.get_qstar(extrapolation='high')
+ # The version of the call with error
+ qstar, qstar_err = inv.get_qstar_with_error(extrapolation='high')
+
+ # Test results
+ self.assertAlmostEquals(qstar, 0.0045773,2)
+
+ def test_use_case_5(self):
+ """
+ Invariant with both high- and low-Q extrapolation
+ """
+ # Create invariant object. Background and scale left as defaults.
+ inv = invariant.InvariantCalculator(data=self.data_q_smear)
+ # Set the extrapolation parameters for the low- and high-Q ranges
+ inv.set_extrapolation(range='low', npts=10, function='guinier')
+ inv.set_extrapolation(range='high', npts=10, function='power_law',
+ power=4)
+ # The version of the call without error
+ # The function parameter defaults to None, then is picked to be
+ # 'power_law' for extrapolation='high'
+ qstar = inv.get_qstar(extrapolation='both')
+ # The version of the call with error
+ qstar, qstar_err = inv.get_qstar_with_error(extrapolation='both')
+
+ # Test results
+ self.assertAlmostEquals(qstar, 0.00460319,3)
+
+
+if __name__ == '__main__':
+ unittest.main(testRunner=unittest.TextTestRunner(verbosity=2))
+
diff --git a/src/sas/__init__.py b/test/sasrealspace/__init__.py
similarity index 100%
copy from src/sas/__init__.py
copy to test/sasrealspace/__init__.py
diff --git a/src/sas/__init__.py b/test/sasrealspace/test/__init__.py
similarity index 100%
copy from src/sas/__init__.py
copy to test/sasrealspace/test/__init__.py
diff --git a/test/sasrealspace/test/early_test.py b/test/sasrealspace/test/early_test.py
index 386908a..583a921 100644
--- a/test/sasrealspace/test/early_test.py
+++ b/test/sasrealspace/test/early_test.py
@@ -1,294 +1,295 @@
-
-import VolumeCanvas
-from sas.models.SphereModel import SphereModel
-from sas.models.CoreShellModel import CoreShellModel
-
-import math, time
-
-def form_factor(q, r):
- qr = q*r
- f = 3*( math.sin(qr) - qr*math.cos(qr) ) / (qr*qr*qr)
- return f*f
-
-def test_1():
-
- radius = 15
-
- density = .1
- vol = 4/3*math.pi*radius*radius*radius
- npts = vol*density
-
- canvas = VolumeCanvas.VolumeCanvas()
- canvas.setParam('lores_density', density)
- handle = canvas.add('sphere')
- canvas.setParam('%s.radius' % handle, radius)
- canvas.setParam('%s.contrast' % handle, 1.0)
-
-
- if False:
- # Time test
- t_0 = time.time()
- value_1 = 1.0e8*canvas.getIq(0.1)
- print "density = 0.1: output=%g time=%g" % (value_1, time.time()-t_0)
-
- t_0 = time.time()
- canvas.setParam('lores_density', 1)
- value_1 = 1.0e8*canvas.getIq(0.1)
- print "density = 1000: output=%g time=%g" % (value_1, time.time()-t_0)
-
- t_0 = time.time()
- canvas.setParam('lores_density', 0.01)
- value_1 = 1.0e8*canvas.getIq(0.1)
- print "density = 0.00001: output=%g time=%g" % (value_1, time.time()-t_0)
- print
-
-
- sphere = SphereModel()
- sphere.setParam('radius', radius)
- sphere.setParam('scale', 1.0)
- sphere.setParam('contrast', 1.0)
-
-
- # Simple sphere sum(Pr) = (rho*V)^2
- # each p(r) point has a volume of 1/density
-
- for i in range(35):
- q = 0.001 + 0.01*i
-
-
-
- #sim_1 = 1.0e8*canvas.getIq(q)*4/3*math.pi/(density*density*density)
- sim_1 = canvas.getIq(q)
- ana_1 = sphere.run(q)
- #ana_1 = form_factor(q, radius)
-
- print "q=%g sim=%g ana=%g ratio=%g" % (q, sim_1, ana_1, sim_1/ana_1)
-
-def test_2():
- radius = 15.0
- thickness = 5.0
-
- core_vol = 4.0/3.0*math.pi*radius*radius*radius
- outer_radius = radius+thickness
- shell_vol = 4.0/3.0*math.pi*outer_radius*outer_radius*outer_radius - core_vol
- shell_sld = -1.0*core_vol/shell_vol
- print "Shell SLD", shell_sld
-
-
- density = .1
- vol = 4/3*math.pi*radius*radius*radius
- npts = vol*density
-
- canvas = VolumeCanvas.VolumeCanvas()
- canvas.setParam('lores_density', density)
- handle = canvas.add('sphere')
- canvas.setParam('%s.radius' % handle, outer_radius)
- canvas.setParam('%s.contrast' % handle, shell_sld)
-
- handle2 = canvas.add('sphere')
- canvas.setParam('%s.radius' % handle2, radius)
- canvas.setParam('%s.contrast' % handle2, 1.0)
-
-
-
- # Core-shell
- sphere = CoreShellModel()
- # Core radius
- sphere.setParam('radius', radius)
- # Shell thickness
- sphere.setParam('thickness', thickness)
- sphere.setParam('core_sld', 1.0)
-
-
- sphere.setParam('shell_sld', shell_sld)
- sphere.setParam('solvent_sld',0.0)
- sphere.setParam('background',0.0)
- sphere.setParam('scale',1.0)
-
- out = open("lores_test.txt",'w')
- out.write("<q> <sim> <ana>\n")
-
- for i in range(65):
- q = 0.001 + 0.01*i
-
- # For each volume integral that we change to a sum,
- # we must multiply by 1/density = V/N
- # Since we want P(r)/V, we will need to multiply
- # the sum by 1/(N*density), where N is the number of
- # points without overlap. Since we already divide
- # by N when calculating I(q), we only need to divide
- # by the density here. We divide by N in the
- # calculation because it is difficult to estimate it here.
-
-
- # Put the factor 2 in the simulation two...
- sim_1 = canvas.getIq(q)
- ana_1 = sphere.run(q)
-
- print "q=%g sim=%g ana=%g ratio=%g" % (q, sim_1, ana_1, sim_1/ana_1)
- out.write( "%g %g %g\n" % (q, sim_1, ana_1))
-
- out.close()
-
-def test_4():
- radius = 15
-
- density = .1
- vol = 4/3*math.pi*radius*radius*radius
- npts = vol*density
-
-
- canvas = VolumeCanvas.VolumeCanvas()
- canvas.setParam('lores_density', density)
- #handle = canvas.add('sphere')
- #canvas.setParam('%s.radius' % handle, radius)
- #canvas.setParam('%s.contrast' % handle, 1.0)
-
- pdb = canvas.add('test.pdb')
-
-
-
- sphere = SphereModel()
- sphere.setParam('radius', radius)
- sphere.setParam('scale', 1.0)
- sphere.setParam('contrast', 1.0)
-
-
- # Simple sphere sum(Pr) = (rho*V)^2
- # each p(r) point has a volume of 1/density
-
- for i in range(35):
- q = 0.001 + 0.01*i
-
-
-
- #sim_1 = 1.0e8*canvas.getIq(q)*4/3*math.pi/(density*density*density)
- sim_1 = canvas.getIq(q)
- ana_1 = sphere.run(q)
- #ana_1 = form_factor(q, radius)
-
- print "q=%g sim=%g ana=%g ratio=%g" % (q, sim_1, ana_1, sim_1/ana_1)
-
-def test_5():
- from sas.models.SphereModel import SphereModel
- model = VolumeCanvas.VolumeCanvas()
-
- handle = model.add('sphere')
-
- radius = 10
- density = .1
-
- ana = SphereModel()
- ana.setParam('scale', 1.0)
- ana.setParam('contrast', 1.0)
- ana.setParam('background', 0.0)
- ana.setParam('radius', radius)
-
- model.setParam('lores_density', density)
- model.setParam('%s.radius' % handle, radius)
- model.setParam('scale' , 1.0)
- model.setParam('%s.contrast' % handle, 1.0)
- model.setParam('background' , 0.0)
-
- ana = ana.runXY([0.1, 0.1])
- sim = model.getIq2D(0.1, 0.1)
- print ana, sim, sim/ana, ana/sim
-
-def test_6():
- from sas.models.CylinderModel import CylinderModel
- radius = 5
- length = 40
- density = 20
-
- ana = CylinderModel()
- ana.setParam('scale', 1.0)
- ana.setParam('contrast', 1.0)
- ana.setParam('background', 0.0)
- ana.setParam('radius', radius)
- ana.setParam('length', length)
-
- # Along Y
- ana.setParam('cyl_theta', 1.57)
- ana.setParam('cyl_phi', 1.57)
-
- # Along Z
- #ana.setParam('cyl_theta', 0)
- #ana.setParam('cyl_phi', 0)
-
- model = VolumeCanvas.VolumeCanvas()
- handle = model.add('cylinder')
- model.setParam('lores_density', density)
- model.setParam('%s.radius' % handle, radius)
- model.setParam('%s.length' % handle, length)
- model.setParam('scale' , 1.0)
- model.setParam('%s.contrast' % handle, 1.0)
- model.setParam('background' , 0.0)
-
- # Along Y
- model.setParam('%s.orientation' % handle, [0,0,0])
-
- # Along Z
- #model.setParam('%s.orientation' % handle, [1.57,0,0])
-
-
- print model.npts
- for i in range(40):
- qmax = 0.5
- anaX = ana.runXY([qmax*i/40.0, 0.0])
- simX = model.getIq2D(qmax*i/40.0, 0.0)
-
- anaY = ana.runXY([0, qmax*i/40.0])
- simY = model.getIq2D(0, qmax*i/40.0)
- print anaX, simX, simX/anaX, '|', anaY, simY, simY/anaY
-
-def test_7():
- from sas.models.CoreShellModel import CoreShellModel
- print "Testing core-shell"
- radius = 15
- thickness = 5
- density = 5
-
- core_vol = 4.0/3.0*math.pi*radius*radius*radius
- outer_radius = radius+thickness
- shell_vol = 4.0/3.0*math.pi*outer_radius*outer_radius*outer_radius - core_vol
- shell_sld = -1.0*core_vol/shell_vol
-
- # Core-shell
- sphere = CoreShellModel()
- # Core radius
- sphere.setParam('radius', radius)
- # Shell thickness
- sphere.setParam('thickness', thickness)
- sphere.setParam('core_sld', 1.0)
- sphere.setParam('shell_sld', shell_sld)
- sphere.setParam('solvent_sld', 0.0)
- sphere.setParam('background', 0.0)
- sphere.setParam('scale', 1.0)
- ana = sphere
-
- canvas = VolumeCanvas.VolumeCanvas()
- canvas.setParam('lores_density', density)
-
- handle = canvas.add('sphere')
- canvas.setParam('%s.radius' % handle, outer_radius)
- canvas.setParam('%s.contrast' % handle, shell_sld)
-
- handle2 = canvas.add('sphere')
- canvas.setParam('%s.radius' % handle2, radius)
- canvas.setParam('%s.contrast' % handle2, 1.0)
-
- canvas.setParam('scale' , 1.0)
- canvas.setParam('background' , 0.0)
-
-
- """ Testing default core-shell orientation """
- qlist = [.0001, 0.002, .01, .1, 1.0, 5.]
- for q in qlist:
- ana_val = ana.runXY([q, 0.2])
- sim_val, err = canvas.getIq2DError(q, 0.2)
- print ana_val, sim_val, sim_val/ana_val, err, (sim_val-ana_val)/err
-
-
-
-if __name__ == "__main__":
- test_6()
+from __future__ import print_function
+
+import VolumeCanvas
+from sas.models.SphereModel import SphereModel
+from sas.models.CoreShellModel import CoreShellModel
+
+import math, time
+
+def form_factor(q, r):
+ qr = q*r
+ f = 3*( math.sin(qr) - qr*math.cos(qr) ) / (qr*qr*qr)
+ return f*f
+
+def test_1():
+
+ radius = 15
+
+ density = .1
+ vol = 4/3*math.pi*radius*radius*radius
+ npts = vol*density
+
+ canvas = VolumeCanvas.VolumeCanvas()
+ canvas.setParam('lores_density', density)
+ handle = canvas.add('sphere')
+ canvas.setParam('%s.radius' % handle, radius)
+ canvas.setParam('%s.contrast' % handle, 1.0)
+
+
+ if False:
+ # Time test
+ t_0 = time.time()
+ value_1 = 1.0e8*canvas.getIq(0.1)
+ print("density = 0.1: output=%g time=%g" % (value_1, time.time()-t_0))
+
+ t_0 = time.time()
+ canvas.setParam('lores_density', 1)
+ value_1 = 1.0e8*canvas.getIq(0.1)
+ print("density = 1000: output=%g time=%g" % (value_1, time.time()-t_0))
+
+ t_0 = time.time()
+ canvas.setParam('lores_density', 0.01)
+ value_1 = 1.0e8*canvas.getIq(0.1)
+ print("density = 0.00001: output=%g time=%g" % (value_1, time.time()-t_0))
+ print()
+
+
+ sphere = SphereModel()
+ sphere.setParam('radius', radius)
+ sphere.setParam('scale', 1.0)
+ sphere.setParam('contrast', 1.0)
+
+
+ # Simple sphere sum(Pr) = (rho*V)^2
+ # each p(r) point has a volume of 1/density
+
+ for i in range(35):
+ q = 0.001 + 0.01*i
+
+
+
+ #sim_1 = 1.0e8*canvas.getIq(q)*4/3*math.pi/(density*density*density)
+ sim_1 = canvas.getIq(q)
+ ana_1 = sphere.run(q)
+ #ana_1 = form_factor(q, radius)
+
+ print("q=%g sim=%g ana=%g ratio=%g" % (q, sim_1, ana_1, sim_1/ana_1))
+
+def test_2():
+ radius = 15.0
+ thickness = 5.0
+
+ core_vol = 4.0/3.0*math.pi*radius*radius*radius
+ outer_radius = radius+thickness
+ shell_vol = 4.0/3.0*math.pi*outer_radius*outer_radius*outer_radius - core_vol
+ shell_sld = -1.0*core_vol/shell_vol
+ print("Shell SLD", shell_sld)
+
+
+ density = .1
+ vol = 4/3*math.pi*radius*radius*radius
+ npts = vol*density
+
+ canvas = VolumeCanvas.VolumeCanvas()
+ canvas.setParam('lores_density', density)
+ handle = canvas.add('sphere')
+ canvas.setParam('%s.radius' % handle, outer_radius)
+ canvas.setParam('%s.contrast' % handle, shell_sld)
+
+ handle2 = canvas.add('sphere')
+ canvas.setParam('%s.radius' % handle2, radius)
+ canvas.setParam('%s.contrast' % handle2, 1.0)
+
+
+
+ # Core-shell
+ sphere = CoreShellModel()
+ # Core radius
+ sphere.setParam('radius', radius)
+ # Shell thickness
+ sphere.setParam('thickness', thickness)
+ sphere.setParam('core_sld', 1.0)
+
+
+ sphere.setParam('shell_sld', shell_sld)
+ sphere.setParam('solvent_sld',0.0)
+ sphere.setParam('background',0.0)
+ sphere.setParam('scale',1.0)
+
+ out = open("lores_test.txt",'w')
+ out.write("<q> <sim> <ana>\n")
+
+ for i in range(65):
+ q = 0.001 + 0.01*i
+
+ # For each volume integral that we change to a sum,
+ # we must multiply by 1/density = V/N
+ # Since we want P(r)/V, we will need to multiply
+ # the sum by 1/(N*density), where N is the number of
+ # points without overlap. Since we already divide
+ # by N when calculating I(q), we only need to divide
+ # by the density here. We divide by N in the
+ # calculation because it is difficult to estimate it here.
+
+
+ # Put the factor 2 in the simulation two...
+ sim_1 = canvas.getIq(q)
+ ana_1 = sphere.run(q)
+
+ print("q=%g sim=%g ana=%g ratio=%g" % (q, sim_1, ana_1, sim_1/ana_1))
+ out.write( "%g %g %g\n" % (q, sim_1, ana_1))
+
+ out.close()
+
+def test_4():
+ radius = 15
+
+ density = .1
+ vol = 4/3*math.pi*radius*radius*radius
+ npts = vol*density
+
+
+ canvas = VolumeCanvas.VolumeCanvas()
+ canvas.setParam('lores_density', density)
+ #handle = canvas.add('sphere')
+ #canvas.setParam('%s.radius' % handle, radius)
+ #canvas.setParam('%s.contrast' % handle, 1.0)
+
+ pdb = canvas.add('test.pdb')
+
+
+
+ sphere = SphereModel()
+ sphere.setParam('radius', radius)
+ sphere.setParam('scale', 1.0)
+ sphere.setParam('contrast', 1.0)
+
+
+ # Simple sphere sum(Pr) = (rho*V)^2
+ # each p(r) point has a volume of 1/density
+
+ for i in range(35):
+ q = 0.001 + 0.01*i
+
+
+
+ #sim_1 = 1.0e8*canvas.getIq(q)*4/3*math.pi/(density*density*density)
+ sim_1 = canvas.getIq(q)
+ ana_1 = sphere.run(q)
+ #ana_1 = form_factor(q, radius)
+
+ print("q=%g sim=%g ana=%g ratio=%g" % (q, sim_1, ana_1, sim_1/ana_1))
+
+def test_5():
+ from sas.models.SphereModel import SphereModel
+ model = VolumeCanvas.VolumeCanvas()
+
+ handle = model.add('sphere')
+
+ radius = 10
+ density = .1
+
+ ana = SphereModel()
+ ana.setParam('scale', 1.0)
+ ana.setParam('contrast', 1.0)
+ ana.setParam('background', 0.0)
+ ana.setParam('radius', radius)
+
+ model.setParam('lores_density', density)
+ model.setParam('%s.radius' % handle, radius)
+ model.setParam('scale' , 1.0)
+ model.setParam('%s.contrast' % handle, 1.0)
+ model.setParam('background' , 0.0)
+
+ ana = ana.runXY([0.1, 0.1])
+ sim = model.getIq2D(0.1, 0.1)
+ print(ana, sim, sim/ana, ana/sim)
+
+def test_6():
+ from sas.models.CylinderModel import CylinderModel
+ radius = 5
+ length = 40
+ density = 20
+
+ ana = CylinderModel()
+ ana.setParam('scale', 1.0)
+ ana.setParam('contrast', 1.0)
+ ana.setParam('background', 0.0)
+ ana.setParam('radius', radius)
+ ana.setParam('length', length)
+
+ # Along Y
+ ana.setParam('cyl_theta', 1.57)
+ ana.setParam('cyl_phi', 1.57)
+
+ # Along Z
+ #ana.setParam('cyl_theta', 0)
+ #ana.setParam('cyl_phi', 0)
+
+ model = VolumeCanvas.VolumeCanvas()
+ handle = model.add('cylinder')
+ model.setParam('lores_density', density)
+ model.setParam('%s.radius' % handle, radius)
+ model.setParam('%s.length' % handle, length)
+ model.setParam('scale' , 1.0)
+ model.setParam('%s.contrast' % handle, 1.0)
+ model.setParam('background' , 0.0)
+
+ # Along Y
+ model.setParam('%s.orientation' % handle, [0,0,0])
+
+ # Along Z
+ #model.setParam('%s.orientation' % handle, [1.57,0,0])
+
+
+ print(model.npts)
+ for i in range(40):
+ qmax = 0.5
+ anaX = ana.runXY([qmax*i/40.0, 0.0])
+ simX = model.getIq2D(qmax*i/40.0, 0.0)
+
+ anaY = ana.runXY([0, qmax*i/40.0])
+ simY = model.getIq2D(0, qmax*i/40.0)
+ print(anaX, simX, simX/anaX, '|', anaY, simY, simY/anaY)
+
+def test_7():
+ from sas.models.CoreShellModel import CoreShellModel
+ print("Testing core-shell")
+ radius = 15
+ thickness = 5
+ density = 5
+
+ core_vol = 4.0/3.0*math.pi*radius*radius*radius
+ outer_radius = radius+thickness
+ shell_vol = 4.0/3.0*math.pi*outer_radius*outer_radius*outer_radius - core_vol
+ shell_sld = -1.0*core_vol/shell_vol
+
+ # Core-shell
+ sphere = CoreShellModel()
+ # Core radius
+ sphere.setParam('radius', radius)
+ # Shell thickness
+ sphere.setParam('thickness', thickness)
+ sphere.setParam('core_sld', 1.0)
+ sphere.setParam('shell_sld', shell_sld)
+ sphere.setParam('solvent_sld', 0.0)
+ sphere.setParam('background', 0.0)
+ sphere.setParam('scale', 1.0)
+ ana = sphere
+
+ canvas = VolumeCanvas.VolumeCanvas()
+ canvas.setParam('lores_density', density)
+
+ handle = canvas.add('sphere')
+ canvas.setParam('%s.radius' % handle, outer_radius)
+ canvas.setParam('%s.contrast' % handle, shell_sld)
+
+ handle2 = canvas.add('sphere')
+ canvas.setParam('%s.radius' % handle2, radius)
+ canvas.setParam('%s.contrast' % handle2, 1.0)
+
+ canvas.setParam('scale' , 1.0)
+ canvas.setParam('background' , 0.0)
+
+
+ """ Testing default core-shell orientation """
+ qlist = [.0001, 0.002, .01, .1, 1.0, 5.]
+ for q in qlist:
+ ana_val = ana.runXY([q, 0.2])
+ sim_val, err = canvas.getIq2DError(q, 0.2)
+ print(ana_val, sim_val, sim_val/ana_val, err, (sim_val-ana_val)/err)
+
+
+
+if __name__ == "__main__":
+ test_6()
diff --git a/test/sasrealspace/test/sim_validation.py b/test/sasrealspace/test/sim_validation.py
index 140b92b..ff02349 100644
--- a/test/sasrealspace/test/sim_validation.py
+++ b/test/sasrealspace/test/sim_validation.py
@@ -1,344 +1,346 @@
-"""
- Validation tests for real-space simulation of I(q)
-
- @copyright: University of Tennessee, 2007
- @license: This software is provided as part of the DANSE project
-"""
-import math, time, pylab
-
-try:
- import VolumeCanvas
- print "Testing local version"
-except:
- print "Testing installed version"
- import sas.sascalc.realspace.VolumeCanvas as VolumeCanvas
-
-class Validator:
-
- def __init__(self):
- self.density = 0.1
- self.canvas = None
- self.ana = None
- self.create()
-
- def create(self):
- pass
-
- def run_sim2D(self, qx, qy, density=None):
- """
- Calculate the mean and error of the simulation
- @param q: q-value to calculate at
- @param density: point density of simulation
- #return: mean, error
- """
- if not density == None:
- self.density = density
- self.create()
-
- return self.canvas.getIq2DError(qx, qy)
-
- def run_sim(self, q, density=None):
- """
- Calculate the mean and error of the simulation
- @param q: q-value to calculate at
- @param density: point density of simulation
- #return: mean, error
- """
- if not density == None:
- self.density = density
- self.create()
-
- return self.canvas.getIqError(q)
-
- def run_ana2D(self, qx, qy):
- """
- Return analytical value
- @param q: q-value to evaluate at [float]
- @return: analytical output [float]
- """
- return self.ana.runXY([qx, qy])
-
- def run_ana(self, q):
- """
- Return analytical value
- @param q: q-value to evaluate at [float]
- @return: analytical output [float]
- """
- return self.ana.run(q)
-
-class SphereValidator(Validator):
-
- def __init__(self, radius=15, density = 0.01):
- from sas.models.SphereModel import SphereModel
-
- self.name = 'sphere'
- self.radius = radius
- self.density = density
-
- self.ana = SphereModel()
- self.ana.setParam('scale', 1.0)
- self.ana.setParam('contrast', 1.0)
- self.ana.setParam('background', 0.0)
- self.ana.setParam('radius', radius)
- self.create()
-
- def create(self):
- canvas = VolumeCanvas.VolumeCanvas()
- canvas.setParam('lores_density', self.density)
- handle = canvas.add('sphere')
- canvas.setParam('%s.radius' % handle, self.radius)
- canvas.setParam('scale' , 1.0)
- canvas.setParam('%s.contrast' % handle, 1.0)
- canvas.setParam('background' , 0.0)
- self.canvas = canvas
-
-class CylinderValidator(Validator):
-
- def __init__(self, radius=15, length=100, density = 0.01):
- from sas.models.CylinderModel import CylinderModel
-
- self.name = 'cylinder'
- self.radius = radius
- self.length = length
- self.density = density
-
- self.ana = CylinderModel()
- self.ana.setParam('scale', 1.0)
- self.ana.setParam('contrast', 1.0)
- self.ana.setParam('background', 0.0)
- self.ana.setParam('radius', radius)
- self.ana.setParam('length', length)
- self.ana.setParam('cyl_theta', math.pi/2.0)
- self.ana.setParam('cyl_phi', math.pi/2.0)
- self.create()
-
- def create(self):
- canvas = VolumeCanvas.VolumeCanvas()
- canvas.setParam('lores_density', self.density)
- handle = canvas.add('cylinder')
- canvas.setParam('%s.radius' % handle, self.radius)
- canvas.setParam('%s.length' % handle, self.length)
- canvas.setParam('scale' , 1.0)
- canvas.setParam('%s.contrast' % handle, 1.0)
- canvas.setParam('background' , 0.0)
- self.canvas = canvas
-
-class EllipsoidValidator(Validator):
-
- def __init__(self, radius_a=60, radius_b=10, density = 0.01):
- from sas.models.EllipsoidModel import EllipsoidModel
- #from sas.models.SphereModel import SphereModel
-
- self.name = 'ellipsoid'
- self.radius_a = radius_a
- self.radius_b = radius_b
- self.density = density
-
- self.ana = EllipsoidModel()
- #self.ana = SphereModel()
- self.ana.setParam('scale', 1.0)
- self.ana.setParam('contrast', 1.0)
- self.ana.setParam('background', 0.0)
- self.ana.setParam('radius_a', radius_a)
- self.ana.setParam('radius_b', radius_b)
- #self.ana.setParam('radius', radius_a)
-
- # Default orientation is there=1.57, phi=0
- # Radius_a is along the x direction
-
- self.create()
-
- def create(self):
- canvas = VolumeCanvas.VolumeCanvas()
- canvas.setParam('lores_density', self.density)
- handle = canvas.add('ellipsoid')
- canvas.setParam('%s.radius_x' % handle, self.radius_a)
- canvas.setParam('%s.radius_y' % handle, self.radius_b)
- canvas.setParam('%s.radius_z' % handle, self.radius_b)
- canvas.setParam('scale' , 1.0)
- canvas.setParam('%s.contrast' % handle, 1.0)
- canvas.setParam('background' , 0.0)
- self.canvas = canvas
-
-class HelixValidator(Validator):
-
- def __init__(self, density = 0.01):
- self.name = 'helix'
- self.density = density
- self.create()
-
- def create(self):
- canvas = VolumeCanvas.VolumeCanvas()
- canvas.setParam('lores_density', self.density)
- handle = canvas.add('singlehelix')
- canvas.setParam('scale' , 1.0)
- canvas.setParam('%s.contrast' % handle, 1.0)
- canvas.setParam('background' , 0.0)
- self.canvas = canvas
- # just to write the parameters to the output file
- self.ana = canvas
-
- def run_ana(self, q):
- return 1
-
-
-class CoreShellValidator(Validator):
-
- def __init__(self, radius=15, thickness=5, density = 0.01):
- from sas.models.CoreShellModel import CoreShellModel
-
- self.name = 'coreshell'
- self.radius = radius
-
- core_vol = 4.0/3.0*math.pi*radius*radius*radius
- self.outer_radius = radius+thickness
- shell_vol = 4.0/3.0*math.pi*self.outer_radius*self.outer_radius*self.outer_radius - core_vol
- self.shell_sld = -1.0*core_vol/shell_vol
-
- self.density = density
-
- # Core-shell
- sphere = CoreShellModel()
- # Core radius
- sphere.setParam('radius', self.radius)
- # Shell thickness
- sphere.setParam('thickness', thickness)
- sphere.setParam('core_sld', 1.0)
- sphere.setParam('shell_sld', self.shell_sld)
- sphere.setParam('solvent_sld', 0.0)
- sphere.setParam('background', 0.0)
- sphere.setParam('scale', 1.0)
- self.ana = sphere
- self.create()
-
- def create(self):
- canvas = VolumeCanvas.VolumeCanvas()
- canvas.setParam('lores_density', self.density)
-
- handle = canvas.add('sphere')
- canvas.setParam('%s.radius' % handle, self.outer_radius)
- canvas.setParam('%s.contrast' % handle, self.shell_sld)
-
- handle2 = canvas.add('sphere')
- canvas.setParam('%s.radius' % handle2, self.radius)
- canvas.setParam('%s.contrast' % handle2, 1.0)
-
- canvas.setParam('scale' , 1.0)
- canvas.setParam('background' , 0.0)
- self.canvas = canvas
-
-def validate_model(validator, q_min, q_max, n_q):
- """
- Validate a model
- An output file containing a comparison between
- simulation and the analytical solution will be
- produced.
-
- @param validator: validator object
- @param q_min: minimum q
- @param q_max: maximum q
- @param n_q: number of q points
- @param N: number of times to evaluate each simulation point
- """
-
- q_list = pylab.arange(q_min, q_max*1.0001, (q_max-q_min)/(n_q-1))
-
- output = open('%s_d=%g_Iq.txt' % (validator.name, validator.density), 'w')
- output.write("PARS: %s\n" % validator.ana.params)
- output.write("<q> <ana> <sim> <err>\n")
- for q in q_list:
- ana = validator.run_ana(q)
- sim, err = validator.run_sim(q)
- print "q=%-g ana=%-g sim=%-g err=%-g diff=%-g (%-g) %s" % (q, ana, sim, err,
- (sim-ana), sim/ana, str(math.fabs(sim-ana)>err))
- output.write("%g %g %g %g\n" % (q, ana, sim, err))
- output.close()
-
-def validate_model_2D(validator, q_min, q_max, phi, n_q):
- """
- Validate a model
- An output file containing a comparison between
- simulation and the analytical solution will be
- produced.
-
- @param validator: validator object
- @param q_min: minimum q
- @param q_max: maximum q
- @param n_q: number of q points
- @param N: number of times to evaluate each simulation point
- """
-
- q_list = pylab.arange(q_min, q_max*1.0001, (q_max-q_min)/(n_q-1))
-
- output = open('%s_d=%g_Iq2D.txt' % (validator.name, validator.density), 'w')
- output.write("PARS: %s\n" % validator.ana.params)
- output.write("<q> <ana> <sim> <err>\n")
- t_0 = time.time()
- for q in q_list:
- ana = validator.run_ana2D(q*math.cos(phi), q*math.sin(phi))
- sim, err = validator.run_sim2D(q*math.cos(phi), q*math.sin(phi))
- print "q=%-g ana=%-g sim=%-g err=%-g diff=%-g (%-g) %s" % (q, ana, sim, err,
- (sim-ana), sim/ana, str(math.fabs(sim-ana)>err))
- output.write("%g %g %g %g\n" % (q, ana, sim, err))
- print "Time elapsed: ", time.time()-t_0
- output.close()
-
-def check_density(validator, q, d_min, d_max, n_d):
- """
- Check simulation output as a function of the density
- An output file containing a comparison between
- simulation and the analytical solution will be
- produced.
-
- @param validator: validator object
- @param q: q-value to evaluate at
- @param d_min: minimum density
- @param d_max: maximum density
- @param n_d: number of density points
- @param N: number of times to evaluate each simulation point
- """
- d_list = pylab.arange(d_min, d_max*1.0001, (d_max-d_min)/(n_d-1.0))
-
- output = open('%s_%g_density.txt' % (validator.name, q), 'w')
- output.write("PARS: %s\n" % validator.ana.params)
- output.write("<density> <ana_d> <sim_d> <err_d>\n")
- ana = validator.run_ana(q)
- for d in d_list:
- sim, err = validator.run_sim(q, density=d)
- print "d=%-g ana=%-g sim=%-g err=%-g diff=%-g (%g) %s" % \
- (d, ana, sim, err, (sim-ana), (sim-ana)/ana,
- str(math.fabs(sim-ana)>err))
- output.write("%g %g %g %g \n" % (d, ana, sim, err))
- output.close()
-
-
-if __name__ == '__main__':
-
- # 2D: Density=5, 71.2 secs for 50 points
- #vali = CoreShellValidator(radius = 15, thickness=5, density = 5.0)
- #validate_model(vali, q_min=0.001, q_max=1, n_q=50)
- #validate_model_2D(vali, q_min=0.001, q_max=1, phi=1.0, n_q=50)
-
- # 2D: Density=2, 11.1 secs for 25 points
- #vali = SphereValidator(radius = 20, density = 0.02)
- #validate_model(vali, q_min=0.001, q_max=0.5, n_q=25)
- #vali = SphereValidator(radius = 20, density = 2.0)
- #validate_model_2D(vali, q_min=0.001, q_max=0.5, phi=1.0, n_q=25)
-
- # 2D: Density=1, 19.4 secs for 25 points
- # 2D: Density=0.5, 9.8 secs for 25 points
- #vali = CylinderValidator(radius = 20, length=100, density = 0.1)
- #validate_model(vali, q_min=0.001, q_max=0.5, n_q=25)
- vali = CylinderValidator(radius = 20, length=100, density = 0.5)
- validate_model_2D(vali, q_min=0.001, q_max=0.2, phi=1.0, n_q=25)
-
- # 2D: Density=0.5, 2.26 secs for 25 points
- #vali = EllipsoidValidator(radius_a = 20, radius_b=15, density = 0.05)
- #validate_model(vali, q_min=0.001, q_max=0.5, n_q=25)
- #vali = EllipsoidValidator(radius_a = 20, radius_b=15, density = 0.5)
- #validate_model_2D(vali, q_min=0.001, q_max=0.5, phi=1.0, n_q=25)
-
- #vali = HelixValidator(density = 0.05)
- #validate_model(vali, q_min=0.001, q_max=0.5, n_q=25)
-
-
+"""
+ Validation tests for real-space simulation of I(q)
+
+ @copyright: University of Tennessee, 2007
+ @license: This software is provided as part of the DANSE project
+"""
+from __future__ import print_function
+
+import math, time, pylab
+
+try:
+ import VolumeCanvas
+ print("Testing local version")
+except:
+ print("Testing installed version")
+ import sas.sascalc.realspace.VolumeCanvas as VolumeCanvas
+
+class Validator:
+
+ def __init__(self):
+ self.density = 0.1
+ self.canvas = None
+ self.ana = None
+ self.create()
+
+ def create(self):
+ pass
+
+ def run_sim2D(self, qx, qy, density=None):
+ """
+ Calculate the mean and error of the simulation
+ @param q: q-value to calculate at
+ @param density: point density of simulation
+ #return: mean, error
+ """
+ if density is not None:
+ self.density = density
+ self.create()
+
+ return self.canvas.getIq2DError(qx, qy)
+
+ def run_sim(self, q, density=None):
+ """
+ Calculate the mean and error of the simulation
+ @param q: q-value to calculate at
+ @param density: point density of simulation
+ #return: mean, error
+ """
+ if density is not None:
+ self.density = density
+ self.create()
+
+ return self.canvas.getIqError(q)
+
+ def run_ana2D(self, qx, qy):
+ """
+ Return analytical value
+ @param q: q-value to evaluate at [float]
+ @return: analytical output [float]
+ """
+ return self.ana.runXY([qx, qy])
+
+ def run_ana(self, q):
+ """
+ Return analytical value
+ @param q: q-value to evaluate at [float]
+ @return: analytical output [float]
+ """
+ return self.ana.run(q)
+
+class SphereValidator(Validator):
+
+ def __init__(self, radius=15, density = 0.01):
+ from sas.models.SphereModel import SphereModel
+
+ self.name = 'sphere'
+ self.radius = radius
+ self.density = density
+
+ self.ana = SphereModel()
+ self.ana.setParam('scale', 1.0)
+ self.ana.setParam('contrast', 1.0)
+ self.ana.setParam('background', 0.0)
+ self.ana.setParam('radius', radius)
+ self.create()
+
+ def create(self):
+ canvas = VolumeCanvas.VolumeCanvas()
+ canvas.setParam('lores_density', self.density)
+ handle = canvas.add('sphere')
+ canvas.setParam('%s.radius' % handle, self.radius)
+ canvas.setParam('scale' , 1.0)
+ canvas.setParam('%s.contrast' % handle, 1.0)
+ canvas.setParam('background' , 0.0)
+ self.canvas = canvas
+
+class CylinderValidator(Validator):
+
+ def __init__(self, radius=15, length=100, density = 0.01):
+ from sas.models.CylinderModel import CylinderModel
+
+ self.name = 'cylinder'
+ self.radius = radius
+ self.length = length
+ self.density = density
+
+ self.ana = CylinderModel()
+ self.ana.setParam('scale', 1.0)
+ self.ana.setParam('contrast', 1.0)
+ self.ana.setParam('background', 0.0)
+ self.ana.setParam('radius', radius)
+ self.ana.setParam('length', length)
+ self.ana.setParam('cyl_theta', math.pi/2.0)
+ self.ana.setParam('cyl_phi', math.pi/2.0)
+ self.create()
+
+ def create(self):
+ canvas = VolumeCanvas.VolumeCanvas()
+ canvas.setParam('lores_density', self.density)
+ handle = canvas.add('cylinder')
+ canvas.setParam('%s.radius' % handle, self.radius)
+ canvas.setParam('%s.length' % handle, self.length)
+ canvas.setParam('scale' , 1.0)
+ canvas.setParam('%s.contrast' % handle, 1.0)
+ canvas.setParam('background' , 0.0)
+ self.canvas = canvas
+
+class EllipsoidValidator(Validator):
+
+ def __init__(self, radius_a=60, radius_b=10, density = 0.01):
+ from sas.models.EllipsoidModel import EllipsoidModel
+ #from sas.models.SphereModel import SphereModel
+
+ self.name = 'ellipsoid'
+ self.radius_a = radius_a
+ self.radius_b = radius_b
+ self.density = density
+
+ self.ana = EllipsoidModel()
+ #self.ana = SphereModel()
+ self.ana.setParam('scale', 1.0)
+ self.ana.setParam('contrast', 1.0)
+ self.ana.setParam('background', 0.0)
+ self.ana.setParam('radius_a', radius_a)
+ self.ana.setParam('radius_b', radius_b)
+ #self.ana.setParam('radius', radius_a)
+
+ # Default orientation is there=1.57, phi=0
+ # Radius_a is along the x direction
+
+ self.create()
+
+ def create(self):
+ canvas = VolumeCanvas.VolumeCanvas()
+ canvas.setParam('lores_density', self.density)
+ handle = canvas.add('ellipsoid')
+ canvas.setParam('%s.radius_x' % handle, self.radius_a)
+ canvas.setParam('%s.radius_y' % handle, self.radius_b)
+ canvas.setParam('%s.radius_z' % handle, self.radius_b)
+ canvas.setParam('scale' , 1.0)
+ canvas.setParam('%s.contrast' % handle, 1.0)
+ canvas.setParam('background' , 0.0)
+ self.canvas = canvas
+
+class HelixValidator(Validator):
+
+ def __init__(self, density = 0.01):
+ self.name = 'helix'
+ self.density = density
+ self.create()
+
+ def create(self):
+ canvas = VolumeCanvas.VolumeCanvas()
+ canvas.setParam('lores_density', self.density)
+ handle = canvas.add('singlehelix')
+ canvas.setParam('scale' , 1.0)
+ canvas.setParam('%s.contrast' % handle, 1.0)
+ canvas.setParam('background' , 0.0)
+ self.canvas = canvas
+ # just to write the parameters to the output file
+ self.ana = canvas
+
+ def run_ana(self, q):
+ return 1
+
+
+class CoreShellValidator(Validator):
+
+ def __init__(self, radius=15, thickness=5, density = 0.01):
+ from sas.models.CoreShellModel import CoreShellModel
+
+ self.name = 'coreshell'
+ self.radius = radius
+
+ core_vol = 4.0/3.0*math.pi*radius*radius*radius
+ self.outer_radius = radius+thickness
+ shell_vol = 4.0/3.0*math.pi*self.outer_radius*self.outer_radius*self.outer_radius - core_vol
+ self.shell_sld = -1.0*core_vol/shell_vol
+
+ self.density = density
+
+ # Core-shell
+ sphere = CoreShellModel()
+ # Core radius
+ sphere.setParam('radius', self.radius)
+ # Shell thickness
+ sphere.setParam('thickness', thickness)
+ sphere.setParam('core_sld', 1.0)
+ sphere.setParam('shell_sld', self.shell_sld)
+ sphere.setParam('solvent_sld', 0.0)
+ sphere.setParam('background', 0.0)
+ sphere.setParam('scale', 1.0)
+ self.ana = sphere
+ self.create()
+
+ def create(self):
+ canvas = VolumeCanvas.VolumeCanvas()
+ canvas.setParam('lores_density', self.density)
+
+ handle = canvas.add('sphere')
+ canvas.setParam('%s.radius' % handle, self.outer_radius)
+ canvas.setParam('%s.contrast' % handle, self.shell_sld)
+
+ handle2 = canvas.add('sphere')
+ canvas.setParam('%s.radius' % handle2, self.radius)
+ canvas.setParam('%s.contrast' % handle2, 1.0)
+
+ canvas.setParam('scale' , 1.0)
+ canvas.setParam('background' , 0.0)
+ self.canvas = canvas
+
+def validate_model(validator, q_min, q_max, n_q):
+ """
+ Validate a model
+ An output file containing a comparison between
+ simulation and the analytical solution will be
+ produced.
+
+ @param validator: validator object
+ @param q_min: minimum q
+ @param q_max: maximum q
+ @param n_q: number of q points
+ @param N: number of times to evaluate each simulation point
+ """
+
+ q_list = pylab.arange(q_min, q_max*1.0001, (q_max-q_min)/(n_q-1))
+
+ output = open('%s_d=%g_Iq.txt' % (validator.name, validator.density), 'w')
+ output.write("PARS: %s\n" % validator.ana.params)
+ output.write("<q> <ana> <sim> <err>\n")
+ for q in q_list:
+ ana = validator.run_ana(q)
+ sim, err = validator.run_sim(q)
+ print("q=%-g ana=%-g sim=%-g err=%-g diff=%-g (%-g) %s" % (q, ana, sim, err,
+ (sim-ana), sim/ana, str(math.fabs(sim-ana)>err)))
+ output.write("%g %g %g %g\n" % (q, ana, sim, err))
+ output.close()
+
+def validate_model_2D(validator, q_min, q_max, phi, n_q):
+ """
+ Validate a model
+ An output file containing a comparison between
+ simulation and the analytical solution will be
+ produced.
+
+ @param validator: validator object
+ @param q_min: minimum q
+ @param q_max: maximum q
+ @param n_q: number of q points
+ @param N: number of times to evaluate each simulation point
+ """
+
+ q_list = pylab.arange(q_min, q_max*1.0001, (q_max-q_min)/(n_q-1))
+
+ output = open('%s_d=%g_Iq2D.txt' % (validator.name, validator.density), 'w')
+ output.write("PARS: %s\n" % validator.ana.params)
+ output.write("<q> <ana> <sim> <err>\n")
+ t_0 = time.time()
+ for q in q_list:
+ ana = validator.run_ana2D(q*math.cos(phi), q*math.sin(phi))
+ sim, err = validator.run_sim2D(q*math.cos(phi), q*math.sin(phi))
+ print("q=%-g ana=%-g sim=%-g err=%-g diff=%-g (%-g) %s" % (q, ana, sim, err,
+ (sim-ana), sim/ana, str(math.fabs(sim-ana)>err)))
+ output.write("%g %g %g %g\n" % (q, ana, sim, err))
+ print("Time elapsed: ", time.time()-t_0)
+ output.close()
+
+def check_density(validator, q, d_min, d_max, n_d):
+ """
+ Check simulation output as a function of the density
+ An output file containing a comparison between
+ simulation and the analytical solution will be
+ produced.
+
+ @param validator: validator object
+ @param q: q-value to evaluate at
+ @param d_min: minimum density
+ @param d_max: maximum density
+ @param n_d: number of density points
+ @param N: number of times to evaluate each simulation point
+ """
+ d_list = pylab.arange(d_min, d_max*1.0001, (d_max-d_min)/(n_d-1.0))
+
+ output = open('%s_%g_density.txt' % (validator.name, q), 'w')
+ output.write("PARS: %s\n" % validator.ana.params)
+ output.write("<density> <ana_d> <sim_d> <err_d>\n")
+ ana = validator.run_ana(q)
+ for d in d_list:
+ sim, err = validator.run_sim(q, density=d)
+ print("d=%-g ana=%-g sim=%-g err=%-g diff=%-g (%g) %s" % \
+ (d, ana, sim, err, (sim-ana), (sim-ana)/ana,
+ str(math.fabs(sim-ana)>err)))
+ output.write("%g %g %g %g \n" % (d, ana, sim, err))
+ output.close()
+
+
+if __name__ == '__main__':
+
+ # 2D: Density=5, 71.2 secs for 50 points
+ #vali = CoreShellValidator(radius = 15, thickness=5, density = 5.0)
+ #validate_model(vali, q_min=0.001, q_max=1, n_q=50)
+ #validate_model_2D(vali, q_min=0.001, q_max=1, phi=1.0, n_q=50)
+
+ # 2D: Density=2, 11.1 secs for 25 points
+ #vali = SphereValidator(radius = 20, density = 0.02)
+ #validate_model(vali, q_min=0.001, q_max=0.5, n_q=25)
+ #vali = SphereValidator(radius = 20, density = 2.0)
+ #validate_model_2D(vali, q_min=0.001, q_max=0.5, phi=1.0, n_q=25)
+
+ # 2D: Density=1, 19.4 secs for 25 points
+ # 2D: Density=0.5, 9.8 secs for 25 points
+ #vali = CylinderValidator(radius = 20, length=100, density = 0.1)
+ #validate_model(vali, q_min=0.001, q_max=0.5, n_q=25)
+ vali = CylinderValidator(radius = 20, length=100, density = 0.5)
+ validate_model_2D(vali, q_min=0.001, q_max=0.2, phi=1.0, n_q=25)
+
+ # 2D: Density=0.5, 2.26 secs for 25 points
+ #vali = EllipsoidValidator(radius_a = 20, radius_b=15, density = 0.05)
+ #validate_model(vali, q_min=0.001, q_max=0.5, n_q=25)
+ #vali = EllipsoidValidator(radius_a = 20, radius_b=15, density = 0.5)
+ #validate_model_2D(vali, q_min=0.001, q_max=0.5, phi=1.0, n_q=25)
+
+ #vali = HelixValidator(density = 0.05)
+ #validate_model(vali, q_min=0.001, q_max=0.5, n_q=25)
+
+
diff --git a/test/sasrealspace/test/utest_oriented.py b/test/sasrealspace/test/utest_oriented.py
index 945b556..f18f534 100644
--- a/test/sasrealspace/test/utest_oriented.py
+++ b/test/sasrealspace/test/utest_oriented.py
@@ -1,486 +1,485 @@
-"""
- Unit tests for specific oriented models
- @copyright: University of Tennessee, for the DANSE project
-"""
-
-import unittest, math, sys
-
-# Disable "missing docstring" complaint
-# pylint: disable-msg=C0111
-# Disable "too many methods" complaint
-# pylint: disable-msg=R0904
-# Disable "could be a function" complaint
-# pylint: disable-msg=R0201
-# pylint: disable-msg=W0702
-
-try:
- import VolumeCanvas
- print "Testing local version"
-except:
- print sys.exc_value
- #testing the version that is working on
- print "Testing installed version"
- import sas.sascalc.realspace.VolumeCanvas as VolumeCanvas
-
-
-class TestSphere(unittest.TestCase):
- """ Tests for oriented (2D) systems """
-
- def setUp(self):
- """
- Set up canvas
- """
- from sas.models.SphereModel import SphereModel
- self.model = VolumeCanvas.VolumeCanvas()
-
- handle = self.model.add('sphere')
-
- radius = 10
- density = .1
-
- ana = SphereModel()
- ana.setParam('scale', 1.0)
- ana.setParam('contrast', 1.0)
- ana.setParam('background', 0.0)
- ana.setParam('radius', radius)
- self.ana = ana
-
- self.model.setParam('lores_density', density)
- self.model.setParam('%s.radius' % handle, radius)
- self.model.setParam('scale' , 1.0)
- self.model.setParam('%s.contrast' % handle, 1.0)
- self.model.setParam('background' , 0.0)
-
-
- def testdefault(self):
- """ Testing sphere """
- # Default orientation
- ana_val = self.ana.runXY([0.1, 0.1])
- sim_val = self.model.getIq2D(0.1, 0.1)
- self.assert_( math.fabs(sim_val/ana_val-1.0)<0.1 )
-
-class TestCylinderAddObject(unittest.TestCase):
- """ Tests for oriented (2D) systems """
-
- def setUp(self):
- """ Set up cylinder model """
- from sas.models.CylinderModel import CylinderModel
- radius = 5
- length = 40
- density = 20
-
- # Analytical model
- self.ana = CylinderModel()
- self.ana.setParam('scale', 1.0)
- self.ana.setParam('contrast', 1.0)
- self.ana.setParam('background', 0.0)
- self.ana.setParam('radius', radius)
- self.ana.setParam('length', length)
-
- # Simulation model
- self.model = VolumeCanvas.VolumeCanvas()
- cyl = VolumeCanvas.CylinderDescriptor()
- self.handle = self.model.addObject(cyl)
- self.model.setParam('lores_density', density)
- self.model.setParam('%s.radius' % self.handle, radius)
- self.model.setParam('%s.length' % self.handle, length)
- self.model.setParam('scale' , 1.0)
- self.model.setParam('%s.contrast' % self.handle, 1.0)
- self.model.setParam('background' , 0.0)
-
- def testalongY(self):
- """ Testing cylinder along Y axis """
- self.ana.setParam('cyl_theta', math.pi/2.0)
- self.ana.setParam('cyl_phi', math.pi/2.0)
-
- self.model.setParam('%s.orientation' % self.handle, [0,0,0])
-
- ana_val = self.ana.runXY([0.1, 0.2])
- sim_val = self.model.getIq2D(0.1, 0.2)
- #print ana_val, sim_val, sim_val/ana_val
-
- self.assert_( math.fabs(sim_val/ana_val-1.0)<0.05 )
-
-
-class TestCylinder(unittest.TestCase):
- """ Tests for oriented (2D) systems """
-
- def setUp(self):
- """ Set up cylinder model """
- from sas.models.CylinderModel import CylinderModel
- radius = 5
- length = 40
- density = 20
-
- # Analytical model
- self.ana = CylinderModel()
- self.ana.setParam('scale', 1.0)
- self.ana.setParam('contrast', 1.0)
- self.ana.setParam('background', 0.0)
- self.ana.setParam('radius', radius)
- self.ana.setParam('length', length)
-
- # Simulation model
- self.model = VolumeCanvas.VolumeCanvas()
- self.handle = self.model.add('cylinder')
- self.model.setParam('lores_density', density)
- self.model.setParam('%s.radius' % self.handle, radius)
- self.model.setParam('%s.length' % self.handle, length)
- self.model.setParam('scale' , 1.0)
- self.model.setParam('%s.contrast' % self.handle, 1.0)
- self.model.setParam('background' , 0.0)
-
- def testalongY(self):
- """ Testing cylinder along Y axis """
- self.ana.setParam('cyl_theta', math.pi/2.0)
- self.ana.setParam('cyl_phi', math.pi/2.0)
-
- self.model.setParam('%s.orientation' % self.handle, [0,0,0])
-
- ana_val = self.ana.runXY([0.1, 0.2])
- sim_val = self.model.getIq2D(0.1, 0.2)
- #print ana_val, sim_val, sim_val/ana_val
-
- self.assert_( math.fabs(sim_val/ana_val-1.0)<0.05 )
-
- def testalongZ(self):
- """ Testing cylinder along Z axis """
- self.ana.setParam('cyl_theta', 0)
- self.ana.setParam('cyl_phi', 0)
-
- self.model.setParam('%s.orientation' % self.handle, [90,0,0])
-
- ana_val = self.ana.runXY([0.1, 0.2])
- sim_val = self.model.getIq2D(0.1, 0.2)
- #print ana_val, sim_val, sim_val/ana_val
-
- self.assert_( math.fabs(sim_val/ana_val-1.0)<0.05 )
-
- def testalongX(self):
- """ Testing cylinder along X axis """
- self.ana.setParam('cyl_theta', 1.57)
- self.ana.setParam('cyl_phi', 0)
-
- self.model.setParam('%s.orientation' % self.handle, [0,0,90])
-
- ana_val = self.ana.runXY([0.1, 0.2])
- sim_val = self.model.getIq2D(0.1, 0.2)
- #print ana_val, sim_val, sim_val/ana_val
-
- self.assert_( math.fabs(sim_val/ana_val-1.0)<0.05 )
-
-class TestEllipsoid(unittest.TestCase):
- """ Tests for oriented (2D) systems """
-
- def setUp(self):
- """ Set up ellipsoid """
- from sas.models.EllipsoidModel import EllipsoidModel
-
- radius_a = 60
- radius_b = 10
- density = 30
-
- self.ana = EllipsoidModel()
- self.ana.setParam('scale', 1.0)
- self.ana.setParam('contrast', 1.0)
- self.ana.setParam('background', 0.0)
- self.ana.setParam('radius_a', radius_a)
- self.ana.setParam('radius_b', radius_b)
- # Default orientation is there=1.57, phi=0
- # Radius_a is along the x direction
-
- canvas = VolumeCanvas.VolumeCanvas()
- canvas.setParam('lores_density', density)
- self.handle = canvas.add('ellipsoid')
- canvas.setParam('%s.radius_x' % self.handle, radius_a)
- canvas.setParam('%s.radius_y' % self.handle, radius_b)
- canvas.setParam('%s.radius_z' % self.handle, radius_b)
- canvas.setParam('scale' , 1.0)
- canvas.setParam('%s.contrast' % self.handle, 1.0)
- canvas.setParam('background' , 0.0)
- self.canvas = canvas
-
- def testalongX(self):
- """ Testing ellipsoid along X """
- self.ana.setParam('axis_theta', 1.57)
- self.ana.setParam('axis_phi', 0)
-
- self.canvas.setParam('%s.orientation' % self.handle, [0,0,0])
-
- ana_val = self.ana.runXY([0.1, 0.2])
- sim_val = self.canvas.getIq2D(0.1, 0.2)
- #print ana_val, sim_val, sim_val/ana_val
-
- self.assert_( math.fabs(sim_val/ana_val-1.0)<0.05 )
-
- def testalongZ(self):
- """ Testing ellipsoid along Z """
- self.ana.setParam('axis_theta', 0)
- self.ana.setParam('axis_phi', 0)
-
- self.canvas.setParam('%s.orientation' % self.handle, [0,90,0])
-
- ana_val = self.ana.runXY([0.1, 0.2])
- sim_val = self.canvas.getIq2D(0.1, 0.2)
- #print ana_val, sim_val, sim_val/ana_val
-
- self.assert_( math.fabs(sim_val/ana_val-1.0)<0.05 )
-
- def testalongY(self):
- """ Testing ellipsoid along Y """
- self.ana.setParam('axis_theta', math.pi/2.0)
- self.ana.setParam('axis_phi', math.pi/2.0)
-
- self.canvas.setParam('%s.orientation' % self.handle, [0,0,90])
-
- ana_val = self.ana.runXY([0.05, 0.15])
- sim_val = self.canvas.getIq2D(0.05, 0.15)
- #print ana_val, sim_val, sim_val/ana_val
-
- try:
- self.assert_( math.fabs(sim_val/ana_val-1.0)<0.05 )
- except:
- print "Error", ana_val, sim_val, sim_val/ana_val
- raise sys.exc_type, sys.exc_value
-
-class TestCoreShell(unittest.TestCase):
- """ Tests for oriented (2D) systems """
-
- def setUp(self):
- """ Set up zero-SLD-average core-shell model """
- from sas.models.CoreShellModel import CoreShellModel
-
- radius = 15
- thickness = 5
- density = 20
-
- core_vol = 4.0/3.0*math.pi*radius*radius*radius
- self.outer_radius = radius+thickness
- shell_vol = 4.0/3.0*math.pi*self.outer_radius*self.outer_radius*self.outer_radius - core_vol
- self.shell_sld = -1.0*core_vol/shell_vol
-
- self.density = density
-
- # Core-shell
- sphere = CoreShellModel()
- # Core radius
- sphere.setParam('radius', radius)
- # Shell thickness
- sphere.setParam('thickness', thickness)
- sphere.setParam('core_sld', 1.0)
- sphere.setParam('shell_sld', self.shell_sld)
- sphere.setParam('solvent_sld', 0.0)
- sphere.setParam('background', 0.0)
- sphere.setParam('scale', 1.0)
- self.ana = sphere
-
- canvas = VolumeCanvas.VolumeCanvas()
- canvas.setParam('lores_density', self.density)
-
- handle = canvas.add('sphere')
- canvas.setParam('%s.radius' % handle, self.outer_radius)
- canvas.setParam('%s.contrast' % handle, self.shell_sld)
-
- handle2 = canvas.add('sphere')
- canvas.setParam('%s.radius' % handle2, radius)
- canvas.setParam('%s.contrast' % handle2, 1.0)
-
- canvas.setParam('scale' , 1.0)
- canvas.setParam('background' , 0.0)
- self.canvas = canvas
-
- def testdefault(self):
- """ Testing default core-shell orientation """
- ana_val = self.ana.runXY([0.1, 0.2])
- sim_val, err = self.canvas.getIq2DError(0.1, 0.2)
-
- self.assert_( math.fabs(sim_val/ana_val-1.0)<0.05 )
-
-class TestCoreShellError(unittest.TestCase):
- """ Tests for oriented (2D) systems """
-
- def setUp(self):
- """ Set up zero-SLD-average core-shell model """
- from sas.models.CoreShellModel import CoreShellModel
-
- radius = 15
- thickness = 5
- density = 5
-
- core_vol = 4.0/3.0*math.pi*radius*radius*radius
- self.outer_radius = radius+thickness
- shell_vol = 4.0/3.0*math.pi*self.outer_radius*self.outer_radius*self.outer_radius - core_vol
- self.shell_sld = -1.0*core_vol/shell_vol
-
- self.density = density
-
- # Core-shell
- sphere = CoreShellModel()
- # Core radius
- sphere.setParam('radius', radius)
- # Shell thickness
- sphere.setParam('thickness', thickness)
- sphere.setParam('core_sld', 1.0)
- sphere.setParam('shell_sld', self.shell_sld)
- sphere.setParam('solvent_sld', 0.0)
- sphere.setParam('background', 0.0)
- sphere.setParam('scale', 1.0)
- self.ana = sphere
-
- canvas = VolumeCanvas.VolumeCanvas()
- canvas.setParam('lores_density', self.density)
-
- handle = canvas.add('sphere')
- canvas.setParam('%s.radius' % handle, self.outer_radius)
- canvas.setParam('%s.contrast' % handle, self.shell_sld)
-
- handle2 = canvas.add('sphere')
- canvas.setParam('%s.radius' % handle2, radius)
- canvas.setParam('%s.contrast' % handle2, 1.0)
-
- canvas.setParam('scale' , 1.0)
- canvas.setParam('background' , 0.0)
- self.canvas = canvas
-
- def testdefault(self):
- """ Testing default core-shell orientation """
- ana_val = self.ana.runXY([0.1, 0.2])
- sim_val, err = self.canvas.getIq2DError(0.1, 0.2)
-
- self.assert_( math.fabs(sim_val-ana_val) < 3.0 * err )
-
-class TestRunMethods(unittest.TestCase):
- """ Tests run methods for oriented (2D) systems """
-
- def setUp(self):
- """ Set up ellipsoid """
- from sas.models.EllipsoidModel import EllipsoidModel
-
- radius_a = 10
- radius_b = 15
- density = 5
-
- self.ana = EllipsoidModel()
- self.ana.setParam('scale', 1.0)
- self.ana.setParam('contrast', 1.0)
- self.ana.setParam('background', 0.0)
- self.ana.setParam('radius_a', radius_a)
- self.ana.setParam('radius_b', radius_b)
-
-
- canvas = VolumeCanvas.VolumeCanvas()
- canvas.setParam('lores_density', density)
- self.handle = canvas.add('ellipsoid')
- canvas.setParam('%s.radius_x' % self.handle, radius_a)
- canvas.setParam('%s.radius_y' % self.handle, radius_b)
- canvas.setParam('%s.radius_z' % self.handle, radius_b)
- canvas.setParam('scale' , 1.0)
- canvas.setParam('%s.contrast' % self.handle, 1.0)
- canvas.setParam('background' , 0.0)
- self.canvas = canvas
-
- self.ana.setParam('axis_theta', 1.57)
- self.ana.setParam('axis_phi', 0)
-
- self.canvas.setParam('%s.orientation' % self.handle, [0,0,0])
-
-
- def testRunXY_List(self):
- """ Testing ellipsoid along X """
- ana_val = self.ana.runXY([0.1, 0.2])
- sim_val = self.canvas.runXY([0.1, 0.2])
- #print ana_val, sim_val, sim_val/ana_val
-
- try:
- self.assert_( math.fabs(sim_val/ana_val-1.0)<0.05 )
- except:
- print "Error", ana_val, sim_val, sim_val/ana_val
- raise sys.exc_type, sys.exc_value
-
- def testRunXY_float(self):
- """ Testing ellipsoid along X """
- ana_val = self.ana.runXY(0.1)
- sim_val = self.canvas.runXY(0.1)
- #print ana_val, sim_val, sim_val/ana_val
-
- try:
- self.assert_( math.fabs(sim_val/ana_val-1.0)<0.05 )
- except:
- print "Error", ana_val, sim_val, sim_val/ana_val
- raise sys.exc_type, sys.exc_value
-
- def testRun_float(self):
- """ Testing ellipsoid along X """
- ana_val = self.ana.run(0.1)
- sim_val = self.canvas.run(0.1)
- #print ana_val, sim_val, sim_val/ana_val
-
- try:
- self.assert_( math.fabs(sim_val/ana_val-1.0)<0.05 )
- except:
- print "Error", ana_val, sim_val, sim_val/ana_val
- raise sys.exc_type, sys.exc_value
-
- def testRun_list(self):
- """ Testing ellipsoid along X """
- ana_val = self.ana.run([0.1, 33.0])
- sim_val = self.canvas.run([0.1, 33.0])
- #print ana_val, sim_val, sim_val/ana_val
-
- try:
- self.assert_( math.fabs(sim_val/ana_val-1.0)<0.05 )
- except:
- print "Error", ana_val, sim_val, sim_val/ana_val
- raise sys.exc_type, sys.exc_value
-
-class TestParamChange(unittest.TestCase):
- """ Tests for oriented (2D) systems """
-
- def setUp(self):
- """ Set up cylinder model """
- from sas.models.CylinderModel import CylinderModel
- radius = 5
- length = 40
- density = 20
-
- # Analytical model
- self.ana = CylinderModel()
- self.ana.setParam('scale', 1.0)
- self.ana.setParam('contrast', 1.0)
- self.ana.setParam('background', 0.0)
- self.ana.setParam('radius', radius)
- self.ana.setParam('length', length)
- self.ana.setParam('cyl_theta', math.pi/2.0)
- self.ana.setParam('cyl_phi', math.pi/2.0)
-
- # Simulation model
- self.model = VolumeCanvas.VolumeCanvas()
- self.handle = self.model.add('cylinder')
- self.model.setParam('lores_density', density)
- self.model.setParam('%s.radius' % self.handle, radius)
- self.model.setParam('%s.length' % self.handle, length)
- self.model.setParam('scale' , 1.0)
- self.model.setParam('%s.contrast' % self.handle, 1.0)
- self.model.setParam('background' , 0.0)
- self.model.setParam('%s.orientation' % self.handle, [0,0,0])
-
- def testalongY(self):
- """ Test that a parameter change forces the generation
- of new space points
- """
- ana_val = self.ana.runXY([0.1, 0.2])
- sim_val = self.model.getIq2D(0.1, 0.2)
-
- self.assert_( math.fabs(sim_val/ana_val-1.0)<0.05 )
-
- # Change the radius a re-evaluate
- self.ana.setParam('radius', 10)
- self.model.setParam('%s.radius' % self.handle, 10)
-
- ana_val = self.ana.runXY([0.1, 0.2])
- sim_val = self.model.getIq2D(0.1, 0.2)
- self.assert_( math.fabs(sim_val/ana_val-1.0)<0.05 )
-
-
-if __name__ == '__main__':
- unittest.main()
+"""
+ Unit tests for specific oriented models
+ @copyright: University of Tennessee, for the DANSE project
+"""
+from __future__ import print_function
+
+import unittest, math, sys
+
+# Disable "missing docstring" complaint
+# pylint: disable-msg=C0111
+# Disable "too many methods" complaint
+# pylint: disable-msg=R0904
+# Disable "could be a function" complaint
+# pylint: disable-msg=R0201
+# pylint: disable-msg=W0702
+
+from sasmodels.sasview_model import _make_standard_model
+EllipsoidModel = _make_standard_model('ellipsoid')
+SphereModel = _make_standard_model('sphere')
+CylinderModel = _make_standard_model('cylinder')
+CoreShellModel = _make_standard_model('core_shell_sphere')
+
+import sas.sascalc.realspace.VolumeCanvas as VolumeCanvas
+
+
+
+class TestSphere(unittest.TestCase):
+ """ Tests for oriented (2D) systems """
+
+ def setUp(self):
+ """
+ Set up canvas
+ """
+ self.model = VolumeCanvas.VolumeCanvas()
+
+ handle = self.model.add('sphere')
+
+ radius = 10
+ density = .1
+
+ ana = SphereModel()
+ ana.setParam('scale', 1.0)
+ ana.setParam('background', 0.0)
+ ana.setParam('sld', 1.0)
+ ana.setParam('sld_solvent', 0.0)
+ ana.setParam('radius', radius)
+ self.ana = ana
+
+ self.model.setParam('lores_density', density)
+ self.model.setParam('scale' , 1.0)
+ self.model.setParam('background' , 0.0)
+ self.model.setParam('%s.contrast' % handle, 1.0)
+ self.model.setParam('%s.radius' % handle, radius)
+
+
+ def testdefault(self):
+ """ Testing sphere """
+ # Default orientation
+ ana_val = self.ana.runXY([0.1, 0.1])
+ sim_val = self.model.getIq2D(0.1, 0.1)
+ self.assert_( math.fabs(sim_val/ana_val-1.0)<0.1 )
+
+class TestCylinderAddObject(unittest.TestCase):
+ """ Tests for oriented (2D) systems """
+
+ def setUp(self):
+ """ Set up cylinder model """
+ radius = 5
+ length = 40
+ density = 20
+
+ # Analytical model
+ self.ana = CylinderModel()
+ self.ana.setParam('scale', 1.0)
+ self.ana.setParam('background', 0.0)
+ self.ana.setParam('sld', 1.0)
+ self.ana.setParam('sld_solvent', 0.0)
+ self.ana.setParam('radius', radius)
+ self.ana.setParam('length', length)
+
+ # Simulation model
+ self.model = VolumeCanvas.VolumeCanvas()
+ cyl = VolumeCanvas.CylinderDescriptor()
+ self.handle = self.model.addObject(cyl)
+ self.model.setParam('lores_density', density)
+ self.model.setParam('scale' , 1.0)
+ self.model.setParam('background' , 0.0)
+ self.model.setParam('%s.contrast' % self.handle, 1.0)
+ self.model.setParam('%s.radius' % self.handle, radius)
+ self.model.setParam('%s.length' % self.handle, length)
+
+ def testalongY(self):
+ """ Testing cylinder along Y axis """
+ self.ana.setParam('theta', math.pi/2.0)
+ self.ana.setParam('phi', math.pi/2.0)
+
+ self.model.setParam('%s.orientation' % self.handle, [0,0,0])
+
+ ana_val = self.ana.runXY([0.1, 0.2])
+ sim_val = self.model.getIq2D(0.1, 0.2)
+ #print ana_val, sim_val, sim_val/ana_val
+
+ self.assert_( math.fabs(sim_val/ana_val-1.0)<0.05 )
+
+
+class TestCylinder(unittest.TestCase):
+ """ Tests for oriented (2D) systems """
+
+ def setUp(self):
+ """ Set up cylinder model """
+ radius = 5
+ length = 40
+ density = 20
+
+ # Analytical model
+ self.ana = CylinderModel()
+ self.ana.setParam('scale', 1.0)
+ self.ana.setParam('background', 0.0)
+ self.ana.setParam('sld', 1.0)
+ self.ana.setParam('sld_solvent', 0.0)
+ self.ana.setParam('radius', radius)
+ self.ana.setParam('length', length)
+
+ # Simulation model
+ self.model = VolumeCanvas.VolumeCanvas()
+ self.handle = self.model.add('cylinder')
+ self.model.setParam('lores_density', density)
+ self.model.setParam('scale' , 1.0)
+ self.model.setParam('background' , 0.0)
+ self.model.setParam('%s.radius' % self.handle, radius)
+ self.model.setParam('%s.length' % self.handle, length)
+ self.model.setParam('%s.contrast' % self.handle, 1.0)
+
+ def testalongY(self):
+ """ Testing cylinder along Y axis """
+ self.ana.setParam('theta', math.pi/2.0)
+ self.ana.setParam('phi', math.pi/2.0)
+
+ self.model.setParam('%s.orientation' % self.handle, [0,0,0])
+
+ ana_val = self.ana.runXY([0.1, 0.2])
+ sim_val = self.model.getIq2D(0.1, 0.2)
+ #print ana_val, sim_val, sim_val/ana_val
+
+ self.assert_( math.fabs(sim_val/ana_val-1.0)<0.05 )
+
+ def testalongZ(self):
+ """ Testing cylinder along Z axis """
+ self.ana.setParam('theta', 0)
+ self.ana.setParam('phi', 0)
+
+ self.model.setParam('%s.orientation' % self.handle, [90,0,0])
+
+ ana_val = self.ana.runXY([0.1, 0.2])
+ sim_val = self.model.getIq2D(0.1, 0.2)
+ #print ana_val, sim_val, sim_val/ana_val
+
+ self.assert_( math.fabs(sim_val/ana_val-1.0)<0.05 )
+
+ def testalongX(self):
+ """ Testing cylinder along X axis """
+ self.ana.setParam('theta', 1.57)
+ self.ana.setParam('phi', 0)
+
+ self.model.setParam('%s.orientation' % self.handle, [0,0,90])
+
+ ana_val = self.ana.runXY([0.1, 0.2])
+ sim_val = self.model.getIq2D(0.1, 0.2)
+ #print ana_val, sim_val, sim_val/ana_val
+
+ self.assert_( math.fabs(sim_val/ana_val-1.0)<0.05 )
+
+class TestEllipsoid(unittest.TestCase):
+ """ Tests for oriented (2D) systems """
+
+ def setUp(self):
+ """ Set up ellipsoid """
+
+ radius_a = 60
+ radius_b = 10
+ density = 30
+
+ self.ana = EllipsoidModel()
+ self.ana.setParam('scale', 1.0)
+ self.ana.setParam('background', 0.0)
+ self.ana.setParam('sld', 1.0)
+ self.ana.setParam('sld_solvent', 0.0)
+ self.ana.setParam('radius_polar', radius_a)
+ self.ana.setParam('radius_equatorial', radius_b)
+ # Default orientation is there=1.57, phi=0
+ # Radius_a is along the x direction
+
+ canvas = VolumeCanvas.VolumeCanvas()
+ self.handle = canvas.add('ellipsoid')
+ canvas.setParam('lores_density', density)
+ canvas.setParam('scale' , 1.0)
+ canvas.setParam('background' , 0.0)
+ canvas.setParam('%s.radius_x' % self.handle, radius_a)
+ canvas.setParam('%s.radius_y' % self.handle, radius_b)
+ canvas.setParam('%s.radius_z' % self.handle, radius_b)
+ canvas.setParam('%s.contrast' % self.handle, 1.0)
+ self.canvas = canvas
+
+ def testalongX(self):
+ """ Testing ellipsoid along X """
+ self.ana.setParam('theta', 1.57)
+ self.ana.setParam('phi', 0)
+
+ self.canvas.setParam('%s.orientation' % self.handle, [0,0,0])
+
+ ana_val = self.ana.runXY([0.1, 0.2])
+ sim_val = self.canvas.getIq2D(0.1, 0.2)
+ #print ana_val, sim_val, sim_val/ana_val
+
+ self.assert_( math.fabs(sim_val/ana_val-1.0)<0.05 )
+
+ def testalongZ(self):
+ """ Testing ellipsoid along Z """
+ self.ana.setParam('theta', 0)
+ self.ana.setParam('phi', 0)
+
+ self.canvas.setParam('%s.orientation' % self.handle, [0,90,0])
+
+ ana_val = self.ana.runXY([0.1, 0.2])
+ sim_val = self.canvas.getIq2D(0.1, 0.2)
+ #print ana_val, sim_val, sim_val/ana_val
+
+ self.assert_( math.fabs(sim_val/ana_val-1.0)<0.05 )
+
+ def testalongY(self):
+ """ Testing ellipsoid along Y """
+ self.ana.setParam('theta', math.pi/2.0)
+ self.ana.setParam('phi', math.pi/2.0)
+
+ self.canvas.setParam('%s.orientation' % self.handle, [0,0,90])
+
+ ana_val = self.ana.runXY([0.05, 0.15])
+ sim_val = self.canvas.getIq2D(0.05, 0.15)
+ #print ana_val, sim_val, sim_val/ana_val
+
+ try:
+ self.assert_( math.fabs(sim_val/ana_val-1.0)<0.05 )
+ except Exception:
+ print("Error", ana_val, sim_val, sim_val/ana_val)
+ raise
+
+class TestCoreShell(unittest.TestCase):
+ """ Tests for oriented (2D) systems """
+
+ def setUp(self):
+ """ Set up zero-SLD-average core-shell model """
+
+ radius = 15
+ thickness = 5
+ density = 20
+
+ core_vol = 4.0/3.0*math.pi*radius*radius*radius
+ self.outer_radius = radius+thickness
+ shell_vol = 4.0/3.0*math.pi*self.outer_radius*self.outer_radius*self.outer_radius - core_vol
+ self.shell_sld = -1.0*core_vol/shell_vol
+
+ self.density = density
+
+ # Core-shell
+ sphere = CoreShellModel()
+ sphere.setParam('scale', 1.0)
+ sphere.setParam('background', 0.0)
+ # Core radius
+ sphere.setParam('radius', radius)
+ # Shell thickness
+ sphere.setParam('thickness', thickness)
+ sphere.setParam('sld_core', 1.0)
+ sphere.setParam('sld_shell', self.shell_sld)
+ sphere.setParam('sld_solvent', 0.0)
+ self.ana = sphere
+
+ canvas = VolumeCanvas.VolumeCanvas()
+ canvas.setParam('lores_density', self.density)
+ canvas.setParam('scale' , 1.0)
+ canvas.setParam('background' , 0.0)
+
+ handle = canvas.add('sphere')
+ canvas.setParam('%s.radius' % handle, self.outer_radius)
+ canvas.setParam('%s.contrast' % handle, self.shell_sld)
+
+ handle2 = canvas.add('sphere')
+ canvas.setParam('%s.radius' % handle2, radius)
+ canvas.setParam('%s.contrast' % handle2, 1.0)
+
+ self.canvas = canvas
+
+ def testdefault(self):
+ """ Testing default core-shell orientation """
+ ana_val = self.ana.runXY([0.1, 0.2])
+ sim_val, err = self.canvas.getIq2DError(0.1, 0.2)
+
+ self.assert_( math.fabs(sim_val/ana_val-1.0)<0.05 )
+
+class TestCoreShellError(unittest.TestCase):
+ """ Tests for oriented (2D) systems """
+
+ def setUp(self):
+ """ Set up zero-SLD-average core-shell model """
+
+ radius = 15
+ thickness = 5
+ density = 5
+
+ core_vol = 4.0/3.0*math.pi*radius*radius*radius
+ self.outer_radius = radius+thickness
+ shell_vol = 4.0/3.0*math.pi*self.outer_radius*self.outer_radius*self.outer_radius - core_vol
+ self.shell_sld = -1.0*core_vol/shell_vol
+
+ self.density = density
+
+ # Core-shell
+ sphere = CoreShellModel()
+ sphere.setParam('scale', 1.0)
+ sphere.setParam('background', 0.0)
+ # Core radius
+ sphere.setParam('radius', radius)
+ # Shell thickness
+ sphere.setParam('thickness', thickness)
+ sphere.setParam('sld_core', 1.0)
+ sphere.setParam('sld_shell', self.shell_sld)
+ sphere.setParam('sld_solvent', 0.0)
+ self.ana = sphere
+
+ canvas = VolumeCanvas.VolumeCanvas()
+ canvas.setParam('lores_density', self.density)
+ canvas.setParam('scale' , 1.0)
+ canvas.setParam('background' , 0.0)
+
+ handle = canvas.add('sphere')
+ canvas.setParam('%s.radius' % handle, self.outer_radius)
+ canvas.setParam('%s.contrast' % handle, self.shell_sld)
+
+ handle2 = canvas.add('sphere')
+ canvas.setParam('%s.radius' % handle2, radius)
+ canvas.setParam('%s.contrast' % handle2, 1.0)
+
+ self.canvas = canvas
+
+ def testdefault(self):
+ """ Testing default core-shell orientation """
+ ana_val = self.ana.runXY([0.1, 0.2])
+ sim_val, err = self.canvas.getIq2DError(0.1, 0.2)
+
+ self.assert_( math.fabs(sim_val-ana_val) < 3.0 * err )
+
+class TestRunMethods(unittest.TestCase):
+ """ Tests run methods for oriented (2D) systems """
+
+ def setUp(self):
+ """ Set up ellipsoid """
+
+ radius_a = 10
+ radius_b = 15
+ density = 5
+
+ self.ana = EllipsoidModel()
+ self.ana.setParam('scale', 1.0)
+ self.ana.setParam('background', 0.0)
+ self.ana.setParam('sld', 1.0)
+ self.ana.setParam('sld_solvent', 1.0)
+ self.ana.setParam('radius_polar', radius_a)
+ self.ana.setParam('radius_equatorial', radius_b)
+
+
+ canvas = VolumeCanvas.VolumeCanvas()
+ self.handle = canvas.add('ellipsoid')
+ canvas.setParam('lores_density', density)
+ canvas.setParam('scale' , 1.0)
+ canvas.setParam('background' , 0.0)
+ canvas.setParam('%s.radius_x' % self.handle, radius_a)
+ canvas.setParam('%s.radius_y' % self.handle, radius_b)
+ canvas.setParam('%s.radius_z' % self.handle, radius_b)
+ canvas.setParam('%s.contrast' % self.handle, 1.0)
+ self.canvas = canvas
+
+ self.ana.setParam('theta', 1.57)
+ self.ana.setParam('phi', 0)
+
+ self.canvas.setParam('%s.orientation' % self.handle, [0,0,0])
+
+
+ def testRunXY_List(self):
+ """ Testing ellipsoid along X """
+ ana_val = self.ana.runXY([0.1, 0.2])
+ sim_val = self.canvas.runXY([0.1, 0.2])
+ #print ana_val, sim_val, sim_val/ana_val
+
+ try:
+ self.assert_( math.fabs(sim_val/ana_val-1.0)<0.05 )
+ except Exception:
+ print("Error", ana_val, sim_val, sim_val/ana_val)
+ raise
+
+ def testRunXY_float(self):
+ """ Testing ellipsoid along X """
+ ana_val = self.ana.runXY(0.1)
+ sim_val = self.canvas.runXY(0.1)
+ #print ana_val, sim_val, sim_val/ana_val
+
+ try:
+ self.assert_( math.fabs(sim_val/ana_val-1.0)<0.05 )
+ except Exception:
+ print("Error", ana_val, sim_val, sim_val/ana_val)
+ raise
+
+ def testRun_float(self):
+ """ Testing ellipsoid along X """
+ ana_val = self.ana.run(0.1)
+ sim_val = self.canvas.run(0.1)
+ #print ana_val, sim_val, sim_val/ana_val
+
+ try:
+ self.assert_( math.fabs(sim_val/ana_val-1.0)<0.05 )
+ except Exception:
+ print("Error", ana_val, sim_val, sim_val/ana_val)
+ raise
+
+ def testRun_list(self):
+ """ Testing ellipsoid along X """
+ ana_val = self.ana.run([0.1, 33.0])
+ sim_val = self.canvas.run([0.1, 33.0])
+ #print ana_val, sim_val, sim_val/ana_val
+
+ try:
+ self.assert_( math.fabs(sim_val/ana_val-1.0)<0.05 )
+ except Exception:
+ print("Error", ana_val, sim_val, sim_val/ana_val)
+ raise
+
+class TestParamChange(unittest.TestCase):
+ """ Tests for oriented (2D) systems """
+
+ def setUp(self):
+ """ Set up cylinder model """
+ radius = 5
+ length = 40
+ density = 20
+
+ # Analytical model
+ self.ana = CylinderModel()
+ self.ana.setParam('scale', 1.0)
+ self.ana.setParam('background', 0.0)
+ self.ana.setParam('sld', 1.0)
+ self.ana.setParam('sld_solvent', 0.0)
+ self.ana.setParam('radius', radius)
+ self.ana.setParam('length', length)
+ self.ana.setParam('theta', math.pi/2.0)
+ self.ana.setParam('phi', math.pi/2.0)
+
+ # Simulation model
+ self.model = VolumeCanvas.VolumeCanvas()
+ self.handle = self.model.add('cylinder')
+ self.model.setParam('lores_density', density)
+ self.model.setParam('scale' , 1.0)
+ self.model.setParam('background' , 0.0)
+ self.model.setParam('%s.radius' % self.handle, radius)
+ self.model.setParam('%s.length' % self.handle, length)
+ self.model.setParam('%s.contrast' % self.handle, 1.0)
+ self.model.setParam('%s.orientation' % self.handle, [0,0,0])
+
+ def testalongY(self):
+ """ Test that a parameter change forces the generation
+ of new space points
+ """
+ ana_val = self.ana.runXY([0.1, 0.2])
+ sim_val = self.model.getIq2D(0.1, 0.2)
+
+ self.assert_( math.fabs(sim_val/ana_val-1.0)<0.05 )
+
+ # Change the radius a re-evaluate
+ self.ana.setParam('radius', 10)
+ self.model.setParam('%s.radius' % self.handle, 10)
+
+ ana_val = self.ana.runXY([0.1, 0.2])
+ sim_val = self.model.getIq2D(0.1, 0.2)
+ self.assert_( math.fabs(sim_val/ana_val-1.0)<0.05 )
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/test/sasrealspace/test/utest_realspace.py b/test/sasrealspace/test/utest_realspace.py
index 9298cc8..78ec3cf 100644
--- a/test/sasrealspace/test/utest_realspace.py
+++ b/test/sasrealspace/test/utest_realspace.py
@@ -1,376 +1,371 @@
-"""
- Unit tests for specific models
- @author: Mathieu Doucet / UTK
-"""
-
-import unittest, math, time
-
-# Disable "missing docstring" complaint
-# pylint: disable-msg=C0111
-# Disable "too many methods" complaint
-# pylint: disable-msg=R0904
-# Disable "could be a function" complaint
-# pylint: disable-msg=R0201
-
-try:
- import VolumeCanvas
- print "Testing local version"
-except:
- import sys
- print sys.exc_value
- #testing the version that is working on
- print "Testing installed version"
- import sas.sascalc.realspace.VolumeCanvas as VolumeCanvas
-
-class TestRealSpaceModel(unittest.TestCase):
- """ Unit tests for sphere model """
-
- def setUp(self):
- self.model = VolumeCanvas.VolumeCanvas()
- self.model.add('cylinder', 'cyl')
- self.model.add('sphere', 'sph')
- self.model.add('ellipsoid', 'elli')
- self.model.add('singlehelix', 'shelix')
-
- def testAdding(self):
- self.assertEqual('cyl', self.model.add('cylinder', 'cyl'))
-
- def testDeleting(self):
- self.model.add('ellipsoid','elli2')
- self.model.delete('elli2')
- self.assert_('elli2' not in self.model.getShapeList())
-
- def testsetParam(self):
- self.model.setParam('q_max', 0.2)
- self.model.setParam('shelix.radius_helix', 12)
-
- def testgetParamList(self):
- #print self.model.getParamList()
- #print self.model.getParamList('shelix')
- pass
-
- def testPr_Iq(self):
- self.model.getPr()
- #print "pr is calculated", self.model.hasPr
- result = self.model.getIq(0.1)
- #print "I(0.1) is calculated: ", result
-
-class TestSphere(unittest.TestCase):
- """ Unit tests for sphere model """
-
- def setUp(self):
- self.canvas = VolumeCanvas.VolumeCanvas()
-
-
- def testSetQmax(self):
- old_value = self.canvas.getParam('q_max')
- new_value = old_value + 0.1
- self.canvas.setParam('q_max', new_value)
- self.assertEqual(self.canvas.getParam("Q_MAx"), new_value)
-
- def testSetDensity(self):
- self.canvas.setParam('lores_density', 0.1)
- handle = self.canvas.add('sphere')
- self.canvas.setParam("%s.radius" % handle, 5.0)
- vol = 4/3*math.pi*5*5*5
- npts_1 = vol/0.1
- value_1 = self.canvas.getIq(0.001)
-
- # Change density, the answer should be the same
- self.canvas.setParam('lores_density', 0.2)
- npts_2 = vol/0.2
- value_2 = self.canvas.getIq(0.001)
-
- self.assert_( (value_1-value_2)/value_1 < 0.1)
-
- def testSetDensityTiming(self):
- """Testing change in computation time with density"""
- handle = self.canvas.add('sphere')
- self.canvas.setParam("%s.radius" % handle, 15.0)
-
- self.canvas.setParam('lores_density', 0.6)
- t_0 = time.time()
- self.canvas.getIq(0.001)
- t_1 = time.time()-t_0
-
- # Change density, the answer should be the same
- self.canvas.setParam('lores_density', 0.1)
- t_0 = time.time()
- self.canvas.getIq(0.001)
- t_2 = time.time()-t_0
-
- self.assert_( t_2 < t_1 and (t_1-t_2)/t_2 > 2)
-
- def testGetParamList(self):
- """ Test GetParamList on empty canvas"""
- self.assert_('lores_density' in self.canvas.getParamList())
- handle = self.canvas.add('sphere')
-
- def testGetParamListWithShape(self):
- """ Test GetParamList on filled canvas"""
- self.canvas.add('sphere')
- self.assert_('lores_density' in self.canvas.getParamList())
-
- def testAdd(self):
- handle = "s1"
- self.assertEqual(handle, self.canvas.add('sphere', handle))
-
- #TODO: test for current list of shape
- self.assertEqual( [handle] , self.canvas.getShapeList())
-
- def testSetRadius(self):
- handle = self.canvas.add('sphere')
- self.canvas.setParam("%s.rAdius" % handle, 24.0)
- self.assertEqual(self.canvas.getParam("%s.rAdius" % handle), 24.0)
-
- def testGetIq(self):
- """ Test the output of I(q) to the analytical solution
- If the normalization is wrong, we will have to fix it.
-
- getIq() should call getPr() behind the scenes so that
- the user doesnt have to do it if he doesn't need to.
- """
- from sas.models.SphereModel import SphereModel
- sphere = SphereModel()
- sphere.setParam('radius', 10.0)
- sphere.setParam('contrast', 1.0)
- sphere.setParam('background', 0.0)
- sphere.setParam('scale', 1.0)
-
- handle = self.canvas.add('sphere')
- self.canvas.setParam('%s.radius' % handle, 10.0)
- self.canvas.setParam('%s.contrast' % handle, 1.0)
-
-
- sim_1 = self.canvas.getIq(0.001)
- ana_1 = sphere.run(0.001)
- sim_2 = self.canvas.getIq(0.01)
- ana_2 = sphere.run(0.01)
-
- # test the shape of the curve (calculate relative error
- # on the output and it should be compatible with zero
- # THIS WILL DEPEND ON THE NUMBER OF SPACE POINTS:
- # that why we need some error analysis.
- self.assert_( (sim_2*ana_1/sim_1 - ana_2)/ana_2 < 0.1)
-
- # test the absolute amplitude
- self.assert_( math.fabs(sim_2-ana_2)/ana_2 < 0.1)
-
- def testGetIq2(self):
- """ Test two different q values
- """
- handle = self.canvas.add('sphere')
- self.canvas.setParam('%s.radius' % handle, 10.0)
-
- sim_1 = self.canvas.getIq(0.001)
- sim_2 = self.canvas.getIq(0.01)
-
- self.assertNotAlmostEqual(sim_2, sim_1, 3)
-
- def testGetIq_Identical(self):
- """ Test for identical model / no param change
- """
- handle = self.canvas.add('sphere')
- self.canvas.setParam('%s.radius' % handle, 10.0)
-
- sim_1 = self.canvas.getIq(0.01)
- sim_2 = self.canvas.getIq(0.01)
-
- self.assertEqual(sim_2, sim_1)
-
- def testGetIq_Identical2(self):
- """ Test for identical model after a parameter change
- Should be different only of the space points
- are regenerated and the random seed is different
- """
- handle = self.canvas.add('sphere')
- self.canvas.setParam('%s.radius' % handle, 10.0)
-
- self.canvas.setParam('lores_density', 0.1)
- sim_1 = self.canvas.getIq(0.01)
-
- # Try to fool the code by changing to a different value
- self.canvas.setParam('lores_density', 0.2)
- self.canvas.getIq(0.01)
-
- self.canvas.setParam('lores_density', 0.1)
- sim_2 = self.canvas.getIq(0.01)
-
- self.assert_((sim_2-sim_1)/sim_1<0.05)
-
- def testGetIq_time(self):
- """ Time profile
- """
- handle = self.canvas.add('sphere')
- self.canvas.setParam('%s.radius' % handle, 15.0)
-
-
- self.canvas.setParam('lores_density', 0.1)
- t_0 = time.time()
- sim_1 = self.canvas.getIq(0.01)
- delta_1 = time.time()-t_0
-
- self.canvas.setParam('lores_density', 0.1)
-
- t_0 = time.time()
- sim_2 = self.canvas.getIq(0.01)
- delta_2 = time.time()-t_0
-
- self.assert_((delta_2-delta_1)/delta_1<0.05)
-
-
- def testGetPr(self):
- """Compare the output of P(r) to the theoretical value"""
- #TODO: find a way to compare you P(r) to the known
- # analytical value.
- pass
-
- def testLogic1(self):
- """ Test that the internal logic is set so that the user
- get the right output after changing a parameter
- """
-
- handle = self.canvas.add('sphere')
- self.canvas.setParam('%s.radius' % handle, 10.0)
- result_1 = self.canvas.getIq(0.1)
- self.canvas.setParam('%s.radius' % handle, 20.0)
- result_2 = self.canvas.getIq(0.1)
- self.assertNotAlmostEqual(result_1, result_2, 2)
-
-class TestCanvas(unittest.TestCase):
- """ Unit tests for all shapes in canvas model """
-
- def setUp(self):
- self.canvas = VolumeCanvas.VolumeCanvas()
- self.canvas.params['lores_density'] = 0.05
-
- def testGetIq_cylinder(self):
- handle = self.canvas.add('cylinder','cyl')
- self.canvas.setParam('%s.radius' % handle, 15.0)
- self.canvas.setParam('%s.length' % handle, 50.0)
- self.assertEqual(50,self.canvas.getParam('%s.length'%handle))
- result_1 = self.canvas.getIq(0.1)
- result_2 = self.canvas.getIq(0.1)
- self.assertEqual(result_1,result_2)
-
- self.canvas.delete(handle)
- handle2 = self.canvas.add('cylinder','cyl2')
- self.assertEqual(40,self.canvas.getParam('%s.length'%handle2))
- result_3 = self.canvas.getIq(0.1)
- self.assertNotEqual(result_1, result_3)
-
- def testGetIq_ellipsoid(self):
- handle = self.canvas.add('ellipsoid','elli')
- self.canvas.setParam('%s.radius_x' % handle, 35)
- self.canvas.setParam('%s.radius_y' % handle, 20)
- self.canvas.setParam('%s.radius_z' % handle, 10)
- result_1 = self.canvas.getIq(0.1)
- result_2 = self.canvas.getIq(0.1)
- self.assertEqual(result_1,result_2)
-
- self.canvas.delete(handle)
- self.assertEqual(False,self.canvas.hasPr)
- handle2 = self.canvas.add('ellipsoid','elli2')
- result_3 = self.canvas.getIq(0.1)
- self.assertNotEqual(result_1, result_3)
-
- def testGetIq_singlehelix(self):
- handle = self.canvas.add('singlehelix','shelix')
- self.canvas.setParam('%s.radius_helix' % handle, 11)
- self.canvas.setParam('%s.radius_tube' % handle, 4)
- self.canvas.setParam('%s.pitch' % handle, 30)
- self.canvas.setParam('%s.turns' % handle, 3.2)
- result_1 = self.canvas.getIq(0.1)
- result_2 = self.canvas.getIq(0.1)
- self.assertEqual(result_1,result_2)
-
- self.canvas.delete(handle)
- self.assertEqual(False,self.canvas.hasPr)
- handle2 = self.canvas.add('singlehelix','shelix2')
- result_3 = self.canvas.getIq(0.1)
- self.assertNotEqual(result_1, result_3)
-
-class TestOrdering(unittest.TestCase):
- """ Unit tests for all shapes in canvas model """
-
- def setUp(self):
- from sas.models.CoreShellModel import CoreShellModel
- radius = 15
- thickness = 5
- core_vol = 4.0/3.0*math.pi*radius*radius*radius
- outer_radius = radius+thickness
- shell_vol = 4.0/3.0*math.pi*outer_radius*outer_radius*outer_radius - core_vol
- self.shell_sld = -1.0*core_vol/shell_vol
-
- self.canvas = VolumeCanvas.VolumeCanvas()
- self.canvas.params['lores_density'] = 0.1
-
- # Core shell model
- sphere = CoreShellModel()
- # Core radius
- sphere.setParam('radius', radius)
- # Shell thickness
- sphere.setParam('thickness', thickness)
- sphere.setParam('core_sld', 1.0)
- sphere.setParam('shell_sld', self.shell_sld)
- sphere.setParam('solvent_sld', 0.0)
- sphere.setParam('background', 0.0)
- sphere.setParam('scale', 1.0)
- self.sphere = sphere
- self.radius = radius
- self.outer_radius = outer_radius
-
- def set_coreshell_on_canvas(self, order1=None, order2=None):
-
- handle = self.canvas.add('sphere')
- self.canvas.setParam('%s.radius' % handle, self.outer_radius)
- self.canvas.setParam('%s.contrast' % handle, self.shell_sld)
- if not order1 == None:
- self.canvas.setParam('%s.order' % handle, order1)
-
- handle2 = self.canvas.add('sphere')
- self.canvas.setParam('%s.radius' % handle2, self.radius)
- self.canvas.setParam('%s.contrast' % handle2, 1.0)
- if not order2 == None:
- self.canvas.setParam('%s.order' % handle2, order2)
-
- self.canvas.setParam('scale' , 1.0)
- self.canvas.setParam('background' , 0.0)
-
-
- def testDefaultOrder(self):
- self.set_coreshell_on_canvas()
-
- ana = self.sphere.run(0.05)
- val, err = self.canvas.getIqError(0.05)
- self.assert_(math.fabs(ana-val)<2.0*err)
-
- def testRightOrder(self):
- self.set_coreshell_on_canvas(3.0, 6.0)
-
- ana = self.sphere.run(0.05)
- val, err = self.canvas.getIqError(0.05)
- #print 'right', ana, val, err
- self.assert_(math.fabs(ana-val)/ana < 1.1)
-
- def testWrongOrder(self):
- from sas.models.SphereModel import SphereModel
- self.set_coreshell_on_canvas(1, 0)
-
- # Core shell model
- sphere = SphereModel()
- # Core radius
- sphere.setParam('radius', self.outer_radius)
- # Shell thickness
- sphere.setParam('contrast', self.shell_sld)
- sphere.setParam('background', 0.0)
- sphere.setParam('scale', 1.0)
-
- ana = sphere.run(0.05)
- val, err = self.canvas.getIqError(0.05)
- #print 'wrong', ana, val, err
- self.assert_(math.fabs(ana-val)/ana < 1.1)
-
-
-if __name__ == '__main__':
- unittest.main()
+"""
+ Unit tests for specific models
+ @author: Mathieu Doucet / UTK
+"""
+from __future__ import print_function
+
+import unittest, math, time
+
+# Disable "missing docstring" complaint
+# pylint: disable-msg=C0111
+# Disable "too many methods" complaint
+# pylint: disable-msg=R0904
+# Disable "could be a function" complaint
+# pylint: disable-msg=R0201
+
+from sasmodels.sasview_model import _make_standard_model
+EllipsoidModel = _make_standard_model('ellipsoid')
+SphereModel = _make_standard_model('sphere')
+CylinderModel = _make_standard_model('cylinder')
+CoreShellModel = _make_standard_model('core_shell_sphere')
+
+import sas.sascalc.realspace.VolumeCanvas as VolumeCanvas
+
+class TestRealSpaceModel(unittest.TestCase):
+ """ Unit tests for sphere model """
+
+ def setUp(self):
+ self.model = VolumeCanvas.VolumeCanvas()
+ self.model.add('cylinder', 'cyl')
+ self.model.add('sphere', 'sph')
+ self.model.add('ellipsoid', 'elli')
+ self.model.add('singlehelix', 'shelix')
+
+ def testAdding(self):
+ self.assertEqual('cyl', self.model.add('cylinder', 'cyl'))
+
+ def testDeleting(self):
+ self.model.add('ellipsoid','elli2')
+ self.model.delete('elli2')
+ self.assert_('elli2' not in self.model.getShapeList())
+
+ def testsetParam(self):
+ self.model.setParam('q_max', 0.2)
+ self.model.setParam('shelix.radius_helix', 12)
+
+ def testgetParamList(self):
+ #print self.model.getParamList()
+ #print self.model.getParamList('shelix')
+ pass
+
+ def testPr_Iq(self):
+ self.model.getPr()
+ #print "pr is calculated", self.model.hasPr
+ result = self.model.getIq(0.1)
+ #print "I(0.1) is calculated: ", result
+
+class TestSphere(unittest.TestCase):
+ """ Unit tests for sphere model """
+
+ def setUp(self):
+ self.canvas = VolumeCanvas.VolumeCanvas()
+
+
+ def testSetQmax(self):
+ old_value = self.canvas.getParam('q_max')
+ new_value = old_value + 0.1
+ self.canvas.setParam('q_max', new_value)
+ self.assertEqual(self.canvas.getParam("Q_MAx"), new_value)
+
+ def testSetDensity(self):
+ self.canvas.setParam('lores_density', 0.1)
+ handle = self.canvas.add('sphere')
+ self.canvas.setParam("%s.radius" % handle, 5.0)
+ vol = 4/3*math.pi*5*5*5
+ npts_1 = vol/0.1
+ value_1 = self.canvas.getIq(0.001)
+
+ # Change density, the answer should be the same
+ self.canvas.setParam('lores_density', 0.2)
+ npts_2 = vol/0.2
+ value_2 = self.canvas.getIq(0.001)
+
+ self.assert_( (value_1-value_2)/value_1 < 0.1)
+
+ def testSetDensityTiming(self):
+ """Testing change in computation time with density"""
+ handle = self.canvas.add('sphere')
+ self.canvas.setParam("%s.radius" % handle, 15.0)
+
+ self.canvas.setParam('lores_density', 0.6)
+ t_0 = time.time()
+ self.canvas.getIq(0.001)
+ t_1 = time.time()-t_0
+
+ # Change density, the answer should be the same
+ self.canvas.setParam('lores_density', 0.1)
+ t_0 = time.time()
+ self.canvas.getIq(0.001)
+ t_2 = time.time()-t_0
+
+ self.assert_( t_2 < t_1 and (t_1-t_2)/t_2 > 2)
+
+ def testGetParamList(self):
+ """ Test GetParamList on empty canvas"""
+ self.assert_('lores_density' in self.canvas.getParamList())
+ handle = self.canvas.add('sphere')
+
+ def testGetParamListWithShape(self):
+ """ Test GetParamList on filled canvas"""
+ self.canvas.add('sphere')
+ self.assert_('lores_density' in self.canvas.getParamList())
+
+ def testAdd(self):
+ handle = "s1"
+ self.assertEqual(handle, self.canvas.add('sphere', handle))
+
+ #TODO: test for current list of shape
+ self.assertEqual( [handle] , self.canvas.getShapeList())
+
+ def testSetRadius(self):
+ handle = self.canvas.add('sphere')
+ self.canvas.setParam("%s.radius" % handle, 24.0)
+ self.assertEqual(self.canvas.getParam("%s.radius" % handle), 24.0)
+
+ def testGetIq(self):
+ """ Test the output of I(q) to the analytical solution
+ If the normalization is wrong, we will have to fix it.
+
+ getIq() should call getPr() behind the scenes so that
+ the user doesnt have to do it if he doesn't need to.
+ """
+ sphere = SphereModel()
+ sphere.setParam('scale', 1.0)
+ sphere.setParam('background', 0.0)
+ sphere.setParam('sld', 1.0)
+ sphere.setParam('sld_solvent', 0.0)
+ sphere.setParam('radius', 10.0)
+
+ handle = self.canvas.add('sphere')
+ self.canvas.setParam('%s.radius' % handle, 10.0)
+ self.canvas.setParam('%s.contrast' % handle, 1.0)
+
+
+ sim_1 = self.canvas.getIq(0.001)
+ ana_1 = sphere.run(0.001)
+ sim_2 = self.canvas.getIq(0.01)
+ ana_2 = sphere.run(0.01)
+
+ # test the shape of the curve (calculate relative error
+ # on the output and it should be compatible with zero
+ # THIS WILL DEPEND ON THE NUMBER OF SPACE POINTS:
+ # that why we need some error analysis.
+ self.assert_( (sim_2*ana_1/sim_1 - ana_2)/ana_2 < 0.1)
+
+ # test the absolute amplitude
+ self.assert_( math.fabs(sim_2-ana_2)/ana_2 < 0.1)
+
+ def testGetIq2(self):
+ """ Test two different q values
+ """
+ handle = self.canvas.add('sphere')
+ self.canvas.setParam('%s.radius' % handle, 10.0)
+
+ sim_1 = self.canvas.getIq(0.001)
+ sim_2 = self.canvas.getIq(0.01)
+
+ self.assertNotAlmostEqual(sim_2, sim_1, 3)
+
+ def testGetIq_Identical(self):
+ """ Test for identical model / no param change
+ """
+ handle = self.canvas.add('sphere')
+ self.canvas.setParam('%s.radius' % handle, 10.0)
+
+ sim_1 = self.canvas.getIq(0.01)
+ sim_2 = self.canvas.getIq(0.01)
+
+ self.assertEqual(sim_2, sim_1)
+
+ def testGetIq_Identical2(self):
+ """ Test for identical model after a parameter change
+ Should be different only of the space points
+ are regenerated and the random seed is different
+ """
+ handle = self.canvas.add('sphere')
+ self.canvas.setParam('%s.radius' % handle, 10.0)
+
+ self.canvas.setParam('lores_density', 0.1)
+ sim_1 = self.canvas.getIq(0.01)
+
+ # Try to fool the code by changing to a different value
+ self.canvas.setParam('lores_density', 0.2)
+ self.canvas.getIq(0.01)
+
+ self.canvas.setParam('lores_density', 0.1)
+ sim_2 = self.canvas.getIq(0.01)
+
+ self.assert_((sim_2-sim_1)/sim_1<0.05)
+
+ def testGetIq_time(self):
+ """ Time profile
+ """
+ handle = self.canvas.add('sphere')
+ self.canvas.setParam('%s.radius' % handle, 15.0)
+
+
+ self.canvas.setParam('lores_density', 0.1)
+ t_0 = time.time()
+ sim_1 = self.canvas.getIq(0.01)
+ delta_1 = time.time()-t_0
+
+ self.canvas.setParam('lores_density', 0.1)
+
+ t_0 = time.time()
+ sim_2 = self.canvas.getIq(0.01)
+ delta_2 = time.time()-t_0
+
+ self.assert_((delta_2-delta_1)/delta_1<0.05)
+
+
+ def testGetPr(self):
+ """Compare the output of P(r) to the theoretical value"""
+ #TODO: find a way to compare you P(r) to the known
+ # analytical value.
+ pass
+
+ def testLogic1(self):
+ """ Test that the internal logic is set so that the user
+ get the right output after changing a parameter
+ """
+
+ handle = self.canvas.add('sphere')
+ self.canvas.setParam('%s.radius' % handle, 10.0)
+ result_1 = self.canvas.getIq(0.1)
+ self.canvas.setParam('%s.radius' % handle, 20.0)
+ result_2 = self.canvas.getIq(0.1)
+ self.assertNotAlmostEqual(result_1, result_2, 2)
+
+class TestCanvas(unittest.TestCase):
+ """ Unit tests for all shapes in canvas model """
+
+ def setUp(self):
+ self.canvas = VolumeCanvas.VolumeCanvas()
+ self.canvas.params['lores_density'] = 0.05
+
+ def testGetIq_cylinder(self):
+ handle = self.canvas.add('cylinder','cyl')
+ self.canvas.setParam('%s.radius' % handle, 15.0)
+ self.canvas.setParam('%s.length' % handle, 50.0)
+ self.assertEqual(50,self.canvas.getParam('%s.length'%handle))
+ result_1 = self.canvas.getIq(0.1)
+ result_2 = self.canvas.getIq(0.1)
+ self.assertEqual(result_1,result_2)
+
+ self.canvas.delete(handle)
+ handle2 = self.canvas.add('cylinder','cyl2')
+ self.assertEqual(40,self.canvas.getParam('%s.length'%handle2))
+ result_3 = self.canvas.getIq(0.1)
+ self.assertNotEqual(result_1, result_3)
+
+ def testGetIq_ellipsoid(self):
+ handle = self.canvas.add('ellipsoid','elli')
+ self.canvas.setParam('%s.radius_x' % handle, 35)
+ self.canvas.setParam('%s.radius_y' % handle, 20)
+ self.canvas.setParam('%s.radius_z' % handle, 10)
+ result_1 = self.canvas.getIq(0.1)
+ result_2 = self.canvas.getIq(0.1)
+ self.assertEqual(result_1,result_2)
+
+ self.canvas.delete(handle)
+ self.assertEqual(False,self.canvas.hasPr)
+ handle2 = self.canvas.add('ellipsoid','elli2')
+ result_3 = self.canvas.getIq(0.1)
+ self.assertNotEqual(result_1, result_3)
+
+ def testGetIq_singlehelix(self):
+ handle = self.canvas.add('singlehelix','shelix')
+ self.canvas.setParam('%s.radius_helix' % handle, 11)
+ self.canvas.setParam('%s.radius_tube' % handle, 4)
+ self.canvas.setParam('%s.pitch' % handle, 30)
+ self.canvas.setParam('%s.turns' % handle, 3.2)
+ result_1 = self.canvas.getIq(0.1)
+ result_2 = self.canvas.getIq(0.1)
+ self.assertEqual(result_1,result_2)
+
+ self.canvas.delete(handle)
+ self.assertEqual(False,self.canvas.hasPr)
+ handle2 = self.canvas.add('singlehelix','shelix2')
+ result_3 = self.canvas.getIq(0.1)
+ self.assertNotEqual(result_1, result_3)
+
+class TestOrdering(unittest.TestCase):
+ """ Unit tests for all shapes in canvas model """
+
+ def setUp(self):
+ radius = 15
+ thickness = 5
+ core_vol = 4.0/3.0*math.pi*radius*radius*radius
+ outer_radius = radius+thickness
+ shell_vol = 4.0/3.0*math.pi*outer_radius*outer_radius*outer_radius - core_vol
+ self.shell_sld = -1.0*core_vol/shell_vol
+
+ self.canvas = VolumeCanvas.VolumeCanvas()
+ self.canvas.params['lores_density'] = 0.1
+
+ # Core shell model
+ sphere = CoreShellModel()
+ sphere.setParam('scale', 1.0)
+ sphere.setParam('background', 0.0)
+ sphere.setParam('sld_core', 1.0)
+ sphere.setParam('sld_shell', self.shell_sld)
+ sphere.setParam('sld_solvent', 0.0)
+ # Core radius
+ sphere.setParam('radius', radius)
+ # Shell thickness
+ sphere.setParam('thickness', thickness)
+ self.sphere = sphere
+ self.radius = radius
+ self.outer_radius = outer_radius
+
+ def set_coreshell_on_canvas(self, order1=None, order2=None):
+
+ handle = self.canvas.add('sphere')
+ self.canvas.setParam('scale' , 1.0)
+ self.canvas.setParam('background' , 0.0)
+
+ self.canvas.setParam('%s.radius' % handle, self.outer_radius)
+ self.canvas.setParam('%s.contrast' % handle, self.shell_sld)
+ if order1 is not None:
+ self.canvas.setParam('%s.order' % handle, order1)
+
+ handle2 = self.canvas.add('sphere')
+ self.canvas.setParam('%s.radius' % handle2, self.radius)
+ self.canvas.setParam('%s.contrast' % handle2, 1.0)
+ if order2 is not None:
+ self.canvas.setParam('%s.order' % handle2, order2)
+
+
+ def testDefaultOrder(self):
+ self.set_coreshell_on_canvas()
+
+ ana = self.sphere.run(0.05)
+ val, err = self.canvas.getIqError(0.05)
+ self.assert_(math.fabs(ana-val)<2.0*err)
+
+ def testRightOrder(self):
+ self.set_coreshell_on_canvas(3.0, 6.0)
+
+ ana = self.sphere.run(0.05)
+ val, err = self.canvas.getIqError(0.05)
+ #print 'right', ana, val, err
+ self.assert_(math.fabs(ana-val)/ana < 1.1)
+
+ def testWrongOrder(self):
+ self.set_coreshell_on_canvas(1, 0)
+
+ sphere = SphereModel()
+ sphere.setParam('scale', 1.0)
+ sphere.setParam('background', 0.0)
+ sphere.setParam('radius', self.outer_radius)
+ sphere.setParam('sld', self.shell_sld)
+ sphere.setParam('sld_solvent', 0.0)
+
+ ana = sphere.run(0.05)
+ val, err = self.canvas.getIqError(0.05)
+ #print 'wrong', ana, val, err
+ self.assert_(math.fabs(ana-val)/ana < 1.1)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/test/utest_sasview.py b/test/utest_sasview.py
old mode 100644
new mode 100755
index 15994d2..7aa0887
--- a/test/utest_sasview.py
+++ b/test/utest_sasview.py
@@ -1,102 +1,113 @@
-#!/usr/bin/env python
-import os
-import subprocess
-import re
-import sys
-try:
- import xmlrunner
-except:
- print "xmlrunner needs to be installed to run these tests"
- print "Try easy_install unittest-xml-reporting"
- sys.exit(1)
-
-# Check whether we have matplotlib installed
-HAS_MPL_WX = True
-try:
- import matplotlib
- import wx
-except:
- HAS_MPL_WX = False
-
-SKIPPED_DIRS = ["sasrealspace", "calculatorview"]
-if not HAS_MPL_WX:
- SKIPPED_DIRS.append("sasguiframe")
-
-#COMMAND_SEP = ';'
-#if os.name == 'nt':
-# COMMAND_SEP = '&'
-
-def run_tests(dirs=None, all=False):
- test_root = os.path.abspath(os.path.dirname(__file__))
- run_one_py = os.path.join(test_root, 'run_one.py')
- passed = 0
- failed = 0
- n_tests = 0
- n_errors = 0
- n_failures = 0
-
- for d in (dirs if dirs else os.listdir(test_root)):
-
- # Check for modules to be skipped
- if d in SKIPPED_DIRS:
- continue
-
- # Go through modules looking for unit tests
- module_dir = os.path.join(test_root, d, "test")
- if os.path.isdir(module_dir):
- for f in os.listdir(module_dir):
- file_path = os.path.join(module_dir,f)
- if os.path.isfile(file_path) and f.startswith("utest_") and f.endswith(".py"):
- module_name,_ = os.path.splitext(f)
- code = '"%s" %s %s'%(sys.executable, run_one_py, file_path)
- proc = subprocess.Popen(code, shell=True, stdout=subprocess.PIPE, stderr = subprocess.STDOUT)
- std_out, std_err = proc.communicate()
- #print std_out
- #sys.exit()
- has_failed = True
- m = re.search("Ran ([0-9]+) test", std_out)
- if m is not None:
- has_failed = False
- n_tests += int(m.group(1))
-
- m = re.search("FAILED \(errors=([0-9]+)\)", std_out)
- if m is not None:
- has_failed = True
- n_errors += int(m.group(1))
-
- m = re.search("FAILED \(failures=([0-9]+)\)", std_out)
- if m is not None:
- has_failed = True
- n_failures += int(m.group(1))
-
- if has_failed:
- failed += 1
- print "Result for %s (%s): FAILED" % (module_name, module_dir)
- print std_out
- else:
- passed += 1
- print "Result for %s: SUCCESS" % module_name
-
- print "\n----------------------------------------------"
- if n_tests == 0:
- print "No tests."
- else:
- print "Results by test modules:"
- print " PASSED: %d" % passed
- ratio = 100.0*failed/(failed+passed)
- print " FAILED: %d (%.0f%%)" % (failed,ratio)
-
- print "Results by tests:"
- print " Tests run: %d" % n_tests
- print " Tests failed: %d" % n_failures
- print " Test errors: %d" % n_errors
- print "----------------------------------------------"
-
- return failed
-
-if __name__ == '__main__':
- all = (len(sys.argv) > 1 and sys.argv[1] == '-all')
- dirs = sys.argv[1:] if not all else sys.argv[2:]
- if run_tests(dirs=dirs, all=all)>0:
- sys.exit(1)
-
+#!/usr/bin/env python
+from __future__ import print_function
+
+import os
+import subprocess
+import re
+import sys
+
+import logging
+import logging.config
+LOGGER_CONFIG_FILE = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'logging.ini')
+logging.config.fileConfig(LOGGER_CONFIG_FILE)
+logger = logging.getLogger(__name__)
+
+try:
+ import xmlrunner
+except:
+ logger.error("xmlrunner needs to be installed to run these tests")
+ logger.error("Try easy_install unittest-xml-reporting")
+ sys.exit(1)
+
+# Check whether we have matplotlib installed
+HAS_MPL_WX = True
+try:
+ import matplotlib
+ import wx
+except ImportError:
+ HAS_MPL_WX = False
+
+SKIPPED_DIRS = ["sasrealspace", "calculatorview"]
+if not HAS_MPL_WX:
+ SKIPPED_DIRS.append("sasguiframe")
+
+#COMMAND_SEP = ';'
+#if os.name == 'nt':
+# COMMAND_SEP = '&'
+
+def run_tests(dirs=None, run_all=False):
+ test_root = os.path.abspath(os.path.dirname(__file__))
+ run_one_py = os.path.join(test_root, 'run_one.py')
+ passed = 0
+ failed = 0
+ n_tests = 0
+ n_errors = 0
+ n_failures = 0
+
+ for d in (dirs if dirs else os.listdir(test_root)):
+
+ # Check for modules to be skipped
+ if d in SKIPPED_DIRS:
+ continue
+
+
+ # Go through modules looking for unit tests
+ module_dir = os.path.join(test_root, d, "test")
+ if os.path.isdir(module_dir):
+ for f in os.listdir(module_dir):
+ file_path = os.path.join(module_dir,f)
+ if os.path.isfile(file_path) and f.startswith("utest_") and f.endswith(".py"):
+ module_name,_ = os.path.splitext(f)
+ code = '"%s" %s %s'%(sys.executable, run_one_py, file_path)
+ proc = subprocess.Popen(code, shell=True, stdout=subprocess.PIPE, stderr = subprocess.STDOUT)
+ std_out, std_err = proc.communicate()
+ std_out, std_err = std_out.decode(), (std_err.decode() if std_err else None)
+ #print(">>>>>> standard out", file_path, "\n", std_out, "\n>>>>>>>>> end stdout", file_path)
+ #sys.exit()
+ m = re.search("Ran ([0-9]+) test", std_out)
+ if m is not None:
+ n_tests += int(m.group(1))
+ has_tests = True
+ else:
+ has_tests = False
+
+ has_failed = "FAILED (" in std_out
+ m = re.search("FAILED \(.*errors=([0-9]+)", std_out)
+ if m is not None:
+ n_errors += int(m.group(1))
+ m = re.search("FAILED \(.*failures=([0-9]+)", std_out)
+ if m is not None:
+ n_failures += int(m.group(1))
+
+ if has_failed or not has_tests:
+ failed += 1
+ modpath = os.path.join(module_dir, module_name+".py")
+ print("Result for %s: FAILED %s"
+ % (module_name, os.path.relpath(modpath, os.getcwd())))
+ #print(std_out)
+ else:
+ passed += 1
+ print("Result for %s: SUCCESS" % module_name)
+
+ print("\n----------------------------------------------")
+ if n_tests == 0:
+ print("No tests.")
+ else:
+ print("Results by test modules:")
+ print(" PASSED: %d" % passed)
+ ratio = 100.0*failed/(failed+passed)
+ print(" FAILED: %d (%.0f%%)" % (failed,ratio))
+
+ print("Results by tests:")
+ print(" Tests run: %d" % n_tests)
+ print(" Tests failed: %d" % n_failures)
+ print(" Test errors: %d" % n_errors)
+ print("----------------------------------------------")
+
+ return failed
+
+if __name__ == '__main__':
+ run_all = (len(sys.argv) > 1 and sys.argv[1] == '-all')
+ dirs = sys.argv[1:] if not run_all else sys.argv[2:]
+ if run_tests(dirs=dirs, run_all=run_all)>0:
+ sys.exit(1)
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/sasview.git
More information about the debian-science-commits
mailing list