Line data Source code
1 :
2 : !!****m* ABINIT/m_opt_effpot
3 : !!
4 : !! NAME
5 : !! m_opt_effpot
6 : !!
7 : !! FUNCTION
8 : !!
9 : !!
10 : !!
11 : !! COPYRIGHT
12 : !! Copyright (C) 2010-2026 ABINIT group (AM)
13 : !! This file is distributed under the terms of the
14 : !! GNU General Public Licence, see ~abinit/COPYING
15 : !! or http://www.gnu.org/copyleft/gpl.txt .
16 : !! For the initials of contributors, see ~abinit/doc/developers/contributors.txt .
17 : !!
18 : !! SOURCE
19 :
20 :
21 :
22 : #if defined HAVE_CONFIG_H
23 : #include "config.h"
24 : #endif
25 :
26 : #include "abi_common.h"
27 : !#include "trace.h"
28 :
29 :
30 : module m_opt_effpot
31 :
32 : use defs_basis
33 : use defs_datatypes
34 : use defs_abitypes
35 : use m_errors
36 : use m_abicore
37 : use m_xmpi
38 : use m_effective_potential
39 : use m_effective_potential_file, only : effective_potential_file_mapHistToRef
40 : use m_fit_data
41 : use m_fit_polynomial_coeff
42 : use m_polynomial_coeff
43 : use m_polynomial_term
44 : use m_crystal,only : symbols_crystal
45 :
46 : implicit none
47 :
48 : public :: opt_effpot
49 : public :: opt_effpotbound
50 : public :: opt_getHOforterm
51 : public :: opt_getCombisforterm
52 : public :: opt_getHoTerms
53 : public :: opt_getHOstrain
54 : public :: opt_getHOcrossdisp
55 : public :: opt_filterdisp
56 : public :: opt_getSingleDispTerms
57 : public :: opt_getHOSingleDispTerms
58 : private :: opt_boundcoeff
59 : private :: check_to_skip
60 : !!****
61 : CONTAINS
62 :
63 : !!****f* m_opt_effpot/opt_effpot
64 : !!
65 : !! NAME
66 : !! opt_effpot
67 : !!
68 : !! FUNCTION
69 : !! Optimize Effective Potential by fitting the value of certain
70 : !! coefficients while keeping the values of the others
71 : !!
72 : !! INPUTS
73 : !! eff_pot<type(effective_potential)> = effective potential
74 : !!
75 : !! opt_coeff(opt_ncoeff) = list of terms whose coefficients are to be
76 : !! optimized
77 : !!
78 : !! hist<type(abihist)> = Training set Data(or snapshot of DFT)
79 : !! comm = MPI communicator
80 : !!
81 : !! OUTPUT
82 : !! eff_pot<type(effective_potential)> = effective potential datatype with new fitted coefficients
83 : !!
84 : !! SOURCE
85 :
86 1 : subroutine opt_effpot(eff_pot,opt_ncoeff,opt_coeff,hist,opt_on,opt_factors,comm, fit_weight_T, print_anh)
87 :
88 : !Arguments ------------------------------------
89 : !scalars
90 : integer,intent(in) :: comm,opt_ncoeff
91 : type(effective_potential_type),intent(inout) :: eff_pot
92 : type(abihist),intent(inout) :: hist
93 : !arrays
94 : integer,intent(in) :: opt_coeff(opt_ncoeff)
95 : real(dp),intent(in) :: opt_factors(3)
96 : real(dp), intent(in):: fit_weight_T
97 : !Logicals
98 : logical,intent(in) :: opt_on(3)
99 : logical,optional,intent(in) :: print_anh
100 : !Strings
101 : !Local variables ------------------------------
102 : !scalars
103 : integer :: ii, info,natom_sc,ntime,unit_anh1,unit_anh2
104 : integer :: master,nproc,my_rank
105 : real(dp) :: factor,mse,msef,mses
106 : real(dp),parameter :: HaBohr_eVAng = Ha_eV /Bohr_Ang
107 : !arrays
108 : integer :: sc_size(3)
109 2 : integer :: coeff_inds(opt_ncoeff)
110 1 : type(fit_data_type) :: fit_data
111 11 : type(polynomial_coeff_type) :: my_coeffs(opt_ncoeff)
112 2 : real(dp) :: coeff_values(opt_ncoeff), coeff_init_values(opt_ncoeff)
113 1 : real(dp), allocatable :: energy_coeffs(:,:),fcart_coeffs(:,:,:,:)
114 1 : real(dp), allocatable :: strten_coeffs(:,:,:)
115 1 : real(dp), allocatable :: my_weights(:)
116 : !Logicals
117 : logical :: need_print_anh,file_opened,iam_master
118 : !Strings
119 : character(len=1000) :: message
120 : character(len=1000) :: frmt
121 : character(len=fnlen) :: fn_bf='before_opt_diff', fn_af='after_opt_diff'
122 : ! *************************************************************************
123 : !MPI
124 1 : master = 0
125 1 : nproc = xmpi_comm_size(comm); my_rank = xmpi_comm_rank(comm)
126 : iam_master = (my_rank == master)
127 :
128 : !Setting/Initializing Variables
129 1 : ntime = hist%mxhist
130 1 : natom_sc = size(hist%xred,2)
131 1 : factor = 1._dp/natom_sc
132 1 : need_print_anh =.False.
133 :
134 1 : call get_weight_from_hist(hist, fit_weight_T, ntime, natom_sc, my_weights, comm)
135 :
136 :
137 1 : if(present(print_anh)) then
138 1 : if(print_anh) need_print_anh=.True.
139 : end if
140 : !if the number of atoms in reference supercell into effpot is not correct,
141 : !wrt to the number of atom in the hist, we set map the hist and set the good supercell
142 1 : if (natom_sc /= eff_pot%supercell%natom) then
143 0 : call effective_potential_file_mapHistToRef(eff_pot,hist,comm,verbose=.TRUE.)
144 : end if
145 :
146 : !we get the size of the supercell in the hist file
147 : ! This is only valid for diagonal sc_size.
148 : ! F08: sc_size(:) = int(anint( norm2(eff_pot%supercell%rprimd, dim=2) / &
149 : ! & norm2(eff_pot%crystal%rprimd, dim=2) ))
150 4 : do ii=1,3
151 : sc_size(ii) = int(anint(sqrt(eff_pot%supercell%rprimd(ii,1)**2+&
152 : & eff_pot%supercell%rprimd(ii,2)**2+&
153 : & eff_pot%supercell%rprimd(ii,3)**2) / &
154 : & sqrt(eff_pot%crystal%rprimd(ii,1)**2+&
155 : & eff_pot%crystal%rprimd(ii,2)**2+&
156 4 : & eff_pot%crystal%rprimd(ii,3)**2)))
157 : end do
158 :
159 :
160 : !Before the fit, compute constants with fit_data_compute.
161 : !Compute the strain of each configuration.
162 : !Compute the displacmeent of each configuration.
163 : !Compute the variation of the displacement due to strain of each configuration.
164 : !Compute fixed forces and stresse and get the standard deviation.
165 : !Compute Sheppard and al Factors \Omega^{2} see J.Chem Phys 136, 074103 (2012) [[cite:Sheppard2012]].
166 1 : call fit_data_compute(fit_data,eff_pot,hist,comm,verbose=.FALSE.)
167 :
168 :
169 1 : if(need_print_anh) call effective_potential_writeAnhHead(eff_pot%anharmonics_terms%ncoeff,&
170 0 : & fn_bf,eff_pot%anharmonics_terms)
171 :
172 : !Before deleting coefficients calculate MSD of initial model
173 : call fit_polynomial_coeff_computeMSD(eff_pot,hist,mse,msef,mses,&
174 : & natom_sc,ntime,fit_data%training_set%sqomega,comm,&
175 1 : & compute_anharmonic=.TRUE.,print_file=.TRUE.,filename=fn_bf)
176 :
177 :
178 : ! Print the standard devition of initial model
179 1 : write(message,'(6a,ES24.16,6a,ES24.16,2a,ES24.16,2a,ES24.16,a)' )ch10,&
180 1 : & ' Mean Standard Deviation values of the effective-potential',ch10,&
181 1 : & ' with respect to the training-set before optimization (meV^2/atm):',&
182 1 : & ch10,' Energy : ',&
183 1 : & mse* (Ha_EV*1000)**2 *factor ,ch10,&
184 1 : & ' Goal function values of the effective.potential',ch10,&
185 1 : & ' with respect to the test-set (eV^2/A^2):',ch10,&
186 1 : & ' Forces+Stresses : ',&
187 1 : & (msef+mses)*(HaBohr_eVAng)**2,ch10,&
188 1 : & ' Forces : ',&
189 1 : & msef*(HaBohr_eVAng)**2,ch10,&
190 1 : & ' Stresses : ',&
191 2 : & mses*(HaBohr_eVAng)**2,ch10
192 1 : call wrtout(ab_out,message,'COLL')
193 1 : call wrtout(std_out,message,'COLL')
194 :
195 :
196 : ! Write terms to my_coeffs(ii) and zero them in eff_pot
197 3 : do ii=1,opt_ncoeff
198 : !Store indices for later
199 2 : coeff_inds(ii) = ii
200 : !Initialize coefficients for optimizing
201 : call polynomial_coeff_init(coeff_values(ii),eff_pot%anharmonics_terms%coefficients(opt_coeff(ii))%nterm,&
202 : & my_coeffs(ii), eff_pot%anharmonics_terms%coefficients(opt_coeff(ii))%terms, &
203 2 : & check=.TRUE.)
204 :
205 : !DMSG(my_coeffs(ii)%debug_str)
206 :
207 : !Store initial values of coefficients
208 2 : coeff_init_values(ii) = eff_pot%anharmonics_terms%coefficients(opt_coeff(ii))%coefficient
209 : !Put them temporarely to zero
210 3 : eff_pot%anharmonics_terms%coefficients(opt_coeff(ii))%coefficient = zero
211 : end do
212 :
213 : !Before the fit, compute constants with fit_data_compute.
214 : !And coefficients to be optimized put to zero
215 : !Conpute the strain of each configuration.
216 : !Compute the displacmeent of each configuration.
217 : !Compute the variation of the displacement due to strain of each configuration.
218 : !Compute fixed forces and stresse and get the standard deviation.
219 : !Compute Sheppard and al Factors \Omega^{2} see J.Chem Phys 136, 074103 (2012) [[cite:Sheppard2012]].
220 1 : call fit_data_compute(fit_data,eff_pot,hist,comm,verbose=.TRUE.)
221 :
222 : !After deleting coefficients calculate MSD
223 : call fit_polynomial_coeff_computeMSD(eff_pot,hist,mse,msef,mses,&
224 : & natom_sc,ntime,fit_data%training_set%sqomega,comm,&
225 1 : & compute_anharmonic=.TRUE.)
226 :
227 :
228 : ! Print the standard deviation after deleting
229 1 : write(message,'(6a,ES24.16,6a,ES24.16,2a,ES24.16,2a,ES24.16,a)' )ch10,&
230 1 : & ' Mean Standard Deviation values of the effective-potential',ch10,&
231 1 : & ' with respect to the training-set after deleting selected terms (meV^2/atm):',&
232 1 : & ch10,' Energy : ',&
233 1 : & mse* (Ha_EV*1000)**2 *factor ,ch10,&
234 1 : & ' Goal function values of the effective.potential',ch10,&
235 1 : & ' with respect to the test-set (eV^2/A^2):',ch10,&
236 1 : & ' Forces+Stresses : ',&
237 1 : & (msef+mses)*(HaBohr_eVAng)**2,ch10,&
238 1 : & ' Forces : ',&
239 1 : & msef*(HaBohr_eVAng)**2,ch10,&
240 1 : & ' Stresses : ',&
241 2 : & mses*(HaBohr_eVAng)**2,ch10
242 1 : call wrtout(ab_out,message,'COLL')
243 1 : call wrtout(std_out,message,'COLL')
244 :
245 :
246 :
247 : ! Allocate necessary arrays for the fit-data
248 4 : ABI_MALLOC(energy_coeffs,(opt_ncoeff,ntime))
249 5 : ABI_MALLOC(fcart_coeffs,(3,natom_sc,opt_ncoeff,ntime))
250 4 : ABI_MALLOC(strten_coeffs,(6,ntime,opt_ncoeff))
251 : ! Calculate forces and stresses per coefficient, which are to be optimized
252 : call fit_polynomial_coeff_getFS(my_coeffs,fit_data%training_set%du_delta,&
253 : & fit_data%training_set%displacement,&
254 : & energy_coeffs,fcart_coeffs,natom_sc,eff_pot%crystal%natom,&
255 : & opt_ncoeff,ntime,sc_size,fit_data%training_set%strain,&
256 1 : & strten_coeffs,fit_data%training_set%ucvol,coeff_inds,opt_ncoeff)
257 :
258 :
259 : ! call the fit process routine
260 : ! This routine solves the linear system proposed
261 : ! by C.Escorihuela-Sayalero see PRB95,094115(2017) [[cite:Escorihuela-Sayalero2017]]
262 : call fit_polynomial_coeff_solve(coeff_values(1:opt_ncoeff),fcart_coeffs,fit_data%fcart_diff,&
263 : & energy_coeffs,fit_data%energy_diff,info,&
264 : & coeff_inds,natom_sc,opt_ncoeff,opt_ncoeff,ntime,&
265 : & strten_coeffs,fit_data%strten_diff,&
266 : & fit_data%training_set%sqomega,opt_on,opt_factors, &
267 1 : & weights=my_weights)
268 1 : if (info /= 0 .and. all(coeff_values < tol16))then
269 0 : write(frmt,*) opt_ncoeff
270 0 : write(message, '(2a,'//ADJUSTR(frmt)//'I4,8a)' ) ch10,&
271 0 : & ' The attempt to optimize the terms: ', opt_coeff ,ch10,&
272 0 : & ' , returned a singular solution', ch10,&
273 0 : & ' The terms could not be optimized ',ch10,&
274 0 : & ' and the effective potential has not been altered.', ch10,&
275 0 : & ' Action: Change training set or coefficients to be optimized.'
276 0 : ABI_WARNING(message)
277 0 : do ii=1,opt_ncoeff
278 0 : eff_pot%anharmonics_terms%coefficients(opt_coeff(ii))%coefficient = coeff_init_values(ii)
279 0 : call polynomial_coeff_free(my_coeffs(ii))
280 : end do
281 : else
282 : ! Transfer new fitted values to coefficients and write them into effective potential
283 : ! Deallcoate temporary coefficients my_coeffs
284 3 : do ii=1,opt_ncoeff
285 2 : eff_pot%anharmonics_terms%coefficients(opt_coeff(ii))%coefficient = coeff_values(ii)
286 3 : call polynomial_coeff_free(my_coeffs(ii))
287 : end do
288 : !Recalculate MSD of Final Model
289 :
290 : !Conpute the strain of each configuration.
291 : !Compute the displacmeent of each configuration.
292 : !Compute the variation of the displacement due to strain of each configuration.
293 : !Compute fixed forces and stresse and get the standard deviation.
294 : !Compute Sheppard and al Factors \Omega^{2} see J.Chem Phys 136, 074103 (2012) [[cite:Sheppard2012]].
295 1 : call fit_data_compute(fit_data,eff_pot,hist,comm,verbose=.TRUE.)
296 :
297 :
298 1 : if(need_print_anh) call effective_potential_writeAnhHead(eff_pot%anharmonics_terms%ncoeff,&
299 0 : & fn_af,eff_pot%anharmonics_terms)
300 :
301 : !After optimization of coefficients opt_coeff recalculate MSD
302 : call fit_polynomial_coeff_computeMSD(eff_pot,hist,mse,msef,mses,&
303 : & natom_sc,ntime,fit_data%training_set%sqomega,comm,&
304 1 : & compute_anharmonic=.TRUE.,print_file=.TRUE.,filename=fn_af)
305 :
306 :
307 : ! Print the standard deviation after optimization
308 1 : write(message,'(6a,ES24.16,6a,ES24.16,2a,ES24.16,2a,ES24.16,a)' )ch10,&
309 1 : & ' Mean Standard Deviation values of the effective-potential',ch10,&
310 1 : & ' with respect to the training-set after optimizing selected terms (meV^2/atm):',&
311 1 : & ch10,' Energy : ',&
312 1 : & mse* (Ha_EV*1000)**2 *factor ,ch10,&
313 1 : & ' Goal function values of the effective.potential',ch10,&
314 1 : & ' with respect to the test-set (eV^2/A^2):',ch10,&
315 1 : & ' Forces+Stresses : ',&
316 1 : & (msef+mses)*(HaBohr_eVAng)**2,ch10,&
317 1 : & ' Forces : ',&
318 1 : & msef*(HaBohr_eVAng)**2,ch10,&
319 1 : & ' Stresses : ',&
320 2 : & mses*(HaBohr_eVAng)**2,ch10
321 1 : call wrtout(ab_out,message,'COLL')
322 1 : call wrtout(std_out,message,'COLL')
323 : end if
324 :
325 : !Deallocation of fitting variables
326 1 : ABI_SFREE(energy_coeffs)
327 1 : ABI_SFREE(fcart_coeffs)
328 1 : ABI_SFREE(strten_coeffs)
329 1 : ABI_SFREE(my_weights)
330 :
331 1 : if(need_print_anh)then
332 0 : INQUIRE(FILE='before_opt_diff_anharmonic_terms_energy.dat',OPENED=file_opened,number=unit_anh1)
333 0 : if(file_opened) close(unit_anh1)
334 0 : INQUIRE(FILE='after_opt_diff_anharmonic_terms_energy.dat',OPENED=file_opened,number=unit_anh2)
335 0 : if(file_opened) close(unit_anh2)
336 : end if
337 : ! Deallocate and delete the fit-date
338 1 : call fit_data_free(fit_data)
339 7 : end subroutine opt_effpot
340 : !!***
341 :
342 : !!****f* m_opt_effpot/opt_effpotbound
343 : !!
344 : !! NAME
345 : !! opt_effpotbound
346 : !!
347 : !! FUNCTION
348 : !! Compute and add high order terms to existing odd or negative even anharmonic terms
349 : !! Fix the coefficient of the added new high order terms to a value such that it
350 : !! doesn't influence the precision of the existing anharmonic potential with respect
351 : !! to a relevent training set (ATTENTIION: A user must know what a relevant training set
352 : !! is for the system he want's to study. Typically something oscillating around its ground-state.)
353 : !! Finally optimize the coefficients of the orignal anharmonic terms under the presence of the
354 : !! added high order terms.
355 : !!
356 : !! INPUTS
357 : !! eff_pot: existing effective potential
358 : !! order: order for which bounding terms are generated
359 : !! order_ran: ?
360 : !! bound_EFS:
361 : !! bound_factors:
362 : !! bound_penalty:
363 : !! comm: MPI communicator
364 : !! fit_weight_T: ?
365 : !! print_anh: ?
366 : !! bound_option: 1 or 2. Whether the bounding term should be the same nbody with the term to be bounded. 1. Yes (default), 2. No
367 : !!
368 : !!
369 : !! OUTPUT
370 : !! eff_pot new effective potential
371 : !!
372 : !!
373 : !! SOURCE
374 :
375 1 : subroutine opt_effpotbound(eff_pot,order_ran,hist,bound_EFS,bound_factors,bound_penalty,comm, fit_weight_T,bound_option, print_anh)
376 :
377 : !Arguments ------------------------------------
378 : !scalars
379 : integer,intent(in) :: comm
380 : type(effective_potential_type),target,intent(inout) :: eff_pot
381 : type(abihist),intent(inout) :: hist
382 : real(dp) :: bound_penalty
383 : !arrays
384 : integer,intent(in) :: order_ran(2),bound_EFS(3)
385 : integer, intent(in) :: bound_option
386 : real(dp),intent(in) :: bound_factors(3)
387 : real(dp), intent(in) :: fit_weight_T
388 : !Logicals
389 : logical,optional,intent(in) :: print_anh
390 : !Strings
391 : !Local variables ------------------------------
392 : !scalars
393 : integer :: i,ii,natom_sc,ntime,iterm,nterm, icombi3, nbody_term
394 : integer :: jterm, ncombi,ncombi1,ncombi2, ncombi1_real, ncombi2_real
395 : integer :: icombi
396 : integer :: nterm_start,nterm2
397 : integer :: nproc,my_rank,master
398 : !1406
399 : real(dp) :: factor,mse_ini,msef_ini,mses_ini,mse,msef,mses
400 : real(dp) :: coeff_tmp
401 : real(dp),parameter :: HaBohr_eVAng = Ha_eV /Bohr_Ang
402 : !arrays
403 : integer :: sc_size(3),temp_cntr
404 1 : integer,allocatable :: terms(:)
405 1 : logical,allocatable :: exists(:)
406 : logical :: any_exists
407 1 : type(fit_data_type) :: fit_data
408 : real(dp) :: GF_arr(2),coeff_opt(2)
409 1 : real(dp), allocatable :: my_weights(:)
410 : !real(dp), allocatable :: energy_coeffs(:,:),fcart_coeffs(:,:,:,:)
411 : !real(dp), allocatable :: strten_coeffs(:,:,:)
412 : !1406 strain_temrs_tmp
413 1 : type(polynomial_coeff_type),target,allocatable :: my_coeffs(:),my_coeffs_tmp(:)
414 1 : type(polynomial_coeff_type),allocatable :: singledisp_terms(:),HOsingledisp_terms(:)
415 1 : type(polynomial_coeff_type),allocatable :: HOcrossdisp_terms(:)
416 : !Logicals
417 : logical :: need_print_anh ! MARCUS FOR THE MOMENT PRINT NO FILES
418 : logical :: to_skip,iam_master
419 : !Strings
420 : character(len=5),allocatable :: symbols(:)
421 : character(len=200):: name
422 : character(len=1000) :: message
423 : character(len=fnlen) :: fn_bf='before_opt_diff'!, fn_af='after_opt_diff'
424 : ! types
425 1 : type(SymPairs_t) :: sympairs
426 : !*************************************************************************
427 : !MPI variables
428 1 : master = 0
429 1 : nproc = xmpi_comm_size(comm); my_rank = xmpi_comm_rank(comm)
430 : iam_master = (my_rank == master)
431 :
432 : ! Say hello to the world!
433 1 : write(message, '(3a)' )'-Start Bound optimization of Anharmonic Potential ',ch10
434 1 : call wrtout(ab_out,message,'COLL')
435 1 : call wrtout(std_out,message,'COLL')
436 :
437 : !Setting/Initializing Variables
438 1 : ntime = hist%mxhist
439 :
440 :
441 1 : natom_sc = size(hist%xred,2)
442 1 : factor = 1._dp/natom_sc
443 1 : nterm =eff_pot%anharmonics_terms%ncoeff
444 1 : need_print_anh=.False.
445 1 : if(present(print_anh))then
446 0 : if(print_anh) need_print_anh = .True.
447 : endif
448 1 : call get_weight_from_hist(hist, fit_weight_T, ntime, natom_sc, my_weights, comm )
449 :
450 3 : ABI_MALLOC(symbols,(eff_pot%crystal%natom))
451 3 : ABI_MALLOC(terms,(nterm))
452 : call symbols_crystal(eff_pot%crystal%natom,eff_pot%crystal%ntypat,eff_pot%crystal%npsp,&
453 1 : & symbols,eff_pot%crystal%typat,eff_pot%crystal%znucl)
454 :
455 :
456 : !if the number of atoms in reference supercell into effpot is not correct,
457 : !wrt to the number of atom in the hist, we set map the hist and set the good supercell
458 1 : if (natom_sc /= eff_pot%supercell%natom) then
459 0 : call effective_potential_file_mapHistToRef(eff_pot,hist,comm,verbose=.TRUE.)
460 : end if
461 :
462 : !Check if input of order is correct
463 : ! TODO write error message here
464 3 : if (any(mod(order_ran,2) /= 0)) return
465 :
466 : !we get the size of the supercell in the hist file
467 4 : do ii=1,3
468 : sc_size(ii) = int(anint(sqrt(eff_pot%supercell%rprimd(ii,1)**2+&
469 : & eff_pot%supercell%rprimd(ii,2)**2+&
470 : & eff_pot%supercell%rprimd(ii,3)**2) / &
471 : & sqrt(eff_pot%crystal%rprimd(ii,1)**2+&
472 : & eff_pot%crystal%rprimd(ii,2)**2+&
473 4 : & eff_pot%crystal%rprimd(ii,3)**2)))
474 : end do
475 :
476 :
477 : !Before the fit, compute constants with fit_data_compute.
478 : !Conpute the strain of each configuration.
479 : !Compute the displacmeent of each configuration.
480 : !Compute the variation of the displacement due to strain of each configuration.
481 : !Compute fixed forces and stresse and get the standard deviation.
482 : !Compute Sheppard and al Factors \Omega^{2} see J.Chem Phys 136, 074103 (2012) [[cite:Sheppard2012]].
483 : !call fit_data_compute(fit_data,eff_pot,hist,comm,verbose=.FALSE.)
484 1 : call fit_data_compute(fit_data,eff_pot,hist,comm,verbose=.FALSE.)
485 :
486 1 : if(need_print_anh) call effective_potential_writeAnhHead(eff_pot%anharmonics_terms%ncoeff,&
487 0 : & fn_bf,eff_pot%anharmonics_terms)
488 :
489 : !Before adding bound coefficients calculate MSD of initial model
490 : !MS FOR THE MOMENT PRINT NO FILE
491 : call fit_polynomial_coeff_computeMSD(eff_pot,hist,mse_ini,msef_ini,mses_ini,&
492 : & natom_sc,ntime,fit_data%training_set%sqomega,comm,&
493 1 : & compute_anharmonic=.TRUE.,print_file=.FALSE.)
494 :
495 :
496 : ! Print the standard devition of initial model
497 1 : write(message,'(6a,ES24.16,6a,ES24.16,2a,ES24.16,2a,ES24.16,a)' )ch10,&
498 1 : & ' Mean Standard Deviation values of the effective-potential',ch10,&
499 1 : & ' with respect to the training-set before attempted bounding (meV^2/atm):',&
500 1 : & ch10,' Energy : ',&
501 1 : & mse_ini* (Ha_EV*1000)**2 *factor ,ch10,&
502 1 : & ' Goal function values of the effective.potential',ch10,&
503 1 : & ' with respect to the test-set (eV^2/A^2):',ch10,&
504 1 : & ' Forces+Stresses : ',&
505 1 : & (msef_ini+mses_ini)*(HaBohr_eVAng)**2,ch10,&
506 1 : & ' Forces : ',&
507 1 : & msef_ini*(HaBohr_eVAng)**2,ch10,&
508 1 : & ' Stresses : ',&
509 2 : & mses_ini*(HaBohr_eVAng)**2,ch10
510 1 : call wrtout(ab_out,message,'COLL')
511 1 : call wrtout(std_out,message,'COLL')
512 :
513 : !MS DEV
514 : ! single displacement terms with second order only.
515 1 : call opt_getSingleDispTerms(singledisp_terms,eff_pot%crystal, sc_size,comm)
516 :
517 :
518 : ! create pair list:
519 1 : call sympairs%init(eff_pot%crystal, sc_size)
520 :
521 : !For the moment order loop commented
522 : !do iorder=order(1),order(2),2, Order will be done per term
523 : !Loop over all original terms + 1
524 : ! + 1 to bound pure strain
525 3 : do iterm =1,nterm +1
526 2 : if(iterm <=nterm)then
527 1 : ncombi1=0
528 1 : ncombi2=0
529 1 : ncombi1_real=0
530 1 : ncombi2_real=0
531 : !Store for optimization
532 1 : terms(iterm) = iterm
533 : !Message: The world wants to know where we stand Batman
534 1 : write(message, '(a,(80a),a)' ) ch10,&
535 81 : & ('_',ii=1,80),ch10
536 1 : call wrtout(ab_out,message,'COLL')
537 1 : call wrtout(std_out,message,'COLL')
538 1 : write(message,'(2a,I3,a,I3,3a)' )ch10,&
539 2 : & ' Check term (',iterm,'/',nterm,'): ', trim(eff_pot%anharmonics_terms%coefficients(iterm)%name),ch10
540 1 : call wrtout(ab_out,message,'COLL')
541 1 : call wrtout(std_out,message,'COLL')
542 1 : to_skip = .FALSE.
543 1 : to_skip = check_to_skip(eff_pot%anharmonics_terms%coefficients(iterm))
544 : !Skip term if it doesn't need bounding
545 1 : if(.not. to_skip)then
546 : associate(term1=>eff_pot%anharmonics_terms%coefficients(iterm)%terms(1))
547 1 : nbody_term = term1%get_nbody()
548 :
549 : !Get List of high order single Terms for terms
550 : call opt_getHOSingleDispTerms(eff_pot%anharmonics_terms%coefficients(iterm),&
551 1 : & HOsingledisp_terms,symbols,singledisp_terms,order_ran,ncombi1)
552 :
553 4 : ABI_MALLOC(my_coeffs,(size(eff_pot%anharmonics_terms%coefficients)))
554 1 : my_coeffs=eff_pot%anharmonics_terms%coefficients
555 1 : do icombi3=1, size(my_coeffs)
556 : !DMSG(my_coeffs(icombi3)%debug_str)
557 : end do
558 :
559 : ! then add the single disp terms.
560 1 : if (ncombi1>0) then
561 3 : do icombi3=1,ncombi1
562 3 : if (HOsingledisp_terms(icombi3)%terms(1)%get_nbody() == nbody_term .or. bound_option/=1) then
563 0 : call coeffs_list_append(my_coeffs,HOsingledisp_terms(icombi3), check=.TRUE.)
564 : !DMSG(my_coeffs(icombi3)%debug_str)
565 0 : ncombi1_real = ncombi1_real + 1
566 : endif
567 : end do
568 : endif
569 :
570 1 : if(allocated(HOsingledisp_terms)) call polynomial_coeff_list_free(HOsingledisp_terms)
571 :
572 :
573 : !Get List of high order cross Terms for term if ndisp > 1
574 1 : if(term1%ndisp>1 .or. &
575 : & term1%ndisp /= 0 .and. & ! why >1 or /=0?
576 : & term1%nstrain /= 0)then
577 : ! output HOcrossdisp_terms, ncombi2.
578 1 : call opt_getHOcrossdisp(HOcrossdisp_terms,ncombi2,eff_pot%anharmonics_terms%coefficients(iterm),order_ran)
579 : endif
580 : ! then add the crossdisp terms.
581 1 : if(ncombi2 > 0)then
582 4 : do icombi3=1,ncombi2
583 : !call coeffs_list_conc_onsite(my_coeffs, HOcrossdisp_terms(icombi3))
584 4 : if (HOcrossdisp_terms(icombi3)%terms(1)%get_nbody() == nbody_term .or. bound_option/=1) then
585 1 : call coeffs_list_append(my_coeffs,HOcrossdisp_terms(icombi3), check=.TRUE.)
586 1 : ncombi2_real = ncombi2_real + 1
587 : !DMSG(my_coeffs(ncombi2_real)%debug_str)
588 : endif
589 : end do
590 : endif
591 2 : if(allocated(HOcrossdisp_terms)) call polynomial_coeff_list_free(HOcrossdisp_terms)
592 : end associate
593 : else ! to_skip
594 : ncombi2=0
595 : ncombi1=0
596 0 : ABI_MALLOC(my_coeffs,(size(eff_pot%anharmonics_terms%coefficients)))
597 0 : my_coeffs = eff_pot%anharmonics_terms%coefficients
598 : endif
599 1 : ncombi = ncombi1_real + ncombi2_real
600 1 : nterm_start = eff_pot%anharmonics_terms%ncoeff
601 : else ! if iterm = nterm + 1 => Take care about strain
602 : block
603 1 : integer :: max_nbody_tmp(order_ran(2))
604 1 : if (bound_option==1) then
605 7 : max_nbody_tmp(:) = 1
606 : else
607 0 : max_nbody_tmp(:) = 888
608 : endif
609 1 : call opt_getHOstrain(my_coeffs,ncombi,nterm_start,eff_pot,order_ran,comm, max_nbody=max_nbody_tmp)
610 : end block
611 : endif !
612 :
613 :
614 : ! Modification of Alireza.
615 : !---------------------------------------------
616 : !Here my_coeffs contains the previous coeff and the new bounding ones. wight is allways +1 so the power in SAT generation does not matter!!
617 :
618 : ! 1. We need to use generateTermsFromList module to create terms.
619 : ! 2. The generateTermsFromList module accepts list combinations of terms: (\1,1,1,1,7,7\)
620 : ! 3. We need to convert the terms from bounding process to a list like (\1,1,1,1,7,7\)
621 : ! 4. use polynomial_coeff_getList to get pairs.
622 : ! 5. compare th list and the terms and find out what is the number of diplacement in list for a term.
623 : ! 6. convert term to list.
624 : ! 7. ask for the temrs from generateTermsFromList
625 : ! 8. check and see if the coeff is already considered or not. use coeffs_compare function
626 : !! strain the same thing should be done for the strain
627 : !! find the list of all the list_str,
628 : !! fond what is number of strain in the displacemt comapring it to
629 : !! the list_str and give this to
630 : ! get coeff from > generateTermsFromList(list_disp,****)
631 : ! setcoeff_to_tmp_coeffs
632 : ! generateTermsFromList(cell,index_coeff,list_coeff,list_str,ncoeff,ndisp_max,nrpt,nstr,nsym,nterm,terms)
633 :
634 : ! call the new function to get the data required to call polynomial_coeff_getList
635 :
636 :
637 2 : call generate_bounding_term_and_add_to_list( sympairs, nterm_start, ncombi, my_coeffs, temp_cntr)
638 :
639 :
640 :
641 2 : if (temp_cntr>0) then
642 5 : do icombi=1,temp_cntr
643 : ! Copy all the terms in eff pot
644 : call polynomial_coeff_getName(name, &
645 3 : & my_coeffs(nterm_start+icombi),symbols,recompute=.TRUE.)
646 3 : call polynomial_coeff_SetName(name,my_coeffs(nterm_start+icombi))
647 :
648 : ! Set dimensions of temporary my_coeffs array
649 3 : nterm2 = eff_pot%anharmonics_terms%ncoeff + 1
650 18 : ABI_MALLOC(my_coeffs_tmp,(nterm2))
651 : ! Copy terms of previous cycle
652 3 : my_coeffs_tmp(1:nterm2-1) = eff_pot%anharmonics_terms%coefficients
653 : !Put new term to my_coeffs_tmp
654 33 : my_coeffs_tmp(nterm2) = my_coeffs(nterm_start+icombi)
655 :
656 :
657 : !call polynomial_coeff_init(my_coeffs(nterm_start+icombi)%coefficient, &
658 : ! & my_coeffs(nterm_start+icombi)%nterm, &
659 : ! & my_coeffs_tmp(nterm2),my_coeffs(nterm_start+icombi)%terms, &
660 : ! &my_coeffs(nterm_start+icombi)%name)
661 :
662 : ! DMSG(my_coeffs_tmp(nterm2)%debug_str)
663 :
664 : ! If order is greater than specified cycle
665 14 : if(sum(my_coeffs_tmp(nterm2)%terms(1)%power_disp) &
666 : & +sum(my_coeffs_tmp(nterm2)%terms(1)%power_strain) > maxval(order_ran))then
667 0 : call polynomial_coeff_list_free(my_coeffs_tmp)
668 0 : cycle
669 : endif
670 : ! Message to Output
671 3 : write(message,'(5a)' )ch10,&
672 6 : & ' ==> high order term: ', trim(my_coeffs_tmp(nterm2)%name),' created',ch10
673 3 : call wrtout(ab_out,message,'COLL')
674 3 : call wrtout(std_out,message,'COLL')
675 : ! Check if generated term is not already contained in effpot
676 : ! If yes cycle
677 9 : ABI_MALLOC(exists, (nterm2))
678 12 : exists=.FALSE.
679 9 : do jterm=1,nterm2-1
680 9 : exists(jterm) = coeffs_compare(my_coeffs_tmp(jterm),my_coeffs_tmp(nterm2))
681 : enddo !jterm
682 12 : any_exists=any(exists)
683 3 : ABI_SFREE(exists)
684 3 : if(any_exists)then
685 0 : write(message,'(3a)' )ch10,&
686 0 : & ' ==> Term exists already. We cycle',ch10
687 0 : call wrtout(ab_out,message,'COLL')
688 0 : call wrtout(std_out,message,'COLL')
689 0 : call polynomial_coeff_list_free(my_coeffs_tmp)
690 0 : cycle
691 : endif
692 :
693 :
694 : ! Set new term into effective potential
695 3 : call effective_potential_setCoeffs(my_coeffs_tmp,eff_pot,nterm2)
696 :
697 : ! Tell the world what we do, They want to know.
698 3 : write(message,'(3a)' )ch10,&
699 6 : & ' ==> Optimizing coefficient',ch10
700 3 : call wrtout(ab_out,message,'COLL')
701 3 : call wrtout(std_out,message,'COLL')
702 :
703 : ! Deallocation in loop
704 3 : call polynomial_coeff_list_free(my_coeffs_tmp)
705 : !Optimizing coefficient old style
706 :
707 5 : if(iterm>nterm)then
708 : ! MS 2006 Decomment for old style optimization
709 : call fit_polynomial_coeff_computeMSD(eff_pot,hist,mse,msef,mses,&
710 : & natom_sc,ntime,fit_data%training_set%sqomega,comm,&
711 2 : & compute_anharmonic=.TRUE.,print_file=.FALSE., weights=my_weights)
712 2 : i = 0
713 2 : write(message,'(a,I2,a,ES24.16)') "cycle ", i ," (msef+mses)/(msef_ini+mses_ini): ", (msef+mses)/(msef_ini+mses_ini)
714 2 : call wrtout(std_out,message,'COLL')
715 2 : write(message,'(a,I2,a,ES24.16)') "cycle ", i ," (msef+mses): ", (msef+mses)
716 2 : call wrtout(std_out,message,'COLL')
717 2 : do while((msef+mses)/(msef_ini+mses_ini) >= 1.001)
718 0 : i = i + 1
719 : eff_pot%anharmonics_terms%coefficients(nterm2)%coefficient = &!coeff_ini / 2**i
720 0 : & eff_pot%anharmonics_terms%coefficients(nterm2)%coefficient / 2**1
721 : call fit_polynomial_coeff_computeMSD(eff_pot,hist,mse,msef,mses,&
722 : & natom_sc,ntime,fit_data%training_set%sqomega,comm,&
723 0 : & compute_anharmonic=.TRUE.,print_file=.FALSE., weights=my_weights)
724 :
725 0 : write(message,'(a,I2,a,ES24.16)') "cycle ",i," (msef+mses)/(msef_ini+mses_ini): ",(msef+mses)/(msef_ini+mses_ini)
726 0 : call wrtout(std_out,message,'COLL')
727 0 : write(message,'(a,I2,a,ES24.16)') "cycle ", i ," (msef+mses): ", (msef+mses)
728 0 : call wrtout(std_out,message,'COLL')
729 : enddo ! while mse/mse_ini>1.0001
730 2 : write(message,'(a,ES24.16)') "coeff after opt:", eff_pot%anharmonics_terms%coefficients(nterm2)%coefficient
731 2 : call wrtout(std_out,message,'COLL')
732 2 : msef_ini = msef
733 2 : mses_ini = mses
734 : ! !Optimize coefficient with opt routine
735 : ! optterm(1)= nterm2
736 : ! nterm_opt = 1
737 : ! call opt_effpot(eff_pot,nterm_opt,optterm,hist,comm,print_anh=.FALSE.)
738 : ! write(*,*) "coeff after opt:", eff_pot%anharmonics_terms%coefficients(nterm2)%coefficient
739 : ! !Store new "inital precision for next coefficient
740 : ! msef_ini = msef
741 : ! mses_ini = mses
742 :
743 : else
744 : !Optimizing coefficient with GF criterion
745 1 : coeff_opt = 0
746 1 : GF_arr = 0
747 1 : i = 1
748 3 : do while(i<=2)
749 : eff_pot%anharmonics_terms%coefficients(nterm2)%coefficient = &
750 2 : & eff_pot%anharmonics_terms%coefficients(nterm2)%coefficient/ 2**(i-1)
751 : call fit_polynomial_coeff_computeMSD(eff_pot,hist,mse,msef,mses,&
752 : & natom_sc,ntime,fit_data%training_set%sqomega,comm,&
753 2 : & compute_anharmonic=.TRUE.,print_file=.FALSE.)
754 : GF_arr(i) = (bound_factors(1)*bound_EFS(1)*mse+bound_factors(2)*bound_EFS(2)*msef&
755 : & +bound_factors(3)*bound_EFS(3)*mses) / &
756 : & (bound_factors(1)*bound_EFS(1)*mse_ini+bound_factors(2)*bound_EFS(2)*msef_ini&
757 2 : & +bound_factors(3)*bound_EFS(3)*mses_ini)
758 2 : write(message,'(a,I2,a,ES24.16)') "cycle ",i," GF/GF_ini: ",GF_arr(i)
759 2 : call wrtout(std_out,message,'COLL')
760 2 : write(message,'(a,I2,a,ES24.16)') "cycle ", i ," GF: ",(bound_factors(1)*bound_EFS(1)*mse&
761 : & +bound_factors(2)*bound_EFS(2)*msef&
762 4 : & +bound_factors(3)*bound_EFS(3)*mses)
763 2 : call wrtout(std_out,message,'COLL')
764 2 : coeff_opt(i) = eff_pot%anharmonics_terms%coefficients(nterm2)%coefficient
765 3 : if(i==2 .and. abs(GF_arr(1)-GF_arr(2)) < tol8)then
766 : eff_pot%anharmonics_terms%coefficients(nterm2)%coefficient =&
767 0 : eff_pot%anharmonics_terms%coefficients(nterm2)%coefficient*10d5
768 0 : write(message,'(5a)') ch10,"Differences between test-cycles to small increase",ch10, &
769 0 : & "test coefficient value by factor 1000",ch10
770 0 : call wrtout(std_out,message,'COLL')
771 0 : i = i+1
772 : ! This is weird, it keeps on increasing the coefficient by 1000, until a NaN is reached.
773 : else
774 2 : i=i+1
775 : end if
776 : enddo ! while mse/mse_ini>10
777 1 : if (eff_pot%anharmonics_terms%coefficients(nterm2)%coefficient /= eff_pot%anharmonics_terms%coefficients(nterm2)%coefficient) then
778 0 : eff_pot%anharmonics_terms%coefficients(nterm2)%coefficient = 0.0_dp
779 : end if
780 :
781 1 : eff_pot%anharmonics_terms%coefficients(nterm2)%coefficient = opt_boundcoeff(GF_arr,coeff_opt,bound_penalty)
782 1 : if (eff_pot%anharmonics_terms%coefficients(nterm2)%coefficient /= eff_pot%anharmonics_terms%coefficients(nterm2)%coefficient) then
783 0 : eff_pot%anharmonics_terms%coefficients(nterm2)%coefficient = 0.0_dp
784 : end if
785 :
786 1 : write(message,'(a,ES24.16)') "coeff after opt1:", eff_pot%anharmonics_terms%coefficients(nterm2)%coefficient
787 1 : call wrtout(std_out,message,'COLL')
788 1 : coeff_tmp = ANINT(eff_pot%anharmonics_terms%coefficients(nterm2)%coefficient*10d10)
789 1 : eff_pot%anharmonics_terms%coefficients(nterm2)%coefficient = coeff_tmp/10d10
790 1 : write(message,'(a,ES24.16)') "coeff after opt2:", eff_pot%anharmonics_terms%coefficients(nterm2)%coefficient
791 1 : call wrtout(std_out,message,'COLL')
792 : call fit_polynomial_coeff_computeMSD(eff_pot,hist,mse,msef,mses,&
793 : & natom_sc,ntime,fit_data%training_set%sqomega,comm,&
794 1 : & compute_anharmonic=.TRUE.,print_file=.FALSE.)
795 1 : write(message,'(a,ES24.16)') "GF/GF_ini after_opt: ", (bound_factors(1)*bound_EFS(1)*mse&
796 : & +bound_factors(2)*bound_EFS(2)*msef&
797 : & +bound_factors(3)*bound_EFS(3)*mses) / &
798 : & (bound_factors(1)*bound_EFS(1)*mse_ini&
799 : & +bound_factors(2)*bound_EFS(2)*msef_ini&
800 2 : & +bound_factors(3)*bound_EFS(3)*mses_ini)
801 1 : call wrtout(std_out,message,'COLL')
802 1 : mse_ini = mse
803 1 : msef_ini = msef
804 1 : mses_ini = mses
805 : endif
806 : !DEALLOCATION
807 : !ABI_FREE(exists)
808 : enddo ! icombi
809 : end if
810 :
811 5 : call polynomial_coeff_list_free(my_coeffs)
812 : end do !iterm
813 : !enddo ! order
814 :
815 1 : if(allocated(singledisp_terms)) call polynomial_coeff_list_free(singledisp_terms)
816 :
817 1 : write(message, '(a,(80a),a)' ) ch10,&
818 81 : &('_',ii=1,80),ch10
819 1 : call wrtout(ab_out,message,'COLL')
820 1 : call wrtout(std_out,message,'COLL')
821 :
822 1 : write(message,'(3a)' )ch10,&
823 2 : & ' Finished creating high-order terms',ch10 !,&
824 : !& ' Optimize initial anharmonic terms !NOT IS COMMENTED NOW!',ch10
825 1 : call wrtout(ab_out,message,'COLL')
826 1 : call wrtout(std_out,message,'COLL')
827 : ! call opt_effpot(eff_pot,nterm,terms,hist,comm,print_anh=.FALSE.)
828 :
829 : ! Print the standard devition of final model
830 1 : write(message,'(6a,ES24.16,6a,ES24.16,2a,ES24.16,2a,ES24.16,a)' )ch10,&
831 1 : & ' Mean Standard Deviation values of the effective-potential',ch10,&
832 1 : & ' with respect to the training-set after attempted bounding (meV^2/atm):',&
833 1 : & ch10,' Energy : ',&
834 1 : & mse_ini* (Ha_EV*1000)**2 *factor ,ch10,&
835 1 : & ' Goal function values of the effective.potential',ch10,&
836 1 : & ' with respect to the test-set (eV^2/A^2):',ch10,&
837 1 : & ' Forces+Stresses : ',&
838 1 : & (msef_ini+mses_ini)*(HaBohr_eVAng)**2,ch10,&
839 1 : & ' Forces : ',&
840 1 : & msef_ini*(HaBohr_eVAng)**2,ch10,&
841 1 : & ' Stresses : ',&
842 2 : & mses_ini*(HaBohr_eVAng)**2,ch10
843 1 : call wrtout(ab_out,message,'COLL')
844 1 : call wrtout(std_out,message,'COLL')
845 :
846 :
847 : !DEALLOCATION
848 1 : ABI_SFREE(symbols)
849 1 : ABI_SFREE(terms)
850 1 : ABI_SFREE(my_weights)
851 :
852 : !ABI_FREE(my_coeffs)
853 1 : call fit_data_free(fit_data)
854 1 : call sympairs%free()
855 :
856 :
857 1 : end subroutine opt_effpotbound
858 : !!***
859 :
860 :
861 : !!****f* m_opt_effpot/opt_getHOforterm
862 : !!
863 : !! NAME
864 : !! opt_effpotbound
865 : !!
866 : !! FUNCTION
867 : !! Compute possible high orders for a given anharmonic term.
868 : !! In the range of order_start,order_stop
869 : !!
870 : !!
871 : !! INPUTS
872 : !! term<polynomial_coeff_type>:anharmonic term
873 : !! order_range(2):start and stop order desired by user
874 : !!
875 : !!
876 : !! OUTPUT
877 : !! order_start:possible start order
878 : !! order_stop: possible stop order
879 : !!
880 : !! SOURCE
881 :
882 2 : subroutine opt_getHOforterm(term,order_range,order_start,order_stop)
883 :
884 : !Arguments ------------------------------------
885 : !scalars
886 : type(polynomial_coeff_type),intent(in) :: term
887 : !arrays
888 : integer,intent(in) :: order_range(2)
889 : integer,intent(out) :: order_start, order_stop
890 : !Logicals
891 : !Strings
892 : !Local variables ------------------------------
893 : !scalars
894 : integer :: idisp,ndisp,nstrain,nterm_of_term,power_tot
895 : integer :: nbody_tot
896 : !arrays
897 2 : integer,allocatable :: powers(:)
898 : !Logicals
899 : !Strings
900 : !*************************************************************************
901 :
902 : !Get/Initialize variables
903 2 : ndisp = term%terms(1)%ndisp
904 2 : nstrain = term%terms(1)%nstrain
905 2 : nbody_tot = ndisp + nstrain
906 2 : nterm_of_term = term%nterm
907 :
908 6 : ABI_MALLOC(powers,(nbody_tot))
909 6 : powers(:ndisp) = term%terms(1)%power_disp
910 3 : powers(ndisp+1:) = term%terms(1)%power_strain
911 7 : power_tot = 0
912 : !write(std_out,*) "powers in getHOforterm", powers
913 :
914 : !Get rid off odd displacements
915 7 : do idisp=1,nbody_tot
916 7 : if(idisp <= ndisp .and. mod(powers(idisp),2) == 1)then
917 2 : powers(idisp) = powers(idisp) + 1
918 3 : else if(mod(powers(idisp),2) == 1)then
919 1 : powers(idisp) = powers(idisp) + 1
920 : endif
921 : enddo !idisp
922 : ! Count order
923 7 : do idisp=1,nbody_tot
924 7 : power_tot = power_tot + powers(idisp)
925 : enddo
926 : ! Get start and stop order for this term
927 : ! If term doesn't fit in order range give back order_start = order_stop = 0
928 2 : if(power_tot >= order_range(1) .and. power_tot <=order_range(2))then
929 1 : order_start = power_tot
930 1 : order_stop = order_range(2)
931 1 : elseif(power_tot < order_range(1))then
932 1 : order_start = order_range(1)
933 1 : order_stop = order_range(2)
934 0 : elseif(power_tot > order_range(2))then
935 0 : order_start = 0
936 0 : order_stop = 0
937 : endif
938 :
939 2 : ABI_SFREE(powers)
940 :
941 2 : end subroutine opt_getHOforterm
942 : !!***
943 :
944 :
945 : !!****f* m_opt_effpot/opt_getCombisforterm
946 : !!
947 : !! NAME
948 : !! opt_getCombisforterm
949 : !!
950 : !! FUNCTION
951 : !! For a given order range: order_start, order_stop
952 : !! calculate number of total possible combinations ncombi
953 : !! and calculat combinations per order ncombi_order(i)
954 : !!
955 : !!
956 : !! INPUTS
957 : !! order_start: start order for bounding terms
958 : !! order_end: end order for bounding terms
959 : !! ndisp: number of displacements a given term contains
960 : !!
961 : !!
962 : !! OUTPUT
963 : !! ncombi: total number of combinations
964 : !! ncombi_order: array with number of combinations per order
965 : !!
966 : !!
967 : !! SOURCE
968 :
969 2 : subroutine opt_getCombisforterm(order_start,order_end,ndisp,ncombi,ncombi_order)
970 :
971 : !Arguments ------------------------------------
972 : !scalars
973 : integer,intent(in) :: ndisp
974 : integer,intent(in) :: order_start, order_end
975 : !arrays
976 : integer,intent(out) :: ncombi
977 : integer,intent(out) :: ncombi_order(:)
978 : !Logicals
979 : !Strings
980 : !Local variables ------------------------------
981 : !scalars
982 : integer :: i
983 : integer :: order,iorder1,iorder2
984 : !arrays
985 : !integer
986 : !Logicals
987 : !Strings
988 : character(len=1000) :: message
989 : !*************************************************************************
990 :
991 : !Test
992 2 : if(mod(order_start,2) /= 0 .or. mod(order_end,2) /= 0)then
993 : ! Message to Output
994 0 : write(message,'(4a)' )ch10,&
995 0 : & 'Either start or stop order are not even numbers',ch10,&
996 0 : & 'Action: change bound_range in input',ch10
997 0 : ABI_ERROR(message)
998 : endif
999 :
1000 : !Initialize Variables
1001 2 : i = 0
1002 2 : ncombi = 0
1003 4 : ncombi_order = 0
1004 :
1005 : !Calculate Combinations
1006 4 : do order=order_start,order_end,2
1007 2 : i = i+1
1008 4 : if(ndisp == 1)then
1009 0 : ncombi = ncombi + 1
1010 0 : ncombi_order(i) = 1
1011 : else
1012 5 : do iorder1 = 2,order-2*(ndisp-1),2
1013 3 : if(ndisp*iorder1 == order)then
1014 1 : ncombi = ncombi + 1
1015 1 : ncombi_order(i) = ncombi_order(i) + 1
1016 1 : cycle
1017 : endif
1018 5 : do iorder2=iorder1+2,order-2*(ndisp-1),2
1019 3 : if( iorder1 + (ndisp-1)*iorder2 == order)then
1020 1 : ncombi = ncombi + ndisp
1021 1 : ncombi_order(i) = ncombi_order(i) + ndisp
1022 0 : elseif(iorder1 * (ndisp-1) + iorder2 == order)then
1023 0 : ncombi = ncombi + ndisp
1024 0 : ncombi_order(i) = ncombi_order(i) + ndisp
1025 : endif
1026 : enddo !iorder2
1027 : enddo !iorder1 !
1028 : endif
1029 : !write(*,*) 'ncombi(',i,') for order',order,' is:', ncombi_order(i), 'are we happy?'
1030 : enddo !order
1031 :
1032 : !write(*,*) ncombi_order(:)
1033 : !write(*,*) 'ncombi for term is:', ncombi, 'are we happy?'
1034 :
1035 :
1036 2 : end subroutine opt_getCombisforterm
1037 : !!***
1038 :
1039 : !!****f* m_opt_effpot/opt_getHoTerms
1040 : !!
1041 : !! NAME
1042 : !! opt_geHoTerms
1043 : !!
1044 : !! FUNCTION
1045 : !! For a term give all possible high order terms
1046 : !! Attention order_start, order_stop, ncombi and
1047 : !! ncombi_order have to be calculated before!
1048 : !!
1049 : !!
1050 : !!
1051 : !! INPUTS
1052 : !! eff_pot: existing effective potential
1053 : !! order: order for which bounding terms are generated
1054 : !!
1055 : !!
1056 : !! OUTPUT
1057 : !! eff_pot new effective potential
1058 : !!
1059 : !!
1060 : !! SOURCE
1061 :
1062 2 : subroutine opt_getHoTerms(terms,order_start,order_stop,ndisp,ncombi_order)
1063 :
1064 : !Arguments ------------------------------------
1065 : !scalars
1066 : integer,intent(in) :: ndisp
1067 : integer,intent(in) :: order_start, order_stop
1068 : !arrays
1069 : integer,intent(in) :: ncombi_order(:)
1070 : !Logicals
1071 : type(polynomial_coeff_type),intent(inout) :: terms(:)
1072 : !Strings
1073 : !Local variables ------------------------------
1074 : !scalars
1075 : integer :: i,icombi,icombi2,icombi_start,icombi_stop,idisp,nterm_of_term
1076 : integer :: order,iterm_of_term,jdisp,power_tot
1077 : integer :: jdisp1,jdisp2,sec,nstrain,nbody_tot
1078 : real(sp) :: to_divide,divider1,divider2,divided
1079 : !arrays
1080 : !integer
1081 : !Logicals
1082 : logical :: equal_term_done
1083 : !Strings
1084 : character(len=1000) :: message
1085 : !*************************************************************************
1086 : !Get Variables
1087 2 : nterm_of_term = terms(1)%nterm
1088 2 : nstrain = terms(1)%terms(1)%nstrain
1089 2 : nbody_tot = ndisp + nstrain
1090 :
1091 : ! Create all possible combinaions for the specified orders
1092 : ! If anybody has ever, ever to read and understand this I'm terribly sorry
1093 : ! ---this will be quite hell---
1094 2 : power_tot = 0
1095 2 : icombi_start = 1
1096 2 : i = 0
1097 : !write(*,*) "what is ncombi?", ncombi
1098 : !write(*,*) "what is ncmobi_order", ncombi_order
1099 :
1100 : !write(*,*) "order_start", order_start
1101 : !write(*,*) "order_stop", order_stop
1102 2 : order = order_start
1103 : ! TODO work here icombi start and order counting does not work yet.
1104 4 : do order=order_start,order_stop,2
1105 : !write(std_out,*) 'Was I now here?!(order-loop)'
1106 2 : i = i + 1
1107 2 : icombi_stop = icombi_start + ncombi_order(i) - 1
1108 2 : equal_term_done = .FALSE.
1109 : !write(std_out,*) 'order', order
1110 : !write(std_out,*) 'icombi_start', icombi_start
1111 : !write(std_out,*) 'icombi_stop', icombi_stop
1112 2 : icombi=icombi_start
1113 6 : do while (icombi<=icombi_stop)
1114 : power_tot = 0
1115 7 : do idisp=1,nbody_tot
1116 : !write(*,*) "what is icombi here?", icombi
1117 : !write(*,*) "what is icombi_stop here?", icombi_stop
1118 7 : if(idisp<=ndisp)then
1119 4 : power_tot = power_tot + terms(icombi)%terms(1)%power_disp(idisp)
1120 : else
1121 1 : power_tot = power_tot + terms(icombi)%terms(1)%power_strain(idisp-ndisp)
1122 : endif
1123 : enddo
1124 : ! Probably have to increase order at same time
1125 : ! If the term already has the right order we cycle
1126 : ! we increase icombi_start and icombi to go to the next term in the array
1127 4 : if(power_tot == order)then
1128 1 : icombi_start = icombi_start + 1
1129 1 : icombi = icombi + 1
1130 : !write(*,*) 'icombi-start in if', icombi_start
1131 1 : cycle
1132 : ! If the term is not already in the right order, we manipulate it until
1133 : ! it is
1134 : else
1135 : jdisp1 = 1
1136 3 : sec = 1
1137 : !write(*,*) 'what is ndisp actually', ndisp
1138 : ! Treat single permutations from the bottom of the order
1139 : ! so start from ^2^2^2 and get ^6^2^2,^2^6^2, and ^2^2^6 f.E.
1140 : ! do loop over displacements
1141 3 : do while(jdisp1<=nbody_tot .and. sec < 100)
1142 : !write(*,*) "what is jdisp1 here?", jdisp1
1143 : !write(*,*) "what is icombi here?", icombi
1144 : !write(*,*) "what is icombi_sotp?", icombi_stop
1145 : ! Increase the order of the displacements
1146 50 : do iterm_of_term=1,nterm_of_term
1147 50 : if(jdisp1 <= ndisp)then
1148 : terms(icombi)%terms(iterm_of_term)%power_disp(jdisp1) =&
1149 48 : & terms(icombi)%terms(iterm_of_term)%power_disp(jdisp1) + 2
1150 : else
1151 : terms(icombi)%terms(iterm_of_term)%power_strain(jdisp1-ndisp) =&
1152 0 : & terms(icombi)%terms(iterm_of_term)%power_strain(jdisp1-ndisp) + 2
1153 :
1154 : endif
1155 : enddo
1156 : ! Check total order of term after increase
1157 : power_tot=0
1158 6 : do jdisp2=1,nbody_tot
1159 6 : if(jdisp2 <= ndisp)then
1160 4 : power_tot = power_tot + terms(icombi)%terms(1)%power_disp(jdisp2)
1161 : else
1162 0 : power_tot = power_tot + terms(icombi)%terms(1)%power_strain(jdisp2-ndisp)
1163 : endif
1164 : enddo
1165 : ! If the term is at the right order do next displacement
1166 : ! increase icombi and icombi_start to go to next term in array
1167 3 : if(power_tot == order)then
1168 2 : icombi = icombi + 1
1169 2 : icombi_start = icombi_start +1
1170 : !write(*,*) 'what is icombi_start here', icombi_start
1171 2 : jdisp1 = jdisp1 + 1
1172 : !write(*,*) 'and what is jdisp1?', jdisp1
1173 :
1174 : endif
1175 : enddo!jdisp1
1176 : !Treat permutations in terms ndisp > 2 and order >= 10
1177 : !Start f.E. from ^4^4^4 and get ^4^2^4, ^2^4^4,^4^4^2
1178 1 : if(icombi_stop - icombi > 1 .and. nbody_tot >2 )then
1179 0 : do icombi2=icombi,icombi+nbody_tot-1
1180 0 : do jdisp=1,nbody_tot
1181 0 : do iterm_of_term=1,nterm_of_term
1182 0 : if(jdisp <= ndisp)then
1183 : terms(icombi2)%terms(iterm_of_term)%power_disp(jdisp) = &
1184 0 : & terms(icombi2)%terms(iterm_of_term)%power_disp(jdisp) +2
1185 : !write(*,*) "What's the power now?", terms(icombi2)%terms(iterm_of_term)%power_disp(jdisp)
1186 : else
1187 : terms(icombi2)%terms(iterm_of_term)%power_strain(jdisp-ndisp) = &
1188 0 : & terms(icombi2)%terms(iterm_of_term)%power_strain(jdisp-ndisp) +2
1189 : endif
1190 : enddo
1191 : enddo !jdisp
1192 : enddo
1193 : jdisp1 = 1
1194 0 : do while(jdisp1<=nbody_tot .and. sec < 100)
1195 0 : sec = sec + 1
1196 : !write(*,*) "how often did I go here, hu ?"
1197 : !write(*,*) "I did at least one displacement"
1198 0 : do iterm_of_term=1,nterm_of_term
1199 0 : if(jdisp1 <= ndisp)then
1200 : terms(icombi)%terms(iterm_of_term)%power_disp(jdisp1) =&
1201 0 : & terms(icombi)%terms(iterm_of_term)%power_disp(jdisp1) + 2
1202 : else
1203 : terms(icombi)%terms(iterm_of_term)%power_strain(jdisp1-ndisp) =&
1204 0 : & terms(icombi)%terms(iterm_of_term)%power_strain(jdisp1-ndisp) + 2
1205 :
1206 : endif
1207 : enddo
1208 : power_tot=0
1209 0 : do jdisp2=1,nbody_tot
1210 0 : if(jdisp2 <= ndisp)then
1211 0 : power_tot = power_tot + terms(icombi)%terms(1)%power_disp(jdisp2)
1212 : else
1213 0 : power_tot = power_tot + terms(icombi)%terms(1)%power_strain(jdisp2-ndisp)
1214 : endif
1215 : enddo
1216 0 : if(power_tot == order)then
1217 0 : icombi = icombi + 1
1218 0 : icombi_start = icombi_start +1
1219 : !write(*,*) 'what is icombi_start here', icombi_start
1220 0 : jdisp1 = jdisp1 + 1
1221 : !write(*,*) 'and what is jdisp1?', jdisp1
1222 : endif
1223 : enddo!jdisp1
1224 : ! Message to Output
1225 : if(sec>100)then
1226 : write(message,'(4a)' )ch10,&
1227 : & "You're stuck in a while loop.",ch10,&
1228 : & 'Action: Contact Abinit Group',ch10
1229 : ABI_ERROR(message)
1230 : endif
1231 : endif! (icombi_stop - icombi)
1232 : !write(*,*) 'I was here!'
1233 1 : to_divide = real(order)
1234 1 : divider1 = real(nbody_tot)
1235 1 : divided = real(to_divide/divider1)
1236 1 : divider2 = real(2)
1237 : !write(*,*) 'divided', divided, 'divider2', divider2
1238 : !Treat terms with even power f.E. ^2^2^2^2, ^4^4 etc...
1239 1 : if(mod(divided,divider2) == 0 .and. .not. equal_term_done .and. nbody_tot > 1)then
1240 : !write(*,*) "Sometimes I should be here sometimes I shouldn't"
1241 0 : do jdisp=1,nbody_tot
1242 0 : do iterm_of_term=1,nterm_of_term
1243 0 : if(jdisp<=ndisp)then
1244 0 : terms(icombi)%terms(iterm_of_term)%power_disp(jdisp) = order/ndisp
1245 : else
1246 0 : terms(icombi)%terms(iterm_of_term)%power_strain(jdisp-ndisp) = order/ndisp
1247 : endif
1248 : enddo
1249 : enddo !jdisp
1250 0 : if(order < order_stop)then
1251 0 : do icombi2=icombi+1,icombi+nbody_tot
1252 0 : do jdisp=1,nbody_tot
1253 0 : do iterm_of_term=1,nterm_of_term
1254 0 : if(jdisp<=ndisp)then
1255 0 : terms(icombi2)%terms(iterm_of_term)%power_disp(jdisp) = order/ndisp
1256 : else
1257 0 : terms(icombi2)%terms(iterm_of_term)%power_strain(jdisp-ndisp) = order/ndisp
1258 : endif
1259 : enddo
1260 : enddo !jdisp
1261 : enddo
1262 : endif
1263 0 : equal_term_done = .TRUE.
1264 0 : icombi = icombi + 1
1265 0 : icombi_start = icombi_start +1
1266 : endif ! equal term if
1267 : endif ! power_tot == order
1268 : enddo !icombination
1269 : enddo !order
1270 :
1271 2 : end subroutine opt_getHoTerms
1272 : !!***
1273 :
1274 : !!****f* m_opt_effpot/opt_filterdisp
1275 : !!
1276 : !! NAME
1277 : !! opt_opt_filterdisp
1278 : !!
1279 : !! FUNCTION
1280 : !! If a anharmonic term represents a strain-phonon coupling
1281 : !! delete the strain and only keep the displacement part.
1282 : !!
1283 : !!
1284 : !! INPUTS
1285 : !! term<polynomial_coeff_type>: anharmonic term to check
1286 : !! nterm_of_term: number of symmetry equivalent terms for term
1287 : !!
1288 : !! OUTPUT
1289 : !! term<polynomial_coeff_type>: only the displacement part of original term
1290 : !!
1291 : !! SOURCE
1292 :
1293 1 : subroutine opt_filterdisp(term,nterm_of_term)
1294 :
1295 : !Arguments ------------------------------------
1296 : !scalars
1297 : type(polynomial_coeff_type),intent(inout) :: term
1298 : integer,intent(in) :: nterm_of_term
1299 : !arrays
1300 : !Logicals
1301 : !Strings
1302 : !Local variables ------------------------------
1303 : !scalars
1304 : integer :: iterm_of_term
1305 : !reals
1306 : real(dp) :: coeff
1307 : !arrays
1308 242 : type(polynomial_term_type) :: terms(nterm_of_term)
1309 : !Logicals
1310 : !Strings
1311 : !*************************************************************************
1312 :
1313 25 : do iterm_of_term=1,nterm_of_term
1314 : !terms(iterm_of_term) = term%terms(iterm_of_term)
1315 :
1316 : call polynomial_term_init(term%terms(iterm_of_term)%atindx, &
1317 : & term%terms(iterm_of_term)%cell,&
1318 : & term%terms(iterm_of_term)%direction,&
1319 : & term%terms(iterm_of_term)%ndisp, &
1320 : & term%terms(iterm_of_term)%nstrain, &
1321 : & terms(iterm_of_term),&
1322 : & term%terms(iterm_of_term)%power_disp, &
1323 : & term%terms(iterm_of_term)%power_strain,&
1324 : & term%terms(iterm_of_term)%strain, &
1325 : & term%terms(iterm_of_term)%weight, &
1326 24 : & check=.TRUE.)
1327 24 : terms(iterm_of_term)%nstrain = 0
1328 48 : terms(iterm_of_term)%power_strain = 0
1329 49 : terms(iterm_of_term)%strain = 0
1330 : !DMSG(terms(iterm_of_term)%debug_str)
1331 : enddo
1332 :
1333 1 : call polynomial_coeff_free(term)
1334 : !Reinitial term
1335 : !check=.TRUE. checks for duplicate terms
1336 1 : call polynomial_coeff_init(coeff,nterm_of_term,term,terms, check=.TRUE.)
1337 : !DMSG(term%debug_str)
1338 :
1339 :
1340 25 : do iterm_of_term=1,nterm_of_term
1341 25 : call polynomial_term_free(terms(iterm_of_term))
1342 : enddo
1343 : !if(nterm_of_term /= term%nterm)then
1344 : ! write(*,*) "nterm_of_term changed after deleting strain"
1345 : !endif
1346 :
1347 :
1348 192 : end subroutine opt_filterdisp
1349 : !!***
1350 :
1351 : !!****f* m_opt_effpot/opt_getHOstrain
1352 : !!
1353 : !! NAME
1354 : !! opt_getHOstrain
1355 : !!
1356 : !! FUNCTION
1357 : !! Get HO anharmnonic strain terms for bounding and add them to list
1358 : !! of existing terms in effective potential
1359 : !!
1360 : !! INPUTS
1361 : !! eff_pot<effective_potential_type>: datatype with all the information
1362 : !! about the effective potential
1363 : !! power_strain(2): start and stop order for strain terms
1364 : !! comm: mpi communicator (at the moment only sequential tested)
1365 : !!
1366 : !! OUTPUT
1367 : !! terms<polynomial_coeff_type>: list with original terms in effective
1368 : !! potential + HO even strain terms
1369 : !!
1370 : !! SOURCE
1371 :
1372 1 : subroutine opt_getHOstrain(terms,ncombi,nterm_start,eff_pot,power_strain,comm, max_nbody)
1373 :
1374 : !Arguments ------------------------------------
1375 : !scalars
1376 : integer,intent(in) :: comm
1377 : type(polynomial_coeff_type),allocatable,intent(inout) :: terms(:)
1378 : type(effective_potential_type), intent(in) :: eff_pot
1379 : integer,intent(in) :: power_strain(2), max_nbody(:)
1380 : integer,intent(out) :: ncombi,nterm_start
1381 : !arrays
1382 : !Logicals
1383 : !Strings
1384 : !Local variables ------------------------------
1385 : !scalars
1386 : integer :: nterm_tot_tmp
1387 : integer :: i,ii
1388 : !integer :: nbody, ref_nbody
1389 : real(dp) :: coeff_ini
1390 : !reals
1391 56 : type(crystal_t) :: crystal
1392 : !arrays
1393 1 : type(polynomial_coeff_type),allocatable :: strain_terms_tmp(:)
1394 : !Logicals
1395 : !Strings
1396 : character(len=1000) :: message
1397 : !*************************************************************************
1398 : !Get variables
1399 1 : crystal = eff_pot%crystal
1400 1 : coeff_ini = 1000000
1401 :
1402 1 : write(message, '(a,(80a),a)' ) ch10,&
1403 81 : & ('_',ii=1,80),ch10
1404 1 : call wrtout(ab_out,message,'COLL')
1405 1 : call wrtout(std_out,message,'COLL')
1406 1 : write(message,'(3a)' )ch10,&
1407 2 : & ' Chreate high order strain terms ',ch10
1408 1 : call wrtout(ab_out,message,'COLL')
1409 1 : call wrtout(std_out,message,'COLL')
1410 :
1411 :
1412 : !1406 get count of high order even anharmonic strain terms and the strain terms itself
1413 1 : call polynomial_coeff_getEvenAnhaStrain(strain_terms_tmp,crystal,ncombi,power_strain,comm, max_nbody)
1414 : ! Allocate my_coeffs with ncombi free space to work with
1415 :
1416 :
1417 :
1418 1 : nterm_start = eff_pot%anharmonics_terms%ncoeff
1419 1 : nterm_tot_tmp = eff_pot%anharmonics_terms%ncoeff + ncombi
1420 7 : ABI_MALLOC(terms,(nterm_tot_tmp))
1421 5 : do i=1,nterm_tot_tmp
1422 5 : if(i<=nterm_start)then
1423 : call polynomial_coeff_init(coeff_ini,eff_pot%anharmonics_terms%coefficients(i)%nterm,terms(i),&
1424 : & eff_pot%anharmonics_terms%coefficients(i)%terms,eff_pot%anharmonics_terms%coefficients(i)%name,&
1425 2 : & check=.TRUE.)
1426 : !DMSG(terms(i)%debug_str)
1427 : else
1428 2 : if (.not.allocated(strain_terms_tmp(i-nterm_start)%terms)) then
1429 0 : write(message,'(4a)' )ch10,&
1430 0 : & 'Error in opt_getHOstrain: strain_terms_tmp(i-nterm_start)%terms not allocated',ch10,&
1431 0 : & 'Action: Contact Abinit Group',ch10
1432 0 : ABI_ERROR(message)
1433 : endif
1434 : call polynomial_coeff_init(coeff_ini,strain_terms_tmp(i-nterm_start)%nterm,terms(i),&
1435 : & strain_terms_tmp(i-nterm_start)%terms,strain_terms_tmp(i-nterm_start)%name,&
1436 2 : & check=.TRUE.)
1437 : !DMSG(strain_terms_tmp(i-nterm_start)%debug_str)
1438 : endif
1439 : enddo
1440 :
1441 1 : call polynomial_coeff_list_free(strain_terms_tmp)
1442 :
1443 1 : end subroutine opt_getHOstrain
1444 : !!***
1445 :
1446 : !!****f* m_opt_effpot/opt_getHOcrossdisp
1447 : !!
1448 : !! NAME
1449 : !! opt_getHOcrossdisp
1450 : !!
1451 : !! FUNCTION
1452 : !! Get even high order displacement terms for a given input term and
1453 : !! add them to an excisting list of terms. If the term is strain phonon type
1454 : !! the strain part gets deleted and the high order terms for the displacement
1455 : !! part are computed.
1456 : !! Example: for a tree linear term with three displacements x*y*z the even high order
1457 : !! possibilites are computed and stored.
1458 : !! For range 6 to 8: x^2*y^2*z^2,x^4*y^2*z^2,x^2*y^4*z^2,x^2*y^2*z^4.
1459 : !!
1460 : !! INPUTS
1461 : !! eff_pot<effective_potential_type>: datatype with all the information
1462 : !! about the effective potential
1463 : !! power_disp(2): start and stop order for disp terms
1464 : !! comm: mpi communicator (at the moment only sequential tested)
1465 : !!
1466 : !! OUTPUT
1467 : !! terms<polynomial_coeff_type>: list with original terms in effective
1468 : !! potential + HO even disp terms
1469 : !!
1470 : !! SOURCE
1471 :
1472 1 : subroutine opt_getHOcrossdisp(terms_out,ncombi,term_in,power_disp)
1473 :
1474 : !Arguments ------------------------------------
1475 : !scalars
1476 : type(polynomial_coeff_type),allocatable,intent(inout) :: terms_out(:)
1477 : type(polynomial_coeff_type),intent(inout) :: term_in
1478 : integer,intent(in) :: power_disp(2)
1479 : integer,intent(out) :: ncombi
1480 : !arrays
1481 : !Logicals
1482 : !Strings
1483 : !Local variables ------------------------------
1484 : !scalars
1485 : integer :: ndisp,nterm_of_term,nstrain,nbody_tot
1486 : integer :: order_start,order_stop,norder
1487 : integer :: order_start_str,order_stop_str
1488 : integer :: icombi,idisp,iterm_of_term
1489 : integer :: ncombi_tot,ncombi_str
1490 : !reals
1491 : real(dp) :: coeff_ini=1
1492 : !arrays
1493 1 : type(polynomial_coeff_type) :: term
1494 : integer,allocatable :: ncombi_order(:),ncombi_order_str(:)
1495 : !Logicals
1496 : logical :: had_strain
1497 : !Strings
1498 : character(len=1000) :: message
1499 : !*************************************************************************
1500 : !Get/Set Variables
1501 1 : norder = abs(((power_disp(2)-power_disp(1))/2)) + 1
1502 3 : ABI_MALLOC(ncombi_order,(norder))
1503 2 : ABI_MALLOC(ncombi_order_str,(norder))
1504 2 : ncombi_order = 0
1505 2 : ncombi_order_str = 0
1506 1 : order_start_str = 0
1507 1 : order_stop_str = 0
1508 :
1509 1 : ncombi = 0
1510 : !Get this term (iterm) and infromations about it
1511 : !Get number of displacements and equivalent terms for this term
1512 : !Chose term one to get ndisp. ndisp is equal for all terms of the term
1513 : !Get minimum oder for this term
1514 : !Get total number of terms in effpot for message
1515 1 : ndisp = term_in%terms(1)%ndisp
1516 1 : nstrain = term_in%terms(1)%nstrain
1517 1 : nbody_tot = ndisp + nstrain
1518 1 : nterm_of_term = term_in%nterm
1519 1 : call polynomial_coeff_init(coeff_ini,nterm_of_term,term,term_in%terms,term_in%name, check=.true.)
1520 : !DMSG(term%debug_str)
1521 : ! Check if term has strain component.
1522 : ! If yes filter strain and fit high order atomic displacement terms
1523 1 : had_strain = .FALSE.
1524 1 : if(term%terms(1)%nstrain /= 0)then
1525 : ! Message to Output
1526 1 : write(message,'(5a)' )ch10,&
1527 1 : & '- Term has strain compenent',ch10,&
1528 2 : & ' -> Filter Displacement',ch10
1529 1 : call wrtout(ab_out,message,'COLL')
1530 1 : call wrtout(std_out,message,'COLL')
1531 1 : call opt_filterdisp(term,nterm_of_term)
1532 : !Get new value of symmetry equivalent term nterm_of_term
1533 1 : nterm_of_term = term%nterm
1534 : !Remember if this term had strain
1535 1 : had_strain = .TRUE.
1536 : !cycle
1537 : endif
1538 : ! Ok we want it. Let's go.
1539 :
1540 : ! get start and stop order for this term
1541 1 : call opt_getHOforterm(term,power_disp,order_start,order_stop)
1542 1 : if(had_strain) call opt_getHOforterm(term_in,power_disp,order_start_str,order_stop_str)
1543 1 : if(order_start == 0)then
1544 : ! Message to Output
1545 0 : write(message,'(5a,I2,a,I2,3a)' )ch10,&
1546 0 : & " ==> High order cross product terms for term ", trim(term%name),ch10,&
1547 0 : & " ==> do not fit into specified order range from ", power_disp(1),' to ',power_disp(2),ch10,&
1548 0 : & " ==> Can not construct high order cross product bounding term",ch10
1549 0 : call wrtout(ab_out,message,'COLL')
1550 0 : call wrtout(std_out,message,'COLL')
1551 0 : ABI_SFREE(ncombi_order)
1552 0 : ABI_SFREE(ncombi_order_str)
1553 0 : return
1554 : end if
1555 :
1556 1 : if(order_start_str == 0 .and. had_strain)then
1557 : ! Message to Output
1558 0 : write(message,'(5a,I2,a,I2,3a)' )ch10,&
1559 0 : & " ==> High order cross product terms for term ", trim(term_in%name),ch10,&
1560 0 : & " ==> do not fit into specified order range from ", power_disp(1),' to ',power_disp(2),ch10,&
1561 0 : & " ==> Can not construct high order cross product bounding term",ch10
1562 0 : call wrtout(ab_out,message,'COLL')
1563 0 : call wrtout(std_out,message,'COLL')
1564 0 : had_strain = .FALSE.
1565 : end if
1566 : ! get total amount of combinations and combinations per order for the term
1567 1 : call opt_getCombisforterm(order_start,order_stop,ndisp,ncombi,ncombi_order)
1568 1 : if(had_strain)then
1569 1 : call opt_getCombisforterm(order_start_str,order_stop_str,nbody_tot,ncombi_str,ncombi_order_str)
1570 : !write(std_out,*) "I was here ncombi_str is: ", ncombi_str
1571 6 : ABI_MALLOC(terms_out,(ncombi+ncombi_str))
1572 2 : ncombi_tot = ncombi+ncombi_str
1573 : else
1574 0 : ABI_MALLOC(terms_out,(ncombi))
1575 0 : ncombi_tot = ncombi
1576 : endif
1577 : ! Copy current term to the ncombination elemenst a the end in array terms
1578 : ! change the value of their coefficient to a start value
1579 : ! The start is estimed to not be larger then half the initial term's value
1580 : ! This is because higher order terms should have smaller coefficients
1581 4 : do icombi=1,ncombi_tot
1582 3 : if(icombi <= ncombi)then
1583 2 : coeff_ini = 1 !abs(terms_out(icombi)%coefficient / 2)
1584 2 : nterm_of_term = term%nterm
1585 2 : call polynomial_coeff_init(coeff_ini,nterm_of_term,terms_out(icombi),term%terms, check=.true.)
1586 : !DMSG(terms_out(icombi)%debug_str)
1587 : else
1588 1 : coeff_ini = 10d3
1589 1 : nterm_of_term = term_in%nterm
1590 1 : call polynomial_coeff_init(coeff_ini,nterm_of_term,terms_out(icombi),term_in%terms, check=.true.)
1591 : !DMSG(terms_out(icombi)%debug_str)
1592 : endif
1593 : ! Set the power of all terms we want to add to two. We find the correct power later
1594 : ! Change the weight of the term to 1 (even terms have allways weight=1)
1595 76 : do iterm_of_term=1,nterm_of_term
1596 72 : terms_out(icombi)%terms(iterm_of_term)%weight = 1
1597 72 : if(icombi > ncombi)then
1598 48 : terms_out(icombi)%terms(iterm_of_term)%power_strain = 2
1599 24 : coeff_ini = 10d3 !abs(terms_out(icombi)%coefficient / 2)
1600 24 : terms_out(icombi)%coefficient = coeff_ini
1601 : ! elseif(icombi>2*ncombi)then
1602 : ! terms_out(icombi)%terms(iterm_of_term)%power_strain = 4
1603 : ! coeff_ini = 10d5 !abs(terms_out(icombi)%coefficient / 2)
1604 : ! terms_out(icombi)%coefficient = coeff_ini
1605 : endif
1606 219 : do idisp=1,ndisp
1607 216 : terms_out(icombi)%terms(iterm_of_term)%power_disp(idisp) = 2
1608 : enddo !idisp
1609 : enddo !iterm_of_term
1610 : enddo !icombi
1611 :
1612 : !If term had strain we had to reinitialize it in the process
1613 : !Refree memory
1614 : !if(had_strain)
1615 1 : call polynomial_coeff_free(term)
1616 :
1617 : ! Get high order combinations
1618 1 : if(had_strain)then
1619 1 : call opt_getHoTerms(terms_out(:ncombi),order_start,order_stop,ndisp,ncombi_order)
1620 1 : call opt_getHoTerms(terms_out(ncombi+1:),order_start_str,order_stop_str,ndisp,ncombi_order_str)
1621 1 : ncombi = ncombi_tot
1622 : else
1623 0 : call opt_getHoTerms(terms_out,order_start,order_stop,ndisp,ncombi_order)
1624 : endif
1625 : !DEALLOCATION
1626 1 : ABI_SFREE(ncombi_order)
1627 1 : ABI_SFREE(ncombi_order_str)
1628 :
1629 3 : end subroutine opt_getHOcrossdisp
1630 : !!***
1631 :
1632 : !!****f* m_opt_effpot/opt_getSingleDispTerms
1633 : !!
1634 : !! NAME
1635 : !! opt_getSingleDispTerms
1636 : !!
1637 : !! FUNCTION
1638 : !! Get polynomial terms (<polynomial_coeff_type>) with single displacements
1639 : !! at second order inside a given range defined by the supercell size
1640 : !!
1641 : !! INPUTS
1642 : !! sc_size(3): supercell size
1643 : !! crystal<type(crystal_t)>: all information about the crystal
1644 : !! comm: mpi communicator (at the moment only sequential tested)
1645 : !!
1646 : !! OUTPUT
1647 : !! terms<polynomial_coeff_type>: list single displacement polynomial_coeffs
1648 : !!
1649 : !! SOURCE
1650 :
1651 1 : subroutine opt_getSingleDispTerms(terms,crystal, sc_size,comm)
1652 :
1653 : !Arguments ------------------------------------
1654 : !scalars
1655 : integer,intent(in) :: comm
1656 : type(polynomial_coeff_type),allocatable,intent(inout) :: terms(:)
1657 : type(crystal_t),intent(inout) :: crystal
1658 : real(dp) :: cutoff
1659 : !arrays
1660 : integer :: sc_size(3)
1661 :
1662 : !Logicals
1663 : !Strings
1664 : !Local variables ------------------------------
1665 : !scalars
1666 : integer :: natom,nsym,nrpt,ncoeff_sym,nstr_sym
1667 : integer :: ncoeff,ncoeff_out,power_strph,option_GN,option
1668 : integer :: nterms_out,nterm1,iterm1,iterm2,ind,iatom,i
1669 : integer :: ncopy
1670 : integer :: ii !,ia,ib,r1,r2,r3
1671 : !integer :: irpt,irpt_ref
1672 : integer :: master,nproc,my_rank
1673 : !arrays
1674 : integer :: power_disp(2)
1675 1 : integer,allocatable :: cell(:,:)
1676 1 : integer,allocatable :: list_symcoeff(:,:,:),list_symstr(:,:,:)
1677 1 : logical,allocatable :: terms_to_copy(:)
1678 1 : type(polynomial_coeff_type),allocatable :: terms_tmp(:),terms_tmp2(:)
1679 : !type(polynomial_coeff_type),allocatable :: terms(:)
1680 : !real(dp),allocatable :: xcart(:,:),xred(:,:),rpt(:,:)
1681 : real(dp) :: rprimd(3,3),range_ifc(3)
1682 1 : real(dp),allocatable :: dist(:,:,:,:)
1683 1 : character(len=5),allocatable :: symbols(:)
1684 : !Logicals
1685 : logical :: iam_master,need_verbose
1686 : !Strings
1687 : character(len=1000) :: message
1688 : !*************************************************************************
1689 :
1690 1 : option = 2
1691 :
1692 : if(option == 1)then
1693 : !MPI variables
1694 : master = 0
1695 : nproc = xmpi_comm_size(comm); my_rank = xmpi_comm_rank(comm)
1696 : iam_master = (my_rank == master)
1697 :
1698 : !Set/Get other variables
1699 : !natom = crystal%natom
1700 : !nsym = crystal%nsym
1701 : rprimd = crystal%rprimd
1702 : need_verbose = .TRUE.
1703 :
1704 :
1705 : call prepare_for_getList(crystal,sc_size, dist, cell, natom, nsym, nrpt, range_ifc , symbols)
1706 :
1707 : ! FIXME: this is dangerous!
1708 : ! It assumes that the structure is cubic in a usual axis setting.
1709 : cutoff = rprimd(1,1)
1710 :
1711 : if(need_verbose)then
1712 : write(message,'(1a)')' Generation of the list of all the possible coefficients'
1713 : call wrtout(std_out,message,'COLL')
1714 : end if
1715 : call polynomial_coeff_getList(cell,crystal,dist,list_symcoeff,list_symstr,&
1716 : & natom,nstr_sym,ncoeff_sym,nrpt,range_ifc,cutoff,sc_size=sc_size)
1717 :
1718 : ABI_SFREE(dist)
1719 : !ABI_FREE(rpt)
1720 :
1721 : !write(*,*) "polynomial_getList worked"
1722 :
1723 : !Get Order1 term s
1724 : !Check difference between ncoeff_out, ncoeff
1725 : call polynomial_coeff_getOrder1(cell,terms,list_symcoeff,natom,nterms_out,ncoeff_sym,nrpt,nsym,symbols)
1726 :
1727 : !do ii=1,nterms_out
1728 : ! write(*,*) "Term(",ii,"/",nterms_out,"): ", terms(ii)%name
1729 : !enddo
1730 :
1731 : elseif(option == 2)then
1732 : !Get/set variables
1733 : ! FIXME: hexu: check these values of 2. Why are they are hard coded here.
1734 : ! Does this mean we only generate high-order terms in 2x2x2 cell?
1735 1 : power_disp = (/2,2/)
1736 1 : power_strph = zero
1737 1 : option_GN = 0
1738 1 : sc_size = (/2,2,2/)
1739 1 : cutoff = 0
1740 1 : natom = crystal%natom
1741 : ! XXX: hexu: why cutoff = sum of axis lengths?
1742 4 : do ii=1,3
1743 : cutoff = cutoff + sqrt(crystal%rprimd(ii,1)**2 + &
1744 : & crystal%rprimd(ii,2)**2 + &
1745 4 : & crystal%rprimd(ii,3)**2)
1746 : enddo
1747 :
1748 :
1749 : !do iatom=1,3
1750 6 : do iatom=1,natom !Subhadeep
1751 : ! TODO: to be validated.
1752 : !do iatom=1,crystal%nirredat
1753 : call polynomial_coeff_getNorder(terms_tmp,crystal,cutoff,ncoeff,ncoeff_out,power_disp,&
1754 : & power_strph,option_GN,sc_size,comm,anharmstr=.false.,spcoupling=.false.,&
1755 : & only_odd_power=.false.,only_even_power=.true.,verbose=.false.,&
1756 : & compute_symmetric=.false.,fit_iatom=iatom, &
1757 5 : & max_nbody=[999,999,999,999,999,999, 999,999,999,999])
1758 : !TEST MS
1759 : ! write(std_out,*) "behind call getNorder"
1760 : ! write(std_out,*) "ncoeff_out: ", ncoeff_out
1761 : ! do ii=1,ncoeff_out
1762 : ! write(*,*) "Term(",ii,"/",ncoeff_out,"): ", terms_tmp(ii)%name
1763 : ! enddo
1764 : !TEST MS
1765 6 : if(iatom == 1)then
1766 13 : ABI_MALLOC(terms,(size(terms_tmp)))
1767 1 : call coeffs_list_copy(terms,terms_tmp)
1768 : else
1769 12 : ABI_MALLOC(terms_to_copy,(size(terms_tmp)))
1770 : ! note: when iatom>1, terms is already initialized.
1771 4 : nterm1 = size(terms)
1772 145 : ABI_MALLOC(terms_tmp2,(nterm1))
1773 4 : terms_tmp2 = terms
1774 44 : terms_to_copy = .TRUE.
1775 44 : do iterm1=1,size(terms_tmp)
1776 795 : do iterm2=1,size(terms)
1777 791 : if(terms_tmp(iterm1) == terms(iterm2))then
1778 0 : terms_to_copy(iterm1) = .FALSE.
1779 0 : exit
1780 : endif
1781 : enddo!iterm1
1782 : enddo!iterm2
1783 44 : ncopy = count(terms_to_copy)
1784 4 : call polynomial_coeff_list_free(terms)
1785 185 : ABI_MALLOC(terms,(nterm1+ncopy))
1786 4 : call coeffs_list_copy(terms(:nterm1),terms_tmp2)
1787 4 : ind = 0
1788 44 : do i =1,size(terms_tmp)
1789 44 : if(terms_to_copy(i))then
1790 40 : ind=ind+1
1791 : call polynomial_coeff_init(terms_tmp(i)%coefficient,terms_tmp(i)%nterm,terms(nterm1+ind),terms_tmp(i)%terms,&
1792 40 : & terms_tmp(i)%name,check=.TRUE.)
1793 : !DMSG(terms(nterm1+ind)%debug_str)
1794 : endif
1795 : enddo!i=1,nterm1+ncopy
1796 4 : call polynomial_coeff_list_free(terms_tmp)
1797 4 : call polynomial_coeff_list_free(terms_tmp2)
1798 4 : ABI_SFREE(terms_to_copy)
1799 : endif!iatom==1
1800 : enddo !iatom=1,natom
1801 : ! call polynomial_coeff_getNorder(terms,crystal,cutoff,ncoeff,ncoeff_out,power_disp,&
1802 : !& power_strph,option_GN,sc_size,comm,anharmstr=.false.,spcoupling=.false.,&
1803 : !& only_odd_power=.false.,only_even_power=.true.,verbose=.false.,&
1804 : !& compute_symmetric=.false.)
1805 :
1806 : endif !option
1807 : !TEST MS
1808 : ! write(std_out,*) "behind call getNorder"
1809 : ! write(std_out,*) "ncoeff_out: ", size(terms)
1810 : ! do ii=1,size(terms)
1811 : ! write(*,*) "Term(",ii,"/",size(terms),"): ", terms(ii)%name
1812 : ! enddo
1813 : !TEST MS
1814 :
1815 1 : end subroutine opt_getSingleDispTerms
1816 : !!***
1817 :
1818 : !!****f* m_opt_effpot/opt_getHOSingleDispTerms
1819 : !!
1820 : !! NAME
1821 : !! opt_getHOSingleDispTerms
1822 : !!
1823 : !! FUNCTION
1824 : !! For a given anharmonic term that might consits of product of
1825 : !! terms find all even high order single displacement terms
1826 : !! Example: Input term: x*y*z
1827 : !! Input HO-range: 6 8
1828 : !! Output terms: x^6,x^8,y^6,y^8,z^6,z^8
1829 : !! Caution only atomic displacements are taken into account
1830 : !!
1831 : !! INPUTS
1832 : !! term_in<polynomial_coeff_type>: input anharmonic term
1833 : !! crystal<type(crystal_t)>: all information about the crystal
1834 : !! single_disp_terms<polynomial_coeff_out>: list of single disp terms at
1835 : !! second order to select terms from
1836 : !! power_disp(2): Start and stop power for HO terms
1837 : !! comm: mpi communicator (at the moment only sequential tested)
1838 : !!
1839 : !! OUTPUT
1840 : !! terms_out<polynomial_coeff_out>: output high order even terms
1841 : !! ncoeff: number of coefficients
1842 : !!
1843 : !! SOURCE
1844 :
1845 1 : subroutine opt_getHOSingleDispTerms(term_in,terms_out,symbols,single_disp_terms,power_disp,ncoeff)
1846 :
1847 : !Arguments ------------------------------------
1848 : !scalars
1849 : integer,intent(out) :: ncoeff
1850 : type(polynomial_coeff_type),intent(in) :: term_in
1851 : type(polynomial_coeff_type),intent(in) :: single_disp_terms(:)
1852 : type(polynomial_coeff_type),allocatable,intent(out) :: terms_out(:)
1853 : !type(crystal_t),intent(inout) :: crystal
1854 : !arrays
1855 : integer, intent(in) :: power_disp(2)
1856 : character(len=5),intent(in) :: symbols(:)
1857 : !Logicals
1858 : !Strings
1859 : !Local variables ------------------------------
1860 : !scalars
1861 : integer :: ndisp,norder, nterm_of_term
1862 : integer :: icoeff,iorder,idisp, iterm1,iterm2,iterm3
1863 : real(dp) :: coeff_ini = 1
1864 : !Strings
1865 : character(len=200):: name
1866 : !arrays
1867 : type(polynomial_coeff_type),allocatable :: terms_out_tmp(:)
1868 : !Logicals
1869 1 : logical,allocatable :: found(:)
1870 : !*************************************************************************
1871 : !Get/Set Variables
1872 : !Number of output terms
1873 1 : ndisp = term_in%terms(1)%ndisp
1874 1 : norder = abs(power_disp(2)-power_disp(1))/2 + 1
1875 1 : ncoeff = norder * ndisp
1876 : !Allocate output terms
1877 5 : ABI_MALLOC(terms_out_tmp,(ncoeff))
1878 : !find equivalent second order terms in list of single disp terms
1879 : !for each displacement in input term
1880 : !Transfer to output term and increase order
1881 1 : icoeff = 0
1882 3 : do idisp=1,ndisp
1883 103 : do iterm1=1,size(single_disp_terms)
1884 2346 : do iterm2=1,single_disp_terms(iterm1)%nterm
1885 2980 : if(all(term_in%terms(1)%atindx(:,idisp) == single_disp_terms(iterm1)%terms(iterm2)%atindx(:,1)))then
1886 606 : if(all(term_in%terms(1)%cell(:,:,idisp) == single_disp_terms(iterm1)%terms(iterm2)%cell(:,:,1)))then
1887 6 : if(term_in%terms(1)%direction(idisp) == single_disp_terms(iterm1)%terms(iterm2)%direction(1))then
1888 4 : do iorder=1,norder
1889 2 : icoeff = icoeff + 1
1890 32 : terms_out_tmp(icoeff) = single_disp_terms(iterm1)
1891 2 : nterm_of_term = single_disp_terms(iterm1)%nterm
1892 : !Change order of term
1893 : call polynomial_coeff_init(coeff_ini,nterm_of_term,terms_out_tmp(icoeff),&
1894 2 : & single_disp_terms(iterm1)%terms(:), check=.true.)
1895 : !DMSG(terms_out_tmp(icoeff)%debug_str)
1896 :
1897 34 : do iterm3=1,nterm_of_term
1898 62 : terms_out_tmp(icoeff)%terms(iterm3)%power_disp = power_disp(1) + (iorder-1)*2
1899 : enddo !iterm3
1900 : enddo !iorder
1901 : endif
1902 : endif
1903 : endif
1904 : enddo !iterm2
1905 : enddo !iterm1
1906 : enddo!idisp
1907 : !Change Name
1908 3 : do icoeff=1,ncoeff
1909 2 : call polynomial_coeff_getName(name,terms_out_tmp(icoeff),symbols,recompute=.TRUE.)
1910 3 : call polynomial_coeff_SetName(name,terms_out_tmp(icoeff))
1911 : enddo
1912 :
1913 : !Check for doubles and delete them
1914 : !First count irreducible terms
1915 3 : ABI_MALLOC(found,(ncoeff))
1916 3 : found = .FALSE.
1917 : iterm3 = 0
1918 3 : do iterm1=1,ncoeff
1919 4 : do iterm2=iterm1+1,ncoeff
1920 3 : if(terms_out_tmp(iterm1) == terms_out_tmp(iterm2) .and. .not. found(iterm2))then
1921 0 : found(iterm2) = .TRUE.
1922 0 : iterm3 = iterm3 + 1
1923 : endif
1924 : enddo
1925 : enddo
1926 1 : iterm3 = ncoeff - iterm3
1927 5 : ABI_MALLOC(terms_out,(iterm3))
1928 1 : iterm3 = 0
1929 3 : do iterm1=1,ncoeff
1930 3 : if(.not. found(iterm1))then
1931 2 : iterm3 = iterm3 + 1
1932 : call polynomial_coeff_init(coeff_ini,terms_out_tmp(iterm1)%nterm,terms_out(iterm3),&
1933 2 : & terms_out_tmp(iterm1)%terms,terms_out_tmp(iterm1)%name, check=.TRUE.)
1934 : !DMSG(terms_out(iterm3)%debug_str)
1935 : endif
1936 : enddo
1937 1 : ABI_SFREE(found)
1938 1 : call polynomial_coeff_list_free(terms_out_tmp)
1939 1 : ncoeff = iterm3
1940 1 : end subroutine opt_getHOSingleDispTerms
1941 : !!***
1942 :
1943 :
1944 :
1945 : !!****f* m_opt_effpot/opt_boundcoeff
1946 : !! NAME
1947 : !! opt_boundcoeff
1948 : !!
1949 : !! FUNCTION
1950 : !!
1951 : !! optimize a bound coefficient if optimized value is negative
1952 : !! put an positive value that respects a precision penalty
1953 : !!
1954 : !! INPUTS
1955 : !!
1956 : !! OUTPUT
1957 : !!
1958 : !! SOURCE
1959 :
1960 1 : function opt_boundcoeff(yvalues,cvalues,penalty_in) result (coeff)
1961 : !Arguments ------------------------------------
1962 :
1963 : !Arguments ------------------------------------
1964 : real(dp),intent(in) :: yvalues(2),cvalues(2),penalty_in
1965 : real(dp) :: coeff
1966 : !local
1967 : !variable
1968 : real(dp) :: a,b,coeff_tmp,x1,x2,penalty
1969 : !array
1970 : ! *************************************************************************
1971 :
1972 1 : a = ( (yvalues(1) - 1) - (yvalues(2)-1)*(cvalues(1)/cvalues(2))) / (cvalues(1)**2 - cvalues(1)*cvalues(2))
1973 :
1974 : b = ( (yvalues(2) - 1)/cvalues(2) ) - ( (yvalues(1) -1)*cvalues(2) - (yvalues(2) - 1)*cvalues(1) )&
1975 1 : & / (cvalues(1)**2 - cvalues(1)*cvalues(2))
1976 :
1977 1 : penalty = penalty_in - 1
1978 1 : if (a/=a .or. b/=b .or. a==0) then
1979 1 : coeff = 0.0_dp
1980 : return
1981 : end if
1982 1 : coeff_tmp = -b/(2*a)
1983 : !write(*,*) "coeff_tmp", coeff_tmp
1984 1 : if(coeff_tmp > 0)then
1985 : coeff = coeff_tmp
1986 : else
1987 1 : x1 = (-b + sqrt(b**2 + 4*a*penalty)) / (2*a) ! 1.001 penalty value
1988 1 : x2 = (-b - sqrt(b**2 + 4*a*penalty)) / (2*a)
1989 1 : if(x1>0)then
1990 : coeff = x1
1991 : else
1992 0 : coeff = x2
1993 : endif
1994 : endif
1995 :
1996 : end function opt_boundcoeff
1997 : !!***
1998 :
1999 : !!****f* m_opt_effpot/check_to_skip
2000 : !! NAME
2001 : !! check_to_skip
2002 : !!
2003 : !! FUNCTION
2004 : !!
2005 : !! Check if term contains only bodies with even power
2006 : !! and has a positive coefficient. If yes term doesn't need
2007 : !! a bounding high order equivalent and we can skip it.
2008 : !! Function retursn logical to_skip.
2009 : !!
2010 : !! INPUTS
2011 : !!
2012 : !! term<polynomial_coeff_type>:anharmonic term
2013 : !!
2014 : !! OUTPUT
2015 : !!
2016 : !! logical: to_skip
2017 : !!
2018 : !! SOURCE
2019 :
2020 1 : function check_to_skip(term) result (to_skip)
2021 : !Arguments ------------------------------------
2022 : type(polynomial_coeff_type),intent(in) :: term
2023 : logical :: to_skip
2024 : ! ------------------------------------
2025 : !local
2026 : !variable
2027 : character(len=1000) :: message
2028 : !array
2029 : ! *************************************************************************
2030 :
2031 1 : to_skip = .FALSE.
2032 : ! Let's check if we really want all this mess
2033 : ! If the term is even and its coefficient positive we skip it. Also here we take terms(1) as example for all equivalent terms of term
2034 2 : if(term%coefficient > 0 .and. .not. any(mod(term%terms(1)%power_disp(:),2) /= 0))then
2035 0 : if(.not. any(mod(term%terms(1)%power_strain(:),2) /= 0))then
2036 : ! Message to Output
2037 0 : write(message,'(3a)' )ch10,&
2038 0 : & ' ==> No need for high order bounding term',ch10
2039 0 : call wrtout(ab_out,message,'COLL')
2040 0 : call wrtout(std_out,message,'COLL')
2041 0 : to_skip = .TRUE.
2042 0 : return
2043 : end if
2044 : end if
2045 :
2046 : end function check_to_skip
2047 : !!***
2048 :
2049 2 : subroutine generate_bounding_term_and_add_to_list(sympairs, nterm_start, ncombi, my_coeffs, temp_cntr)
2050 : ! check if myterm
2051 : !type(polynomial_coeff_type),target, intent(in) :: terms(:)
2052 :
2053 : type(polynomial_coeff_type), allocatable, intent(inout) :: my_coeffs(:)
2054 : type(SymPairs_t), intent(inout) :: sympairs
2055 : integer, intent(in) :: nterm_start, ncombi
2056 : integer, intent(out) :: temp_cntr
2057 :
2058 2 : type(polynomial_term_type), allocatable :: terms2(:)
2059 : type(polynomial_term_type), pointer :: myterm=> null()
2060 : type(polynomial_coeff_type), target, allocatable :: my_coeffs_tmp(:)
2061 : integer :: idisp, my_nrpt, list_cntr, number_coeff, icombi
2062 : integer :: jterm
2063 : integer :: tmp_list(5), pwr
2064 : logical :: found
2065 : logical :: reverse_i, any_exists
2066 2 : logical, allocatable :: reverse(:), false_reverse(:), exists(:)
2067 : integer :: counter, nterm, tot_power
2068 2 : type(polynomial_coeff_type):: temp_coeff
2069 2 : integer, allocatable :: list_disp(:)
2070 : character(len=200):: name
2071 : integer :: ncoeff
2072 :
2073 : ! copy the coefficients to a temporary array my_coeffs_tmp
2074 2 : ncoeff=size(my_coeffs)
2075 :
2076 :
2077 12 : ABI_MALLOC(my_coeffs_tmp,(ncoeff))
2078 :
2079 : ! check if my_coeffs i allocated and has the right size
2080 2 : if(.not. allocated(my_coeffs)) then
2081 0 : ABI_BUG("my_coeffs is not allocated")
2082 : end if
2083 2 : if(size(my_coeffs) /= ncoeff) then
2084 0 : ABI_BUG("my_coeffs has the wrong size")
2085 : end if
2086 2 : if(size(my_coeffs_tmp) /= ncoeff) then
2087 0 : ABI_BUG("my_coeffs_tmp has the wrong size")
2088 : end if
2089 :
2090 2 : my_coeffs_tmp=my_coeffs
2091 :
2092 : !call coeffs_list_copy(my_coeffs_tmp, my_coeffs)
2093 :
2094 : ! free the original array and allocate a new one with the correct size
2095 2 : call polynomial_coeff_list_free(my_coeffs)
2096 10 : ABI_MALLOC(my_coeffs, (ncoeff))
2097 : !my_coeffs(1:nterm_start) = my_coeffs_tmp(1:nterm_start)
2098 2 : call coeffs_list_copy(my_coeffs(1:nterm_start), my_coeffs_tmp(1:nterm_start))
2099 :
2100 :
2101 :
2102 2 : temp_cntr =0
2103 5 : do icombi=1, ncombi
2104 3 : if(size( my_coeffs_tmp(nterm_start+icombi)%terms) == 0) cycle
2105 3 : myterm=> my_coeffs_tmp(nterm_start+icombi)%terms(1)
2106 8 : tot_power=sum(myterm%power_disp) + sum(myterm%power_strain)
2107 9 : ABI_MALLOC(list_disp, (tot_power))
2108 6 : ABI_MALLOC(reverse, (tot_power))
2109 6 : ABI_MALLOC(false_reverse, (tot_power))
2110 :
2111 21 : list_disp(:)=0
2112 21 : reverse(:)=.False.
2113 21 : false_reverse(:)=.False.
2114 3 : counter=0
2115 : ! put the indices of the disp terms into a list
2116 5 : do idisp=1,myterm%ndisp
2117 : ! for each disp, find its index in the pair list.
2118 2 : my_nrpt=find_irpt(cells=sympairs%cell, cell=myterm%cell(:, 2, idisp))
2119 : tmp_list(:) = (/myterm%direction(idisp),myterm%atindx(1,idisp), &
2120 12 : & myterm%atindx(2,idisp),my_nrpt,int(myterm%weight) /)
2121 2 : found=.False. ! to find if the symmetry adapted term already exist.
2122 2 : reverse_i=.False.
2123 1518 : do list_cntr=1,size(sympairs%list_symcoeff, 2)
2124 : !do isym=1, sympairs%nsym
2125 2220 : if (all(tmp_list(:4)==sympairs%list_symcoeff(:4,list_cntr,1))) then
2126 2 : number_coeff = sympairs%list_symcoeff(6,list_cntr,1)
2127 2 : found = .True.
2128 : !if (found) exit
2129 : end if
2130 : !end do
2131 : !if(found) exit
2132 : end do
2133 2 : if(.not. found) then
2134 0 : reverse_i=.True.
2135 0 : my_nrpt=find_irpt(cells=sympairs%cell, cell=-myterm%cell(:, 2, idisp))
2136 : tmp_list(:) = (/myterm%direction(idisp),myterm%atindx(2,idisp), &
2137 0 : & myterm%atindx(1,idisp),my_nrpt,-int(myterm%weight) /)
2138 0 : do list_cntr=1,size(sympairs%list_symcoeff, 2)
2139 : !do isym=1, sympairs%nsym
2140 0 : if (all(tmp_list(:4)==sympairs%list_symcoeff(:4,list_cntr,1))) then
2141 0 : number_coeff = sympairs%list_symcoeff(6,list_cntr,1)
2142 0 : found = .True.
2143 : !if (found) exit
2144 : end if
2145 : !end do
2146 : !if(found) exit
2147 : end do
2148 : end if
2149 :
2150 3 : if (found )then
2151 6 : do pwr=1,myterm%power_disp(idisp)
2152 4 : counter=counter+1
2153 4 : list_disp(counter) = number_coeff
2154 6 : reverse(counter) = reverse_i
2155 : end do
2156 : else
2157 0 : ABI_BUG("The pair is not found in generated bounding terms.")
2158 : end if
2159 : end do
2160 :
2161 6 : do idisp=1,myterm%nstrain
2162 20 : do pwr=1,myterm%power_strain(idisp)
2163 14 : counter = counter+1
2164 17 : list_disp(counter) = myterm%strain(idisp)+size(sympairs%list_symcoeff,2)
2165 : end do
2166 : end do
2167 3 : nullify(myterm)
2168 :
2169 : ! generate the terms with false reverse, and save to the temp_coeff.
2170 3 : nterm=sympairs%nsym
2171 153 : ABI_MALLOC(terms2, (nterm))
2172 3 : call sympairs%generateTerms(list_disp, tot_power, nterm, terms2, reverse=false_reverse)
2173 : call polynomial_coeff_init(one,nterm,temp_coeff, &
2174 3 : &terms2(1:nterm), check=.true.)
2175 3 : call polynomial_term_list_free(terms2)
2176 : !DMSG(temp_coeff%debug_str)
2177 :
2178 : call polynomial_coeff_getName(name, &
2179 3 : & temp_coeff,sympairs%symbols,recompute=.TRUE.)
2180 :
2181 : ! check if temp coeff already exists in the list of coeffs my_coeffs
2182 9 : ABI_MALLOC(exists, (nterm_start+icombi-1))
2183 9 : exists=.False.
2184 9 : do jterm=1,(nterm_start+icombi-1)
2185 9 : exists(jterm) = coeffs_compare(my_coeffs(jterm),temp_coeff)
2186 : enddo !jterm
2187 3 : call polynomial_coeff_free(temp_coeff)
2188 :
2189 9 : any_exists=any(exists)
2190 3 : ABI_FREE(exists)
2191 :
2192 : ! if the term already exists, we skip it. Otherwise we add also the reverse.
2193 3 : if (.not. any_exists) then
2194 3 : temp_cntr = temp_cntr+1
2195 153 : ABI_MALLOC(terms2, (nterm))
2196 3 : call sympairs%generateTerms(list_disp, tot_power, nterm, terms2, reverse=reverse)
2197 : call polynomial_coeff_init(one,nterm, &
2198 3 : & my_coeffs(nterm_start+temp_cntr),terms2, check=.true.)
2199 : !DMSG(my_coeffs(nterm_start+temp_cntr)%debug_str)
2200 3 : call polynomial_term_list_free(terms2)
2201 : end if
2202 :
2203 3 : ABI_SFREE(list_disp)
2204 3 : ABI_SFREE(reverse)
2205 5 : ABI_SFREE(false_reverse)
2206 : end do
2207 :
2208 2 : call polynomial_coeff_list_free(my_coeffs_tmp)
2209 :
2210 : ! truncate my_coeffs.
2211 2 : call coeffs_list_truncate(my_coeffs, nterm_start+temp_cntr)
2212 2 : end subroutine generate_bounding_term_and_add_to_list
2213 :
2214 :
2215 : end module m_opt_effpot
2216 : !!***
|