├── scripts ├── __init__.py ├── requirements.txt ├── model_interpolators │ └── readme.txt ├── compile_fortran_codes.py ├── dask_client.py ├── solar_isotopes.py ├── convolve.py ├── solar_abundances.py ├── auxiliary_functions.py ├── faltbon.f90 ├── run_wrapper.py └── marcs_class.py ├── unittests ├── __init__.py ├── linelist_testing │ ├── molecular_test_data2 │ ├── molecular_test_data3 │ ├── expected_result │ │ ├── molecular_test_data_expected │ │ └── atomic_test_data_expected │ ├── molecular_test_data │ └── atomic_test_data └── unit_test.py ├── .gitattributes ├── output_files └── readme.txt ├── input_files ├── linemask_files │ ├── O │ │ └── o-lmask.txt │ ├── Li │ │ └── li-lmask.txt │ ├── Sr │ │ └── sr-lmask.txt │ ├── Al │ │ └── al-lmask.txt │ ├── Fe │ │ ├── fe-lmask_test.txt │ │ └── fe-lmask.txt │ ├── Na │ │ └── na-lmask.txt │ ├── Ba │ │ └── ba-lmask.txt │ ├── Si │ │ └── si-lmask.txt │ ├── Mg │ │ └── mg-lmask.txt │ ├── Eu │ │ └── eu-lmask.txt │ ├── Y │ │ └── y-lmask.txt │ ├── Ca │ │ └── ca-lmask.txt │ ├── Co │ │ ├── co-seg.txt │ │ └── co-lmask.txt │ ├── Cr │ │ ├── cr-seg.txt │ │ └── cr-lmask.txt │ ├── H │ │ └── H-lmask.txt │ ├── Ti │ │ └── ti-lmask.txt │ └── Ni │ │ └── ni-lmask.txt ├── nlte_data │ ├── model_atoms │ │ └── readme.txt │ ├── readme.txt │ └── nlte_filenames.cfg ├── fitlist ├── fitlist_example ├── observed_spectra │ └── readme.txt ├── synthetic_spectra_parameters ├── synthetic_spectra_generation_configuration.cfg ├── linelists │ ├── linelist_vald │ │ └── Hlinedata │ └── linelist_for_fitting │ │ └── Hlinedata ├── tsfitpy_input_configuration.cfg └── model_atmospheres │ └── 3D │ └── model_atmosphere_list.txt ├── docs └── tsfitpy_doc.pdf ├── example_image_plot └── fitted_star_example.png ├── turbospectrum └── readme.txt ├── calculate_nlte_correction_line.py ├── main.py ├── utilities ├── print_interesting_loggf.py ├── read_nlte_grid.py ├── download_nlte_grids.py └── nlte_grids_links.cfg └── plotting_tools ├── plot_synthetic_grid.ipynb ├── analyse_the_output.py ├── analyse_the_output_new_flags.py └── plot_output.ipynb /scripts/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /unittests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.zip filter=lfs diff=lfs merge=lfs -text 2 | -------------------------------------------------------------------------------- /output_files/readme.txt: -------------------------------------------------------------------------------- 1 | Output files from fitting will end up here. 2 | 3 | -------------------------------------------------------------------------------- /input_files/linemask_files/O/o-lmask.txt: -------------------------------------------------------------------------------- 1 | ; 2 | 6300.3040 6300.0 6300.51 16.01 3 | -------------------------------------------------------------------------------- /input_files/nlte_data/model_atoms/readme.txt: -------------------------------------------------------------------------------- 1 | put all model atom files here for all elements 2 | -------------------------------------------------------------------------------- /docs/tsfitpy_doc.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TSFitPy-developers/TSFitPy/HEAD/docs/tsfitpy_doc.pdf -------------------------------------------------------------------------------- /scripts/requirements.txt: -------------------------------------------------------------------------------- 1 | numpy 2 | matplotlib 3 | astropy 4 | scipy 5 | dask 6 | pandas 7 | dask_jobqueue -------------------------------------------------------------------------------- /input_files/linemask_files/Li/li-lmask.txt: -------------------------------------------------------------------------------- 1 | ; 2 | 6707.7610 6707.57 6707.8 03.01 3 | 6707.9120 6707.8 6708.34 03.01 4 | 5 | -------------------------------------------------------------------------------- /input_files/linemask_files/Sr/sr-lmask.txt: -------------------------------------------------------------------------------- 1 | ; 2 | 4077.71 4077.2 4078.2 3 | 4215.52 4215.19 4215.80 4 | 4607.33 4607.13 4607.48 5 | -------------------------------------------------------------------------------- /example_image_plot/fitted_star_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TSFitPy-developers/TSFitPy/HEAD/example_image_plot/fitted_star_example.png -------------------------------------------------------------------------------- /input_files/linemask_files/Al/al-lmask.txt: -------------------------------------------------------------------------------- 1 | ; 2 | 5557.0630 5556.76 5557.21 3 | 6696.0230 6695.7 6696.28 4 | 6698.6730 6698.3 6698.95 5 | -------------------------------------------------------------------------------- /input_files/fitlist: -------------------------------------------------------------------------------- 1 | #name_of_spectrum_to_fit rv teff logg [Fe/H] Input_vmicroturb Input_vmacroturb 2 | UVES_Sun-1_cleaned_norm.txt 0.000000 5771 4.44 0.03 -------------------------------------------------------------------------------- /input_files/fitlist_example: -------------------------------------------------------------------------------- 1 | #name_of_spectrum_to_fit rv teff logg [Fe/H] Input_vmicroturb 2 | UVES_Sun-1_cleaned_norm.txt 0.000000 5771 4.44 0.03 3 | -------------------------------------------------------------------------------- /input_files/observed_spectra/readme.txt: -------------------------------------------------------------------------------- 1 | put all observations you would like to fit here (ascii files with first column wavelength and second column normalized flux) 2 | -------------------------------------------------------------------------------- /scripts/model_interpolators/readme.txt: -------------------------------------------------------------------------------- 1 | put the model interpolators (fortran scripts) from https://github.com/bertrandplez/Turbospectrum2020/interpolator into this folder -------------------------------------------------------------------------------- /input_files/linemask_files/Fe/fe-lmask_test.txt: -------------------------------------------------------------------------------- 1 | ; line mask 2 | ; Fe I lines, test lines as an example 3 | 5415.199 5414.95 5415.46 4 | 5441.339 5441.120 5441.58 5 | -------------------------------------------------------------------------------- /input_files/synthetic_spectra_parameters: -------------------------------------------------------------------------------- 1 | teff logg [Fe/H] vmic vmac A(Y) [Ba/Fe] O_H 2 | 5777 4.44 0.03 1 1 2.27 0.3 0.5 3 | 6000 4.5 0.05 1.1 3 2.37 0.5 0.3 -------------------------------------------------------------------------------- /turbospectrum/readme.txt: -------------------------------------------------------------------------------- 1 | This is the directory to place your turbospectrum version. Be sure to build TS from this directory. 2 | 3 | You can find it at https://github.com/bertrandplez/Turbospectrum2020 -------------------------------------------------------------------------------- /input_files/linemask_files/Na/na-lmask.txt: -------------------------------------------------------------------------------- 1 | ; 2 | 5889.9510 5886.39 5893.90 11.01 3 | 5895.9240 5894.38 5897.91 11.01 4 | 6154.2260 6153.88 6154.70 11.01 5 | 6160.7470 6160.46 6161.02 11.01 6 | -------------------------------------------------------------------------------- /input_files/linemask_files/Ba/ba-lmask.txt: -------------------------------------------------------------------------------- 1 | ; Barium Line list 2 | 4934.0760 4933.945 4934.500 54.02 ; blend with Fe 1 3 | 5853.6680 5853.500 5853.900 54.02 4 | 6141.7130 6141.420 6142.110 54.02 5 | 6496.8970 6496.677 6497.200 54.02 -------------------------------------------------------------------------------- /input_files/linemask_files/Si/si-lmask.txt: -------------------------------------------------------------------------------- 1 | ; 2 | 5690.4250 5690.13 5690.7 14.01 3 | 5701.1040 5700.8 5701.29 14.01 4 | ;5772.1460 5771.8 5772.3 14.01 5 | ;5793.0730 5792.72 5793.4 14.01 6 | 5948.5410 5948.48 5948.915 14.01 7 | -------------------------------------------------------------------------------- /unittests/linelist_testing/molecular_test_data2: -------------------------------------------------------------------------------- 1 | '0822.000050 ' 1 1 2 | 'linelist_reduced50_all_deltacorr.dat ' 3 | 4208.709 0.623 -3.766 0.00 91.0 0.20E+08 'X' 'X' 0.0 1.0 '10 4 QP21 46 A ' -------------------------------------------------------------------------------- /unittests/linelist_testing/molecular_test_data3: -------------------------------------------------------------------------------- 1 | '0822.000050 ' 1 1 2 | 'linelist_reduced50_all_deltacorr.dat ' 3 | 3208.709 0.623 -3.766 0.00 91.0 0.20E+08 'X' 'X' 0.0 1.0 '10 4 QP21 46 A ' -------------------------------------------------------------------------------- /input_files/linemask_files/Mg/mg-lmask.txt: -------------------------------------------------------------------------------- 1 | ; Mg I 2 | ; 3 | 5528.405 5528.1 5528.7 12.01 4 | 5711.088 5710.8 5711.4 12.01 5 | ;6318.717 6318.5 6319.0 12.01 6 | ;6319.237 6319.0 6319.5 12.01 7 | ;6319.495 6319.3 6319.5 12.01 8 | -------------------------------------------------------------------------------- /input_files/nlte_data/readme.txt: -------------------------------------------------------------------------------- 1 | put all nlte files here (such as auxiliary text files and binary files of departure coefficients) 2 | 3 | TS will read these to create NLTE spectra 4 | 5 | My suggestion is to create a folder for each element. There is also a folder to put model atoms. 6 | 7 | -------------------------------------------------------------------------------- /input_files/linemask_files/Eu/eu-lmask.txt: -------------------------------------------------------------------------------- 1 | ; Europium 2 2 | 5818.7378 5818.654 5818.874 63.02 3 | 5818.7549 5818.654 5818.874 63.02 4 | 6049.5049 6049.405 6049.655 63.02 5 | 6049.5220 6049.405 6049.655 63.02 6 | 6173.0210 6172.952 6173.133 63.02 7 | 6173.0391 6172.952 6173.133 63.02 8 | 6645.0640 6644.910 6645.285 63.02 9 | -------------------------------------------------------------------------------- /input_files/linemask_files/Y/y-lmask.txt: -------------------------------------------------------------------------------- 1 | ; Ytrium 2 | 4982.1290 4982.030 4982.245 39.02 3 | 5087.4160 5087.277 5087.682 39.02 4 | 5200.4060 5200.295 5200.567 39.02 5 | 5289.8150 5289.700 5289.950 39.02 ; blend with C2 6 | 5402.7740 5402.661 5402.918 39.02 ; blend with C2 7 | 5544.6110 5544.558 5544.688 39.02 ; C2 blends in the wings 8 | 5728.8867 5728.752 5729.011 39.02 9 | 6795.4140 6795.245 6795.546 39.02 10 | -------------------------------------------------------------------------------- /input_files/linemask_files/Ca/ca-lmask.txt: -------------------------------------------------------------------------------- 1 | ; 2 | 5260.387 5260.163 5260.583 3 | 5261.704 5261.53 5261.9 4 | 5512.980 5512.7 5513.2 5 | 5581.965 5581.7 5582.2 6 | 5588.749 5588.45 5589.06 7 | 5590.114 5589.8 5590.4 8 | 5867.562 5867.3 5867.8 9 | 6102.723 6102.4 6102.95 10 | 6122.217 6121.85 6122.5 11 | 6156.023 6155.78 6156.24 12 | 6162.173 6161.67 6162.5 13 | 6166.439 6166.1 6166.7 14 | 6169.042 6168.67 6169.3 15 | 6169.563 6169.3 6169.8 16 | 6439.075 6438.8 6439.49 17 | 6455.598 6455.25 6455.88 18 | 6471.662 6471.40 6471.95 19 | 6493.781 6493.4 6494.0 20 | 6499.650 6499.30 6499.99 21 | -------------------------------------------------------------------------------- /input_files/linemask_files/Co/co-seg.txt: -------------------------------------------------------------------------------- 1 | wave_base wave_top 2 | 481.24933 481.72187 3 | 484.97918 488.03864 4 | 514.39148 519.81841 5 | 521.17981 521.72905 6 | 526.03835 528.86123 7 | 530.00466 531.00585 8 | 532.20432 534.54232 9 | 535.12304 535.28394 10 | 536.56031 537.59319 11 | 537.86155 538.82997 12 | 545.72375 549.02222 13 | 552.26080 553.16237 14 | 555.79057 559.74203 15 | 564.31696 565.15617 16 | 591.26673 591.75654 17 | 600.10881 601.07199 18 | 609.18740 609.52501 19 | 610.92835 611.78954 20 | 617.32575 620.23472 21 | 642.85104 643.61150 22 | 644.59131 646.87900 23 | 648.90366 649.25193 24 | 662.90219 663.31881 25 | 676.70343 677.50343 26 | 681.09437 681.89437 27 | 535.82807 536.11487 28 | -------------------------------------------------------------------------------- /unittests/linelist_testing/expected_result/molecular_test_data_expected: -------------------------------------------------------------------------------- 1 | '0822.000050 ' 1 7 2 | 'linelist_reduced50_all_deltacorr.dat ' 3 | 4200.000 0.213 -8.497 0.00 109.0 0.19E+08 'X' 'X' 0.0 1.0 ' 9 0 PR13 53 H ' 4 | 4200.005 0.409 -8.652 0.00 153.0 0.73E+05 'X' 'X' 0.0 1.0 '14 0 Q3 76 E ' 5 | 4200.548 0.314 -6.114 0.00 109.0 0.22E+08 'X' 'X' 0.0 1.0 '10 1 RQ21 54 H ' 6 | 4200.548 1.287 -7.047 0.00 259.0 0.21E+08 'X' 'X' 0.0 1.0 '12 2 TR31 128 H ' 7 | 4200.551 0.623 -3.369 0.00 127.0 0.19E+08 'X' 'X' 0.0 1.0 ' 9 3 Q1 63 A ' 8 | 4200.552 0.167 -8.112 0.00 93.0 0.19E+08 'X' 'X' 0.0 1.0 ' 9 0 OQ13 46 H ' 9 | 4200.552 1.485 -5.463 0.00 253.0 0.11E+08 'X' 'X' 0.0 1.0 '15 4 RQ21 126 H ' -------------------------------------------------------------------------------- /input_files/linemask_files/Cr/cr-seg.txt: -------------------------------------------------------------------------------- 1 | wave_base wave_top 480.01880 480.25674 484.50100 485.13300 492.98941 494.76924 495.06404 495.57653 496.34219 496.90379 509.24694 509.89769 519.68800 521.59506 521.86446 522.29454 523.57301 524.00679 527.06194 527.51500 527.62776 528.12479 528.56075 528.80425 529.32400 530.18443 532.15456 533.56473 533.73100 535.16200 536.66850 536.97876 540.78224 541.32600 541.85198 542.40200 547.89306 548.36300 549.96716 550.37410 562.70392 563.12514 563.92100 565.19585 570.04881 570.52166 571.80533 572.20041 577.80300 578.37248 583.59682 584.77900 586.02700 586.65900 597.97100 598.60900 612.81746 613.16849 632.66200 633.26942 649.79600 650.44400 653.46500 654.04085 662.65200 663.33100 665.78700 666.42300 666.79504 667.19533 488.20136 489.59844 530.25466 530.76621 530.90468 531.46665 531.75387 532.07148 524.04897 524.48818 524.51052 525.04651 578.43046 579.08033 -------------------------------------------------------------------------------- /calculate_nlte_correction_line.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | from sys import argv 3 | from scripts.calculate_nlte_correction_line import run_nlte_corrections 4 | import datetime 5 | import numpy as np 6 | 7 | 8 | if __name__ == '__main__': 9 | abundance: float = 0.0 # abundance of element in LTE [X/Fe]; scaled with metallicity 10 | 11 | if len(argv) > 1: # when calling the program, can now add extra argument with location of config file, easier to call 12 | config_location = argv[1] 13 | else: 14 | config_location = "./input_files/tsfitpy_input_configuration.cfg" # location of config file 15 | 16 | output_folder_title_date = datetime.datetime.now().strftime( 17 | "%b-%d-%Y-%H-%M-%S") # used to not conflict with other instances of fits 18 | output_folder_title_date = f"{output_folder_title_date}_{np.random.random(1)[0]}" # in case if someone calls the function several times per second 19 | print(f"Start of the fitting: {output_folder_title_date}") 20 | 21 | 22 | run_nlte_corrections(config_location, output_folder_title_date) -------------------------------------------------------------------------------- /input_files/linemask_files/H/H-lmask.txt: -------------------------------------------------------------------------------- 1 | ; 2 | 4861.900 4850.0 4850.88 1.01 3 | 4861.900 4858.5 4858.8 1.01 4 | 4861.900 4860.45 4860.72 1.01 5 | 4861.900 4862.8 4863.05 1.01 6 | 4861.900 4867.0 4867.2 1.01 7 | 4861.900 4872.85 4872.9 1.01 8 | 4861.900 4876.85 4877.35 1.01 9 | 4861.900 4879.3 4879.75 1.01 10 | 5172.684 5170.23 5170.34 12.01 11 | 5172.684 5171.15 5171.37 12.01 12 | 5172.684 5171.84 5172.16 12.01 13 | 5172.684 5172.95 5173.144 12.01 14 | 5172.684 5173.95 5174.2 12.01 15 | 5183.604 5182.785 5183.215 12.01 16 | 5183.604 5183.94 5184.04 12.01 17 | 5183.604 5184.32 5184.45 12.01 18 | 5183.604 5185.11 5185.614 12.01 19 | 6546.238 6545.8 6546.6 26.01 20 | 6554.223 6553.84 6554.67 22.01 21 | 6556.062 6555.77 6556.22 22.01 22 | 6562.79 6561.1 6561.35 1.01 23 | 6562.79 6561.7 6561.9 1.01 24 | 6562.79 6564.35 6564.7 1.01 25 | 6562.79 6566.37 6566.8 1.01 26 | 6562.79 6567.70 6568.2 1.01 27 | 6581.209 6580.985 6581.48 26.01 28 | -------------------------------------------------------------------------------- /unittests/linelist_testing/molecular_test_data: -------------------------------------------------------------------------------- 1 | '0822.000050 ' 1 13 2 | 'linelist_reduced50_all_deltacorr.dat ' 3 | 4199.997 0.743 -4.964 0.00 149.0 0.15E+08 'X' 'X' 0.0 1.0 '13 3 QP32 75 H ' 4 | 4199.997 2.460 -4.655 0.00 371.0 0.94E+07 'X' 'X' 0.0 1.0 '15 3 SR21 184 H ' 5 | 4199.999 0.824 -4.692 0.00 167.0 0.15E+08 'X' 'X' 0.0 1.0 '13 3 RQ32 83 H ' 6 | 4199.999 1.075 -3.705 0.00 145.0 0.18E+08 'X' 'X' 0.0 1.0 '13 6 QP32 73 A ' 7 | 4200.000 0.213 -8.497 0.00 109.0 0.19E+08 'X' 'X' 0.0 1.0 ' 9 0 PR13 53 H ' 8 | 4200.005 0.409 -8.652 0.00 153.0 0.73E+05 'X' 'X' 0.0 1.0 '14 0 Q3 76 E ' 9 | 4200.548 0.314 -6.114 0.00 109.0 0.22E+08 'X' 'X' 0.0 1.0 '10 1 RQ21 54 H ' 10 | 4200.548 1.287 -7.047 0.00 259.0 0.21E+08 'X' 'X' 0.0 1.0 '12 2 TR31 128 H ' 11 | 4200.551 0.623 -3.369 0.00 127.0 0.19E+08 'X' 'X' 0.0 1.0 ' 9 3 Q1 63 A ' 12 | 4200.552 0.167 -8.112 0.00 93.0 0.19E+08 'X' 'X' 0.0 1.0 ' 9 0 OQ13 46 H ' 13 | 4200.552 1.485 -5.463 0.00 253.0 0.11E+08 'X' 'X' 0.0 1.0 '15 4 RQ21 126 H ' 14 | 4206.709 0.623 -3.766 0.00 91.0 0.20E+08 'X' 'X' 0.0 1.0 '10 4 QP21 46 A ' 15 | 4208.709 0.623 -3.766 0.00 91.0 0.20E+08 'X' 'X' 0.0 1.0 '10 4 QP21 46 A ' -------------------------------------------------------------------------------- /input_files/linemask_files/Co/co-lmask.txt: -------------------------------------------------------------------------------- 1 | wave_peak wave_base wave_top note 2 | 481.34764 481.33058 481.36377 Co 1 3 | 481.39717 481.38431 481.41157 Co 1 4 | 486.78695 486.76925 486.80506 Co 1 5 | 517.60760 517.58910 517.63589 Co 1 6 | 521.26878 521.25158 521.28772 Co 1 7 | 528.06258 528.05053 528.07979 Co 1 8 | 528.75543 528.73850 528.76716 Co 1 9 | 530.10410 530.09112 530.12481 Co 1 10 | 532.52737 532.51283 532.54050 Co 1 11 | 533.14532 533.12347 533.16685 Co 1 12 | 534.27006 534.25519 534.28500 Co 1 13 | 535.20397 535.18529 535.22519 Co 1 14 | 535.91995 535.90398 535.93770 Co 1 15 | 536.95889 536.94128 536.97930 Co 1 16 | 538.17703 538.15507 538.20366 Co 1 17 | 548.33535 548.32000 548.35927 Co 1 18 | 548.39539 548.37306 548.41639 Co 1 19 | 552.32973 552.30773 552.35145 Co 1 20 | 553.07752 553.05869 553.10374 Co 1 21 | 559.07380 559.05099 559.10107 Co 1 22 | 564.72338 564.69597 564.75196 Co 1 23 | 591.55496 591.53333 591.57720 Co 1 24 | 600.50264 600.48250 600.52403 Co 1 25 | 609.31407 609.29565 609.33803 Co 1 26 | 611.69902 611.67701 611.72018 Co 1 27 | 618.89963 618.87800 618.92033 Co 1 28 | 642.98966 642.97015 643.01338 Co 1 29 | 645.49943 645.47421 645.52724 Co 1 30 | 649.03281 649.00119 649.05652 Co 1 31 | 663.24394 663.22000 663.26775 Co 1 32 | 677.10343 677.00343 677.20343 Co 1 33 | 681.49437 681.39437 681.59437 Co 1 34 | -------------------------------------------------------------------------------- /scripts/compile_fortran_codes.py: -------------------------------------------------------------------------------- 1 | import os 2 | from os import path as os_path 3 | 4 | compiler = input("Type of compiler (GNU or IFORT or IFX): ") 5 | if compiler.lower() == "ifort": 6 | os.system("ifort -o faltbon faltbon.f90") 7 | os.chdir("./model_interpolators/") 8 | os.system("ifort -o interpol_modeles interpol_modeles.f") 9 | os.system("ifort -o interpol_modeles_nlte interpol_modeles_nlte.f") 10 | os.system("ifort -o interpol_multi interpol_multi.f") 11 | os.system("ifort -o interpol_multi_nlte interpol_multi_nlte.f") 12 | elif compiler.lower() == "gnu": 13 | os.system("gfortran -o faltbon faltbon.f90") 14 | os.chdir("./model_interpolators/") #need a separate file for GNU and INTEL codes 15 | os.system("gfortran -o interpol_modeles interpol_modeles.f") 16 | os.system("gfortran -o interpol_modeles_nlte interpol_modeles_nlte_gfort.f") 17 | os.system("gfortran -o interpol_multi interpol_multi.f") 18 | os.system("gfortran -o interpol_multi_nlte interpol_multi_nlte_gfort.f") 19 | elif compiler.lower() == "ifx": 20 | os.system("ifx -o faltbon faltbon.f90") 21 | os.chdir("./model_interpolators/") 22 | os.system("ifx -o interpol_modeles interpol_modeles.f") 23 | os.system("ifx -o interpol_modeles_nlte interpol_modeles_nlte.f") 24 | os.system("ifx -o interpol_multi interpol_multi.f") 25 | os.system("ifx -o interpol_multi_nlte interpol_multi_nlte.f") 26 | else: 27 | print('Write only GNU, IFORT or IFX, you wrote: ') 28 | print(compiler) -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from scripts.TSFitPy import run_tsfitpy 4 | import scipy 5 | from sys import argv 6 | import datetime 7 | import numpy as np 8 | 9 | if __name__ == '__main__': 10 | major_version_scipy, minor_version_scipy, patch_version_scipy = scipy.__version__.split(".") 11 | if int(major_version_scipy) < 1 or (int(major_version_scipy) == 1 and int(minor_version_scipy) < 7) or ( 12 | int(major_version_scipy) == 1 and int(minor_version_scipy) == 7 and int(patch_version_scipy) == 0): 13 | raise ImportError(f"Scipy has to be at least version 1.7.1, otherwise bounds are not considered in minimisation. " 14 | f"That will lead to bad fits. Please update to scipy 1.7.1 OR higher. Your version: " 15 | f"{scipy.__version__}") 16 | 17 | if len(argv) > 1: # when calling the program, can now add extra argument with location of config file, easier to call 18 | config_location = argv[1] 19 | else: 20 | config_location = "./input_files/tsfitpy_input_configuration.cfg" # location of config file 21 | if len(argv) > 2: # when calling the program, can now add extra argument with location of observed spectra, easier to call 22 | obs_location = argv[2] 23 | else: 24 | obs_location = None # otherwise defaults to the input one 25 | print(config_location) 26 | output_folder_title_date = datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S") # used to not conflict with other instances of fits 27 | output_folder_title_date = f"{output_folder_title_date}_{np.random.random(1)[0]}" # in case if someone calls the function several times per second 28 | print(f"Start of the fitting: {output_folder_title_date}") 29 | try: 30 | run_tsfitpy(output_folder_title_date, config_location, obs_location) 31 | print("Fitting completed") 32 | except KeyboardInterrupt: 33 | print(f"KeyboardInterrupt detected. Terminating job.") #TODO: cleanup temp folders here? 34 | finally: 35 | print(f"End of the fitting: {datetime.datetime.now().strftime('%b-%d-%Y-%H-%M-%S')}") 36 | -------------------------------------------------------------------------------- /utilities/print_interesting_loggf.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | def read_element_data(filename): 4 | with open(filename, 'r') as file: 5 | lines = file.readlines() 6 | 7 | i = 0 8 | elements_data = [] 9 | while i < len(lines): 10 | line_parts = lines[i].split() 11 | if line_parts[0] == "'": 12 | atomic_num = (line_parts[1]) 13 | else: 14 | atomic_num = (line_parts[0]) 15 | ionization = int(line_parts[-2]) 16 | num_lines = int(line_parts[-1]) 17 | 18 | element_name = lines[i + 1].strip() 19 | 20 | for _ in range(num_lines): 21 | i += 1 22 | data_line = lines[i + 1] 23 | wavelength, loggf = float(data_line.split()[0]), float(data_line.split()[2]) 24 | elements_data.append((element_name, atomic_num, ionization, wavelength, loggf)) 25 | 26 | i += 2 27 | 28 | return elements_data 29 | 30 | def find_elements(elements_data, left_wavelength, right_wavelength, loggf_threshold): 31 | filtered_elements = [] 32 | for element_data in elements_data: 33 | element_name, atomic_num, ionization, wavelength, loggf = element_data 34 | if left_wavelength <= wavelength <= right_wavelength and loggf > loggf_threshold: 35 | filtered_elements.append(element_data) 36 | 37 | sorted_elements = sorted(filtered_elements, key=lambda x: x[3]) # Sort by wavelength 38 | 39 | for element_data in sorted_elements: 40 | element_name, atomic_num, ionization, wavelength, loggf = element_data 41 | print(element_name.replace("'", "").replace("NLTE", "").replace("LTE", ""), atomic_num, wavelength, loggf) 42 | 43 | 44 | if __name__ == '__main__': 45 | linelist_path = "../input_files/linelists/linelist_for_fitting/" 46 | linelist_filename = "nlte_ges_linelist_jmg17feb2022_I_II" 47 | print("element atomic_number wavelength loggf") 48 | 49 | left_wavelength = 6645.0 - 0.1 # change this to change the range of wavelengths to print 50 | right_wavelength = 6645.104 51 | loggf_threshold = -4 # change this to change the threshold for loggf 52 | 53 | elements_data = read_element_data(os.path.join(linelist_path, linelist_filename)) 54 | find_elements(elements_data, left_wavelength, right_wavelength, loggf_threshold) -------------------------------------------------------------------------------- /input_files/linemask_files/Cr/cr-lmask.txt: -------------------------------------------------------------------------------- 1 | wave_peak wave_base wave_top note 480.10247 480.08500 480.12166 Cr 1 484.82350 484.80100 484.83300 Cr 2 488.46070 488.43600 488.47100 Cr 2 488.57701 488.56000 488.58800 Cr 1 488.59530 488.58800 488.61000 Cr 1 493.63360 493.60800 493.65800 Cr 1 495.37170 495.34900 495.38800 Cr 1 495.48060 495.46700 495.50200 Cr 1 496.49275 496.48100 496.50800 Cr 1 509.73110 509.72100 509.73754 Cr 2 520.01730 519.99795 520.02800 Cr 1 520.45110 520.42897 520.48644 Cr 1 520.60370 520.58300 520.64200 Cr 1 520.84250 520.82021 520.87900 Cr 1 521.41314 521.39700 521.43500 Cr 1 522.08920 522.06700 522.09540 Cr 1 523.73285 523.71100 523.74728 Cr 2 523.89610 523.87900 523.91900 Cr 1 524.14590 524.12600 524.17000 Cr 1 524.33540 524.32000 524.35700 Cr 1 524.67680 524.66928 524.68400 Cr 2 524.75650 524.74000 524.77600 Cr 1 524.94370 524.92900 524.94894 Cr 2 527.20000 527.18000 527.21500 Cr 1 527.98758 527.97600 527.99700 Cr 2 528.71780 528.69100 528.73800 Cr 1 529.66910 529.64907 529.70100 Cr 1 529.80165 529.77300 529.81300 Cr 1 529.82720 529.81300 529.84334 Cr 1 530.07450 530.05200 530.09100 Cr 1 530.41800 530.40512 530.44000 Cr 1 530.58526 530.56500 530.60800 Cr 2 531.06864 531.05700 531.08357 Cr 2 531.28560 531.27200 531.30300 Cr 1 531.35628 531.34200 531.36895 Cr 2 531.87710 531.86385 531.89300 Cr 1 532.91381 532.89300 532.94700 Cr 1 534.04470 534.03100 534.05600 Cr 1 534.47570 534.46300 534.49600 Cr 1 534.57960 534.55677 534.60513 Cr 1 534.83150 534.81102 534.86200 Cr 1 536.93560 536.92216 536.94190 Cr 2 540.97840 540.96446 541.02600 Cr 1 542.09220 542.07000 542.10200 Cr 2 548.05065 548.02700 548.06300 Cr 1 550.20669 550.19100 550.22916 Cr 2 562.86430 562.84900 562.88900 Cr 1 564.23582 564.22100 564.24800 Cr 1 564.82615 564.80600 564.83800 Cr 1 570.23060 570.21100 570.24900 Cr 1 571.98160 571.95300 572.00200 Cr 1 578.11670 578.10300 578.13830 Cr 1 578.30635 578.27700 578.33300 Cr 1 578.49690 578.48200 578.51300 Cr 1 578.79180 578.76700 578.81900 Cr 1 578.83820 578.81900 578.84953 Cr 1 583.86690 583.85400 583.88600 Cr 1 584.45950 584.44100 584.47900 Cr 1 586.34488 586.32700 586.35900 Cr 1 598.28738 598.27100 598.30900 Cr 1 612.92260 612.90757 612.93500 Cr 2 633.00910 632.96200 633.04500 Cr 1 650.11850 650.09600 650.14400 Cr 1 653.79212 653.76500 653.82000 Cr 1 663.00109 662.95200 663.03100 Cr 1 666.10752 666.08700 666.12300 Cr 1 666.92814 666.90900 666.95800 Cr 1 -------------------------------------------------------------------------------- /input_files/linemask_files/Ti/ti-lmask.txt: -------------------------------------------------------------------------------- 1 | ; 2 | ; 4758.118 4757.88 4758.32 22.01 3 | ; 4759.270 4759.07 4759.49 22.01 4 | ; 4798.521 4798.36 4798.6 22.02 5 | ; 4865.6114 4865.32 4865.92 22.02 6 | ; 4874.0095 4873.84 4874.18 22.02 7 | ; 4911.193 4910.96 4911.35 22.02 8 | ; 4913.614 4913.38 4913.80 22.01 9 | ; 4915.229 4915.04 4915.45 22.01 10 | ; 4926.148 4925.9 4926.5 22.01 11 | ; 4981.355 4981.0 4981.55 22.02 12 | ; 4981.731 4981.55 4981.97 22.01 13 | ; 4997.096 4996.91 4997.35 22.01 14 | ; 4999.503 4999.26 4999.82 22.01 15 | ; 5005.157 5004.9 5004.4 22.02 16 | 5009.645 5009.3 5009.86 22.01 17 | 5016.161 5015.9 5016.36 22.01 18 | 5024.844 5024.55 5025.01 22.01 19 | 5113.440 5113.29 5113.65 22.01 20 | 5145.460 5145.26 5145.65 22.01 21 | 5147.478 5147.25 5147.64 22.01 22 | 5152.184 5152.03 5152.40 22.01 23 | 5210.385 5210.07 5210.6 22.02 24 | 5211.5304 5211.36 5211.70 22.02 25 | 5219.702 5219.4 5219.82 22.01 26 | 5295.775 5295.52 5295.96 22.01 27 | 5336.771 5336.55 5337.05 22.02 28 | 5338.305 5338.13 5338.41 22.01 29 | 5366.639 5366.39 5366.75 22.01 30 | 5381.015 5380.83 5381.27 22.02 31 | 5384.630 5384.38 5384.77 22.01 32 | 5418.751 5418.53 5418.95 22.02 33 | 5426.250 5426.0 5426.50 22.01 34 | 5460.499 5460.2 5460.69 22.01 35 | 5490.148 5489.9 5490.4 22.01 36 | ; 5490.690 5490.3 5490.8 22.02 37 | 5490.846 5490.8 5491.05 22.01 38 | 5662.150 5661.9 5662.32 22.01 39 | 5689.460 5689.25 5689.7 22.01 40 | 5702.656 5702.47 5702.9 22.01 41 | 5716.445 5716.2 5716.7 22.01 42 | 5866.451 5866.2 5866.7 22.01 43 | 5903.315 5903.0 5903.62 22.01 44 | 5918.535 5918.2 5918.83 22.01 45 | 5922.109 5921.9 5921.4 22.01 46 | 5937.809 5937.5 5938.1 22.01 47 | 5953.160 5952.9 5953.46 22.01 48 | 5965.828 5965.6 5966.1 22.01 49 | 5978.541 5978.24 5978.76 22.01 50 | 6064.626 6064.3 6064.82 22.01 51 | 6091.171 6090.83 6091.48 22.01 52 | 6092.792 6092.5 6092.96 22.01 53 | 6126.216 6125.9 6126.5 22.01 54 | 6258.102 6257.8 6258.4 22.01 55 | 6261.098 6260.77 6261.47 22.01 56 | 6312.236 6312.0 6312.5 22.01 57 | 6336.099 6335.8 6336.38 22.01 58 | 6395.472 6395.27 6395.65 22.01 59 | 6554.223 6554.0 6554.5 22.01 60 | 6556.062 6555.8 6556.3 22.01 61 | 6599.105 6598.8 6599.43 22.01 62 | -------------------------------------------------------------------------------- /unittests/linelist_testing/expected_result/atomic_test_data_expected: -------------------------------------------------------------------------------- 1 | ' 3.000 ' 1 1 2 | 'Li I LTE' 3 | 4202.894 1.848 -0.353 2006.342 6.0 6.03E+07 'p' 'd' 0.0 1.0 'Li I LS:1s2.2p 2P* LS:1s2.4d 2D' 4 | ' 13.000 ' 1 2 5 | 'Al I NLTE' 6 | 4202.414 3.143 -3.125 2.500 4.0 1.00E+05 's' 'p' 0.0 1.0 'Al I LS:3s2.4s 2S LS:3s2.10p 2P*' 3 39 '4s2S0.5' '10p2P' 'c' 'a' 7 | 4202.512 3.143 -3.426 2.500 2.0 1.00E+05 's' 'p' 0.0 1.0 'Al I LS:3s2.4s 2S LS:3s2.10p 2P*' 3 39 '4s2S0.5' '10p2P' 'c' 'a' 8 | ' 14.000 ' 1 9 9 | 'Si I NLTE' 10 | 4200.038 4.930 -4.698 -6.860 5.0 3.39E+08 'd' 'f' 0.0 1.0 'Si I LS:3s2.3p.4s 3P* JK:3s2.3p.(2P*<1/2>).7f 2[5/2]' 8 143 '4s3P1*' '7i1H*' 'c' 'a' 11 | 4200.686 4.954 -4.263 -6.860 7.0 3.39E+08 'd' 'f' 0.0 1.0 'Si I LS:3s2.3p.4s 3P* JK:3s2.3p.(2P*<1/2>).7f 2[5/2]' 9 143 '4s3P2*' '7i1H*' 'c' 'a' 12 | 4200.906 4.954 -4.317 -6.860 5.0 3.39E+08 'd' 'f' 0.0 1.0 'Si I LS:3s2.3p.4s 3P* JK:3s2.3p.(2P*<1/2>).7f 2[5/2]' 9 143 '4s3P2*' '7i1H*' 'c' 'a' 13 | 4201.164 4.954 -5.223 -6.860 7.0 3.39E+08 'd' 'f' 0.0 1.0 'Si I LS:3s2.3p.4s 3P* JK:3s2.3p.(2P*<1/2>).7f 2[7/2]' 9 143 '4s3P2*' '7i1H*' 'c' 'a' 14 | 4202.428 4.930 -3.241 -6.870 5.0 3.39E+08 's' 'p' 0.0 1.0 'Si I LS:3s2.3p.4s 3P* JJ:3s2.3p.(2P*<1/2>).8p.<3/2> (1/2,3/2)' 8 0 '4s3P1*' 'none' 'c' 'x' 15 | 4203.124 4.920 -4.245 -6.980 3.0 3.31E+08 'd' 'f' 0.0 1.0 'Si I LS:3s2.3p.4s 3P* JK:3s2.3p.(2P*<3/2>).6f 2[3/2]' 7 130 '4s3P0*' '6g3D*' 'c' 'a' 16 | 4204.087 4.954 -2.744 -6.870 5.0 3.39E+08 's' 'p' 0.0 1.0 'Si I LS:3s2.3p.4s 3P* JJ:3s2.3p.(2P*<1/2>).8p.<3/2> (1/2,3/2)' 9 0 '4s3P2*' 'none' 'c' 'x' 17 | 4204.302 4.930 -3.844 -6.980 5.0 3.39E+08 'd' 'f' 0.0 1.0 'Si I LS:3s2.3p.4s 3P* JK:3s2.3p.(2P*<3/2>).6f 2[3/2]' 8 130 '4s3P1*' '6g3D*' 'c' 'a' 18 | 4205.000 4.930 -4.429 -6.980 3.0 3.39E+08 'd' 'f' 0.0 1.0 'Si I LS:3s2.3p.4s 3P* JK:3s2.3p.(2P*<3/2>).6f 2[3/2]' 8 130 '4s3P1*' '6g3D*' 'c' 'a' 19 | ' 14.000 ' 2 2 20 | 'Si II NLTE' 21 | 4200.969 12.839 -0.904 -6.960 10.0 3.55E+08 'd' 'f' 0.0 1.0 'Si II LS:3s2.(1S).4f 2F LS:3s2.(1S).9g 2G*' 303 334 '4f2F*' '9g2G' 'c' 'a' 22 | 4204.994 12.839 -1.017 -6.960 8.0 3.55E+08 'd' 'f' 0.0 1.0 'Si II LS:3s2.(1S).4f 2F LS:3s2.(1S).9g 2G*' 303 334 '4f2F*' '9g2G' 'c' 'a' 23 | ' 15.000 ' 1 3 24 | 'P I LTE' 25 | 4200.019 6.936 -2.500 2.500 4.0 1.00E+05 's' 'p' 0.0 1.0 'P I LS:3s2.3p2.(3P).4s 4P LS:3s2.3p2.(3P).6p 4P*' 26 | 4202.997 6.985 -2.000 2.500 4.0 1.00E+05 's' 'p' 0.0 1.0 'P I LS:3s2.3p2.(3P).4s 4P LS:3s2.3p2.(3P).6p 4S*' 27 | 4204.988 6.985 -2.300 2.500 6.0 1.00E+05 's' 'p' 0.0 1.0 'P I LS:3s2.3p2.(3P).4s 4P LS:3s2.3p2.(3P).6p 4P*' -------------------------------------------------------------------------------- /input_files/linemask_files/Fe/fe-lmask.txt: -------------------------------------------------------------------------------- 1 | ; line mask 2 | ; Fe I lines 3 | 4808.148 4807.97 4808.33 4 | 5141.739 5141.4 5142.0 5 | 5217.389 5217.0 5217.56 6 | 5242.491 5242.3 5242.7 7 | 5247.050 5246.885 5247.21 8 | 5324.179 5323.65 5324.6 9 | 5364.871 5364.6 5365.2 10 | 5365.399 5365.1 5365.7 11 | 5367.467 5367.35 5367.67 12 | 5379.574 5379.23 5379.89 13 | 5383.369 5383.08 5383.6 14 | 5386.334 5386.1 5386.6 15 | 5398.279 5398.1 5398.45 16 | 5415.199 5414.95 5415.46 17 | 5441.339 5441.120 5441.58 18 | 5445.042 5444.9 5445.2 19 | 5501.465 5501.115 5501.672 20 | 5506.779 5506.6 5507.05 21 | 5543.936 5543.622 5544.13 22 | 5560.212 5560.0 5560.36 23 | 5569.618 5569.33 5569.87 24 | 5576.089 5575.8 5576.3 25 | 5638.262 5637.913 5638.518 26 | 5651.469 5651.278 5651.665 27 | 5661.346 5661.152 5661.615 28 | 5679.023 5678.770 5679.411 29 | 5696.090 5695.95 5696.2 30 | 5705.465 5705.3 5705.70 31 | 5731.762 5731.5 5732.012 32 | 5732.296 5732.110 5732.49 33 | 5741.848 5741.6 5742.0 34 | 5855.077 5854.830 5855.3 35 | 5858.778 5858.6 5859.0 36 | 5883.817 5883.6 5884.05 37 | 5905.672 5905.480 5905.86 38 | 5927.789 5927.615 5927.968 39 | 5930.180 5929.98 5930.485 40 | 5956.694 5956.442 5956.935 41 | 6024.058 6023.8 6024.35 42 | 6027.051 6026.8 6027.25 43 | 6056.005 6055.66 6056.2 44 | 6093.644 6093.45 6093.8 45 | 6151.618 6151.34 6151.91 46 | 6165.360 6165.0 6165.7 47 | 6173.336 6173.1 6173.7 48 | 6187.990 6187.71 6188.302 49 | 6219.281 6218.985 6219.502 50 | 6246.319 6246.1 6246.857 51 | 6252.555 6252.15 6253.0 52 | 6265.134 6264.9 6265.4 53 | 6270.225 6270.037 6270.565 54 | 6297.793 6297.557 6298.038 55 | 6301.501 6301.25 6301.8 56 | 6322.685 6322.45 6323.0 57 | 6330.850 6330.6 6331.1 58 | 6335.331 6334.960 6335.655 59 | 6336.824 6336.500 6337.15 60 | 6393.601 6393.3 6394.03 61 | 6411.649 6411.264 6412.0 62 | 6430.846 6430.538 6431.35 63 | 6481.870 6481.61 6482.086 64 | 6498.939 6498.630 6499.157 65 | 6518.367 6518.080 6518.58 66 | 6593.870 6593.6 6594.2 67 | 6699.142 6698.924 6699.463 68 | 6713.745 6713.440 6714.192 69 | 6739.522 6739.307 6739.854 70 | 6750.153 6749.7 6750.4 71 | ; Fe II lines 72 | 4923.927 4923.7 4924.14 73 | 4993.358 4993.15 4994.51 74 | 5234.625 5234.4 5234.85 75 | 5264.625 5264.3 5264.95 76 | 5316.615 5316.3 5317.34 77 | 5316.784 5316.3 5317.34 78 | 5325.553 5325.4 5325.8 79 | 5414.073 5413.88 5414.3 80 | 5425.257 5424.985 5425.44 81 | 5991.376 5991.15 5991.55 82 | 6084.111 6083.93 6084.33 83 | 6369.462 6369.2 6369.7 84 | 6432.680 6432.385 6433.02 85 | 6456.383 6456.09 6456.67 86 | -------------------------------------------------------------------------------- /utilities/read_nlte_grid.py: -------------------------------------------------------------------------------- 1 | # script to read the binary NLTE grid at a pointer (specified in the auxiliary file) 2 | 3 | import numpy as np 4 | import matplotlib.pyplot as plt 5 | import matplotlib 6 | 7 | #matplotlib.use('MacOSX') 8 | 9 | def read_binary_grid(grid_file, pointer=1): 10 | """ 11 | # author: @Katerina Magg 12 | 13 | Reads a record at specified position from the binary NLTE grid 14 | (grid of departure coefficients) 15 | 16 | Parameters 17 | ---------- 18 | grid_file : str 19 | path to the binary NLTE grid 20 | pointer : int 21 | bitwise start of the record as read from the auxiliarly file 22 | 23 | Returns 24 | ------- 25 | ndep : int 26 | number of depth points in the model atmosphere used to solve for NLTE 27 | nk : int 28 | number of energy levels in the model atom used to solved for NLTE 29 | depart : array 30 | NLTE departure coefficients of shape (ndep, nk) 31 | tau : array 32 | depth scale (e.g. TAU500nm) in the model atmosphere 33 | used to solve for NLTE of shape (ndep) 34 | """ 35 | with open(grid_file, 'rb') as f: 36 | # -1 since Python stars at 0 37 | pointer = pointer - 1 38 | 39 | f.seek(pointer) 40 | atmosStr = f.readline(500).decode('utf-8', 'ignore').strip() 41 | ndep = int.from_bytes(f.read(4), byteorder='little') 42 | nk = int.from_bytes(f.read(4), byteorder='little') 43 | tau = np.log10(np.fromfile(f, count = ndep, dtype='f8')) 44 | depart = np.fromfile(f, dtype='f8', count=ndep*nk).reshape(nk, ndep) 45 | 46 | return ndep, nk, depart, tau, atmosStr 47 | 48 | 49 | def plot_departure_coefficients(depart, tau, atmosStr, levels_to_plot): 50 | # plot departure coefficients 51 | 52 | # if levels_to_plot is int, convert to list 53 | if isinstance(levels_to_plot, int): 54 | levels_to_plot = [levels_to_plot] 55 | 56 | fig, ax = plt.subplots() 57 | for level in levels_to_plot: 58 | ax.plot(tau, depart[level - 1], label=f"level {level}") 59 | ax.set_xlabel(r"$\log_{10}(\tau)$") 60 | ax.set_ylabel(r"$b_{\rm NLTE}$") 61 | ax.set_title(f"Departure coefficients for {atmosStr}") 62 | ax.legend() 63 | plt.show() 64 | 65 | 66 | 67 | if __name__ == '__main__': 68 | pointer = 1001 69 | grid_file = 'binary_grid.bin' 70 | ndep, nk, depart, tau, atmosStr = read_binary_grid(grid_file, pointer=pointer) 71 | 72 | print(f"atmosStr={atmosStr}") # atmosStr is the model atmosphere used to solve for NLTE, can compare to the model atmosphere in the auxiliary file 73 | print(f"ndep={ndep} nk={nk}") # ndep are number of depth points, nk are number of energy levels 74 | print(f"tau={(tau)}") # converted to log10(tau) 75 | print(f"depart={depart}") # departure coefficients as a function of depth and energy level, 2D array. 76 | # depart[level] is the departure coefficients for a given energy level, at all depths 77 | 78 | # levels_to_plot can be a list of levels to plot, or a single level 79 | # levels are indexed from 1 80 | plot_departure_coefficients(depart, tau, atmosStr, levels_to_plot=[1, 2]) -------------------------------------------------------------------------------- /input_files/linemask_files/Ni/ni-lmask.txt: -------------------------------------------------------------------------------- 1 | wave_peak wave_base wave_top note 2 | 481.19829 481.16900 481.21300 Ni 1 3 | 481.45910 481.44800 481.47800 Ni 1 4 | 482.90231 482.88300 482.92000 Ni 1 5 | 487.34380 487.33300 487.36200 Ni 1 6 | 490.44118 490.41200 490.46800 Ni 1 7 | 491.20180 491.19000 491.22639 Ni 1 8 | 491.39730 491.38100 491.42000 Ni 1 9 | 491.83640 491.81700 491.85300 Ni 1 10 | 493.58305 493.55600 493.60397 Ni 1 11 | 494.60317 494.58400 494.61800 Ni 1 12 | 495.32000 495.29917 495.34364 Ni 1 13 | 497.61300 497.59600 497.62300 Ni 1 14 | 497.63255 497.62300 497.64989 Ni 1 15 | 497.66968 497.65490 497.68100 Ni 1 16 | 499.56503 499.55300 499.57900 Ni 1 17 | 500.37407 500.35700 500.39000 Ni 1 18 | 501.09381 501.06900 501.11300 Ni 1 19 | 503.27271 503.25200 503.29100 Ni 1 20 | 503.53570 503.50600 503.55900 Ni 1 21 | 508.11103 508.08400 508.14100 Ni 1 22 | 508.40957 508.39200 508.43149 Ni 1 23 | 509.44107 509.42300 509.46571 Ni 1 24 | 513.70738 513.69000 513.72300 Ni 1 25 | 515.51259 515.49400 515.53222 Ni 1 26 | 515.57639 515.55900 515.59400 Ni 1 27 | 515.79760 515.78600 515.81427 Ni 1 28 | 517.65603 517.63400 517.67200 Ni 1 29 | 534.77080 534.76000 534.78700 Ni 1 30 | 539.23309 539.21600 539.25300 Ni 1 31 | 542.45361 542.44200 542.46250 Ni 1 32 | 542.46450 542.46250 542.49400 Ni 1 33 | 543.58576 543.55600 543.60600 Ni 1 34 | 546.24931 546.22000 546.27100 Ni 1 35 | 546.81039 546.79400 546.82600 Ni 1 36 | 547.54294 547.52146 547.55800 Ni 1 37 | 547.69035 547.67200 547.72000 Ni 1 38 | 557.87183 557.85000 557.89400 Ni 1 39 | 558.78578 558.77200 558.80500 Ni 1 40 | 558.93580 558.91700 558.96100 Ni 1 41 | 559.37355 559.35100 559.39400 Ni 1 42 | 562.53168 562.51000 562.54800 Ni 1 43 | 562.83417 562.81300 562.84900 Ni 1 44 | 563.87467 563.85600 563.89300 Ni 1 45 | 564.18809 564.16600 564.20800 Ni 1 46 | 564.30780 564.29200 564.32800 Ni 1 47 | 568.21987 568.19000 568.23700 Ni 1 48 | 569.49833 569.48500 569.52000 Ni 1 49 | 570.95448 570.94700 570.97900 Ni 1 50 | 574.83507 574.81600 574.85800 Ni 1 51 | 576.08298 576.05957 576.10583 Ni 1 52 | 580.52166 580.49543 580.54463 Ni 1 53 | 584.69935 584.67700 584.72200 Ni 1 54 | 599.67301 599.64400 599.70300 Ni 1 55 | 600.73098 600.70100 600.75100 Ni 1 56 | 602.57539 602.55587 602.59464 Ni 1 57 | 608.62815 608.59900 608.65400 Ni 1 58 | 610.81158 610.78200 610.83900 Ni 1 59 | 611.10703 611.08600 611.13700 Ni 1 60 | 612.89731 612.87100 612.91500 Ni 1 61 | 613.01348 612.99100 613.04300 Ni 1 62 | 613.39626 613.37000 613.42600 Ni 1 63 | 617.53665 617.51700 617.56400 Ni 1 64 | 617.68070 617.65100 617.70700 Ni 1 65 | 617.72415 617.70700 617.74400 Ni 1 66 | 618.67109 618.64900 618.70000 Ni 1 67 | 619.11783 619.08800 619.13500 Ni 1 68 | 620.46000 620.43303 620.49000 Ni 1 69 | 622.39810 622.36900 622.42500 Ni 1 70 | 623.00889 622.97900 623.02900 Ni 1 71 | 632.21656 632.18700 632.23800 Ni 1 72 | 632.75985 632.73400 632.78800 Ni 1 73 | 637.03458 637.01200 637.06400 Ni 1 74 | 637.82470 637.80300 637.84800 Ni 1 75 | 638.46617 638.43700 638.49600 Ni 1 76 | 641.45810 641.44100 641.47500 Ni 1 77 | 642.48515 642.45800 642.51400 Ni 1 78 | 648.27983 648.25000 648.30400 Ni 1 79 | 653.28730 653.26100 653.30800 Ni 1 80 | 658.63098 658.60600 658.65400 Ni 1 81 | 659.85978 659.83800 659.88900 Ni 1 82 | 663.51224 663.48300 663.53900 Ni 1 83 | 664.36303 664.33400 664.39300 Ni 1 84 | 676.77720 676.67720 676.87720 Ni 1 85 | 677.23149 677.13149 677.33149 Ni 1 86 | 684.20367 684.10367 684.30367 Ni 1 87 | 877.06777 876.96777 877.16777 Ni 1 88 | -------------------------------------------------------------------------------- /scripts/dask_client.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | from dask.distributed import Client 3 | import time 4 | import numpy as np 5 | import socket 6 | 7 | 8 | def get_dask_client(client_type: str, cluster_name: str, workers_amount_cpus: int, night_mode=False, nodes=1, slurm_script_commands=None, 9 | slurm_memory_per_core=3.6, time_limit_hours=72, slurm_partition="debug", **kwargs): 10 | if cluster_name is None: 11 | cluster_name = "unknown" 12 | if not night_mode: 13 | print("Preparing workers") 14 | if client_type == "local": 15 | client = get_local_client(workers_amount_cpus) 16 | elif client_type == "slurm": 17 | client = get_slurm_cluster(workers_amount_cpus, nodes, slurm_memory_per_core, 18 | script_commands=slurm_script_commands, time_limit_hours=time_limit_hours, 19 | slurm_partition=slurm_partition, **kwargs) 20 | else: 21 | raise ValueError("client_type must be either local or slurm") 22 | if not night_mode: 23 | print(client) 24 | 25 | host = client.run_on_scheduler(socket.gethostname) 26 | port = client.scheduler_info()['services']['dashboard'] 27 | if not night_mode: 28 | print(f"Assuming that the cluster is ran at {cluster_name} (change in config if not the case)") 29 | 30 | print(f"ssh -N -L {port}:{host}:{port} {cluster_name}") 31 | print(f"Then go to http://localhost:{port}/status to check the status of the workers") 32 | 33 | print("Worker preparation complete") 34 | 35 | return client 36 | 37 | 38 | def get_local_client(workers_amount, **kwargs): 39 | if workers_amount >= 1: 40 | client = Client(threads_per_worker=1, n_workers=workers_amount, **kwargs) 41 | else: 42 | client = Client(threads_per_worker=1, **kwargs) 43 | return client 44 | 45 | 46 | def get_slurm_cluster(cores_per_job: int, jobs_nodes: int, memory_per_core_gb: int, script_commands=None, 47 | time_limit_hours=72, slurm_partition='debug', **kwargs): 48 | from dask_jobqueue import SLURMCluster 49 | if script_commands is None: 50 | script_commands = [ # Additional commands to run before starting dask worker 51 | 'module purge', 52 | 'module load basic-path', 53 | 'module load intel', 54 | 'module load anaconda3-py3.10'] 55 | # Create a SLURM cluster object 56 | # split into days, hours in format: days-hh:mm:ss 57 | days = time_limit_hours // 24 58 | hours = time_limit_hours % 24 59 | if days == 0: 60 | time_limit_string = f"{int(hours):02d}:00:00" 61 | else: 62 | time_limit_string = f"{int(days)}-{int(hours):02d}:00:00" 63 | print(time_limit_string) 64 | cluster = SLURMCluster( 65 | queue=slurm_partition, # Which queue/partition to submit jobs to 66 | cores=cores_per_job, # Number of cores per job (so like cores/workers per node) 67 | memory=f"{memory_per_core_gb * cores_per_job}GB", # Amount of memory per job (also per node) 68 | job_script_prologue=script_commands, # Additional commands to run before starting dask worker 69 | walltime=time_limit_string # Time limit for each job 70 | ) 71 | cluster.scale(jobs=jobs_nodes) # How many nodes 72 | client = Client(cluster) 73 | 74 | return client 75 | -------------------------------------------------------------------------------- /plotting_tools/plot_synthetic_grid.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "id": "initial_id", 7 | "metadata": { 8 | "collapsed": true 9 | }, 10 | "outputs": [], 11 | "source": [ 12 | "from __future__ import annotations\n", 13 | "try:\n", 14 | " from scripts_for_plotting import *\n", 15 | "except ModuleNotFoundError:\n", 16 | " import sys\n", 17 | " sys.path.append('../')\n", 18 | " from scripts_for_plotting import *" 19 | ] 20 | }, 21 | { 22 | "cell_type": "code", 23 | "execution_count": null, 24 | "outputs": [], 25 | "source": [ 26 | "# CHANGE NEXT LINE\n", 27 | "output_folder_location: str = \"../synthetic_spectra/OUTPUTCHANGEHERE/\" # CHANGE\n", 28 | "grid_df = load_output_grid(output_folder_location) # dataframe with all the output data\n", 29 | "print(\"Column names are:\")\n", 30 | "print(grid_df.columns.values) # Column names if you want to plot them\n", 31 | "grid_df" 32 | ], 33 | "metadata": { 34 | "collapsed": false 35 | }, 36 | "id": "23ab1dc7151760a8" 37 | }, 38 | { 39 | "cell_type": "code", 40 | "execution_count": null, 41 | "outputs": [], 42 | "source": [ 43 | "# can plot your own results using column names from the data frame\n", 44 | "# can also take any extra arguments just like plt.scatter, example with color='black' is shown below\n", 45 | "# can also add e.g. xlim=(-5, 5) or ylim=(-1, 1) for x and y limits\n", 46 | "# CHANGE COLUMN NAMES IF NEEDED\n", 47 | "plot_scatter_df_results(grid_df, \"teff\", \"logg\", color='feh', invert_x_axis=True, invert_y_axis=True) # can pass colour as a column name or as a colour\n", 48 | "# works in similar way, but plots the density map with the desired cmap\n", 49 | "# s=10 stands for point size\n", 50 | "plot_density_df_results(grid_df, \"teff\", \"logg\", s=10, cmap=\"plasma_r\", alpha=0.5, invert_x_axis=True, invert_y_axis=True)\n", 51 | "# also histogram if needed as well\n", 52 | "plot_histogram_df_results(grid_df, \"feh\", color='grey', bins=20, alpha=0.5, histtype='bar', ec='black')" 53 | ], 54 | "metadata": { 55 | "collapsed": false 56 | }, 57 | "id": "9549e09b26ac3793" 58 | }, 59 | { 60 | "cell_type": "code", 61 | "execution_count": null, 62 | "outputs": [], 63 | "source": [ 64 | "# can also plot individual synthetic spectra\n", 65 | "plot_synthetic_spectra_from_grid(output_folder_location, \"0.spec\")" 66 | ], 67 | "metadata": { 68 | "collapsed": false 69 | }, 70 | "id": "2431292b029869c5" 71 | }, 72 | { 73 | "cell_type": "code", 74 | "execution_count": null, 75 | "outputs": [], 76 | "source": [ 77 | "# can also overplot many synthetic spectra\n", 78 | "plot_many_spectra_same_plot(output_folder_location, [\"0.spec\", \"1.spec\"])" 79 | ], 80 | "metadata": { 81 | "collapsed": false 82 | }, 83 | "id": "8757b2a382422fd" 84 | } 85 | ], 86 | "metadata": { 87 | "kernelspec": { 88 | "display_name": "Python 3", 89 | "language": "python", 90 | "name": "python3" 91 | }, 92 | "language_info": { 93 | "codemirror_mode": { 94 | "name": "ipython", 95 | "version": 2 96 | }, 97 | "file_extension": ".py", 98 | "mimetype": "text/x-python", 99 | "name": "python", 100 | "nbconvert_exporter": "python", 101 | "pygments_lexer": "ipython2", 102 | "version": "2.7.6" 103 | } 104 | }, 105 | "nbformat": 4, 106 | "nbformat_minor": 5 107 | } 108 | -------------------------------------------------------------------------------- /scripts/solar_isotopes.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | A list of solar isotopes. 5 | 6 | Source: Asplund et al. 2009 7 | """ 8 | 9 | solar_isotopes = { 10 | "3.006": 0.0759, 11 | "3.007": 0.9241, 12 | "5.010": 0.199, 13 | "5.011": 0.801, 14 | "6.012": 0.988938, 15 | "6.013": 0.011062, 16 | "7.014": 0.99771, 17 | "7.015": 0.00229, 18 | "8.016": 0.997621, 19 | "8.017": 0.000379, 20 | "8.018": 0.002, 21 | "10.020": 0.929431, 22 | "10.021": 0.002228, 23 | "10.022": 0.068341, 24 | "12.024": 0.7899, 25 | "12.025": 0.1000, 26 | "12.026": 0.1101, 27 | "14.028": 0.922297, 28 | "14.029": 0.046832, 29 | "14.030": 0.030872, 30 | "16.032": 0.9493, 31 | "16.033": 0.0076, 32 | "16.034": 0.0429, 33 | "16.036": 0.0002, 34 | "17.035": 0.7578, 35 | "17.037": 0.2422, 36 | "18.036": 0.845946, 37 | "18.038": 0.153808, 38 | "18.040": 0.000246, 39 | "19.039": 0.93132, 40 | "19.040": 0.00147, 41 | "19.041": 0.06721, 42 | "20.040": 0.96941, 43 | "20.042": 0.00647, 44 | "20.043": 0.00135, 45 | "20.044": 0.02086, 46 | "20.046": 0.00004, 47 | "20.048": 0.00187, 48 | "22.046": 0.0825, 49 | "22.047": 0.0744, 50 | "22.048": 0.7372, 51 | "22.049": 0.0541, 52 | "22.050": 0.0518, 53 | "23.050": 0.0025, 54 | "23.051": 0.9975, 55 | "24.050": 0.04345, 56 | "24.052": 0.83789, 57 | "24.053": 0.09501, 58 | "24.054": 0.02365, 59 | "26.054": 0.05845, 60 | "26.056": 0.91754, 61 | "26.057": 0.02119, 62 | "26.058": 0.00282, 63 | "28.058": 0.680769, 64 | "28.060": 0.262231, 65 | "28.061": 0.011399, 66 | "28.062": 0.036345, 67 | "28.064": 0.009256, 68 | "29.063": 0.6917, 69 | "29.065": 0.3083, 70 | "30.064": 0.4863, 71 | "30.066": 0.279, 72 | "30.067": 0.041, 73 | "30.068": 0.1875, 74 | "30.070": 0.0062, 75 | "31.069": 0.60108, 76 | "31.071": 0.39892, 77 | "32.070": 0.2084, 78 | "32.072": 0.2754, 79 | "32.073": 0.0773, 80 | "32.074": 0.3628, 81 | "32.076": 0.0761, 82 | "34.074": 0.0089, 83 | "34.076": 0.0937, 84 | "34.077": 0.0763, 85 | "34.078": 0.2377, 86 | "34.080": 0.4961, 87 | "34.082": 0.0873, 88 | "35.079": 0.5069, 89 | "35.081": 0.4931, 90 | "36.078": 0.00362, 91 | "36.080": 0.02326, 92 | "36.082": 0.11655, 93 | "36.083": 0.11546, 94 | "36.084": 0.56903, 95 | "36.086": 0.17208, 96 | "37.085": 0.70844, 97 | "37.087": 0.29156, 98 | "38.084": 0.00558, 99 | "38.086": 0.098678, 100 | "38.087": 0.068961, 101 | "38.088": 0.826781, 102 | "40.090": 0.5145, 103 | "40.091": 0.1122, 104 | "40.092": 0.1715, 105 | "40.094": 0.1738, 106 | "40.096": 0.028, 107 | "42.092": 0.14525, 108 | "42.094": 0.09151, 109 | "42.095": 0.15838, 110 | "42.096": 0.16672, 111 | "42.097": 0.09599, 112 | "42.098": 0.24391, 113 | "42.100": 0.09824, 114 | "44.096": 0.0554, 115 | "44.098": 0.0187, 116 | "44.099": 0.1276, 117 | "44.100": 0.126, 118 | "44.101": 0.1706, 119 | "44.102": 0.3155, 120 | "44.104": 0.1862, 121 | "46.102": 0.0102, 122 | "46.104": 0.1114, 123 | "46.105": 0.2233, 124 | "46.106": 0.2733, 125 | "46.108": 0.2646, 126 | "46.110": 0.1172, 127 | "47.107": 0.51839, 128 | "47.109": 0.48161, 129 | "48.106": 0.0125, 130 | "48.108": 0.0089, 131 | "48.110": 0.1249, 132 | "48.111": 0.128, 133 | "48.112": 0.2413, 134 | "48.113": 0.1222, 135 | "48.114": 0.2873, 136 | "48.116": 0.0749, 137 | "49.113": 0.0429, 138 | "49.115": 0.9571, 139 | "50.112": 0.0097, 140 | "50.114": 0.0066, 141 | "50.115": 0.0034, 142 | "50.116": 0.1454, 143 | "50.117": 0.0768, 144 | "50.118": 0.2422, 145 | "50.119": 0.0859, 146 | "50.120": 0.3258, 147 | "50.122": 0.0463, 148 | "50.124": 0.0579, 149 | "51.121": 0.5721, 150 | "51.123": 0.4279, 151 | "52.120": 0.0009, 152 | "52.122": 0.0255, 153 | "52.123": 0.0089, 154 | "52.124": 0.0474, 155 | "52.125": 0.0707, 156 | "52.126": 0.1884, 157 | "52.128": 0.3174, 158 | "52.130": 0.3408, 159 | "56.134": 0.02417, 160 | "56.135": 0.06592, 161 | "56.136": 0.07854, 162 | "56.137": 0.11232, 163 | "56.138": 0.71698, 164 | "63.151": 0.4781, 165 | "63.153": 0.5219 166 | } 167 | 168 | -------------------------------------------------------------------------------- /input_files/synthetic_spectra_generation_configuration.cfg: -------------------------------------------------------------------------------- 1 | [turbospectrum_compiler] 2 | # The compiler used to compile turbospectrum. ifort, gnu, ifx or m3dis 3 | compiler = ifort 4 | 5 | [MainPaths] 6 | # Main paths for the input and output files 7 | code_path = ./turbospectrum/ 8 | interpolators_path = ./scripts/model_interpolators/ 9 | line_list_path = ./input_files/linelists/linelist_for_fitting/ 10 | model_atmosphere_grid_path_1d = ./input_files/model_atmospheres/1D/ 11 | model_atmosphere_grid_path_3d = ./input_files/model_atmospheres/3D/ 12 | model_atoms_path = ./input_files/nlte_data/model_atoms/ 13 | departure_file_path = ./input_files/nlte_data/ 14 | departure_file_config_path = ./input_files/nlte_data/nlte_filenames.cfg 15 | output_path = ./synthetic_spectra/ 16 | input_parameter_path = ./input_files/ 17 | temporary_directory_path = ./temp_directory/ 18 | 19 | [AtmosphereParameters] 20 | # Atmosphere type. ('1D' / '3D') 21 | atmosphere_type = 1D 22 | # Whether or not molecules are included in the fit ('True' / 'False') 23 | include_molecules = True 24 | # Whether to use nlte or not. ('True' or 'False') 25 | nlte = False 26 | # Elements to have in NLTE (just choose whichever elements you want to have in NLTE) 27 | # nlte_elements = Mg Ca Fe 28 | nlte_elements = Fe 29 | # Wavelength setup [AA] 30 | wavelength_min = 6500 31 | wavelength_max = 6600 32 | wavelength_delta = 0.005 33 | # Common resolution for all spectra (lambda_center/FWHM). If 0, no convolution is done 34 | resolution = 0 35 | 36 | [ExtraParameters] 37 | # Extra parameters 38 | # Debug mode. If 1, will print more Python output. If 2, will print more Fortran output. Recommended to keep at 0 39 | debug_mode = 0 40 | # Number of CPUs to use for the fit (1 = no parallelisation). If 0, will use all available CPUs 41 | number_of_cpus = 1 42 | # Name of the cluster (if not launched locally), only used for printing purposes 43 | cluster_name = 44 | # whether to save unnormalised synthetic spectra or not ('True' or 'False') 45 | save_unnormalised_spectra = False 46 | 47 | [InputFile] 48 | # Input file name with the atmospheric parameters to generate the synthetic spectra 49 | input_filename = synthetic_spectra_parameters 50 | 51 | [SlurmClusterParameters] 52 | # Parameters for the Slurm cluster 53 | # Type of cluster. Can be 'slurm' or 'local'. 'local' ignores the other parameters 54 | cluster_type = local 55 | # Number of nodes to use, cpus are taken from the number_of_cpus parameter 56 | number_of_nodes = 1 57 | # Memory per CPU in GB 58 | memory_per_cpu_gb = 3.6 59 | # Commands to run before the script. Each command is separated by a semicolon. example below purges the modules and loads the ones needed 60 | script_commands = module purge;module load basic-path;module load intel;module load anaconda3-py3.10 61 | # Time limit for the job in hours 62 | time_limit_hours = 167 63 | # Partition to use in the cluster passed to the --partition flag 64 | partition = debug 65 | 66 | [AdvancedOptions] 67 | # Only change these if you know what you're doing!! 68 | # Value of lpoint for turbospectrum in spectrum.inc file 69 | lpoint_turbospectrum = 500000 70 | # compute_intensity? True = compute intensity, False = compute flux 71 | compute_intensity_flag = False 72 | # intensity angles to use (defaults are given already) 73 | intensity_angles = 0.010018 0.052035 0.124619 0.222841 0.340008 0.468138 0.598497 0.722203 0.830825 0.916958 0.974726 1.000000 74 | # m3dis parameters 75 | m3dis_python_package_name = m3dis 76 | 77 | [m3disParameters] 78 | # Parameters for the m3dis code 79 | # Number of different nu points (less = faster, but more memory) 80 | n_nu = 1 81 | # Less = faster, but might need higher for 3D or NLTE 82 | # 1D NLTE - 100 seems to work, 1D LTE - 10 or less? 83 | hash_table_size = 100 84 | # Number of cores to use for each separate m3dis run (leave it at 1 for 1D) 85 | mpi_cores = 1 86 | # Only NLTE parameters, iterations is how many times to iterate, convlim is the convergence limit 87 | # iterations_max_precompute is how many times to iterate when precomputing the departure coefficients 88 | # iterations_max is how many times to iterate when fitting when using precomputed departure coefficients (recommended lower than iterations_max_precompute) 89 | iterations_max_precompute = 10 90 | iterations_max = 3 91 | convlim = 0.01 92 | # Only 3D parameters, snap is the snapshot number, dims is the number of dimensions, nx, ny, nz are the resolution of the model (if Stagger) 93 | snap = 1 94 | dims = 23 95 | nx = 10 96 | ny = 10 97 | nz = 230 -------------------------------------------------------------------------------- /scripts/convolve.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | import numpy as np 3 | from astropy import constants as const 4 | from numpy.fft import fft, ifft 5 | from scipy.interpolate import interp1d 6 | 7 | SPEED_OF_LIGHT_KMS = const.c.to('km/s').value 8 | #CONV_RES_CONST_TWOS = (2.0 * np.sqrt(2. * np.log(2.))) # just not to call it every time 9 | MIN_RD = 0.1 / SPEED_OF_LIGHT_KMS # RESAMPLING-DISTANCE 10 | 11 | def conv_res(wavelength, flux, resolution): 12 | """ 13 | Applies convolutions to data sx, sy. Uses gaussian doppler broadedning. 14 | Give resolution in R for gaussian doppler broadening. Converts to doppler broadedning via v_dop = c / R 15 | Credits: Richard Hoppe 16 | """ 17 | # convert resolution to doppler velocity 18 | velocity_doppler = SPEED_OF_LIGHT_KMS / resolution 19 | 20 | sxx = np.log(wavelength.astype(np.float64)) # original xscale in 21 | syy = flux.astype(np.float64) 22 | 23 | rd = 0.5 * np.min(np.diff(sxx)) 24 | rd = np.max([rd, MIN_RD]) 25 | 26 | npres = ((sxx[-1] - sxx[0]) // rd) + 1 27 | npresn = npres + npres % 2 28 | 29 | rd = (sxx[-1] - sxx[0]) / (npresn - 1) 30 | sxn = sxx[0] + np.arange(npresn) * rd 31 | syn = interp1d(sxx, syy)(sxn) 32 | 33 | px = (np.arange(npresn) - npresn // 2) * rd 34 | 35 | width = velocity_doppler / SPEED_OF_LIGHT_KMS 36 | 37 | py = np.exp(- (1.66511 * px / width) ** 2) / (np.sqrt(np.pi) * width) 38 | sxn, syn = conv_profile(sxn, syn, px, py) 39 | 40 | xx = np.exp(sxn) 41 | yy = syn 42 | 43 | return xx, yy 44 | 45 | 46 | def conv_profile(xx, yy, px, py): 47 | norm = np.trapz(py, x=px) 48 | n = len(xx) 49 | dxn = (xx[-1] - xx[0]) / (n - 1) 50 | conv = dxn * ifft(fft(yy) * fft(np.roll(py / norm, int(n / 2)))) 51 | 52 | return xx, np.real(conv) 53 | 54 | 55 | def conv_macroturbulence(wavelength, flux, vmac): 56 | """ 57 | Applies convolutions to data sx, sy. 58 | Give vmac in km/s for convolution with macroturbulence. 59 | Credits: Richard Hoppe 60 | """ 61 | sxx = np.log(wavelength.astype(np.float64)) # original xscale in 62 | syy = flux.astype(np.float64) 63 | 64 | rd = 0.5 * np.min(np.diff(sxx)) 65 | rd = np.max([rd, MIN_RD]) 66 | 67 | npres = ((sxx[-1] - sxx[0]) // rd) + 1 68 | npresn = npres + npres%2 69 | 70 | rd = (sxx[-1] - sxx[0]) / (npresn-1) 71 | sxn = sxx[0] + np.arange(npresn) * rd 72 | syn = interp1d(sxx, syy)(sxn) 73 | 74 | px = (np.arange(npresn) - npresn // 2) * rd 75 | 76 | WAVE_RT_VMAC = np.arange(20) / 10. 77 | FLUX_RT_VMAC = [1.128, 0.939, 0.773, 0.628, 0.504, 0.399, 0.312, 0.240, 0.182, 0.133, 78 | 0.101, 0.070, 0.052, 0.037, 0.024, 0.017, 0.012, 0.010, 0.009, 0.007] 79 | 80 | WAVE_RT_VMAC = np.concatenate([-WAVE_RT_VMAC[:0:-1],WAVE_RT_VMAC]) 81 | FLUX_RT_VMAC = np.concatenate([ FLUX_RT_VMAC[:0:-1],FLUX_RT_VMAC]) 82 | zeta_rt1 = vmac / SPEED_OF_LIGHT_KMS * 1.433 83 | WAVE_RT_VMAC = WAVE_RT_VMAC * zeta_rt1 84 | FLUX_RT_VMAC = FLUX_RT_VMAC / zeta_rt1 85 | py = interp1d(WAVE_RT_VMAC, FLUX_RT_VMAC, bounds_error=False, fill_value=0)(px) 86 | mask = (px < WAVE_RT_VMAC[0]) + (px > WAVE_RT_VMAC[-1]) 87 | py[mask] = 0 88 | 89 | sxn, syn = conv_profile(sxn, syn, px, py) 90 | 91 | xx = np.exp(sxn) 92 | yy = syn 93 | 94 | return xx, yy 95 | 96 | 97 | def conv_rotation(wavelength, flux, vrot): 98 | """ 99 | Applies convolutions to data sx, sy. 100 | Give vrot in km/s for convolution with a rotational profile. 101 | Credits: Richard Hoppe 102 | """ 103 | beta = 1.5 104 | sxx = np.log(wavelength.astype(np.float64)) # original xscale in 105 | syy = flux.astype(np.float64) 106 | 107 | rd = 0.5 * np.min(np.diff(sxx)) 108 | rd = np.max([rd, MIN_RD]) 109 | 110 | npres = ((sxx[-1] - sxx[0]) // rd) + 1 111 | npresn = npres + npres%2 112 | 113 | rd = (sxx[-1] - sxx[0]) / (npresn-1) 114 | sxn = sxx[0] + np.arange(npresn) * rd 115 | syn = interp1d(sxx, syy)(sxn) 116 | 117 | px = (np.arange(npresn) - npresn // 2) * rd 118 | 119 | normf = SPEED_OF_LIGHT_KMS / vrot 120 | xi = normf*px 121 | 122 | xi[abs(xi) > 1] = 1 123 | 124 | py = (2*np.sqrt(1-xi**2) / np.pi + beta*(1-xi**2) / 2) * normf / (1 + 6/9*beta) 125 | 126 | sxn, syn = conv_profile(sxn, syn, px, py) 127 | 128 | xx = np.exp(sxn) 129 | yy = syn 130 | 131 | return xx, yy 132 | -------------------------------------------------------------------------------- /input_files/nlte_data/nlte_filenames.cfg: -------------------------------------------------------------------------------- 1 | # You can add more or change models paths/names here if needed 2 | # 3 | # Changelog: 4 | # 2023 Apr 18: File creation date 5 | # 2023 Jun 6: Added Y for 3D models (actually was in May, but forgot to update comments) 6 | # 2023 Jul 18: Added Sr for 3D models 7 | # 2023 Aug 4: Added Al for 1D models, updated Ba and Na 1D models 8 | # 2023 Aug 4: Added Al, Co, Na, Ti, Si for 3D models 9 | # 2023 Aug 14: Updated Ba and Ni 3D models 10 | # 2024 Nov 25: Updated Mg, Co grids, added 3D Eu grid 11 | # 2025 May 16: Updated Cr grids 12 | # 2025 July 8: Updated Mg grid, fixed naming of the Y model atom 13 | 14 | # 17 elements 15 | # 3D and 1D models: Al, Ba, Ca, Co, Cr, Eu, Fe, Na, H, Mg, Mn, Ni, O, Si, Sr, Ti, Y 16 | # 1D models only: 17 | 18 | [Al] 19 | 1d_bin = Al/NLTEgrid_Al_MARCS_Jul-25-2023.bin 20 | 1d_aux = Al/auxData_Al_MARCS_Jul-25-2023.dat 21 | 3d_bin = Al/NLTEgrid_Al_STAGGERmean3D_Aug-05-2023.bin 22 | 3d_aux = Al/auxData_Al_STAGGERmean3D_Aug-05-2023_marcs_names.txt 23 | atom_file = atom.al_qmh 24 | 25 | [Ba] 26 | 1d_bin = Ba/NLTEgrid_Ba_MARCS_Jul-29-2023.bin 27 | 1d_aux = Ba/auxData_Ba_MARCS_Jul-29-2023.dat 28 | 3d_bin = Ba/NLTEgrid4TS_Ba_STAGGERmean3D_Aug-11-2023.bin 29 | 3d_aux = Ba/auxData_Ba_STAGGERmean3D_Aug-11-2023_marcs_names.txt 30 | atom_file = atom.ba111 31 | 32 | [Ca] 33 | 1d_bin = Ca/NLTEgrid4TS_Ca_MARCS_Jun-02-2021.bin 34 | 1d_aux = Ca/auxData_Ca_MARCS_Jun-02-2021.dat 35 | 3d_bin = Ca/NLTEgrid4TS_Ca_STAGGERmean3D_May-18-2021.bin 36 | 3d_aux = Ca/auxData_Ca_STAGGERmean3D_May-18-2021_marcs_names.txt 37 | atom_file = atom.ca105b 38 | 39 | [Co] 40 | 1d_bin = Co/NLTEgrid4TS_CO_MARCS_Nov-14-2024.bin 41 | 1d_aux = Co/auxData_CO_MARCS_Nov-14-2024.dat 42 | 3d_bin = Co/NLTEgrid4TS_Co_STAGGERmean3D_Nov-20-2024.bin 43 | 3d_aux = Co/auxData_Co_STAGGERmean3D_Nov-20-2024_marcs_names.txt 44 | atom_file = atom.co247qm 45 | 46 | [Cr] 47 | 1d_bin = Cr/NLTEgrid4TS_Cr_MARCS_Dec-16-2024.bin 48 | 1d_aux = Cr/auxData_Cr_MARCS_Dec-16-2024.dat 49 | 3d_bin = Cr/NLTEgrid4TS_Cr_STAGGERmean3D_Dec-12-2024.bin 50 | 3d_aux = Cr/auxData_Cr_STAGGERmean3D_Dec-12-2024_marcs_names.txt 51 | atom_file = atom.cr374 52 | 53 | [Eu] 54 | 1d_bin = Eu/NLTEgrid_Eu_MARCS_Sep-13-2023.bin 55 | 1d_aux = Eu/auxData_Eu_MARCS_Sep-13-2023.dat 56 | 3d_bin = Eu/NLTEgrid4TS_Eu_STAGGERmean3D_Nov-20-2024.bin 57 | 3d_aux = Eu/auxData_Eu_STAGGERmean3D_Nov-20-2024_marcs_names.txt 58 | atom_file = atom.eu662qmkhfs 59 | 60 | [Fe] 61 | 1d_bin = Fe/NLTEgrid4TS_Fe_MARCS_May-07-2021.bin 62 | 1d_aux = Fe/auxData_Fe_MARCS_May-07-2021.dat 63 | 3d_bin = Fe/NLTEgrid4TS_Fe_STAGGERmean3D_May-21-2021.bin 64 | 3d_aux = Fe/auxData_Fe_STAGGERmean3D_May-21-2021_marcs_names.txt 65 | atom_file = atom.fe607a 66 | 67 | [H] 68 | 1d_bin = H/NLTEgrid_H_MARCS_May-10-2021.bin 69 | 1d_aux = H/auxData_H_MARCS_May-10-2021.txt 70 | 3d_bin = H/NLTEgrid4TS_H_STAGGERmean3D_Jun-17-2021.bin 71 | 3d_aux = H/auxData_H_STAGGERmean3D_Jun-17-2021_marcs_names.txt 72 | atom_file = atom.h20 73 | 74 | [Mg] 75 | 1d_bin = Mg/NLTEgrid4TS_Mg_MARCS_Nov-13-2024.bin 76 | 1d_aux = Mg/auxData_Mg_MARCS_Nov-13-2024.dat 77 | 3d_bin = Mg/NLTEgrid4TS_Mg_STAGGERmean3D_Nov-20-2024.bin 78 | 3d_aux = Mg/auxData_Mg_STAGGERmean3D_Nov-20-2024_marcs_names.txt 79 | atom_file = atom.mg86d 80 | 81 | [Mn] 82 | 1d_bin = Mn/NLTEgrid4TS_MN_MARCS_Mar-15-2023.bin 83 | 1d_aux = Mn/auxData_MN_MARCS_Mar-15-2023.dat 84 | 3d_bin = Mn/NLTEgrid4TS_Mn_STAGGERmean3D_May-17-2021.bin 85 | 3d_aux = Mn/auxData_Mn_STAGGERmean3D_May-17-2021_marcs_names.txt 86 | atom_file = atom.mn281kbc 87 | 88 | [Na] 89 | 1d_bin = Na/NLTEgrid4TS_Na_MARCS_Jul-14-2023.bin 90 | 1d_aux = Na/auxData_Na_MARCS_Jul-14-2023.dat 91 | 3d_bin = Na/NLTEgrid4TS_Na_STAGGERmean3D_Aug-04-2023.bin 92 | 3d_aux = Na/auxData_Na_STAGGERmean3D_Aug-04-2023_marcs_names.txt 93 | atom_file = atom.na_qmh 94 | 95 | [Ni] 96 | 1d_bin = Ni/NLTEgrid4TS_Ni_MARCS_Jan-31-2022.bin 97 | 1d_aux = Ni/auxData_Ni_MARCS_Jan-21-2022.txt 98 | 3d_bin = Ni/NLTEgrid4TS_NI_STAGGERmean3D_Aug-12-2023.bin 99 | 3d_aux = Ni/auxData_NI_STAGGERmean3D_Aug-12-2023_marcs_names.txt 100 | atom_file = atom.ni538qm 101 | 102 | [O] 103 | 1d_bin = O/NLTEgrid4TS_O_MARCS_May-21-2021.bin 104 | 1d_aux = O/auxData_O_MARCS_May-21-2021.txt 105 | 3d_bin = O/NLTEgrid4TS_O_STAGGERmean3D_May-18-2021.bin 106 | 3d_aux = O/auxData_O_STAGGER_May-18-2021_marcs_names.txt 107 | atom_file = atom.o41f 108 | 109 | [Si] 110 | 1d_bin = Si/NLTEgrid4TS_Si_MARCS_Feb-13-2022.bin 111 | 1d_aux = Si/auxData_Si_MARCS_Feb-13-2022.dat 112 | 3d_bin = Si/NLTEgrid4TS_Si_STAGGERmean3D_Aug-05-2023.bin 113 | 3d_aux = Si/auxData_Si_STAGGERmean3D_Aug-05-2023_marcs_names.txt 114 | atom_file = atom.si340 115 | 116 | [Sr] 117 | 1d_bin = Sr/NLTEgrid4TS_Sr_MARCS_Mar-15-2023.bin 118 | 1d_aux = Sr/auxData_Sr_MARCS_Mar-15-2023.dat 119 | 3d_bin = Sr/NLTEgrid_Sr_STAGGERmean3D_Jul-17-2023.bin 120 | 3d_aux = Sr/auxData_Sr_STAGGEmean3D_Jul-17-2023_marcs_names.dat 121 | atom_file = atom.sr191 122 | 123 | [Ti] 124 | 1d_bin = Ti/NLTEgrid4TS_TI_MARCS_Feb-21-2022.bin 125 | 1d_aux = Ti/auxData_TI_MARCS_Feb-21-2022.dat 126 | 3d_bin = Ti/NLTEgrid4TS_Ti_STAGGERmean3D_Aug-07-2023.bin 127 | 3d_aux = Ti/auxData_Ti_STAGGERmean3D_Aug-07-2023_marcs_names.txt 128 | atom_file = atom.ti503 129 | 130 | [Y] 131 | 1d_bin = Y/NLTEgrid4TS_Y_MARCS_Mar-27-2023.bin 132 | 1d_aux = Y/auxData_Y_MARCS_Mar-27-2023.dat 133 | 3d_bin = Y/NLTEgrid4TS_Y_STAGGERmean3D_May-08-2023.bin 134 | 3d_aux = Y/auxData_Y_STAGGERmean3D_May-08-2023_marcs_names.dat 135 | atom_file = atom.y423qm_pf -------------------------------------------------------------------------------- /unittests/linelist_testing/atomic_test_data: -------------------------------------------------------------------------------- 1 | ' 3.000 ' 1 3 2 | 'Li I LTE' 3 | 3602.826 1.848 -0.613 2006.342 4.0 6.61E+07 'p' 'd' 0.0 1.0 'Li I LS:1s2.2p 2P* LS:1s2.4d 2D' 4 | 4202.894 1.848 -0.353 2006.342 6.0 6.03E+07 'p' 'd' 0.0 1.0 'Li I LS:1s2.2p 2P* LS:1s2.4d 2D' 5 | 9009.733 3.879 -2.994 2.500 4.0 6.92E+07 'd' 'p' 0.0 1.0 'Li I LS:1s2.3d 2D LS:1s2.10p 2P*' 6 | ' 13.000 ' 1 6 7 | 'Al I NLTE' 8 | 3592.227 3.143 -3.291 2.500 4.0 1.00E+05 's' 'p' 0.0 1.0 'Al I LS:3s2.4s 2S LS:3s2.11p 2P*' 3 47 '4s2S0.5' '11p2P' 'c' 'a' 9 | 3592.296 3.143 -3.592 2.500 2.0 1.00E+05 's' 'p' 0.0 1.0 'Al I LS:3s2.4s 2S LS:3s2.11p 2P*' 3 47 '4s2S0.5' '11p2P' 'c' 'a' 10 | 4202.414 3.143 -3.125 2.500 4.0 1.00E+05 's' 'p' 0.0 1.0 'Al I LS:3s2.4s 2S LS:3s2.10p 2P*' 3 39 '4s2S0.5' '10p2P' 'c' 'a' 11 | 4202.512 3.143 -3.426 2.500 2.0 1.00E+05 's' 'p' 0.0 1.0 'Al I LS:3s2.4s 2S LS:3s2.10p 2P*' 3 39 '4s2S0.5' '10p2P' 'c' 'a' 12 | 9170.870 4.022 -3.088 2.500 4.0 1.00E+05 'd' 'p' 0.0 1.0 'Al I LS:3s2.3d 2D LS:3s2.6p 2P*' 5 13 '3d2D' '6p2P' 'c' 'a' 13 | 9172.150 4.022 -3.343 2.500 2.0 1.00E+05 'd' 'p' 0.0 1.0 'Al I LS:3s2.3d 2D LS:3s2.6p 2P*' 5 13 '3d2D' '6p2P' 'c' 'a' 14 | ' 13.000 ' 2 2 15 | 'Al II NLTE' 16 | 3663.046 10.598 -0.284 2.500 3.0 9.77E+07 'p' 's' 0.0 1.0 'Al II LS:3p2 1D LS:3s.4p 1P*' 0 0 'none' 'none' 'x' 'x' 17 | 4998.860 14.890 -3.460 2.500 3.0 1.00E+05 's' 'p' 0.0 1.0 'Al II LS:3s.5s 3S LS:3s.7p 3P*' 0 0 'none' 'none' 'x' 'x' 18 | ' 14.000 ' 1 9 19 | 'Si I NLTE' 20 | 4200.038 4.930 -4.698 -6.860 5.0 3.39E+08 'd' 'f' 0.0 1.0 'Si I LS:3s2.3p.4s 3P* JK:3s2.3p.(2P*<1/2>).7f 2[5/2]' 8 143 '4s3P1*' '7i1H*' 'c' 'a' 21 | 4200.686 4.954 -4.263 -6.860 7.0 3.39E+08 'd' 'f' 0.0 1.0 'Si I LS:3s2.3p.4s 3P* JK:3s2.3p.(2P*<1/2>).7f 2[5/2]' 9 143 '4s3P2*' '7i1H*' 'c' 'a' 22 | 4200.906 4.954 -4.317 -6.860 5.0 3.39E+08 'd' 'f' 0.0 1.0 'Si I LS:3s2.3p.4s 3P* JK:3s2.3p.(2P*<1/2>).7f 2[5/2]' 9 143 '4s3P2*' '7i1H*' 'c' 'a' 23 | 4201.164 4.954 -5.223 -6.860 7.0 3.39E+08 'd' 'f' 0.0 1.0 'Si I LS:3s2.3p.4s 3P* JK:3s2.3p.(2P*<1/2>).7f 2[7/2]' 9 143 '4s3P2*' '7i1H*' 'c' 'a' 24 | 4202.428 4.930 -3.241 -6.870 5.0 3.39E+08 's' 'p' 0.0 1.0 'Si I LS:3s2.3p.4s 3P* JJ:3s2.3p.(2P*<1/2>).8p.<3/2> (1/2,3/2)' 8 0 '4s3P1*' 'none' 'c' 'x' 25 | 4203.124 4.920 -4.245 -6.980 3.0 3.31E+08 'd' 'f' 0.0 1.0 'Si I LS:3s2.3p.4s 3P* JK:3s2.3p.(2P*<3/2>).6f 2[3/2]' 7 130 '4s3P0*' '6g3D*' 'c' 'a' 26 | 4204.087 4.954 -2.744 -6.870 5.0 3.39E+08 's' 'p' 0.0 1.0 'Si I LS:3s2.3p.4s 3P* JJ:3s2.3p.(2P*<1/2>).8p.<3/2> (1/2,3/2)' 9 0 '4s3P2*' 'none' 'c' 'x' 27 | 4204.302 4.930 -3.844 -6.980 5.0 3.39E+08 'd' 'f' 0.0 1.0 'Si I LS:3s2.3p.4s 3P* JK:3s2.3p.(2P*<3/2>).6f 2[3/2]' 8 130 '4s3P1*' '6g3D*' 'c' 'a' 28 | 4205.000 4.930 -4.429 -6.980 3.0 3.39E+08 'd' 'f' 0.0 1.0 'Si I LS:3s2.3p.4s 3P* JK:3s2.3p.(2P*<3/2>).6f 2[3/2]' 8 130 '4s3P1*' '6g3D*' 'c' 'a' 29 | ' 14.000 ' 2 4 30 | 'Si II NLTE' 31 | 3200.658 12.525 -0.889 -7.010 6.0 8.13E+08 'd' 'f' 0.0 1.0 'Si II LS:3s2.(1S).4d 2D* LS:3s2.(1S).8f 2F' 302 329 '4d2D' '8f2F*' 'c' 'a' 32 | 3200.898 12.526 -0.733 -7.010 8.0 8.13E+08 'd' 'f' 0.0 1.0 'Si II LS:3s2.(1S).4d 2D* LS:3s2.(1S).8f 2F' 302 329 '4d2D' '8f2F*' 'c' 'a' 33 | 4200.969 12.839 -0.904 -6.960 10.0 3.55E+08 'd' 'f' 0.0 1.0 'Si II LS:3s2.(1S).4f 2F LS:3s2.(1S).9g 2G*' 303 334 '4f2F*' '9g2G' 'c' 'a' 34 | 4204.994 12.839 -1.017 -6.960 8.0 3.55E+08 'd' 'f' 0.0 1.0 'Si II LS:3s2.(1S).4f 2F LS:3s2.(1S).9g 2G*' 303 334 '4f2F*' '9g2G' 'c' 'a' 35 | ' 15.000 ' 1 6 36 | 'P I LTE' 37 | 4200.019 6.936 -2.500 2.500 4.0 1.00E+05 's' 'p' 0.0 1.0 'P I LS:3s2.3p2.(3P).4s 4P LS:3s2.3p2.(3P).6p 4P*' 38 | 4202.997 6.985 -2.000 2.500 4.0 1.00E+05 's' 'p' 0.0 1.0 'P I LS:3s2.3p2.(3P).4s 4P LS:3s2.3p2.(3P).6p 4S*' 39 | 4204.988 6.985 -2.300 2.500 6.0 1.00E+05 's' 'p' 0.0 1.0 'P I LS:3s2.3p2.(3P).4s 4P LS:3s2.3p2.(3P).6p 4P*' 40 | 4205.054 8.284 -1.880 2.500 6.0 1.00E+05 'p' 'd' 0.0 1.0 'P I LS:3s2.3p2.(3P).4p 2D* LS:3s2.3p2.(3P).4d 4P' 41 | 9175.813 6.936 -0.810 506.230 4.0 1.00E+05 's' 'p' 0.0 1.0 'P I LS:3s2.3p2.(3P).4s 4P LS:s2.3p2.(3P).4p 4S*' 42 | 9193.852 6.936 -2.630 2.500 4.0 1.00E+05 's' 'p' 0.0 1.0 'P I LS:3s2.3p2.(3P).4s 4P LS:3s2.3p2.(3P).4p 2D*' 43 | ' 15.000 ' 2 3 44 | 'P II LTE' 45 | 3669.249 0.020 -9.141 -7.910 1.0 1.00E+05 'p' 's' 0.0 1.0 'P II LS:3s2.3p2 3P LS:3s2.3p2 1S*' 46 | 3720.344 10.755 -1.948 -7.680 5.0 1.70E+09 's' 'p' 0.0 1.0 'P II LS:3s2.3p.4s 3P* LS:3s2.3p.4p 1D' 47 | 3739.557 12.813 -1.422 -7.550 3.0 8.13E+08 'p' 's' 0.0 1.0 'P II LS:3s2.3p.4p 3D LS:3s2.3p.5s 1P*' 48 | ' 16.000 ' 1 3 49 | 'S I LTE' 50 | 9039.300 8.046 -1.040 1674.292 5.0 2.00E+08 'p' 'd' 0.0 1.0 'S I LS:3s2.3p3.(4S).4p 3P LS:s2.3p3.(4S).4d 3D*' 51 | 9039.630 8.046 -2.210 1674.292 3.0 2.00E+08 'p' 'd' 0.0 1.0 'S I LS:3s2.3p3.(4S).4p 3P LS:s2.3p3.(4S).4d 3D*' 52 | 9186.692 8.584 -3.946 -6.990 3.0 7.59E+08 's' 'p' 0.0 1.0 'S I LS:3s2.3p3.(2D*).4s 1D* LS:3s2.3p3.(4S*).7p 3P' 53 | -------------------------------------------------------------------------------- /scripts/solar_abundances.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | A list of solar abundances. 5 | 6 | Changed by Gerber Nov. 2019 7 | Source: Asplund et al. 2009 8 | Updated to Magg et al. 2022 on Feb. 5 2022 9 | """ 10 | solar_abundances = { 11 | "STD?": "T", 12 | "[Fe/H]": 0.00, 13 | "[alpha/Fe]": 0.00, 14 | "[C/Fe]": 0.00, 15 | "[N/Fe]": 0.00, 16 | "[O/Fe]": 0.00, 17 | "[r/Fe]": 0.00, 18 | "[s/Fe]": 0.00, 19 | "C/O": 0.54954, 20 | "X": 0.73826, 21 | "Y_": 0.24954, # because Yttrium is also Y, so Y_ is used for Helium 22 | "Z": 1.22E-02, 23 | "H": 12.00, 24 | "He": 10.93, 25 | "Li": 1.05, 26 | "Be": 1.38, 27 | "B": 2.70, 28 | "C": 8.56, 29 | "N": 7.98, 30 | "O": 8.77, 31 | "F": 4.40, 32 | "Ne": 8.16, 33 | "Na": 6.29, 34 | "Mg": 7.55, 35 | "Al": 6.43, 36 | "Si": 7.59, 37 | "P": 5.41, 38 | "S": 7.16, 39 | "Cl": 5.25, 40 | "Ar": 6.40, 41 | "K": 5.14, 42 | "Ca": 6.37, 43 | "Sc": 3.07, 44 | "Ti": 4.94, 45 | "V": 3.89, 46 | "Cr": 5.74, 47 | "Mn": 5.52, 48 | "Fe": 7.50, 49 | "Co": 4.95, 50 | "Ni": 6.24, 51 | "Cu": 4.19, 52 | "Zn": 4.56, 53 | "Ga": 3.04, 54 | "Ge": 3.65, 55 | "As": 2.29, #not in asplund, kept old value 56 | "Se": 3.33, #ditto 57 | "Br": 2.56, #ditto 58 | "Kr": 3.25, 59 | "Rb": 2.52, 60 | "Sr": 2.87, 61 | "Y": 2.21, 62 | "Zr": 2.58, 63 | "Nb": 1.46, 64 | "Mo": 1.88, 65 | "Tc": -99.00, #ditto 66 | "Ru": 1.75, 67 | "Rh": 0.91, 68 | "Pd": 1.57, 69 | "Ag": 0.94, 70 | "Cd": 1.77, #ditto 71 | "In": 0.80, 72 | "Sn": 2.04, 73 | "Sb": 1.00, #ditto 74 | "Te": 2.19, #ditto 75 | "I": 1.51, #ditto 76 | "Xe": 2.24, 77 | "Cs": 1.07, #ditto 78 | "Ba": 2.18, 79 | "La": 1.10, 80 | "Ce": 1.58, 81 | "Pr": 0.72, 82 | "Nd": 1.42, 83 | "Pm": -99.00, #ditto 84 | "Sm": 0.96, 85 | "Eu": 0.52, 86 | "Gd": 1.07, 87 | "Tb": 0.30, 88 | "Dy": 1.10, 89 | "Ho": 0.48, 90 | "Er": 0.92, 91 | "Tm": 0.10, 92 | "Yb": 0.84, 93 | "Lu": 0.10, 94 | "Hf": 0.85, 95 | "Ta": -0.17, #ditto 96 | "W": 0.85, 97 | "Re": 0.23, #ditto 98 | "Os": 1.40, 99 | "Ir": 1.38, 100 | "Pt": 1.64, #ditto 101 | "Au": 0.92, 102 | "Hg": 1.13, #ditto 103 | "Tl": 0.90, 104 | "Pb": 1.75, 105 | "Bi": 0.65, #ditto 106 | "Po": -99.00, #ditto 107 | "At": -99.00, #ditto 108 | "Rn": -99.00, #ditto 109 | "Fr": -99.00, #ditto 110 | "Ra": -99.00, #ditto 111 | "Ac": -99.00, #ditto 112 | "Th": 0.02, 113 | "Pa": -99.00, #ditto 114 | "U": -0.52 #ditto 115 | } 116 | 117 | """ 118 | A list of solar abundances. 119 | 120 | These values were supplied by Bengt Edvardsson, June 2017 121 | Source: Grevesse et al. 2007, Space Sci Rev 130,105 122 | """ 123 | 124 | #solar_abundances = { 125 | # "STD?": "T", 126 | # "[Fe/H]": 0.00, 127 | # "[alpha/Fe]": 0.00, 128 | # "[C/Fe]": 0.00, 129 | # "[N/Fe]": 0.00, 130 | # "[O/Fe]": 0.00, 131 | # "[r/Fe]": 0.00, 132 | # "[s/Fe]": 0.00, 133 | # "C/O": 0.537, 134 | # "X": 0.73826, 135 | # "Y": 0.24954, 136 | # "Z": 1.22E-02, 137 | # "H": 12.00, 138 | # "He": 10.93, 139 | # "Li": 1.05, 140 | # "Be": 1.38, 141 | # "B": 2.70, 142 | # "C": 8.39, 143 | # "N": 7.78, 144 | # "O": 8.66, 145 | # "F": 4.56, 146 | # "Ne": 7.84, 147 | # "Na": 6.17, 148 | # "Mg": 7.53, 149 | # "Al": 6.37, 150 | # "Si": 7.51, 151 | # "P": 5.36, 152 | # "S": 7.14, 153 | # "Cl": 5.50, 154 | # "Ar": 6.18, 155 | # "K": 5.08, 156 | # "Ca": 6.31, 157 | # "Sc": 3.17, 158 | # "Ti": 4.90, 159 | # "V": 4.00, 160 | # "Cr": 5.64, 161 | # "Mn": 5.39, 162 | # "Fe": 7.45, 163 | # "Co": 4.92, 164 | # "Ni": 6.23, 165 | # "Cu": 4.21, 166 | # "Zn": 4.60, 167 | # "Ga": 2.88, 168 | # "Ge": 3.58, 169 | # "As": 2.29, 170 | # "Se": 3.33, 171 | # "Br": 2.56, 172 | # "Kr": 3.25, 173 | # "Rb": 2.60, 174 | # "Sr": 2.92, 175 | # "Y": 2.21, 176 | # "Zr": 2.58, 177 | # "Nb": 1.42, 178 | # "Mo": 1.92, 179 | # "Tc": -99.00, 180 | # "Ru": 1.84, 181 | # "Rh": 1.12, 182 | # "Pd": 1.66, 183 | # "Ag": 0.94, 184 | # "Cd": 1.77, 185 | # "In": 1.60, 186 | # "Sn": 2.00, 187 | # "Sb": 1.00, 188 | # "Te": 2.19, 189 | # "I": 1.51, 190 | # "Xe": 2.24, 191 | # "Cs": 1.07, 192 | # "Ba": 2.17, 193 | # "La": 1.13, 194 | # "Ce": 1.70, 195 | # "Pr": 0.58, 196 | # "Nd": 1.45, 197 | # "Pm": -99.00, 198 | # "Sm": 1.00, 199 | # "Eu": 0.52, 200 | # "Gd": 1.11, 201 | # "Tb": 0.28, 202 | # "Dy": 1.14, 203 | # "Ho": 0.51, 204 | # "Er": 0.93, 205 | # "Tm": 0.00, 206 | # "Yb": 1.08, 207 | # "Lu": 0.06, 208 | # "Hf": 0.88, 209 | # "Ta": -0.17, 210 | # "W": 1.11, 211 | # "Re": 0.23, 212 | # "Os": 1.25, 213 | # "Ir": 1.38, 214 | # "Pt": 1.64, 215 | # "Au": 1.01, 216 | # "Hg": 1.13, 217 | # "Tl": 0.90, 218 | # "Pb": 2.00, 219 | # "Bi": 0.65, 220 | # "Po": -99.00, 221 | # "At": -99.00, 222 | # "Rn": -99.00, 223 | # "Fr": -99.00, 224 | # "Ra": -99.00, 225 | # "Ac": -99.00, 226 | # "Th": 0.06, 227 | # "Pa": -99.00, 228 | # "U": -0.52 229 | #} 230 | 231 | periodic_table = [ 232 | "", 233 | "H", "He", "Li", "Be", "B", "C", "N", "O", "F", "Ne", 234 | "Na", "Mg", "Al", "Si", "P", "S", "Cl", "Ar", 235 | "K", "Ca", "Sc", "Ti", "V", "Cr", "Mn", "Fe", "Co", "Ni", "Cu", "Zn", "Ga", "Ge", "As", "Se", "Br", "Kr", 236 | "Rb", "Sr", "Y", "Zr", "Nb", "Mo", "Tc", "Ru", "Rh", "Pd", "Ag", "Cd", "In", "Sn", "Sb", "Te", "I", "Xe", 237 | "Cs", "Ba", "La", 238 | "Ce", "Pr", "Nd", "Pm", "Sm", "Eu", "Gd", "Tb", "Dy", "Ho", "Er", "Tm", "Yb", "Lu", 239 | "Hf", "Ta", "W", "Re", "Os", "Ir", "Pt", "Au", "Hg", "Tl", "Pb", "Bi", "Po", "At", "Rn", 240 | "Fr", "Ra", "Ac", "Th", "Pa", "U"] 241 | 242 | molecules_atomic_number = {"CH": ["0106.000000", "C H"], "CN": ["0607.000000", "C N"]} -------------------------------------------------------------------------------- /plotting_tools/analyse_the_output.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | import sys, os 3 | 4 | sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..', ))) 5 | 6 | import numpy as np 7 | import pandas as pd 8 | import matplotlib 9 | import matplotlib.pyplot as plt 10 | from plotting_tools.scripts_for_plotting import load_output_data 11 | import argparse 12 | from pathlib import Path 13 | 14 | 15 | # Created by storm at 06.11.24 16 | 17 | def get_average_abundance(output_folder_location, remove_errors, remove_warnings, chisqr_limit, ew_limits, ew_limit_total): 18 | config_dict = load_output_data(output_folder_location) 19 | output_file_df = config_dict["output_file_df"] 20 | fitted_element = config_dict["fitted_element"] 21 | if fitted_element != "Fe": 22 | fitted_element = f"{fitted_element}_Fe" 23 | x_value_plot = "Fe_H" 24 | else: 25 | fitted_element = "Fe_H" 26 | x_value_plot = "wave_center" 27 | 28 | # remove any rows 29 | if remove_errors: 30 | output_file_df = output_file_df[output_file_df['flag_error'] == 0] 31 | if remove_warnings: 32 | output_file_df = output_file_df[output_file_df['flag_warning'] == 0] 33 | output_file_df = output_file_df[output_file_df['chi_squared'] <= chisqr_limit] 34 | output_file_df = output_file_df[output_file_df['ew_just_line'] >= ew_limits[0]] 35 | output_file_df = output_file_df[output_file_df['ew_just_line'] <= ew_limits[1]] 36 | output_file_df = output_file_df[output_file_df['ew'] <= ew_limit_total] 37 | 38 | output_file_df.reset_index(drop=True, inplace=True) 39 | 40 | output_df = pd.DataFrame() 41 | # new columns: specname, x_value, y_value 42 | output_df["specname"] = [] 43 | output_df[x_value_plot] = [] 44 | output_df[fitted_element] = [] 45 | output_df[f"{fitted_element}_err"] = [] 46 | output_df["vmac"] = [] 47 | output_df["vmac_err"] = [] 48 | output_df["vsini"] = [] 49 | output_df["vsini_err"] = [] 50 | output_df["ew_line"] = [] 51 | 52 | # get the data from the fitted spectra 53 | specnames = np.unique(output_file_df['specname'].values) 54 | 55 | for specname in specnames: 56 | # find all rows with the same specname 57 | indices = np.where(output_file_df['specname'] == specname)[0] 58 | 59 | if np.size(indices) > 0: 60 | # new row in the dataframe 61 | output_df.loc[len(output_df)] = [specname, np.mean(output_file_df[x_value_plot][indices]), 62 | np.mean(output_file_df[fitted_element][indices]), 63 | np.std(output_file_df[fitted_element][indices]), 64 | np.mean(output_file_df["Macroturb"][indices]), 65 | np.std(output_file_df["Macroturb"][indices]), 66 | np.mean(output_file_df["rotation"][indices]), 67 | np.std(output_file_df["rotation"][indices]), 68 | np.mean(output_file_df["ew_just_line"][indices]),] 69 | print(f"specname: {specname}, x_value: {np.mean(output_file_df[x_value_plot][indices])}, y_value: {np.mean(output_file_df[fitted_element][indices])}") 70 | 71 | return output_df 72 | 73 | def main( 74 | folder_path: str, 75 | *, 76 | remove_errors: bool = True, 77 | remove_warnings: bool = True, 78 | chisqr_limit: float = 5.0, 79 | ew_limits: tuple[float, float] = (1, 200), 80 | ew_limit_total: float = 350.0, 81 | ): 82 | """Run TSFitPy post-processing and write average_abundance.csv.""" 83 | output_df = get_average_abundance( 84 | folder_path, 85 | remove_errors=remove_errors, 86 | remove_warnings=remove_warnings, 87 | chisqr_limit=chisqr_limit, 88 | ew_limits=ew_limits, 89 | ew_limit_total=ew_limit_total, 90 | ) 91 | print(output_df) 92 | output_df.to_csv(Path(folder_path) / "average_abundance.csv", index=False) 93 | 94 | 95 | # ---------------------------------------------------------------------- 96 | # 2. Command-line interface (all *optional*, with sensible defaults) 97 | # ---------------------------------------------------------------------- 98 | if __name__ == "__main__": 99 | # remove_errors - if True, remove all rows with flag_error != 0 100 | # remove_warnings - if True, remove all rows with flag_warning != 0 101 | # chisqr_limit - maximum chi_squared value to keep (set higher for bigger linemasks, e.g. molecular bands) 102 | # ew_limits - tuple with minimum and maximum equivalent width to keep for the actual line 103 | # ew_limit_total - maximum equivalent width to keep for the whole line (including blends) 104 | 105 | parser = argparse.ArgumentParser( 106 | description="Analyse the output of the TSFitPy fitting process." 107 | ) 108 | 109 | parser.add_argument( 110 | "folder_path", 111 | nargs="?", 112 | default=None, 113 | help="Path to the output folder containing the fitting results." 114 | " If omitted, the hard-coded fallback value is used.", 115 | ) 116 | 117 | parser.add_argument( 118 | "--remove-errors", 119 | dest="remove_errors", 120 | action=argparse.BooleanOptionalAction, 121 | default=True, 122 | help="Remove rows with flag_error != 0 (default: True)", 123 | ) 124 | parser.add_argument( 125 | "--remove-warnings", 126 | dest="remove_warnings", 127 | action=argparse.BooleanOptionalAction, 128 | default=True, 129 | help="Remove rows with flag_warning != 0 (default: True)", 130 | ) 131 | 132 | parser.add_argument( 133 | "--chisqr-limit", 134 | type=float, 135 | default=5.0, 136 | help="Maximum chi_squared value to keep (default: 5.0)", 137 | ) 138 | parser.add_argument( 139 | "--ew-limits", 140 | type=float, 141 | nargs=2, 142 | metavar=("MIN", "MAX"), 143 | default=(1, 200), 144 | help="Min and max equivalent width for the line (default: 1 200)", 145 | ) 146 | parser.add_argument( 147 | "--ew-limit-total", 148 | type=float, 149 | default=350.0, 150 | help="Max equivalent width for the whole line incl. blends (default: 350)", 151 | ) 152 | 153 | args = parser.parse_args() 154 | 155 | fallback_folder_path = "PATH_TO_YOUR_OUTPUT_FOLDER" # ← change just this 156 | 157 | main( 158 | folder_path=args.folder_path or fallback_folder_path, 159 | remove_errors=args.remove_errors, 160 | remove_warnings=args.remove_warnings, 161 | chisqr_limit=args.chisqr_limit, 162 | ew_limits=tuple(args.ew_limits), 163 | ew_limit_total=args.ew_limit_total, 164 | ) -------------------------------------------------------------------------------- /plotting_tools/analyse_the_output_new_flags.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | import sys, os 3 | 4 | sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..', ))) 5 | 6 | import numpy as np 7 | import pandas as pd 8 | import matplotlib 9 | import matplotlib.pyplot as plt 10 | from plotting_tools.scripts_for_plotting import load_output_data 11 | import argparse 12 | from pathlib import Path 13 | 14 | 15 | # Created by storm at 06.11.24 16 | 17 | def get_average_abundance(output_folder_location, remove_errors, remove_warnings, chisqr_limit, ew_limits, ew_limit_total): 18 | config_dict = load_output_data(output_folder_location) 19 | output_file_df = config_dict["output_file_df"] 20 | fitted_element = config_dict["fitted_element"] 21 | if fitted_element != "Fe": 22 | fitted_element = f"{fitted_element}_Fe" 23 | x_value_plot = "Fe_H" 24 | else: 25 | fitted_element = "Fe_H" 26 | x_value_plot = "wave_center" 27 | 28 | new_flags_df = pd.read_csv(f"{output_folder_location}/new_flags.csv") 29 | 30 | if remove_errors: 31 | output_file_df = output_file_df[output_file_df['flag_error'] == 0] 32 | if remove_warnings: 33 | output_file_df = output_file_df[output_file_df['flag_warning'] == 0] 34 | output_file_df = output_file_df[output_file_df['chi_squared'] <= chisqr_limit] 35 | output_file_df = output_file_df[output_file_df['ew_just_line'] >= ew_limits[0]] 36 | output_file_df = output_file_df[output_file_df['ew_just_line'] <= ew_limits[1]] 37 | output_file_df = output_file_df[output_file_df['ew'] <= ew_limit_total] 38 | 39 | # remove any rows that have a flag == 1 40 | # specname,linemask,extra_error columns 41 | for index, row in new_flags_df.iterrows(): 42 | specname = row["specname"] 43 | linemask = row["linemask"] 44 | extra_error = row["extra_error"] 45 | # find the row in the output_file_df 46 | indices = np.where((output_file_df['specname'] == specname) & (output_file_df['wave_center'] == linemask))[0] 47 | if extra_error == 1: 48 | print(f"Removing {specname} {linemask} {output_file_df['specname'][indices].values} {output_file_df['wave_center'][indices].values}") 49 | output_file_df = output_file_df.drop(indices) 50 | output_file_df.reset_index(drop=True, inplace=True) 51 | 52 | output_df = pd.DataFrame() 53 | # new columns: specname, x_value, y_value 54 | output_df["specname"] = [] 55 | output_df[x_value_plot] = [] 56 | output_df[fitted_element] = [] 57 | output_df[f"{fitted_element}_err"] = [] 58 | output_df["vmac"] = [] 59 | output_df["vmac_err"] = [] 60 | output_df["vsini"] = [] 61 | output_df["vsini_err"] = [] 62 | output_df["ew_line"] = [] 63 | 64 | # get the data from the fitted spectra 65 | specnames = np.unique(output_file_df['specname'].values) 66 | 67 | for specname in specnames: 68 | # find all rows with the same specname 69 | indices = np.where(output_file_df['specname'] == specname)[0] 70 | 71 | if np.size(indices) > 0: 72 | # new row in the dataframe 73 | output_df.loc[len(output_df)] = [specname, np.mean(output_file_df[x_value_plot][indices]), 74 | np.mean(output_file_df[fitted_element][indices]), 75 | np.std(output_file_df[fitted_element][indices]), 76 | np.mean(output_file_df["Macroturb"][indices]), 77 | np.std(output_file_df["Macroturb"][indices]), 78 | np.mean(output_file_df["rotation"][indices]), 79 | np.std(output_file_df["rotation"][indices]), 80 | np.mean(output_file_df["ew_just_line"][indices])] 81 | print(f"specname: {specname}, x_value: {np.mean(output_file_df[x_value_plot][indices])}, y_value: {np.mean(output_file_df[fitted_element][indices])}") 82 | 83 | return output_df 84 | 85 | 86 | def main( 87 | folder_path: str, 88 | *, 89 | remove_errors: bool = True, 90 | remove_warnings: bool = False, 91 | chisqr_limit: float = 50.0, 92 | ew_limits: tuple[float, float] = (1, 400), 93 | ew_limit_total: float = 550.0 94 | ): 95 | """Run TSFitPy post-processing and write average_abundance.csv.""" 96 | output_df = get_average_abundance( 97 | folder_path, 98 | remove_errors=remove_errors, 99 | remove_warnings=remove_warnings, 100 | chisqr_limit=chisqr_limit, 101 | ew_limits=ew_limits, 102 | ew_limit_total=ew_limit_total, 103 | ) 104 | print(output_df) 105 | output_df.to_csv(Path(folder_path) / "average_abundance.csv", index=False) 106 | 107 | 108 | # ---------------------------------------------------------------------- 109 | # 2. Command-line interface (all *optional*, with sensible defaults) 110 | # ---------------------------------------------------------------------- 111 | if __name__ == "__main__": 112 | # should be used together with flags from TSGuiPy. Put "new_flags.csv" in the output folder and it will remove everything that has a flag == 1 AND other limits. 113 | # So if you onl want to use the flags, set remove_errors and remove_warnings to False, and set chisqr_limit, ew_limits and ew_limit_total to very high values. 114 | 115 | # remove_errors - if True, remove all rows with flag_error != 0 116 | # remove_warnings - if True, remove all rows with flag_warning != 0 117 | # chisqr_limit - maximum chi_squared value to keep (set higher for bigger linemasks, e.g. molecular bands) 118 | # ew_limits - tuple with minimum and maximum equivalent width to keep for the actual line 119 | # ew_limit_total - maximum equivalent width to keep for the whole line (including blends) 120 | 121 | parser = argparse.ArgumentParser( 122 | description="Analyse the output of the TSFitPy fitting process." 123 | ) 124 | 125 | parser.add_argument( 126 | "folder_path", 127 | nargs="?", 128 | default=None, 129 | help="Path to the output folder containing the fitting results." 130 | " If omitted, the hard-coded fallback value is used.", 131 | ) 132 | 133 | parser.add_argument( 134 | "--remove-errors", 135 | dest="remove_errors", 136 | action=argparse.BooleanOptionalAction, 137 | default=True, 138 | help="Remove rows with flag_error != 0 (default: True)", 139 | ) 140 | parser.add_argument( 141 | "--remove-warnings", 142 | dest="remove_warnings", 143 | action=argparse.BooleanOptionalAction, 144 | default=False, 145 | help="Remove rows with flag_warning != 0 (default: True)", 146 | ) 147 | 148 | parser.add_argument( 149 | "--chisqr-limit", 150 | type=float, 151 | default=50.0, 152 | help="Maximum chi_squared value to keep (default: 5.0)", 153 | ) 154 | parser.add_argument( 155 | "--ew-limits", 156 | type=float, 157 | nargs=2, 158 | metavar=("MIN", "MAX"), 159 | default=(1, 400), 160 | help="Min and max equivalent width for the line (default: 1 200)", 161 | ) 162 | parser.add_argument( 163 | "--ew-limit-total", 164 | type=float, 165 | default=550.0, 166 | help="Max equivalent width for the whole line incl. blends (default: 350)", 167 | ) 168 | 169 | args = parser.parse_args() 170 | 171 | fallback_folder_path = "PATH_TO_YOUR_OUTPUT_FOLDER" # ← change just this 172 | 173 | main( 174 | folder_path=args.folder_path or fallback_folder_path, 175 | remove_errors=args.remove_errors, 176 | remove_warnings=args.remove_warnings, 177 | chisqr_limit=args.chisqr_limit, 178 | ew_limits=tuple(args.ew_limits), 179 | ew_limit_total=args.ew_limit_total, 180 | ) 181 | 182 | -------------------------------------------------------------------------------- /utilities/download_nlte_grids.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | Download NLTE grid binaries, auxiliary data and model atoms listed in 4 | `nlte_grids_links.cfg`. 5 | 6 | Usage 7 | ----- 8 | python3 download_nlte_grids.py 9 | 10 | Examples 11 | -------- 12 | # Download 1D **and** 3D grids for Al, Ba, Ca into ./grids/ 13 | python3 download_nlte_grids.py ./grids 1D,3D Al Ba Ca 14 | 15 | # Download only 1D grids for Fe & Mg (case‑insensitive, commas or spaces) 16 | python3 download_nlte_grids.py ./grids 1d Fe,Mg 17 | 18 | Accepted values for *grid_types*: 19 | • 1D – download 1‑D grid files (…1d_bin & …1d_aux) 20 | • 3D – download 3‑D grid files (…3d_bin & …3d_aux) 21 | • 1D,3D – download both (comma separated list, order doesn’t matter) 22 | • all – synonym for 1D,3D 23 | 24 | Accepted values for *elements*: 25 | • Element symbols (case‑insensitive, e.g. Fe, Mg, Al) 26 | • "All" to download all elements listed in the config file 27 | """ 28 | from __future__ import annotations 29 | 30 | import argparse 31 | import configparser 32 | import os 33 | import sys 34 | import textwrap 35 | from typing import Iterable, List, Set, Tuple 36 | import datetime 37 | 38 | import requests 39 | from zipfile import ZipFile 40 | 41 | # Created by storm at 20.06.25 42 | 43 | # ----------------------------------------------------------------------------- 44 | # Argument parsing helpers 45 | # ----------------------------------------------------------------------------- 46 | def _parse_args() -> argparse.Namespace: 47 | parser = argparse.ArgumentParser( 48 | formatter_class=argparse.RawDescriptionHelpFormatter, 49 | description=textwrap.dedent(__doc__), 50 | ) 51 | parser.add_argument( 52 | "output_dir", help="Directory where downloaded files will be stored." 53 | ) 54 | parser.add_argument( 55 | "grid_types", 56 | help="Grid types to fetch: 1D, 3D, 1D,3D or all (case‑insensitive)", 57 | ) 58 | parser.add_argument( 59 | "elements", 60 | nargs="+", 61 | help="Element symbols (case‑insensitive, space or comma separated)", 62 | ) 63 | return parser.parse_args() 64 | 65 | 66 | def _normalise_grid_types(raw: str) -> Set[str]: 67 | raw = raw.strip().lower() 68 | if raw == "all": 69 | return {"1d", "3d"} 70 | parts = {p.strip() for p in raw.split(",") if p.strip()} 71 | valid = {"1d", "3d"} 72 | if not parts.issubset(valid): 73 | raise ValueError( 74 | f"Invalid grid_types '{raw}'. Allowed values: 1D, 3D, 1D,3D, all." 75 | ) 76 | return parts 77 | 78 | 79 | def _normalise_elements(tokens: List[str]) -> List[str]: 80 | # Accept either commas or spaces between element symbols. 81 | joined = " ".join(tokens) 82 | elems: List[str] = [tok.capitalize() for tok in joined.replace(",", " ").split() if tok] 83 | return elems 84 | 85 | 86 | # ----------------------------------------------------------------------------- 87 | # Download helpers 88 | # ----------------------------------------------------------------------------- 89 | 90 | def _download_file(url: str, dest_path: str) -> Tuple[bool, bool]: 91 | """Download *url* to *dest_path* (skip if already present). 92 | 93 | Returns True on success, False if an exception occurs. 94 | Returns second True if skipped because the file already exists. 95 | """ 96 | if os.path.exists(dest_path): 97 | print(f" ✔ Exists, skipping: {os.path.basename(dest_path)}") 98 | return True, True 99 | 100 | if os.path.exists(dest_path.replace(".zip", "")): 101 | print(f" ✔ Unzipped exists, skipping: {os.path.basename(dest_path)}") 102 | return True, True 103 | 104 | try: 105 | with requests.get(url, stream=True, timeout=60) as r: 106 | r.raise_for_status() 107 | os.makedirs(os.path.dirname(dest_path), exist_ok=True) 108 | with open(dest_path, "wb") as fh: 109 | for chunk in r.iter_content(chunk_size=8192): 110 | fh.write(chunk) 111 | return True, False # Downloaded successfully, not skipped 112 | except Exception as exc: 113 | print(f" ✖ Failed: {exc}") 114 | return False, False 115 | 116 | 117 | def _maybe_unzip(path: str, *, delete_zip: bool = True) -> bool: 118 | """Unzip *path* if it ends with .zip. Returns True on success.""" 119 | if not path.lower().endswith(".zip"): 120 | return True # nothing to do 121 | 122 | try: 123 | with ZipFile(path) as zf: 124 | zf.extractall(os.path.dirname(path)) 125 | if delete_zip: 126 | os.remove(path) 127 | print(f" ✔ Unpacked & removed ZIP: {os.path.basename(path)}") 128 | return True 129 | except Exception as exc: 130 | print(f" ✖ Unzip failed: {exc}") 131 | return False 132 | 133 | 134 | # ----------------------------------------------------------------------------- 135 | # Main logic 136 | # ----------------------------------------------------------------------------- 137 | 138 | def _build_task_list(cfg: configparser.ConfigParser, elements: Iterable[str], grids: Set[str]) -> List[Tuple[str, str, str, str]]: 139 | """Return a list of (element, tag, url, filename) tuples to download.""" 140 | tasks: List[Tuple[str, str, str, str]] = [] 141 | # get all elements from the config 142 | all_elements = set(cfg.sections()) 143 | if elements == ["All"]: 144 | elements = all_elements 145 | for elem in elements: 146 | if elem not in cfg: 147 | print(f"! Warning: '{elem}' not found in cfg; skipping.") 148 | continue 149 | sec = cfg[elem] 150 | tasks.append((elem, "model_atom", sec.get("model_atom_link"), sec.get("model_atom_name"))) 151 | if "1d" in grids: 152 | tasks.append((elem, "1d_bin", sec.get("1d_bin_link"), sec.get("1d_bin_name"))) 153 | tasks.append((elem, "1d_aux", sec.get("1d_aux_link"), sec.get("1d_aux_name"))) 154 | if "3d" in grids: 155 | tasks.append((elem, "3d_bin", sec.get("3d_bin_link"), sec.get("3d_bin_name"))) 156 | tasks.append((elem, "3d_aux", sec.get("3d_aux_link"), sec.get("3d_aux_name"))) 157 | # Filter out any (url or filename) missing 158 | filtered = [t for t in tasks if t[2] and t[3]] 159 | return filtered 160 | 161 | 162 | def main() -> None: 163 | args = _parse_args() 164 | 165 | out_dir = os.path.abspath(args.output_dir) 166 | grid_types = _normalise_grid_types(args.grid_types) 167 | 168 | if args.elements == ["All"]: 169 | print("WARNING: Downloading all elements takes a lot of space: ~600 GB.") 170 | 171 | elements = _normalise_elements(args.elements) 172 | 173 | cfg_file = os.path.join(os.path.dirname(__file__), "nlte_grids_links.cfg") 174 | if not os.path.isfile(cfg_file): 175 | sys.exit(f"Configuration file not found: {cfg_file}") 176 | 177 | cfg = configparser.ConfigParser(interpolation=None) 178 | cfg.read(cfg_file) 179 | 180 | tasks = _build_task_list(cfg, elements, grid_types) 181 | total = len(tasks) 182 | done = 0 183 | errors: List[str] = [] 184 | 185 | print("Starting downloads…\n") 186 | for idx, (elem, tag, url, fname) in enumerate(tasks, start=1): 187 | dest = os.path.join(out_dir, elem, fname) 188 | print(f"[{idx:>3}/{total}] {elem:2s} {tag:<8s} → {fname}") 189 | ok, skipped = _download_file(url, dest) 190 | if ok and not skipped: 191 | ok = _maybe_unzip(dest) 192 | if ok: 193 | done += 1 194 | else: 195 | errors.append(f"{elem} {tag}") 196 | 197 | print("\nFinished:") 198 | print(f" Downloaded {done}/{total} files successfully.") 199 | if errors: 200 | print(f" Errors ({len(errors)}): {', '.join(errors)}") 201 | else: 202 | print(" No errors encountered. 🎉") 203 | 204 | 205 | if __name__ == "__main__": 206 | print(f"NLTE grid downloader script, {datetime.datetime.now().isoformat()}") 207 | main() 208 | print(f"Done at {datetime.datetime.now().isoformat()}") 209 | -------------------------------------------------------------------------------- /plotting_tools/plot_output.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": { 7 | "collapsed": true 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "from __future__ import annotations\n", 12 | "try:\n", 13 | " from scripts_for_plotting import *\n", 14 | "except ModuleNotFoundError:\n", 15 | " import sys\n", 16 | " sys.path.append('../')\n", 17 | " from scripts_for_plotting import *" 18 | ] 19 | }, 20 | { 21 | "cell_type": "code", 22 | "execution_count": null, 23 | "outputs": [], 24 | "source": [ 25 | "# CHANGE NEXT LINE\n", 26 | "output_folder_location: str = \"../output_files/OUTPUTCHANGEHERE/\" # CHANGE\n", 27 | "# loads all data from config file and output, config is copied into output folder with name \"configuration.txt\" from now on\n", 28 | "config_dict = load_output_data(output_folder_location)" 29 | ], 30 | "metadata": { 31 | "collapsed": false 32 | } 33 | }, 34 | { 35 | "cell_type": "code", 36 | "execution_count": null, 37 | "outputs": [], 38 | "source": [ 39 | "output_results_pd_df = config_dict[\"output_file_df\"] # Pandas dataframe for your own use\n", 40 | "print(\"Column names are:\")\n", 41 | "print(output_results_pd_df.columns.values) # Column names if you want to plot them\n", 42 | "output_results_pd_df" 43 | ], 44 | "metadata": { 45 | "collapsed": false 46 | } 47 | }, 48 | { 49 | "cell_type": "code", 50 | "execution_count": null, 51 | "outputs": [], 52 | "source": [ 53 | "# can plot your own results using column names from the data frame\n", 54 | "# can also take any extra arguments just like plt.scatter, example with color='black' is shown below\n", 55 | "# can also add e.g. xlim=(-5, 5) or ylim=(-1, 1) for x and y limits\n", 56 | "# CHANGE COLUMN NAMES IF NEEDED\n", 57 | "plot_scatter_df_results(output_results_pd_df, \"Fe_H\", \"chi_squared\", color='black')\n", 58 | "# works in similar way, but plots the density map with the desired cmap\n", 59 | "# s=10 stands for point size\n", 60 | "plot_density_df_results(output_results_pd_df, \"Fe_H\", \"chi_squared\", s=10, cmap=\"plasma_r\", alpha=0.5)\n", 61 | "# also histogram if needed as well\n", 62 | "plot_histogram_df_results(output_results_pd_df, \"Fe_H\", color='grey', bins=20, alpha=0.5, histtype='bar', ec='black')" 63 | ], 64 | "metadata": { 65 | "collapsed": false 66 | } 67 | }, 68 | { 69 | "cell_type": "code", 70 | "execution_count": null, 71 | "outputs": [], 72 | "source": [ 73 | "# CHANGE NEXT LINE\n", 74 | "star_name_to_plot: str = \"CHANGE_NAME_OF_STAR_TO_PLOT_HERE\" # CHANGE\n", 75 | "# plots all fitted lines for the requested star\n", 76 | "plot_one_star(config_dict, star_name_to_plot, plot_title=True)" 77 | ], 78 | "metadata": { 79 | "collapsed": false 80 | } 81 | }, 82 | { 83 | "cell_type": "code", 84 | "execution_count": null, 85 | "outputs": [], 86 | "source": [ 87 | "# can also plot all stars and all lines as well\n", 88 | "for specname in set(output_results_pd_df[\"specname\"].values):\n", 89 | " print(specname)\n", 90 | " plot_one_star(config_dict, specname, plot_title=True)" 91 | ], 92 | "metadata": { 93 | "collapsed": false 94 | } 95 | }, 96 | { 97 | "cell_type": "code", 98 | "execution_count": null, 99 | "outputs": [], 100 | "source": [ 101 | "turbospectrum_paths = {\"turbospec_path\": \"../turbospectrum/exec/\", # change to /exec-gf/ if gnu compiler\n", 102 | " \"interpol_path\": \"../scripts/model_interpolators/\",\n", 103 | " \"model_atom_path\": \"../input_files/nlte_data/model_atoms/\",\n", 104 | " \"departure_file_path\": \"../input_files/nlte_data/\",\n", 105 | " \"model_atmosphere_grid_path\": \"../input_files/model_atmospheres/\",\n", 106 | " \"line_list_path\": \"../input_files/linelists/linelist_for_fitting/\"}\n", 107 | "\n", 108 | "teff = 5777\n", 109 | "logg = 4.4\n", 110 | "met = 0.0\n", 111 | "vmic = 1.0\n", 112 | "lmin = 6560\n", 113 | "lmax = 6565\n", 114 | "ldelta = 0.01\n", 115 | "atmosphere_type = \"1D\" # \"1D\" or \"3D\"\n", 116 | "nlte_flag = False\n", 117 | "elements_in_nlte = [\"Fe\", \"Mg\"] # can choose several elements, used ONLY if nlte_flag = True\n", 118 | "element_abundances = {\"Mg\": 0.0, \"O\": 0.0} # elemental abundances [X/Fe]; if not written solar scaled ones are used\n", 119 | "include_molecules = False # way faster without them\n", 120 | "\n", 121 | "# plots the data, but can also save it for later use\n", 122 | "wavelength, flux = plot_synthetic_data(turbospectrum_paths, teff, logg, met, vmic, lmin, lmax, ldelta, atmosphere_type, nlte_flag, elements_in_nlte, element_abundances, include_molecules, resolution=0, macro=0, rotation=0, verbose=False)" 123 | ], 124 | "metadata": { 125 | "collapsed": false 126 | } 127 | }, 128 | { 129 | "cell_type": "code", 130 | "execution_count": null, 131 | "outputs": [], 132 | "source": [ 133 | "# if using m3dis\n", 134 | "\n", 135 | "m3dis_paths = {\"m3dis_path\": \"../m3dis/experiments/Multi3D/\", \n", 136 | " \"nlte_config_path\": \"../input_files/nlte_data/nlte_filenames.cfg\",\n", 137 | " \"model_atom_path\": \"../input_files/nlte_data/model_atoms/\",\n", 138 | " \"model_atmosphere_grid_path\": \"../input_files/model_atmospheres/\",\n", 139 | " \"line_list_path\": \"../input_files/linelists/linelist_for_fitting/\",\n", 140 | " \"3D_atmosphere_path\": None} # change to path to 3D atmosphere if running 3D model atmosphere\n", 141 | "\n", 142 | "teff = 5777\n", 143 | "logg = 4.4\n", 144 | "met = 0.0\n", 145 | "vmic = 1.0\n", 146 | "lmin = 4883\n", 147 | "lmax = 4884\n", 148 | "ldelta = 0.01\n", 149 | "element_abundances = {\"Mg\": 0.0, \"O\": 0.0} # elemental abundances [X/Fe]; if not written solar scaled ones are used\n", 150 | "atmosphere_type = \"1D\" # \"1D\" or \"3D\"\n", 151 | "hash_table_size = 100\n", 152 | "n_nu = 1\n", 153 | "mpi_cores = 1\n", 154 | "# if 3D atmosphere is used, then the following is needed\n", 155 | "dims = 23 # dimensions of the atmosphere\n", 156 | "atmos_format = 'Multi' # MUST, Stagger or Multi\n", 157 | "nx = 10 # only if Stagger\n", 158 | "ny = 10 # only if Stagger\n", 159 | "nz = 230 # only if Stagger\n", 160 | "snap = 1 # snapshot number, only if Stagger\n", 161 | "# nlte settings\n", 162 | "nlte_flag = False\n", 163 | "# nlte settings, if nlte_flag = False, these are not used\n", 164 | "nlte_iterations_max = 10\n", 165 | "nlte_convergence_limit = 0.001\n", 166 | "element_in_nlte = \"Fe\" # can choose only one element\n", 167 | "\n", 168 | "# plots the data, but can also save it for later use\n", 169 | "wavelength_m3dis, flux_m3dis = plot_synthetic_data_m3dis(m3dis_paths, teff, logg, met, vmic, lmin, lmax, ldelta, atmosphere_type, atmos_format, n_nu, mpi_cores, hash_table_size, nlte_flag, element_in_nlte, element_abundances, snap, dims, nx, ny, nz, nlte_iterations_max, nlte_convergence_limit, resolution=0, macro=0, rotation=0, verbose=False)" 170 | ], 171 | "metadata": { 172 | "collapsed": false 173 | } 174 | }, 175 | { 176 | "cell_type": "code", 177 | "outputs": [], 178 | "source": [], 179 | "metadata": { 180 | "collapsed": false 181 | } 182 | } 183 | ], 184 | "metadata": { 185 | "kernelspec": { 186 | "display_name": "Python 3", 187 | "language": "python", 188 | "name": "python3" 189 | }, 190 | "language_info": { 191 | "codemirror_mode": { 192 | "name": "ipython", 193 | "version": 2 194 | }, 195 | "file_extension": ".py", 196 | "mimetype": "text/x-python", 197 | "name": "python", 198 | "nbconvert_exporter": "python", 199 | "pygments_lexer": "ipython2", 200 | "version": "2.7.6" 201 | } 202 | }, 203 | "nbformat": 4, 204 | "nbformat_minor": 0 205 | } 206 | -------------------------------------------------------------------------------- /scripts/auxiliary_functions.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import os 4 | import types 5 | 6 | import numpy as np 7 | from scipy import integrate 8 | from scipy.interpolate import interp1d 9 | import importlib.util 10 | import sys 11 | 12 | 13 | def create_dir(directory: str): 14 | """ 15 | Creates a directory if it does not exist 16 | :param directory: Path to the directory that can be created (relative or not) 17 | """ 18 | if not os.path.exists(directory): 19 | try: 20 | os.mkdir(directory) 21 | except FileNotFoundError: # if one needs to create folders in-between 22 | os.makedirs(directory) # can't recall why I just don't call this function directly 23 | 24 | 25 | def calculate_vturb(teff: float, logg: float, met: float) -> float: 26 | """ 27 | Calculates micro turbulence based on the input parameters 28 | :param teff: Temperature in kelvin 29 | :param logg: log(g) in dex units 30 | :param met: metallicity [Fe/H] scaled by solar 31 | :return: micro turbulence in km/s 32 | """ 33 | t0 = 5500. 34 | g0 = 4. 35 | tlim = 5000. 36 | glim = 3.5 37 | 38 | delta_logg = logg - g0 39 | 40 | if logg >= glim: 41 | # dwarfs 42 | if teff >= tlim: 43 | # hot dwarfs 44 | delta_t = teff - t0 45 | else: 46 | # cool dwarfs 47 | delta_t = tlim - t0 48 | 49 | v_mturb = (1.05 + 2.51e-4 * delta_t + 1.5e-7 * delta_t**2 - 0.14 * delta_logg - 0.005 * delta_logg**2 + 50 | 0.05 * met + 0.01 * met**2) 51 | 52 | elif logg < glim: 53 | # giants 54 | delta_t = teff - t0 55 | 56 | v_mturb = (1.25 + 4.01e-4 * delta_t + 3.1e-7 * delta_t**2 - 0.14 * delta_logg - 0.005 * delta_logg**2 + 57 | 0.05 * met + 0.01 * met**2) 58 | 59 | return v_mturb 60 | 61 | 62 | def calculate_equivalent_width(wavelength: np.ndarray, normalised_flux: np.ndarray, left_bound: float, right_bound: float) -> float: 63 | """ 64 | Calculates the equivalent width of a line based on the input parameters 65 | :param wavelength: Wavelength array 66 | :param normalised_flux: Normalised flux array 67 | :param left_bound: Left bound of the line 68 | :param right_bound: Right bound of the line 69 | :return: Equivalent width of the line 70 | """ 71 | # first cut wavelength and flux to the bounds 72 | try: 73 | normalised_flux = normalised_flux[np.logical_and(wavelength >= left_bound, wavelength <= right_bound)] 74 | wavelength = wavelength[np.logical_and(wavelength >= left_bound, wavelength <= right_bound)] 75 | except TypeError: 76 | return -9999 77 | line_func = interp1d(wavelength, normalised_flux, kind='linear', assume_sorted=True, fill_value=1, bounds_error=False) 78 | total_area = (right_bound - left_bound) * 1.0 # continuum 79 | try: 80 | integration_points = wavelength[np.logical_and.reduce((wavelength > left_bound, wavelength < right_bound))] 81 | area_under_line = integrate.quad(line_func, left_bound, right_bound, points=integration_points, limit=len(integration_points) * 5) 82 | except ValueError: 83 | return -9999 84 | 85 | return total_area - area_under_line[0] 86 | 87 | 88 | def get_second_degree_polynomial(x: list, y: list) -> tuple[int, int, int]: 89 | """ 90 | Takes a list of x and y of length 3 each and calculates perfectly fitted second degree polynomial through it. 91 | Returns a, b, c that are related to the function ax^2+bx+c = y 92 | :param x: x values, length 3 93 | :param y: y values, length 3 94 | :return a,b,c -> ax^2+bx+c = y 2nd degree polynomial 95 | """ 96 | x1 = x[0] 97 | x2 = x[1] 98 | x3 = x[2] 99 | y1 = y[0] 100 | y2 = y[1] 101 | y3 = y[2] 102 | 103 | a = (x1 * (y3 - y2) + x2 * (y1 - y3) + x3 * (y2 - y1)) / ((x1 - x2) * (x1 - x3) * (x2 - x3)) 104 | b = (y2 - y1) / (x2 - x1) - a * (x1 + x2) 105 | c = y1 - a * x1 * x1 - b * x2 106 | 107 | return a, b, c 108 | 109 | 110 | def apply_doppler_correction(wave_ob: np.ndarray, doppler: float) -> np.ndarray: 111 | return wave_ob / (1 + (doppler / 299792.)) 112 | 113 | 114 | def create_segment_file(segment_size: float, line_begins_list: np.ndarray[float], line_ends_list: np.ndarray[float]) -> tuple[np.ndarray[float], np.ndarray[float]]: 115 | segments_left = [] 116 | segments_right = [] 117 | start: float = line_begins_list[0] - segment_size 118 | end: float = line_ends_list[0] + segment_size 119 | 120 | for (line_left, line_right) in zip(line_begins_list, line_ends_list): 121 | if line_left > end + segment_size: 122 | segments_left.append(start) 123 | segments_right.append(end) 124 | start = line_left - segment_size 125 | end = line_right + segment_size 126 | else: 127 | end = line_right + segment_size 128 | 129 | segments_left.append(start) 130 | segments_right.append(end) 131 | 132 | return np.asarray(segments_left), np.asarray(segments_right) 133 | 134 | 135 | def closest_available_value(target: float, options: list[float]) -> float: 136 | """ 137 | Return the option from a list which most closely matches some target value. 138 | 139 | :param target: 140 | The target value that we're trying to match. 141 | :param options: 142 | The list of possible values that we can try to match to target. 143 | :return: 144 | The option value which is closest to . 145 | """ 146 | options = np.asarray(options) 147 | idx = (np.abs(options - target)).argmin() 148 | return options[idx] 149 | 150 | def import_module_from_path(module_name, file_path): 151 | """ 152 | Imports a module by temporarily adding its parent directory to sys.path. 153 | 154 | Parameters: 155 | module_name (str): The full dotted module name (e.g., 'm3dis.m3dis'). 156 | file_path (str): The file path to the module. 157 | 158 | Returns: 159 | module: The imported module. 160 | """ 161 | # Determine the directory containing the module 162 | module_dir = os.path.dirname(file_path) 163 | 164 | # Calculate how many levels up we need to go to get the package root 165 | levels_up = module_name.count('.') 166 | 167 | # Get the package root directory 168 | package_root = module_dir 169 | for _ in range(levels_up): 170 | package_root = os.path.dirname(package_root) 171 | 172 | # Add the package root to sys.path temporarily 173 | sys.path.insert(0, package_root) 174 | try: 175 | module = importlib.import_module(module_name) 176 | finally: 177 | # Remove the package root from sys.path 178 | sys.path.pop(0) 179 | return module 180 | 181 | 182 | def combine_linelists(line_list_path_trimmed: str, combined_linelist_name: str = "combined_linelist.bsyn", return_parsed_linelist: bool = False, save_combined_linelist: bool = True): 183 | parsed_linelist_data = [] 184 | for folder in os.listdir(line_list_path_trimmed): 185 | if os.path.isdir(os.path.join(line_list_path_trimmed, folder)): 186 | # go into each folder and combine all linelists into one 187 | combined_linelist = os.path.join(line_list_path_trimmed, folder, combined_linelist_name) 188 | if save_combined_linelist: 189 | with open(combined_linelist, "w") as combined_linelist_file: 190 | for file in os.listdir(os.path.join(line_list_path_trimmed, folder)): 191 | if file.endswith(".bsyn") and not file == combined_linelist_name: 192 | with open(os.path.join(line_list_path_trimmed, folder, file), "r") as linelist_file: 193 | read_file = linelist_file.read() 194 | combined_linelist_file.write(read_file) 195 | if return_parsed_linelist: 196 | parsed_linelist_data.append(read_file) 197 | # delete the file 198 | os.remove(os.path.join(line_list_path_trimmed, folder, file)) 199 | else: 200 | for file in os.listdir(os.path.join(line_list_path_trimmed, folder)): 201 | if file.endswith(".bsyn") and not file == combined_linelist_name: 202 | with open(os.path.join(line_list_path_trimmed, folder, file), "r") as linelist_file: 203 | try: 204 | first_line: str = linelist_file.readline() 205 | fields = first_line.strip().split() 206 | sep = '.' 207 | element = fields[0] + fields[1] 208 | elements = element.split(sep, 1)[0] 209 | if len(elements) <= 3: 210 | with open(os.path.join(line_list_path_trimmed, folder, file), "r") as linelist_file: 211 | read_file = linelist_file.read() 212 | # opens each file, reads first row, if it is long enough then it is molecule. If fitting molecules, then 213 | # keep it, otherwise ignore molecules 214 | if return_parsed_linelist: 215 | parsed_linelist_data.append(read_file) 216 | except UnicodeDecodeError: 217 | print(f"LINELIST WARNING! File {linelist_file} is not a valid linelist file") 218 | continue 219 | if return_parsed_linelist: 220 | return parsed_linelist_data 221 | -------------------------------------------------------------------------------- /input_files/linelists/linelist_vald/Hlinedata: -------------------------------------------------------------------------------- 1 | '01.000000 ' 1 133 2 | 'H I lambda(AA) nblo nbup elo(eV) eup(eV) loggf ident raddamp/from BE 20/11-96' 3 | 920.963 1 10 0.000 13.462 -2.493 'Ly 10 ' 6.31E+08 4 | 923.150 1 9 0.000 13.430 -2.353 'Ly 9 ' 6.31E+08 5 | 926.226 1 8 0.000 13.386 -2.196 'Ly 8 ' 6.31E+08 6 | 930.748 1 7 0.000 13.321 -2.016 'Ly 7 ' 6.24E+08 7 | 937.803 1 6 0.000 13.220 -1.807 'Lyepsilon' 6.21E+08 8 | 949.743 1 5 0.000 13.054 -1.555 'Lydelta ' 6.17E+08 9 | 972.537 1 4 0.000 12.748 -1.237 'Lygamma ' 6.04E+08 10 | 1025.722 1 3 0.000 12.087 -0.801 'Lybeta ' 5.70E+08 11 | 1215.671 1 2 0.000 10.199 -0.080 'Lyalpha ' 4.70E+08 12 | 3666.095 2 27 10.199 13.581 -2.850 'H 27 ' 6.31E+08 13 | 3667.682 2 26 10.199 13.579 -2.801 'H 26 ' 6.31E+08 14 | 3669.464 2 25 10.199 13.578 -2.749 'H 25 ' 6.31E+08 15 | 3671.476 2 24 10.199 13.576 -2.695 'H 24 ' 6.31E+08 16 | 3673.759 2 23 10.199 13.574 -2.639 'H 23 ' 6.31E+08 17 | 3676.363 2 22 10.199 13.571 -2.580 'H 22 ' 6.31E+08 18 | 3679.353 2 21 10.199 13.569 -2.518 'H 21 ' 6.31E+08 19 | 3682.808 2 20 10.199 13.565 -2.453 'H 20 ' 6.31E+08 20 | 3686.831 2 19 10.199 13.562 -2.385 'H 19 ' 6.31E+08 21 | 3691.555 2 18 10.199 13.558 -2.313 'H 18 ' 6.31E+08 22 | 3697.152 2 17 10.199 13.552 -2.237 'H 17 ' 6.31E+08 23 | 3703.853 2 16 10.199 13.546 -2.155 'H 16 ' 6.31E+08 24 | 3711.971 2 15 10.199 13.539 -2.068 'H 15 ' 6.31E+08 25 | 3721.939 2 14 10.199 13.530 -1.975 'H 14 ' 6.31E+08 26 | 3734.368 2 13 10.199 13.519 -1.874 'H 13 ' 6.31E+08 27 | 3750.152 2 12 10.199 13.505 -1.764 'H 12 ' 6.31E+08 28 | 3770.630 2 11 10.199 13.487 -1.644 'H 11 ' 6.31E+08 29 | 3797.898 2 10 10.199 13.463 -1.511 'H 10 ' 6.31E+08 30 | 3835.384 2 9 10.199 13.432 -1.362 'H 9 ' 6.31E+08 31 | 3889.048 2 8 10.199 13.387 -1.192 'H 8 ' 6.31E+08 32 | 3970.072 2 7 10.199 13.322 -0.993 'Hepsilon ' 6.24E+08 33 | 4101.734 2 6 10.199 13.222 -0.753 'Hdelta ' 6.21E+08 34 | 4340.462 2 5 10.199 13.055 -0.447 'Hgamma ' 6.17E+08 35 | 4861.323 2 4 10.199 12.749 -0.020 'Hbeta ' 6.04E+08 36 | 6562.797 2 3 10.199 12.088 0.710 'Halpha ' 5.70E+08 37 | 8298.839 3 28 12.088 13.582 -2.348 'Pa 28 ' 6.31E+08 38 | 8306.116 3 27 12.088 13.581 -2.299 'Pa 27 ' 6.31E+08 39 | 8314.265 3 26 12.088 13.579 -2.249 'Pa 26 ' 6.31E+08 40 | 8323.429 3 25 12.088 13.578 -2.196 'Pa 25 ' 6.31E+08 41 | 8333.787 3 24 12.088 13.576 -2.141 'Pa 24 ' 6.31E+08 42 | 8345.557 3 23 12.088 13.574 -2.084 'Pa 23 ' 6.31E+08 43 | 8359.008 3 22 12.088 13.571 -2.024 'Pa 22 ' 6.31E+08 44 | 8374.479 3 21 12.088 13.568 -1.961 'Pa 21 ' 6.31E+08 45 | 8392.401 3 20 12.088 13.565 -1.895 'Pa 20 ' 6.31E+08 46 | 8413.322 3 19 12.088 13.562 -1.824 'Pa 19 ' 6.31E+08 47 | 8437.959 3 18 12.088 13.557 -1.750 'Pa 18 ' 6.31E+08 48 | 8467.258 3 17 12.088 13.552 -1.671 'Pa 17 ' 6.31E+08 49 | 8502.487 3 16 12.088 13.546 -1.587 'Pa 16 ' 6.31E+08 50 | 8545.387 3 15 12.088 13.539 -1.496 'Pa 15 ' 6.31E+08 51 | 8598.396 3 14 12.088 13.530 -1.398 'Pa 14 ' 6.31E+08 52 | 8665.022 3 13 12.088 13.519 -1.292 'Pa 13 ' 6.31E+08 53 | 8750.476 3 12 12.088 13.505 -1.175 'Pa 12 ' 6.31E+08 54 | 8862.787 3 11 12.088 13.487 -1.046 'Pa 11 ' 6.31E+08 55 | 9014.913 3 10 12.088 13.463 -0.901 'Pa 10 ' 6.31E+08 56 | 9229.017 3 9 12.088 13.431 -0.735 'Pa 9 ' 6.31E+08 57 | 9545.973 3 8 12.088 13.387 -0.540 'Paepsilon' 6.31E+08 58 | 10049.373 3 7 12.088 13.322 -0.303 'Padelta ' 6.24E+08 59 | 10938.093 3 6 12.088 13.221 0.002 'Pagamma ' 6.21E+08 60 | 12818.077 3 5 12.088 13.055 0.433 'Pabeta ' 6.17E+08 61 | 14867.025 4 29 12.749 13.583 -2.001 'Br 29 ' 6.31E+08 62 | 14888.017 4 28 12.749 13.582 -1.954 'Br 28 ' 6.31E+08 63 | 14911.454 4 27 12.749 13.580 -1.904 'Br 27 ' 6.31E+08 64 | 14937.736 4 26 12.749 13.579 -1.853 'Br 26 ' 6.31E+08 65 | 14967.344 4 25 12.749 13.577 -1.799 'Br 25 ' 6.31E+08 66 | 15000.870 4 24 12.749 13.575 -1.743 'Br 24 ' 6.31E+08 67 | 15039.047 4 23 12.749 13.573 -1.684 'Br 23 ' 6.31E+08 68 | 15082.784 4 22 12.749 13.571 -1.623 'Br 22 ' 6.31E+08 69 | 15133.231 4 21 12.749 13.568 -1.558 'Br 21 ' 6.31E+08 70 | 15191.853 4 20 12.749 13.565 -1.489 'Br 20 ' 6.31E+08 71 | 15260.547 4 19 12.749 13.561 -1.416 'Br 19 ' 6.31E+08 72 | 15341.799 4 18 12.749 13.557 -1.339 'Br 18 ' 6.31E+08 73 | 15438.929 4 17 12.749 13.552 -1.256 'Br 17 ' 6.31E+08 74 | 15556.457 4 16 12.749 13.546 -1.167 'Br 16 ' 6.31E+08 75 | 15700.670 4 15 12.749 13.539 -1.071 'Br 15 ' 6.31E+08 76 | 15880.549 4 14 12.749 13.530 -0.966 'Br 14 ' 6.31E+08 77 | 16109.320 4 13 12.749 13.519 -0.852 'Br 13 ' 6.31E+08 78 | 16407.199 4 12 12.749 13.505 -0.725 'Br 12 ' 6.31E+08 79 | 16806.526 4 11 12.749 13.487 -0.582 'Br 11 ' 6.31E+08 80 | 17362.112 4 10 12.749 13.463 -0.417 'Br 10 ' 6.31E+08 81 | 18174.122 4 9 12.749 13.431 -0.223 'Brepsilon' 6.31E+08 82 | 18751.008 3 4 12.088 12.749 1.181 'Paalpha ' 6.04E+08 83 | 19445.562 4 8 12.749 13.387 0.014 'Brdelta ' 6.31E+08 84 | 21655.282 4 7 12.749 13.322 0.321 'Brgamma ' 6.24E+08 85 | 23438.894 5 30 13.055 13.584 -1.739 'H5 30 ' 6.31E+08 86 | 23485.970 5 29 13.055 13.583 -1.692 'H5 29 ' 6.31E+08 87 | 23538.400 5 28 13.055 13.582 -1.643 'H5 28 ' 6.31E+08 88 | 23597.040 5 27 13.055 13.580 -1.593 'H5 27 ' 6.31E+08 89 | 23662.921 5 26 13.055 13.579 -1.540 'H5 26 ' 6.31E+08 90 | 23737.305 5 25 13.055 13.577 -1.485 'H5 25 ' 6.31E+08 91 | 23821.743 5 24 13.055 13.575 -1.427 'H5 24 ' 6.31E+08 92 | 23918.161 5 23 13.055 13.573 -1.366 'H5 23 ' 6.31E+08 93 | 24028.979 5 22 13.055 13.571 -1.302 'H5 22 ' 6.31E+08 94 | 24157.272 5 21 13.055 13.568 -1.235 'H5 21 ' 6.31E+08 95 | 24306.999 5 20 13.055 13.565 -1.163 'H5 20 ' 6.31E+08 96 | 24483.333 5 19 13.055 13.561 -1.087 'H5 19 ' 6.31E+08 97 | 24693.147 5 18 13.055 13.557 -1.005 'H5 18 ' 6.31E+08 98 | 24945.748 5 17 13.055 13.552 -0.918 'H5 17 ' 6.31E+08 99 | 25254.024 5 16 13.055 13.546 -0.823 'H5 16 ' 6.31E+08 100 | 25636.286 5 15 13.055 13.539 -0.719 'H5 15 ' 6.31E+08 101 | 26119.360 5 14 13.055 13.530 -0.606 'H5 14 ' 6.31E+08 102 | 26251.501 4 6 12.749 13.221 0.759 'Brbeta ' 6.21E+08 103 | 26744.024 5 13 13.055 13.519 -0.479 'H5 13 ' 6.31E+08 104 | 27575.160 5 12 13.055 13.505 -0.337 'H5 12 ' 6.31E+08 105 | 28722.128 5 11 13.055 13.487 -0.173 'H5 11 ' 6.31E+08 106 | 30383.734 5 10 13.055 13.463 0.022 'H5 10 ' 6.31E+08 107 | 32960.918 5 9 13.055 13.431 0.261 'H5 9 ' 6.31E+08 108 | 34091.585 6 31 13.221 13.585 -1.528 'H6 31 ' 6.31E+08 109 | 34181.751 6 30 13.221 13.584 -1.482 'H6 30 ' 6.31E+08 110 | 34281.960 6 29 13.221 13.583 -1.434 'H6 29 ' 6.31E+08 111 | 34393.787 6 28 13.221 13.581 -1.384 'H6 28 ' 6.31E+08 112 | 34519.129 6 27 13.221 13.580 -1.332 'H6 27 ' 6.31E+08 113 | 34660.295 6 26 13.221 13.579 -1.277 'H6 26 ' 6.31E+08 114 | 34820.119 6 25 13.221 13.577 -1.220 'H6 25 ' 6.31E+08 115 | 35002.112 6 24 13.221 13.575 -1.160 'H6 24 ' 6.31E+08 116 | 35210.668 6 23 13.221 13.573 -1.097 'H6 23 ' 6.31E+08 117 | 35451.357 6 22 13.221 13.571 -1.030 'H6 22 ' 6.31E+08 118 | 35731.321 6 21 13.221 13.568 -0.959 'H6 21 ' 6.31E+08 119 | 36059.866 6 20 13.221 13.565 -0.884 'H6 20 ' 6.31E+08 120 | 36449.312 6 19 13.221 13.561 -0.803 'H6 19 ' 6.31E+08 121 | 36916.287 6 18 13.221 13.557 -0.716 'H6 18 ' 6.31E+08 122 | 37395.353 5 8 13.055 13.387 0.571 'H5 8 ' 6.31E+08 123 | 37483.730 6 17 13.221 13.552 -0.622 'H6 17 ' 6.31E+08 124 | 38184.117 6 16 13.221 13.546 -0.519 'H6 16 ' 6.31E+08 125 | 39064.850 6 15 13.221 13.538 -0.406 'H6 15 ' 6.31E+08 126 | 40197.729 6 14 13.221 13.529 -0.280 'H6 14 ' 6.31E+08 127 | 40511.565 4 5 12.749 13.055 1.521 'Bralpha ' 6.17E+08 128 | 41696.583 6 13 13.221 13.518 -0.137 'H6 13 ' 6.31E+08 129 | 43752.624 6 12 13.221 13.504 0.027 'H6 12 ' 6.31E+08 130 | 46525.068 5 7 13.055 13.321 1.015 'H5 7 ' 6.24E+08 131 | 46712.354 6 11 13.221 13.486 0.223 'H6 11 ' 6.31E+08 132 | 51272.589 6 10 13.221 13.463 0.463 'H6 10 ' 6.31E+08 133 | 59066.002 6 9 13.221 13.431 0.777 'H6 9 ' 6.31E+08 134 | 74578.197 5 6 13.055 13.221 1.789 'H5 6 ' 6.21E+08 135 | 75004.441 6 8 13.221 13.386 1.227 'H6 8 ' 6.31E+08 136 | -------------------------------------------------------------------------------- /input_files/linelists/linelist_for_fitting/Hlinedata: -------------------------------------------------------------------------------- 1 | '01.000000 ' 1 133 2 | 'H I lambda(AA) nblo nbup elo(eV) eup(eV) loggf ident raddamp/from BE 20/11-96' 3 | 920.963 1 10 0.000 13.462 -2.493 'Ly 10 ' 6.31E+08 4 | 923.150 1 9 0.000 13.430 -2.353 'Ly 9 ' 6.31E+08 5 | 926.226 1 8 0.000 13.386 -2.196 'Ly 8 ' 6.31E+08 6 | 930.748 1 7 0.000 13.321 -2.016 'Ly 7 ' 6.24E+08 7 | 937.803 1 6 0.000 13.220 -1.807 'Lyepsilon' 6.21E+08 8 | 949.743 1 5 0.000 13.054 -1.555 'Lydelta ' 6.17E+08 9 | 972.537 1 4 0.000 12.748 -1.237 'Lygamma ' 6.04E+08 10 | 1025.722 1 3 0.000 12.087 -0.801 'Lybeta ' 5.70E+08 11 | 1215.671 1 2 0.000 10.199 -0.080 'Lyalpha ' 4.70E+08 12 | 3666.095 2 27 10.199 13.581 -2.850 'H 27 ' 6.31E+08 13 | 3667.682 2 26 10.199 13.579 -2.801 'H 26 ' 6.31E+08 14 | 3669.464 2 25 10.199 13.578 -2.749 'H 25 ' 6.31E+08 15 | 3671.476 2 24 10.199 13.576 -2.695 'H 24 ' 6.31E+08 16 | 3673.759 2 23 10.199 13.574 -2.639 'H 23 ' 6.31E+08 17 | 3676.363 2 22 10.199 13.571 -2.580 'H 22 ' 6.31E+08 18 | 3679.353 2 21 10.199 13.569 -2.518 'H 21 ' 6.31E+08 19 | 3682.808 2 20 10.199 13.565 -2.453 'H 20 ' 6.31E+08 20 | 3686.831 2 19 10.199 13.562 -2.385 'H 19 ' 6.31E+08 21 | 3691.555 2 18 10.199 13.558 -2.313 'H 18 ' 6.31E+08 22 | 3697.152 2 17 10.199 13.552 -2.237 'H 17 ' 6.31E+08 23 | 3703.853 2 16 10.199 13.546 -2.155 'H 16 ' 6.31E+08 24 | 3711.971 2 15 10.199 13.539 -2.068 'H 15 ' 6.31E+08 25 | 3721.939 2 14 10.199 13.530 -1.975 'H 14 ' 6.31E+08 26 | 3734.368 2 13 10.199 13.519 -1.874 'H 13 ' 6.31E+08 27 | 3750.152 2 12 10.199 13.505 -1.764 'H 12 ' 6.31E+08 28 | 3770.630 2 11 10.199 13.487 -1.644 'H 11 ' 6.31E+08 29 | 3797.898 2 10 10.199 13.463 -1.511 'H 10 ' 6.31E+08 30 | 3835.384 2 9 10.199 13.432 -1.362 'H 9 ' 6.31E+08 31 | 3889.048 2 8 10.199 13.387 -1.192 'H 8 ' 6.31E+08 32 | 3970.072 2 7 10.199 13.322 -0.993 'Hepsilon ' 6.24E+08 33 | 4101.734 2 6 10.199 13.222 -0.753 'Hdelta ' 6.21E+08 34 | 4340.462 2 5 10.199 13.055 -0.447 'Hgamma ' 6.17E+08 35 | 4861.323 2 4 10.199 12.749 -0.020 'Hbeta ' 6.04E+08 36 | 6562.797 2 3 10.199 12.088 0.710 'Halpha ' 5.70E+08 37 | 8298.839 3 28 12.088 13.582 -2.348 'Pa 28 ' 6.31E+08 38 | 8306.116 3 27 12.088 13.581 -2.299 'Pa 27 ' 6.31E+08 39 | 8314.265 3 26 12.088 13.579 -2.249 'Pa 26 ' 6.31E+08 40 | 8323.429 3 25 12.088 13.578 -2.196 'Pa 25 ' 6.31E+08 41 | 8333.787 3 24 12.088 13.576 -2.141 'Pa 24 ' 6.31E+08 42 | 8345.557 3 23 12.088 13.574 -2.084 'Pa 23 ' 6.31E+08 43 | 8359.008 3 22 12.088 13.571 -2.024 'Pa 22 ' 6.31E+08 44 | 8374.479 3 21 12.088 13.568 -1.961 'Pa 21 ' 6.31E+08 45 | 8392.401 3 20 12.088 13.565 -1.895 'Pa 20 ' 6.31E+08 46 | 8413.322 3 19 12.088 13.562 -1.824 'Pa 19 ' 6.31E+08 47 | 8437.959 3 18 12.088 13.557 -1.750 'Pa 18 ' 6.31E+08 48 | 8467.258 3 17 12.088 13.552 -1.671 'Pa 17 ' 6.31E+08 49 | 8502.487 3 16 12.088 13.546 -1.587 'Pa 16 ' 6.31E+08 50 | 8545.387 3 15 12.088 13.539 -1.496 'Pa 15 ' 6.31E+08 51 | 8598.396 3 14 12.088 13.530 -1.398 'Pa 14 ' 6.31E+08 52 | 8665.022 3 13 12.088 13.519 -1.292 'Pa 13 ' 6.31E+08 53 | 8750.476 3 12 12.088 13.505 -1.175 'Pa 12 ' 6.31E+08 54 | 8862.787 3 11 12.088 13.487 -1.046 'Pa 11 ' 6.31E+08 55 | 9014.913 3 10 12.088 13.463 -0.901 'Pa 10 ' 6.31E+08 56 | 9229.017 3 9 12.088 13.431 -0.735 'Pa 9 ' 6.31E+08 57 | 9545.973 3 8 12.088 13.387 -0.540 'Paepsilon' 6.31E+08 58 | 10049.373 3 7 12.088 13.322 -0.303 'Padelta ' 6.24E+08 59 | 10938.093 3 6 12.088 13.221 0.002 'Pagamma ' 6.21E+08 60 | 12818.077 3 5 12.088 13.055 0.433 'Pabeta ' 6.17E+08 61 | 14867.025 4 29 12.749 13.583 -2.001 'Br 29 ' 6.31E+08 62 | 14888.017 4 28 12.749 13.582 -1.954 'Br 28 ' 6.31E+08 63 | 14911.454 4 27 12.749 13.580 -1.904 'Br 27 ' 6.31E+08 64 | 14937.736 4 26 12.749 13.579 -1.853 'Br 26 ' 6.31E+08 65 | 14967.344 4 25 12.749 13.577 -1.799 'Br 25 ' 6.31E+08 66 | 15000.870 4 24 12.749 13.575 -1.743 'Br 24 ' 6.31E+08 67 | 15039.047 4 23 12.749 13.573 -1.684 'Br 23 ' 6.31E+08 68 | 15082.784 4 22 12.749 13.571 -1.623 'Br 22 ' 6.31E+08 69 | 15133.231 4 21 12.749 13.568 -1.558 'Br 21 ' 6.31E+08 70 | 15191.853 4 20 12.749 13.565 -1.489 'Br 20 ' 6.31E+08 71 | 15260.547 4 19 12.749 13.561 -1.416 'Br 19 ' 6.31E+08 72 | 15341.799 4 18 12.749 13.557 -1.339 'Br 18 ' 6.31E+08 73 | 15438.929 4 17 12.749 13.552 -1.256 'Br 17 ' 6.31E+08 74 | 15556.457 4 16 12.749 13.546 -1.167 'Br 16 ' 6.31E+08 75 | 15700.670 4 15 12.749 13.539 -1.071 'Br 15 ' 6.31E+08 76 | 15880.549 4 14 12.749 13.530 -0.966 'Br 14 ' 6.31E+08 77 | 16109.320 4 13 12.749 13.519 -0.852 'Br 13 ' 6.31E+08 78 | 16407.199 4 12 12.749 13.505 -0.725 'Br 12 ' 6.31E+08 79 | 16806.526 4 11 12.749 13.487 -0.582 'Br 11 ' 6.31E+08 80 | 17362.112 4 10 12.749 13.463 -0.417 'Br 10 ' 6.31E+08 81 | 18174.122 4 9 12.749 13.431 -0.223 'Brepsilon' 6.31E+08 82 | 18751.008 3 4 12.088 12.749 1.181 'Paalpha ' 6.04E+08 83 | 19445.562 4 8 12.749 13.387 0.014 'Brdelta ' 6.31E+08 84 | 21655.282 4 7 12.749 13.322 0.321 'Brgamma ' 6.24E+08 85 | 23438.894 5 30 13.055 13.584 -1.739 'H5 30 ' 6.31E+08 86 | 23485.970 5 29 13.055 13.583 -1.692 'H5 29 ' 6.31E+08 87 | 23538.400 5 28 13.055 13.582 -1.643 'H5 28 ' 6.31E+08 88 | 23597.040 5 27 13.055 13.580 -1.593 'H5 27 ' 6.31E+08 89 | 23662.921 5 26 13.055 13.579 -1.540 'H5 26 ' 6.31E+08 90 | 23737.305 5 25 13.055 13.577 -1.485 'H5 25 ' 6.31E+08 91 | 23821.743 5 24 13.055 13.575 -1.427 'H5 24 ' 6.31E+08 92 | 23918.161 5 23 13.055 13.573 -1.366 'H5 23 ' 6.31E+08 93 | 24028.979 5 22 13.055 13.571 -1.302 'H5 22 ' 6.31E+08 94 | 24157.272 5 21 13.055 13.568 -1.235 'H5 21 ' 6.31E+08 95 | 24306.999 5 20 13.055 13.565 -1.163 'H5 20 ' 6.31E+08 96 | 24483.333 5 19 13.055 13.561 -1.087 'H5 19 ' 6.31E+08 97 | 24693.147 5 18 13.055 13.557 -1.005 'H5 18 ' 6.31E+08 98 | 24945.748 5 17 13.055 13.552 -0.918 'H5 17 ' 6.31E+08 99 | 25254.024 5 16 13.055 13.546 -0.823 'H5 16 ' 6.31E+08 100 | 25636.286 5 15 13.055 13.539 -0.719 'H5 15 ' 6.31E+08 101 | 26119.360 5 14 13.055 13.530 -0.606 'H5 14 ' 6.31E+08 102 | 26251.501 4 6 12.749 13.221 0.759 'Brbeta ' 6.21E+08 103 | 26744.024 5 13 13.055 13.519 -0.479 'H5 13 ' 6.31E+08 104 | 27575.160 5 12 13.055 13.505 -0.337 'H5 12 ' 6.31E+08 105 | 28722.128 5 11 13.055 13.487 -0.173 'H5 11 ' 6.31E+08 106 | 30383.734 5 10 13.055 13.463 0.022 'H5 10 ' 6.31E+08 107 | 32960.918 5 9 13.055 13.431 0.261 'H5 9 ' 6.31E+08 108 | 34091.585 6 31 13.221 13.585 -1.528 'H6 31 ' 6.31E+08 109 | 34181.751 6 30 13.221 13.584 -1.482 'H6 30 ' 6.31E+08 110 | 34281.960 6 29 13.221 13.583 -1.434 'H6 29 ' 6.31E+08 111 | 34393.787 6 28 13.221 13.581 -1.384 'H6 28 ' 6.31E+08 112 | 34519.129 6 27 13.221 13.580 -1.332 'H6 27 ' 6.31E+08 113 | 34660.295 6 26 13.221 13.579 -1.277 'H6 26 ' 6.31E+08 114 | 34820.119 6 25 13.221 13.577 -1.220 'H6 25 ' 6.31E+08 115 | 35002.112 6 24 13.221 13.575 -1.160 'H6 24 ' 6.31E+08 116 | 35210.668 6 23 13.221 13.573 -1.097 'H6 23 ' 6.31E+08 117 | 35451.357 6 22 13.221 13.571 -1.030 'H6 22 ' 6.31E+08 118 | 35731.321 6 21 13.221 13.568 -0.959 'H6 21 ' 6.31E+08 119 | 36059.866 6 20 13.221 13.565 -0.884 'H6 20 ' 6.31E+08 120 | 36449.312 6 19 13.221 13.561 -0.803 'H6 19 ' 6.31E+08 121 | 36916.287 6 18 13.221 13.557 -0.716 'H6 18 ' 6.31E+08 122 | 37395.353 5 8 13.055 13.387 0.571 'H5 8 ' 6.31E+08 123 | 37483.730 6 17 13.221 13.552 -0.622 'H6 17 ' 6.31E+08 124 | 38184.117 6 16 13.221 13.546 -0.519 'H6 16 ' 6.31E+08 125 | 39064.850 6 15 13.221 13.538 -0.406 'H6 15 ' 6.31E+08 126 | 40197.729 6 14 13.221 13.529 -0.280 'H6 14 ' 6.31E+08 127 | 40511.565 4 5 12.749 13.055 1.521 'Bralpha ' 6.17E+08 128 | 41696.583 6 13 13.221 13.518 -0.137 'H6 13 ' 6.31E+08 129 | 43752.624 6 12 13.221 13.504 0.027 'H6 12 ' 6.31E+08 130 | 46525.068 5 7 13.055 13.321 1.015 'H5 7 ' 6.24E+08 131 | 46712.354 6 11 13.221 13.486 0.223 'H6 11 ' 6.31E+08 132 | 51272.589 6 10 13.221 13.463 0.463 'H6 10 ' 6.31E+08 133 | 59066.002 6 9 13.221 13.431 0.777 'H6 9 ' 6.31E+08 134 | 74578.197 5 6 13.055 13.221 1.789 'H5 6 ' 6.21E+08 135 | 75004.441 6 8 13.221 13.386 1.227 'H6 8 ' 6.31E+08 136 | -------------------------------------------------------------------------------- /input_files/tsfitpy_input_configuration.cfg: -------------------------------------------------------------------------------- 1 | [turbospectrum_compiler] 2 | # The compiler used to compile turbospectrum: ifort, ifx, gnu. If running M3DIS@DISPATCH, use m3dis 3 | compiler = ifort 4 | 5 | [MainPaths] 6 | # Main paths for the input and output files 7 | code_path = ./turbospectrum/ 8 | interpolators_path = ./scripts/model_interpolators/ 9 | line_list_path = ./input_files/linelists/linelist_for_fitting/ 10 | model_atmosphere_grid_path_1d = ./input_files/model_atmospheres/1D/ 11 | model_atmosphere_grid_path_3d = ./input_files/model_atmospheres/3D/ 12 | model_atoms_path = ./input_files/nlte_data/model_atoms/ 13 | departure_file_path = ./input_files/nlte_data/ 14 | departure_file_config_path = ./input_files/nlte_data/nlte_filenames.cfg 15 | output_path = ./output_files/ 16 | linemasks_path = ./input_files/linemask_files/ 17 | spectra_input_path = ./input_files/observed_spectra/ 18 | fitlist_input_path = ./input_files/ 19 | temporary_directory_path = ./temp_directory/ 20 | 21 | [FittingParameters] 22 | # Atmosphere type. ('1D' / '3D') 23 | atmosphere_type = 1D 24 | # Fit mode: ('all' / 'lbl' / 'teff' / 'vmic') 25 | fitting_mode = lbl 26 | # Whether or not molecules are included in the fit ('True' / 'False') 27 | include_molecules = True 28 | # Whether to use nlte or not. ('True' or 'False') 29 | nlte = False 30 | # Whether or not mAcroturbulence is fit as a parameter or taken from the value below ('Yes' / "No" / "Input") 31 | # If set to 'No', mAcroturbulence is taken from the value below 32 | # If set to 'Input', mAcroturbulence is taken from the fitlist 33 | fit_vmac = Yes 34 | # Whether to fit mIcroturbulence or not. Only works in lbl mode. ('Yes' / 'No' / 'Input') 35 | # If set to 'No', mIcroturbulence is calculated based on Teff and loggq 36 | # If set to 'Input', mIcroturbulence is taken from the fitlist 37 | fit_vmic = No 38 | #whether to fit rotation or use the one below as a constant for all of them (Yes / No) 39 | fit_rotation = No 40 | # Elements to fit. (E.g. 'Fe Ca Mg'). Fits all elements within the linemask 41 | element_to_fit = Fe 42 | # Elements to have in NLTE (just choose whichever elements you want to have in NLTE) 43 | # nlte_elements = Mg Ca Fe 44 | nlte_elements = Fe 45 | # Linemask file. The line is fitted within bounds of the linemask 46 | linemask_file = Fe/fe-lmask_test.txt 47 | # Wavelength delta for the generated spectra [AA] 48 | wavelength_delta = 0.005 49 | # Segment size for the each line. Too small might not include wings from other lines 50 | # Larger segment size will be slower. [AA], recommended to keep at 3-5 51 | segment_size = 4 52 | 53 | [ExtraParameters] 54 | # Extra parameters 55 | # Debug mode. If 1, will print more Python output. If 2, will print more Fortran output. Recommended to keep at 0 56 | debug_mode = 0 57 | # Number of CPUs to use for the fit (1 = no parallelisation). If 0, will use all available CPUs 58 | number_of_cpus = 1 59 | # Experimental. ('True' / 'False') 60 | # True - can use several CPUs for one spectrum, but might not work for all Dask versions 61 | experimental_parallelisation = False 62 | # Name of the cluster (if not launched locally), only used for printing purposes 63 | cluster_name = 64 | 65 | [InputAndOutputFiles] 66 | # Input and output files 67 | # Fitlist file name. Contains the input spectra and atmospheric parameters 68 | input_filename = fitlist 69 | # Name of the output file (not folder) 70 | output_filename = output 71 | 72 | [SpectraParameters] 73 | # Resolution of the spectra (lambda_center/FWHM). If 0, no convolution is done 74 | resolution = 0 75 | # Macroturbulence [km/s] for all spectra, only used if fit_vmac = 'No' 76 | vmac = 0.0 77 | # Rotation [km/s] for all spectra, only used if fit_rotation = 'No' 78 | rotation = 0.0 79 | # If you want to fit with a certain initial guess for an element, can write which element it is and where the file is 80 | # E.g. if you want to fit with a guess of Mg, can write 81 | # init_guess_elem = Mg 82 | # init_guess_elem_location = location/mg.txt 83 | init_guess_elements = 84 | init_guess_elements_path = 85 | # If you know the abundance of an element, can write which element it is and where the file is 86 | # E.g. if you know the abundance of Ti, can write 87 | # input_elem_abundance = Ti 88 | # input_elem_abundance_location = location/ti.txt 89 | input_elements_abundance = 90 | input_elements_abundance_path = 91 | 92 | [ParametersForModeAll] 93 | # Parameters for mode = 'all' [AA] 94 | wavelength_min = 5300 95 | wavelength_max = 5700 96 | 97 | [ParametersForModeLbl] 98 | # Parameters for mode = 'lbl' 99 | # Bounds and guess ranges for the microturbulence 100 | # km/s, can never be less than 0, mIIIIcro 101 | bounds_vmic = 0.01 5 102 | # km/s, can never be less than 0, mIIIIcro 103 | guess_range_vmic = 0.9 1.3 104 | # if you want to also find upper limit after fit by varying abundance, change it here 105 | find_upper_limit = False 106 | # how many sigma to use for upper limit 107 | upper_limit_sigma = 1 108 | # whether to fit continuum using a simple linear relationship 109 | fit_continuum = True 110 | # relationship flux_norm += 1 - ((wavelength - wavelength_left_linemask_line) * slope + intercept) 111 | # bounds for slope and intercept 112 | bounds_continuum_slope = -0.1 0.1 113 | bounds_continuum_intercept = 0.9 1.1 114 | 115 | [ParametersForModeTeff] 116 | # Parameters for mode = 'teff' 117 | # Hard bounds for Teff. If the fit results in a Teff outside of these bounds, the fit is rejected 118 | bounds_teff = 2500 8000 119 | # Guess range for teff, from which the initial guesses are made. The guesses are made by taking the input Teff +/- guess_range_teff 120 | guess_range_teff = -200 200 121 | # Find errors for Teff. If True, will find the error (in 1 direction only) for Teff by varying Teff and finding the chi2 122 | find_teff_errors = False 123 | # How many sigma to use for Teff errors 124 | teff_error_sigma = 1 125 | 126 | [ParametersForModeLogg] 127 | # Parameters for mode = 'logg' 128 | # Hard bounds for logg. If the fit results in a logg outside of these bounds, the fit is rejected 129 | bounds_logg = -0.5 5.5 130 | # Guess range for logg, from which the initial guesses are made. The guesses are made by taking the input logg +/- guess_range_logg 131 | guess_range_logg = -0.25 0.25 132 | # Find errors for logg. If True, will find the error (in 1 direction only) for logg by varying logg and finding the chi2; most likely doesn't work atm 133 | find_logg_errors = False 134 | # How many sigma to use for logg errors 135 | logg_error_sigma = 1 136 | 137 | [Bounds] 138 | #bounds for the minimisation -> HARD BOUND, will NEVER fit outside these bounds 139 | # km/s, can never be less than 0, mAAAAcro 140 | bounds_vmac = 0 15 141 | # km/s, can never be less than 0, NOT USED IN MODE = 'all' 142 | bounds_rotation = 0 15 143 | # [X/Fe] 144 | bounds_abundance = -40 100 145 | # [Fe/H], hard bounds set by model atmosphere grid 146 | bounds_feh = -5 1.0 147 | # km/s, too high might result in fits of wrong lines 148 | # Added to RV of the star, so if the star has a RV of 10 km/s, and the fit has a RV of 2 km/s, the total RV is 12 km/s 149 | bounds_doppler = -2 2 150 | 151 | [GuessRanges] 152 | # Guess ranges for the minimisation -> GUESS ONLY. CAN fit outside, but depending on variable (especially abund/micro), 153 | # may never fit outside guesses 154 | # km/s, can never be less than 0, mAAAAcro 155 | guess_range_vmac = 0.2 8.0 156 | # km/s, can never be less than 0, NOT USED IN MODE = 'all' 157 | guess_range_rotation = 0.2 2.0 158 | # [X/Fe] or [Fe/H] 159 | guess_range_abundance = 0 0.5 160 | # km/s 161 | guess_range_doppler = -2 2 162 | 163 | [SlurmClusterParameters] 164 | # Parameters for the Slurm cluster 165 | # Type of cluster. Can be 'slurm' or 'local'. 'local' ignores the other parameters 166 | cluster_type = local 167 | # Number of nodes to use, cpus are taken from the number_of_cpus parameter 168 | number_of_nodes = 1 169 | # Memory per CPU in GB 170 | memory_per_cpu_gb = 3.6 171 | # Commands to run before the script. Each command is separated by a semicolon. example below purges the modules and loads the ones needed 172 | script_commands = module purge;module load basic-path;module load intel;module load anaconda3-py3.10 173 | # Time limit for the job in hours 174 | time_limit_hours = 167 175 | # Partition to use in the cluster passed to the --partition flag 176 | partition = debug 177 | 178 | [m3disParameters] 179 | # Parameters for the m3dis code 180 | # Number of different nu points (less = faster, but more memory) 181 | n_nu = 1 182 | # Less = faster, but might need higher for 3D or NLTE 183 | # 1D NLTE - 100 seems to work, 1D LTE - 10 or less? 184 | hash_table_size = 100 185 | # Number of cores to use for each separate m3dis run (leave it at 1 for 1D) 186 | mpi_cores = 1 187 | # Only NLTE parameters, iterations is how many times to iterate, convlim is the convergence limit 188 | # iterations_max_precompute is how many times to iterate when precomputing the departure coefficients 189 | # iterations_max is how many times to iterate when fitting when using precomputed departure coefficients (recommended lower than iterations_max_precompute) 190 | iterations_max_precompute = 10 191 | iterations_max = 3 192 | convlim = 0.01 193 | # Only 3D parameters, snap is the snapshot number, dims is the number of dimensions, nx, ny, nz are the resolution of the model (if Stagger) 194 | snap = 1 195 | dims = 23 196 | nx = 10 197 | ny = 10 198 | nz = 230 199 | 200 | [AdvancedOptions] 201 | # Only change these if you know what you're doing!! 202 | # scipy xatol and fatol for the minimisation, different methods 203 | xatol_all = 0.05 204 | fatol_all = 0.05 205 | xatol_lbl = 0.0001 206 | fatol_lbl = 0.00001 207 | xatol_teff = 0.01 208 | fatol_teff = 0.01 209 | xatol_logg = 0.00001 210 | fatol_logg = 0.00001 211 | xatol_vmic = 0.005 212 | fatol_vmic = 0.000001 213 | # scipy maxfev for the minimisation 214 | maxfev = 50 215 | # Value of lpoint for turbospectrum in spectrum.inc file 216 | lpoint_turbospectrum = 1000000 217 | # m3dis parameters 218 | m3dis_python_package_name = m3dis 219 | # margin in AA of how much observed spectra to keep when cutting out the line 220 | margin = 3 221 | # adds this much randomness to the guess ratio wise to the guess for the parameters. 0 means guess is the same as the input 222 | guess_ratio_to_add = 0.1 223 | # whether to save the different types of results 224 | save_original_spectra = True 225 | save_fitted_spectra = True 226 | save_convolved_fitted_spectra = True 227 | save_results = True 228 | save_linemask = True 229 | save_fitlist = True 230 | save_config_file = True 231 | # whether to pretrim the linelist or not 232 | pretrim_linelist = True 233 | # whether to run babsma once or every time during iteration; False is technically more accurate, but slower 234 | lightweight_ts_run = False 235 | # after fitting tries to compute and save spectra of just blend and changed abundance 236 | # this is whether to compute them or not 237 | compute_blend_spectra = True 238 | # by how much to change the abundance of the fitted element to see sensitivity of the line 239 | sensitivity_abundance_offset = 0.2 240 | # by how much to reduce the abundance of the fitted element to see the blend 241 | just_blend_reduce_abundance = -10 -------------------------------------------------------------------------------- /utilities/nlte_grids_links.cfg: -------------------------------------------------------------------------------- 1 | # 2025 July 8: Checked everything, looks good for both 1D and 3D grids. 2 | 3 | [Al] 4 | model_atom_name = atom.al_qmh 5 | model_atom_link = https://keeper.mpdl.mpg.de/f/a8d56401e25f4fbcad22/?dl=1 6 | 1d_bin_name = NLTEgrid_Al_MARCS_Jul-25-2023.bin.zip 7 | 1d_bin_link = https://keeper.mpdl.mpg.de/f/0df34c9440024ed18e78/?dl=1 8 | 1d_aux_name = auxData_Al_MARCS_Jul-25-2023.dat 9 | 1d_aux_link = https://keeper.mpdl.mpg.de/f/bbe071e38df14ef5bfa8/?dl=1 10 | 3d_bin_name = NLTEgrid_Al_STAGGERmean3D_Aug-05-2023.bin 11 | 3d_bin_link = https://keeper.mpdl.mpg.de/f/5bbc96082f8b4b20b5bc/?dl=1 12 | 3d_aux_name = auxData_Al_STAGGERmean3D_Aug-05-2023_marcs_names.txt 13 | 3d_aux_link = https://keeper.mpdl.mpg.de/f/71fc72d0aa384a70949c/?dl=1 14 | 15 | [Ba] 16 | model_atom_name = atom.ba111 17 | model_atom_link = https://keeper.mpdl.mpg.de/f/3011460bb6f94f979706/?dl=1 18 | 1d_bin_name = NLTEgrid_Ba_MARCS_Jul-29-2023.bin.zip 19 | 1d_bin_link = https://keeper.mpdl.mpg.de/f/e85b756d6b4a4973bbd3/?dl=1 20 | 1d_aux_name = auxData_Ba_MARCS_Jul-29-2023.dat 21 | 1d_aux_link = https://keeper.mpdl.mpg.de/f/073d8ca28bb94837a36b/?dl=1 22 | 3d_bin_name = NLTEgrid4TS_Ba_STAGGERmean3D_Aug-11-2023.bin 23 | 3d_bin_link = https://keeper.mpdl.mpg.de/f/7e56df4e75c04743ae13/?dl=1 24 | 3d_aux_name = auxData_Ba_STAGGERmean3D_Aug-11-2023_marcs_names.txt 25 | 3d_aux_link = https://keeper.mpdl.mpg.de/f/df6a4dc1f6ab4ee5b338/?dl=1 26 | 27 | [Ca] 28 | model_atom_name = atom.ca105b 29 | model_atom_link = https://keeper.mpdl.mpg.de/f/0d4e29243e0047ae8777/?dl=1 30 | 1d_bin_name = NLTEgrid4TS_Ca_MARCS_Jun-02-2021.bin.zip 31 | 1d_bin_link = https://keeper.mpdl.mpg.de/f/06e10b553c08488a87d6/?dl=1 32 | 1d_aux_name = auxData_Ca_MARCS_Jun-02-2021.dat 33 | 1d_aux_link = https://keeper.mpdl.mpg.de/f/475fd582bb594c0da9f1/?dl=1 34 | 3d_bin_name = NLTEgrid4TS_Ca_STAGGERmean3D_May-18-2021.bin.zip 35 | 3d_bin_link = https://keeper.mpdl.mpg.de/f/2377a1308eff4887beff/?dl=1 36 | 3d_aux_name = auxData_Ca_STAGGERmean3D_May-18-2021_marcs_names.txt 37 | 3d_aux_link = https://keeper.mpdl.mpg.de/f/5a670e2ba32f448f91ff/?dl=1 38 | 39 | [Co] 40 | model_atom_name = atom.co247qm 41 | model_atom_link = https://keeper.mpdl.mpg.de/f/a2ce33c90c6b47109875/?dl=1 42 | 1d_bin_name = NLTEgrid4TS_CO_MARCS_Nov-14-2024.bin.zip 43 | 1d_bin_link = https://keeper.mpdl.mpg.de/f/1c6dd1d999dc4d7b9871/?dl=1 44 | 1d_aux_name = auxData_CO_MARCS_Nov-14-2024.dat 45 | 1d_aux_link = https://keeper.mpdl.mpg.de/f/fa2847085e8b42e29f20/?dl=1 46 | 3d_bin_name = NLTEgrid4TS_Co_STAGGERmean3D_Nov-20-2024.bin 47 | 3d_bin_link = https://keeper.mpdl.mpg.de/f/e456eedb63c249a389ad/?dl=1 48 | 3d_aux_name = auxData_Co_STAGGERmean3D_Nov-20-2024_marcs_names.txt 49 | 3d_aux_link = https://keeper.mpdl.mpg.de/f/2a82f58a87e043f1a904/?dl=1 50 | 51 | [Cr] 52 | model_atom_name = atom.cr374 53 | model_atom_link = https://keeper.mpdl.mpg.de/f/5a56173314c64a2683f8/?dl=1 54 | 1d_bin_name = NLTEgrid4TS_Cr_MARCS_Dec-16-2024.bin.zip 55 | 1d_bin_link = https://keeper.mpdl.mpg.de/f/c16fe047208d402a955c/?dl=1 56 | 1d_aux_name = auxData_Cr_MARCS_Dec-16-2024.dat 57 | 1d_aux_link = https://keeper.mpdl.mpg.de/f/54a0c57b393f422b9e5e/?dl=1 58 | 3d_bin_name = NLTEgrid4TS_Cr_STAGGERmean3D_Dec-12-2024.bin 59 | 3d_bin_link = https://keeper.mpdl.mpg.de/f/6e3fbaeb3c6d402b8164/?dl=1 60 | 3d_aux_name = auxData_Cr_STAGGERmean3D_Dec-12-2024_marcs_names.txt 61 | 3d_aux_link = https://keeper.mpdl.mpg.de/f/f34e5b594ae746948adc/?dl=1 62 | 63 | [Eu] 64 | model_atom_name = atom.eu662qmkhfs 65 | model_atom_link = https://keeper.mpdl.mpg.de/f/0c6d1f2b3a4e4b8f9c5e/?dl=1 66 | 1d_bin_name = NLTEgrid_Eu_MARCS_Sep-13-2023.bin.zip 67 | 1d_bin_link = https://keeper.mpdl.mpg.de/f/cce60a798c6f44ce94bb/?dl=1 68 | 1d_aux_name = auxData_Eu_MARCS_Sep-13-2023.dat 69 | 1d_aux_link = https://keeper.mpdl.mpg.de/f/a8867a4979e54a5fb99f/?dl=1 70 | 3d_bin_name = NLTEgrid4TS_Eu_STAGGERmean3D_Nov-20-2024.bin 71 | 3d_bin_link = https://keeper.mpdl.mpg.de/f/14c35060d69b4883b397/?dl=1 72 | 3d_aux_name = auxData_Eu_STAGGERmean3D_Nov-20-2024_marcs_names.txt 73 | 3d_aux_link = https://keeper.mpdl.mpg.de/f/5e6e7356225249eea0b3/?dl=1 74 | 75 | [Fe] 76 | model_atom_name = atom.fe607a 77 | model_atom_link = https://keeper.mpdl.mpg.de/f/8bc18d80b2754d029aaa/?dl=1 78 | 1d_bin_name = NLTEgrid4TS_Fe_MARCS_May-07-2021.bin.zip 79 | 1d_bin_link = https://keeper.mpdl.mpg.de/f/e7c115fa632d4c42a8b3/?dl=1 80 | 1d_aux_name = auxData_Fe_MARCS_May-07-2021.dat 81 | 1d_aux_link = https://keeper.mpdl.mpg.de/f/fe366a514c9a4daf8f65/?dl=1 82 | 3d_bin_name = NLTEgrid4TS_Fe_STAGGERmean3D_May-21-2021.bin.zip 83 | 3d_bin_link = https://keeper.mpdl.mpg.de/f/0cf0770eaf61440fbfce/?dl=1 84 | 3d_aux_name = auxData_Fe_STAGGERmean3D_May-21-2021_marcs_names.txt 85 | 3d_aux_link = https://keeper.mpdl.mpg.de/f/57c84752f46c4326ab24/?dl=1 86 | 87 | [H] 88 | model_atom_name = atom.h20 89 | model_atom_link = https://keeper.mpdl.mpg.de/f/12d1913cff844c70866d/?dl=1 90 | 1d_bin_name = NLTEgrid_H_MARCS_May-10-2021.bin.zip 91 | 1d_bin_link = https://keeper.mpdl.mpg.de/f/c70a87b91e384847b1f8/?dl=1 92 | 1d_aux_name = auxData_H_MARCS_May-10-2021.txt 93 | 1d_aux_link = https://keeper.mpdl.mpg.de/f/fb1424922f424aa980ce/?dl=1 94 | 3d_bin_name = NLTEgrid4TS_H_STAGGERmean3D_Jun-17-2021.bin.zip 95 | 3d_bin_link = https://keeper.mpdl.mpg.de/f/f1de951a96874d5d9670/?dl=1 96 | 3d_aux_name = auxData_H_STAGGERmean3D_Jun-17-2021_marcs_names.txt 97 | 3d_aux_link = https://keeper.mpdl.mpg.de/f/2ff5dc9a31024a88b569/?dl=1 98 | 99 | [Mg] 100 | model_atom_name = atom.mg86d 101 | model_atom_link = https://keeper.mpdl.mpg.de/f/85997523dd4f4eedbe56/?dl=1 102 | 1d_bin_name = NLTEgrid4TS_Mg_MARCS_Nov-13-2024.bin.zip 103 | 1d_bin_link = https://keeper.mpdl.mpg.de/f/0910baf8184e41c3bdf0/?dl=1 104 | 1d_aux_name = auxData_Mg_MARCS_Nov-13-2024.dat 105 | 1d_aux_link = https://keeper.mpdl.mpg.de/f/0c57afa355fe45f49f2a/?dl=1 106 | 3d_bin_name = NLTEgrid4TS_Mg_STAGGERmean3D_Nov-20-2024.bin 107 | 3d_bin_link = https://keeper.mpdl.mpg.de/f/a78d9a5428304ad5abed/?dl=1 108 | 3d_aux_name = auxData_Mg_STAGGERmean3D_Nov-20-2024_marcs_names.txt 109 | 3d_aux_link = https://keeper.mpdl.mpg.de/f/82d668c211994df7a4e3/?dl=1 110 | 111 | [Mn] 112 | model_atom_name = atom.mn281kbc 113 | model_atom_link = https://keeper.mpdl.mpg.de/f/39fb1c4531494da594bd/?dl=1 114 | 1d_bin_name = NLTEgrid4TS_MN_MARCS_Mar-15-2023.bin.zip 115 | 1d_bin_link = https://keeper.mpdl.mpg.de/f/26173f90793a4b0a858c/?dl=1 116 | 1d_aux_name = auxData_MN_MARCS_Mar-15-2023.dat 117 | 1d_aux_link = https://keeper.mpdl.mpg.de/f/7a252b64d5ea459aaa0c/?dl=1 118 | 3d_bin_name = NLTEgrid4TS_Mn_STAGGERmean3D_May-17-2021.bin.zip 119 | 3d_bin_link = https://keeper.mpdl.mpg.de/f/aff75d9185744e3d9c89/?dl=1 120 | 3d_aux_name = auxData_Mn_STAGGERmean3D_May-17-2021_marcs_names.txt 121 | 3d_aux_link = https://keeper.mpdl.mpg.de/f/ae6249f81ecd475388a2/?dl=1 122 | 123 | [Na] 124 | model_atom_name = atom.na_qmh 125 | model_atom_link = https://keeper.mpdl.mpg.de/f/e591b04ed6694306b876/?dl=1 126 | 1d_bin_name = NLTEgrid4TS_Na_MARCS_Jul-14-2023.bin.zip 127 | 1d_bin_link = https://keeper.mpdl.mpg.de/f/4223b6468d914975896b/?dl=1 128 | 1d_aux_name = auxData_Na_MARCS_Jul-14-2023.dat 129 | 1d_aux_link = https://keeper.mpdl.mpg.de/f/f844a547fe0746c196e8/?dl=1 130 | 3d_bin_name = NLTEgrid4TS_Na_STAGGERmean3D_Aug-04-2023.bin 131 | 3d_bin_link = https://keeper.mpdl.mpg.de/f/da8fe797a1cb418f9f40/?dl=1 132 | 3d_aux_name = auxData_Na_STAGGERmean3D_Aug-04-2023_marcs_names.txt 133 | 3d_aux_link = https://keeper.mpdl.mpg.de/f/c537b6c1215d4599a78e/?dl=1 134 | 135 | [Ni] 136 | model_atom_name = atom.ni538qm 137 | model_atom_link = https://keeper.mpdl.mpg.de/f/64fab2d399cc4803a3e1/?dl=1 138 | 1d_bin_name = NLTEgrid4TS_Ni_MARCS_Jan-31-2022.bin.zip 139 | 1d_bin_link = https://keeper.mpdl.mpg.de/f/191a40fe18ba49b7b2e9/?dl=1 140 | 1d_aux_name = auxData_Ni_MARCS_Jan-21-2022.txt 141 | 1d_aux_link = https://keeper.mpdl.mpg.de/f/622d81f0369642b8a5e7/?dl=1 142 | 3d_bin_name = NLTEgrid4TS_NI_STAGGERmean3D_Aug-12-2023.bin 143 | 3d_bin_link = https://keeper.mpdl.mpg.de/f/4166b727a3ef4f3e9a4b/?dl=1 144 | 3d_aux_name = auxData_NI_STAGGERmean3D_Aug-12-2023_marcs_names.txt 145 | 3d_aux_link = https://keeper.mpdl.mpg.de/f/353abfaf3c5540e0aa39/?dl=1 146 | 147 | [O] 148 | model_atom_name = atom.o41f 149 | model_atom_link = https://keeper.mpdl.mpg.de/f/71b6565adcc2498181ac/?dl=1 150 | 1d_bin_name = NLTEgrid4TS_O_MARCS_May-21-2021.bin.zip 151 | 1d_bin_link = https://keeper.mpdl.mpg.de/f/d3a239e5f5d848089dfd/?dl=1 152 | 1d_aux_name = auxData_O_MARCS_May-21-2021.txt 153 | 1d_aux_link = https://keeper.mpdl.mpg.de/f/e85d1a6e4d7945ff9f52/?dl=1 154 | 3d_bin_name = NLTEgrid4TS_O_STAGGERmean3D_May-18-2021.bin.zip 155 | 3d_bin_link = https://keeper.mpdl.mpg.de/f/895f1329f2154aa28727/?dl=1 156 | 3d_aux_name = auxData_O_STAGGER_May-18-2021_marcs_names.txt 157 | 3d_aux_link = https://keeper.mpdl.mpg.de/f/10718f46fec7454f921b/?dl=1 158 | 159 | [Si] 160 | model_atom_name = atom.si340 161 | model_atom_link = https://keeper.mpdl.mpg.de/f/9d70635e75864b8e9b79/?dl=1 162 | 1d_bin_name = NLTEgrid4TS_Si_MARCS_Feb-13-2022.bin.zip 163 | 1d_bin_link = https://keeper.mpdl.mpg.de/f/4235ff57b3e64e6f928a/?dl=1 164 | 1d_aux_name = auxData_Si_MARCS_Feb-13-2022.dat 165 | 1d_aux_link = https://keeper.mpdl.mpg.de/f/9292d086fc104a90a997/?dl=1 166 | 3d_bin_name = NLTEgrid4TS_Si_STAGGERmean3D_Aug-05-2023.bin 167 | 3d_bin_link = https://keeper.mpdl.mpg.de/f/4b2d28874c9c4a86a8cf/?dl=1 168 | 3d_aux_name = auxData_Si_STAGGERmean3D_Aug-05-2023_marcs_names.txt 169 | 3d_aux_link = https://keeper.mpdl.mpg.de/f/88dcb441624c4e37b5d8/?dl=1 170 | 171 | [Sr] 172 | model_atom_name = atom.sr191 173 | model_atom_link = https://keeper.mpdl.mpg.de/f/9e24d5055c1a4bd0bc95/?dl=1 174 | 1d_bin_name = NLTEgrid4TS_Sr_MARCS_Mar-15-2023.bin.zip 175 | 1d_bin_link = https://keeper.mpdl.mpg.de/f/ed4f4b5172bf4fbfb91f/?dl=1 176 | 1d_aux_name = auxData_Sr_MARCS_Mar-15-2023.dat 177 | 1d_aux_link = https://keeper.mpdl.mpg.de/f/01c0c05b3b1743088f9b/?dl=1 178 | 3d_bin_name = NLTEgrid_Sr_STAGGERmean3D_Jul-17-2023.bin 179 | 3d_bin_link = https://keeper.mpdl.mpg.de/f/c3b9e5a35f3e4cdebb71/?dl=1 180 | 3d_aux_name = auxData_Sr_STAGGEmean3D_Jul-17-2023_marcs_names.dat 181 | 3d_aux_link = https://keeper.mpdl.mpg.de/f/7395833edf6046548b50/?dl=1 182 | 183 | [Ti] 184 | model_atom_name = atom.ti503 185 | model_atom_link = https://keeper.mpdl.mpg.de/f/2d745fa5d80b40a99b92/?dl=1 186 | 1d_bin_name = NLTEgrid4TS_TI_MARCS_Feb-21-2022.bin.zip 187 | 1d_bin_link = https://keeper.mpdl.mpg.de/f/f9055fc8111a44298eb8/?dl=1 188 | 1d_aux_name = auxData_TI_MARCS_Feb-21-2022.dat 189 | 1d_aux_link = https://keeper.mpdl.mpg.de/f/957265e3da894aa6a6c0/?dl=1 190 | 3d_bin_name = NLTEgrid4TS_Ti_STAGGERmean3D_Aug-07-2023.bin 191 | 3d_bin_link = https://keeper.mpdl.mpg.de/f/6da738347a884afa973b/?dl=1 192 | 3d_aux_name = auxData_Ti_STAGGERmean3D_Aug-07-2023_marcs_names.txt 193 | 3d_aux_link = https://keeper.mpdl.mpg.de/f/e4f45fab4f34468b984b/?dl=1 194 | 195 | [Y] 196 | model_atom_name = atom.y423qm_pf 197 | model_atom_link = https://keeper.mpdl.mpg.de/f/5823b0c51c004fe18f61/?dl=1 198 | 1d_bin_name = NLTEgrid4TS_Y_MARCS_Mar-27-2023.bin.zip 199 | 1d_bin_link = https://keeper.mpdl.mpg.de/f/d563533e53364248a721/?dl=1 200 | 1d_aux_name = auxData_Y_MARCS_Mar-27-2023.dat 201 | 1d_aux_link = https://keeper.mpdl.mpg.de/f/74fd6412bbcc41708586/?dl=1 202 | 3d_bin_name = NLTEgrid4TS_Y_STAGGERmean3D_May-08-2023.bin 203 | 3d_bin_link = https://keeper.mpdl.mpg.de/f/01b2111f204845669933/?dl=1 204 | 3d_aux_name = auxData_Y_STAGGERmean3D_May-08-2023_marcs_names.dat 205 | 3d_aux_link = https://keeper.mpdl.mpg.de/f/f5fd431605d44138a2e5/?dl=1 -------------------------------------------------------------------------------- /scripts/faltbon.f90: -------------------------------------------------------------------------------- 1 | program faltbo 2 | 3 | ! This version can read up to 100 columns and convolve them all. 4 | ! The convolution window adapts to the wavelength 5 | ! BPz 13/02-2019 6 | 7 | implicit none 8 | 9 | integer :: iprf,ii,jj,ios,isize,isize2,jmax,i 10 | integer :: resample,itype,ipad,jbeg,jend,ipad2,ipad1,kk 11 | real(kind=kind(1.d0)) :: FWHM,FWHM2,somme,dlam,dlam2,clight 12 | real(kind=kind(1.d0)), allocatable, dimension(:) :: lambda 13 | real(kind=kind(1.d0)), dimension(102) :: Ftest 14 | real(kind=kind(1.d0)), allocatable, dimension(:) :: lambda2,F2,dl,prof 15 | real(kind=kind(1.d0)), allocatable, dimension(:,:) :: Fconv,Farray 16 | real(kind=kind(1.d0)), parameter :: pi = 4.*atan(1.) 17 | character(len=800) :: inspec,outfil,command,oneline 18 | logical :: velocity 19 | 20 | clight = 2.99792458e5 21 | resample=1 22 | ! read inputs and open files 23 | print*,'input file ?' 24 | read(5,' (A) ') inspec 25 | print*,'output file ?' 26 | read(5,' (A) ') outfil 27 | 28 | ios=0 29 | open(unit=10,file=inspec,status='old',iostat=ios,action='read') 30 | if (ios==0) print*,'input file opened' 31 | if (ios/=0) stop "problem in file opening ..." 32 | open(unit=20,file=outfil,status='unknown') 33 | 34 | print*,'FWHM (in km/s or mA, <0 if velocity) ?' 35 | read(5,*) FWHM 36 | print*,'profile type ? (1 = exp - 2 = gauss - 3 = rad.-tan. - 4 = rot.)' 37 | read(5,*) iprf ! profile type 38 | ! 39 | ! we don't give the choice anymore. 40 | ! we suppose that spectra are always 2 or 3 or 4 or 5 columns: 1st is 41 | ! lambda, the next 1 or 2 is/are Fnorm and/or Fabs, and the 4th is 42 | ! absolute intensity, the 5th is normalized intensity 43 | ! we convolve all. BPz 6/02-2019 44 | ! 45 | ! print*,'1 = convol. Fnorm; 2 = convol. Fabs' 46 | ! read(5,*) itype ! 1 if convol. of Fnorm, 2 if convol. of Fabs 47 | ! print*,'step (resampling) for output (< 100)?' 48 | ! read(5,*) resample ! nb of wavelengths to be skipped in output (max. 99) 49 | 50 | velocity=.false. 51 | if (FWHM.LT.0.) velocity=.true. 52 | 53 | ! assumes no headers in inspec ... 54 | 55 | ! command='wc -l ' // inspec 56 | ! call system(command) 57 | 58 | ! read input spectrum 59 | 60 | ! first determine number of columns in input (read a dummy line first to deal with a possible header) 61 | read(unit=10, fmt=*) 62 | ios=0 63 | read(unit=10,iostat=ios,fmt='(a)') oneline 64 | do jmax=1,102 65 | read(oneline,iostat=ios,fmt=*) Ftest(1:jmax) 66 | if (ios /= 0) exit 67 | enddo 68 | jmax=jmax-2 69 | if (jmax == 100) then 70 | stop ' input file may have more than 100 columns, increase jmax!' 71 | endif 72 | print*,jmax,' columns to convolve in input' 73 | backspace(10) 74 | ! and number of lines in input file 75 | isize=0 76 | ios=0 77 | do while (ios == 0) 78 | read(unit=10,fmt=*,iostat=ios) Ftest(1) 79 | isize=isize+1 80 | enddo 81 | isize=isize-1 82 | print*,isize,' lines to read ' 83 | rewind(10) 84 | 85 | allocate(Farray(isize,jmax)) 86 | allocate(lambda(isize)) 87 | 88 | ! now read 89 | ios=0 90 | do ii=1,isize 91 | read(unit=10,iostat=ios,fmt=*) lambda(ii),Farray(ii,1:jmax) 92 | end do 93 | if (ios /= 0) then 94 | stop 'something went wrong while reading' 95 | endif 96 | 97 | print*,isize,' lines read in input file' 98 | allocate(Fconv(isize,jmax)) 99 | 100 | ! define how many 0s necessary before and after and extend input spectrum 101 | dlam=lambda(2)-lambda(1) 102 | dlam2=lambda(isize)-lambda(isize-1) 103 | if (velocity) then 104 | ipad1=int(-50.*FWHM*lambda(1)/clight/dlam)+1 105 | ipad2=int(-50.*FWHM*lambda(isize)/clight/dlam2)+1 106 | else 107 | ipad1=int(50.*FWHM/1.e3/dlam)+1 108 | ipad2=int(50.*FWHM/1.e3/dlam2)+1 109 | endif 110 | print*,'ipad1, ipad2, isize ',ipad1,ipad2,isize 111 | isize2=isize+ipad1+ipad2 112 | print*,'ipad1+ipad2, isize2 = ',ipad1+ipad2,isize2 113 | allocate(lambda2(isize2),F2(isize2)) 114 | do ii=1,ipad1 115 | lambda2(ii)=lambda(1)-dlam*(ipad1-ii+1) 116 | F2(ii)=0. 117 | end do 118 | do ii=1,ipad2 119 | lambda2(isize+ipad1+ii)=lambda(isize)+dlam2*ii 120 | F2(isize+ipad1+ii)=0. 121 | end do 122 | 123 | ! loop to convolve 4 spectra (if needed) 124 | i=0 125 | do itype=1,jmax 126 | do ii=1,isize 127 | kk=ii+ipad1 128 | lambda2(kk)=lambda(ii) 129 | F2(kk)=Farray(ii,itype) 130 | end do 131 | 132 | FWHM2=FWHM/1.e3 133 | do ii=1,isize,resample 134 | ! at current wavelength: check step, and allocate conv. profile accordingly 135 | if (ii.eq.isize) then 136 | dlam=lambda(ii)-lambda(ii-1) 137 | else 138 | dlam=lambda(ii+1)-lambda(ii) 139 | endif 140 | if (velocity) then 141 | FWHM2=-FWHM*lambda(ii)/clight ! km/s -> A 142 | ipad=int(-50.*FWHM*lambda(ii)/clight/dlam)+1 143 | else 144 | ipad=int(50.*FWHM/1.e3/dlam)+1 145 | endif 146 | 147 | jbeg=1 148 | jend=2*ipad+1 149 | kk=ii+ipad1 150 | allocate(dl(jend)) 151 | allocate(prof(jend)) 152 | do jj=jbeg,jend 153 | dl(jj)=lambda2(kk+jj-1-ipad)-lambda2(kk) !where segfault is occurring 154 | end do 155 | ! call relevant procedure for convolution profile 156 | if (iprf==1 .or. iprf==2) then 157 | call gauss(ipad,dl,iprf,FWHM2,prof,jbeg,jend) 158 | else if (iprf==3) then 159 | call radtan(ipad,dl,FWHM2,prof,jbeg,jend) 160 | else if (iprf==4) then 161 | call rota(ipad,dl,FWHM2,lambda(ii),prof,jbeg,jend) 162 | else 163 | stop 'undefined profile' 164 | endif 165 | ! if (iprf==5) call FTS(FWHM) 166 | 167 | ! normalization of convolution profile 168 | ! somme=0. 169 | somme=prof(jbeg)*(dl(jbeg+1)-dl(jbeg))*0.5 170 | do jj=jbeg+1,jend-1 171 | ! somme=somme+prof(jj) 172 | somme=somme+prof(jj)*(dl(jj+1)-dl(jj-1))*0.5 173 | end do 174 | somme=somme+prof(jend)*(dl(jend)-dl(jend-1))*0.5 175 | if (somme.le.0) stop 'problem with profile normalization ...' 176 | do jj=jbeg,jend 177 | prof(jj)=prof(jj)/somme 178 | end do 179 | 180 | ! convolution : f'(ii) = sum (C(j)*f(j)) j = ii-ipad -> ii+ipad 181 | ! somme=0. 182 | somme=prof(jbeg)*F2(kk+jbeg-1-ipad)*(dl(jbeg+1)-dl(jbeg))*0.5 183 | do jj=jbeg+1,jend-1 184 | ! somme=somme+prof(jj)*F2(kk+jj-1-ipad) 185 | somme=somme+prof(jj)*F2(kk+jj-1-ipad)*(dl(jj+1)-dl(jj-1))*0.5 186 | end do 187 | somme=somme+prof(jend)*F2(kk+jend-1-ipad)*(dl(jend)-dl(jend-1))*0.5 188 | Fconv(ii,itype)=somme 189 | deallocate(dl) 190 | deallocate(prof) 191 | end do 192 | print*,'test5' 193 | enddo 194 | 195 | ! print*,'convolution done ! Now writing output ...' 196 | 197 | ! output, with resampling 198 | do ii=1,isize,resample 199 | write(20,200) lambda(ii),Fconv(ii,1:jmax) 200 | end do 201 | 202 | 200 format(f13.4,100(1x,1pe12.5)) 203 | 204 | 205 | end program faltbo 206 | 207 | ! *************************************************************************** 208 | 209 | subroutine gauss(ipad,dl,iprf,FWHM,prof,jbeg,jend) 210 | 211 | ! exponential and gaussian profiles 212 | 213 | implicit none 214 | 215 | integer :: ipad,iprf,i,jbeg,jend 216 | real(kind=kind(1.d0)),dimension(2*ipad+1) :: prof,dl 217 | real(kind=kind(1.d0)) :: FWHM,const,y 218 | 219 | if (iprf==1) const=1.38629/FWHM 220 | if (iprf==2) const=1.66511/FWHM 221 | 222 | ! we require at least the 3 central points of the profile. 223 | jbeg=ipad 224 | jend=ipad+2 225 | 226 | do i=1,2*ipad+1 227 | prof(i)=0. 228 | y=dl(i)*const 229 | if (iprf==1) then 230 | if (exp(-abs(y)).gt.1.e-6) then 231 | prof(i)=exp(-abs(y)) 232 | jbeg=min(jbeg,i) 233 | jend=max(jend,i) 234 | endif 235 | else if (iprf==2) then 236 | if (exp(-y*y).gt.1.e-6) then 237 | prof(i)=exp(-y*y) 238 | jbeg=min(jbeg,i) 239 | jend=max(jend,i) 240 | endif 241 | endif 242 | end do 243 | 244 | return 245 | 246 | end subroutine gauss 247 | 248 | ! *************************************************************************** 249 | 250 | subroutine radtan(ipad,dl,FWHM,prof,jbeg,jend) 251 | 252 | ! radial-tangential profile; macroturbulent velocity = 1.433*FWHM 253 | ! cf. Gray 1978, Solar Phys. 59, 193 254 | 255 | implicit none 256 | 257 | integer :: i,j,ipad,jbeg,jend 258 | real(kind=kind(1.d0)),dimension(2*ipad+1) :: prof,dl 259 | real(kind=kind(1.d0)) :: FWHM,width,delta,di,pp 260 | real(kind=kind(1.d0)),dimension(40),parameter :: rtf = & 261 | (/1.128,.939,.773,.628,.504,.399,.312,.240,.182,.133, & 262 | .101,.070,.052,.037,.024,.017,.012,.010,.009,.007,.006, & 263 | .005,.004,.004,.003,.003,.002,.002,.002,.002,.001,.001, & 264 | .001,.001,.001,.001,.000,.000,.000,.000 /) 265 | 266 | ! delta is the wavelength distance between given RTF points. 267 | width=FWHM*1.433 268 | delta=width/10. 269 | 270 | do j=1,2*ipad+1 271 | prof(j)=0. 272 | end do 273 | 274 | prof(ipad+1)=rtf(1) 275 | 276 | j=ipad+2 277 | di=delta 278 | do i=2,35 279 | di=delta*float(i-1) 280 | do while (dl(j).le.di) 281 | pp=log(rtf(i))+(log(rtf(i-1))-log(rtf(i)))*(di-dl(j))/delta 282 | prof(j)=exp(pp) 283 | jend=j 284 | j=j+1 285 | end do 286 | end do 287 | 288 | j=ipad 289 | do i=2,36 290 | di=delta*float(i-1) 291 | do while (abs(dl(j)).le.di) 292 | pp=log(rtf(i))+(log(rtf(i-1))-log(rtf(i)))*(di-abs(dl(j)))/delta 293 | prof(j)=exp(pp) 294 | jbeg=j 295 | j=j-1 296 | end do 297 | end do 298 | 299 | return 300 | 301 | end subroutine radtan 302 | 303 | ! *************************************************************************** 304 | 305 | subroutine rota(ipad,dl,FWHM,lambda,prof,jbeg,jend) 306 | 307 | ! rotational profile; eps is wavelength dependant linear (in mu) 308 | ! limb-darkening coefficient found for F V -K IV stars (improve !!!) 309 | ! FWHM is v*sin i in wavelength units 310 | 311 | implicit none 312 | 313 | integer :: i,ipad,jprof,nmax,jbeg,jend 314 | real(kind=kind(1.d0)) :: FWHM,dlam,dlambda,lambda,eps 315 | real(kind=kind(1.d0)),dimension(2*ipad+1) :: prof,x 316 | real(kind=kind(1.d0)),dimension(2*ipad) :: dl 317 | real(kind=kind(1.d0)),parameter :: pi = 4.*atan(1.) 318 | 319 | eps=1.-0.3*lambda/5000. 320 | dlambda=FWHM 321 | jbeg=2*ipad+1 322 | jend=1 323 | do i=1,2*ipad+1 324 | if (abs(dl(i)).le.dlambda) then 325 | jbeg=min(jbeg,i) 326 | jend=max(jend,i) 327 | prof(i)=(2.*(1.-eps)*sqrt(1.-(dl(i)/dlambda)**2)+pi*0.5*eps* & 328 | (1.-(dl(i)/dlambda)**2))/(pi*dlambda*(1.-eps/3.)) 329 | endif 330 | end do 331 | 332 | return 333 | 334 | end subroutine rota 335 | 336 | ! *************************************************************************** 337 | 338 | subroutine FTS(FWHM) 339 | 340 | ! FTS profile (sin(x)/x) - from Kurucz- program broaden.f 341 | ! obsviously not ready for use.!! 342 | 343 | implicit none 344 | 345 | real(kind=kind(1.d0)) :: FWHM ! assumed in km/s ... 346 | 347 | ! x=(i-1.)*vstep/FWHM*2.*1.8954942 348 | ! red(i)=sin(x)/x*exp(-0.06*x**2) 349 | 350 | return 351 | 352 | end subroutine FTS 353 | -------------------------------------------------------------------------------- /scripts/run_wrapper.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import pickle 4 | from .turbospectrum_class_nlte import TurboSpectrum 5 | from .m3dis_class import M3disCall 6 | from .convolve import * 7 | import datetime 8 | import shutil 9 | import os 10 | from .solar_abundances import solar_abundances 11 | from .auxiliary_functions import calculate_vturb, import_module_from_path 12 | 13 | 14 | def run_wrapper(ts_config, spectrum_name, teff, logg, met, lmin, lmax, ldelta, nlte_flag, abundances_dict, resolution=0, 15 | macro=0, rotation=0, vmic=None, verbose=False, lpoint_turbospectrum=500_000, **kwargs): 16 | #parameters to adjust 17 | 18 | teff = teff 19 | logg = logg 20 | met = met 21 | if vmic is None: 22 | vmic = calculate_vturb(teff, logg, met) 23 | #print(vturb) 24 | #vturb = 0.9 25 | lmin = lmin 26 | lmax = lmax 27 | ldelta = ldelta 28 | temp_directory = os.path.join(ts_config["global_temporary_directory"], 29 | f"temp_directory_{datetime.datetime.now().strftime('%b-%d-%Y-%H-%M-%S')}__{np.random.random(1)[0]}", "") 30 | 31 | abundances_dict_xh = abundances_dict.copy() 32 | 33 | # need to convert abundances_dict from X/Fe to X/H 34 | for key, value in abundances_dict_xh.items(): 35 | abundances_dict_xh[key] = value + met 36 | 37 | if not os.path.exists(temp_directory): 38 | os.makedirs(temp_directory) 39 | 40 | if not ts_config["m3dis_flag"]: 41 | ssg = TurboSpectrum( 42 | turbospec_path=ts_config["turbospec_path"], 43 | interpol_path=ts_config["interpol_path"], 44 | line_list_paths=ts_config["line_list_paths"], 45 | marcs_grid_path=ts_config["model_atmosphere_grid_path"], 46 | marcs_grid_list=ts_config["model_atmosphere_grid_list"], 47 | model_atom_path=ts_config["model_atom_path"], 48 | departure_file_path=ts_config["departure_file_path"], 49 | aux_file_length_dict=ts_config["aux_file_length_dict"], 50 | model_temperatures=ts_config["model_temperatures"], 51 | model_logs=ts_config["model_logs"], 52 | model_mets=ts_config["model_mets"], 53 | marcs_value_keys=ts_config["marcs_value_keys"], 54 | marcs_models=ts_config["marcs_models"], 55 | marcs_values=ts_config["marcs_values"],) 56 | else: 57 | ssg = M3disCall( 58 | m3dis_path=ts_config["turbospec_path"], 59 | interpol_path=ts_config["interpol_path"], 60 | line_list_paths=ts_config["line_list_paths"], 61 | marcs_grid_path=ts_config["model_atmosphere_grid_path"], 62 | marcs_grid_list=ts_config["model_atmosphere_grid_list"], 63 | model_atom_path=ts_config["model_atom_path"], 64 | departure_file_path=ts_config["departure_file_path"], 65 | aux_file_length_dict=ts_config["aux_file_length_dict"], 66 | model_temperatures=ts_config["model_temperatures"], 67 | model_logs=ts_config["model_logs"], 68 | model_mets=ts_config["model_mets"], 69 | marcs_value_keys=ts_config["marcs_value_keys"], 70 | marcs_models=ts_config["marcs_models"], 71 | marcs_values=ts_config["marcs_values"], 72 | m3dis_python_module=import_module_from_path("m3dis.m3dis", ts_config["m3dis_python_module"]), 73 | n_nu=ts_config["m3dis_n_nu"], 74 | hash_table_size=ts_config["m3dis_hash_table_size"], 75 | mpi_cores=ts_config["m3dis_mpi_cores"], 76 | iterations_max=ts_config["m3dis_iterations_max"], 77 | convlim=ts_config["m3dis_convlim"], 78 | snap=ts_config["m3dis_snap"], 79 | dims=ts_config["m3dis_dims"], 80 | nx=ts_config["m3dis_nx"], 81 | ny=ts_config["m3dis_ny"], 82 | nz=ts_config["m3dis_nz"]) 83 | ssg.use_precomputed_depart = False 84 | 85 | # TODO: support for intensity in m3dis 86 | ts_config["compute_intensity_flag"] = False 87 | 88 | ssg.configure(t_eff=teff, log_g=logg, metallicity=met, 89 | turbulent_velocity=vmic, lambda_delta=ldelta, lambda_min=lmin, lambda_max=lmax, 90 | free_abundances=abundances_dict_xh, temp_directory=temp_directory, nlte_flag=nlte_flag, 91 | verbose=verbose, 92 | atmosphere_dimension=ts_config["atmosphere_type"], 93 | windows_flag=ts_config["windows_flag"], 94 | segment_file=ts_config["segment_file"], 95 | line_mask_file=ts_config["line_mask_file"], 96 | depart_bin_file=ts_config["depart_bin_file"], 97 | depart_aux_file=ts_config["depart_aux_file"], 98 | model_atom_file=ts_config["model_atom_file"]) 99 | 100 | ssg.compute_intensity_flag = ts_config["compute_intensity_flag"] 101 | ssg.mupoint_path = ts_config["mupoint_path"] 102 | 103 | ssg.lpoint = lpoint_turbospectrum 104 | 105 | results = ssg.synthesize_spectra() 106 | 107 | shutil.rmtree(temp_directory) 108 | 109 | if ts_config["compute_intensity_flag"]: 110 | wavelength, intensities = results 111 | return wavelength, intensities, [] 112 | else: 113 | wave_mod_orig, flux_norm_mod_orig, flux_mod_orig = results 114 | 115 | 116 | try: 117 | if ts_config["windows_flag"]: 118 | seg_begins, seg_ends = np.loadtxt(ts_config['segment_file'], comments = ";", usecols=(0,1), unpack=True) 119 | wave_mod_filled = [] 120 | flux_norm_mod_filled = [] 121 | flux_mod_filled = [] 122 | for i in range(len(seg_begins)): 123 | j = 0 124 | while wave_mod_orig[j] < seg_begins[i]: 125 | j+=1 126 | while wave_mod_orig[j] >= seg_begins[i] and wave_mod_orig[j] <= seg_ends[i]: 127 | wave_mod_filled.append(wave_mod_orig[j]) 128 | flux_norm_mod_filled.append(flux_norm_mod_orig[j]) 129 | flux_mod_filled.append(flux_mod_orig[j]) 130 | j+=1 131 | if i < len(seg_begins)-1: 132 | k = 1 133 | while (seg_begins[i+1] - 0.001 > seg_ends[i]+k*0.005): 134 | wave_mod_filled.append(seg_ends[i]+0.005*k) 135 | flux_norm_mod_filled.append(1.0) 136 | flux_mod_filled.append(np.mean(flux_mod_orig)) 137 | k+=1 138 | else: 139 | wave_mod_filled = wave_mod_orig 140 | flux_norm_mod_filled = flux_norm_mod_orig 141 | flux_mod_filled = flux_mod_orig 142 | 143 | if resolution != 0.0: 144 | wave_mod_conv, flux_norm_mod_conv = conv_res(wave_mod_filled, flux_norm_mod_filled, resolution) 145 | wave_mod_conv, flux_mod_conv = conv_res(wave_mod_filled, flux_mod_filled, resolution) 146 | else: 147 | wave_mod_conv = wave_mod_filled 148 | flux_norm_mod_conv = flux_norm_mod_filled 149 | flux_mod_conv = flux_mod_filled 150 | 151 | if macro != 0.0: 152 | wave_mod_macro, flux_norm_mod_macro = conv_macroturbulence(wave_mod_conv, flux_norm_mod_conv, macro) 153 | wave_mod_macro, flux_mod_macro = conv_macroturbulence(wave_mod_conv, flux_mod_conv, macro) 154 | else: 155 | wave_mod_macro = wave_mod_conv 156 | flux_norm_mod_macro = flux_norm_mod_conv 157 | flux_mod_macro = flux_mod_conv 158 | 159 | if rotation != 0.0: 160 | wave_mod, flux_norm_mod = conv_rotation(wave_mod_macro, flux_norm_mod_macro, rotation) 161 | wave_mod, flux_mod = conv_rotation(wave_mod_macro, flux_mod_macro, rotation) 162 | else: 163 | wave_mod = wave_mod_macro 164 | flux_norm_mod = flux_norm_mod_macro 165 | flux_mod = flux_mod_macro 166 | except (FileNotFoundError, OSError, ValueError) as err: 167 | print(f"FileNotFoundError: {spectrum_name}. Failed to generate spectrum. Error: {err}") 168 | wave_mod, flux_norm_mod, flux_mod = [], [], [] 169 | 170 | return wave_mod, flux_norm_mod, flux_mod 171 | 172 | 173 | def run_and_save_wrapper(tsfitpy_pickled_configuration_path, teff, logg, met, lmin, lmax, ldelta, spectrum_name, nlte_flag, resolution, macro, rotation, new_directory_to_save_to, vturb, abundances_dict: dict, save_unnormalised_spectra, verbose, lpoint_turbospectrum): 174 | with open(tsfitpy_pickled_configuration_path, 'rb') as f: 175 | ts_config = pickle.load(f) 176 | 177 | wave_mod, flux_norm_mod, flux_mod = run_wrapper(ts_config, spectrum_name, teff, logg, met, lmin, lmax, ldelta, nlte_flag, abundances_dict, resolution, macro, rotation, vturb, verbose=verbose, lpoint_turbospectrum=lpoint_turbospectrum) 178 | file_location_output = os.path.join(new_directory_to_save_to, f"{spectrum_name}") 179 | if wave_mod is not None and len(wave_mod) > 0: 180 | f = open(file_location_output, 'w') 181 | 182 | # save the parameters used to generate the spectrum 183 | # print when spectra was generated 184 | print("#Generated using TurboSpectrum and TSFitPy wrapper", file=f) 185 | print("#date: {}".format(datetime.datetime.now()), file=f) 186 | print("#spectrum_name: {}".format(spectrum_name), file=f) 187 | print("#teff: {}".format(teff), file=f) 188 | print("#logg: {}".format(logg), file=f) 189 | print("#[Fe/H]: {}".format(met), file=f) 190 | if vturb is None: 191 | vturb = calculate_vturb(teff, logg, met) 192 | print("#vmic: {}".format(vturb), file=f) 193 | print("#vmac: {}".format(macro), file=f) 194 | print("#resolution: {}".format(resolution), file=f) 195 | print("#rotation: {}".format(rotation), file=f) 196 | print("#nlte_flag: {}".format(nlte_flag), file=f) 197 | 198 | # get which elements are in NLTE using ts_config["model_atom_file"] 199 | nlte_elements = ts_config["model_atom_file"].keys() 200 | 201 | for element, value in abundances_dict.items(): 202 | if nlte_flag: 203 | if element in nlte_elements: 204 | nlte_flag_label = "NLTE" 205 | else: 206 | nlte_flag_label = "LTE" 207 | else: 208 | nlte_flag_label = "LTE" 209 | if element != "Fe": 210 | print(f"#[{element}/Fe]={value:.4f} {nlte_flag_label}", file=f) 211 | else: 212 | # if Fe, it is given as weird Fe/Fe way, which can be fixed back by: 213 | # xfe + feh + A(X)_sun = A(X)_star 214 | print(f"#A({element})={value + met + solar_abundances['Fe']:.4f} {nlte_flag_label}", file=f) 215 | 216 | # also print NLTE elements that are not in the abundances_dict 217 | if nlte_flag: 218 | for element in nlte_elements: 219 | if element not in abundances_dict.keys(): 220 | if element != "Fe" or element != "H": 221 | print(f"#[{element}/Fe]=0.0 (solar scaled) NLTE", file=f) 222 | elif element == "H": 223 | print(f"#A({element})=12.0 NLTE", file=f) 224 | elif element == "Fe": 225 | print(f"#[Fe/H]={met:.4f} NLTE", file=f) 226 | 227 | print("#", file=f) 228 | 229 | if save_unnormalised_spectra and not ts_config["compute_intensity_flag"]: 230 | print("#Wavelength Normalised_flux Unnormalised_flux", file=f) 231 | for i in range(len(wave_mod)): 232 | print("{} {} {}".format(wave_mod[i], flux_norm_mod[i], flux_mod[i]), file=f) 233 | elif not ts_config["compute_intensity_flag"]: 234 | print("#Wavelength Normalised_flux", file=f) 235 | for i in range(len(wave_mod)): 236 | print("{} {}".format(wave_mod[i], flux_norm_mod[i]), file=f) 237 | else: 238 | print("#Wavelength Intensities", file=f) 239 | # Example: flux_norm_mod is 1D 240 | if flux_norm_mod.ndim == 1: 241 | for i in range(len(wave_mod)): 242 | print(f"{wave_mod[i]} {flux_norm_mod[i]}", file=f) 243 | # Example: flux_norm_mod is 2D (multiple columns) 244 | elif flux_norm_mod.ndim == 2: 245 | for i in range(len(wave_mod)): 246 | # Convert the row of flux values into strings, separated by spaces 247 | flux_str = " ".join(str(val) for val in flux_norm_mod[i]) 248 | print(f"{wave_mod[i]} {flux_str}", file=f) 249 | f.close() 250 | return spectrum_name 251 | else: 252 | return "" 253 | -------------------------------------------------------------------------------- /unittests/unit_test.py: -------------------------------------------------------------------------------- 1 | import os 2 | import shutil 3 | import unittest 4 | 5 | import scripts.auxiliary_functions 6 | import scripts.curve_of_growth 7 | from scripts import TSFitPy 8 | import numpy as np 9 | from scripts import turbospectrum_class_nlte 10 | from scripts.create_window_linelist_function import create_window_linelist 11 | 12 | class MyTestCase(unittest.TestCase): 13 | # TODO: more unittests? 14 | 15 | def test_segment_creation(self): 16 | # tests if the segments are created correctly in TSFitPy.create_segments 17 | segment_size = 5 18 | wavelength_start = [4200.0, 4201.0, 4202.0, 4220.0, 4240.0] 19 | wavelength_end = [4201.0, 4202.0, 4203.0, 4221.0, 4241.0] 20 | segment_left, segment_right = scripts.auxiliary_functions.create_segment_file(segment_size, wavelength_start, wavelength_end) 21 | segment_left = list(segment_left) 22 | segment_right = list(segment_right) 23 | 24 | self.assertListEqual(segment_left, [4195.0, 4215.0, 4235.0]) 25 | self.assertListEqual(segment_right, [4208.0, 4226.0, 4246.0]) 26 | 27 | wavelength_start = [4200.0] 28 | wavelength_end = [4201.0] 29 | segment_left, segment_right = scripts.auxiliary_functions.create_segment_file(segment_size, wavelength_start, wavelength_end) 30 | segment_left = list(segment_left) 31 | segment_right = list(segment_right) 32 | 33 | self.assertListEqual(segment_left, [4195.0]) 34 | self.assertListEqual(segment_right, [4206.0]) 35 | 36 | def test_create_window_linst_linelist_function(self): 37 | def compare_files_ignore_consecutive_spaces(file1, file2): 38 | with open(file1, 'r') as f1, open(file2, 'r') as f2: 39 | lines1 = [' '.join(line.split()) for line in f1.readlines()] 40 | lines2 = [' '.join(line.split()) for line in f2.readlines()] 41 | 42 | if len(lines1) != len(lines2): 43 | return False 44 | 45 | for line1, line2 in zip(lines1, lines2): 46 | if line1 != line2: 47 | return False 48 | 49 | return True 50 | 51 | lmin, lmax = 4200.0, 4205.0 52 | 53 | # remove directory if it exists 54 | if os.path.exists("unittests/linelist_testing/test_output/0/"): 55 | shutil.rmtree("unittests/linelist_testing/test_output/0/") 56 | 57 | create_window_linelist([lmin], [lmax], "unittests/linelist_testing/", "unittests/linelist_testing/test_output/", molecules_flag=True, lbl=True) 58 | print(os.getcwd()) 59 | self.assertTrue(compare_files_ignore_consecutive_spaces("unittests/linelist_testing/expected_result/atomic_test_data_expected", "unittests/linelist_testing/test_output/0/linelist-0.bsyn")) 60 | self.assertTrue(compare_files_ignore_consecutive_spaces("unittests/linelist_testing/expected_result/molecular_test_data_expected", "unittests/linelist_testing/test_output/0/linelist-3.bsyn")) 61 | # get number of files in directory 62 | num_files = len([f for f in os.listdir("unittests/linelist_testing/test_output/0/") if os.path.isfile(os.path.join("unittests/linelist_testing/test_output/0/", f))]) 63 | self.assertEqual(2, num_files) 64 | 65 | shutil.rmtree("unittests/linelist_testing/test_output/0/") 66 | 67 | # check that molecules are not included 68 | create_window_linelist([lmin], [lmax], "unittests/linelist_testing/", "unittests/linelist_testing/test_output/", 69 | molecules_flag=False, lbl=True) 70 | 71 | num_files = len([f for f in os.listdir("unittests/linelist_testing/test_output/0/") if 72 | os.path.isfile(os.path.join("unittests/linelist_testing/test_output/0/", f))]) 73 | self.assertEqual(1, num_files) 74 | 75 | shutil.rmtree("unittests/linelist_testing/test_output/0/") 76 | 77 | def test_get_simplex_guess(self): 78 | for i in range(1000): 79 | initial_guess, bounds = TSFitPy.Spectra.get_simplex_guess(1, -10, 10, -5, 5) 80 | self.assertTupleEqual((-5, 5), bounds) 81 | self.assertLess(initial_guess[1], bounds[1]) 82 | self.assertGreater(initial_guess[0], bounds[0]) 83 | for i in range(1000): 84 | initial_guess, bounds = TSFitPy.Spectra.get_simplex_guess(1, -3, 3, -5, 5) 85 | self.assertTupleEqual((-5, 5), bounds) 86 | self.assertLess(initial_guess[1], 3) 87 | self.assertGreater(initial_guess[0], -3) 88 | 89 | def test_calculate_vturb(self): 90 | self.assertAlmostEqual(scripts.auxiliary_funciton.calculate_vturb(5777, 4.44, 0.0), 1.0, delta=0.1) 91 | 92 | def test_chi_square_lbl(self): 93 | wave_obs = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) 94 | flux_obs = np.array([1, 0.9, .8, .9, 1, 1, 1, 1, 1, 1]) 95 | wave_mod_orig = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) 96 | flux_mod_orig = np.array([1, 0.9, .8, .9, 1, 1, 1, 1, 1, 1]) 97 | fwhm, macro, rot = 0, 0, 0 98 | lmax, lmin = 5000, -10 99 | res = TSFitPy.calculate_lbl_chi_squared(None, wave_obs, flux_obs, wave_mod_orig, flux_mod_orig, fwhm, lmin, 100 | lmax, macro, rot, save_convolved=False) 101 | self.assertAlmostEqual(0, res) 102 | 103 | wave_obs = np.array([1, 2, 3, 4, 5, ]) 104 | flux_mod_orig = np.array([11.8, 24.67, 39.15, 48.81, 30.57]) # expected 105 | wave_mod_orig = np.array([1, 2, 3, 4, 5, ]) 106 | flux_obs = np.array([17, 25, 39, 42, 32]) # observed 107 | res = TSFitPy.calculate_lbl_chi_squared(None, wave_obs, flux_obs, wave_mod_orig, flux_mod_orig, fwhm, lmin, 108 | lmax, macro, rot, save_convolved=False) 109 | self.assertAlmostEqual(3.314, res, places=3) # done by hand to check 110 | 111 | wave_obs = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) 112 | flux_obs = np.array([1, 0.9, .8, .9, 1, 1, 1, 1, 1, 1.1]) 113 | wave_mod_orig = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) 114 | flux_mod_orig = np.array([1, 0.9, .8, .9, 1, 1, 1, 1, 1, 1]) 115 | res = TSFitPy.calculate_lbl_chi_squared(None, wave_obs, flux_obs, wave_mod_orig, flux_mod_orig, fwhm, lmin, 116 | lmax, macro, rot, save_convolved=False) 117 | self.assertAlmostEqual(0.01 / 1.0, res) 118 | 119 | wave_obs = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) 120 | flux_obs = np.array([1, 0.9, .8, .9, 1, 1, 1, 1, 1, 1.0]) 121 | wave_mod_orig = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) 122 | flux_mod_orig = np.array([1, 0.9, .8, .9, 1, 1, 1, 1, 1, 1.1]) 123 | res = TSFitPy.calculate_lbl_chi_squared(None, wave_obs, flux_obs, wave_mod_orig, flux_mod_orig, fwhm, lmin, 124 | lmax, macro, rot, save_convolved=False) 125 | self.assertAlmostEqual(0.01 / 1.1, res) 126 | 127 | wave_obs = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) 128 | flux_obs = np.array([1, 0.8, .7, .8, 1.1, 1.2, 0.7, 1.4, 1.2, 1.0]) 129 | wave_mod_orig = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) 130 | flux_mod_orig = np.array([1, 0.9, .8, .9, 1, 1, 1, 1, 1, 1.1]) 131 | res = TSFitPy.calculate_lbl_chi_squared(None, wave_obs, flux_obs, wave_mod_orig, flux_mod_orig, fwhm, lmin, 132 | lmax, macro, rot, save_convolved=False) 133 | self.assertAlmostEqual(0.3838131313131312, res) 134 | 135 | rot = 100000 136 | wave_obs = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) 137 | flux_obs = np.array([1, 0.8, .7, .8, 1.1, 1.2, 0.7, 1.4, 1.2, 1.0]) 138 | wave_mod_orig = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) 139 | flux_mod_orig = np.array([1, 0.9, .8, .9, 1, 1, 1, 1, 1, 1.1]) 140 | res = TSFitPy.calculate_lbl_chi_squared(None, wave_obs, flux_obs, wave_mod_orig, flux_mod_orig, fwhm, lmin, 141 | lmax, macro, rot, save_convolved=False) 142 | self.assertAlmostEqual(0.3674679979008318, res) 143 | 144 | rot = 200000 145 | wave_obs = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) 146 | flux_obs = np.array([1, 0.8, .7, .8, 1.1, 1.2, 0.7, 1.4, 1.2, 1.0]) 147 | wave_mod_orig = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) 148 | flux_mod_orig = np.array([1, 0.9, .8, .9, 1, 1, 1, 1, 1, 1.1]) 149 | res = TSFitPy.calculate_lbl_chi_squared(None, wave_obs, flux_obs, wave_mod_orig, flux_mod_orig, fwhm, lmin, 150 | lmax, macro, rot, save_convolved=False) 151 | self.assertAlmostEqual(0.386082941394771, res) 152 | 153 | def test_load_nlte_files_in_dict(self): 154 | elems = ["Eu", "Fe"] 155 | files1 = ["Eu1", "Fe1"] 156 | files2 = ["Eu2", "Fe2"] 157 | files3 = ["Eu3", "Fe3"] 158 | 159 | expec_dict1 = {"Eu": "Eu1", "Fe": "Fe1"} 160 | expec_dict2 = {"Eu": "Eu2", "Fe": "Fe2"} 161 | expec_dict3 = {"Eu": "Eu3", "Fe": "Fe3"} 162 | 163 | dict1, dict2, dict3 = scripts.curve_of_growth.load_nlte_files_in_dict(elems, files1, files2, files3, True) 164 | self.assertDictEqual(expec_dict1, dict1) 165 | self.assertDictEqual(expec_dict2, dict2) 166 | self.assertDictEqual(expec_dict3, dict3) 167 | 168 | elems = ["Fe", "Eu"] 169 | files1 = ["Fe1", "Eu1"] 170 | files2 = ["Fe2", "Eu2"] 171 | files3 = ["Fe3", "Eu3"] 172 | 173 | expec_dict1 = {"Fe": "Fe1", "Eu": "Eu1"} 174 | expec_dict2 = {"Fe": "Fe2", "Eu": "Eu2"} 175 | expec_dict3 = {"Fe": "Fe3", "Eu": "Eu3"} 176 | 177 | dict1, dict2, dict3 = scripts.curve_of_growth.load_nlte_files_in_dict(elems, files1, files2, files3, True) 178 | self.assertDictEqual(expec_dict1, dict1) 179 | self.assertDictEqual(expec_dict2, dict2) 180 | self.assertDictEqual(expec_dict3, dict3) 181 | 182 | elems = ["Eu", "Fe5"] 183 | files1 = ["Eu1", "Fe1", "Fe01"] 184 | files2 = ["Eu2", "Fe2", "Fe02"] 185 | files3 = ["Eu3", "Fe3", "Fe03"] 186 | 187 | expec_dict1 = {"Eu": "Eu1", "Fe5": "Fe1", "Fe": "Fe01"} 188 | expec_dict2 = {"Eu": "Eu2", "Fe5": "Fe2", "Fe": "Fe02"} 189 | expec_dict3 = {"Eu": "Eu3", "Fe5": "Fe3", "Fe": "Fe03"} 190 | 191 | dict1, dict2, dict3 = scripts.curve_of_growth.load_nlte_files_in_dict(elems, files1, files2, files3, False) 192 | self.assertDictEqual(expec_dict1, dict1) 193 | self.assertDictEqual(expec_dict2, dict2) 194 | self.assertDictEqual(expec_dict3, dict3) 195 | 196 | elems = ["Fe5", "Eu"] 197 | files1 = ["Fe1", "Eu1", "Fe01"] 198 | files2 = ["Fe2", "Eu2", "Fe02"] 199 | files3 = ["Fe3", "Eu3", "Fe03"] 200 | 201 | expec_dict1 = {"Fe5": "Fe1", "Eu": "Eu1", "Fe": "Fe01"} 202 | expec_dict2 = {"Fe5": "Fe2", "Eu": "Eu2", "Fe": "Fe02"} 203 | expec_dict3 = {"Fe5": "Fe3", "Eu": "Eu3", "Fe": "Fe03"} 204 | 205 | dict1, dict2, dict3 = scripts.curve_of_growth.load_nlte_files_in_dict(elems, files1, files2, files3, False) 206 | self.assertDictEqual(expec_dict1, dict1) 207 | self.assertDictEqual(expec_dict2, dict2) 208 | self.assertDictEqual(expec_dict3, dict3) 209 | 210 | elems = ["Fe5", "Eu"] 211 | files1 = ["Fe1", "Fe01"] 212 | files2 = ["Fe2", "Fe02"] 213 | files3 = ["Fe3", "Fe03"] 214 | 215 | expec_dict1 = {"Fe5": "Fe1", "Eu": "", "Fe": "Fe01"} 216 | expec_dict2 = {"Fe5": "Fe2", "Eu": "", "Fe": "Fe02"} 217 | expec_dict3 = {"Fe5": "Fe3", "Eu": "", "Fe": "Fe03"} 218 | 219 | dict1, dict2, dict3 = scripts.curve_of_growth.load_nlte_files_in_dict(elems, files1, files2, files3, False) 220 | self.assertDictEqual(expec_dict1, dict1) 221 | self.assertDictEqual(expec_dict2, dict2) 222 | self.assertDictEqual(expec_dict3, dict3) 223 | 224 | def test_second_degree(self): 225 | a, b, c = scripts.auxiliary_functions.get_second_degree_polynomial([1, 2, 3], [1, 4, 9]) 226 | func = lambda t: a * t * t + b * t + c 227 | self.assertEqual(25, func(5)) 228 | self.assertEqual(25, func(-5)) 229 | 230 | a, b, c = scripts.auxiliary_functions.get_second_degree_polynomial([1, 2, 3], [2, 5, 10]) 231 | func = lambda t: a * t * t + b * t + c 232 | self.assertEqual(26, func(5)) 233 | self.assertEqual(26, func(-5)) 234 | 235 | def test_closest_available_value(self): 236 | self.assertEqual(scripts.auxiliary_functions.closest_available_value(1, [0, 2.5, 5, 10]), 0) 237 | self.assertEqual(scripts.auxiliary_functions.closest_available_value(5, [0, 2.5, 5, 10]), 5) 238 | self.assertEqual(scripts.auxiliary_functions.closest_available_value(-10, [0, 2.5, 5, 10]), 0) 239 | self.assertEqual(scripts.auxiliary_functions.closest_available_value(100, [0, 2.5, 5, 10]), 10) 240 | self.assertEqual(scripts.auxiliary_functions.closest_available_value(7, [0, 2.5, 5, 10]), 5) 241 | self.assertEqual(scripts.auxiliary_functions.closest_available_value(8, [0, 2.5, 5, 10]), 10) 242 | 243 | 244 | if __name__ == '__main__': 245 | unittest.main() 246 | -------------------------------------------------------------------------------- /input_files/model_atmospheres/3D/model_atmosphere_list.txt: -------------------------------------------------------------------------------- 1 | 4500_g+3.0_m0.0_t02_st_z+0.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 2 | 4500_g+3.0_m0.0_t02_st_z+0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 3 | 4500_g+3.0_m0.0_t02_st_z-0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 4 | 4500_g+3.0_m0.0_t02_st_z-1.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 5 | 4500_g+3.0_m0.0_t02_st_z-2.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 6 | 4500_g+3.0_m0.0_t02_st_z-3.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 7 | 4500_g+3.5_m0.0_t02_st_z+0.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 8 | 4500_g+3.5_m0.0_t02_st_z+0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 9 | 4500_g+3.5_m0.0_t02_st_z-0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 10 | 4500_g+3.5_m0.0_t02_st_z-1.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 11 | 4500_g+3.5_m0.0_t02_st_z-2.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 12 | 4500_g+3.5_m0.0_t02_st_z-3.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 13 | 4500_g+3.5_m0.0_t02_st_z-4.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 14 | 4500_g+4.0_m0.0_t02_st_z+0.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 15 | 4500_g+4.0_m0.0_t02_st_z+0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 16 | 4500_g+4.0_m0.0_t02_st_z-0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 17 | 4500_g+4.0_m0.0_t02_st_z-1.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 18 | 4500_g+4.0_m0.0_t02_st_z-2.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 19 | 4500_g+4.0_m0.0_t02_st_z-3.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 20 | 4500_g+4.0_m0.0_t02_st_z-4.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 21 | 4500_g+4.5_m0.0_t02_st_z+0.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 22 | 4500_g+4.5_m0.0_t02_st_z+0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 23 | 4500_g+4.5_m0.0_t02_st_z-0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 24 | 4500_g+4.5_m0.0_t02_st_z-1.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 25 | 4500_g+4.5_m0.0_t02_st_z-2.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 26 | 4500_g+4.5_m0.0_t02_st_z-3.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 27 | 4500_g+4.5_m0.0_t02_st_z-4.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 28 | 4500_g+5.0_m0.0_t02_st_z+0.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 29 | 4500_g+5.0_m0.0_t02_st_z+0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 30 | 4500_g+5.0_m0.0_t02_st_z-0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 31 | 4500_g+5.0_m0.0_t02_st_z-1.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 32 | 4500_g+5.0_m0.0_t02_st_z-2.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 33 | 4500_g+5.0_m0.0_t02_st_z-3.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 34 | 4500_g+5.0_m0.0_t02_st_z-4.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 35 | 5000_g+3.0_m0.0_t02_st_z+0.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 36 | 5000_g+3.0_m0.0_t02_st_z+0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 37 | 5000_g+3.0_m0.0_t02_st_z-0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 38 | 5000_g+3.0_m0.0_t02_st_z-1.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 39 | 5000_g+3.0_m0.0_t02_st_z-2.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 40 | 5000_g+3.0_m0.0_t02_st_z-3.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 41 | 5000_g+3.0_m0.0_t02_st_z-4.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 42 | 5000_g+3.5_m0.0_t02_st_z+0.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 43 | 5000_g+3.5_m0.0_t02_st_z+0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 44 | 5000_g+3.5_m0.0_t02_st_z-0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 45 | 5000_g+3.5_m0.0_t02_st_z-1.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 46 | 5000_g+3.5_m0.0_t02_st_z-2.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 47 | 5000_g+3.5_m0.0_t02_st_z-3.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 48 | 5000_g+3.5_m0.0_t02_st_z-4.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 49 | 5000_g+4.0_m0.0_t02_st_z+0.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 50 | 5000_g+4.0_m0.0_t02_st_z+0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 51 | 5000_g+4.0_m0.0_t02_st_z-0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 52 | 5000_g+4.0_m0.0_t02_st_z-1.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 53 | 5000_g+4.0_m0.0_t02_st_z-2.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 54 | 5000_g+4.0_m0.0_t02_st_z-3.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 55 | 5000_g+4.0_m0.0_t02_st_z-4.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 56 | 5000_g+4.5_m0.0_t02_st_z+0.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 57 | 5000_g+4.5_m0.0_t02_st_z+0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 58 | 5000_g+4.5_m0.0_t02_st_z-0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 59 | 5000_g+4.5_m0.0_t02_st_z-1.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 60 | 5000_g+4.5_m0.0_t02_st_z-2.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 61 | 5000_g+4.5_m0.0_t02_st_z-3.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 62 | 5000_g+4.5_m0.0_t02_st_z-4.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 63 | 5000_g+5.0_m0.0_t02_st_z+0.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 64 | 5000_g+5.0_m0.0_t02_st_z+0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 65 | 5000_g+5.0_m0.0_t02_st_z-0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 66 | 5000_g+5.0_m0.0_t02_st_z-1.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 67 | 5000_g+5.0_m0.0_t02_st_z-2.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 68 | 5000_g+5.0_m0.0_t02_st_z-3.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 69 | 5000_g+5.0_m0.0_t02_st_z-4.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 70 | 5500_g+3.0_m0.0_t02_st_z+0.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 71 | 5500_g+3.0_m0.0_t02_st_z-0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 72 | 5500_g+3.0_m0.0_t02_st_z-1.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 73 | 5500_g+3.0_m0.0_t02_st_z-2.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 74 | 5500_g+3.0_m0.0_t02_st_z-3.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 75 | 5500_g+3.0_m0.0_t02_st_z-4.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 76 | 5500_g+3.5_m0.0_t02_st_z+0.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 77 | 5500_g+3.5_m0.0_t02_st_z+0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 78 | 5500_g+3.5_m0.0_t02_st_z-0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 79 | 5500_g+3.5_m0.0_t02_st_z-1.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 80 | 5500_g+3.5_m0.0_t02_st_z-2.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 81 | 5500_g+3.5_m0.0_t02_st_z-3.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 82 | 5500_g+3.5_m0.0_t02_st_z-4.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 83 | 5500_g+4.0_m0.0_t02_st_z+0.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 84 | 5500_g+4.0_m0.0_t02_st_z+0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 85 | 5500_g+4.0_m0.0_t02_st_z-0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 86 | 5500_g+4.0_m0.0_t02_st_z-1.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 87 | 5500_g+4.0_m0.0_t02_st_z-2.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 88 | 5500_g+4.0_m0.0_t02_st_z-3.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 89 | 5500_g+4.0_m0.0_t02_st_z-4.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 90 | 5500_g+4.5_m0.0_t02_st_z+0.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 91 | 5500_g+4.5_m0.0_t02_st_z+0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 92 | 5500_g+4.5_m0.0_t02_st_z-0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 93 | 5500_g+4.5_m0.0_t02_st_z-1.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 94 | 5500_g+4.5_m0.0_t02_st_z-2.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 95 | 5500_g+4.5_m0.0_t02_st_z-3.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 96 | 5500_g+4.5_m0.0_t02_st_z-4.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 97 | 5500_g+5.0_m0.0_t02_st_z+0.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 98 | 5500_g+5.0_m0.0_t02_st_z+0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 99 | 5500_g+5.0_m0.0_t02_st_z-0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 100 | 5500_g+5.0_m0.0_t02_st_z-1.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 101 | 5500_g+5.0_m0.0_t02_st_z-2.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 102 | 5500_g+5.0_m0.0_t02_st_z-3.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 103 | 5500_g+5.0_m0.0_t02_st_z-4.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 104 | 6000_g+3.5_m0.0_t02_st_z+0.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 105 | 6000_g+3.5_m0.0_t02_st_z+0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 106 | 6000_g+3.5_m0.0_t02_st_z-0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 107 | 6000_g+3.5_m0.0_t02_st_z-1.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 108 | 6000_g+3.5_m0.0_t02_st_z-2.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 109 | 6000_g+3.5_m0.0_t02_st_z-3.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 110 | 6000_g+3.5_m0.0_t02_st_z-4.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 111 | 6000_g+4.0_m0.0_t02_st_z+0.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 112 | 6000_g+4.0_m0.0_t02_st_z+0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 113 | 6000_g+4.0_m0.0_t02_st_z-0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 114 | 6000_g+4.0_m0.0_t02_st_z-1.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 115 | 6000_g+4.0_m0.0_t02_st_z-2.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 116 | 6000_g+4.0_m0.0_t02_st_z-3.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 117 | 6000_g+4.0_m0.0_t02_st_z-4.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 118 | 6000_g+4.5_m0.0_t02_st_z+0.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 119 | 6000_g+4.5_m0.0_t02_st_z+0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 120 | 6000_g+4.5_m0.0_t02_st_z-0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 121 | 6000_g+4.5_m0.0_t02_st_z-1.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 122 | 6000_g+4.5_m0.0_t02_st_z-2.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 123 | 6000_g+4.5_m0.0_t02_st_z-3.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 124 | 6000_g+4.5_m0.0_t02_st_z-4.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 125 | 6500_g+4.0_m0.0_t02_st_z+0.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 126 | 6500_g+4.0_m0.0_t02_st_z+0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 127 | 6500_g+4.0_m0.0_t02_st_z-0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 128 | 6500_g+4.0_m0.0_t02_st_z-1.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 129 | 6500_g+4.0_m0.0_t02_st_z-2.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 130 | 6500_g+4.0_m0.0_t02_st_z-3.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 131 | 6500_g+4.0_m0.0_t02_st_z-4.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 132 | 6500_g+4.5_m0.0_t02_st_z+0.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 133 | 6500_g+4.5_m0.0_t02_st_z+0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 134 | 6500_g+4.5_m0.0_t02_st_z-0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 135 | 6500_g+4.5_m0.0_t02_st_z-1.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 136 | 6500_g+4.5_m0.0_t02_st_z-2.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 137 | 6500_g+4.5_m0.0_t02_st_z-3.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 138 | 6500_g+4.5_m0.0_t02_st_z-4.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 139 | 7000_g+4.5_m0.0_t02_st_z+0.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 140 | 7000_g+4.5_m0.0_t02_st_z-0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 141 | 7000_g+4.5_m0.0_t02_st_z-1.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 142 | 7000_g+4.5_m0.0_t02_st_z-2.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 143 | 7000_g+4.5_m0.0_t02_st_z-3.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 144 | 7000_g+4.5_m0.0_t02_st_z-4.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 145 | 4000_g+1.5_m1.0_t02_st_z-0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 146 | 4000_g+1.5_m1.0_t02_st_z-1.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 147 | 4000_g+1.5_m1.0_t02_st_z-3.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 148 | 4000_g+2.0_m1.0_t02_st_z+0.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 149 | 4000_g+2.0_m1.0_t02_st_z+0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 150 | 4000_g+2.0_m1.0_t02_st_z-0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 151 | 4000_g+2.0_m1.0_t02_st_z-1.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 152 | 4000_g+2.0_m1.0_t02_st_z-2.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 153 | 4000_g+2.5_m1.0_t02_st_z+0.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 154 | 4000_g+2.5_m1.0_t02_st_z+0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 155 | 4000_g+2.5_m1.0_t02_st_z-0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 156 | 4000_g+2.5_m1.0_t02_st_z-1.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 157 | 4000_g+2.5_m1.0_t02_st_z-2.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 158 | 4000_g+2.5_m1.0_t02_st_z-4.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 159 | 4500_g+1.5_m1.0_t02_st_z-1.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 160 | 4500_g+1.5_m1.0_t02_st_z-2.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 161 | 4500_g+1.5_m1.0_t02_st_z-3.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 162 | 4500_g+2.0_m1.0_t02_st_z+0.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 163 | 4500_g+2.0_m1.0_t02_st_z+0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 164 | 4500_g+2.0_m1.0_t02_st_z-0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 165 | 4500_g+2.0_m1.0_t02_st_z-1.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 166 | 4500_g+2.0_m1.0_t02_st_z-3.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 167 | 4500_g+2.5_m1.0_t02_st_z+0.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 168 | 4500_g+2.5_m1.0_t02_st_z+0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 169 | 4500_g+2.5_m1.0_t02_st_z-0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 170 | 4500_g+2.5_m1.0_t02_st_z-1.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 171 | 5000_g+2.0_m1.0_t02_st_z+0.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 172 | 5000_g+2.0_m1.0_t02_st_z-0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 173 | 5000_g+2.0_m1.0_t02_st_z-1.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 174 | 5000_g+2.0_m1.0_t02_st_z-2.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 175 | 5000_g+2.0_m1.0_t02_st_z-4.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 176 | 5000_g+2.5_m1.0_t02_st_z+0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 177 | 5000_g+2.5_m1.0_t02_st_z-0.50_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 178 | 5000_g+2.5_m1.0_t02_st_z-1.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 179 | 5000_g+2.5_m1.0_t02_st_z-2.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 180 | 5000_g+2.5_m1.0_t02_st_z-4.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 181 | 5500_g+2.5_m1.0_t02_st_z-2.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 182 | 5500_g+2.5_m1.0_t02_st_z-3.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00 183 | -------------------------------------------------------------------------------- /scripts/marcs_class.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import Union 4 | 5 | # class for MARCS model atmospheres 6 | import numpy as np 7 | import matplotlib.pyplot as plt 8 | from .solar_abundances import periodic_table 9 | import matplotlib 10 | from scipy.interpolate import interp1d 11 | 12 | #matplotlib.use("MacOSX") 13 | 14 | class MARCSModel: 15 | def __init__(self, file): 16 | self.file = file 17 | # read in file. it is a constantly formatted file 18 | with open(file) as f: 19 | lines_marcs_model = f.readlines() 20 | current_line = 0 21 | # first line is name of the atmosphere model 22 | self.name = lines_marcs_model[current_line].strip() 23 | current_line += 1 24 | # second line is temperature with junk at the end 25 | self.teff = float(lines_marcs_model[current_line].strip().split()[0]) 26 | current_line += 1 27 | # third line if flux in erg/s/cm^2 with junk at the end 28 | self.flux = float(lines_marcs_model[current_line].strip().split()[0]) 29 | current_line += 1 30 | # fourth line is log(g) with junk at the end 31 | self.logg = np.log10(float(lines_marcs_model[current_line].strip().split()[0])) 32 | current_line += 1 33 | # fifth line is vmicro with junk at the end 34 | self.vmicro = float(lines_marcs_model[current_line].strip().split()[0]) 35 | current_line += 1 36 | # sixth line is mass with junk at the end 37 | self.mass = float(lines_marcs_model[current_line].strip().split()[0]) 38 | current_line += 1 39 | # seventh line is metallicity and alpha with junk at the end 40 | self.metallicity = float(lines_marcs_model[current_line].strip().split()[0]) 41 | self.alpha = float(lines_marcs_model[current_line].strip().split()[1]) 42 | current_line += 1 43 | # eighth line is 1 cm radius for plane-parallel models with junk at the end 44 | self.radius = float(lines_marcs_model[current_line].strip().split()[0]) 45 | current_line += 1 46 | # ninth line is Luminosity [Lsun] FOR A RADIUS OF 1 cm! with junk at the end 47 | self.luminosity_1cm = float(lines_marcs_model[current_line].strip().split()[0]) 48 | current_line += 1 49 | # tenth line is are the convection parameters: alpha, nu, y and beta with junk at the end 50 | self.alpha_convection = float(lines_marcs_model[current_line].strip().split()[0]) 51 | self.nu_convection = float(lines_marcs_model[current_line].strip().split()[1]) 52 | self.y_convection = float(lines_marcs_model[current_line].strip().split()[2]) 53 | self.beta_convection = float(lines_marcs_model[current_line].strip().split()[3]) 54 | current_line += 1 55 | # eleventh line is are X, Y and Z, 12C/13C=89 (=solar) with junk at the end 56 | self.x = float(lines_marcs_model[current_line].strip().split()[0]) 57 | self.y = float(lines_marcs_model[current_line].strip().split()[1]) 58 | self.z = float(lines_marcs_model[current_line].strip().split()[2]) 59 | current_line += 1 60 | # line 12 is header, skipped 61 | # next 9 lines are the abundances of the elements, 10 elements per line, 92 elements in total 62 | # convert to dictionary, where the key is the element name and the value is the abundance 63 | self.abundances = {} 64 | current_element_atomic_number = 1 65 | for i in range(9): 66 | current_line += 1 67 | for j in range(10): 68 | element_name = periodic_table[current_element_atomic_number] 69 | element_abundance = float(lines_marcs_model[current_line].strip().split()[j]) 70 | self.abundances[element_name] = element_abundance 71 | current_element_atomic_number += 1 72 | # last line only has 2 elements 73 | current_line += 1 74 | for j in range(2): 75 | element_name = periodic_table[current_element_atomic_number] 76 | element_abundance = float(lines_marcs_model[current_line].strip().split()[j]) 77 | self.abundances[element_name] = element_abundance 78 | current_element_atomic_number += 1 79 | current_line += 1 80 | # next line is number of depth points with junk at the end 81 | self.number_depth_points = int(lines_marcs_model[current_line].strip().split()[0]) 82 | current_line += 3 83 | # next 2 lines is header, skipped 84 | # now we have number of depth points lines with k lgTauR lgTau5 Depth T Pe Pg Prad Pturb 85 | # use numpy to read in the data, by passing the lines_marcs_model list and skipping the first current_line lines 86 | data = np.loadtxt(lines_marcs_model[current_line:current_line + self.number_depth_points], skiprows=0) 87 | self.k = data[:, 0].astype(int) 88 | self.lgTauR = data[:, 1].astype(float) 89 | self.lgTau5 = data[:, 2].astype(float) 90 | self.depth = data[:, 3].astype(float) 91 | self.temperature = data[:, 4].astype(float) 92 | self.pe = data[:, 5].astype(float) 93 | self.pg = data[:, 6].astype(float) 94 | self.prad = data[:, 7].astype(float) 95 | self.pturb = data[:, 8].astype(float) 96 | current_line += self.number_depth_points + 1 97 | # next line is header, skipped 98 | # now we have number of depth points lines with k lgTauR KappaRoss Density Mu Vconv Fconv/F RHOX 99 | # use numpy to read in the data, by passing the lines_marcs_model list and skipping the first current_line lines 100 | data = np.loadtxt(lines_marcs_model[current_line:current_line + self.number_depth_points], skiprows=0) 101 | self.lgTauR = data[:, 1].astype(float) 102 | self.kappaRoss = data[:, 2].astype(float) 103 | self.density = data[:, 3].astype(float) 104 | self.mu = data[:, 4].astype(float) 105 | self.vconv = data[:, 5].astype(float) 106 | self.fconv_f = data[:, 6].astype(float) 107 | self.rhox = data[:, 7].astype(float) 108 | # next lines are elemental pressures, skipped 109 | # done 110 | 111 | def interpolate_all_parameters(self, number_depth_points: int) -> None: 112 | # interpolate all parameters to the number of depth points: lgTauR, lgTau5, depth, temperature, pe, pg, prad, pturb, kappaRoss, density, mu, vconv, fconv_f, rhox 113 | # number_depth_points: number of depth points to interpolate to 114 | self.number_depth_points = number_depth_points 115 | # first create new depth points 116 | depth_new = np.linspace(self.depth[0], self.depth[-1], number_depth_points) 117 | # interpolate all parameters 118 | self.lgTauR = interp1d(self.depth, self.lgTauR, kind='linear')(depth_new) 119 | self.lgTau5 = interp1d(self.depth, self.lgTau5, kind='linear')(depth_new) 120 | self.depth = interp1d(self.depth, self.depth, kind='linear')(depth_new) 121 | self.temperature = interp1d(self.depth, self.temperature, kind='linear')(depth_new) 122 | self.pe = interp1d(self.depth, self.pe, kind='linear')(depth_new) 123 | self.pg = interp1d(self.depth, self.pg, kind='linear')(depth_new) 124 | self.prad = interp1d(self.depth, self.prad, kind='linear')(depth_new) 125 | self.pturb = interp1d(self.depth, self.pturb, kind='linear')(depth_new) 126 | self.kappaRoss = interp1d(self.depth, self.kappaRoss, kind='linear')(depth_new) 127 | self.density = interp1d(self.depth, self.density, kind='linear')(depth_new) 128 | self.mu = interp1d(self.depth, self.mu, kind='linear')(depth_new) 129 | self.vconv = interp1d(self.depth, self.vconv, kind='linear')(depth_new) 130 | self.fconv_f = interp1d(self.depth, self.fconv_f, kind='linear')(depth_new) 131 | self.rhox = interp1d(self.depth, self.rhox, kind='linear')(depth_new) 132 | 133 | def plot_temperature(self): 134 | plt.plot(self.depth, self.temperature) 135 | plt.gca().invert_yaxis() 136 | plt.ylabel("Temperature [K]") 137 | plt.xlabel("Depth [cm]") 138 | # invert y axis 139 | plt.gca().invert_yaxis() 140 | plt.show() 141 | 142 | def interpolate_temperature(self, depth_points: Union[list, np.ndarray, int]) -> tuple[np.ndarray, np.ndarray]: 143 | # if number_depth_points is an integer, then interpolate to that number of depth points 144 | # if number_depth_points is a list, then interpolate to those depth points 145 | if isinstance(depth_points, int): 146 | depth_new, temperature_new = self._interpolate_temperature_number_depth_points(depth_points) 147 | elif isinstance(depth_points, list) or isinstance(depth_points, np.ndarray): 148 | depth_new, temperature_new = self._interpolate_temperature_new_depth(depth_points) 149 | else: 150 | raise TypeError("number_depth_points must be int or list") 151 | return depth_new, temperature_new 152 | 153 | def _interpolate_temperature_number_depth_points(self, number_depth_points: int) -> tuple[np.ndarray, np.ndarray]: 154 | # down or upsample to the number of depth points. returns the interpolated depth and temperature 155 | # number_depth_points: number of depth points to interpolate to 156 | 157 | # create new depth points 158 | depth_new = np.linspace(self.depth[0], self.depth[-1], number_depth_points) 159 | return self._interpolate_temperature_new_depth(depth_new) 160 | 161 | def _interpolate_temperature_new_depth(self, depth_new: Union[list, np.ndarray]) -> tuple[np.ndarray, np.ndarray]: 162 | # down or upsample to the number of depth points. returns the interpolated depth and temperature 163 | # number_depth_points: number of depth points to interpolate to 164 | 165 | # create new depth points 166 | if type(depth_new) == list: 167 | depth_new = np.asarray(depth_new) 168 | # interpolate temperature 169 | temperature_new = interp1d(self.depth, self.temperature, kind='linear')(depth_new) 170 | return depth_new, temperature_new 171 | 172 | def write_m3d_type_model(self, new_file: str, depth_points: Union[list, np.ndarray, int]) -> None: 173 | # write a model in the format of Multi3D 174 | # file: file to write to 175 | # depth_points: number of depth points to interpolate to 176 | # write header 177 | with open(new_file, "w") as f: 178 | f.write(f"equidistant_{self.name}\n") 179 | f.write(f"{depth_points}\n") 180 | f.write(f"* Depth_[cm] Temperature_[K] Electron_pressure_[cgs] Density_[cgs] Microturbulence_[km/s]\n") 181 | # interpolate to new depth points 182 | depth_new, temperature_new, electron_pressure_new, density_new, vmicro_new = self.interpolate_m3d_type_model(depth_points) 183 | # write data 184 | with open(new_file, "a") as f: 185 | for i in range(depth_points): 186 | f.write(f"{depth_new[i]:>13.6e} {temperature_new[i]:>8.1f} {electron_pressure_new[i]:>12.4E} {density_new[i]:>12.4E} {vmicro_new[i]:>3.1f}\n") 187 | 188 | def interpolate_m3d_type_model(self, depth_points: Union[list, np.ndarray, int]) -> tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray]: 189 | # if number_depth_points is an integer, then interpolate to that number of depth points 190 | # if number_depth_points is a list, then interpolate to those depth points 191 | if isinstance(depth_points, int): 192 | depth_new, temperature_new, electron_pressure_new, density_new, vmicro_new = self._interpolate_m3d_number_depth_points(depth_points) 193 | elif isinstance(depth_points, list) or isinstance(depth_points, np.ndarray): 194 | depth_new, temperature_new, electron_pressure_new, density_new, vmicro_new = self._interpolate_m3d_new_depth(depth_points) 195 | else: 196 | raise TypeError("number_depth_points must be int or list") 197 | return depth_new, temperature_new, electron_pressure_new, density_new, vmicro_new 198 | 199 | def _interpolate_m3d_number_depth_points(self, number_depth_points: int) -> tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray]: 200 | # down or upsample to the number of depth points. returns the interpolated depth and temperature 201 | # number_depth_points: number of depth points to interpolate to 202 | 203 | # create new depth points 204 | depth_new = np.linspace(self.depth[0], self.depth[-1], number_depth_points) 205 | return self._interpolate_m3d_new_depth(depth_new) 206 | 207 | def _interpolate_m3d_new_depth(self, depth_new: Union[list, np.ndarray]) -> tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray]: 208 | # down or upsample to the number of depth points. returns the interpolated depth and temperature 209 | # number_depth_points: number of depth points to interpolate to 210 | 211 | # create new depth points 212 | if type(depth_new) == list: 213 | depth_new = np.asarray(depth_new) 214 | # interpolate temperature 215 | temperature_new = self.interpolate_temperature(depth_new)[1] 216 | # interpolate electron pressure 217 | electron_pressure_new = interp1d(self.depth, self.pe, kind='linear')(depth_new) 218 | # interpolate density 219 | density_new = interp1d(self.depth, self.density, kind='linear')(depth_new) 220 | # vmic is constant float, converted to array of same length as depth_new 221 | vmic_new = np.full(len(depth_new), self.vmicro) 222 | return depth_new, temperature_new, electron_pressure_new, density_new, vmic_new 223 | 224 | 225 | if __name__ == '__main__': 226 | # example usage 227 | file = "/Users/storm/docker_common_folder/TSFitPy/input_files/model_atmospheres/1D/p5750_g+4.5_m0.0_t01_st_z+0.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00.mod" 228 | file = "/Users/storm/PycharmProjects/3d_nlte_stuff/m3dis_l/m3dis/experiments/Multi3D/input_multi3d/atmos/p5777_g+4.4_m0.0_t01_st_z+0.00_a+0.00_c+0.00_n+0.00_o+0.00_r+0.00_s+0.00.mod" 229 | marcs_model = MARCSModel(file) 230 | #marcs_model.depth = marcs_model.radius - marcs_model.depth 231 | #print(marcs_model.depth) 232 | #marcs_model.plot_temperature() 233 | #plt.plot(marcs_model.depth, marcs_model.lgTauR) 234 | # plot y = x 235 | #plt.plot(marcs_model.depth, marcs_model.depth) 236 | #plt.ylabel("lgTauR") 237 | #plt.xlabel("Depth [cm]") 238 | #plt.show() 239 | 240 | plt.plot(marcs_model.prad, marcs_model.density) 241 | plt.ylabel("Density [cgs]") 242 | plt.xlabel("Pg [cgs]") 243 | plt.show() 244 | 245 | sunint_file = "/Users/storm/docker_common_folder/TSFitPy/temp_directory_Dec-14-2023-11-52-14__0.06273117145467688/marcs_tef5777.0_g4.40_z0.00_tur1.00.interpol" 246 | sunint_temperature, sunint_depth = np.loadtxt(sunint_file, unpack=True, usecols=(1,5), dtype=float, skiprows=1, comments="/") 247 | sunint_depth = marcs_model.radius - sunint_depth 248 | 249 | marcs_50_depth, marcs_50_temperature = np.loadtxt("/Users/storm/PycharmProjects/3d_nlte_stuff/m3dis_l/m3dis/experiments/Multi3D/input_multi3d/atmos/atmos.sun_MARCS_50", unpack=True, usecols=(0,1), dtype=float, skiprows=2) 250 | #plt.plot(marcs_50_depth, marcs_50_temperature, label="MARCS 50", color="red") 251 | plt.plot(sunint_depth, sunint_temperature, label="MARCS TS interpolated", color="black") 252 | #xx, yy = marcs_model.interpolate_temperature(50) 253 | #plt.plot(xx, yy, label="MARCS 50 interpolated", color="blue", linestyle="--") 254 | xx2, yy2 = marcs_model.interpolate_temperature(marcs_50_depth) 255 | xx2, yy2 = marcs_model.interpolate_temperature(marcs_model.depth) 256 | plt.plot(xx2, yy2, label="MARCS 50 interpolated v2", color="red", linestyle="--") 257 | plt.legend() 258 | plt.show() 259 | 260 | marcs_model.write_m3d_type_model("test_marcs50.txt", 50) 261 | 262 | --------------------------------------------------------------------------------