LCOV - code coverage report
Current view: top level - src/78_effpot - m_fit_polynomial_coeff.F90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 62.7 % 1709 1071
Test Date: 2026-09-20 18:56:22 Functions: 84.4 % 32 27

            Line data    Source code
       1              : !!****m* ABINIT/m_fit_polynomial_coeff
       2              : !!
       3              : !! NAME
       4              : !! m_fit_polynomial_coeff
       5              : !!
       6              : !! FUNCTION
       7              : !!
       8              : !! COPYRIGHT
       9              : !! Copyright (C) 2010-2026 ABINIT group (AM)
      10              : !! This file is distributed under the terms of the
      11              : !! GNU General Public Licence, see ~abinit/COPYING
      12              : !! or http://www.gnu.org/copyleft/gpl.txt .
      13              : !! For the initials of contributors, see ~abinit/doc/developers/contributors.txt .
      14              : !!
      15              : !! SOURCE
      16              : 
      17              : 
      18              : #if defined HAVE_CONFIG_H
      19              : #include "config.h"
      20              : #endif
      21              : 
      22              : #include "abi_common.h"
      23              : 
      24              : module m_fit_polynomial_coeff
      25              : 
      26              :  use defs_basis
      27              :  use m_errors
      28              :  use m_abicore
      29              :  use m_polynomial_term
      30              :  use m_polynomial_coeff
      31              :  use m_atomdata
      32              :  use m_xmpi
      33              :  use m_supercell
      34              :  use m_fstrings, only : itoa, ftoa
      35              : 
      36              :  use m_hashtable_strval, only: hash_table_t
      37              :  use m_mergesort, only: mergesort
      38              :  use m_dynamic_array, only : int_array_type, real_array_type
      39              :  use m_special_funcs,only : factorial
      40              :  use m_geometry,       only : xred2xcart
      41              :  use m_crystal,only : symbols_crystal
      42              :  use m_strain,only : strain_type,strain_get
      43              :  use m_effective_potential,only : effective_potential_type, effective_potential_evaluate
      44              :  use m_effective_potential,only : effective_potential_freeCoeffs,effective_potential_setCoeffs
      45              :  use m_effective_potential,only : effective_potential_getDisp, effective_potential_writeAnhHead
      46              :  use m_effective_potential,only : effective_potential_copy,effective_potential_free,effective_potential_init
      47              :  use m_effective_potential_file, only : effective_potential_file_mapHistToRef
      48              :  use m_io_tools,   only : open_file,get_unit
      49              :  use m_abihist, only : abihist,abihist_free,abihist_init,abihist_copy,write_md_hist,var2hist
      50              :  use m_random_zbq
      51              :  use m_fit_data
      52              :  use m_geometry, only: metric
      53              :  use m_scup_dataset
      54              : #if defined DEV_MS_SCALEUP
      55              :  use scup_global, only : global_set_parent_iter,global_set_print_parameters
      56              : #endif
      57              : 
      58              :  implicit none
      59              : 
      60              :  public :: fit_polynomial_coeff_computeGF
      61              :  public :: fit_polynomial_coeff_computeMSD
      62              :  public :: fit_polynomial_coeff_fit
      63              :  public :: fit_polynomial_coeff_getFS
      64              :  public :: fit_polynomial_coeff_getPositive
      65              :  public :: fit_polynomial_coeff_getCoeffBound
      66              :  public :: fit_polynomial_coeff_solve
      67              :  public :: fit_polynomial_coeff_testEffPot
      68              :  public :: fit_polynomial_printSystemFiles
      69              :  public :: genereList
      70              : !!***
      71              : 
      72              : CONTAINS
      73              : !===========================================================================================
      74              : 
      75              : 
      76              : !!****f* m_fit_polynomial_coeff/fit_polynomial_coeff_fit
      77              : !!
      78              : !! NAME
      79              : !! fit_polynomial_coeff_fit
      80              : !!
      81              : !! FUNCTION
      82              : !! Fit the list of coefficients included in eff_pot,
      83              : !! if the coefficients are not set in eff_pot, this routine will genenerate
      84              : !! a list of coefficients by taking into acount the symmetries of the system
      85              : !! and the cutoff
      86              : !!
      87              : !! INPUTS
      88              : !! eff_pot<type(effective_potential)> = effective potential
      89              : !! bancoeff(nbancoeff) = list of bannned coeffcients, these coefficients will NOT be
      90              : !!                       used during the fit process
      91              : !! fixcoeff(nfixcoeff) = list of fixed coefficient, these coefficients will be
      92              : !!                       imposed during the fit process
      93              : !! hist<type(abihist)> = The history of the MD (or snapshot of DFT)
      94              : !! generateterm = term to activate the generation of the term set
      95              : !! power_disps(2) = array with the minimal and maximal power_disp to be computed
      96              : !! nbancoeff = number of banned coeffcients
      97              : !! ncycle_in = number of maximum cycle (maximum coefficient to be fitted)
      98              : !! nfixcoeff = Number of coefficients imposed during the fit process
      99              : !! option = option of the fit process : 1 - selection of the coefficient one by one
     100              : !!                                      2 - selection of the coefficients with Monte Carlo(testversion)
     101              : !! comm = MPI communicator
     102              : !! cutoff_in = optional,cut off to apply to the range of interation if
     103              : !!           the coefficient are genereted in this routine
     104              : !! max_power_strain = maximum order of the strain of the strain phonon coupling
     105              : !! fit_initializeData = optional, logical !If true, we store all the information for the fit,
     106              : !!                      it will reduce the computation time but increase a lot the memory...
     107              : !! fit_tolMSDF = optional, tolerance in eV^2/A^2 on the Forces for the fit process
     108              : !! fit_tolMSDS = optional, tolerance in eV^2/A^2 on the Stresses for the fit process
     109              : !! fit_tolMSDE = optional, tolerance in meV^2/A^2 on the Energy for the fit process
     110              : !! fit_tolMSDFS= optional, tolerance in eV^2/A^2 on the Forces+stresses for the fit process
     111              : !! positive = optional, TRUE will return only positive coefficients
     112              : !!                      FALSE, default
     113              : !! verbose  = optional, flag for the verbose mode
     114              : !! anhstr = logical, optional : TRUE, the anharmonic strain are computed
     115              : !!                              FALSE, (default) the anharmonic strain are not computed
     116              : !! only_odd_power = logical, optional : if TRUE generate only odd power
     117              : !! only_even_power= logical, optional : if TRUE generate only even power
     118              : !!
     119              : !! OUTPUT
     120              : !! eff_pot<type(effective_potential)> = effective potential datatype with new fitted coefficients
     121              : !!
     122              : !! SOURCE
     123              : 
     124           76 : subroutine fit_polynomial_coeff_fit(eff_pot,bancoeff,fixcoeff,hist,generateterm,power_disps,&
     125           38 : &                                   nbancoeff,ncoeff_in,nfixcoeff,nimposecoeff,imposecoeff,&
     126              : &                                   option,comm,cutoff_in,max_power_strain,initialize_data,&
     127              : &                                   fit_tolMSDF,fit_tolMSDS,fit_tolMSDE,fit_tolMSDFS,fit_tolGF,&
     128              : &                                   positive,verbose,anharmstr,spcoupling,&
     129              : &                                   only_odd_power,only_even_power,prt_anh,&
     130              : &                                   fit_iatom,prt_files,fit_on,sel_on,fit_factors,prt_GF_csv,&
     131           38 : &                                   dispterms,coeff_file_rw,read_effective_potential, max_nbody, &
     132              : &                                    drop_rate, ncoeff_per_cycle, fit_weight_T)
     133              : 
     134              :  implicit none
     135              : 
     136              : !Arguments ------------------------------------
     137              : !scalars
     138              :  integer,intent(in) :: ncoeff_in,nfixcoeff,nimposecoeff,comm
     139              :  integer,intent(in) :: generateterm,nbancoeff,option, ncoeff_per_cycle
     140              : !arrays
     141              :  integer,intent(in) :: fixcoeff(nfixcoeff), bancoeff(nbancoeff),imposecoeff(nimposecoeff)
     142              :  integer,intent(in) :: power_disps(2)
     143              :  type(effective_potential_type),target,intent(inout) :: eff_pot
     144              :  type(effective_potential_type),optional,intent(inout) :: read_effective_potential
     145              :  type(abihist),intent(inout) :: hist
     146              :  integer,optional,intent(in) :: max_power_strain,prt_anh,fit_iatom,  coeff_file_rw, max_nbody(:)
     147              :  real(dp),optional,intent(in) :: cutoff_in,fit_tolMSDF,fit_tolMSDS,fit_tolMSDE,fit_tolMSDFS
     148              :  real(dp),optional,intent(in) :: fit_tolGF
     149              :  logical,optional,intent(in) :: verbose,positive,anharmstr,spcoupling
     150              :  logical,optional,intent(in) :: only_odd_power,only_even_power
     151              :  logical,optional,intent(in) :: initialize_data,prt_files,prt_GF_csv
     152              :  logical,optional,intent(in) :: fit_on(3), sel_on(3),dispterms
     153              :  real(dp),optional,intent(in) :: fit_factors(3)
     154              :  real(dp), optional, intent(in) :: drop_rate
     155              :  real(dp), intent(in) :: fit_weight_T
     156              : !Local variables-------------------------------
     157              : !scalar
     158              :  integer ::  nfix
     159              :  integer :: ii,icoeff,my_icoeff,icycle,icycle_tmp,ierr,info,index_min,iproc,isweep,jcoeff,ia,generateterm_in
     160              :  integer :: master,max_power_strain_in,my_rank,my_ncoeff,ncoeff_model,ncoeff_tot,natom_sc,ncell,ncoeff_to_select,ncoeff_tot_tmp
     161              :  integer :: ncoeff_preselected, ncoeff_selected, ncoeff_to_fit,nproc,ntime,nsweep,size_mpi,ncoeff_fix,ncoeff_out
     162              :  integer :: my_ncoeff_start,my_ncoeff_end,my_ncoeff_simple,ncoeff_alone
     163              :  integer :: rank_to_send,unit_anh,fit_iatom_in,unit_GF_val,nfix_and_impose,nfixcoeff_corr,atom_start,atom_end
     164              :  integer :: ncopy_terms
     165              :  real(dp) :: cutoff,factor,time,tolMSDF,tolMSDS,tolMSDE,tolMSDFS,tolGF,check_value
     166              :  real(dp),parameter :: HaBohr_eVAng = Ha_eV /Bohr_Ang
     167         2394 :  type(effective_potential_type) :: eff_pot_fixed
     168              :  logical :: iam_master,need_verbose,need_positive,converge,file_opened
     169              :  logical :: need_anharmstr,need_spcoupling,ditributed_coefficients,need_prt_anh
     170              :  logical :: need_only_odd_power,need_only_even_power,need_initialize_data
     171              :  logical :: need_prt_files,need_prt_GF_csv,need_disp
     172              :  logical :: fit_iatom_all
     173              : !arrays
     174              :  real(dp) :: mingf(4),int_fit_factors(3)
     175              :  real(dp) :: remaining_rate
     176              :  integer :: sc_size(3)
     177           38 :  logical, allocatable :: isbanned(:)
     178           38 :  logical, allocatable :: isselected(:)
     179           38 :  logical,allocatable  :: fix_and_impose(:)
     180           38 :  integer,allocatable  :: buffsize(:),buffdisp(:),buffin(:),fixcoeff_corr(:)
     181           76 :  integer,allocatable  :: list_coeffs(:),list_coeffs_tmp(:),list_coeffs_tmp2(:)
     182           76 :  integer,allocatable  :: my_coeffindexes(:),singular_coeffs(:)
     183           38 :  integer,allocatable  :: my_coefflist(:) ,stat_coeff(:),list_coeffs_copy(:)
     184           38 :  real(dp),allocatable :: gf_values_iter(:,:)
     185           76 :  real(dp),allocatable :: buffGF(:,:),coeff_values(:),energy_coeffs(:,:)
     186           38 :  real(dp),allocatable :: energy_coeffs_tmp(:,:)
     187           76 :  real(dp),allocatable :: fcart_coeffs(:,:,:,:),gf_values(:,:),gf_mpi(:,:)
     188           38 :  real(dp),allocatable :: fcart_coeffs_tmp(:,:,:,:),strten_coeffs_tmp(:,:,:)
     189           38 :  real(dp),allocatable :: strten_coeffs(:,:,:)
     190           38 :  real(dp), allocatable :: weights(:)
     191           38 :  type(polynomial_coeff_type),allocatable :: my_coeffs(:),coeffs_iatom(:)
     192           38 :  type(polynomial_coeff_type),allocatable :: coeffs_out(:)
     193           38 :  type(polynomial_coeff_type),target,allocatable :: coeffs_tmp(:)
     194           38 :  type(polynomial_coeff_type),pointer :: coeffs_in(:)
     195           38 :  type(fit_data_type) :: fit_data
     196              : 
     197              :  !type(real_array_type) :: gf_array
     198              :  character(len=20000) :: message,message2
     199              :  character(len=fnlen) :: filename
     200              :  character(len=3)  :: i_char
     201              :  character(len=7)  :: j_char
     202           38 :  character(len=5),allocatable :: symbols(:)
     203           38 :  integer, allocatable :: list_bound(:), list_fix(:)
     204              :  integer :: n_remaining
     205              : 
     206              : ! *************************************************************************
     207              : 
     208              : !MPI variables
     209           38 :  master = 0
     210           38 :  nproc = xmpi_comm_size(comm); my_rank = xmpi_comm_rank(comm)
     211           38 :  iam_master = (my_rank == master)
     212              : 
     213              : #if defined CC_INTEL_ONEAPI
     214              :     if (iam_master) then
     215              :       write(message,'(3a)') ch10,' This part of code does not compile with intel IFX compiler'
     216              :       ABI_ERROR(message)
     217              :     end if
     218              : #else
     219           38 :  call initialize_parameters()
     220           38 :  call copy_eff_pot_to_eff_pot_fixed()
     221           38 :  ncopy_terms = 0
     222           38 :  call combine_fixcoeff_and_imposecoeff()
     223           38 :  call print_start_fitting()
     224           38 :  call map_hist_to_supercell()
     225           38 :  call generate_list_of_coefficients_to_fit()
     226           38 :  call read_or_write_coeffs_to_xml()
     227           38 :  ncoeff_tot = ncoeff_tot + ncoeff_model
     228           38 :  if((iam_master .and. ncopy_terms > 0)) my_ncoeff = my_ncoeff + ncopy_terms
     229              :  call get_num_fixed_coeff()
     230           38 :  call assign_coeffs_to_cpu()
     231           38 :  call check_sanity_ncoeff_in()
     232           38 :  call initialize_tags_for_coeffs()
     233              :  !call select_bounding_terms()
     234           38 :  call select_fix_terms()
     235           38 :  call get_ncoeff_preselected()
     236           38 :  call get_ncoeff_to_select_and_ncoeff_to_fit()
     237           38 :  call initialize_fitting_parameters_for_coefficients()
     238           38 :  call get_weight_from_hist(hist, fit_weight_T, ntime, eff_pot%supercell%natom, weights, comm )
     239           38 :  call initialize_gf()
     240           76 :  select case(option)
     241              :  case(1)
     242           38 :    call select_one_by_one()
     243              :  case(2)
     244           38 :    call select_with_monte_carlo()
     245              :  end select
     246           38 :  call fit_all_selected_coefficients()
     247           38 :  call deallocate_arrays()
     248              : 
     249              : contains
     250           38 :   subroutine initialize_parameters()
     251           38 :     need_verbose = .TRUE.
     252           38 :     if(present(verbose)) need_verbose = verbose
     253           38 :     need_initialize_data = .TRUE.
     254           38 :     if(present(initialize_data)) need_initialize_data = initialize_data
     255           38 :     need_positive = .FALSE.
     256           38 :     if(present(positive)) need_positive = positive
     257           38 :     need_anharmstr = .FALSE.
     258           38 :     if(present(anharmstr)) need_anharmstr = anharmstr
     259           38 :     need_disp = .TRUE.
     260           38 :     if(present(dispterms)) need_disp = dispterms
     261           38 :     need_spcoupling = .TRUE.
     262           38 :     if(present(spcoupling)) need_spcoupling = spcoupling
     263           38 :     need_only_odd_power = .FALSE.
     264              :     !----------------
     265           38 :     generateterm_in = generateterm
     266           38 :     if(present(coeff_file_rw))then
     267           38 :       if (coeff_file_rw==2) generateterm_in = 0
     268              :     end if
     269              :     !----------------
     270           38 :     if(present(only_odd_power)) need_only_odd_power = only_odd_power
     271           38 :     need_prt_anh = .FALSE.
     272           38 :     if(present(prt_anh))then
     273           38 :       if(prt_anh == 1) need_prt_anh = .TRUE.
     274              :     end if
     275           38 :     need_prt_GF_csv = .FALSE.
     276           38 :     if(present(prt_GF_csv)) need_prt_GF_csv = prt_GF_csv
     277           38 :     need_prt_files = .TRUE.
     278           38 :     if(present(prt_files))need_prt_files=prt_files
     279           38 :     need_only_even_power = .FALSE.
     280           38 :     if(present(only_even_power)) need_only_even_power = only_even_power
     281           38 :     if(need_only_odd_power.and.need_only_even_power)then
     282              :       write(message, '(3a)' )&
     283            0 :         &       'need_only_odd_power and need_only_even_power are both true',ch10,&
     284            0 :         &       'Action: contact abinit group'
     285            0 :       ABI_ERROR(message)
     286              :     end if
     287           38 :     max_power_strain_in = 1
     288           38 :     if(present(max_power_strain))then
     289           38 :       max_power_strain_in = max_power_strain
     290              :     end if
     291           38 :     if(max_power_strain_in <= 0)then
     292              :       write(message, '(3a)' )&
     293            0 :         &       'max_power_strain can not be inferior or equal to zero',ch10,&
     294            0 :         &       'Action: contact abinit group'
     295            0 :       ABI_ERROR(message)
     296              :     end if
     297              :     !Check which atom to fit, if not present do all atoms
     298           38 :     if(present(fit_iatom))then
     299           38 :       fit_iatom_in = fit_iatom
     300              :     else
     301            0 :       fit_iatom_in = -1
     302              :     endif
     303              : 
     304           38 :     fit_iatom_all=.False.
     305           38 :     if(present(fit_iatom)) then
     306           38 :       fit_iatom_all=(fit_iatom==-2)
     307              :     end if
     308              : 
     309              :     !Set int fit factors to default value if fit factors not present
     310           38 :     int_fit_factors = (/1,1,1/)
     311           38 :     if (present(fit_factors)) int_fit_factors = fit_factors
     312              : 
     313           38 :     ditributed_coefficients = .true.
     314           38 :     if(option==2) ditributed_coefficients = .false.
     315              : 
     316              : 
     317              :     !Set the tolerance for the fit
     318           38 :     tolMSDF=zero;tolMSDS=zero;tolMSDE=zero;tolMSDFS=zero;tolGF=zero
     319           38 :     if(present(fit_tolMSDF)) tolMSDF  = fit_tolMSDF
     320           38 :     if(present(fit_tolMSDS)) tolMSDS  = fit_tolMSDS
     321           38 :     if(present(fit_tolMSDE)) tolMSDE  = fit_tolMSDE
     322           38 :     if(present(fit_tolMSDFS))tolMSDFS = fit_tolMSDFS
     323           38 :     if(present(fit_tolGF))      tolGF = fit_tolGF
     324              : 
     325           38 :     remaining_rate=0.5
     326           38 :     if(present(drop_rate))  remaining_rate=1.0_dp-drop_rate
     327           38 :     ncoeff_selected=0
     328              : 
     329          153 :     if(nfixcoeff==-1 .and. any(max_nbody==-1)) then
     330            0 :       ABI_ERROR("nfixcoeff=-1 and max_nbody -1 cannot be used together in the current version of Multibinit.")
     331              :     end if
     332           38 :   end subroutine initialize_parameters
     333              : 
     334              : 
     335           38 :   subroutine deallocate_arrays()
     336              :     !Deallocation of arrays
     337           38 :     call fit_data_free(fit_data)
     338              :     !Deallocate the temporary coefficient
     339              : 
     340          198 :     do ii=1,size(coeffs_tmp)
     341          198 :       call polynomial_coeff_free(coeffs_tmp(ii))
     342              :     end do
     343          198 :     ABI_SFREE(coeffs_tmp)
     344              : 
     345              :     !do ii =1, my_ncoeff
     346         5043 :     do ii=1,size(my_coeffs)
     347         5043 :       call polynomial_coeff_free(my_coeffs(ii))
     348              :     end do
     349         5043 :     ABI_SFREE(my_coeffs)
     350              : 
     351          198 :     do ii=1,size(coeffs_out)
     352          198 :       call polynomial_coeff_free(coeffs_out(ii))
     353              :     end do
     354          198 :     ABI_SFREE(coeffs_out)
     355              : 
     356              :     !Deallocate fixed eff_pot
     357           38 :     call effective_potential_free(eff_pot_fixed)
     358              :     !Other deallocations
     359           38 :     ABI_SFREE(list_bound)
     360           38 :     ABI_SFREE(list_fix)
     361           38 :     ABI_SFREE(gf_values_iter)
     362           38 :     ABI_SFREE(buffsize)
     363           38 :     ABI_SFREE(buffdisp)
     364           38 :     ABI_SFREE(buffGF)
     365           38 :     ABI_SFREE(coeff_values)
     366           38 :     ABI_SFREE(energy_coeffs)
     367           38 :     ABI_SFREE(energy_coeffs_tmp)
     368           38 :     ABI_SFREE(fcart_coeffs)
     369           38 :     ABI_SFREE(fcart_coeffs_tmp)
     370           38 :     ABI_SFREE(gf_mpi)
     371           38 :     ABI_SFREE(gf_values)
     372           38 :     ABI_SFREE(list_coeffs)
     373           38 :     ABI_SFREE(list_coeffs_tmp)
     374           38 :     ABI_SFREE(list_coeffs_tmp2)
     375           38 :     ABI_SFREE(my_coeffindexes)
     376           38 :     ABI_SFREE(my_coefflist)
     377           38 :     ABI_SFREE(singular_coeffs)
     378           38 :     ABI_SFREE(strten_coeffs)
     379           38 :     ABI_SFREE(strten_coeffs_tmp)
     380           38 :     ABI_SFREE(stat_coeff)
     381              : 
     382           38 :     ABI_FREE(isselected)
     383           38 :     ABI_FREE(isbanned)
     384           38 :     ABI_SFREE(fixcoeff_corr)
     385           38 :     ABI_SFREE(fix_and_impose)
     386           38 :     ABI_SFREE(list_coeffs_copy)
     387           38 :     ABI_FREE(weights)
     388           38 :   end subroutine deallocate_arrays
     389              : 
     390              :   !> Copy effective potential parameters to a fixed version
     391              :   !>
     392              :   !> If there are no imposed coefficients, copies the potential without coefficients.
     393              :   !> If there are imposed coefficients, copies only those coefficients.
     394              :   !> If nimposecoeff=-1, imposes all coefficients.
     395              :   !>
     396              :   !> Sets ncoeff_model based on number of anharmonic terms.
     397              :   !> Validates that imposed coefficients are within valid range.
     398           38 :   subroutine copy_eff_pot_to_eff_pot_fixed()
     399              :     ! if there is no imposed coefficient, just copy the effpot without any coefficient.
     400              :     ! if impose, copy all the imposed coefficient.
     401              :     ! if nimposedcoeff=-1, impose all the coefficients.
     402              : 
     403              :     !Copy the input effective potential eff_pot to eff_pot fixed
     404              :     !If nimposecoeff=0 the fixed potential is the harmonic potential
     405           38 :     ncoeff_model = eff_pot%anharmonics_terms%ncoeff
     406           38 :     if (nimposecoeff > ncoeff_model)then
     407              :       write(message,'(2a)') "fit_nimposecoeff is greater then the number of anharmonic terms&
     408            0 :         &                          provided by input effective potential."&
     409            0 :         &                         ,"Action -> Change fit_nimposecoeff, and fit_imposecoeff in the input"
     410            0 :       ABI_ERROR(message)
     411              :     endif
     412              :     !Impose some coefficients of the input potential
     413           38 :     if (nimposecoeff > 0)then
     414            0 :       if (any(imposecoeff > ncoeff_model))then
     415              :         write(message,'(2a)') "At least one value in fit_imposeccoeff is greater then the number of anharmonic terms&
     416            0 :           &                              provided by input effective potential."&
     417            0 :           &                            ,"Action -> Change fit_imposecoeff in the input"
     418            0 :         ABI_ERROR(message)
     419              :       endif
     420              : 
     421            0 :       ABI_MALLOC(coeffs_tmp,(nimposecoeff))
     422              :       ! Copy the imposed coefficients to coeffs_tmp, then set them in eff_pot_fixed
     423            0 :       do ia = 1,nimposecoeff
     424            0 :         ii = imposecoeff(ia)
     425              :         ! set imposed coefficient to coeff_tmp
     426              :         call polynomial_coeff_init(eff_pot%anharmonics_terms%coefficients(ii)%coefficient,&
     427              :           &                             eff_pot%anharmonics_terms%coefficients(ii)%nterm,coeffs_tmp(ia),&
     428              :           &                             eff_pot%anharmonics_terms%coefficients(ii)%terms,&
     429              :           &                             eff_pot%anharmonics_terms%coefficients(ii)%name,&
     430            0 :           &                             check = .TRUE.)
     431              :       enddo
     432              :       !Copy the input eff pot, free the coeffs and set the ones who shall be imposed to fixed
     433            0 :       call effective_potential_copy(eff_pot_fixed,eff_pot,comm)
     434            0 :       call effective_potential_freeCoeffs(eff_pot_fixed)
     435            0 :       call effective_potential_setCoeffs(coeffs_tmp,eff_pot_fixed,nimposecoeff)
     436              :       ! set the eff_pot_fixed with coeffs_tmp with imposed coefficients
     437              :       !Deallocate coeffs tmp
     438            0 :       do ii = 1,nimposecoeff
     439            0 :         call polynomial_coeff_free(coeffs_tmp(ii))
     440              :       enddo
     441            0 :       ABI_SFREE(coeffs_tmp)
     442           38 :     elseif (nimposecoeff == -1)then
     443            0 :       call effective_potential_copy(eff_pot_fixed,eff_pot,comm)
     444              :     else
     445           38 :       call effective_potential_copy(eff_pot_fixed,eff_pot,comm)
     446           38 :       call effective_potential_freeCoeffs(eff_pot_fixed)
     447              :     endif
     448           38 :   end subroutine copy_eff_pot_to_eff_pot_fixed
     449              : 
     450              : 
     451              : 
     452              :   !> Combine fixed and imposed coefficients for consistency
     453              :   !>
     454              :   !> This routine:
     455              :   !> - Checks for overlap between fixed and imposed coefficients
     456              :   !> - Corrects the fixed coefficient list to avoid duplicates
     457              :   !> - Handles special cases like nfixcoeff=-1
     458              :   !> - Creates a mapping between original and corrected coefficient indices
     459              :   !> - Sets up arrays for tracking fixed/imposed status
     460              :   !> - Updates nfixcoeff_corr and ncopy_terms accordingly
     461           38 :   subroutine combine_fixcoeff_and_imposecoeff()
     462              :     !Set consistency between fixcoeff and imposecoeff.
     463           38 :     if ( nfixcoeff > 0 .and. nimposecoeff >0)then
     464            0 :       ABI_MALLOC(fix_and_impose,(nfixcoeff))
     465            0 :       fix_and_impose = .FALSE.
     466            0 :       do ii = 1,nfixcoeff
     467            0 :         if (any(imposecoeff == fixcoeff(ii)))then
     468            0 :           fix_and_impose(ii) = .TRUE.
     469              :         endif
     470              :       enddo
     471            0 :       nfix_and_impose = count(fix_and_impose)
     472            0 :       nfixcoeff_corr = nfixcoeff - nfix_and_impose
     473            0 :       ABI_MALLOC(fixcoeff_corr,(nfixcoeff_corr))
     474            0 :       ia = 1
     475            0 :       do ii = 1,nfixcoeff
     476            0 :         if (.not. fix_and_impose(ii))then
     477            0 :           fixcoeff_corr(ia) = fixcoeff(ii)
     478            0 :           ia = ia + 1
     479              :         endif
     480              :       enddo
     481            0 :       ncopy_terms = ncoeff_model - nimposecoeff
     482            0 :       ABI_MALLOC(list_coeffs_copy,(ncopy_terms))
     483            0 :       ia = 1
     484            0 :       do ii = 1,ncoeff_model
     485            0 :         if( .not. any(imposecoeff == ii))then
     486            0 :           list_coeffs_copy(ia) = ii
     487            0 :           ia = ia + 1
     488              :         endif
     489              :       enddo
     490            0 :       do ii = 1,ncopy_terms
     491            0 :         do ia = 1,nfixcoeff_corr
     492            0 :           if (list_coeffs_copy(ii) == fixcoeff_corr(ia))then
     493            0 :             fixcoeff_corr(ia) = ii
     494              :           endif
     495              :         enddo
     496              :       enddo
     497           38 :     elseif (nfixcoeff == -1 .and. nimposecoeff > 0)then
     498            0 :       ABI_MALLOC(fix_and_impose,(ncoeff_model))
     499            0 :       fix_and_impose = .FALSE.
     500            0 :       do ii = 1,ncoeff_model
     501            0 :         if (any( imposecoeff == ii))then
     502            0 :           fix_and_impose(ii) = .TRUE.
     503              :         endif
     504              :       enddo
     505            0 :       nfix_and_impose = nimposecoeff
     506            0 :       ncopy_terms = ncoeff_model - nimposecoeff
     507            0 :       ABI_MALLOC(fixcoeff_corr,(ncopy_terms))
     508            0 :       ABI_MALLOC(list_coeffs_copy,(ncopy_terms))
     509            0 :       ia = 1
     510            0 :       do ii = 1,ncoeff_model
     511            0 :         if (.not. fix_and_impose(ii))then
     512            0 :           fixcoeff_corr(ia) = ia
     513            0 :           list_coeffs_copy(ia) = ii
     514            0 :           ia = ia + 1
     515              :         endif
     516              :       enddo
     517            0 :       nfixcoeff_corr = ncoeff_model- nfix_and_impose
     518           38 :     elseif (nfixcoeff == -1 .and. nimposecoeff ==-1)then
     519            0 :       nfixcoeff_corr = 0
     520            0 :       write(message,'(3a)') "nfixcoeff and nimposecoeff are set to -1.",ch10,&
     521            0 :         &                         "This does not make sense. nfixcoeff will be set to 0."
     522            0 :       if(iam_master) ABI_WARNING(message)
     523            0 :       ncopy_terms = 0
     524            0 :       ABI_MALLOC(list_coeffs_copy,(ncopy_terms))
     525           38 :     elseif (nfixcoeff >0 .and. nimposecoeff ==-1)then
     526            0 :       nfixcoeff_corr = 0
     527            0 :       write(message,'(3a)') "nfixcoeff is > 0 and nimposecoeff is set to -1.",ch10,&
     528            0 :         &                         "This does not make sense. nfixcoeff will be set to 0."
     529            0 :       if(iam_master) ABI_WARNING(message)
     530            0 :       ncopy_terms = 0
     531              :     else
     532           38 :       nfixcoeff_corr = nfixcoeff
     533          114 :       ABI_MALLOC(fixcoeff_corr,(nfixcoeff_corr))
     534              :       !nimposecoeff or nfixcoeff always 0 here so fix_and_impose is empty
     535           38 :       ABI_MALLOC(fix_and_impose,(0))
     536           90 :       fixcoeff_corr = fixcoeff
     537           38 :       ncopy_terms = ncoeff_model
     538          114 :       ABI_MALLOC(list_coeffs_copy,(ncopy_terms))
     539          126 :       do ii = 1,ncopy_terms
     540          126 :         list_coeffs_copy(ii) = ii
     541              :       enddo
     542              :     endif
     543           38 :   end subroutine combine_fixcoeff_and_imposecoeff
     544              : 
     545              : 
     546              :   !> Print the header message for starting the fitting process
     547           38 :   subroutine print_start_fitting()
     548           38 :     if(need_verbose) then
     549         3078 :       write(message,'(a,(80a))') ch10,('-',ii=1,80)
     550           38 :       call wrtout(ab_out,message,'COLL')
     551           38 :       call wrtout(std_out,message,'COLL')
     552           38 :       write(message,'(2a)') ch10,' Starting Fit process'
     553           38 :       call wrtout(ab_out,message,'COLL')
     554           38 :       call wrtout(std_out,message,'COLL')
     555         3078 :       write(message,'(a,(80a))') ch10,('-',ii=1,80)
     556           38 :       call wrtout(ab_out,message,'COLL')
     557           38 :       call wrtout(std_out,message,'COLL')
     558              :     end if
     559           38 :   end subroutine print_start_fitting
     560              : 
     561              :   !> Map history data to supercell and set up cutoff parameters
     562              :   !>
     563              :   !> - Maps history data to supercell if sizes don't match
     564              :   !> - Sets cutoff distance for interactions
     565              :   !> - If cutoff is 0, uses default of cell diagonal/3
     566              :   !> - Calculates supercell size based on cell dimensions
     567           38 :   subroutine map_hist_to_supercell()
     568              :     !if the number of atoms in reference supercell into effpot is not correct,
     569              :     !wrt to the number of atom in the hist, we set map the hist and set the good supercell
     570           38 :     if (size(hist%xred,2) /= eff_pot%supercell%natom) then
     571            0 :       call effective_potential_file_mapHistToRef(eff_pot,hist,comm,verbose=need_verbose)
     572              :     end if
     573              :     !Set the cut off
     574           38 :     cutoff = zero
     575           38 :     if(present(cutoff_in))then
     576           38 :       cutoff = cutoff_in
     577              :     end if
     578              :     !If the cutoff is set to zero, we define a default value
     579              :     ! which is the diagonal of the cell/3.
     580           38 :     if(abs(cutoff)<tol16)then
     581            0 :       do ii=1,3
     582              :         cutoff = cutoff + sqrt(eff_pot%supercell%rprimd(ii,1)**2+&
     583              :           &                           eff_pot%supercell%rprimd(ii,2)**2+&
     584            0 :           &                           eff_pot%supercell%rprimd(ii,3)**2)
     585              :       end do
     586            0 :       cutoff = cutoff / 3.0_dp
     587              :     end if
     588              :     !we get the size of the supercell in the hist file
     589          152 :     do ii=1,3
     590              :       sc_size(ii) = int(anint(sqrt(eff_pot%supercell%rprimd(ii,1)**2+&
     591              :         &                               eff_pot%supercell%rprimd(ii,2)**2+&
     592              :         &                               eff_pot%supercell%rprimd(ii,3)**2) / &
     593              :         &                          sqrt(eff_pot%crystal%rprimd(ii,1)**2+&
     594              :         &                               eff_pot%crystal%rprimd(ii,2)**2+&
     595          152 :         &                               eff_pot%crystal%rprimd(ii,3)**2)))
     596              :     end do
     597           38 :   end subroutine map_hist_to_supercell
     598              : 
     599              :   !> Generate or retrieve list of coefficients to be fitted
     600              :   !>
     601              :   !> This routine either:
     602              :   !> - Uses coefficients present in the input effective potential, or
     603              :   !> - Generates a new list of coefficients based on symmetries and cutoffs
     604              :   !>
     605              :   !> For each atom to fit:
     606              :   !> - Generates coefficients within cutoff radius
     607              :   !> - Handles special cases like fit_iatom=-2 (fit all atoms)
     608              :   !> - Validates coefficient generation parameters
     609              :   !> - Sets up coefficient arrays and counters
     610           38 :   subroutine generate_list_of_coefficients_to_fit()
     611              :     integer :: max_nbody_tmp(20)
     612              :     !Get the list of coefficients to fit:
     613              :     !get from the eff_pot type (from the input)
     614              :     !or
     615              :     !regenerate the list
     616           38 :     my_ncoeff = 0
     617           38 :     ncoeff_tot = 0
     618              : 
     619              :     !Reset ncoeff_tot
     620           38 :     if(ncoeff_model > 0)then
     621           27 :       if(need_verbose)then
     622           27 :         write(message, '(4a)' )ch10,' The coefficients present in the effective',&
     623           54 :           &    ' potential will be used for the fit'
     624           27 :         call wrtout(std_out,message,'COLL')
     625           27 :         call wrtout(ab_out,message,'COLL')
     626              :       end if
     627              :     end if
     628              : 
     629          114 :     ABI_MALLOC(symbols,(eff_pot%crystal%natom))
     630              :     call symbols_crystal(eff_pot%crystal%natom,eff_pot%crystal%ntypat,eff_pot%crystal%npsp,&
     631           38 :       &                     symbols,eff_pot%crystal%typat,eff_pot%crystal%znucl)
     632              : 
     633           38 :     if (fit_iatom_all .and. generateterm==1) then
     634            0 :       atom_start = 1
     635            0 :       atom_end = eff_pot%crystal%nirredat
     636              :     else
     637           38 :       atom_start = fit_iatom_in
     638           38 :       atom_end = fit_iatom_in
     639              :     end if
     640              : 
     641           38 :     if(generateterm == 1)then
     642              :       ! we need to regenerate them
     643           38 :       ncoeff_tot = 0
     644           76 :       do ii = atom_start, atom_end
     645           38 :         if (fit_iatom_all) then  ! fit_iatom=-2
     646            0 :           fit_iatom_in=eff_pot%crystal%irredatindx(ii)
     647              :         end if
     648           38 :         if(need_verbose)then
     649           38 :           if(fit_iatom_in > 0)then
     650           31 :             write(message, '(2a,I3,4a)' )ch10,' The coefficients for the fit around atom', fit_iatom_in,': ',&
     651           62 :               &                                    trim(symbols(fit_iatom_in)),', will be generated',ch10
     652           31 :             call wrtout(std_out,message,'COLL')
     653           31 :             call wrtout(ab_out,message,'COLL')
     654              :           else
     655            7 :             write(message, '(3a)' )ch10,' The coefficients for the fit will be generated with all cross terms',ch10
     656            7 :             call wrtout(std_out,message,'COLL')
     657            7 :             call wrtout(ab_out,message,'COLL')
     658              :           endif
     659           38 :           write(message,'(a,F6.3,a)') " Cutoff of ",cutoff," Bohr is imposed"
     660           38 :           call wrtout(std_out,message,'COLL')
     661              :         end if  !need_verbose
     662              : 
     663          798 :           max_nbody_tmp(:) = 20
     664          153 :           max_nbody_tmp(1: size(max_nbody)) = max_nbody
     665              :         call polynomial_coeff_getNorder(coeffs_iatom,eff_pot%crystal,cutoff,my_ncoeff,ncoeff_tot_tmp,power_disps,&
     666              :           &                                  max_power_strain_in,0,sc_size,comm,anharmstr=(ii==1 .and. need_anharmstr),&
     667              :           &                                  spcoupling=need_spcoupling,distributed=.true.,&
     668              :           &                                  only_odd_power=need_only_odd_power,&
     669              :           &                                  only_even_power=need_only_even_power,&
     670              :           &                                  fit_iatom=fit_iatom_in,dispterms=need_disp, &
     671           73 :           &                                  max_nbody=max_nbody_tmp)
     672              : 
     673              : 
     674           76 :         if (.not. fit_iatom_all) then
     675           38 :           call polynomial_coeff_list_free(coeffs_tmp)
     676           38 :           ncoeff_tot = ncoeff_tot_tmp
     677         5071 :           ABI_MALLOC(coeffs_tmp,(my_ncoeff))
     678              :           !if(allocated(coeffs_iatom)) then
     679           38 :           call coeffs_list_copy(coeffs_tmp,coeffs_iatom)
     680           38 :           call polynomial_coeff_list_free(coeffs_iatom)
     681              :           !end if
     682              :         else
     683            0 :           ncoeff_tot = ncoeff_tot+ncoeff_tot_tmp
     684            0 :           if(.not.(allocated(coeffs_tmp))) then
     685            0 :             ABI_MALLOC(coeffs_tmp,(size(coeffs_iatom)))
     686            0 :             call coeffs_list_copy(coeffs_tmp,coeffs_iatom)
     687              :           else
     688              :           ! FIXME: this does not work on ubu_intel
     689            0 :             if(allocated(coeffs_iatom))  then
     690            0 :               call coeffs_list_conc_onsite(coeffs_tmp,coeffs_iatom)
     691              :             endif
     692              :           end if ! not allocate coeffs_tmp
     693            0 :           call polynomial_coeff_list_free(coeffs_iatom)
     694              :         end if  !fit_iatom/=-2
     695              :       end do  ! ii = atom_start, atom_end
     696              : 
     697              :       !call coeffs_list_reduce_duplicate(coeffs_tmp, eff_pot%crystal, sc_size, fit_iatom_in, cutoff , power_disps(2))
     698           38 :       my_ncoeff = size(coeffs_tmp)
     699           38 :       if (fit_iatom_all .and. iam_master) then
     700              :         ! FIXME: this does not compile on alpa intel 2025 elpa!
     701            0 :         message=ch10 // ' fit_iatom = -2 : The total number of coefficients for all atoms are'// itoa(my_ncoeff) // ch10
     702            0 :         call wrtout(std_out,message,'COLL')
     703            0 :         call wrtout(ab_out,message,'COLL')
     704              :       end if
     705              :     end if   ! generateterm == 1
     706           38 :     ABI_FREE(symbols)
     707           38 :   end subroutine generate_list_of_coefficients_to_fit
     708              : 
     709              :    !> Check if a coefficient is a duplicate of any in the given list
     710              :    !>
     711              :    !> This function:
     712              :    !> - Compares a coefficient against a list of existing coefficients
     713              :    !> - Checks both direct and inverse term comparisons
     714              :    !> - Returns true if a match is found, false otherwise
     715              :    !>
     716              :    !> @param coeff The coefficient to check
     717              :    !> @param lcoeffs List of coefficients to compare against
     718              :    !> @param ncoeff_to_compare Number of coefficients to compare
     719              :    !> @return found True if duplicate found, false otherwise
     720           42 :    function is_duplicate_coeff(coeff, lcoeffs, ncoeff_to_compare) result(found)
     721              :      type(polynomial_coeff_type), intent(in):: coeff, lcoeffs(:)
     722              :      integer, intent(in) :: ncoeff_to_compare
     723              :      logical :: found
     724           42 :      found =.False.
     725           42 :      do ii=1, ncoeff_to_compare
     726            0 :        if(terms_compare(coeff%terms(1), lcoeffs(ii)%terms(1))) then
     727              :          found=.True.
     728              :          cycle
     729              :        end if
     730           42 :        if(terms_compare_inverse(coeff%terms(1), lcoeffs(ii)%terms(1))) then
     731            0 :          found=.True.
     732              :          cycle
     733              :        end if
     734              :      end do
     735           42 :    end function is_duplicate_coeff
     736              : 
     737              : 
     738              :   !> Read or write coefficients to XML file based on coeff_file_rw setting
     739              :   !>
     740              :   !> This routine:
     741              :   !> - If coeff_file_rw=1: Writes generated coefficients to XML file
     742              :   !> - If coeff_file_rw=2: Reads coefficients from XML file
     743              :   !> - Redistributes coefficients across CPUs for parallel processing
     744              :   !> - Updates coefficient counts and data structures accordingly
     745              :   !>
     746              :   !> Handles MPI distribution of coefficients when reading from file
     747           38 :   subroutine read_or_write_coeffs_to_xml()
     748              : 
     749           38 :     if(present(coeff_file_rw)) then
     750              :         ! TODO hexu: This functionality needs more test and is now temporarily disabled
     751              :         ! If test ok, remove setting it to 0.
     752              : 
     753           38 :       if (coeff_file_rw==1 .and. generateterm_in == 1 ) then
     754            0 :         write (filename, "(A9,I2,I2,A4)") "TEST_TERMS", my_rank+1,fit_iatom_in,".xml"
     755            0 :         call polynomial_coeff_writeXML(coeffs_tmp,my_ncoeff,filename=filename)
     756              :       end if
     757              : 
     758           38 :       if (coeff_file_rw==2) then
     759            0 :         ncoeff_tot = read_effective_potential%anharmonics_terms%ncoeff
     760            0 :         if (iam_master) then
     761            0 :           write(message,'(1a,I7,1a)')' Reading coefficients from file',ncoeff_tot,' Coefficients read'
     762            0 :           call wrtout(std_out,message,'COLL')
     763            0 :           write(message,'(1a)')' Redistributing the coefficients over CPUs'
     764            0 :           call wrtout(std_out,message,'COLL')
     765              :         end if
     766              : 
     767            0 :         ncoeff_alone = mod(ncoeff_tot,nproc)
     768            0 :         my_ncoeff_simple = int(aint(real(ncoeff_tot,sp)/(nproc)))
     769            0 :         if(ncoeff_alone == 0 .and. ncoeff_tot >= nproc)then
     770            0 :           my_ncoeff_start = (my_ncoeff_simple * my_rank) + 1
     771            0 :           my_ncoeff_end   = my_ncoeff_start + my_ncoeff_simple - 1
     772            0 :         else if(ncoeff_tot < nproc)then
     773            0 :           if(my_rank + 1 <= ncoeff_tot)then !myrank smaller than ncombi
     774            0 :             my_ncoeff_start = my_rank + 1
     775            0 :             my_ncoeff_end = my_ncoeff_start
     776              :           else
     777            0 :             my_ncoeff_start = ncoeff_tot + 1 !myrank bigger than ncombi
     778            0 :             my_ncoeff_end = ncoeff_tot + 1
     779              :           endif
     780            0 :         else if(ncoeff_tot > nproc .and. ncoeff_alone /= 0)then
     781            0 :           if(my_rank >= (nproc-ncoeff_alone)) then
     782            0 :             my_ncoeff_start = (my_ncoeff_simple * my_rank) + 1 + (my_rank - nproc + ncoeff_alone)
     783            0 :             my_ncoeff_end = my_ncoeff_start + my_ncoeff_simple
     784              :           else
     785            0 :             my_ncoeff_start = (my_ncoeff_simple * my_rank) + 1
     786            0 :             my_ncoeff_end   = my_ncoeff_start + my_ncoeff_simple - 1
     787              :           endif
     788              :         end if
     789            0 :         if(my_ncoeff_end <= ncoeff_tot)then
     790            0 :           my_ncoeff = my_ncoeff_end+1-my_ncoeff_start
     791              :         else
     792            0 :           my_ncoeff = 0
     793              :         endif
     794            0 :         call polynomial_coeff_list_free(coeffs_tmp)
     795            0 :         ABI_MALLOC(coeffs_tmp,(my_ncoeff))
     796            0 :         if(my_ncoeff /= 0)coeffs_tmp = read_effective_potential%anharmonics_terms%coefficients(my_ncoeff_start:my_ncoeff_end)
     797              :       end if
     798              :     end if
     799           38 :   end subroutine read_or_write_coeffs_to_xml
     800              : 
     801              :   !> Distribute coefficients across CPUs for parallel processing
     802              :   !>
     803              :   !> This routine:
     804              :   !> - Determines coefficient distribution across MPI ranks
     805              :   !> - Creates mapping arrays for coefficient indexing
     806              :   !> - Copies/initializes coefficients on each CPU
     807              :   !> - Handles special case for CPU0 which gets input coefficients
     808              :   !> - Sets up MPI communication patterns
     809              :   !> - Updates global coefficient arrays and indexing
     810              :   !> - Frees temporary storage after distribution
     811           38 :   subroutine assign_coeffs_to_cpu()
     812              :     !Get the list with the number of coeff on each CPU
     813              :     !In order to be abble to compute the my_coeffindexes array which is for example:
     814              :     ! if CPU0 has 200  Coeff and CPU1 has 203 Coeff then
     815              :     ! for CPU0:my_coeffindexes=>1-200 and for CPU1:my_coeffindexes=>201-403
     816              :     !Also fill the my_coeffs array with the generated coefficients and/or the coefficient from the input xml
     817          114 :     ABI_MALLOC(buffin,(nproc))
     818          132 :     buffin = 0
     819           38 :     buffin(my_rank+1) = my_ncoeff
     820              :     call xmpi_sum(buffin,comm,ierr)
     821          114 :     ABI_MALLOC(my_coeffindexes,(my_ncoeff))
     822           76 :     ABI_MALLOC(my_coefflist,(my_ncoeff))
     823         5119 :     ABI_MALLOC(my_coeffs,(my_ncoeff))
     824         5043 :     do icoeff=1,my_ncoeff
     825         5005 :       jcoeff = icoeff
     826         5005 :       my_coefflist(icoeff) = icoeff
     827              : 
     828         5005 :       if(my_rank==0) then
     829         3850 :         my_coeffindexes(icoeff) = icoeff
     830              :       else
     831         3003 :         my_coeffindexes(icoeff) = sum(buffin(1:my_rank)) + icoeff
     832              :       end if
     833              : 
     834              :       !  Only copy the input coefficients on the CPU0
     835         5005 :       if(my_rank==0) then
     836         3850 :         if(icoeff <= ncopy_terms)then
     837           48 :           coeffs_in => eff_pot%anharmonics_terms%coefficients
     838           48 :           jcoeff = list_coeffs_copy(icoeff)
     839              :         else
     840         3802 :           coeffs_in => coeffs_tmp
     841         3802 :           jcoeff = jcoeff - ncopy_terms
     842              :         end if
     843              :       else
     844         1155 :         coeffs_in => coeffs_tmp
     845              :       end if
     846              :       ! set the my_coeffs.
     847              :       call polynomial_coeff_init(zero,coeffs_in(jcoeff)%nterm,&
     848              :         &                             my_coeffs(icoeff),coeffs_in(jcoeff)%terms,&
     849              :         &                             coeffs_in(jcoeff)%name,&
     850         5005 :         &                             check=.true.)
     851         5043 :       call polynomial_coeff_free(coeffs_in(jcoeff))
     852              :     end do
     853              : 
     854              :     !Deallocation
     855         4995 :     ABI_SFREE(coeffs_tmp)
     856           38 :     NULLIFY(coeffs_in)
     857           38 :     ABI_FREE(buffin)
     858              : 
     859              :     !wait everybody
     860           38 :     call xmpi_barrier(comm)
     861              : 
     862              :     !Reset the output (we free the memory)
     863           38 :     call effective_potential_freeCoeffs(eff_pot)
     864           38 :   end subroutine assign_coeffs_to_cpu
     865              : 
     866           38 :   subroutine get_num_fixed_coeff()
     867              :     !Get number of fixed coeff
     868           38 :     ncoeff_fix = 0
     869           38 :     if(nfixcoeff_corr /=0) then
     870           27 :       if(nfixcoeff_corr == -1)then
     871           20 :         ncoeff_fix = ncoeff_model
     872              :       else
     873            7 :         ncoeff_fix = nfixcoeff_corr
     874              :       endif
     875              :     endif
     876              :   end subroutine get_num_fixed_coeff
     877              : 
     878              :   !> Check if ncoeff_in value is valid and adjust if needed
     879              :   !>
     880              :   !> This routine:
     881              :   !> - Verifies ncoeff_in is not zero or larger than ncoeff_tot
     882              :   !> - Displays warning if ncoeff_in needs adjustment
     883              :   !> - Sets ncoeff_in to ncoeff_tot if invalid
     884              :   !> - Handles special case when nfixcoeff_corr = -1
     885           38 :   subroutine check_sanity_ncoeff_in()
     886              :     !Check if ncycle_in is not zero or superior to ncoeff_tot
     887           38 :     if(need_verbose.and.(ncoeff_in > ncoeff_tot).or.(ncoeff_in<0.and.nfixcoeff_corr /= -1)) then
     888            0 :       write(message, '(6a,I0,3a)' )ch10,&
     889            0 :         &        ' --- !WARNING',ch10,&
     890            0 :         &        '     The number of coeff requested in the input is not correct.',ch10,&
     891            0 :         &        '     This number will be set to the maximum of coefficients: ',ncoeff_tot,ch10,&
     892            0 :         &        ' ---',ch10
     893            0 :       call wrtout(std_out,message,"COLL")
     894              :     end if
     895           38 :   end subroutine check_sanity_ncoeff_in
     896              :   !> Initialize coefficient selection status arrays
     897              :   !>
     898              :   !> This routine:
     899              :   !> - Allocates arrays to track coefficient status
     900              :   !> - Initializes isselected array for tracking selected coefficients
     901              :   !> - Initializes isbanned array for tracking banned coefficients
     902              :   !> - Sets initial remaining coefficient count
     903           38 :   subroutine initialize_tags_for_coeffs()
     904              :     ! initialize isselected and isbanned
     905          114 :     ABI_MALLOC(isselected, (ncoeff_tot))
     906           76 :     ABI_MALLOC(isbanned, (ncoeff_tot))
     907           38 :     n_remaining=ncoeff_tot
     908         8779 :     isselected(:)=.False.
     909         8779 :     isbanned(:)=.False.
     910           38 :   end subroutine initialize_tags_for_coeffs
     911              : 
     912              : 
     913              : !  subroutine select_bounding_terms()
     914              : !      integer :: ico
     915              : !      type(int_array_type) :: ind_bound
     916              : !      nbound=0
     917              : !      do ico=1, size(my_coeffs)
     918              : !        if ( my_coeffs(ico)%isbound==1) then
     919              : !          ! If it is already imposed/fixed, it needs not to be added.
     920              : !          !if (.not.(any(fixcoeff_corr==my_coeffindexes(ico)))) then
     921              : !            nbound =nbound +1
     922              : !            call ind_bound%push(my_coeffindexes(ico))
     923              : !            isselected(my_coeffindexes(ico))=.True.
     924              : !          !end if
     925              :           !end if
     926              : !      end do
     927              : !      call xmpi_sum(nbound, comm, ierr)
     928              : !      call ind_bound%allgatherv(list_bound, comm, nproc)
     929              : !      call xmpi_bcast(list_bound, master, comm, ierr)
     930              : !      call ind_bound%finalize()
     931              : !      call xmpi_lor(isselected, comm)
     932              : !      !if (nbound /=count(isselected)) then
     933              : !      !  ABI_ERROR("The number of the bounding term is not consistent with the selected terms.")
     934              : !      !end if
     935              : !  end subroutine select_bounding_terms
     936              : 
     937              :   !> Select and mark fixed coefficient terms
     938              :   !>
     939              :   !> This routine:
     940              :   !> - Handles fixed coefficient selection based on nfixcoeff_corr
     941              :   !> - For nfixcoeff_corr > 0: Selects specific fixed coefficients
     942              :   !> - For nfixcoeff_corr = -1: Selects all coefficients up to ncoeff_model
     943              :   !> - Updates isselected array to mark fixed terms
     944              :   !> - Validates selection count matches expected number
     945              :   !> - Uses MPI to synchronize selection across processes
     946           38 :   subroutine select_fix_terms()
     947              :     integer :: ico, ifix
     948           38 :     type(int_array_type) :: ind_fix
     949           38 :     nfix=0
     950              : 
     951           52 :     if(nfixcoeff_corr>0) then
     952          163 :       do ico=1, size(my_coeffs)
     953          156 :         ifix=my_coeffindexes(ico)
     954          466 :         if( any(fixcoeff_corr==ifix) ) then
     955            6 :           nfix=nfix+1
     956            6 :           call ind_fix%push(ifix)
     957            6 :           isselected(ifix)=.True.
     958              :         end if
     959              :       end do
     960              :       call xmpi_sum(nfix, comm, ierr)
     961            7 :       call ind_fix%allgatherv(list_fix, comm, nproc)
     962              :       call xmpi_bcast(list_fix, master, comm, ierr)
     963            7 :       call ind_fix%finalize()
     964            7 :       call xmpi_lor(isselected, comm)
     965          371 :       if (nfix/=count(isselected)) then
     966            0 :         ABI_ERROR("The number of the fixed term is not consistent with the selected terms.")
     967              :       end if
     968           71 :     else if(nfixcoeff_corr==-1) then
     969         3114 :       do ico=1, size(my_coeffs)
     970         3094 :         ifix=my_coeffindexes(ico)
     971         3114 :         if( ifix<=ncoeff_model) then
     972           36 :           nfix=nfix+1
     973           36 :           call ind_fix%push(ifix)
     974           36 :           isselected(ifix)=.True.
     975              :         end if
     976              :       end do
     977              :       call xmpi_sum(nfix, comm, ierr)
     978           20 :       call ind_fix%allgatherv(list_fix, comm, nproc)
     979              :       call xmpi_bcast(list_fix, master, comm, ierr)
     980           20 :       call ind_fix%finalize()
     981           20 :       call xmpi_lor(isselected, comm)
     982         5506 :       if (nfix/=count(isselected)) then
     983            0 :         ABI_ERROR("The number of the fixed term is not consistent with the selected terms.")
     984              :       end if
     985              :     end if
     986              : 
     987           38 :   end subroutine select_fix_terms
     988              : 
     989              : 
     990              : 
     991              :   !> Calculate number of preselected coefficients and handle banned terms
     992              :   !>
     993              :   !> This routine:
     994              :   !> - Updates ncoeff_model and ncoeff_tot
     995              :   !> - Initializes ncoeff_preselected counter
     996              :   !> - Marks banned coefficients in isbanned array
     997              :   !> - Handles special case when nfixcoeff_corr = -1
     998              :   !> - Outputs informative messages about coefficient selection
     999              :   !> - Synchronizes banned coefficient status across MPI processes
    1000           38 :   subroutine get_ncoeff_preselected()
    1001              :     !Use fixcoeff
    1002              :     !ncoeff_preselected store the curent number of coefficient in the model
    1003              :     !Do not reset this variable...
    1004              : 
    1005           38 :     ncoeff_model = eff_pot%anharmonics_terms%ncoeff
    1006           38 :     ncoeff_tot = ncoeff_tot + ncoeff_model
    1007           38 :     ncoeff_preselected = 0
    1008              : 
    1009           38 :     isbanned(bancoeff(1: nbancoeff))=.True.
    1010           38 :     call xmpi_lor(isbanned, comm)
    1011              : 
    1012              : 
    1013           38 :     if (nfixcoeff_corr == -1)then
    1014           20 :       write(message, '(3a)')' nfixcoeff is set to -1, the coefficients present in the model',&
    1015           40 :         &                        ' are imposed.',ch10
    1016              :     else
    1017           18 :       if (nfixcoeff_corr > 0)then
    1018           21 :         if(maxval(fixcoeff_corr(:)) > ncoeff_tot) then
    1019            0 :           write(message, '(4a,I0,6a)' )ch10,&
    1020            0 :             &        ' --- !WARNING',ch10,&
    1021            0 :             &        '     The value ',maxval(fixcoeff_corr(:)),' is not in the list.',ch10,&
    1022            0 :             &        '     Start from scratch...',ch10,&
    1023            0 :             &        ' ---',ch10
    1024              :         else
    1025            7 :           write(message, '(2a)')' Some coefficients are imposed from the input.',ch10
    1026              :         end if
    1027              :       else
    1028           11 :         write(message, '(4a)')' There is no coefficient imposed from the input.',ch10,&
    1029           22 :           &                        ' Start from scratch',ch10
    1030              :       end if
    1031              :     end if
    1032              : 
    1033           38 :     ncoeff_preselected = ncoeff_preselected + nfix
    1034              : 
    1035           38 :     if(need_verbose) call wrtout(std_out,message,'COLL')
    1036           38 :   end subroutine get_ncoeff_preselected
    1037              : 
    1038              :   !> Calculate number of coefficients to select and fit
    1039              :   !>
    1040              :   !> This routine:
    1041              :   !> - Computes ncoeff_to_select based on ncoeff_in
    1042              :   !> - Computes ncoeff_to_fit by adding preselected coefficients
    1043              :   !> - Validates that total coefficients don't exceed maximum allowed
    1044              :   !> - Adjusts counts if needed and displays warnings
    1045              :   !> - Handles special case for option 2 (Monte Carlo mode)
    1046              :   !> - Updates ncoeff_to_select and ncoeff_to_fit accordingly
    1047           38 :   subroutine get_ncoeff_to_select_and_ncoeff_to_fit()
    1048              :     !Compute the number of cycle:
    1049           38 :     ncoeff_to_select     = ncoeff_in
    1050           38 :     if (ncoeff_in + nimposecoeff + nfix > ncoeff_tot .and. generateterm_in==0) then
    1051            0 :       ncoeff_to_select = ncoeff_tot - nimposecoeff - nfix
    1052            0 :       write(message, '(4a,I0,2a,I0,2a,I0,3a)' )ch10,&
    1053            0 :         &      ' --- !WARNING',ch10,&
    1054            0 :         &      '     The number of cycle + the number of imposed coefficients: ',ncoeff_to_select,ch10,&
    1055            0 :         &      '     is superior to the maximum number of coefficients in the initial list: ',ncoeff_tot,ch10,&
    1056            0 :         &      '     The number of cycle is set to ',ncoeff_to_select,ch10,&
    1057            0 :         &      ' ---',ch10
    1058            0 :       if(need_verbose) call wrtout(std_out,message,'COLL')
    1059              :     end if
    1060              :     !Compute the maximum number of cycle
    1061           38 :     ncoeff_to_fit = ncoeff_to_select + ncoeff_preselected
    1062              : 
    1063              : 
    1064              :     !Check if the number of request cycle + the initial number of coeff is superior to
    1065              :     !the maximum number of coefficient allowed
    1066           38 :     if(ncoeff_to_fit > ncoeff_tot .and. generateterm_in==0) then
    1067            0 :       ncoeff_to_select = ncoeff_tot - ncoeff_preselected -nimposecoeff
    1068            0 :       ncoeff_to_fit = ncoeff_tot-nimposecoeff
    1069              : 
    1070            0 :       write(message, '(4a,I0,2a,I0,2a,I0,3a)' )ch10,&
    1071            0 :         &      ' --- !WARNING',ch10,&
    1072            0 :         &      '     The number of cycle + the number of imposed coefficients: ',ncoeff_to_fit,ch10,&
    1073            0 :         &      '     is superior to the maximum number of coefficients in the initial list: ',ncoeff_tot,ch10,&
    1074            0 :         &      '     The number of cycle is set to ',ncoeff_to_select,ch10,&
    1075            0 :         &      ' ---',ch10
    1076            0 :       if(need_verbose) call wrtout(std_out,message,'COLL')
    1077           38 :     else if (option==2)then
    1078              :       !  Always set to the maximum
    1079            0 :       ncoeff_to_fit = ncoeff_tot
    1080              :     end if
    1081              : 
    1082              :     ! Debug the number of coefficients to fit
    1083              : 
    1084           38 :   end subroutine get_ncoeff_to_select_and_ncoeff_to_fit
    1085              : 
    1086              :   !> Initialize parameters and arrays needed for coefficient fitting
    1087              :   !>
    1088              :   !> This routine:
    1089              :   !> - Sets up constants for fitting process (ntime, natom_sc, ncell, factor)
    1090              :   !> - Allocates arrays for energy, forces and stress coefficients
    1091              :   !> - Initializes list_coeffs array for tracking coefficients
    1092              :   !> - Handles fixed coefficients from previous selections
    1093              :   !> - Sets up data structures for decomposing forces and stresses
    1094              :   !> - Computes constants through fit_data_compute
    1095              :   !> - Initializes storage for fit results based on memory settings
    1096           38 :   subroutine initialize_fitting_parameters_for_coefficients()
    1097              :     !Initialisation of constants
    1098           38 :     ntime    = hist%mxhist
    1099           38 :     natom_sc = eff_pot%supercell%natom
    1100           38 :     ncell    = eff_pot%supercell%ncells
    1101           38 :     factor   = 1._dp/natom_sc
    1102              : 
    1103              :     !Initialisation of arrays:
    1104          152 :     ABI_MALLOC(energy_coeffs_tmp,(ncoeff_to_fit,ntime))
    1105          114 :     ABI_MALLOC(list_coeffs,(ncoeff_to_fit))
    1106          190 :     ABI_MALLOC(fcart_coeffs_tmp,(3,natom_sc,ncoeff_to_fit,ntime))
    1107          152 :     ABI_MALLOC(strten_coeffs_tmp,(6,ntime,ncoeff_to_fit))
    1108              :     !ABI_MALLOC(weights, (ntime))
    1109          198 :     list_coeffs  = 0
    1110              : 
    1111              : 
    1112              : 
    1113           38 :     if(nfix > 0) then
    1114          101 :       do ii = 1,nfix
    1115          101 :         list_coeffs(ii) = list_fix(ii)
    1116              :       end do
    1117              :     end if
    1118              : 
    1119              :     !if ncoeff_preselected > 0 fill list_coeffs with the fixed coefficients
    1120              :     ! TODO: check if the bounding terms are already in the list of fixed.
    1121              :     !if(ncoeff_preselected > nbound)then
    1122              :     !  do ii = nbound+1,ncoeff_preselected
    1123              :     !    if(nfixcoeff_corr == -1)then
    1124              :     !      if(ii <= ncoeff_model)then
    1125              :     !        list_coeffs(ii) = ii
    1126              :     !        isselected(ii) = .True.
    1127              :     !      end if
    1128              :     !    else
    1129              :     !      list_coeffs(ii) = fixcoeff_corr(ii-nbound)
    1130              :     !      isselected(fixcoeff_corr(ii-nbound)) = .True.
    1131              :     !    end if
    1132              :     !  end do
    1133              :     !end if
    1134              :     !call  xmpi_lor(isselected, comm)
    1135              : 
    1136              : 
    1137              :     !Get the decomposition for each coefficients of the forces and stresses for
    1138              :     !each atoms and each step  equations 11 & 12 of  PRB95,094115(2017) [[cite:Escorihuela-Sayalero2017]]
    1139           38 :     if(need_verbose)then
    1140           38 :       write(message, '(a)' ) ' Initialisation of the fit process...'
    1141           38 :       call wrtout(std_out,message,'COLL')
    1142              :     end if
    1143              :     !Before the fit, compute constants with fit_data_compute.
    1144              :     !Conpute the strain of each configuration.
    1145              :     !Compute the displacmeent of each configuration.
    1146              :     !Compute the variation of the displacement due to strain of each configuration.
    1147              :     !Compute fixed forces and stresse and get the standard deviation.
    1148              :     !Compute Sheppard and al Factors  \Omega^{2} see J.Chem Phys 136, 074103 (2012) [[cite:Sheppard2012]].
    1149           38 :     call fit_data_compute(fit_data,eff_pot,hist,comm,verbose=need_verbose)
    1150              : 
    1151              :     !Get the decomposition for each coefficients of the forces,stresses and energy for
    1152              :     !each atoms and each step  (see equations 11 & 12 of
    1153              :     !PRB95,094115(2017)) [[cite:Escorihuela-Sayalero2017]]+ allocation
    1154              :     !If the user does not turn off this initialization, we store all the information for the fit,
    1155              :     !it will reduce the computation time but increase a lot the memory...
    1156           38 :     if(need_initialize_data)then
    1157            0 :       ABI_MALLOC(energy_coeffs,(my_ncoeff,ntime))
    1158            0 :       ABI_MALLOC(fcart_coeffs,(3,natom_sc,my_ncoeff,ntime))
    1159            0 :       ABI_MALLOC(strten_coeffs,(6,ntime,my_ncoeff))
    1160              :       call fit_polynomial_coeff_getFS(my_coeffs,fit_data%training_set%du_delta,&
    1161              :         &                                 fit_data%training_set%displacement,&
    1162              :         &                                 energy_coeffs,fcart_coeffs,natom_sc,eff_pot%crystal%natom,&
    1163              :         &                                 my_ncoeff,ntime,sc_size,fit_data%training_set%strain,&
    1164            0 :         &                                 strten_coeffs,fit_data%training_set%ucvol,my_coefflist,my_ncoeff)
    1165              :     else
    1166              :       !  Allocate just 1 dimension ! Save MEMORY !
    1167          114 :       ABI_MALLOC(energy_coeffs,(1,ntime))
    1168          152 :       ABI_MALLOC(fcart_coeffs,(3,natom_sc,1,ntime))
    1169          114 :       ABI_MALLOC(strten_coeffs,(6,ntime,1))
    1170              :     end if
    1171           38 :   end subroutine initialize_fitting_parameters_for_coefficients
    1172              : 
    1173              :   !> Initialize goal function parameters and arrays
    1174              :   !>
    1175              :   !> This routine:
    1176              :   !> - Allocates arrays for tracking coefficients and goal function values
    1177              :   !> - Sets up MPI communication buffers and patterns
    1178              :   !> - Handles previously imposed coefficients from input
    1179              :   !> - Computes initial goal function values for fixed terms
    1180              :   !> - Initializes arrays for tracking coefficient values and statistics
    1181              :   !> - Sets up tracking of goal function values during iterations
    1182              :   !> - Prints initial goal function values if in verbose mode
    1183              :   !> - Synchronizes data across MPI processes
    1184           38 :   subroutine initialize_gf()
    1185              :     integer :: ipre, duplicated, ipre_real
    1186           38 :     real(dp) , allocatable :: weights1(:)
    1187              :     !Allocation of arrays
    1188          274 :     ABI_MALLOC(coeffs_tmp,(ncoeff_to_fit))
    1189          114 :     ABI_MALLOC(singular_coeffs,(max(1,my_ncoeff)))
    1190          114 :     ABI_MALLOC(coeff_values,(ncoeff_to_fit))
    1191          114 :     ABI_MALLOC(gf_values,(4,max(1,my_ncoeff)))
    1192          114 :     ABI_MALLOC(list_coeffs_tmp,(ncoeff_to_fit))
    1193           76 :     ABI_MALLOC(list_coeffs_tmp2,(ncoeff_to_fit))
    1194          114 :     ABI_MALLOC(stat_coeff,(ncoeff_tot))
    1195          198 :     coeff_values = zero
    1196         5043 :     singular_coeffs = 0
    1197         8779 :     stat_coeff = 0
    1198              :     !Set mpi buffer
    1199              :     !Set the bufsize for mpi allgather
    1200          114 :     ABI_MALLOC(buffsize,(nproc))
    1201           76 :     ABI_MALLOC(buffdisp,(nproc))
    1202           38 :     ABI_MALLOC(buffGF,(5,1))
    1203          114 :     ABI_MALLOC(gf_mpi,(5,nproc))
    1204          132 :     buffsize(:) = 0
    1205           38 :     buffdisp(1) = 0
    1206              : 
    1207          132 :     do ii= 1,nproc
    1208          132 :       buffsize(ii) =  5
    1209              :     end do
    1210           94 :     do ii = 2,nproc
    1211           94 :       buffdisp(ii) = buffdisp(ii-1) + buffsize(ii-1)
    1212              :     end do
    1213           38 :     size_mpi = 5*nproc
    1214              :     !If some coeff are imposed by the input, we need to fill the arrays
    1215              :     !with this coeffs and broadcast to the others CPUs :
    1216           38 :     if(ncoeff_preselected>=1)then
    1217              :       ipre_real=0
    1218          101 :       do ipre=1, ncoeff_preselected
    1219           74 :           list_coeffs_tmp(ipre) = ipre
    1220           74 :           rank_to_send = 0
    1221           74 :           duplicated= 0
    1222        12226 :           do icoeff=1,my_ncoeff
    1223        12226 :             if((my_coeffindexes(icoeff)==list_coeffs(ipre)))then
    1224           42 :               if (is_duplicate_coeff(my_coeffs(icoeff), coeffs_tmp, ncoeff_selected))   duplicated=1
    1225              :             endif
    1226              :           end do
    1227              :           call xmpi_sum(duplicated, comm, ierr)
    1228          175 :           if(duplicated==0) then
    1229              :             ipre_real=ipre_real+1
    1230         3079 :             do icoeff=1,my_ncoeff
    1231         3079 :               if((my_coeffindexes(icoeff)==list_coeffs(ipre)))then
    1232           42 :                 if(need_initialize_data)then
    1233            0 :                   my_icoeff = icoeff
    1234              :                 else
    1235           42 :                   my_icoeff = 1
    1236              :                   !          Need to initialized the data for the fit for this coefficient
    1237              :                   call fit_polynomial_coeff_getFS(my_coeffs,fit_data%training_set%du_delta,&
    1238              :                     &                                          fit_data%training_set%displacement,&
    1239              :                     &                                          energy_coeffs,fcart_coeffs,natom_sc,eff_pot%crystal%natom,&
    1240              :                     &                                          my_ncoeff,ntime,sc_size,fit_data%training_set%strain,&
    1241              :                     &                                          strten_coeffs,fit_data%training_set%ucvol,&
    1242           42 :                     &                                          my_coefflist(icoeff),1)
    1243              :                 end if
    1244          504 :                 energy_coeffs_tmp(ipre,:)    = energy_coeffs(my_icoeff,:)
    1245        74424 :                 fcart_coeffs_tmp(:,:,ipre,:) = fcart_coeffs(:,:,my_icoeff,:)
    1246         3276 :                 strten_coeffs_tmp(:,:,ipre)  = strten_coeffs(:,:,my_icoeff)
    1247              : 
    1248           42 :                 rank_to_send = my_rank
    1249           42 :                 call polynomial_coeff_free(coeffs_tmp(ipre))
    1250              :                 call polynomial_coeff_init(coeff_values(ipre),my_coeffs(icoeff)%nterm,&
    1251              :                   &                                   coeffs_tmp(ipre),my_coeffs(icoeff)%terms,&
    1252              :                   &                                   my_coeffs(icoeff)%name,&
    1253           42 :                   &                                   check=.false.)
    1254           42 :                 exit
    1255              :               end if
    1256              :             end do
    1257              :             !    Boadcast the coefficient
    1258              :             !    Need to send the rank with the chosen coefficient
    1259              :             call xmpi_sum(rank_to_send, comm, ierr)
    1260           74 :             call xmpi_bcast(energy_coeffs_tmp(ipre,:), rank_to_send, comm, ierr)
    1261           74 :             call xmpi_bcast(fcart_coeffs_tmp(:,:,ipre,:) , rank_to_send, comm, ierr)
    1262           74 :             call xmpi_bcast(strten_coeffs_tmp(:,:,ipre), rank_to_send, comm, ierr)
    1263           74 :             call polynomial_coeff_broadcast(coeffs_tmp(ipre), rank_to_send, comm)
    1264              :           end if
    1265              :       end do
    1266              :     end if
    1267              :     !Waiting for all
    1268           38 :     if(nproc > 1)  then
    1269           24 :       if(need_verbose)then
    1270           24 :         write(message, '(a)') ' Initialisation done... waiting for all the CPU'
    1271           24 :         call wrtout(std_out,message,'COLL')
    1272              :       end if
    1273           24 :       call xmpi_barrier(comm)
    1274              :     end if
    1275              : 
    1276              :     !Compute GF, coeff_values,strten_coeffs and fcart_coeffs are set to zero
    1277              :     !it means that only the harmonic part wiil be computed
    1278           38 :     if(fit_weight_T>0.0_dp) then
    1279           15 :         coeff_values = zero
    1280              :         call fit_polynomial_coeff_computeGF(coeff_values,energy_coeffs,fit_data%energy_diff,fcart_coeffs,&
    1281              :           &                                    fit_data%fcart_diff,gf_values(:,1),int((/1/)),natom_sc,&
    1282              :           &                                    0,my_ncoeff,ntime,strten_coeffs,fit_data%strten_diff,&
    1283            3 :           &                                    fit_data%training_set%sqomega, weights=weights)
    1284              : 
    1285              :         !Print the standard deviation before the fit
    1286              :         ! FIXME: on builder ALPS_INTEL_2025_elpa, compile fails.
    1287              :         ! This is probably due to the fact that the format is too long.
    1288              :         ! We should split the write in two writes.
    1289            3 :         write(message,'(4a,ES24.16,2a,ES24.16,2a,ES24.16,2a,ES24.16,a)' ) ch10,&
    1290            3 :           &           ' Weighted Goal function values at the begining of the fit process (eV^2/A^2):',ch10, &
    1291            3 :           &                    '   Energy          : ',&
    1292            3 :           &               gf_values(4,1)*(HaBohr_eVAng)**2,ch10,&
    1293            3 :           &                    '   Forces+Stresses : ',&
    1294            3 :           &               gf_values(1,1)*(HaBohr_eVAng)**2,ch10,&
    1295            3 :           &                    '   Forces          : ',&
    1296            3 :           &               gf_values(2,1)*(HaBohr_eVAng)**2,ch10,&
    1297            3 :           &                    '   Stresses        : ',&
    1298            6 :           &               gf_values(3,1)*(HaBohr_eVAng)**2,ch10
    1299            3 :         if(need_verbose)then
    1300            3 :           call wrtout(ab_out,message,'COLL')
    1301            3 :           call wrtout(std_out,message,'COLL')
    1302              :         end if
    1303              :     end if
    1304              : 
    1305          114 :     ABI_MALLOC(weights1,(ntime))
    1306          595 :     weights1=one
    1307          198 :     coeff_values = zero
    1308              :     call fit_polynomial_coeff_computeGF(coeff_values,energy_coeffs,fit_data%energy_diff,fcart_coeffs,&
    1309              :       &                                    fit_data%fcart_diff,gf_values(:,1),int((/1/)),natom_sc,&
    1310              :       &                                    0,my_ncoeff,ntime,strten_coeffs,fit_data%strten_diff,&
    1311           38 :       &                                    fit_data%training_set%sqomega, weights=weights1)
    1312              : 
    1313              :     !Print the standard deviation before the fit
    1314              :     ! FIXME: on builder ALPS_INTEL_2025_elpa, compile fails.
    1315              :     ! This is probably due to the fact that the format is too long.
    1316              :     ! We should split the write in two writes.
    1317           38 :     write(message,'(4a,ES24.16,2a,ES24.16,2a,ES24.16,2a,ES24.16,a)' ) ch10,&
    1318           38 :       &                    ' Goal function values at the begining of the fit process (eV^2/A^2):',ch10,&
    1319           38 :       &                    '   Energy          : ',&
    1320           38 :       &               gf_values(4,1)*(HaBohr_eVAng)**2,ch10,&
    1321           38 :       &                    '   Forces+Stresses : ',&
    1322           38 :       &               gf_values(1,1)*(HaBohr_eVAng)**2,ch10,&
    1323           38 :       &                    '   Forces          : ',&
    1324           38 :       &               gf_values(2,1)*(HaBohr_eVAng)**2,ch10,&
    1325           38 :       &                    '   Stresses        : ',&
    1326           76 :       &               gf_values(3,1)*(HaBohr_eVAng)**2,ch10
    1327              :     !message = ' Goal function values at the begining of the fit process (eV^2/A^2):'//ch10
    1328              :     !message = trim(message) // '   Energy          : ' // trim(ftoa(gf_values(4,1)*(HaBohr_eVAng)**2))//ch10
    1329              :     !message = trim(message) // '   Forces+Stresses : ' // trim(ftoa(gf_values(1,1)*(HaBohr_eVAng)**2))//ch10
    1330              :     !message = trim(message) // '   Forces          : ' // trim(ftoa(gf_values(2,1)*(HaBohr_eVAng)**2))//ch10
    1331              :     !message = trim(message) // '   Stresses        : ' // trim(ftoa(gf_values(3,1)*(HaBohr_eVAng)**2))//ch10
    1332           38 :     if(need_verbose)then
    1333           38 :       call wrtout(ab_out,message,'COLL')
    1334           38 :       call wrtout(std_out,message,'COLL')
    1335              :     end if
    1336           38 :     ABI_FREE(weights1)
    1337              : 
    1338              : 
    1339          114 :     ABI_MALLOC(gf_values_iter,(4,ncoeff_to_select+1))
    1340          658 :     gf_values_iter(:,:) = zero
    1341              :     !Store initial gf_values as first value in gf_values_iter
    1342          190 :     gf_values_iter(:,1) = gf_values(:,1)
    1343           38 :   end subroutine initialize_gf
    1344              : 
    1345              :   !> Selects coefficients one by one based on goal function improvement
    1346              :   !>
    1347              :   !> This routine:
    1348              :   !> - Iteratively selects coefficients that minimize the goal function
    1349              :   !> - Handles coefficient selection in cycles with ncoeff_per_cycle terms per cycle
    1350              :   !> - Performs coefficient fitting and evaluation for each candidate
    1351              :   !> - Tracks selected coefficients and updates goal function values
    1352              :   !> - Applies convergence criteria based on goal function improvement
    1353              :   !> - Handles MPI parallelization for distributed coefficient selection
    1354              :   !> - Outputs progress information in verbose mode
    1355              :   !> - Maintains CSV log of goal function values if requested
    1356              : 
    1357           38 :   subroutine select_one_by_one()
    1358              :     integer :: ncycle_select ! number of cycles for the selection
    1359              :     integer :: ncoeff_this_cycle
    1360              :     integer :: ncoeff_selected
    1361              :     integer :: ic
    1362              : 
    1363           38 :     ncycle_select=ceiling(real(ncoeff_to_select)/real(ncoeff_per_cycle))
    1364           38 :     ncoeff_selected = ncoeff_preselected
    1365              :    !Option 1, we select the coefficients one by one
    1366           38 :    if(need_verbose.and.ncoeff_to_select > 0)then
    1367           38 :      write(message,'(a,3x,a,10x,a,14x,a,14x,a,14x,a)') " N","Selecting","MSDE","MSDFS","MSDF","MSDS"
    1368              :      !message = " N Selecting            MSDE         MSDFS        MSDF         MSDS"
    1369           38 :      call wrtout(ab_out,message,'COLL')
    1370           38 :      write(message,'(4x,a,6x,a,8x,a,8x,a,8x,a)') "Coefficient","(eV^2/A^2)","(eV^2/A^2)","(eV^2/A^2)",&
    1371           76 :       &                                       "(eV^2/A^2)"
    1372              :      !message = "   Coefficient      (eV^2/A^2)   (eV^2/A^2)   (eV^2/A^2)   (eV^2/A^2)"
    1373           38 :      call wrtout(ab_out,message,'COLL')
    1374              :    end if
    1375              : 
    1376              : !  Start fit process
    1377          124 :    do icycle_tmp = 1,ncycle_select
    1378           86 :      ncoeff_this_cycle= min(ncoeff_per_cycle, ncoeff_to_select+ncoeff_preselected-ncoeff_selected)
    1379           86 :      icycle=ncoeff_selected+1
    1380           86 :      list_coeffs_tmp(icycle)= icycle
    1381           86 :      if(need_verbose)then
    1382           86 :        write(message, '(4a,I0,a)')ch10,'--',ch10,' Try to find the best model with ',&
    1383          172 :        &                          ncoeff_selected+ncoeff_this_cycle,' coefficient'
    1384              :        !message = '--' // ch10 // ' Try to find the best model with '
    1385              :        !message = message // trim(itoa(ncoeff_selected+ncoeff_this_cycle)) // ' coefficient'
    1386              : 
    1387           86 :        if(ncoeff_selected+ncoeff_this_cycle> 1)  message =  trim(message)// 's'
    1388              :        !write(message, '(2a)') trim(message),'s'
    1389           86 :        if(nproc > 1)  then
    1390           48 :          if(my_ncoeff>=1) then
    1391           48 :            write(message, '(2a,I0,a)')trim(message), ' (only the ',my_ncoeff,&
    1392           96 :            &                                     ' first are printed for this CPU)'
    1393              :            ! message = trim(message) // ' (only the ' // trim(itoa(my_ncoeff))
    1394              :            ! message = trim(message) // ' first are printed for this CPU)'
    1395              : 
    1396              :          else
    1397            0 :            write(message, '(2a)')trim(message), ' (no coefficient treated by this CPU)'
    1398              :            !message = trim(message) // ' (no coefficient treated by this CPU)'
    1399              :          end if
    1400              :        end if
    1401           86 :        call wrtout(std_out,message,'COLL')
    1402          118 :        if(ncoeff_selected>0 .or. any(list_coeffs(:) > zero))then
    1403              :          !write(message, '(3a)') ' The coefficient numbers from the previous cycle are:',ch10,' ['
    1404           75 :          message = ' The coefficient numbers from the previous cycle are:' // ch10 // ' ['
    1405          326 :          do ii=1,ncoeff_selected
    1406          326 :            if(ii<ncoeff_selected)then
    1407          176 :              write(message, '(a,I0,a)') trim(message),list_coeffs(ii),','
    1408              :              !message = trim(message) // trim(itoa(list_coeffs(ii))) // ','
    1409              :            else
    1410           75 :              write(message, '(a,I0)') trim(message),list_coeffs(ii)
    1411              :              !message = trim(message) // trim(itoa(list_coeffs(ii)))
    1412              :            end if
    1413              :          end do
    1414              :          !write(message, '(3a)') trim(message),']',ch10
    1415           75 :          message = trim(message) // ']' // ch10
    1416           75 :          call wrtout(std_out,message,'COLL')
    1417              :        end if
    1418              : 
    1419           86 :        write(message,'(2x,a,12x,a,14x,a,13x,a,14x,a)') " Testing","MSDE","MSDFS","MSDF","MSDS"
    1420              :        !message = ' Testing            MSDE         MSDFS        MSDF         MSDS'
    1421           86 :        call wrtout(std_out,message,'COLL')
    1422           86 :        write(message,'(a,7x,a,8x,a,8x,a,8x,a)') " Coefficient","(eV^2/A^2)","(eV^2/A^2)","(eV^2/A^2)",&
    1423          172 :        &                                      "(eV^2/A^2)"
    1424              :        ! message = ' Coefficient (eV^2/A^2) (eV^2/A^2) (eV^2/A^2) (eV^2/A^2)'
    1425           86 :        call wrtout(std_out,message,'COLL')
    1426              :      end if!End if verbose
    1427              : 
    1428              :      !Print all GF VALUES in CSV if wanted
    1429              :      !Open *csv file for storing GF values of all cores for this iteration
    1430              :      !TODO:  Should move inside the loop over all selected?
    1431           86 :      if(need_prt_GF_csv)then
    1432            6 :         write(filename,'(a,I1,a,I3.3,a,I3.3,a)') "GF_values_iatom",fit_iatom_in,"_proc",my_rank,"_iter",icycle,".csv"
    1433              :         !filename = "GF_values_iatom" // trim(itoa(fit_iatom_in)) // "_proc"
    1434              :         !filename = trim(filename) // trim(itoa(my_rank)) // "_iter" // trim(itoa(icycle)) // ".csv"
    1435              : 
    1436            6 :         unit_GF_val = get_unit()
    1437            6 :         if (open_file(filename,message,unit=unit_GF_val,form="formatted",&
    1438              : &          status="unknown",action="write") /= 0) then
    1439            0 :            ABI_ERROR(message)
    1440              :         end if
    1441              :      end if
    1442              : !    Reset gf_values
    1443        63086 :      gf_values(:,:) = huge(0.0_dp)/5.0_dp
    1444              : 
    1445        12686 :      do icoeff=1,my_ncoeff
    1446        12600 :        if(isbanned(my_coeffindexes(icoeff)) .or. &
    1447              :          & isselected(my_coeffindexes(icoeff))  )then
    1448         4495 :          gf_values(:,icoeff) = huge(0.0_dp)/5.0_dp
    1449              :          cycle
    1450              :        endif
    1451        87395 :        if(any(list_coeffs==my_coeffindexes(icoeff)) .or. singular_coeffs(icoeff) == 1)then
    1452            0 :           gf_values(:,icoeff) = huge(0.0_dp)/5.0_dp
    1453              :           cycle
    1454              :        endif
    1455              :        !if(nbancoeff >= 1)then
    1456              :        !end if
    1457              :        !list_coeffs(icycle) = my_coeffindexes(icoeff)
    1458              :        !my_coeffindexes(my_coeffindexes(icoeff)) = .True.
    1459              : 
    1460        11701 :        if(need_initialize_data)then
    1461            0 :          my_icoeff = icoeff
    1462              :        else
    1463              : !        Need to initialized the data for the fit for this coefficient
    1464        11701 :          my_icoeff = 1
    1465              :          call fit_polynomial_coeff_getFS(my_coeffs,fit_data%training_set%du_delta,&
    1466              : &                                        fit_data%training_set%displacement,&
    1467              : &                                        energy_coeffs,fcart_coeffs,natom_sc,eff_pot%crystal%natom,&
    1468              : &                                        my_ncoeff,ntime,sc_size,fit_data%training_set%strain,&
    1469              : &                                        strten_coeffs,fit_data%training_set%ucvol,&
    1470        11701 :                                         my_coefflist(icoeff),1)
    1471              :        end if
    1472              : 
    1473              : !      Fill the temporary arrays
    1474       558385 :        energy_coeffs_tmp(icycle,:)    = energy_coeffs(my_icoeff,:)
    1475     88027825 :        fcart_coeffs_tmp(:,:,icycle,:) = fcart_coeffs(:,:,my_icoeff,:)
    1476      3838489 :        strten_coeffs_tmp(:,:,icycle)  = strten_coeffs(:,:,my_icoeff)
    1477              : 
    1478              : 
    1479              : !      call the fit process routine
    1480              : !      This routine solves the linear system proposed
    1481              : !      by C.Escorihuela-Sayalero see PRB95,094115(2017) [[cite:Escorihuela-Sayalero2017]]
    1482        65983 :          do ic =1, icycle
    1483        65983 :            list_coeffs_tmp(ic) =ic
    1484              :          end do
    1485              :        call fit_polynomial_coeff_solve(coeff_values(1:icycle),fcart_coeffs_tmp,fit_data%fcart_diff,&
    1486              :          &                                      energy_coeffs_tmp,fit_data%energy_diff,info,&
    1487              :          &                                      list_coeffs_tmp(1:icycle),natom_sc,icycle,ncoeff_to_fit,ntime,&
    1488              :          &                                      strten_coeffs_tmp,fit_data%strten_diff,&
    1489              :          &                                      fit_data%training_set%sqomega,fit_on,int_fit_factors, &
    1490        11701 :          &                                      weights=weights)
    1491              : 
    1492        11701 :        if(info==0)then
    1493        17911 :          if (need_positive.and.any(coeff_values(ncoeff_fix+1:icycle) < zero)) then
    1494              :            !write(message, '(a)') ' Negative value detected...'
    1495            0 :            message = 'Negative value detected...'
    1496            0 :            gf_values(:,icoeff) = zero
    1497            0 :            coeff_values = zero
    1498              :          else
    1499              :            call fit_polynomial_coeff_computeGF(coeff_values(1:icycle),energy_coeffs_tmp,&
    1500              : &                                            fit_data%energy_diff,fcart_coeffs_tmp,fit_data%fcart_diff,&
    1501              : &                                            gf_values(:,icoeff),list_coeffs_tmp(1:icycle),natom_sc,&
    1502              : &                                            icycle,ncoeff_to_fit,ntime,strten_coeffs_tmp,&
    1503        11632 : &                                            fit_data%strten_diff,fit_data%training_set%sqomega, weights=weights)
    1504        11632 :            write(j_char, '(i7)') my_coeffindexes(icoeff)
    1505              :            !j_char = itoa(my_coeffindexes(icoeff))
    1506              : 
    1507        11632 :            write(message, '(4x,a,3x,4ES18.10)') adjustl(j_char), &
    1508              : !&                                   gf_values(4,icoeff)*factor*(1000*Ha_ev)**2 ,&
    1509        11632 :            &   gf_values(4,icoeff)*HaBohr_eVAng**2, &
    1510        11632 :            &   gf_values(1,icoeff)*HaBohr_eVAng**2, &
    1511        11632 :            &   gf_values(2,icoeff)*HaBohr_eVAng**2, &
    1512        23264 :            &   gf_values(3,icoeff)*HaBohr_eVAng**2
    1513              :            !message = trim(adjustl(j_char)) // " " // &
    1514              :            !  ftoa(gf_values(4,icoeff)*HaBohr_eVAng**2) // " " // &
    1515              :            !  ftoa(gf_values(1,icoeff)*HaBohr_eVAng**2) // " " // &
    1516              :            !  ftoa(gf_values(2,icoeff)*HaBohr_eVAng**2) // " " // &
    1517              :            !  ftoa(gf_values(3,icoeff)*HaBohr_eVAng**2)
    1518              : 
    1519              : 
    1520        11632 :            if(need_prt_GF_csv)then
    1521         1635 :              write(message2, '(I7.7,3a,ES18.10,a,ES18.10,a,ES18.10,a,ES18.10)') my_coeffindexes(icoeff),",",&
    1522         1635 :              & trim(my_coeffs(icoeff)%name),",", &
    1523         1635 :              & gf_values(4,icoeff)*HaBohr_eVAng**2,",", &
    1524         1635 :              & gf_values(1,icoeff)*HaBohr_eVAng**2,",", &
    1525         1635 :              & gf_values(2,icoeff)*HaBohr_eVAng**2,",", &
    1526         3270 :              & gf_values(3,icoeff)*HaBohr_eVAng**2
    1527              :              !message2 = itoa(my_coeffindexes(icoeff)) // "," // &
    1528              :              !  trim(my_coeffs(icoeff)%name) // "," // &
    1529              :              !  ftoa(gf_values(4,icoeff)*HaBohr_eVAng**2) // "," // &
    1530              :              !  ftoa(gf_values(1,icoeff)*HaBohr_eVAng**2) // "," // &
    1531              :              !  ftoa(gf_values(2,icoeff)*HaBohr_eVAng**2) // "," // &
    1532              :              !  ftoa(gf_values(3,icoeff)*HaBohr_eVAng**2)
    1533              :              end if
    1534              :          end if
    1535              :        else!In this case the matrix is singular.
    1536          345 :          gf_values(:,icoeff) = huge(0.0_dp)/5.0_dp
    1537           69 :          isbanned(my_coeffindexes(icoeff))=.True.
    1538           69 :          singular_coeffs(icoeff) = 1
    1539              :          !write(message, '(a)') ' The matrix is singular...'
    1540           69 :          message = 'The matrix is singular...'
    1541           69 :          if(need_prt_GF_csv)then
    1542           30 :            write(message2, '(I7.7,10a)') my_coeffindexes(icoeff),",", &
    1543           30 : &                                   trim(my_coeffs(icoeff)%name),",",&
    1544           30 : &                                  "None",",",&
    1545           30 :              & "None",",",&
    1546           30 :              & "None",",",&
    1547           60 :              & "None"
    1548              :            !message2 = itoa(my_coeffindexes(icoeff)) // "," // &
    1549              :            !    trim(my_coeffs(icoeff)%name) // "," // &
    1550              :            !    "None,None,None,None"
    1551              :          endif
    1552              :        end if
    1553        11787 :        if(need_verbose)then
    1554        11701 :            call wrtout(std_out,message,'COLL')
    1555        11701 :            if(need_prt_GF_csv)then
    1556         1665 :              call wrtout(unit_GF_val,message2,'PERS',do_flush=.TRUE.)
    1557              :            end if
    1558              :        endif
    1559              :      end do !icoeff=1,my_ncoeff
    1560           86 :      call xmpi_lor(isbanned, comm)
    1561              : 
    1562              :      !Close *csv file for GF values of this iteration
    1563           86 :      if(need_prt_GF_csv)close(unit_GF_val)
    1564              : 
    1565              : !    find the best coeff on each CPU
    1566          430 :      mingf(:)  = huge(0.0_dp)/5.0_dp
    1567           86 :      index_min = 0
    1568        12686 :      do icoeff=1,my_ncoeff
    1569              :        !if(gf_values(1,icoeff) > huge(0.0_dp)/5-1.0) cycle
    1570              :        !if(abs(gf_values(1,icoeff)) <tol16) cycle
    1571        12600 :        if(isbanned(my_coeffindexes(icoeff)) .or. isselected(my_coeffindexes(icoeff)) ) cycle
    1572        81510 :        if(sum(gf_values(2:4,icoeff),MASK=sel_on) < sum(mingf(2:4),MASK=sel_on))then
    1573         1670 :          mingf(:) = gf_values(:,icoeff)
    1574          334 :          index_min = my_coeffindexes(icoeff)
    1575              :        end if
    1576              :      end do
    1577              : 
    1578              : 
    1579              : !    MPI GATHER THE BEST COEFF ON EACH CPU
    1580           86 :      if(nproc > 1)then
    1581           48 :        buffGF(1,1) = index_min
    1582          240 :        buffGF(2:5,1) =  mingf(:)
    1583           48 :        call xmpi_barrier(comm)
    1584           48 :        call xmpi_allgatherv(buffGF,5,gf_mpi,buffsize,buffdisp, comm, ierr)
    1585          240 :        mingf(:)    = huge(0.0_dp)/5.0_dp
    1586           48 :        index_min= 0
    1587          208 :        do icoeff=1,nproc
    1588          160 :          if(gf_mpi(2,icoeff) > huge(0.0_dp)/5-1) cycle
    1589              :          !if(abs(gf_mpi(2,icoeff)) < tol16) cycle
    1590         1168 :          if(sum(gf_mpi(3:5,icoeff),MASK=sel_on) < sum(mingf(2:4),MASK=sel_on))then
    1591          310 :            mingf(:) = gf_mpi(2:5,icoeff)
    1592           62 :            index_min = int(gf_mpi(1,icoeff))
    1593              :          end if
    1594              :        end do
    1595              :      end if
    1596              : 
    1597          124 :      BLOCK  ! sort the coeff on each CPU
    1598          172 :        real(dp) :: mygf(my_ncoeff)
    1599          172 :        integer :: myorder(my_ncoeff), ntot
    1600           86 :        real(dp), allocatable :: allgf(:)
    1601           86 :        integer, allocatable :: allorder(:)
    1602        12686 :        do icoeff=1,my_ncoeff
    1603        12600 :          if(gf_values(1,icoeff) < zero) then
    1604            0 :            mygf(icoeff)=huge(0.0_dp)/5.0_dp
    1605        12600 :          else if(abs(gf_values(1,icoeff)) <tol16) then
    1606            0 :            mygf(icoeff)=huge(0.0_dp)/5.0_dp
    1607              :          else
    1608        50400 :            mygf(icoeff) = sum(gf_values(2:4,icoeff),MASK=sel_on)
    1609              :          end if
    1610        12686 :          myorder(icoeff) = my_coeffindexes(icoeff)
    1611              :        end do
    1612           86 :        call mpigatherv(mygf,myorder, my_ncoeff, allgf, allorder, ntot, comm, nproc)
    1613              :        BLOCK
    1614          172 :          real(dp) :: allgf_copy(size(allgf))
    1615          172 :          real(dp):: work((ntot+1)/2)
    1616          172 :          integer:: worder((ntot+1)/2)
    1617              :          integer :: i
    1618           86 :          logical :: ideg(ntot)
    1619        20158 :          ideg=.False.
    1620              : 
    1621        20158 :          allgf_copy(:)=allgf(:)
    1622           86 :          call MergeSort(allgf_copy, work, allorder, worder)
    1623        20072 :          do i=2, ntot
    1624        20072 :            if(abs(allgf(allorder(i))-allgf(allorder(i-1)))< 1e-16) then
    1625         2592 :               ideg(allorder(i))=.True.
    1626         2592 :               isbanned(allorder(i))=.True.
    1627              :            end if
    1628              :          end do
    1629        20072 :          do i=2, ntot
    1630        20072 :            if(ideg(allorder(i))) then
    1631              :               !print *, "new:", allgf(allorder(i-1)), allgf(allorder(i))
    1632         2592 :               allgf(allorder(i))=9D99
    1633              :            endif
    1634              :          end do
    1635           86 :          call MergeSort(allgf, work, allorder, worder)
    1636              : 
    1637           86 :          n_remaining = max(ceiling(n_remaining * remaining_rate), min(ncoeff_to_select*40, ncoeff_tot) )
    1638           86 :          do i=n_remaining+1, ncoeff_tot
    1639           86 :            isbanned(allorder(i))=.True.
    1640              :          end do
    1641              : 
    1642              : 
    1643              :        end BLOCK
    1644              : 
    1645              :        BLOCK ! add selected terms
    1646              : 
    1647              :          integer :: i
    1648              :          integer :: ind_select
    1649              :          integer :: nselected_this_cycle
    1650           86 :          nselected_this_cycle=0
    1651           86 :          i=0
    1652          258 :          do while(nselected_this_cycle<ncoeff_this_cycle)
    1653           86 :            i=i+1
    1654              :            !do while( isbanned(allorder(i))  .or. isselected(allorder(i)))
    1655              :            !  i=i+1
    1656              :            !enddo
    1657           86 :            index_min = allorder(i)
    1658              :            !    Check if there is still coefficient
    1659              :            !if(i>size(allorder))then
    1660              :            !  exit
    1661              :            !end if
    1662              : 
    1663           86 :            if(index_min==0) then
    1664              :              exit
    1665              :            ! TODO : check if this is necessary
    1666              :            !else if(is_duplicate_coeff(index_min)) then
    1667              :            !  cycle
    1668           86 :            else if ( isbanned(allorder(i))  .or. isselected(allorder(i))) then
    1669              :              cycle
    1670              :            else
    1671           86 :             ind_select=ncoeff_selected+1
    1672           86 :             list_coeffs(ind_select) = index_min
    1673           86 :             isselected(index_min)=.True.
    1674           86 :             nselected_this_cycle=nselected_this_cycle+1
    1675              :            end if
    1676              :            !    Check if this coeff is treat by this cpu and fill the
    1677              :            !    temporary array before broadcast
    1678           86 :            rank_to_send = 0
    1679         6094 :            do icoeff=1,my_ncoeff
    1680         6094 :              if((my_coeffindexes(icoeff)==list_coeffs(ind_select)))then
    1681           54 :                if(need_initialize_data)then
    1682            0 :                  my_icoeff = icoeff
    1683              :                else
    1684              :                  !          Need to initialized the data for the fit for this coefficient
    1685           54 :                  my_icoeff = 1
    1686              :                  call fit_polynomial_coeff_getFS(my_coeffs,fit_data%training_set%du_delta,&
    1687              :                    &                                          fit_data%training_set%displacement,&
    1688              :                    &                                          energy_coeffs,fcart_coeffs,natom_sc,eff_pot%crystal%natom,&
    1689              :                    &                                          my_ncoeff,ntime,sc_size,fit_data%training_set%strain,&
    1690              :                    &                                          strten_coeffs,fit_data%training_set%ucvol,&
    1691           54 :                    &                                          my_coefflist(icoeff),1)
    1692              :                end if
    1693              : 
    1694         2316 :                energy_coeffs_tmp(ind_select,:)    = energy_coeffs(my_icoeff,:)
    1695       364236 :                fcart_coeffs_tmp(:,:,ind_select,:) = fcart_coeffs(:,:,my_icoeff,:)
    1696        15888 :                strten_coeffs_tmp(:,:,ind_select)  = strten_coeffs(:,:,my_icoeff)
    1697              : 
    1698           54 :                call polynomial_coeff_free(coeffs_tmp(ind_select))
    1699              : 
    1700              : 
    1701              :                call polynomial_coeff_init(coeff_values(ind_select),my_coeffs(icoeff)%nterm,&
    1702              :                  &                                   coeffs_tmp(ind_select),my_coeffs(icoeff)%terms,&
    1703              :                  &                                   my_coeffs(icoeff)%name,&
    1704           54 :                  &                                   check=.false.)
    1705           54 :                rank_to_send = my_rank
    1706           54 :                exit
    1707              :              end if
    1708              :            end do
    1709              :            !    Need to send the rank with the chosen coefficient
    1710              :            call xmpi_sum(rank_to_send, comm, ierr)
    1711              :            !    Boadcast the coefficient
    1712           86 :            call xmpi_bcast(energy_coeffs_tmp(ind_select,:), rank_to_send, comm, ierr)
    1713           86 :            call xmpi_bcast(fcart_coeffs_tmp(:,:,ind_select,:) , rank_to_send, comm, ierr)
    1714           86 :            call xmpi_bcast(strten_coeffs_tmp(:,:,ind_select), rank_to_send, comm, ierr)
    1715           86 :            call polynomial_coeff_broadcast(coeffs_tmp(ind_select), rank_to_send, comm)
    1716           86 :            if(need_verbose) then
    1717           86 :              write(message, '(a,I0,2a)' )' Selecting the coefficient number ',list_coeffs(ind_select),&
    1718          172 :                &                                   ' ===> ',trim(coeffs_tmp(ind_select)%name)
    1719           86 :              call wrtout(std_out,message,'COLL')
    1720              : 
    1721           86 :              write (i_char, '(i3)') ind_select
    1722           86 :              write (j_char, '(i7)') list_coeffs(ind_select)
    1723           86 :              write(message, '(a,a,3x,a,3x,4ES18.10)') " ",adjustl(i_char),adjustl(j_char),&
    1724              :                !&                                    mingf(4)* factor * (Ha_eV *1000)**2,&
    1725           86 :                &                                    mingf(4)*HaBohr_eVAng**2,&
    1726           86 :                &                                    mingf(1)*HaBohr_eVAng**2,&
    1727           86 :                &                                    mingf(2)*HaBohr_eVAng**2,&
    1728          172 :                &                                    mingf(3)*HaBohr_eVAng**2
    1729           86 :              call wrtout(ab_out,message,'COLL')
    1730              :            end if
    1731          430 :            gf_values_iter(:,icycle_tmp+1) = mingf(:)
    1732              :            !Store GF Values of this iteration
    1733              :            !    Check the stopping criterion
    1734           86 :            converge = .false.
    1735           86 :            if(tolGF > zero)then
    1736              :              check_value =  (sum(gf_values_iter(2:4,icycle_tmp+1),MASK=sel_on) - &
    1737              :                &             sum(gf_values_iter(2:4,icycle_tmp),MASK=sel_on)) &
    1738              :                &            /(sum(gf_values_iter(2:4,icycle_tmp+1),MASK=sel_on) &
    1739            0 :                &            - sum(gf_values_iter(2:4,1),MASK=sel_on))
    1740            0 :              if(check_value < tolGF)then
    1741            0 :                write(message,'(2a,ES18.10,a,ES18.10,a)') ch10," Fit process complete =>",&
    1742            0 :                  &                                                check_value ," < ",tolGF,&
    1743            0 :                  &                                              ' Goal Function is converged'
    1744            0 :                converge = .true.
    1745              :              end if
    1746              :            endif
    1747           86 :            if(tolMSDE  > zero)then
    1748            0 :              if(abs(tolMSDE) > abs(mingf(4)* (Ha_eV *1000)**2 *factor))then
    1749            0 :                write(message,'(2a,ES18.10,a,ES18.10,a)') ch10," Fit process complete =>",&
    1750            0 :                  &                                                mingf(4)* (Ha_eV *1000)**2 * factor ," < ",tolMSDE,&
    1751            0 :                  &                                              ' for MSDE'
    1752            0 :                converge = .true.
    1753              :              end if
    1754              :            end if
    1755           86 :            if(tolMSDF  > zero) then
    1756            0 :              if(abs(tolMSDF) > abs(mingf(2)*HaBohr_eVAng**2))then
    1757            0 :                write(message,'(2a,ES18.10,a,ES18.10,a)') ch10," Fit process complete =>",&
    1758            0 :                  &                                                  mingf(2)*HaBohr_eVAng**2 ," < ",tolMSDF,&
    1759            0 :                  &                                              ' for MSDF'
    1760            0 :                converge = .true.
    1761              :              end if
    1762              :            end if
    1763           86 :            if(tolMSDS  > zero) then
    1764            0 :              if(abs(tolMSDS) > abs(mingf(3)*HaBohr_eVAng**2))then
    1765            0 :                write(message,'(2a,ES18.10,a,ES18.10,a)') ch10," Fit process complete =>",&
    1766            0 :                  &                                                  mingf(3)*HaBohr_eVAng**2 ," < ",tolMSDS,&
    1767            0 :                  &                                              ' for MSDS'
    1768            0 :                converge = .true.
    1769              :              end if
    1770              :            end if
    1771           86 :            if(tolMSDFS > zero)then
    1772            0 :              if(abs(tolMSDFS) > abs(mingf(1)*HaBohr_eVAng**2))then
    1773            0 :                write(message,'(2a,ES18.10,a,ES18.10,a)') ch10," Fit process complete =>",&
    1774            0 :                  &                                                  mingf(1)*HaBohr_eVAng**2 ," < ",tolMSDFS,&
    1775            0 :                  &                                              ' for MSDFS'
    1776            0 :                converge = .true.
    1777              :              end if
    1778              :            end if
    1779           86 :            if(converge)then
    1780            0 :              call wrtout(ab_out,message,'COLL')
    1781            0 :              call wrtout(std_out,message,'COLL')
    1782            0 :              exit
    1783              :            else
    1784           86 :              if(any((/abs(tolMSDE),abs(tolMSDF),abs(tolMSDS),abs(tolMSDFS)/) > tol20) .and.&
    1785              :                &         icycle_tmp == ncoeff_to_select)then
    1786            0 :                write(message,'(2a,I0,a)') ch10," WARNING: ",ncoeff_to_select,&
    1787            0 :                  &                                   " cycles was not enougth to converge the fit process"
    1788            0 :                call wrtout(ab_out,message,'COLL')
    1789            0 :                call wrtout(std_out,message,'COLL')
    1790              :              end if
    1791              :            end if
    1792           86 :            ncoeff_selected = ncoeff_selected + 1
    1793              :            !list_coeffs_tmp(ncoeff_selected) = ncoeff_selected
    1794              :          end do
    1795              :        end BLOCK
    1796           86 :        ABI_FREE(allgf)
    1797           86 :        ABI_FREE(allorder)
    1798              :      end BLOCK
    1799              :    end do !icycle_tmp=1,ncoeff_to_select
    1800           38 :   end subroutine select_one_by_one
    1801              : 
    1802              : 
    1803              :   !> Selects coefficients using Monte Carlo sampling approach
    1804              :   !>
    1805              :   !> This routine:
    1806              :   !> - Performs Monte Carlo sampling over coefficient combinations
    1807              :   !> - Runs for a fixed number of sweeps (default 10000)
    1808              :   !> - Randomly selects coefficients and evaluates goal function
    1809              :   !> - Keeps track of best coefficient combination found
    1810              :   !> - Handles MPI parallelization for distributed sampling
    1811              :   !> - Updates goal function values and coefficient statistics
    1812              :   !> - Transfers final model from best performing CPU
    1813              :   !> - Outputs progress and final results in verbose mode
    1814              :   !> - Optional validation of coefficient selection
    1815            0 :   subroutine select_with_monte_carlo()
    1816              :     !  Monte Carlo selection
    1817            0 :     nsweep = 10000
    1818              :     !  If no coefficient imposed in the inputs we reset the goal function
    1819            0 :     if (ncoeff_preselected == 0) then
    1820            0 :       gf_values(:,:) = zero
    1821            0 :       mingf(:) = 9D99
    1822              :     else
    1823            0 :       mingf = gf_values(:,1)
    1824              :     end if
    1825            0 :     call cpu_time(time)
    1826            0 :     call ZBQLINI(int(time*1000000/(my_rank+1)))
    1827            0 :     if(need_verbose)then
    1828            0 :       write(message,'(a,I0,a)') " Start Monte Carlo simulations on ", nproc," CPU"
    1829            0 :       if(nproc>1) write(message,'(2a)') trim(message)," (only print result of the master)"
    1830            0 :       call wrtout(std_out,message,'COLL')
    1831            0 :       call wrtout(ab_out,message,'COLL')
    1832            0 :       write(message,'(a,2x,a,9x,a,14x,a,13x,a,14x,a)') ch10," Iteration ","MSDE","MSDFS","MSDF","MSdS"
    1833            0 :       call wrtout(std_out,message,'COLL')
    1834            0 :       write(message,'(a,5x,a,8x,a,8x,a,8x,a)') "              ","(eV^2/A^2)","(eV^2/A^2)","(eV^2/A^2)",&
    1835            0 :         &                                            "(eV^2/A^2)"
    1836            0 :       call wrtout(std_out,message,'COLL')
    1837              : 
    1838              :     end if
    1839              : 
    1840            0 :     do ii = 1,1!nyccle
    1841            0 :       do isweep =1,nsweep
    1842            0 :         write (j_char, '(i7)') isweep
    1843              :         !TEST_AM
    1844            0 :         icycle_tmp = int(ZBQLU01(zero)*(ncoeff_to_select+1-1))+1
    1845            0 :         icycle_tmp = ncoeff_to_select
    1846            0 :         do icycle=1,icycle_tmp
    1847            0 :           icoeff = int(ZBQLU01(zero)*(my_ncoeff))+1
    1848              :           !         icycle = int(ZBQLU01(zero)*(ncoeff_to_select))+1
    1849            0 :           list_coeffs_tmp2(icycle) = icoeff
    1850            0 :           list_coeffs_tmp(icycle)= icycle
    1851              :           !        Fill the temporary arrays
    1852            0 :           energy_coeffs_tmp(icycle,:)    = energy_coeffs(icoeff,:)
    1853            0 :           fcart_coeffs_tmp(:,:,icycle,:) = fcart_coeffs(:,:,icoeff,:)
    1854            0 :           strten_coeffs_tmp(:,:,icycle)  = strten_coeffs(:,:,icoeff)
    1855              :         end do
    1856              :         !TEST_AM
    1857              : 
    1858              :         !      call the fit process routine
    1859              :         !      This routine solves the linear system proposed by
    1860              :         !      C.Escorihuela-Sayalero see PRB95,094115(2017)
    1861              :         !      [[cite:Escorihuela-Sayalero2017]]
    1862              :         call fit_polynomial_coeff_solve(coeff_values(1:icycle_tmp)&
    1863              :           &,fcart_coeffs_tmp,fit_data%fcart_diff, energy_coeffs_tmp,fit_data&
    1864              :           &%energy_diff,info, list_coeffs_tmp(1:icycle_tmp),natom_sc,icycle_tmp&
    1865              :           &,ncoeff_to_fit, ntime,strten_coeffs_tmp,fit_data%strten_diff, fit_data&
    1866            0 :           &%training_set%sqomega,fit_on,int_fit_factors,  weights=weights )
    1867            0 :         if(info==0)then
    1868              :           call fit_polynomial_coeff_computeGF(coeff_values(1:icycle_tmp),energy_coeffs_tmp,&
    1869              :             &                                            fit_data%energy_diff,fcart_coeffs_tmp,fit_data%fcart_diff,&
    1870              :             &                                            gf_values(:,1),list_coeffs_tmp(1:icycle_tmp),natom_sc,&
    1871              :             &                                            icycle_tmp,ncoeff_to_fit,ntime,strten_coeffs_tmp,&
    1872            0 :             &                                            fit_data%strten_diff,fit_data%training_set%sqomega, weights=weights)
    1873              : 
    1874              :         else!In this case the matrix is singular
    1875            0 :           gf_values(:,icoeff) = zero
    1876            0 :           singular_coeffs(icoeff) = 1
    1877              :         end if
    1878              : 
    1879            0 :         if(gf_values(1,1) > zero.and.abs(gf_values(1,1))>tol16.and.&
    1880            0 :           &         gf_values(1,1) < mingf(1) ) then
    1881            0 :           mingf = gf_values(:,1)
    1882            0 :           list_coeffs(1:icycle_tmp) = list_coeffs_tmp2(1:icycle_tmp)
    1883            0 :           ncoeff_preselected = icycle_tmp
    1884              : 
    1885            0 :           write(message, '(4x,a,3x,4ES18.10)') adjustl(j_char),&
    1886            0 :             &                                   gf_values(4,1)* (1000*Ha_ev)**2 *factor,&
    1887            0 :             &                                   gf_values(1,1)*HaBohr_eVAng**2,&
    1888            0 :             &                                   gf_values(2,1)*HaBohr_eVAng**2,&
    1889            0 :             &                                   gf_values(3,1)*HaBohr_eVAng**2
    1890            0 :           if(need_verbose) call wrtout(std_out,message,'COLL')
    1891              :         else
    1892            0 :           list_coeffs_tmp2(1:icycle_tmp) = list_coeffs(1:icycle_tmp)
    1893              :         end if
    1894              :       end do
    1895              : 
    1896            0 :       if(nproc > 1) then
    1897              :         !TEST_AM
    1898            0 :         do iproc=1,ncoeff_preselected
    1899            0 :           stat_coeff(list_coeffs(iproc)) =  stat_coeff(list_coeffs(iproc)) + 1
    1900              :         end do
    1901              :         !TEST_AM
    1902              : 
    1903              :         !    Find the best model on all the CPUs
    1904            0 :         buffGF(1,1) = zero
    1905            0 :         buffGF(2:5,1) =  mingf(:)
    1906            0 :         call xmpi_allgatherv(buffGF,5,gf_mpi,buffsize,buffdisp, comm, ierr)
    1907              :         !      find the best coeff
    1908            0 :         mingf(:) = huge(0.0_dp)/5.0_dp
    1909            0 :         index_min= 0
    1910            0 :         do iproc=1,nproc
    1911            0 :           if(gf_mpi(2,iproc) < zero) cycle
    1912            0 :           if(abs(gf_mpi(2,iproc)) <tol16) cycle
    1913            0 :           if(gf_mpi(2,iproc) < mingf(1) ) then
    1914            0 :             mingf(:) = gf_mpi(2:5,iproc)
    1915            0 :             index_min = int(gf_mpi(1,iproc))
    1916            0 :             rank_to_send = iproc-1
    1917              :           end if
    1918              :         end do
    1919            0 :         write(message, '(2a,I0)') ch10,' Best model found on the CPU: ', rank_to_send
    1920            0 :         call wrtout(std_out,message,'COLL')
    1921              :       end if
    1922              :     end do
    1923              : 
    1924              :     !TEST_AM
    1925              :     !   call xmpi_sum(stat_coeff, comm, ierr)
    1926              :     !   do ii=1,ncoeff_tot
    1927              :     !     write(100,*) ii,stat_coeff(ii)
    1928              :     !   end do
    1929              :     !   close(100)
    1930              :     !TEST_AM
    1931              : 
    1932              :     !  Transfer final model
    1933            0 :     if(nproc>1)then
    1934              :       call xmpi_bcast(ncoeff_preselected,rank_to_send,comm,ierr)
    1935            0 :       call xmpi_bcast(list_coeffs(1:ncoeff_preselected),rank_to_send,comm,ierr)
    1936              :     end if
    1937            0 :     do ii=1,ncoeff_preselected
    1938            0 :       icoeff = list_coeffs(ii)
    1939            0 :       list_coeffs_tmp(ii) = ii
    1940              :       !    Fill the temporary arrays
    1941            0 :       energy_coeffs_tmp(ii,:)    = energy_coeffs(icoeff,:)
    1942            0 :       fcart_coeffs_tmp(:,:,ii,:) = fcart_coeffs(:,:,icoeff,:)
    1943            0 :       strten_coeffs_tmp(:,:,ii)  = strten_coeffs(:,:,icoeff)
    1944            0 :       call polynomial_coeff_free(coeffs_tmp(ii))
    1945              :       call polynomial_coeff_init(one,my_coeffs(icoeff)%nterm,&
    1946              :         &                               coeffs_tmp(ii),my_coeffs(icoeff)%terms,&
    1947              :         &                               my_coeffs(icoeff)%name,&
    1948            0 :         &                               check=.false.)
    1949              :     end do
    1950              : 
    1951            0 :  end subroutine select_with_monte_carlo
    1952              : 
    1953              :  !> Fits all selected coefficients to find their optimal values
    1954              :  !>
    1955              :  !> This routine:
    1956              :  !> - Performs final fitting of all selected coefficients together
    1957              :  !> - Solves the complete linear system for all coefficients
    1958              :  !> - Updates coefficient values in the effective potential
    1959              :  !> - Computes final goal function values for the fit
    1960              :  !> - Handles weighted and unweighted goal function calculations
    1961              :  !> - Outputs detailed fitting results in verbose mode
    1962              :  !> - Updates the effective potential with fitted coefficients
    1963              :  !> - Optionally writes anharmonic terms to output files
    1964           38 :  subroutine fit_all_selected_coefficients()
    1965              :    !This routine solves the linear system proposed by
    1966              :    ! C.Escorihuela-Sayalero see PRB95,094115(2017) [[cite:Escorihuela-Sayalero2017]]
    1967           38 :    real(dp), allocatable :: weights1(:)
    1968           38 :    if(ncoeff_to_fit > 0)then
    1969              :      block
    1970              :        integer :: ic
    1971          198 :        do ic =1, ncoeff_to_fit
    1972          198 :          list_coeffs_tmp(ic) =ic
    1973              :        end do
    1974              :      end block
    1975              :      call fit_polynomial_coeff_solve(coeff_values(1:ncoeff_to_fit),fcart_coeffs_tmp,fit_data%fcart_diff,&
    1976              :        &                                  energy_coeffs_tmp,fit_data%energy_diff,info,&
    1977              :        &                                  list_coeffs_tmp(1:ncoeff_to_fit),natom_sc,&
    1978              :        &                                  ncoeff_to_fit,ncoeff_to_fit,ntime,strten_coeffs_tmp,&
    1979              :        &                                  fit_data%strten_diff,fit_data%training_set%sqomega,fit_on,int_fit_factors, &
    1980           38 :        &                                  weights=weights)
    1981              : 
    1982              : 
    1983           38 :      if(need_verbose) then
    1984           38 :        write(message, '(3a)') ch10,' Fitted coefficients at the end of the fit process: '
    1985           38 :        call wrtout(ab_out,message,'COLL')
    1986           38 :        call wrtout(std_out,message,'COLL')
    1987              :      end if
    1988          198 :      do ii = 1,ncoeff_to_fit
    1989          160 :        if(list_coeffs(ii) ==0) cycle
    1990              :        !    Set the value of the coefficient
    1991          160 :        coeffs_tmp(ii)%coefficient = coeff_values(ii)
    1992          198 :        if(need_verbose) then
    1993          160 :          write(message, '(a,I0,a,ES19.10,2a)') " ",list_coeffs(ii)," =>",coeff_values(ii),&
    1994          320 :            &                                " ",trim(coeffs_tmp(ii)%name)
    1995          160 :          call wrtout(ab_out,message,'COLL')
    1996          160 :          call wrtout(std_out,message,'COLL')
    1997              :        end if
    1998              :      end do
    1999           38 :      if(fit_weight_T>0.0_dp) then
    2000              :          call fit_polynomial_coeff_computeGF(coeff_values(1:ncoeff_to_fit),energy_coeffs_tmp,&
    2001              :            &                                      fit_data%energy_diff,fcart_coeffs_tmp,fit_data%fcart_diff,&
    2002              :            &                                      gf_values(:,1),list_coeffs_tmp(1:ncoeff_to_fit),natom_sc,&
    2003              :            &                                      ncoeff_to_fit,ncoeff_to_fit,ntime,strten_coeffs_tmp,&
    2004            3 :            &                                      fit_data%strten_diff,fit_data%training_set%sqomega, weights=weights)
    2005              : 
    2006            3 :          if(need_verbose) then
    2007              :            !  Print the standard deviation after the fit
    2008            3 :            write(message,'(4a,ES24.16,2a,ES24.16,2a,ES24.16,2a,ES24.16,a)' )ch10,&
    2009              :              !&                    ' Mean Standard Deviation values at the end of the fit process (meV^2/atm): ',ch10,&
    2010              :              !&                    '   Energy          : ',&
    2011              :              !&               gf_values(4,1)*(Ha_EV*1000)**2 *factor ,ch10,&
    2012            3 :              &                    'Weighted goal function values at the end of the fit process (eV^2/A^2):',ch10,&
    2013            3 :              &                    '   Energy          : ',&
    2014            3 :              &               gf_values(4,1)*(HaBohr_eVAng)**2,ch10,&
    2015            3 :              &                    '   Forces+Stresses : ',&
    2016            3 :              &               gf_values(1,1)*(HaBohr_eVAng)**2,ch10,&
    2017            3 :              &                    '   Forces          : ',&
    2018            3 :              &               gf_values(2,1)*(HaBohr_eVAng)**2,ch10,&
    2019            3 :              &                    '   Stresses        : ',&
    2020            6 :              &               gf_values(3,1)*(HaBohr_eVAng)**2,ch10
    2021            3 :            call wrtout(ab_out,message,'COLL')
    2022            3 :            call wrtout(std_out,message,'COLL')
    2023              :          end if
    2024              :      endif
    2025              : 
    2026          114 :        ABI_MALLOC(weights1,(ntime))
    2027          595 :        weights1(:) = one
    2028              :        call fit_polynomial_coeff_computeGF(coeff_values(1:ncoeff_to_fit),energy_coeffs_tmp,&
    2029              :            &                                      fit_data%energy_diff,fcart_coeffs_tmp,fit_data%fcart_diff,&
    2030              :            &                                      gf_values(:,1),list_coeffs_tmp(1:ncoeff_to_fit),natom_sc,&
    2031              :            &                                      ncoeff_to_fit,ncoeff_to_fit,ntime,strten_coeffs_tmp,&
    2032           38 :            &                                      fit_data%strten_diff,fit_data%training_set%sqomega, weights=weights1)
    2033              : 
    2034           38 :          if(need_verbose) then
    2035              :            !  Print the standard deviation after the fit
    2036           38 :            write(message,'(4a,ES24.16,2a,ES24.16,2a,ES24.16,2a,ES24.16,a)' )ch10,&
    2037              :              !&                    ' Mean Standard Deviation values at the end of the fit process (meV^2/atm): ',ch10,&
    2038              :              !&                    '   Energy          : ',&
    2039              :              !&               gf_values(4,1)*(Ha_EV*1000)**2 *factor ,ch10,&
    2040           38 :              &                    ' Goal function values at the end of the fit process (eV^2/A^2):',ch10,&
    2041           38 :              &                    '   Energy          : ',&
    2042           38 :              &               gf_values(4,1)*(HaBohr_eVAng)**2,ch10,&
    2043           38 :              &                    '   Forces+Stresses : ',&
    2044           38 :              &               gf_values(1,1)*(HaBohr_eVAng)**2,ch10,&
    2045           38 :              &                    '   Forces          : ',&
    2046           38 :              &               gf_values(2,1)*(HaBohr_eVAng)**2,ch10,&
    2047           38 :              &                    '   Stresses        : ',&
    2048           76 :              &               gf_values(3,1)*(HaBohr_eVAng)**2,ch10
    2049           38 :            call wrtout(ab_out,message,'COLL')
    2050           38 :            call wrtout(std_out,message,'COLL')
    2051              :          end if
    2052           38 :         ABI_FREE(weights1)
    2053              : 
    2054              : 
    2055              :      !Allocate output coeffs -> selected plus fixed ones
    2056           38 :      ncoeff_out = ncoeff_to_fit+eff_pot_fixed%anharmonics_terms%ncoeff
    2057              : 
    2058          274 :      ABI_MALLOC(coeffs_out,(ncoeff_out))
    2059          198 :      do ii = 1,ncoeff_out
    2060          198 :        if(ii <= eff_pot_fixed%anharmonics_terms%ncoeff)then
    2061              :          call polynomial_coeff_init(eff_pot_fixed%anharmonics_terms%coefficients(ii)%coefficient,&
    2062              :            &                             eff_pot_fixed%anharmonics_terms%coefficients(ii)%nterm,coeffs_out(ii),&
    2063              :            &                             eff_pot_fixed%anharmonics_terms%coefficients(ii)%terms,&
    2064              :            &                             eff_pot_fixed%anharmonics_terms%coefficients(ii)%name,&
    2065            0 :            &                             check = .TRUE.)
    2066              :        else
    2067          160 :          ia = ii - eff_pot_fixed%anharmonics_terms%ncoeff
    2068              :          call polynomial_coeff_init( &
    2069              :             coeffs_tmp(ia)%coefficient, &  ! Coefficient value
    2070              :             coeffs_tmp(ia)%nterm, &        ! Number of terms
    2071              :             coeffs_out(ii), &             ! Output coefficient structure
    2072              :             coeffs_tmp(ia)%terms, &       ! Terms array
    2073              :             coeffs_tmp(ia)%name, &        ! Name of the coefficient
    2074              :             check = .true.      &            ! Validation flag
    2075          160 :          )
    2076              : 
    2077              :         !call polynomial_coeff_free(coeffs_tmp(ia))
    2078              :        endif
    2079              : 
    2080              :      enddo
    2081              :      !ABI_SFREE(coeffs_tmp)
    2082              : 
    2083              : 
    2084              : 
    2085              : 
    2086              :      !  Set the final set of coefficients into the eff_pot type
    2087           38 :      call effective_potential_setCoeffs(coeffs_out(:),eff_pot,ncoeff_out)
    2088              : 
    2089              :      ! If Wanted open the anharmonic_terms_file and write header
    2090           38 :      filename = "TRS_fit_diff"
    2091           38 :      if(need_prt_anh .and. ncoeff_model > 0 )then
    2092              :        call effective_potential_writeAnhHead(ncoeff_model,filename,&
    2093            0 :          &                                     eff_pot%anharmonics_terms)
    2094           38 :      else if (need_prt_anh)then
    2095            0 :        write(message, '(6a,I3,3a)' )ch10,&
    2096            0 :          &          ' --- !WARNING',ch10,&
    2097            0 :          &          '     Printing of anharmonic terms has been asked,but',ch10,&
    2098            0 :          &          '     there are',ncoeff_model,'anharmonic terms in the potential',ch10,&
    2099            0 :          &          ' ---',ch10
    2100            0 :        call wrtout(ab_out,message,'COLL')
    2101            0 :        call wrtout(std_out,message,'COLL')
    2102              :      end if
    2103              : 
    2104              :      ! Calculate MSD values for final model
    2105           38 :      if(need_prt_files)call fit_polynomial_coeff_computeMSD(eff_pot,hist,gf_values(4,1),gf_values(2,1),gf_values(1,1),&
    2106              :        &                                       natom_sc,ntime,fit_data%training_set%sqomega,comm,&
    2107           18 :        &                                       compute_anharmonic=.TRUE.,print_file=.TRUE.,filename=filename, weights=weights)
    2108              : 
    2109              : 
    2110              :      INQUIRE(FILE='TRS_fit_diff_anharmonic_terms_energy.dat',OPENED=file_opened&
    2111           38 :        &,number=unit_anh)
    2112           38 :      if(file_opened) close(unit_anh)
    2113              :    else
    2114            0 :      ncoeff_out = 0
    2115            0 :      if(need_verbose) then
    2116            0 :        write(message, '(9a)' )ch10,&
    2117            0 :          &          ' --- !WARNING',ch10,&
    2118            0 :          &          '     The fit process does not provide possible terms.',ch10,&
    2119            0 :          &          '     Please make sure that the terms set is correct',ch10,&
    2120            0 :          &          ' ---',ch10
    2121            0 :        call wrtout(ab_out,message,'COLL')
    2122            0 :        call wrtout(std_out,message,'COLL')
    2123              :      end if
    2124              :    end if
    2125           38 :  end subroutine fit_all_selected_coefficients
    2126              : 
    2127              :  !> Selects a single coefficient to include in the model
    2128              :  !>
    2129              :  !> This routine:
    2130              :  !> - Takes a coefficient index and marks it as selected
    2131              :  !> - Updates global selection status arrays
    2132              :  !> - Updates coefficient counts and remaining coefficient pool
    2133              :  !> - Handles MPI synchronization of selection status
    2134              :  !> - Updates list of selected coefficients
    2135              :  !>
    2136              :  !> @param ind Index of coefficient to select
    2137              :  subroutine select_one_coeff(ind)
    2138              :    ! Note ind is my_coeffindexes(icoeff)
    2139              :    integer :: ind
    2140              :    if (.not. isselected(ind)) then
    2141              :      rank_to_send= my_rank
    2142              :      isselected(ind)=.True.
    2143              :      call xmpi_lor(isselected, comm)
    2144              :    end if
    2145              :      !ncoeff_selected=count(isselected)
    2146              :    if(isselected(ind)) then
    2147              :      ncoeff_selected = ncoeff_selected+1
    2148              :      n_remaining=n_remaining-1
    2149              :      call xmpi_bcast(n_remaining, rank_to_send, comm, ierr)
    2150              :    end if
    2151              :    list_coeffs(ncoeff_selected) = ind
    2152              :  end subroutine select_one_coeff
    2153              : 
    2154              :  !> Bans a coefficient from being selected in future iterations
    2155              :  !>
    2156              :  !> This routine:
    2157              :  !> - Marks a coefficient as banned in the global banned array
    2158              :  !> - Updates the count of remaining available coefficients
    2159              :  !> - Synchronizes banned status across MPI processes
    2160              :  !> - Only bans if coefficient wasn't already banned
    2161              :  !>
    2162              :  !> @param icoeff Index of coefficient to ban
    2163              :  subroutine ban_one_term(icoeff)
    2164              :    integer :: icoeff
    2165              :    if (.not. isbanned(my_coeffindexes(icoeff))) then
    2166              :      isbanned(my_coeffindexes(icoeff))=.True.
    2167              :      call xmpi_lor(isbanned, comm)
    2168              :      n_remaining=n_remaining-1
    2169              :      call xmpi_bcast(n_remaining, rank_to_send, comm, ierr)
    2170              :    end if
    2171              :  end subroutine ban_one_term
    2172              : 
    2173              : 
    2174              : #endif
    2175              : 
    2176              : end subroutine fit_polynomial_coeff_fit
    2177              : !!***
    2178              : 
    2179              : 
    2180              : 
    2181              : !!****f* m_fit_polynomial_coeff/fit_polynomial_coeff_getPositive
    2182              : !!
    2183              : !! NAME
    2184              : !! fit_polynomial_coeff_getPositive
    2185              : !!
    2186              : !! FUNCTION
    2187              : !! This routine fit a list of possible model.
    2188              : !! Return in the isPositive array:
    2189              : !!   0 if the model ii does not contain possive coefficients
    2190              : !!   1 if the model ii contain possive coefficients
    2191              : !!
    2192              : !! INPUTS
    2193              : !! eff_pot<type(effective_potential)> = effective potential
    2194              : !! hist<type(abihist)> = The history of the MD (or snapshot of DFT
    2195              : !! coeff_values(nmodel,ncoeff) = values of the coefficients for each model
    2196              : !! isPositive(nmodel) = see description below
    2197              : !! list_coeff(nmodel,ncoeff) = list of the models
    2198              : !! ncoeff = number of coeff per model
    2199              : !! nfixcoeff = will not test the nfixcoeff first coeffcients
    2200              : !! nmodel = number of model
    2201              : !! comm = MPI communicator
    2202              : !! verbose  = optional, flag for the verbose mode
    2203              : !!
    2204              : !! OUTPUT
    2205              : !! eff_pot = effective potential datatype with new fitted coefficients
    2206              : !!
    2207              : !! SOURCE
    2208              : 
    2209            0 : subroutine fit_polynomial_coeff_getPositive(eff_pot,hist,coeff_values,isPositive,list_coeff,ncoeff,&
    2210              : &                                           nfixcoeff,nmodel,comm,verbose, fit_weight_T)
    2211              : 
    2212              :  implicit none
    2213              : 
    2214              : !Arguments ------------------------------------
    2215              : !scalars
    2216              :  integer,intent(in) :: ncoeff,nfixcoeff,nmodel,comm
    2217              : !arrays
    2218              :  integer,intent(in)  :: list_coeff(nmodel,ncoeff)
    2219              :  integer,intent(out) :: isPositive(nmodel)
    2220              :  real(dp),intent(out) :: coeff_values(nmodel,ncoeff)
    2221              :  type(effective_potential_type),intent(inout) :: eff_pot
    2222              :  type(abihist),intent(inout) :: hist
    2223              :  logical,optional,intent(in) :: verbose
    2224              :  real(dp) :: fit_weight_T
    2225              : !Local variables-------------------------------
    2226              : !scalar
    2227              :  integer :: ierr,ii,info,imodel,my_nmodel,nmodel_alone
    2228              :  integer :: master,my_rank,ncoeff_tot,natom_sc,ncell
    2229              :  integer :: nproc,ntime
    2230              :  logical :: iam_master,need_verbose
    2231              : !arrays
    2232            0 : real(dp), allocatable :: weights(:)
    2233              :  integer :: sc_size(3)
    2234            0 :  integer,allocatable  :: list_coeffs(:),my_modelindexes(:),my_modellist(:)
    2235            0 :  real(dp),allocatable :: energy_coeffs(:,:),fcart_coeffs(:,:,:,:), strten_coeffs(:,:,:)
    2236            0 :  type(polynomial_coeff_type),allocatable :: coeffs_in(:)
    2237            0 :  type(fit_data_type) :: fit_data
    2238              :  character(len=500) :: message
    2239              :  logical :: fit_on(3)
    2240              :  real(dp) :: fit_factors(3)
    2241              : ! *************************************************************************
    2242              : 
    2243              : !MPI variables
    2244            0 :  master = 0
    2245            0 :  nproc = xmpi_comm_size(comm); my_rank = xmpi_comm_rank(comm)
    2246            0 :  iam_master = (my_rank == master)
    2247              : 
    2248              : !Initialisation of optional arguments
    2249            0 :  need_verbose = .TRUE.
    2250            0 :  if(present(verbose)) need_verbose = verbose
    2251              : 
    2252            0 :  fit_on(1) = .FALSE.
    2253            0 :  fit_on(2) = .TRUE.
    2254            0 :  fit_on(3) = .TRUE.
    2255              : 
    2256            0 :  fit_factors = (/1,1,1/)
    2257              : 
    2258              : !Get the list of coefficients from the eff_pot
    2259            0 :  if(eff_pot%anharmonics_terms%ncoeff > 0)then
    2260              : !  Copy the initial coefficients array
    2261            0 :    ncoeff_tot = eff_pot%anharmonics_terms%ncoeff
    2262            0 :    ABI_MALLOC(coeffs_in,(ncoeff_tot))
    2263            0 :    do ii=1,ncoeff_tot
    2264              :      call polynomial_coeff_init(eff_pot%anharmonics_terms%coefficients(ii)%coefficient,&
    2265              :        &                               eff_pot%anharmonics_terms%coefficients(ii)%nterm,&
    2266              :        &                               coeffs_in(ii),&
    2267              :        &                               eff_pot%anharmonics_terms%coefficients(ii)%terms,&
    2268              :        &                               eff_pot%anharmonics_terms%coefficients(ii)%name,&
    2269            0 :        &                               check=.false.)
    2270              :    end do
    2271              :  end if
    2272              : 
    2273              : !Reset the output (we free the memory)
    2274            0 :  call effective_potential_freeCoeffs(eff_pot)
    2275              : 
    2276              : !if the number of atoms in reference supercell into effpot is not corret,
    2277              : !wrt to the number of atom in the hist, we set map the hist and set the good
    2278              : !supercell
    2279            0 :  if (size(hist%xred,2) /= eff_pot%supercell%natom) then
    2280            0 :    call effective_potential_file_mapHistToRef(eff_pot,hist,comm,verbose=need_verbose)
    2281              :  end if
    2282              : 
    2283              : !Initialisation of constants
    2284            0 :  natom_sc   = eff_pot%supercell%natom
    2285            0 :  ncell      = eff_pot%supercell%ncells
    2286            0 :  ntime      = hist%mxhist
    2287            0 :  do ii = 1, 3
    2288            0 :    sc_size(ii) = eff_pot%supercell%rlatt(ii,ii)
    2289              :  end do
    2290              : 
    2291              : !Initialisation of arrays:
    2292            0 :  ABI_MALLOC(list_coeffs,(ncoeff_tot))
    2293            0 :  list_coeffs  = 0
    2294            0 :  do ii = 1,ncoeff_tot
    2295            0 :    list_coeffs(ii) = ii
    2296              :  end do
    2297              : 
    2298              : !Get the decomposition for each coefficients of the forces and stresses for
    2299              : !each atoms and each step  equations 11 & 12 of  PRB95,094115(2017) [[cite:Escorihuela-Sayalero2017]]
    2300            0 :  if(need_verbose)then
    2301            0 :    write(message, '(a)' ) ' Initialisation of the fit process...'
    2302            0 :    call wrtout(std_out,message,'COLL')
    2303              :  end if
    2304              : !Before the fit, compute constants with fit_data_compute.
    2305              : !Conpute the strain of each configuration.
    2306              : !Compute the displacmeent of each configuration.
    2307              : !Compute the variation of the displacement due to strain of each configuration.
    2308              : !Compute fixed forces and stresse and get the standard deviation.
    2309              : !Compute Sheppard and al Factors  \Omega^{2} see J.Chem Phys 136, 074103 (2012) [[cite:Sheppard2012]].
    2310            0 :  call fit_data_compute(fit_data,eff_pot,hist,comm,verbose=need_verbose)
    2311              : 
    2312              : 
    2313            0 :  call get_weight_from_hist(hist, fit_weight_T, ntime, eff_pot%supercell%natom, weights, comm )
    2314              : 
    2315              : !Get the decomposition for each coefficients of the forces,stresses and energy for
    2316              : !each atoms and each step  (see equations 11 & 12 of
    2317              : ! PRB95,094115(2017)) [[cite:Escorihuela-Sayalero2017]] + allocation
    2318            0 :  ABI_MALLOC(energy_coeffs,(ncoeff_tot,ntime))
    2319            0 :  ABI_MALLOC(fcart_coeffs,(3,natom_sc,ncoeff_tot,ntime))
    2320            0 :  ABI_MALLOC(strten_coeffs,(6,ntime,ncoeff_tot))
    2321              : 
    2322              :  call fit_polynomial_coeff_getFS(coeffs_in,fit_data%training_set%du_delta,&
    2323              : &                                fit_data%training_set%displacement,&
    2324              : &                                energy_coeffs,fcart_coeffs,natom_sc,eff_pot%crystal%natom,&
    2325              : &                                ncoeff_tot,ntime,sc_size,&
    2326              : &                                fit_data%training_set%strain,strten_coeffs,&
    2327            0 : &                                fit_data%training_set%ucvol,list_coeffs,ncoeff_tot)
    2328              : 
    2329              : 
    2330              : 
    2331              : !set MPI, really basic stuff...
    2332            0 :  nmodel_alone = mod(nmodel,nproc)
    2333            0 :  my_nmodel = int(aint(real(nmodel,sp)/(nproc)))
    2334              : 
    2335            0 :  if(my_rank >= (nproc-nmodel_alone)) then
    2336            0 :    my_nmodel = my_nmodel  + 1
    2337              :  end if
    2338              : 
    2339            0 :  ABI_MALLOC(my_modelindexes,(my_nmodel))
    2340            0 :  ABI_MALLOC(my_modellist,(my_nmodel))
    2341              : 
    2342              : 
    2343              : 
    2344              : !2:compute the number of model and the list of the corresponding for each CPU.
    2345            0 :  do imodel=1,my_nmodel
    2346            0 :    if(my_rank >= (nproc-nmodel_alone))then
    2347              :      my_modelindexes(imodel)=(int(aint(real(nmodel,sp)/nproc)))*(my_rank)+&
    2348            0 :        & (my_rank - (nproc-nmodel_alone)) + imodel
    2349            0 :      my_modellist(imodel) = imodel
    2350              :    else
    2351            0 :      my_modelindexes(imodel)=(my_nmodel)*(my_rank)  + imodel
    2352            0 :      my_modellist(imodel) = imodel
    2353              :   end if
    2354              :  end do
    2355              : 
    2356              : 
    2357              : 
    2358              : !Start fit process
    2359            0 :  isPositive   = 0
    2360            0 :  coeff_values = zero
    2361            0 :  do ii=1,my_nmodel
    2362            0 :    imodel = my_modelindexes(ii)
    2363              :    call fit_polynomial_coeff_solve(coeff_values(imodel,1:ncoeff),fcart_coeffs&
    2364              :      &,fit_data%fcart_diff, energy_coeffs,fit_data%energy_diff,info,&
    2365              :      & list_coeff(imodel,1:ncoeff),natom_sc,ncoeff, ncoeff_tot,ntime&
    2366              :      &,strten_coeffs,fit_data%strten_diff, fit_data%training_set%sqomega,fit_on&
    2367            0 :      &,fit_factors, weights=weights)
    2368              : 
    2369            0 :    if(info==0)then
    2370              : 
    2371            0 :      if (any(coeff_values(imodel,nfixcoeff+1:ncoeff) < zero))then
    2372              : !       coeff_values(imodel,:) = zero
    2373            0 :        isPositive(imodel) = 0
    2374              :      else
    2375            0 :        isPositive(imodel) = 1
    2376              :      end if
    2377              :    end if
    2378              :  end do
    2379              : 
    2380            0 :  call xmpi_sum(isPositive, comm, ierr)
    2381            0 :  call xmpi_sum(coeff_values, comm, ierr)
    2382              : 
    2383              : 
    2384              : 
    2385              : !Deallocation of arrays
    2386            0 :  do ii=1,ncoeff_tot
    2387            0 :    call polynomial_coeff_free(coeffs_in(ii))
    2388              :  end do
    2389            0 :  call fit_data_free(fit_data)
    2390              : 
    2391            0 :  ABI_FREE(coeffs_in)
    2392            0 :  ABI_FREE(energy_coeffs)
    2393            0 :  ABI_FREE(fcart_coeffs)
    2394            0 :  ABI_FREE(list_coeffs)
    2395            0 :  ABI_FREE(my_modelindexes)
    2396            0 :  ABI_FREE(my_modellist)
    2397            0 :  ABI_FREE(strten_coeffs)
    2398            0 :  ABI_FREE(weights)
    2399            0 : end subroutine fit_polynomial_coeff_getPositive
    2400              : !!***
    2401              : 
    2402              : !!****f* m_fit_polynomial_coeff/fit_polynomial_coeff_getCoeffBound
    2403              : !!
    2404              : !! NAME
    2405              : !! fit_polynomial_coeff_getCoeffBound
    2406              : !!
    2407              : !! FUNCTION
    2408              : !! This routine fit a list of possible model.
    2409              : !! Return in the isPositive array:
    2410              : !!
    2411              : !! INPUTS
    2412              : !! NEED TO UPDATE
    2413              : !! eff_pot<type(effective_potential)> = effective potential
    2414              : !! hist<type(abihist)> = The history of the MD (or snapshot of DFT
    2415              : !! comm = MPI communicator
    2416              : !! verbose  = optional, flag for the verbose mode
    2417              : !!
    2418              : !! OUTPUT
    2419              : !!
    2420              : !!
    2421              : !! SOURCE
    2422              : 
    2423            0 : subroutine fit_polynomial_coeff_getCoeffBound(eff_pot,coeffs_out,hist,ncoeff_bound,comm,verbose, max_nbody)
    2424              : 
    2425              :  implicit none
    2426              : 
    2427              : !Arguments ------------------------------------
    2428              :  !scalars
    2429              :  integer,intent(in) :: comm, max_nbody(:)
    2430              :  integer,intent(out) :: ncoeff_bound
    2431              :  logical,optional,intent(in) :: verbose
    2432              : !arrays
    2433              :  type(abihist),intent(inout) :: hist
    2434              :  type(effective_potential_type),target,intent(inout) :: eff_pot
    2435              :  type(polynomial_coeff_type),allocatable,intent(out) :: coeffs_out(:)
    2436              : !Local variables-------------------------------
    2437              : !scalar
    2438              :  integer :: counter,icoeff,icoeff_bound,idisp,istrain,ii
    2439              :  integer :: istart,iterm,ndisp,nstrain,nterm,ncoeff_model,ncoeff_in,ncoeff_max
    2440              :  real(dp):: weight
    2441              :  logical :: need_verbose
    2442              : !arrays
    2443            0 :  integer,allocatable :: atindx(:,:),cells(:,:,:),direction(:)
    2444            0 :  integer,allocatable :: power_disps(:),power_strain(:),strain(:)
    2445            0 :  type(polynomial_term_type),dimension(:),allocatable :: terms
    2446            0 :  integer,allocatable :: odd_coeff(:),need_bound(:)
    2447            0 :  type(polynomial_coeff_type),pointer :: coeffs_in(:)
    2448            0 :  type(polynomial_coeff_type),allocatable :: coeffs_test(:)
    2449            0 :  character(len=5),allocatable :: symbols(:)
    2450              :  character(len=200):: name
    2451              :  character(len=500) :: msg
    2452              : ! *************************************************************************
    2453              : 
    2454              : 
    2455              : !set the inputs varaibles
    2456            0 :  ncoeff_model =  eff_pot%anharmonics_terms%ncoeff
    2457            0 :  coeffs_in => eff_pot%anharmonics_terms%coefficients
    2458              : 
    2459              : !Do check
    2460            0 :  if(ncoeff_model == 0)then
    2461            0 :    write(msg,'(a)')'ncoeff_model must be different to 0'
    2462            0 :    ABI_BUG(msg)
    2463              :  end if
    2464              : 
    2465              : !Map the hist in order to be consistent with the supercell into reference_effective_potential
    2466            0 :  call effective_potential_file_mapHistToRef(eff_pot,hist,comm)
    2467              : 
    2468              : !Initialisation of optional arguments
    2469            0 :  need_verbose = .TRUE.
    2470            0 :  if(present(verbose)) need_verbose = verbose
    2471              : 
    2472            0 :  write(msg, '(a)' ) ' Detection of the unbound coefficients'
    2473            0 :  if(need_verbose)call wrtout(std_out,msg,'COLL')
    2474              : 
    2475              : !Allocation
    2476            0 :  ncoeff_max = 2 * ncoeff_model
    2477            0 :  ABI_MALLOC(odd_coeff,(ncoeff_max))
    2478            0 :  ABI_MALLOC(need_bound,(ncoeff_max))
    2479              : 
    2480            0 :  ABI_MALLOC(symbols,(eff_pot%crystal%natom))
    2481              :  call symbols_crystal(eff_pot%crystal%natom,eff_pot%crystal%ntypat,eff_pot%crystal%npsp,&
    2482            0 : &                     symbols,eff_pot%crystal%typat,eff_pot%crystal%znucl)
    2483              : 
    2484              : 
    2485            0 :  ABI_MALLOC(coeffs_test,(ncoeff_max))
    2486              : 
    2487            0 :  do icoeff=1,ncoeff_model
    2488              :    call polynomial_coeff_init(coeffs_in(icoeff)%coefficient,coeffs_in(icoeff)%nterm,&
    2489              :      &                             coeffs_test(icoeff),coeffs_in(icoeff)%terms,&
    2490              :      &                             coeffs_in(icoeff)%name, &
    2491            0 :      &                          check=.false.)
    2492              :  end do
    2493              : 
    2494              : !array to know which coeff has to be bound
    2495            0 :  need_bound(:) = 1
    2496              :  counter = 0
    2497              :  ncoeff_in = ncoeff_model
    2498              : 
    2499            0 :  do while(.not.all(need_bound == 0).and.counter<1)
    2500              : !  Get the coefficients with odd coefficient
    2501            0 :    odd_coeff = 0
    2502              :    if(counter>0) then
    2503              :      need_bound(1:ncoeff_in) = 0
    2504              :      icoeff_bound = ncoeff_in
    2505              :    else
    2506              :      icoeff_bound = 1
    2507              :    end if
    2508              : 
    2509            0 :    do icoeff=icoeff_bound,ncoeff_model
    2510            0 :      if(any(mod(coeffs_in(icoeff)%terms(1)%power_disp(:),2)/=0))then
    2511            0 :        odd_coeff(icoeff) = 1
    2512              :      end if
    2513            0 :      if(any(mod(coeffs_in(icoeff)%terms(1)%power_strain(:),2)/=0))then
    2514            0 :        odd_coeff(icoeff) = 1
    2515              :      end if
    2516            0 :      if(odd_coeff(icoeff) == 0 .and. coeffs_in(icoeff)%coefficient > zero) then
    2517            0 :        need_bound(icoeff) = 0
    2518              :      else
    2519            0 :         need_bound(icoeff) = 1
    2520              :      end if
    2521              :    end do
    2522            0 :    if(need_verbose)then
    2523            0 :      write(msg, '(a)' ) ' The following coefficients need to be bound:'
    2524            0 :      call wrtout(std_out,msg,'COLL')
    2525            0 :      do icoeff=1,ncoeff_model
    2526            0 :        if(need_bound(icoeff) == 1)then
    2527            0 :          write(msg, '(2a)' ) ' =>',trim(coeffs_in(icoeff)%name)
    2528            0 :          call wrtout(std_out,msg,'COLL')
    2529              :        end if
    2530              :      end do
    2531              :    end if
    2532              : 
    2533              : 
    2534            0 :    icoeff_bound = ncoeff_in + 1
    2535              :    if(counter==0)then
    2536              :      istart = 1
    2537              :    else
    2538              :      istart = ncoeff_in
    2539              :    end if
    2540              : 
    2541            0 :    ncoeff_bound = count(need_bound(istart:ncoeff_model)==1)
    2542              : 
    2543            0 :    do icoeff=istart,ncoeff_model
    2544            0 :      if(need_bound(icoeff)==1)then
    2545              : 
    2546            0 :        nterm = coeffs_in(icoeff)%nterm
    2547            0 :        ndisp = coeffs_in(icoeff)%terms(1)%ndisp
    2548            0 :        nstrain = coeffs_in(icoeff)%terms(1)%nstrain
    2549              : 
    2550            0 :        ABI_MALLOC(terms,(nterm))
    2551            0 :        ABI_MALLOC(atindx,(2,ndisp))
    2552            0 :        ABI_MALLOC(cells,(3,2,ndisp))
    2553            0 :        ABI_MALLOC(direction,(ndisp))
    2554            0 :        ABI_MALLOC(power_disps,(ndisp))
    2555            0 :        ABI_MALLOC(power_strain,(nstrain))
    2556            0 :        ABI_MALLOC(strain,(nstrain))
    2557              : 
    2558            0 :        do iterm=1,coeffs_in(icoeff)%nterm
    2559            0 :          atindx(:,:) = coeffs_in(icoeff)%terms(iterm)%atindx(:,:)
    2560            0 :          cells(:,:,:) = coeffs_in(icoeff)%terms(iterm)%cell(:,:,:)
    2561            0 :          direction(:) = coeffs_in(icoeff)%terms(iterm)%direction(:)
    2562            0 :          power_strain(:) = coeffs_in(icoeff)%terms(iterm)%power_strain(:)
    2563            0 :          power_disps(:) = coeffs_in(icoeff)%terms(iterm)%power_disp(:)
    2564            0 :          strain(:) =  coeffs_in(icoeff)%terms(iterm)%strain(:)
    2565            0 :          weight =  1
    2566            0 :          do idisp=1,ndisp
    2567            0 :            if(mod(power_disps(idisp),2) /= 0) then
    2568            0 :              power_disps(idisp) = power_disps(idisp) + 1
    2569              :            else
    2570            0 :              power_disps(idisp) = power_disps(idisp) + 2
    2571              :            end if
    2572              :          end do
    2573            0 :          do istrain=1,nstrain
    2574            0 :            if(mod(power_strain(istrain),2) /= 0)then
    2575            0 :              power_strain(istrain) = power_strain(istrain) + 1
    2576              :            else
    2577            0 :              if(power_strain(istrain) < 4 ) power_strain(istrain) = power_strain(istrain) + 2
    2578              :            end if
    2579              :          end do
    2580              : 
    2581              :          call polynomial_term_init(atindx,cells,direction,ndisp,nstrain,terms(iterm),&
    2582            0 : &                                  power_disps,power_strain,strain,weight,check=.true.)
    2583              :        end do
    2584              : 
    2585            0 :        name = ""
    2586            0 :        call polynomial_coeff_init(one,nterm,coeffs_test(icoeff_bound),terms,name, check=.true.)
    2587            0 :        call polynomial_coeff_getName(name,coeffs_test(icoeff_bound),symbols,recompute=.TRUE.)
    2588            0 :        call polynomial_coeff_SetName(name,coeffs_test(icoeff_bound))
    2589              : 
    2590              : !      Deallocate the terms
    2591            0 :        do iterm=1,nterm
    2592            0 :          call polynomial_term_free(terms(iterm))
    2593              :        end do
    2594            0 :        ABI_FREE(terms)
    2595            0 :        ABI_FREE(atindx)
    2596            0 :        ABI_FREE(cells)
    2597            0 :        ABI_FREE(direction)
    2598            0 :        ABI_FREE(power_disps)
    2599            0 :        ABI_FREE(power_strain)
    2600            0 :        ABI_FREE(strain)
    2601              : 
    2602            0 :        icoeff_bound = icoeff_bound  + 1
    2603              : 
    2604              :      end if
    2605              :    end do
    2606              : 
    2607              : 
    2608            0 :    if(counter==0)ncoeff_model = ncoeff_model + ncoeff_bound
    2609              : !   call effective_potential_setCoeffs(coeffs_test,eff_pot,ncoeff_model)
    2610              :    call fit_polynomial_coeff_fit(eff_pot,(/0/),(/0/),hist,0,(/0,0/),1,0,&
    2611              :      &             -1,0,(/0/),1,comm,verbose=.true.,positive=.false., max_nbody=max_nbody, &
    2612            0 :      & drop_rate=0.0_dp, ncoeff_per_cycle=1, fit_weight_T=-0.1_dp)
    2613              : 
    2614            0 :    coeffs_in => eff_pot%anharmonics_terms%coefficients
    2615              : 
    2616            0 :    counter = counter + 1
    2617              :  end do
    2618              : 
    2619            0 :  ABI_MALLOC(coeffs_out,(ncoeff_bound))
    2620            0 :  do ii=1,ncoeff_bound
    2621            0 :    icoeff_bound = ncoeff_in + ii
    2622              :    call polynomial_coeff_init(one,coeffs_test(icoeff_bound)%nterm,coeffs_out(ii),&
    2623              :      &                    coeffs_test(icoeff_bound)%terms,coeffs_test(icoeff_bound)%name,&
    2624            0 :      &                    check=.true.)
    2625              :  end do
    2626              : !Deallocation
    2627            0 :  do ii=ncoeff_model,ncoeff_max
    2628            0 :    call polynomial_coeff_free(coeffs_test(ii))
    2629              :  end do
    2630              : 
    2631              : !Deallocation
    2632            0 :  do icoeff=1,ncoeff_max
    2633            0 :    call polynomial_coeff_free(coeffs_test(icoeff))
    2634              :  end do
    2635            0 :  ABI_FREE(coeffs_test)
    2636            0 :  ABI_FREE(odd_coeff)
    2637            0 :  ABI_FREE(need_bound)
    2638            0 :  ABI_FREE(symbols)
    2639              : 
    2640              : 
    2641            0 : end subroutine fit_polynomial_coeff_getCoeffBound
    2642              : !!***
    2643              : 
    2644              : 
    2645              : !!****f* m_fit_polynomial_coeff/fit_polynomial_coeff_solve
    2646              : !!
    2647              : !! NAME
    2648              : !! fit_polynomial_coeff_solve
    2649              : !!
    2650              : !! FUNCTION
    2651              : !! Build and the solve the system to get the values of the coefficients
    2652              : !! This routine solves the linear system proposed by
    2653              : !! C.Escorihuela-Sayalero see PRB95,094115(2017) [[cite:Escorihuela-Sayalero2017]]
    2654              : !!
    2655              : !! INPUTS
    2656              : !! fcart_coeffs(3,natom_sc,ncoeff_max,ntime) = List of the values of the contribution to the
    2657              : !!                                             cartesian forces for all coefficients
    2658              : !!                                             for each direction and each time
    2659              : !! fcart_diff(3,natom,ntime) = Difference of cartesian forces between DFT calculation and
    2660              : !!                             fixed part of the model (more often harmonic part)
    2661              : !! energy_coeffs(ncoeff,ntime)   = value of the energy for each  coefficient (Ha)
    2662              : !! energy_diff(ntime) = Difference of energ ybetween DFT calculation and fixed part
    2663              : !!                             of the model (more often harmonic part)
    2664              : !! list_coeffs(ncoeff_fit) = List with the index of the coefficients used for this model
    2665              : !! natom = Number of atoms
    2666              : !! ncoeff_fit = Number of coeff for the fit (dimension of the system)
    2667              : !! ncoeff_max = Maximum number of coeff in the list
    2668              : !! ntime = Number of time (number of snapshot, number of md step...)
    2669              : !! strten_coeffs(6,ntime,ncoeff_max) = List of the values of the contribution to the stress tensor
    2670              : !!                                      of  the coefficients for each direction,time
    2671              : !! strten_diff(6,natom) = Difference of stress tensor between DFT calculation and
    2672              : !!                        fixed part of the model (more often harmonic part)
    2673              : !! sqomega(ntime) =  Sheppard and al Factors \Omega^{2} see J.Chem Phys 136, 074103 (2012) [[cite:Sheppard2012]]
    2674              : !! weights(ntime) = weight of each configuration
    2675              : !! fit_on(3) = Flag to know if we fit the energy,  forces and stresses
    2676              : !! fit_factors(3) = Factors to apply to the energy, forces and stresses
    2677              : !!
    2678              : !! OUTPUT
    2679              : !! coefficients(ncoeff_fit) = Values of the coefficients
    2680              : !! info_out = 0:  successful exit
    2681              : !!          < 0:  if INFO = -i, the i-th argument had an illegal value
    2682              : !!          > 0:  if INFO = i, U(i,i) computed in DOUBLE PRECISION is
    2683              : !!                exactly zero.  The factorization has been completed,
    2684              : !!                but the factor U is exactly singular, so the solution
    2685              : !!                could not be computed.  = 0:  successful exit
    2686              : !!          information from the subroutine dsgesv in LAPACK
    2687              : !!
    2688              : !! SOURCE
    2689              : 
    2690        11740 : subroutine fit_polynomial_coeff_solve(coefficients,fcart_coeffs,fcart_diff,energy_coeffs,energy_diff,&
    2691        11740 : &                                     info_out,list_coeffs,natom,ncoeff_fit,ncoeff_max,ntime,&
    2692        11740 : &                                     strten_coeffs,strten_diff,sqomega,fit_on,fit_factors, weights)
    2693              : 
    2694              :  implicit none
    2695              : 
    2696              : !Arguments ------------------------------------
    2697              : !scalars
    2698              :  integer,intent(in)  :: natom,ncoeff_fit,ncoeff_max,ntime
    2699              :  integer,intent(out) :: info_out
    2700              : !arrays
    2701              :  real(dp),intent(in) :: energy_coeffs(ncoeff_max,ntime)
    2702              :  real(dp),intent(in) :: energy_diff(ntime)
    2703              :  integer,intent(in)  :: list_coeffs(ncoeff_fit)
    2704              :  real(dp),intent(in) :: fcart_coeffs(3,natom,ncoeff_max,ntime)
    2705              :  real(dp),intent(in) :: fcart_diff(3,natom,ntime)
    2706              :  real(dp),intent(in) :: strten_coeffs(6,ntime,ncoeff_max)
    2707              :  real(dp),intent(in) :: strten_diff(6,ntime),sqomega(ntime)
    2708              :  real(dp),intent(out):: coefficients(ncoeff_fit)
    2709              :  real(dp),intent(in)  :: fit_factors(3)
    2710              :  logical,intent(in)  :: fit_on(3)
    2711              :  real(dp), intent(in) :: weights(ntime)
    2712              : 
    2713              : !Local variables-------------------------------
    2714              : !scalar
    2715              :  integer :: ia,itime,icoeff,jcoeff,icoeff_tmp,jcoeff_tmp,mu,LDA,LDB,LDX,LDAF,N,NRHS
    2716              :  real(dp):: efact,ffact,sfact,ftmpA,stmpA,ftmpB,stmpB,etmpA,etmpB,fmu,fnu,smu,snu,emu,enu
    2717              :  integer :: INFO
    2718              :  !integer :: ITER ! Only needed if DSGESV is used
    2719              :  real(dp):: RCOND
    2720        11740 :  real(dp),allocatable:: fcart_coeffs_tmp(:,:,:)
    2721        11740 :  real(dp),allocatable:: AF(:,:),BERR(:),FERR(:),WORK(:),C(:),R(:)
    2722        11740 :  integer,allocatable :: IPIV(:),IWORK(:),SWORK(:)
    2723              : !arrays
    2724        11740 :  real(dp),allocatable :: A(:,:),B(:,:)
    2725              :  character(len=1) :: FACT,EQUED,TRANS
    2726              : ! character(len=500) :: message
    2727              : ! *************************************************************************
    2728              : 
    2729              : !0-Set variables for the
    2730        11740 :  N    = ncoeff_fit; NRHS = 1; LDA  = ncoeff_fit; LDB  = ncoeff_fit; LDX  = ncoeff_fit
    2731        11740 :  LDAF = ncoeff_fit;  RCOND = zero; INFO  = 0; TRANS='N'; EQUED='N'; FACT='N'
    2732              : 
    2733              : !Set the factors
    2734        11740 :  efact = fit_factors(1)*one/(ntime)
    2735        11740 :  ffact = fit_factors(2)*one/(3*natom*ntime)
    2736        11740 :  sfact = fit_factors(3)*one/(6*ntime)
    2737              : 
    2738              : !0-Allocation
    2739        46960 :  ABI_MALLOC(A,(LDA,N))
    2740        35220 :  ABI_MALLOC(B,(LDB,NRHS))
    2741        35220 :  ABI_MALLOC(AF,(LDAF,N))
    2742        35220 :  ABI_MALLOC(IPIV,(N))
    2743        35220 :  ABI_MALLOC(R,(N))
    2744        23480 :  ABI_MALLOC(C,(N))
    2745        11740 :  ABI_MALLOC(FERR,(NRHS))
    2746        11740 :  ABI_MALLOC(BERR,(NRHS))
    2747        35220 :  ABI_MALLOC(WORK,(4*N))
    2748        23480 :  ABI_MALLOC(IWORK,(N))
    2749        35220 :  ABI_MALLOC(SWORK,(N*(N+NRHS)))
    2750        46960 :  ABI_MALLOC(fcart_coeffs_tmp,(3,natom,ntime))
    2751       465112 :  A=zero; B=zero;
    2752       453372 :  AF = zero; IPIV = 1;
    2753       120628 :  R = one; C = one;
    2754        35220 :  FERR = zero; BERR = zero
    2755       283960 :  IWORK = 0; WORK = 0
    2756              : 
    2757              : !1-Get forces and stresses from the model and fill A
    2758              : !  Fill alsor B with the forces and stresses from
    2759              : !  the DFT snapshot and the model
    2760              : !  See equation 17 of PRB95 094115 (2017) [[cite:Escorihuela-Sayalero2017]]
    2761        66184 :  do icoeff=1,ncoeff_fit
    2762        54444 :    icoeff_tmp = list_coeffs(icoeff)
    2763    530387800 :    fcart_coeffs_tmp(:,:,:) = fcart_coeffs(:,:,icoeff_tmp,:)
    2764      3348440 :    ftmpA= zero; ftmpB = zero
    2765      3348440 :    stmpA= zero; stmpB = zero
    2766      3348440 :    etmpA= zero; etmpB = zero
    2767              : !  loop over the configuration
    2768      3348440 :    do itime=1,ntime
    2769              : !    Fill energy
    2770      3293996 :      emu = energy_coeffs(icoeff_tmp,itime)
    2771     29312412 :      do jcoeff=1,ncoeff_fit
    2772     26018416 :        jcoeff_tmp = list_coeffs(jcoeff)
    2773     26018416 :        enu = energy_coeffs(jcoeff_tmp,itime)
    2774     29312412 :        if(fit_on(3))then
    2775       361889 :          etmpA =  emu*enu/(sqomega(itime)**(1.0/2.0))
    2776       361889 :          A(icoeff,jcoeff) = A(icoeff,jcoeff) + efact*etmpA* weights(itime)
    2777              :        endif
    2778              :      end do
    2779      3293996 :      if(fit_on(3))then
    2780        73403 :         etmpB = etmpB + energy_diff(itime)*emu/(sqomega(itime)**(1.0/2.0)) * weights(itime)!/ (sqomega(itime)**3)
    2781              :      else
    2782              :         etmpB = zero ! REMOVE THIS LINE TO TAKE INTO ACOUNT THE ENERGY
    2783              :      endif
    2784              : !    Fill forces
    2785    135053836 :      do ia=1,natom
    2786    530333356 :        do mu=1,3
    2787    395279520 :          fmu = fcart_coeffs_tmp(mu,ia,itime)
    2788   3517489440 :          do jcoeff=1,ncoeff_fit
    2789   3122209920 :            jcoeff_tmp = list_coeffs(jcoeff)
    2790   3122209920 :            fnu = fcart_coeffs(mu,ia,jcoeff_tmp,itime)
    2791   3122209920 :            ftmpA =  fmu*fnu
    2792   3517489440 :            if(fit_on(1))A(icoeff,jcoeff) = A(icoeff,jcoeff) + ffact*ftmpA* weights(itime)
    2793              :          end do
    2794    527039360 :          if(fit_on(1))then
    2795    395279520 :            ftmpB = ftmpB + fcart_diff(mu,ia,itime)*fmu* weights(itime)
    2796              :          else
    2797              :            ftmpB = zero
    2798              :          endif
    2799              :        end do !End loop dir
    2800              :      end do !End loop natom
    2801              : !    Fill stresses
    2802     23112416 :      do mu=1,6
    2803     19763976 :        smu = strten_coeffs(mu,itime,icoeff_tmp)
    2804    175874472 :        do jcoeff=1,ncoeff_fit
    2805    156110496 :          jcoeff_tmp = list_coeffs(jcoeff)
    2806    156110496 :          snu = strten_coeffs(mu,itime,jcoeff_tmp)
    2807    156110496 :          stmpA =  sqomega(itime)*smu*snu
    2808    175874472 :          if(fit_on(2))A(icoeff,jcoeff) = A(icoeff,jcoeff) + sfact*stmpA *weights(itime)
    2809              :        end do
    2810     23057972 :         if(fit_on(2))then
    2811     19763976 :           stmpB = stmpB + sqomega(itime)*strten_diff(mu,itime)*smu * weights(itime)
    2812              :         else
    2813              :           stmpB = zero
    2814              :         endif
    2815              :      end do !End loop stress dir
    2816              :    end do ! End loop time
    2817        66184 :    B(icoeff,1) = B(icoeff,1) + ffact*ftmpB + sfact*stmpB + efact*etmpB
    2818              :  end do ! End loop icoeff
    2819              : 
    2820              : !2-Solve Ax=B
    2821              : 
    2822              : !== Three different LAPACK routines are possible ==
    2823              : !OLD VERSION..
    2824              : ! call dgesvx(FACT,TRANS,N,NRHS,A,LDA,AF,LDAF,IPIV,EQUED,R,C,B,LDB,coefficients,LDX,&
    2825              :  !RCOND,FERR,BERR,WORK,IWORK,INFO)
    2826              : !U is nonsingular
    2827              : ! if (INFO==N+1) then
    2828              : !   coefficients = zero
    2829              : ! end if
    2830              : 
    2831              : !VERSION PRIOR TO 20240817. However test multibinit multi_l_6_1 fails on the new reference machine (eos).
    2832              : !call DSGESV(N,NRHS,A,LDA,IPIV,B,LDB,coefficients,LDX,WORK,SWORK,ITER,INFO)
    2833              : 
    2834              : !Other routine, activated on 20240817, together with the change of reference machine
    2835              : ! Check matrix conditioning
    2836              :  !if (any(isnan(A))) then
    2837              :  !  INFO = -2
    2838              :  !  print *, "NaN in A"
    2839              :  !  coefficients = zero
    2840              :  !endif
    2841              : 
    2842              :  !if (any(isnan(B))) then
    2843              :  !   INFO = -2
    2844              :  !   !print *, "NaN in B"
    2845              :  !   coefficients = zero
    2846              :  !endif
    2847              :    ! Solve the system
    2848              :   ! call dgesv(N,NRHS,A,LDA,IPIV,B,LDB,INFO)
    2849              :    !if (INFO == 0) then
    2850              :      ! Check solution for NaN or very large values
    2851              :     ! if (any(isnan(B(:,NRHS))) .or. any(abs(B(:,NRHS)) > 1.0e10_dp)) then
    2852              :     !   INFO = -3
    2853              :     !   coefficients = zero
    2854              :     !   !print *, "NaN or very large values in coefficients"
    2855              :     ! else
    2856              :     !   coefficients = B(:,NRHS)
    2857              :     !   print *, "INFO=", INFO
    2858              :     !   print *, "Good solution", coefficients
    2859              :     ! endif
    2860              :     !else
    2861              :     !    print*, "INFO=", INFO, "setting coefficients to zero"
    2862              :     !  coefficients = zero
    2863              :     !end if
    2864              : 
    2865              : !==================================================
    2866              : 
    2867              : 
    2868        11740 :  call dgesv(N,NRHS,A,LDA,IPIV,B,LDB,INFO)
    2869        66184 :  coefficients = B(:,NRHS)
    2870              : 
    2871              :  !U is nonsingular
    2872        11740 :  if (INFO==N+2) then
    2873            0 :    coefficients = zero
    2874              :  end if
    2875              : 
    2876       132299 :    if(any(abs(coefficients)>1.0E10) .or. any(coefficients /= coefficients))then
    2877           69 :      INFO = 1
    2878          218 :      coefficients = zero
    2879              :    end if
    2880              : 
    2881        11740 :    info_out = INFO
    2882              : 
    2883        11740 :  ABI_FREE(AF)
    2884        11740 :  ABI_FREE(IPIV)
    2885        11740 :  ABI_FREE(R)
    2886        11740 :  ABI_FREE(C)
    2887        11740 :  ABI_FREE(FERR)
    2888        11740 :  ABI_FREE(BERR)
    2889        11740 :  ABI_FREE(WORK)
    2890        11740 :  ABI_FREE(IWORK)
    2891        11740 :  ABI_FREE(SWORK)
    2892        11740 :  ABI_FREE(A)
    2893        11740 :  ABI_FREE(B)
    2894        11740 :  ABI_FREE(fcart_coeffs_tmp)
    2895              : 
    2896        11740 : end subroutine fit_polynomial_coeff_solve
    2897              : !!***
    2898              : 
    2899              : 
    2900              : 
    2901              : !> Computes weights for history configurations based on forces and temperature
    2902              : !>
    2903              : !> This routine:
    2904              : !> - Calculates average force magnitudes for each configuration
    2905              : !> - Applies Boltzmann weighting based on input temperature
    2906              : !> - Uses atomic forces to determine configuration importance
    2907              : !> - Normalizes weights to sum to ntime
    2908              : !> - Outputs detailed statistics about forces and weights
    2909              : !> - Handles both temperature-dependent and uniform weighting
    2910              : !>
    2911              : !> @param hist Input history containing force data
    2912              : !> @param temperature Temperature in K for Boltzmann weighting
    2913              : !> @param ntime Number of timesteps in history
    2914              : !> @param natom Number of atoms in system
    2915              : !> @param weights Output array of weights for each configuration
    2916              : !> @param comm MPI communicator
    2917           40 : subroutine get_weight_from_hist(hist, temperature, ntime, natom, weights, comm)
    2918              :   type(abihist), intent(in) :: hist
    2919              :   !real(dp), intent(in) :: DFT_forces(3,natom,ntime)
    2920              :   real(dp), intent(in) :: temperature
    2921              :   integer, intent(in) :: ntime, natom
    2922              :   integer, intent(in) :: comm
    2923              :   real(dp), allocatable, intent(out) :: weights(:)
    2924              :   integer :: itime, iatom
    2925              :   ! Boltzmann constant in Ha/K
    2926              :   real(dp), parameter :: kb = 3.166815d-6
    2927           80 :   real(dp) :: average_forces(ntime)
    2928           40 :   character(len=ntime*100) :: msg
    2929              :   integer ::  master, my_rank
    2930              :   logical :: iam_master
    2931              : 
    2932           40 :   master = 0
    2933           40 :   my_rank = xmpi_comm_rank(comm)
    2934           40 :   iam_master = (my_rank == master)
    2935          120 :   ABI_MALLOC(weights, (ntime))
    2936          799 :   weights=1.0_dp
    2937              : 
    2938              :   ! compute average forces for each time step
    2939          799 :   average_forces = 0.0_dp
    2940          799 :   do itime=1,ntime
    2941        31119 :      do iatom=1,natom
    2942       122199 :        average_forces(itime) = average_forces(itime) + norm2(hist%fcart(:,iatom,itime))
    2943              :      end do
    2944          799 :      average_forces(itime) = average_forces(itime)/natom
    2945              :   end do
    2946              : 
    2947           40 :   if (temperature > 0.0_dp) then
    2948              :      ! compute the average norm of force for each atom
    2949              :       ! compute the weight
    2950           36 :       weights = 0.0_dp
    2951           36 :       do itime=1,ntime
    2952           33 :         weights(itime) = exp(-average_forces(itime)/(kb*temperature))
    2953           36 :         if (weights(itime)< 0.001) then
    2954           21 :           weights(itime) = 0.001
    2955              :         endif
    2956              :       end do
    2957              :       ! normalize the weight
    2958           69 :       weights = weights/sum(weights)* ntime
    2959              :   end if
    2960              :   ! For each time, print the average forces, the energy, the weight,
    2961              :   ! the maximum of axial stress, and maximum of shear stress
    2962              :   ! first write the header of the table
    2963              :   ! write a separator
    2964              : 
    2965           40 : if(iam_master)then
    2966           24 :   write(msg, '(a)') '-----------------------------------------------------------------------------------'
    2967           24 :   write(msg, '(a)') 'Time  Average_forces  Etot-min(Etot)       Weight      Max(axial_stress) Max(shear_stress)'
    2968           24 :   call wrtout(std_out,msg,'COLL')
    2969              :   ! then write the data
    2970          607 :   do itime=1,ntime
    2971          583 :       write(msg, '(i5, 3e15.6, 2e15.6)') itime, average_forces(itime), &
    2972        46609 :         & hist%etot(itime)-minval(hist%etot(:)), weights(itime), &
    2973         6413 :         & maxval(abs(hist%strten(1:3,itime))), maxval(abs(hist%strten(4:6,itime)))
    2974          607 :      call wrtout(std_out,msg,'COLL')
    2975              :   end do
    2976           24 :   write(msg, '(a)') '-----------------------------------------------------------------------------------'
    2977              : endif
    2978              : 
    2979              : 
    2980           40 : end subroutine  get_weight_from_hist
    2981              : 
    2982              : 
    2983              : 
    2984              : 
    2985              : !> Computes goal function values comparing model predictions to reference data
    2986              : !>
    2987              : !> This routine calculates:
    2988              : !> - Forces + stresses combined goal function (gf_value(1))
    2989              : !> - Forces only goal function (gf_value(2))
    2990              : !> - Stresses only goal function (gf_value(3))
    2991              : !> - Energy goal function (gf_value(4))
    2992              : !>
    2993              : !> The calculations:
    2994              : !> - Use supplied coefficient values to evaluate model
    2995              : !> - Compare to reference energy/force/stress differences
    2996              : !> - Apply configuration weights if provided
    2997              : !> - Handle volume/supercell normalization
    2998              : !> - Support parallel evaluation across processes
    2999              : !>
    3000              : !> @param coefficients Model coefficient values
    3001              : !> @param energy_coeffs Energy terms for each coefficient
    3002              : !> @param energy_diff Reference energy differences
    3003              : !> @param fcart_coeffs Force terms for each coefficient
    3004              : !> @param fcart_diff Reference force differences
    3005              : !> @param gf_value Output goal function values
    3006              : !> @param list_coeffs List of coefficients to include
    3007              : !> @param natom Number of atoms
    3008              : !> @param ncoeff_fit Number of coefficients being fit
    3009              : !> @param ncoeff_max Maximum number of coefficients
    3010              : !> @param ntime Number of configurations
    3011              : !> @param strten_coeffs Stress terms for each coefficient
    3012              : !> @param strten_diff Reference stress differences
    3013              : !> @param sqomega Configuration weighting factors
    3014              : !> @param weights Optional weights for each configuration
    3015        11714 : subroutine fit_polynomial_coeff_computeGF(coefficients,energy_coeffs,energy_diff,&
    3016        11714 : &                                         fcart_coeffs,fcart_diff,gf_value,list_coeffs,&
    3017        11714 : &                                         natom,ncoeff_fit,ncoeff_max,ntime,strten_coeffs,&
    3018        11714 : &                                         strten_diff,sqomega, weights)
    3019              : 
    3020              :  implicit none
    3021              : 
    3022              : !Arguments ------------------------------------
    3023              : !scalars
    3024              :  integer,intent(in)  :: natom,ncoeff_fit,ncoeff_max,ntime
    3025              : !arrays
    3026              :  integer,intent(in)  :: list_coeffs(ncoeff_fit)
    3027              :  real(dp),intent(in) :: energy_coeffs(ncoeff_max,ntime)
    3028              :  real(dp),intent(in) :: energy_diff(ntime)
    3029              :  real(dp),intent(in) :: fcart_coeffs(3,natom,ncoeff_max,ntime)
    3030              :  real(dp),intent(in) :: fcart_diff(3,natom,ntime)
    3031              :  real(dp),intent(in) :: strten_coeffs(6,ntime,ncoeff_max)
    3032              :  real(dp),intent(in) :: strten_diff(6,ntime),sqomega(ntime)
    3033              :  real(dp),intent(in) :: coefficients(ncoeff_fit)
    3034              :  real(dp), intent(in) :: weights(ntime)
    3035              :  real(dp),intent(out) :: gf_value(4)
    3036              : !Local variables-------------------------------
    3037              : !scalar
    3038              :  integer :: ia,icoeff,icoeff_tmp,itime,mu
    3039              :  real(dp):: etmp,emu,fmu,ftmp,smu,stmp
    3040              :  real(dp) :: ffact,sfact,efact
    3041              : !arrays
    3042              : ! *************************************************************************
    3043              : 
    3044              : !1-Compute the value of the goal function
    3045              : ! see equation 9 of PRB 95 094115(2017) [[cite:Escorihuela-Sayalero2017]]
    3046              :  gf_value = zero
    3047        11714 :  etmp     = zero
    3048        11714 :  ftmp     = zero
    3049        11714 :  stmp     = zero
    3050              : 
    3051              : !Compute factors
    3052        11714 :  ffact = one/(3*natom*ntime)
    3053        11714 :  sfact = one/(6*ntime)
    3054        11714 :  efact = one/(ntime)
    3055              : 
    3056              : ! loop over the configuration
    3057       558819 :  do itime=1,ntime
    3058              : ! Fill energy
    3059              :    emu = zero
    3060      3839392 :    do icoeff=1,ncoeff_fit
    3061      3292287 :      icoeff_tmp = list_coeffs(icoeff)
    3062      3839392 :      emu = emu + coefficients(icoeff)*energy_coeffs(icoeff_tmp,itime)
    3063              :    end do
    3064              : !   uncomment the next line to be consistent with the definition of the goal function
    3065       547105 :    etmp = etmp + (energy_diff(itime)-emu)**2* weights(itime)/(sqomega(itime)**(1.0/2.0))
    3066              : !   uncomment the next get a measure in Ha instead of Ha^2
    3067              : !   etmp = etmp + abs(energy_diff(itime)-emu)
    3068              : !  Fill forces
    3069     22431305 :    do ia=1,natom
    3070     88083905 :      do mu=1,3
    3071              :        fmu  = zero
    3072    460727040 :        do icoeff=1,ncoeff_fit
    3073    395074440 :          icoeff_tmp = list_coeffs(icoeff)
    3074    460727040 :          fmu =  fmu + coefficients(icoeff)*fcart_coeffs(mu,ia,icoeff_tmp,itime)
    3075              :        end do
    3076     87536800 :        ftmp = ftmp + (fcart_diff(mu,ia,itime)-fmu)**2* weights(itime)
    3077              :      end do !End loop dir
    3078              :    end do !End loop natom
    3079      3841449 :    do mu=1,6
    3080              :      smu = zero
    3081     23036352 :      do icoeff=1,ncoeff_fit
    3082     19753722 :        icoeff_tmp = list_coeffs(icoeff)
    3083     23036352 :        smu = smu + coefficients(icoeff)*strten_coeffs(mu,itime,icoeff_tmp)
    3084              :      end do
    3085      3829735 :      stmp = stmp + sqomega(itime)* weights(itime) *(strten_diff(mu,itime)-smu)**2
    3086              :    end do !End loop stress dir
    3087              :  end do ! End loop time
    3088              : 
    3089        11714 :  gf_value(1)   =  ffact*ftmp + sfact*stmp !+ efact*etmp !Stresses + Forces
    3090        11714 :  gf_value(2)   =  ffact*ftmp ! only Forces
    3091        11714 :  gf_value(3)   =  sfact*stmp ! only Stresses
    3092        11714 :  gf_value(4)   =  efact*etmp !abs(Energy)
    3093              : 
    3094        11714 : end subroutine fit_polynomial_coeff_computeGF
    3095              : !!***
    3096              : 
    3097              : 
    3098              : !> Computes force and stress contributions for all polynomial coefficients
    3099              : !>
    3100              : !> This routine:
    3101              : !> - Evaluates energy, force and stress terms for each coefficient
    3102              : !> - Handles displacement-displacement and displacement-strain couplings
    3103              : !> - Applies periodic boundary conditions for supercell calculations
    3104              : !> - Computes derivatives needed for force and stress evaluations
    3105              : !> - Includes strain-dependent volume corrections
    3106              : !> - Supports parallel evaluation across processes
    3107              : !>
    3108              : !> Based on equations 11 & 12 in PRB95,094115 (2017) [[cite:Escorihuela-Sayalero2017]]
    3109              : !>
    3110              : !> @param coefficients Input polynomial coefficients
    3111              : !> @param du_delta Changes in displacements due to strain
    3112              : !> @param displacement Atomic displacements
    3113              : !> @param energy_out Output energy terms for each coefficient
    3114              : !> @param fcart_out Output force terms for each coefficient
    3115              : !> @param natom_sc Number of atoms in supercell
    3116              : !> @param natom_uc Number of atoms in unit cell
    3117              : !> @param ncoeff_max Maximum number of coefficients
    3118              : !> @param ntime Number of configurations
    3119              : !> @param sc_size Supercell dimensions
    3120              : !> @param strain Strain values
    3121              : !> @param strten_out Output stress terms for each coefficient
    3122              : !> @param ucvol Unit cell volumes
    3123              : !> @param coeffs List of coefficients to evaluate
    3124              : !> @param ncoeff Number of coefficients to evaluate
    3125        11798 : subroutine fit_polynomial_coeff_getFS(coefficients,du_delta,displacement,energy_out,fcart_out,&
    3126        11798 : &                                     natom_sc,natom_uc,ncoeff_max,ntime,sc_size,strain,strten_out,&
    3127        11798 : &                                     ucvol,coeffs,ncoeff)
    3128              : 
    3129              :  implicit none
    3130              : 
    3131              : !Arguments ------------------------------------
    3132              : !scalars
    3133              :  integer,intent(in) :: natom_sc,natom_uc,ncoeff_max,ntime
    3134              :  integer,intent(in) :: ncoeff
    3135              : !arrays
    3136              :  integer,intent(in) :: sc_size(3)
    3137              :  integer,intent(in) :: coeffs(ncoeff_max)
    3138              :  real(dp),intent(in) :: du_delta(6,3,natom_sc,ntime)
    3139              :  real(dp),intent(in) :: displacement(3,natom_sc,ntime)
    3140              :  real(dp),intent(in) :: strain(6,ntime),ucvol(ntime)
    3141              :  real(dp),intent(out):: energy_out(ncoeff,ntime)
    3142              :  real(dp),intent(out) :: fcart_out(3,natom_sc,ncoeff,ntime)
    3143              :  real(dp),intent(out) :: strten_out(6,ntime,ncoeff)
    3144              :  type(polynomial_coeff_type), intent(in) :: coefficients(ncoeff_max)
    3145              : !Local variables-------------------------------
    3146              : !scalar
    3147              :  integer :: i1,i2,i3,ia1,ia2,ib1,ib2,ii,icell,icoeff,icoeff_tmp
    3148              :  integer :: idir1,idir2,idisp1,idisp2,idisp1_strain,idisp2_strain
    3149              :  integer :: iterm,itime,ndisp,ndisp_tot,nstrain,power_disp,power_strain
    3150              :  real(dp):: disp1,disp2,tmp1,tmp2,tmp3,weight
    3151              : !arrays
    3152              :  integer :: cell_atoma1(3),cell_atoma2(3)
    3153              :  integer :: cell_atomb1(3),cell_atomb2(3)
    3154              : 
    3155              : ! *************************************************************************
    3156              : 
    3157              : 
    3158              : !1-Get forces and stresses from the model
    3159              : !  Initialisation of variables
    3160     89048517 :  fcart_out(:,:,:,:) = zero
    3161      3870867 :  strten_out(:,:,:)  = zero
    3162      1110917 :  energy_out(:,:)    = zero
    3163        11798 :  icell = 0; ib1=0; ia1=0
    3164        35394 :  do i1=1,sc_size(1)
    3165        82586 :    do i2=1,sc_size(2)
    3166       165172 :      do i3=1,sc_size(3)
    3167        94384 :        ii = icell*natom_uc
    3168        94384 :        icell = icell + 1
    3169              : !      Loop over configurations
    3170      4537648 :        do itime=1,ntime
    3171              : !       Loop over coefficients
    3172      8887336 :          do icoeff_tmp=1,ncoeff
    3173      4396880 :            icoeff = coeffs(icoeff_tmp)
    3174              : !          Loop over terms of this coefficient
    3175    129038056 :            do iterm=1,coefficients(icoeff)%nterm
    3176    120245104 :              ndisp = coefficients(icoeff)%terms(iterm)%ndisp
    3177    120245104 :              nstrain = coefficients(icoeff)%terms(iterm)%nstrain
    3178    120245104 :              ndisp_tot = ndisp + nstrain
    3179              : !            Set the weight of this term
    3180    120245104 :              weight =coefficients(icoeff)%terms(iterm)%weight
    3181    120245104 :              tmp1 = one
    3182              : !            Loop over displacement and strain
    3183    527428432 :              do idisp1=1,ndisp_tot
    3184              : 
    3185              : !              Set to one the acculation of forces and strain
    3186    407183328 :                tmp2 = one
    3187    407183328 :                tmp3 = one
    3188              : !              Strain case idir => -6, -5, -4, -3, -2 or -1
    3189    407183328 :                if (idisp1 > ndisp)then
    3190     48745920 :                  idisp1_strain = idisp1 - ndisp
    3191     48745920 :                  power_strain = coefficients(icoeff)%terms(iterm)%power_strain(idisp1_strain)
    3192              : !                Get the direction of the displacement or strain
    3193     48745920 :                  idir1 = coefficients(icoeff)%terms(iterm)%strain(idisp1_strain)
    3194     48745920 :                  if(abs(strain(idir1,itime)) > tol10)then
    3195              : !                  Accumulate energy fo each displacement (\sum ((A_x-O_x)^Y(A_y-O_c)^Z))
    3196     29382624 :                    tmp1 = tmp1 * (strain(idir1,itime))**power_strain
    3197     29382624 :                    if(power_strain > 1) then
    3198              : !                    Accumulate stress for each strain (\sum (Y(eta_2)^Y-1(eta_2)^Z+...))
    3199        45360 :                      tmp3 = tmp3 *  power_strain*(strain(idir1,itime))**(power_strain-1)
    3200              :                    end if
    3201              :                  else
    3202     19363296 :                    tmp1 = zero
    3203     19363296 :                    if(power_strain > 1) then
    3204         2160 :                      tmp3 = zero
    3205              :                    end if
    3206              :                  end if
    3207              :                else
    3208              : !                Set the power_disp of the displacement:
    3209    358437408 :                  power_disp = coefficients(icoeff)%terms(iterm)%power_disp(idisp1)
    3210              : !                Get the direction of the displacement or strain
    3211    358437408 :                  idir1 = coefficients(icoeff)%terms(iterm)%direction(idisp1)
    3212              : !                Displacement case idir = 1, 2  or 3
    3213              : !                indexes of the cell of the atom a
    3214   1433749632 :                  cell_atoma1 = coefficients(icoeff)%terms(iterm)%cell(:,1,idisp1)
    3215    358437408 :                  if(cell_atoma1(1)/=0.or.cell_atoma1(2)/=0.or.cell_atoma1(3)/=0) then
    3216              : !                  if the cell is not 0 0 0 we apply PBC:
    3217            0 :                    cell_atoma1(1) =  i1 + cell_atoma1(1)
    3218            0 :                    cell_atoma1(2) =  i2 + cell_atoma1(2)
    3219            0 :                    cell_atoma1(3) =  i3 + cell_atoma1(3)
    3220            0 :                    call getPBCIndexes_supercell(cell_atoma1(1:3),sc_size(1:3))
    3221              : !                  index of the first atom (position in the supercell if the cell is not 0 0 0)
    3222              :                    ia1 = (cell_atoma1(1)-1)*sc_size(2)*sc_size(3)*natom_uc+&
    3223              : &                        (cell_atoma1(2)-1)*sc_size(3)*natom_uc+&
    3224              : &                        (cell_atoma1(3)-1)*natom_uc+&
    3225            0 : &                        coefficients(icoeff)%terms(iterm)%atindx(1,idisp1)
    3226              :                  else
    3227              : !                  index of the first atom (position in the supercell if the cell is 0 0 0)
    3228    358437408 :                    ia1 = ii + coefficients(icoeff)%terms(iterm)%atindx(1,idisp1)
    3229              :                  end if
    3230              : 
    3231              : !                indexes of the cell of the atom b  (with PBC) same as ia1
    3232   1433749632 :                  cell_atomb1 = coefficients(icoeff)%terms(iterm)%cell(:,2,idisp1)
    3233    358437408 :                  if(cell_atomb1(1)/=0.or.cell_atomb1(2)/=0.or.cell_atomb1(3)/=0) then
    3234    195199584 :                    cell_atomb1(1) =  i1 + cell_atomb1(1)
    3235    195199584 :                    cell_atomb1(2) =  i2 + cell_atomb1(2)
    3236    195199584 :                    cell_atomb1(3) =  i3 + cell_atomb1(3)
    3237    195199584 :                    call getPBCIndexes_supercell(cell_atomb1(1:3),sc_size(1:3))
    3238              : 
    3239              : !                  index of the second atom in the (position in the supercell  if the cell is not 0 0 0)
    3240              :                    ib1 = (cell_atomb1(1)-1)*sc_size(2)*sc_size(3)*natom_uc+&
    3241              : &                        (cell_atomb1(2)-1)*sc_size(3)*natom_uc+&
    3242              : &                        (cell_atomb1(3)-1)*natom_uc+&
    3243    195199584 : &                        coefficients(icoeff)%terms(iterm)%atindx(2,idisp1)
    3244              :                  else
    3245              : !                  index of the first atom (position in the supercell if the cell is 0 0 0)
    3246    163237824 :                    ib1 = ii + coefficients(icoeff)%terms(iterm)%atindx(2,idisp1)
    3247              :                  end if
    3248              : 
    3249              : !                Get the displacement for the both atoms
    3250    358437408 :                  disp1 = displacement(idir1,ia1,itime)
    3251    358437408 :                  disp2 = displacement(idir1,ib1,itime)
    3252              : 
    3253    358437408 :                  if(abs(disp1) > tol10 .or. abs(disp2)> tol10)then
    3254              : !                  Accumulate energy fo each displacement (\sum ((A_x-O_x)^Y(A_y-O_c)^Z))
    3255    351505920 :                    tmp1 = tmp1 * (disp1-disp2)**power_disp
    3256    351505920 :                    if(power_disp > 1) then
    3257              : !                    Accumulate forces for each displacement (\sum (Y(A_x-O_x)^Y-1(A_y-O_c)^Z+...))
    3258     32850240 :                      tmp2 = tmp2 * power_disp*(disp1-disp2)**(power_disp-1)
    3259              :                    end if
    3260              :                  else
    3261      6931488 :                    tmp1 = zero
    3262      6931488 :                    if(power_disp > 1) then
    3263       368736 :                      tmp2 = zero
    3264              :                    end if
    3265              :                  end if
    3266              :                end if
    3267              : 
    3268   1831660032 :                do idisp2=1,ndisp_tot
    3269   1831660032 :                  if(idisp2 /= idisp1) then
    3270              : 
    3271              : !                  Strain case
    3272   1017293376 :                    if (idisp2 > ndisp)then
    3273    126657792 :                      idisp2_strain = idisp2 - ndisp
    3274    126657792 :                      idir2 = coefficients(icoeff)%terms(iterm)%strain(idisp2_strain)
    3275              : !                    Set the power_strain of the strain:
    3276    126657792 :                      power_strain = coefficients(icoeff)%terms(iterm)%power_strain(idisp2_strain)
    3277              : !                    Accumulate energy forces
    3278    126657792 :                      tmp2 = tmp2 * (strain(idir2,itime))**power_strain
    3279              : !                    Accumulate stress for each strain (\sum (Y(eta_2)^Y-1(eta_2)^Z+...))
    3280    126657792 :                      tmp3 = tmp3 * (strain(idir2,itime))**power_strain
    3281              : !                  Atomic displacement case
    3282              :                    else
    3283              : !                    Set the power_disp of the displacement:
    3284    890635584 :                      power_disp = coefficients(icoeff)%terms(iterm)%power_disp(idisp2)
    3285              : !                    Set the direction of the displacement:
    3286    890635584 :                      idir2 = coefficients(icoeff)%terms(iterm)%direction(idisp2)
    3287              : 
    3288   3562542336 :                      cell_atoma2=coefficients(icoeff)%terms(iterm)%cell(:,1,idisp2)
    3289    890635584 :                      if(cell_atoma2(1)/=0.or.cell_atoma2(2)/=0.or.cell_atoma2(3)/=0) then
    3290            0 :                        cell_atoma2(1) =  i1 + cell_atoma2(1)
    3291            0 :                        cell_atoma2(2) =  i2 + cell_atoma2(2)
    3292            0 :                        cell_atoma2(3) =  i3 + cell_atoma2(3)
    3293            0 :                        call getPBCIndexes_supercell(cell_atoma2(1:3),sc_size(1:3))
    3294              : !                      index of the first atom (position in the supercell and direction)
    3295              : !                      if the cell of the atom a is not 0 0 0 (may happen)
    3296              :                        ia2 = (cell_atoma2(1)-1)*sc_size(2)*sc_size(3)*natom_uc+&
    3297              : &                            (cell_atoma2(2)-1)*sc_size(3)*natom_uc+&
    3298              : &                            (cell_atoma2(3)-1)*natom_uc+&
    3299            0 : &                        coefficients(icoeff)%terms(iterm)%atindx(1,idisp2)
    3300              :                      else
    3301              : !                      index of the first atom (position in the supercell and direction)
    3302    890635584 :                        ia2 = ii + coefficients(icoeff)%terms(iterm)%atindx(1,idisp2)
    3303              :                      end if
    3304              : 
    3305   3562542336 :                      cell_atomb2 = coefficients(icoeff)%terms(iterm)%cell(:,2,idisp2)
    3306              : 
    3307    890635584 :                      if(cell_atomb2(1)/=0.or.cell_atomb2(2)/=0.or.cell_atomb2(3)/=0) then
    3308              : !                      indexes of the cell2 (with PBC)
    3309    475655760 :                        cell_atomb2(1) =  i1 + cell_atomb2(1)
    3310    475655760 :                        cell_atomb2(2) =  i2 + cell_atomb2(2)
    3311    475655760 :                        cell_atomb2(3) =  i3 + cell_atomb2(3)
    3312    475655760 :                        call getPBCIndexes_supercell(cell_atomb2(1:3),sc_size(1:3))
    3313              : 
    3314              : !                      index of the second atom in the (position in the supercell)
    3315              :                        ib2 = (cell_atomb2(1)-1)*sc_size(2)*sc_size(3)*natom_uc+&
    3316              : &                            (cell_atomb2(2)-1)*sc_size(3)*natom_uc+&
    3317              : &                            (cell_atomb2(3)-1)*natom_uc+&
    3318    475655760 : &                            coefficients(icoeff)%terms(iterm)%atindx(2,idisp2)
    3319              :                      else
    3320    414979824 :                        ib2 = ii + coefficients(icoeff)%terms(iterm)%atindx(2,idisp2)
    3321              :                      end if
    3322              : 
    3323    890635584 :                      disp1 = displacement(idir2,ia2,itime)
    3324    890635584 :                      disp2 = displacement(idir2,ib2,itime)
    3325              : 
    3326    890635584 :                      tmp2 = tmp2 * (disp1-disp2)**power_disp
    3327    890635584 :                      tmp3 = tmp3 * (disp1-disp2)**power_disp
    3328              : 
    3329              :                    end if
    3330              :                  end if
    3331              :                end do
    3332              : 
    3333    527428432 :                if(idisp1 > ndisp)then
    3334              : !                Accumule stress tensor
    3335              :                     strten_out(idir1,itime,icoeff_tmp) = strten_out(idir1,itime,icoeff_tmp) + &
    3336     48745920 : &                                                      weight * tmp3
    3337              :                else
    3338              : !                Accumule  forces
    3339    358437408 :                  fcart_out(idir1,ia1,icoeff_tmp,itime)=fcart_out(idir1,ia1,icoeff_tmp,itime)+weight*tmp2
    3340    358437408 :                  fcart_out(idir1,ib1,icoeff_tmp,itime)=fcart_out(idir1,ib1,icoeff_tmp,itime)-weight*tmp2
    3341              :                end if
    3342              :              end do
    3343              : 
    3344              : !            accumule energy
    3345    124641984 :              energy_out(icoeff_tmp,itime) = energy_out(icoeff_tmp,itime) +  weight * tmp1
    3346              : 
    3347              :            end do!End do iterm
    3348              :          end do!End do coeff
    3349              :        end do!End time
    3350              :      end do!End do i3
    3351              :    end do!End do i2
    3352              :  end do!End do i1
    3353              : 
    3354              : ! multiply by -1
    3355     89048517 :  fcart_out(:,:,:,:) = -1 * fcart_out(:,:,:,:)
    3356              : 
    3357              : !ADD stress due to forces on atoms and variation of disp with strain
    3358        23597 :  do icoeff=1,ncoeff
    3359       573207 :    do itime=1,ntime
    3360     22545809 :      do ia1=1,natom_sc
    3361     88487210 :        do idir1=1,3
    3362    483656800 :          do idir2=1,6
    3363              :               strten_out(idir2,itime,icoeff) = strten_out(idir2,itime,icoeff) - &
    3364    461672400 : &                     du_delta(idir2,idir1,ia1,itime)*fcart_out(idir1,ia1,icoeff,itime)
    3365              :          end do
    3366              :        end do
    3367              :      end do
    3368              :    end do
    3369              :  end do
    3370              : 
    3371       561307 :  do itime=1, ntime
    3372      3858361 :     do idir1=1,6
    3373      3846563 :        if (idir1 < 4) then
    3374      3297357 :           strten_out(idir1,itime,:) = strten_out(idir1,itime,:) * (1 + strain(idir1,itime))/ucvol(itime)
    3375              :        else
    3376      3297357 :           strten_out(idir1,itime,:) = strten_out(idir1,itime,:) * (1 - strain(idir1,itime)**2)/ucvol(itime)
    3377              :        end if
    3378              :     end do
    3379              :  end do
    3380              : 
    3381        11798 : end subroutine fit_polynomial_coeff_getFS
    3382              : 
    3383              : 
    3384              : 
    3385              : 
    3386              : 
    3387              : !> Computes mean squared deviations between model and reference data
    3388              : !>
    3389              : !> This routine:
    3390              : !> - Evaluates the effective potential for all configurations
    3391              : !> - Computes energy, force and stress differences vs reference
    3392              : !> - Calculates weighted mean squared deviations
    3393              : !> - Handles optional printing of detailed comparisons
    3394              : !> - Supports electronic model evaluations if requested
    3395              : !> - Can output phonon-specific analysis data
    3396              : !>
    3397              : !> @param eff_pot Effective potential to evaluate
    3398              : !> @param hist Reference history with DFT data
    3399              : !> @param mse Output mean squared error for energies
    3400              : !> @param msef Output mean squared error for forces
    3401              : !> @param mses Output mean squared error for stresses
    3402              : !> @param natom Number of atoms in system
    3403              : !> @param ntime Number of configurations
    3404              : !> @param sqomega Sheppard-like weighting factors
    3405              : !> @param comm MPI communicator
    3406              : !> @param compute_anharmonic Flag to include anharmonic terms
    3407              : !> @param print_file Flag to print detailed comparison files
    3408              : !> @param filename Base name for output files
    3409              : !> @param scup_dtset Optional SCUP dataset parameters
    3410              : !> @param prt_ph Flag to print phonon analysis
    3411              : !> @param weights Optional weights for each configuration
    3412           56 : subroutine fit_polynomial_coeff_computeMSD(eff_pot,hist,mse,msef,mses,natom,ntime,sqomega,comm,&
    3413              : &                                          compute_anharmonic,print_file,filename,scup_dtset,&
    3414           20 : &                                          prt_ph, weights)
    3415              : 
    3416              :  implicit none
    3417              : 
    3418              : !Arguments ------------------------------------
    3419              : !scalars
    3420              :  integer, intent(in) :: natom,ntime,comm
    3421              :  real(dp),intent(out):: mse,msef,mses
    3422              :  logical,optional,intent(in) :: compute_anharmonic,print_file,prt_ph
    3423              : !arrays
    3424              :  real(dp),intent(in) :: sqomega(ntime)
    3425              :  type(effective_potential_type),intent(in) :: eff_pot
    3426              :  type(abihist),intent(in) :: hist
    3427              : !Strings/Characters
    3428              :  character(len=fnlen),optional,intent(in) :: filename
    3429              :  type(scup_dtset_type),optional,intent(inout) :: scup_dtset
    3430              :  real(dp),optional, intent(in) :: weights(ntime)
    3431              : !Local variables-------------------------------
    3432              : !scalar
    3433              : integer :: ii,ia,mu,unit_energy,unit_stress,itime,master,nproc,my_rank,i
    3434              : !Uncommend for dipdip test
    3435              :  integer :: ifirst
    3436              :  real(dp):: energy,energy_harm
    3437              :  logical :: need_anharmonic,need_print,need_elec_eval,iam_master
    3438              :  logical :: need_prt_ph
    3439              :  !arrays
    3440              :  real(dp):: strten(6),rprimd(3,3)
    3441           28 :  real(dp),allocatable :: fcart(:,:),gred(:,:),xred(:,:)
    3442              : !Strings/Characters
    3443              :  character(len=fnlen) :: file_energy, file_stress, file_anh, name_file
    3444              :  character(len=500) :: msg
    3445              : !Uncommend for dipdip test
    3446           28 :  type(abihist) :: hist_out
    3447              :  character(len=200) :: filename_hist
    3448              : 
    3449           28 :  real(dp),allocatable :: weights_tmp(:)
    3450              : ! *************************************************************************
    3451              :  !MS Hide SCALE-UP variables
    3452              :  ABI_UNUSED(itime)
    3453              : 
    3454           84 :  ABI_MALLOC(fcart,(3,natom))
    3455           56 :  ABI_MALLOC(gred,(3,natom))
    3456           56 :  ABI_MALLOC(xred,(3,natom))
    3457           84 :  ABI_MALLOC(weights_tmp,(ntime))
    3458              : 
    3459              :  !MPI
    3460           28 :  master = 0
    3461           28 :  nproc = xmpi_comm_size(comm); my_rank = xmpi_comm_rank(comm)
    3462           28 :  iam_master = (my_rank == master)
    3463              : 
    3464              :  !Do some checks
    3465           28 :  if(ntime /= hist%mxhist)then
    3466            0 :    write(msg,'(a)')'ntime is not correct'
    3467            0 :    ABI_BUG(msg)
    3468              :  end if
    3469              : 
    3470           28 :  if(natom /= size(hist%xred,2)) then
    3471            0 :    write(msg,'(a)')'natom is not correct'
    3472            0 :    ABI_BUG(msg)
    3473              :  end if
    3474              : 
    3475           28 :  need_anharmonic = .TRUE.
    3476           28 :  if(present(compute_anharmonic))then
    3477           28 :    need_anharmonic = compute_anharmonic
    3478              :  end if
    3479              : 
    3480           28 :  name_file=''
    3481           28 :  if(present(filename))name_file = filename
    3482              : 
    3483           28 :  need_print=.FALSE.
    3484           28 :  if(present(print_file))need_print=print_file
    3485              : 
    3486           28 :  need_elec_eval = .FALSE.
    3487           28 :  if(present(scup_dtset))need_elec_eval=scup_dtset%scup_elec_model
    3488              : 
    3489           28 :  need_prt_ph=.FALSE.
    3490           28 :  if(present(prt_ph))need_prt_ph=prt_ph
    3491              : 
    3492              : 
    3493           28 :  if(need_print .and. present(filename))then
    3494              :    !MS hist out uncommented for PHONOPY test
    3495           21 :    call abihist_init(hist_out,natom,ntime,.false.,.false.)
    3496           21 :    file_energy=trim(name_file)//'_energy.dat'
    3497           21 :    unit_energy = get_unit()
    3498           21 :    if (open_file(file_energy,msg,unit=unit_energy,form="formatted",&
    3499              : &     status="unknown",action="write") /= 0) then
    3500            0 :      ABI_ERROR(msg)
    3501              :    end if
    3502           21 :    unit_stress = get_unit()
    3503           21 :    file_stress=trim(name_file)//'_stress.dat'
    3504           21 :    if (open_file(file_stress,msg,unit=unit_stress,form="formatted",&
    3505              : &     status="unknown",action="write") /= 0) then
    3506            0 :      ABI_ERROR(msg)
    3507              :    end if
    3508            7 :  else if(need_print .and. .not. present(filename))then
    3509            0 :    write(msg,'(3a)')' You asked for printing of the MSD-values',ch10,&
    3510            0 : &        ' without specifying a filename'
    3511            0 :    ABI_ERROR(msg)
    3512              :  end if
    3513              : 
    3514           28 :  if(present(weights))then
    3515          579 :    weights_tmp = weights
    3516              :  else
    3517          816 :    weights_tmp = one
    3518              :  end if
    3519              : 
    3520           28 :  file_anh=trim(name_file)//'_anharmonic_terms_energy.dat'
    3521              : 
    3522           28 :  mse  = zero
    3523           28 :  msef = zero
    3524           28 :  mses = zero
    3525         1375 :  do ii=1,ntime ! Loop over configurations
    3526       216867 :    xred(:,:)   = hist%xred(:,:,ii)
    3527        17511 :    rprimd(:,:) = hist%rprimd(:,:,ii)
    3528         1347 :    itime = ii
    3529              : #if defined DEV_MS_SCALEUP
    3530              :    !Pass print options to scale-up
    3531              :    itime = ii
    3532              :    if(need_elec_eval)then
    3533              :         call global_set_parent_iter(itime)
    3534              :         ! Set all print options to false.
    3535              :         call global_set_print_parameters(geom=.FALSE.,eigvals=.FALSE.,eltic=.FALSE.,&
    3536              : &                orbocc=.FALSE.,bands=.FALSE.)
    3537              :         if(ii == 1 .or. modulo(ii,scup_dtset%scup_printniter) == 0)then
    3538              :            call global_set_print_parameters(scup_dtset%scup_printgeom,scup_dtset%scup_printeigv,scup_dtset%scup_printeltic,&
    3539              : &                   scup_dtset%scup_printorbocc,scup_dtset%scup_printbands)
    3540              :         end if
    3541              :    end if
    3542              : #endif
    3543              :    call effective_potential_evaluate(eff_pot,energy_harm,fcart,gred,strten,natom,rprimd,&
    3544              : &                                    xred=xred,compute_anharmonic=.False.,verbose=.false.,&
    3545         1347 : &                                    elec_eval=need_elec_eval)
    3546              : 
    3547              :    call effective_potential_evaluate(eff_pot,energy,fcart,gred,strten,natom,rprimd,&
    3548              : &                                    xred=xred,compute_anharmonic=need_anharmonic,verbose=.false.,&
    3549         1347 : &                                    filename=file_anh,elec_eval=need_elec_eval)
    3550              : 
    3551         1347 :    if(need_print .and. iam_master)then
    3552          552 :      WRITE(unit_energy ,'(I10,7(F23.14))') ii,hist%etot(ii),energy_harm,energy,&
    3553         1104 : &                                       abs(hist%etot(ii) - energy_harm),abs(hist%etot(ii) - energy)
    3554          552 :      WRITE(unit_stress,'(I10,12(F23.14))') ii,hist%strten(:,ii),strten(:)
    3555              :    end if
    3556              : 
    3557              :     !MS Uncommented for abihist test
    3558         1347 :    if(need_prt_ph)then
    3559            0 :     if(ii == 1)then
    3560            0 :       write(msg,'(a,(80a))') ch10,('-',i=1,80)
    3561            0 :       call wrtout(ab_out,msg,'COLL')
    3562            0 :       call wrtout(std_out,msg,'COLL')
    3563            0 :       write(msg,'(3a)') ch10,'test_prt_ph == 1, write evulation of Model on the TEST-set into ph_test.nc',ch10
    3564            0 :       call wrtout(ab_out,msg,'COLL')
    3565            0 :       call wrtout(std_out,msg,'COLL')
    3566              :     endif
    3567            0 :     ifirst=merge(0,1,(ii>1))
    3568            0 :     filename_hist = trim("ph_test.nc")
    3569            0 :     hist_out%fcart(:,:,hist_out%ihist) = fcart(:,:)
    3570            0 :     hist_out%strten(:,hist_out%ihist)  = strten(:)
    3571            0 :     hist_out%etot(hist_out%ihist)      = energy
    3572            0 :     hist_out%entropy(hist_out%ihist)   = hist%entropy(ii)
    3573            0 :     hist_out%time(hist_out%ihist)      = real(ii,kind=dp)
    3574              : !    call vel2hist(ab_mover%amass,hist,vel,vel_cell)
    3575            0 :     call var2hist(hist%acell(:,ii),hist_out,natom,hist%rprimd(:,:,ii),hist%xred(:,:,ii),.false.)
    3576            0 :     if(iam_master)then
    3577              :        call write_md_hist(hist_out,filename_hist,ifirst,ii,natom,1,eff_pot%crystal%ntypat,&
    3578              : &                    eff_pot%supercell%typat,eff_pot%crystal%amu,eff_pot%crystal%znucl,&
    3579            0 : &                    real(100,dp),(/real(100,dp),real(100,dp)/))
    3580              :     endif
    3581              :    endif!(need_prt_ph)
    3582              : 
    3583         1347 :    mse  = mse  + weights_tmp(ii) * ((hist%etot(ii) - energy))**2/(sqomega(ii)**(1.0/2.0)) !+abs(hist$etot(ii) - energy)
    3584        55227 :    do ia=1,natom ! Loop over atoms
    3585       216867 :      do mu=1,3   ! Loop over cartesian directions
    3586       215520 :        msef = msef + weights_tmp(ii) * (hist%fcart(mu,ia,ii)  - fcart(mu,ia))**2
    3587              :      end do
    3588              :    end do
    3589         9457 :    do mu=1,6 ! Loop over stresses
    3590         9429 :      mses = mses + weights_tmp(ii) * sqomega(ii)*(hist%strten(mu,ii) - strten(mu))**2
    3591              :    end do
    3592              :  end do ! End loop itime
    3593           28 :    if(need_prt_ph)then
    3594            0 :     write(msg,'(a,(80a))') ch10,('-',i=1,80)
    3595            0 :     call wrtout(ab_out,msg,'COLL')
    3596            0 :     call wrtout(std_out,msg,'COLL')
    3597              :    endif
    3598              : 
    3599           28 :  mse  = mse  /  ntime
    3600           28 :  msef = msef / (3*natom*ntime)
    3601           28 :  mses = mses / (6*ntime)
    3602              : 
    3603           28 :  if(need_print)then
    3604           21 :    close(unit_energy)
    3605           21 :    close(unit_stress)
    3606              :  end if
    3607              : 
    3608              :  !MS uncommented for PHONOPY TEST
    3609           28 :  call abihist_free(hist_out)
    3610              : 
    3611           28 :  ABI_FREE(fcart)
    3612           28 :  ABI_FREE(gred)
    3613           28 :  ABI_FREE(xred)
    3614           28 :  ABI_FREE(weights_tmp)
    3615              : 
    3616           56 : end subroutine fit_polynomial_coeff_computeMSD
    3617              : 
    3618              : 
    3619              : 
    3620              : !MARCUS_EXPERIMENTAL_SECTION
    3621              : !!****f* m_fit_polynomiaL_coeff/testEffPot
    3622              : !! NAME
    3623              : !!  testEffPot
    3624              : !!
    3625              : !! FUNCTION
    3626              : !!  Calculate the energy, forces for displacements provided
    3627              : !!  in an test-set (input:hist) within a given effective potential
    3628              : !!  (input: eff_pot)
    3629              : !!  If the test set is from DFT and contains DFT energies and forces
    3630              : !!  calculate the Goal Function values and the MSD of the Energy with
    3631              : !!  respect to the DFT energies
    3632              : !!
    3633              : !! INPUTS
    3634              : !! eff_pot = effective_potential datatype
    3635              : !! hist = abihist datatype
    3636              : !!
    3637              : !! OUTPUT
    3638              : !!
    3639              : !! SOURCE
    3640            1 : subroutine fit_polynomial_coeff_testEffPot(eff_pot,hist,master,comm,print_anharmonic,scup_dtset,prt_ph)
    3641              : 
    3642              : 
    3643              :   implicit none
    3644              : 
    3645              : !Arguments ------------------------------------
    3646              : !scalars
    3647              :   integer,intent(in) :: master,comm
    3648              :   integer,optional,intent(in) :: prt_ph
    3649              : !logicals
    3650              :   logical,optional,intent(in) :: print_anharmonic
    3651              : !array
    3652              :   type(effective_potential_type),intent(inout) :: eff_pot
    3653              :   type(abihist),intent(in) :: hist
    3654              :   type(scup_dtset_type),optional,intent(inout) :: scup_dtset
    3655              : !Local variables-------------------------------
    3656              : !reals
    3657              :   real(dp) :: factor,mse,msef,mses
    3658            1 :   real(dp),allocatable :: sqomega(:),ucvol(:)
    3659              :   real(dp),parameter :: HaBohr_eVAng = Ha_eV /Bohr_Ang
    3660              : !scalar
    3661              :   integer :: itime,unit_anh
    3662              :   integer :: natom,ntime,ncoeff,my_rank
    3663              : !logicals
    3664              :   logical :: iam_master, need_print_anharmonic,file_opened,need_prt_ph
    3665              : !strings/characters
    3666              :  character(len=fnlen) :: filename
    3667              :  character(len=1000) :: message
    3668              : !arrays
    3669              :  real(dp) :: gmet(3,3),gprimd(3,3),rmet(3,3)
    3670              : ! *************************************************************************
    3671              : 
    3672              :   !MPI variables
    3673            1 :   my_rank=xmpi_comm_rank(comm)
    3674            1 :   iam_master = (my_rank == master)
    3675              : 
    3676              :   !Initialisation of optional arguments
    3677            1 :   need_print_anharmonic = .FALSE.
    3678            1 :   if(present(print_anharmonic)) need_print_anharmonic = print_anharmonic
    3679              : 
    3680            1 :   need_prt_ph = .FALSE.
    3681            1 :   if(present(prt_ph))then
    3682            1 :      if(prt_ph==1) need_prt_ph=.TRUE.
    3683              :   endif
    3684              : 
    3685              :   !Setting/Allocating other Variables
    3686            1 :   natom = size(hist%xred,2)
    3687            1 :   factor   = 1._dp/natom
    3688            1 :   ntime = hist%mxhist
    3689            3 :   ABI_MALLOC(sqomega,(ntime))
    3690            2 :   ABI_MALLOC(ucvol,(ntime))
    3691          102 :   sqomega = zero
    3692            1 :   filename = 'TES_fit_diff'
    3693            1 :   ncoeff = eff_pot%anharmonics_terms%ncoeff
    3694              : 
    3695          102 :   do itime=1,ntime
    3696              : !  Compute \Omega^{2} and ucvol for each time
    3697          101 :    call metric(gmet,gprimd,-1,rmet,hist%rprimd(:,:,itime),ucvol(itime))
    3698              : !  Formula: sqomega(itime) = (((ucvol(itime)**(-2.))* ((natom)**(0.5)))**(-1.0/3.0))**2
    3699              : !   Compact form:
    3700          102 :    sqomega(itime) = ((ucvol(itime)**(4.0/3.0)) / ((natom)**(1/3.0)))
    3701              :   end do
    3702              : 
    3703              : 
    3704            1 :   if(need_print_anharmonic) call effective_potential_writeAnhHead(ncoeff,&
    3705            1 : &                            filename,eff_pot%anharmonics_terms)
    3706              : 
    3707              :   call fit_polynomial_coeff_computeMSD(eff_pot,hist,mse,msef,mses,natom,ntime,&
    3708              : &                                     sqomega,comm,&
    3709              : &                                     compute_anharmonic=.TRUE.,print_file=.TRUE.,filename=filename,&
    3710            1 : &                                     scup_dtset=scup_dtset,prt_ph=need_prt_ph)
    3711              : 
    3712              : 
    3713              : !  Print the standard deviation after the fit
    3714            1 :      write(message,'(6a,ES24.16,2a,ES24.16,2a,ES24.16,2a,ES24.16,a)' )ch10,&
    3715              : !&                    ' Mean Standard Deviation values of the effective-potential',ch10,&
    3716              : !&                    ' with respect to the test-set (meV^2/atm):',&
    3717              : !&               ch10,'   Energy          : ',&
    3718              : !&               mse* (Ha_EV*1000)**2 *factor ,ch10,&
    3719            1 : &                    ' Goal function values of the effective.potential',ch10,&
    3720            1 : &                    ' with respect to the test-set (eV^2/A^2):',ch10,&
    3721            1 : &                    '   Energy          : ',&
    3722            1 : &               (mse)*(HaBohr_eVAng)**2,ch10,&
    3723            1 : &                    '   Forces+Stresses : ',&
    3724            1 : &               (msef+mses)*(HaBohr_eVAng)**2,ch10,&
    3725            1 : &                    '   Forces          : ',&
    3726            1 : &               msef*(HaBohr_eVAng)**2,ch10,&
    3727            1 : &                    '   Stresses        : ',&
    3728            2 : &               mses*(HaBohr_eVAng)**2,ch10
    3729            1 :      call wrtout(ab_out,message,'COLL')
    3730            1 :      call wrtout(std_out,message,'COLL')
    3731              : 
    3732              : 
    3733              :   !Deallocating
    3734            1 :   ABI_FREE(sqomega)
    3735            1 :   ABI_FREE(ucvol)
    3736              : 
    3737            1 :   INQUIRE(FILE='TES_fit_diff_anharmonic_terms_energy.dat',OPENED=file_opened,number=unit_anh)
    3738            1 :   if(file_opened) close(unit_anh)
    3739              : 
    3740              : 
    3741            1 : end subroutine fit_polynomial_coeff_testEffPot
    3742              : !!***
    3743              : 
    3744              : 
    3745              : 
    3746              : !> Prints system files needed for external fitting scripts
    3747              : !>
    3748              : !> This routine writes:
    3749              : !> - Born effective charges
    3750              : !> - Dielectric tensor
    3751              : !> - Reference structure and energy
    3752              : !> - Harmonic force constants in XML format
    3753              : !> - Strain tensors
    3754              : !> - Symmetry operations
    3755              : !> - Molecular dynamics trajectory data
    3756              : !>
    3757              : !> The files are organized in a standard format expected by external fitting tools.
    3758              : !> Special care is taken to properly order atoms and handle supercell transformations.
    3759              : !>
    3760              : !> @param eff_pot Effective potential containing system parameters
    3761              : !> @param hist History containing MD trajectory data
    3762            0 : subroutine fit_polynomial_printSystemFiles(eff_pot,hist)
    3763              : 
    3764              :  implicit none
    3765              : 
    3766              : !Arguments ------------------------------------
    3767              : !scalars
    3768              : !arrays
    3769              :  type(effective_potential_type), intent(in) :: eff_pot
    3770              :  type(abihist),intent(in) :: hist
    3771              : !Local variables-------------------------------
    3772              : !scalar
    3773              :  integer :: ia,ib,ib1,ii,jj,irpt,kk,ll,mu,nu,nstep,nshift
    3774              :  integer :: natom_uc
    3775              :  integer :: unit_born=22,unit_epsiloninf=23,unit_md=24
    3776              :  integer :: unit_harmonic=25,unit_ref=26,unit_strain=27,unit_sym=28
    3777              : !arrays
    3778            0 :  integer,allocatable :: typat_order(:),typat_order_uc(:)
    3779              :  integer, dimension(3)  :: A,ncell
    3780            0 :  real(dp), allocatable :: xcart(:,:),fcart(:,:)
    3781              :  character(len=500) :: msg
    3782            0 :  type(supercell_type) :: supercell
    3783              : ! *************************************************************************
    3784              : 
    3785              : !Create new supercell corresponding to the MD
    3786            0 :  ncell = (/2,2,2/)
    3787              :  call supercell%init(eff_pot%crystal%natom, (/ncell(1),0,0,  0,ncell(2),0,  0,0,ncell(3)/),&
    3788              :                      eff_pot%crystal%rprimd,eff_pot%crystal%typat,&
    3789            0 :                      eff_pot%crystal%xcart,eff_pot%crystal%znucl)
    3790              : 
    3791              : !allocation of array
    3792            0 :  ABI_MALLOC(xcart,(3,supercell%natom))
    3793            0 :  ABI_MALLOC(fcart,(3,supercell%natom))
    3794            0 :  ABI_MALLOC(typat_order,(supercell%natom))
    3795            0 :  ABI_MALLOC(typat_order_uc,(eff_pot%crystal%natom))
    3796              : 
    3797            0 :  A = (/ 2, 3, 1/)
    3798              : 
    3799            0 :  nshift = product(ncell)
    3800            0 :  natom_uc = eff_pot%crystal%natom
    3801              : !Fill the typat_order array:
    3802              : !In the fit script the atom must be in the order 11111 222222 33333 ..
    3803              : !and the order of the atom can not be change in the fit script,
    3804              : !we transform into the format of the script
    3805            0 :  ib = 1
    3806            0 :  ib1= 1
    3807            0 :  do ii=1,eff_pot%crystal%ntypat
    3808            0 :    jj = A(ii)
    3809            0 :    do kk=1,natom_uc
    3810            0 :      if(supercell%typat(kk)==jj)then
    3811            0 :        typat_order_uc(ib1) = kk
    3812            0 :        ib1 = ib1 + 1
    3813            0 :        do ll=1,nshift
    3814            0 :          ia = (ll-1)*natom_uc + kk
    3815            0 :          typat_order(ib) = ia
    3816            0 :          ib = ib + 1
    3817              :        end do
    3818              :      end if
    3819              :    end do
    3820              :  end do
    3821              : 
    3822              : ! BORN CHARGES FILE
    3823            0 :  if (open_file('system/Born_Charges',msg,unit=unit_born,form="formatted",&
    3824              : &    status="replace",action="write") /= 0) then
    3825            0 :    ABI_ERROR(msg)
    3826              :  end if
    3827            0 :  do ii=1,eff_pot%crystal%ntypat
    3828            0 :    jj = A(ii)
    3829            0 :    do ia=1,eff_pot%crystal%natom
    3830            0 :      if(eff_pot%crystal%typat(ia)==jj)then
    3831            0 :        write(unit_born,'(i2,a,1F10.5)') ia,"    ",eff_pot%crystal%amu(eff_pot%crystal%typat(ia))
    3832            0 :        do mu=1,3
    3833            0 :          WRITE(unit_born,'(a,3(F23.14))') "     ",eff_pot%harmonics_terms%zeff(:,mu,ia)
    3834              :        end do
    3835              :      end if
    3836              :    end do
    3837              :  end do
    3838              : 
    3839              : !DIELECTRIC TENSOR FILE
    3840            0 :  if (open_file('system/Dielectric_Tensor',msg,unit=unit_epsiloninf,form="formatted",&
    3841              : &    status="replace",action="write") /= 0) then
    3842            0 :    ABI_ERROR(msg)
    3843              :  end if
    3844            0 :  do mu=1,3
    3845            0 :    WRITE(unit_epsiloninf,'(3(F23.14))') eff_pot%harmonics_terms%epsilon_inf(:,mu)
    3846              :  end do
    3847              : 
    3848              : 
    3849              : !REFERENCE STRUCTURE FILE
    3850            0 :  if (open_file('system/Reference_structure',msg,unit=unit_ref,form="formatted",&
    3851              : &    status="replace",action="write") /= 0) then
    3852            0 :    ABI_ERROR(msg)
    3853              :  end if
    3854              : 
    3855            0 :  write(unit_ref,'("Energy (Hartree)")')
    3856            0 :  write(unit_ref,'("================")')
    3857            0 :  write(unit_ref,'(F23.14)') (hist%etot(1)/nshift)
    3858            0 :  write(unit_ref,'("")')
    3859            0 :  write(unit_ref,'("Cell vectors")')
    3860            0 :  write(unit_ref,'("============")')
    3861            0 :  do jj=1,3
    3862            0 :    write(unit_ref,'(3(F22.14))') (supercell%rprimd(:,jj))
    3863              :  end do
    3864              : 
    3865            0 :  write(unit_ref,'("")')
    3866            0 :  write(unit_ref,'("Atomic positions (Bohr radius)")')
    3867            0 :  write(unit_ref,'("==============================")')
    3868              : 
    3869            0 :  do ia=1,supercell%natom
    3870            0 :    write(unit_ref,'(3(F23.14))') supercell%xcart(:,typat_order(ia))
    3871              :  end do
    3872              : 
    3873              : !Harmonic XML file
    3874            0 :  if (open_file('system/harmonic.xml',msg,unit=unit_harmonic,form="formatted",&
    3875              : &     status="replace",action="write") /= 0) then
    3876            0 :    ABI_ERROR(msg)
    3877              :  end if
    3878              : 
    3879              : !Write header
    3880            0 :  write(unit_harmonic,'("<?xml version=""1.0"" ?>")')
    3881            0 :  write(unit_harmonic,'("<name>")')
    3882              : 
    3883            0 :  do irpt=1,eff_pot%harmonics_terms%ifcs%nrpt
    3884            0 :    if(any(abs(eff_pot%harmonics_terms%ifcs%short_atmfrc(:,:,:,:,irpt))>tol9)) then
    3885            0 :      write(unit_harmonic,'("  <local_force_constant units=""hartree/bohrradius**2"">")')
    3886            0 :      write(unit_harmonic,'("    <data>")')
    3887            0 :      do ia=1,eff_pot%crystal%natom
    3888            0 :        do mu=1,3
    3889            0 :          do ib=1,eff_pot%crystal%natom
    3890            0 :            do  nu=1,3
    3891              :              write(unit_harmonic,'(F22.14)', advance="no")&
    3892              : &                 (eff_pot%harmonics_terms%ifcs%short_atmfrc(mu,typat_order_uc(ia),&
    3893            0 : &                                                              nu,typat_order_uc(ib),irpt))
    3894              :            end do
    3895              :          end do
    3896            0 :          write(unit_harmonic,'(a)')''
    3897              :        end do
    3898              :      end do
    3899            0 :      write(unit_harmonic,'("    </data>")')
    3900            0 :      write(unit_harmonic,'("    <cell>")')
    3901            0 :      write(unit_harmonic,'(3(I4))') (eff_pot%harmonics_terms%ifcs%cell(:,irpt))
    3902            0 :      write(unit_harmonic,'("    </cell>")')
    3903            0 :      write(unit_harmonic,'("  </local_force_constant>")')
    3904              :    end if
    3905              :  end do
    3906            0 :  write(unit_harmonic,'("</name>")')
    3907              : 
    3908              : !STRAIN FILE
    3909            0 :  if (open_file('system/Strain_Tensor',msg,unit=unit_strain,form="formatted",&
    3910              : &     status="replace",action="write") /= 0) then
    3911            0 :    ABI_ERROR(msg)
    3912              :  end if
    3913            0 :  write(unit_strain,'(6(F23.14))') (eff_pot%harmonics_terms%elastic_constants)
    3914              : 
    3915              : ! SYM FILE
    3916            0 :  if (open_file('system/symmetry_operations',msg,unit=unit_sym,form="formatted",&
    3917              : &     status="replace",action="write") /= 0) then
    3918            0 :    ABI_ERROR(msg)
    3919              :  end if
    3920              :  write(unit_sym,'("(x,y,z)  (y,-x,z) (z,x,y) (y,z,x) (x,z,y) (y,x,z) (z,y,x) (x,-y,-z) (z,-x,-y)",&
    3921              : &                " (y,-z,-x) (x,-z,-y) (y,-x,-z) (z,-y,-x) (-x,y,-z) (-z,x,-y) (-y,z,-x) (-x,z,-y)",&
    3922              : &                " (-y,x,-z) (-z,y,-x) (-x,-y,z) (-z,-x,y) (-y,-z,x) (-x,-z,y) (-y,-x,z) (-z,-y,x)",&
    3923              : &                " (-x,-y,-z) (-z,-x,-y) (-y,-z,-x) (-x,-z,-y) (-y,-x,-z) (-z,-y,-x) (-x,y,z)",&
    3924              : &                " (-z,x,y) (-y,z,x) (-x,z,y) (-y,x,z) (-z,y,x) (x,-y,z) (z,-x,y) (y,-z,x) (x,-z,y)",&
    3925            0 : &                " (z,-y,x) (x,y,-z) (z,x,-y) (y,z,-x) (x,z,-y) (y,x,-z) (z,y,-x)")')
    3926              : 
    3927              : 
    3928              : !MD file
    3929            0 :  nstep = hist%mxhist
    3930            0 :  if (open_file('system/Molecular_dynamic',msg,unit=unit_md,form="formatted",&
    3931              : &     status="replace",action="write") /= 0) then
    3932            0 :    ABI_ERROR(msg)
    3933              :  end if
    3934            0 :  do ii=1,nstep
    3935            0 :    write(unit_md,'(I5)') ii-1
    3936            0 :    write(unit_md,'(F22.14)') hist%etot(ii)/nshift
    3937            0 :    do jj=1,3
    3938            0 :      write(unit_md,'(3(F22.14))') (hist%rprimd(:,jj,ii))
    3939              :    end do
    3940              : !  Set xcart and fcart for this step
    3941              :    call xred2xcart(supercell%natom,hist%rprimd(:,:,ii),&
    3942            0 : &                  xcart,hist%xred(:,:,ii))
    3943              : 
    3944            0 :    fcart(:,:) = hist%fcart(:,:,ii)
    3945              : 
    3946            0 :    do ia=1,supercell%natom
    3947            0 :      write(unit_md,'(3(E22.14),3(E22.14))') xcart(:,typat_order(ia)),fcart(:,typat_order(ia))
    3948              :    end do
    3949            0 :    write(unit_md,'(6(E22.14))') hist%strten(:,ii)
    3950              :  end do
    3951              : 
    3952              : !Close files
    3953            0 :  close(unit_ref)
    3954            0 :  close(unit_born)
    3955            0 :  close(unit_harmonic)
    3956            0 :  close(unit_epsiloninf)
    3957            0 :  close(unit_md)
    3958            0 :  close(unit_strain)
    3959            0 :  close(unit_sym)
    3960              : 
    3961              : !Deallocation array
    3962            0 :  ABI_FREE(typat_order)
    3963            0 :  ABI_FREE(typat_order_uc)
    3964            0 :  ABI_FREE(xcart)
    3965            0 :  ABI_FREE(fcart)
    3966            0 :  call supercell%free()
    3967              : 
    3968            0 : end subroutine fit_polynomial_printSystemFiles
    3969              : 
    3970              : 
    3971              : !> Recursively generates combinations of numbers with specific conditions
    3972              : !>
    3973              : !> This routine:
    3974              : !> - Generates combinations of numbers from 1 to n_max of length m_max
    3975              : !> - Ensures each number in a combination is greater than previous one
    3976              : !> - Can either count combinations or store them based on compute flag
    3977              : !> - Uses recursive approach to build combinations
    3978              : !>
    3979              : !> @param i Current index/counter for output combinations
    3980              : !> @param m Current position in combination being built
    3981              : !> @param m_max Maximum length of combinations
    3982              : !> @param n_max Maximum number to use in combinations
    3983              : !> @param list Working array for current combination
    3984              : !> @param list_out Output array for storing combinations
    3985              : !> @param size Size of output array
    3986              : !> @param compute Whether to store combinations or just count them
    3987            0 : recursive subroutine genereList(i,m,m_max,n_max,list,list_out,size,compute)
    3988              : 
    3989              :  implicit none
    3990              : 
    3991              : !Arguments ---------------------------------------------
    3992              : !scalar
    3993              :  integer, intent(in) :: m_max,n_max,m,size
    3994              :  integer, intent(inout) :: i
    3995              :  logical,intent(in) :: compute
    3996              : !arrays
    3997              :  integer, intent(out) :: list(m_max),list_out(size,m_max)
    3998              : !Local variables ---------------------------------------
    3999              : !scalar
    4000              :  integer n
    4001              : !arrays
    4002              : 
    4003              : ! *************************************************************************
    4004            0 :  if (m > m_max) then
    4005            0 :    i = i + 1
    4006            0 :    if(compute)list_out(i,:) = list(:)
    4007              :  else
    4008            0 :    do n = 1, n_max
    4009            0 :      if (m == 1)then
    4010            0 :        list(m) = n
    4011            0 :        call genereList (i, m + 1,m_max,n_max,list,list_out,size,compute)
    4012            0 :      else if (n > list(m - 1)) then
    4013            0 :        list(m) = n
    4014            0 :        call genereList (i, m + 1,m_max,n_max,list,list_out,size,compute)
    4015              :      end if
    4016              :    end do
    4017              :  end if
    4018              : 
    4019            0 : end subroutine genereList
    4020              : !!***
    4021              : 
    4022              : !> Gathers arrays from all MPI processes with varying lengths
    4023              : !>
    4024              : !> This routine:
    4025              : !> - Gathers real values and their corresponding ordering indices
    4026              : !> - Handles arrays of different sizes from different processes
    4027              : !> - Allocates output buffers based on total gathered size
    4028              : !> - Sets up displacement arrays for MPI communication
    4029              : !> - Performs AllGatherv for both values and indices
    4030              : !>
    4031              : !> @param A Input array of values from this process
    4032              : !> @param order Input array of indices from this process
    4033              : !> @param n Size of input arrays from this process
    4034              : !> @param buff_A Output buffer for gathered values
    4035              : !> @param buff_order Output buffer for gathered indices
    4036              : !> @param totsize Total size across all processes
    4037              : !> @param comm MPI communicator
    4038              : !> @param nproc Number of MPI processes
    4039           86 : subroutine mpigatherv(A, order, n ,buff_A, buff_order, totsize, comm, nproc)
    4040              :    integer, intent(inout) :: n, totsize
    4041              :   real(dp),  intent(inout) ::  A(n)
    4042              :   integer, intent(inout):: order(n)
    4043              :   integer, intent(in) :: comm, nproc
    4044              :   real(dp), allocatable, intent(out) ::  buff_A(:)
    4045              :   integer, allocatable, intent(out) :: buff_order(:)
    4046          172 :   integer :: disps(nproc), sizes(nproc)
    4047              :   integer ::  ierr, i
    4048           86 :   totsize=n
    4049           86 :   call xmpi_sum(totsize, comm, ierr)
    4050          258 :   ABI_MALLOC(buff_A, (totsize))
    4051          258 :   ABI_MALLOC(buff_order, (totsize))
    4052           86 :   call xmpi_allgather(n, sizes, comm, ierr)
    4053           86 :   disps(1)=0
    4054          198 :   do i=2, nproc
    4055          198 :     disps(i)=disps(i-1)+sizes(i-1)
    4056              :   end do
    4057           86 :   call xmpi_allgatherv(A, n, buff_A, sizes, disps, comm, ierr  )
    4058           86 :   call xmpi_allgatherv(order, n, buff_order, sizes, disps, comm, ierr  )
    4059           86 : end subroutine mpigatherv
    4060              : 
    4061              : 
    4062              : 
    4063              : end module m_fit_polynomial_coeff
    4064              : !!***
        

Generated by: LCOV version 2.3-1