! SP_Ace derives stellar parameters, such as gravity, temperature, and element ! abundances from optical stellar spectra, assuming Local Thermodynamic ! Equilibrium (LTE) and 1D stellar atmosphere models. ! ! Copyright (C) 2016 Corrado Boeche ! ! This program is free software: you can redistribute it and/or modify ! it under the terms of the GNU General Public License as published by ! the Free Software Foundation, either version 3 of the License, or ! (at your option) any later version. ! ! This program is distributed in the hope that it will be useful, ! but WITHOUT ANY WARRANTY; without even the implied warranty of ! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! GNU General Public License for more details. ! ! You should have received a copy of the GNU General Public License ! along with this program. If not, see . PROGRAM space USE num_type USE error USE space_pars, ONLY: read_space_pars,sn_ratio,sn_flag,& &TGM_force,error_est,flag_norm,flag_ABD_loop USE share USE utils USE make_model USE read_GCOG USE func_poly USE interfaces, ONLY: fit_cont,write_res USE minimize USE uncertains2, ONLY:TGM_errors,TGM_errors_null IMPLICIT NONE INTEGER(I2B) :: i,j,infoTGM,infoABD INTEGER(I1B) :: AllocateStatus REAL(DP),DIMENSION(5) :: temp_gridS,logg_gridS,met_gridS REAL(DP), DIMENSION(3) :: TGM_old, residTGM REAL(DP), DIMENSION(4) :: pars REAL(DP), DIMENSION(:), ALLOCATABLE :: TGMx,ABDx REAL(DP) :: chisq,chisq_old LOGICAL :: flag_lim,flag_limS,flag_move CHARACTER(LEN=5),DIMENSION(3) :: TGMc !write the SP_Ace version write(*,*) 'SP_Ace version 2.0' write(*,*) 'Copyright (C) 2016 Corrado Boeche' write(*,*) 'This program comes with ABSOLUTELY NO WARRANTY.' write(*,*) 'This is free software, and you are welcome to redistribute it' write(*,*) 'under certain conditions; see for details.' !initialize variables TGM_prox=REAL((/-99.,-99.,-99./),SP) flag_lim=.FALSE. flag_limS=.FALSE. flag_move=.FALSE. !read the parameters file CALL read_space_pars('space.par') !load the spectrum, the line lists CALL read_files(obs_sp_file,llist,llist_rej)! !---------------------- !allocate the mask for the llist that will be use for the measures ALLOCATE(select_ll_mask(dim_ll), STAT = AllocateStatus) IF (AllocateStatus/=0) CALL stop_msg('Not enough memory to allocate select_ll_mask') sn=sn_ratio !allocate the array sig_noise ALLOCATE(sig_noise(dimsp), STAT = AllocateStatus) IF (AllocateStatus/=0) CALL stop_msg('Not enough memory to allocate sig_noise') !allocate the array f_discrep ALLOCATE(f_discrep(dimsp), STAT = AllocateStatus) IF (AllocateStatus/=0) CALL stop_msg('Not enough memory to allocate f_discrep') ! allocate the array ele2meas which contains the list of elements ! present in the line list. It also allocate ABD, ADB_old,residABD ! ABD_mask. It outputs dim_ele CALL alloc_ABD(ele_ll,dim_ll,dim_ele) ALLOCATE(ABDx(dim_ele), STAT = AllocateStatus) IF (AllocateStatus/=0) CALL stop_msg('Not enough memory to allocate ABDx') ABDx=PACK(ABD,ABD_mask) !initialize TGM_mask TGM_mask=.TRUE. !give a starting point TGM(1:3)=(/5000.,3.0,-0.4/) !initialize Teff and gravity to the user's input, if any IF (TGM_force(1)>-9.) THEN TGM(1)=TGM_force(1) TGM_mask(1)=.FALSE. END IF IF (TGM_force(2)>-9.) THEN TGM(2)=TGM_force(2) TGM_mask(2)=.FALSE. END IF !initialize other TGM variables TGM(4)=sigma TGM(5)=0. TGM(6)=1.0 !if the user do not want the continuum normalization, IF(.NOT.flag_norm) THEN TGM_mask(6)=.FALSE. END IF !allocate the array TGMx to be used as shorted array when TGM_force is employed !and fed to the lmdif1 routine. TGMx must be long as much as the number of .TRUE. in TGM_mask ALLOCATE(TGMx(COUNT(TGM_mask)), STAT = AllocateStatus) IF (AllocateStatus/=0) CALL stop_msg('Not enough memory to allocate TGMx') TGMx=PACK(TGM,TGM_mask) !initialize the internal normalized spectrum f_sp_norm=f_sp !prepare for the first TGM estimation weights=1.0_dp sig_noise=(1.0_dp/sn)/weights select_ll_mask=.TRUE. TGM_old=TGM(1:3) !initialize the GCOG CALL load_GCOG_lin(5000.,3.0,-0.4) !start normalization loop that serves as a first guess too normal_loop: DO j=1,30 CALL make_model_TGM(f_model,TGM) CALL lmdif1(chi_TGM,dimsp,INT(SIZE(TGMx),I2B),TGMx,f_discrep,1E-3,infoTGM) TGM=UNPACK(TGMx,TGM_mask,TGM) write(TGMc(1),fmt='(I5)') INT(TGM(1)) write(TGMc(2),fmt='(F5.2)') TGM(2) write(TGMc(3),fmt='(F5.2)') TGM(3) write(*,*) 'TGM norm. loop',j,' Teff=',TGMc(1),' log g=',TGMc(2),' [M/H]=',TGMc(3)!, ' info=',infoTGM!,'cont=',TGM(6) !make the model sigma=TGM(4) CALL update_gridS_ll CALL make_model_TGM(f_model,TGM) !now re-normalize the observed spectrum IF(flag_norm) THEN CALL fit_cont(f_sp,f_model,cont); f_sp_norm=f_sp/TGM(6)/cont END IF !compute the chisq chisq=SUM(((f_sp_norm-f_model)/sig_noise)**2) !update some variables residTGM=ABS(TGM_old-TGM(1:3)) TGM_old=TGM(1:3) !if the user does not want the re-normalization, then exit this loop IF(.NOT.flag_norm) EXIT !check the convergence IF((residTGM(1)<10..AND.residTGM(2)<0.02.AND.residTGM(3)<0.02).AND.j>1) EXIT END DO normal_loop IF(j>=30) THEN CALL error_msg(1_I1B,'norm loop did not converge') END IF !find the closest point in the sub-grid and verify if TGM is inside the grid CALL find_proxS(TGM,temp_gridS,logg_gridS,met_gridS,TGM_prox,& &flag_lim,flag_limS,flag_move) !if flag_lim=.TRUE. means that TGM is out of the grid, then exit IF(flag_lim) THEN CALL error_msg(2_I1B,'stellar parameters out of the limits') END IF !final normalization of the observed spectrum f_sp_norm=f_sp/TGM(6)/cont chisq_old=chisq CALL update_gridS_ll !######################### !###### start iterations outer loop !######################### outer: DO i=1,30 !############## !search for TGM !############## CALL lmdif1(chi_TGM,dimsp,INT(SIZE(TGMx),I2B),TGMx,f_discrep,1E-3,infoTGM) TGM=UNPACK(TGMx,TGM_mask,TGM) CALL make_model_TGM(f_model,TGM) chisq=SUM(((f_sp_norm-f_model)/sig_noise)**2) !write to the standard output the temporary solution found write(TGMc(1),fmt='(I5)') INT(TGM(1)) write(TGMc(2),fmt='(F5.2)') TGM(2) write(TGMc(3),fmt='(F5.2)') TGM(3) write(*,*) 'TGM outer loop',i,' Teff=',TGMc(1),' log g=',TGMc(2),' [M/H]=',TGMc(3)!, ' info=',infoTGM !update the value sigma sigma=ABS(TGM(4)) !find the closest point in the sub-grid and verify if TGM is inside the grid CALL find_proxS(TGM,temp_gridS,logg_gridS,met_gridS,TGM_prox,& &flag_lim,flag_limS,flag_move) !if flag_lim=.TRUE. means that TGM is out of the grid, then exit IF(flag_lim) THEN CALL error_msg(2_I1B,'stellar parameters out of the limits') END IF !update some variables sigma=ABS(TGM(4)) residTGM=ABS(TGM_old-TGM(1:3)) ! write(*,*) 'resid',residTGM !check if some of the parameters are meaningful. !check the FWHM: if it is too large, quit IF((sigma*2.35)>10.) THEN CALL error_msg(3_I1B,'FWHM does not converge') END IF !check the abs(RV): if it is too large, quit IF(ABS(TGM(5))*w_sp(1)/300000.>sigma*2.35) THEN CALL error_msg(4_I1B,'RV too far from zero (beyond 1FWHM)') END IF !################## !now search for ABD !################## !assign to the dummy ABDx array the same values of ABD ABDx=ABD CALL lmdif1(chi_ABD,dimsp,INT(SIZE(ABDx),I2B),ABDx,f_discrep,1E-3,infoABD) !now assign to ABD the new values of ABDx ABD=UNPACK(ABDx,ABD_mask,ABD) ! write(*,*) 'abd',PACK(ABD-ABD(1),write_ABD_mask) CALL make_model_ABD(f_model,ABD) ! write(*,*) 'residTGM',residTGM TGM_old=TGM(1:3) !check the convergence of the outer loop IF((residTGM(1)<1..AND.residTGM(2)<0.01.AND.residTGM(3)<0.01)) THEN EXIT END IF IF(flag_ABD_loop) THEN !compute the differences between the old and new ABD estimations ! residABD=ABS(ABD-ABD_old) !if the differences are large, then re-do the loop ! IF(ANY((PACK(residABD,write_ABD_mask))>0.05).AND.i<30) THEN !Now substitute the Fe abundance (if the internal loop cycled at least one time) in TMG(3) !if this is the first loop for the internal loop, then ABD=0 and TGM does not change TGM(3)=TGM(3)+ABD(1) WHERE(ABD_mask) ABD=ABD-ABD(1) !update the ABD_old ABD_old=ABD CYCLE ! END IF END IF !check the convergence and flags of the lmdif1 routines IF(infoTGM==0.OR.infoABD==0) THEN CALL error_msg(5_I1B,'improper input parameters in lmdif1)') ELSE IF (infoTGM==5) THEN CALL error_msg(6_I1B,'TGM minim routine exceeded the max N of iterations') EXIT ELSE IF (infoABD==5) THEN CALL error_msg(7_I1B,'ABD minim routine exceeded the max N of iterations') EXIT ELSE EXIT END IF END DO outer !###################### !if the outer loop has more than 30 loops, it means !it could not converge, then quit ! IF(i>=30) THEN ! CALL error_msg(8_I1B,'TGM outer loop did not converge') ! END IF !make the final model and compute the chi square CALL make_model_TGM(f_model,TGM) chisq=SUM(((f_sp_norm-f_model)/sig_noise)**2) !compute the overall S/N IF(sn_flag) THEN CALL new_sn(sn) END IF !compute the errors, if requested by the user IF(error_est) THEN write(*,*) 'errors estimation in progress' CALL TGM_errors(chisq) !if you decomment the following line, the !chisq surface is output in the file space_chisq.dat !CALL write_chi2_grid(chisq) ! CALL TGM_errors_poly(chisq) ELSE CALL TGM_errors_null END IF !write the results and exit CALL make_model_TGM(f_model,TGM) CALL write_res(error_est,chisq) !here the program ends! CONTAINS !####################################### SUBROUTINE update_gridS_ll IMPLICIT NONE LOGICAL,DIMENSION(dimsp) :: mask1 !make a new subgrids ! CALL find_prox(TGM,TGM_prox) ! CALL make_gridS(TGM_prox,temp_gridS,logg_gridS,met_gridS) ! allocate and upload the table coeff_4deg which contains the coefficient ! to construct the polynomial GCOG ! CALL load_GCOG_4deg(TGM_prox(1),TGM_prox(2),TGM_prox(3)) !remove the cosmic rays with a 4sigma clipping CALL cosmic_rej !compute the S/N IF(sn_flag) THEN CALL new_sn(sn) END IF IF(sn_flag) THEN CALL find_sn_var(f_sp_norm,f_model,sn_var) ELSE sn_var=sn END IF !select the lines strong enough to be measurable in this !region of the parameters space pars=(/TGM(1),TGM(2),TGM(3),0._dp/) CALL select_lines(ew_lin_interp,coeff_ew_lin,pars,sigma,.TRUE.) sig_noise=(1.0_dp/sn_var)/weights !give to n_weig the number of pixels having weight>0.01 mask1=.TRUE. WHERE(weights<0.01) mask1=.FALSE. n_weig=INT(COUNT(mask1),I2B) IF(n_weig<1) THEN n_weig=dimsp END IF END SUBROUTINE update_gridS_ll !######################################## END PROGRAM space