Line data Source code
1 : !!****m* ABINIT/m_paw_gaussfit
2 : !! NAME
3 : !! m_paw_gaussfit
4 : !!
5 : !! FUNCTION
6 : !! Module to fit PAW related data to sums of gaussians
7 : !!
8 : !! COPYRIGHT
9 : !! Copyright (C) 2012-2026 ABINIT group (T. Rangel)
10 : !! This file is distributed under the terms of the
11 : !! GNU General Public License, see ~abinit/COPYING
12 : !! or http://www.gnu.org/copyleft/gpl.txt .
13 : !!
14 : !! NOTES
15 : !! FOR DEVELOPPERS: in order to preserve the portability of libPAW library,
16 : !! please consult ~abinit/src/??_libpaw/libpaw-coding-rules.txt
17 : !!
18 : !! SOURCE
19 :
20 : #include "libpaw.h"
21 :
22 : module m_paw_gaussfit
23 :
24 : USE_DEFS
25 : USE_MSG_HANDLING
26 : USE_MPI_WRAPPERS
27 : USE_MEMORY_PROFILING
28 :
29 : use m_paw_numeric, only : paw_splint, paw_spline
30 : use m_pawrad, only : pawrad_type, pawrad_init, pawrad_deducer0, pawrad_free, pawrad_ifromr
31 :
32 : implicit none
33 :
34 : private
35 :
36 : public:: gaussfit_projector !fit non-local projectors to a sum of gaussians
37 : public:: gaussfit_main !main routine to fit
38 : !Routines related to MPI:
39 : private:: gaussfit_mpi_set_weight
40 : private:: gaussfit_mpi_remove_item
41 : private:: gaussfit_mpi_add_item
42 : private:: gaussfit_mpi_assign
43 : private:: gaussfit_mpi_main
44 : private:: gaussfit_mpi_calc_deviation
45 : private:: gaussfit_mpi_swap
46 : !Routines related to fitting:
47 : private:: gaussfit_fit !fit a function to gaussians
48 : private:: gaussfit_calc_deriv_r !calc. derivatives for real gauss.
49 : private:: gaussfit_calc_deriv_c !calc. derivatives for cplex. gauss. of form 1
50 : private:: gaussfit_calc_deriv_c2 !calc. derivatives for cplex. gauss. of form 2
51 : private:: gaussfit_calc_deriv_c3 !calc. derivatives for cplex. gauss. of form 3
52 : private:: gaussfit_calc_deriv_c4 !calc. derivatives for cplex. gauss. of form 4
53 : private:: gaussfit_rlsf !retreined least squares fit
54 : private:: gaussfit_chisq_alpha_beta
55 : !set parameters for LSF (for 5 different forms of gauss. sums):
56 : private:: gaussfit_set_param1
57 : private:: gaussfit_set_param2
58 : private:: gaussfit_set_param3
59 : private:: gaussfit_set_param4
60 : private:: gaussfit_set_param5
61 : private:: gaussfit_constrains_init !initialize constrains
62 : private:: gaussfit_apply_constrains !apply cons. to get new params.
63 :
64 : !!***
65 : integer,private,parameter:: positive=2
66 : integer,private,parameter:: restricted=3
67 : integer,private,parameter:: restricted_and_positive=4
68 :
69 : CONTAINS
70 : !===========================================================
71 : !!***
72 :
73 : !!****f* m_paw_gaussfit/gaussfit_main
74 : !! NAME
75 : !! gaussfit_main
76 : !!
77 : !! FUNCTION
78 : !! Fits a given input function f(r) to a sum of gaussians
79 : !!
80 : !! INPUTS
81 : !! nterm_bounds= sets the minimum and maximum number of terms to be taken into account.
82 : !! mparam= maximum number of parameters
83 : !! if(option==1)mparam=nterm_bounds(2)*4
84 : !! if(option==2)mparam=nterm_bounds(2)*6
85 : !! if(option==3)mparam=nterm_bounds(2)*2
86 : !! if(option==4)mparam=nterm_bounds(2)*4
87 : !! nr= number of real space points
88 : !! pawrad= pawrad type
89 : !! option=1 fit to a1 cos(a2 x^2)+ a3 sin( a4 x^2)
90 : !! 2 fit to a1 exp(-a2 x^2)*(a3 cos (a4 x^2) + a5 sin (a6 x^2) )
91 : !! 3 fit to a1 cos (k x^2) + a2 sin (k x^2)
92 : !! 4 fit to a1 exp(-a2 x^2)* (a3 cos(k x^2)+ a4 sin (k x^2))
93 : !! Given these definitions, the number of complex gaussians are:
94 : !! ngauss=4*nterm (for option=1,2)
95 : !! ngauss=2*nterm (for option=3,4)
96 : !! outfile= filename to write out fitted functions.
97 : !! rpaw=paw radius
98 : !! y(nr)= function to fit
99 : !!
100 : !! OUTPUT
101 : !! nparam_out= number of parameters found.
102 : !! param_out(nparam_out)= parameters (coefficients and factors of complex gaussians).
103 : !!
104 : !! SOURCE
105 :
106 0 : subroutine gaussfit_main(mparam,nparam_out,nterm_bounds,nr,&
107 0 : & param_out,pawrad,option,outfile,rpaw,y,comm_mpi)
108 :
109 : !Arguments ------------------------------------
110 : integer,intent(in)::mparam,nr,nterm_bounds(2)
111 : integer,intent(in)::option
112 : integer,intent(in),optional:: comm_mpi
113 : real(dp),intent(in)::rpaw
114 : real(dp),intent(inout)::y(nr)
115 : character(80),intent(in)::outfile
116 : type(pawrad_type),intent(in) :: pawrad
117 : integer,intent(out)::nparam_out
118 : real(dp),intent(out)::param_out(mparam)
119 :
120 : !Local variables-------------------------------
121 : !scalars
122 : logical,parameter::modify_y=.false. !used only for plotting purposes
123 : integer :: ichisq,ierr,ii,jj
124 : integer :: master,me
125 : integer :: maxiter,minterm,my_chisq_size,counts_all
126 : integer :: ngauss,nparam,nproc,nterm
127 : integer :: verbosity
128 : real(dp) :: chisq,chisq_min
129 : !real(dp) :: T1,T2 !uncomment for timming
130 : !arrays
131 0 : integer::constrains(mparam)
132 0 : integer::proc_dist(nterm_bounds(1):nterm_bounds(2))
133 0 : integer,allocatable::counts(:),disp(:),map_nterm(:)
134 0 : real(dp)::limit(mparam),param_tmp(mparam),weight(mparam)
135 0 : real(dp),allocatable::chisq_array(:),recv_buf(:),send_buf(:)
136 0 : real(dp),allocatable::y_out(:)
137 : character(len=500) :: msg
138 :
139 : ! *************************************************************************
140 :
141 : !initialize variables
142 0 : maxiter=200
143 : !
144 : !initialize mpi quantities:
145 0 : master=0; me=0; nproc=1; proc_dist=1;
146 0 : if(present(comm_mpi)) then
147 0 : me=xmpi_comm_rank(comm_mpi)
148 0 : nproc=xmpi_comm_size(comm_mpi)
149 : end if
150 0 : if(nproc>1) then
151 : ! Find distribution (master)
152 0 : if(me==master) then
153 0 : call gaussfit_mpi_main(nproc,nterm_bounds,proc_dist)
154 : end if
155 : ! send distribution to all processors
156 : call xmpi_bcast(proc_dist(nterm_bounds(1):nterm_bounds(2)),&
157 0 : & master,comm_mpi,ierr)
158 : end if
159 : !Set size of chisq treated by each proc
160 0 : my_chisq_size=nterm_bounds(2)-nterm_bounds(1)+1 !all terms
161 0 : if(nproc>1 .and. .not. me==master) then
162 0 : do nterm=nterm_bounds(1),nterm_bounds(2)
163 0 : if(.not. proc_dist(nterm)==me+1) cycle
164 0 : my_chisq_size=my_chisq_size+1
165 : end do
166 : end if
167 :
168 : !
169 : !Allocate objects
170 : !
171 0 : LIBPAW_ALLOCATE(y_out,(nr))
172 0 : LIBPAW_ALLOCATE(chisq_array,(my_chisq_size))
173 0 : if(master==me ) then
174 0 : LIBPAW_BOUND1_ALLOCATE(map_nterm,BOUNDS(nterm_bounds(1),nterm_bounds(2)))
175 0 : jj=1
176 0 : do ii=1,nproc
177 0 : do nterm=nterm_bounds(1),nterm_bounds(2)
178 0 : if(proc_dist(nterm)==ii) then
179 0 : map_nterm(nterm)=jj
180 0 : jj=jj+1
181 : end if
182 : end do
183 : end do
184 : end if
185 : !
186 : !fill with zeros
187 : !
188 0 : chisq_array=zero
189 0 : nparam_out=0
190 0 : y_out=0.d0
191 0 : verbosity=1 !print the minimum at the terminal
192 : !
193 0 : ichisq=0
194 0 : do nterm=nterm_bounds(1),nterm_bounds(2)
195 : ! mpi distribution
196 0 : if(.not. proc_dist(nterm)==me+1) cycle
197 0 : ichisq=ichisq+1
198 :
199 : ! call CPU_TIME(T1)
200 :
201 0 : if(option==1) nparam=nterm*4
202 0 : if(option==2) nparam=nterm*6
203 0 : if(option==3) nparam=nterm*2
204 0 : if(option==4) nparam=nterm*4
205 : ! set initial guess
206 : ! if(option==1) then
207 : ! call gaussfit_set_param3(nterm,nparam,param_tmp(1:nparam),sep(ii))
208 : ! elseif(option==2) then
209 : ! call gaussfit_set_param1(nterm,nparam,nr,&
210 : !& param_tmp(1:nparam),sep(ii),pawrad%rad(1:nr),y)
211 0 : if(option==3) then
212 0 : call gaussfit_set_param4(nparam,param_tmp(1:nparam))
213 0 : elseif(option==4) then
214 : call gaussfit_set_param5(nterm,nparam,nr,&
215 0 : & param_tmp(1:nparam),rpaw,y)
216 : end if
217 : !
218 : !
219 : call gaussfit_constrains_init(weight(1:nparam),constrains(1:nparam),&
220 0 : & limit(1:nparam),nparam,nterm,nr,option,rpaw,y)
221 : !
222 : call gaussfit_fit(chisq,constrains(1:nparam),&
223 : & limit(1:nparam),maxiter,nparam,nterm,nr,option,outfile,param_tmp,&
224 0 : & verbosity,weight(1:nparam),pawrad%rad(1:nr),y,y_out)
225 :
226 : ! if there was an error, set chisq to very high
227 : ! if there is an NaN, for instance:
228 0 : if(abs(chisq+1.d0)<tol8) chisq=99999
229 0 : if(abs(chisq)==chisq*chisq) chisq=99999
230 0 : if(chisq .ne. chisq) chisq=99999
231 : !
232 0 : chisq_array(ichisq)=chisq
233 :
234 : ! call CPU_TIME(T2)
235 : ! print *, 'Time for fit ', T2-T1, 'seconds.'
236 :
237 : end do !nterm
238 :
239 : !mpicast results
240 : !send distribution to master
241 0 : if(nproc>1) then
242 : ! Prepare communications:
243 0 : LIBPAW_ALLOCATE(counts,(nproc))
244 0 : counts(:)=0
245 0 : do nterm=nterm_bounds(1),nterm_bounds(2)
246 0 : counts(proc_dist(nterm))=counts(proc_dist(nterm))+1
247 : end do
248 0 : counts_all=sum(counts)
249 0 : LIBPAW_ALLOCATE(send_buf,(counts(me+1)))
250 0 : send_buf(:)=chisq_array(1:counts(me+1))
251 0 : if(me==master) then
252 0 : LIBPAW_ALLOCATE(recv_buf,(counts_all))
253 : else
254 0 : LIBPAW_ALLOCATE(recv_buf,(1))
255 : end if
256 0 : LIBPAW_ALLOCATE(disp,(nproc))
257 0 : disp(1)=0
258 0 : do ii=2,nproc
259 0 : disp(ii)=disp(ii-1)+counts(ii-1)
260 : end do
261 : ! communicate all info to master
262 : call xmpi_gatherv(send_buf,counts(me+1),recv_buf,&
263 0 : & counts,disp,master,comm_mpi,ierr)
264 : ! fill in chisq_array with all received info:
265 0 : if(master==me) then
266 0 : do ii=1,counts_all
267 0 : chisq_array(ii)=recv_buf(ii)
268 : end do
269 : end if
270 : ! Deallocate MPI arrays:
271 0 : LIBPAW_DEALLOCATE(recv_buf)
272 0 : LIBPAW_DEALLOCATE(counts)
273 0 : LIBPAW_DEALLOCATE(disp)
274 0 : LIBPAW_DEALLOCATE(send_buf)
275 : end if
276 :
277 : !Print out info:
278 0 : if(me==master) then
279 0 : write(msg,'(3a)')'Preliminary results (with only 200 iter.):',ch10,' ngauss chisq'
280 0 : call wrtout(std_out,msg,'COLL')
281 0 : do nterm=nterm_bounds(1),nterm_bounds(2)
282 0 : if(option==1) ngauss=nterm*4
283 0 : if(option==2) ngauss=nterm*4
284 0 : if(option==3) ngauss=nterm*2
285 0 : if(option==4) ngauss=nterm*2
286 0 : write(msg,'(i4,2x,e13.6,1x)')ngauss,&
287 0 : & chisq_array(map_nterm(nterm))
288 0 : call wrtout(std_out,msg,'COLL')
289 : end do
290 : end if
291 :
292 : !get minterm for best accuracy:
293 0 : if(me==master) then
294 0 : chisq_min=999999999
295 0 : do nterm=nterm_bounds(1),nterm_bounds(2)
296 0 : if(chisq_array(map_nterm(nterm))<chisq_min) then
297 0 : chisq_min=chisq_array(map_nterm(nterm))
298 0 : minterm=nterm
299 : end if
300 : end do
301 :
302 : !run again with the best parameters
303 0 : nterm=minterm
304 0 : if(option==1)nparam=4*nterm
305 0 : if(option==2)nparam=6*nterm
306 0 : if(option==3)nparam=2*nterm
307 0 : if(option==4)nparam=4*nterm
308 :
309 : ! set initial guess
310 0 : if (option==3) then
311 0 : call gaussfit_set_param4(nparam,param_tmp(1:nparam))
312 0 : elseif (option==4) then
313 : call gaussfit_set_param5(nterm,nparam,nr,&
314 0 : & param_tmp(1:nparam),rpaw,y)
315 : end if
316 : !
317 : call gaussfit_constrains_init(weight(1:nparam),constrains(1:nparam),&
318 0 : & limit(1:nparam),nparam,nterm,nr,option,rpaw,y)
319 : !
320 : verbosity=1;
321 0 : maxiter=1000 !this time we do more iterations
322 : call gaussfit_fit(chisq,constrains(1:nparam),&
323 : & limit(1:nparam),maxiter,nparam,nterm,nr,option,outfile,param_tmp,&
324 0 : & verbosity,weight(1:nparam),pawrad%rad(1:nr),y,y_out)
325 :
326 : ! Write out best solution
327 0 : write(msg,'(3a)')"Best solution (with more iterations):",ch10," ngauss chisq"
328 0 : call wrtout(std_out,msg,'COLL')
329 0 : if(option==1) ngauss=nterm*4
330 0 : if(option==2) ngauss=nterm*4
331 0 : if(option==3) ngauss=nterm*2
332 0 : if(option==4) ngauss=nterm*2
333 0 : write(msg,'(i4,2x,e13.6,1x)')ngauss,chisq
334 0 : call wrtout(std_out,msg,'COLL')
335 : end if
336 :
337 : !Fill output variables
338 : !and communicate results to all procs:
339 0 : if(option==1) then
340 0 : nparam_out=minterm*4
341 0 : elseif (option==2) then
342 0 : nparam_out=minterm*6
343 0 : elseif (option==3) then
344 0 : nparam_out=minterm*2
345 0 : elseif (option==4) then
346 0 : nparam_out=minterm*4
347 : end if
348 :
349 : !communicate
350 0 : if(nproc>1) then
351 0 : call xmpi_bcast(nparam_out,master,comm_mpi,ierr)
352 0 : call xmpi_bcast(param_tmp(1:nparam_out),master,comm_mpi,ierr)
353 : end if !nproc>1
354 :
355 0 : param_out(:)=param_tmp
356 :
357 : if(modify_y) then
358 : ! call xmpi_scatterv(y_out,nr,mpi_displ,y_out,nr,0,comm_mpi,ierr)
359 : y=y_out !at output modify y for the fitted y
360 : end if
361 :
362 0 : LIBPAW_DEALLOCATE(y_out)
363 0 : LIBPAW_DEALLOCATE(chisq_array)
364 0 : if(me==master) then
365 0 : LIBPAW_DEALLOCATE(map_nterm)
366 : end if
367 :
368 0 : end subroutine gaussfit_main
369 : !!***
370 :
371 : !----------------------------------------------------------------------
372 :
373 : !!****f* m_paw_gaussfit/gaussfit_mpi_set_weight
374 : !! NAME
375 : !! gaussfit_mpi_set_weight
376 : !!
377 : !! FUNCTION
378 : !! It sets a weight to the number of
379 : !! Gaussians used.
380 : !! This was calculated by measuring the time
381 : !! it takes to fit a projector with different
382 : !! number of gaussians.
383 : !!
384 : !! INPUTS
385 : !!
386 : !! OUTPUT
387 : !!
388 : !! SOURCE
389 :
390 0 : subroutine gaussfit_mpi_set_weight(f,x)
391 :
392 : !Arguments ------------------------------------
393 : integer,intent(in)::x
394 : integer,intent(out)::f
395 :
396 : !Local variables ------------------------------
397 : real(dp)::a,b,c,d,ff,xx
398 :
399 : !************************************************************************
400 :
401 : !The following parameters were obtained
402 : !from the time (in seconds)
403 : !it takes to fit a given projector
404 : !using from 1 to 100 gaussians.
405 0 : a = -0.374137d0 ! +/- 2.013 (538.1%)
406 0 : b = 0.207854d0 ! +/- 0.3385 (162.8%)
407 0 : c = 0.0266371d0 ! +/- 0.01534 (57.59%)
408 0 : d = 0.000152476d0 ! +/- 0.0001978 (129.7%)
409 :
410 0 : xx=real(x,dp)
411 0 : ff=a+b*xx+c*xx**2+d*xx**3
412 0 : f=max(1,ceiling(ff))
413 :
414 0 : end subroutine gaussfit_mpi_set_weight
415 : !!***
416 :
417 : !----------------------------------------------------------------------
418 :
419 : !!****f* m_paw_gaussfit/gaussfit_mpi_remove_item
420 : !! NAME
421 : !! gaussfit_mpi_remove_item
422 : !!
423 : !! FUNCTION
424 : !!
425 : !! INPUTS
426 : !!
427 : !! OUTPUT
428 : !!
429 : !! SOURCE
430 :
431 0 : subroutine gaussfit_mpi_remove_item(iterm,pload)
432 :
433 : !Arguments ------------------------------------
434 : integer,intent(in)::iterm
435 : integer,intent(inout)::pload
436 :
437 : !Local variables ------------------------------
438 : integer:: f_i
439 :
440 : !***********************************************************************
441 :
442 0 : call gaussfit_mpi_set_weight(f_i,iterm)
443 0 : pload=pload-f_i
444 :
445 0 : end subroutine gaussfit_mpi_remove_item
446 : !!***
447 :
448 : !----------------------------------------------------------------------
449 :
450 : !!****f* m_paw_gaussfit/gaussfit_mpi_add_item
451 : !! NAME
452 : !! gaussfit_mpi_add_item
453 : !!
454 : !! FUNCTION
455 : !!
456 : !! INPUTS
457 : !!
458 : !! OUTPUT
459 : !!
460 : !! SOURCE
461 :
462 0 : subroutine gaussfit_mpi_add_item(iterm,pload)
463 :
464 : !Arguments ------------------------------------
465 : integer,intent(in)::iterm
466 : integer,intent(inout)::pload
467 :
468 : !Local variables ------------------------------
469 : integer:: f_i
470 :
471 : !************************************************************************
472 :
473 0 : call gaussfit_mpi_set_weight(f_i,iterm)
474 0 : pload=pload+f_i
475 :
476 : end subroutine gaussfit_mpi_add_item
477 : !!***
478 :
479 : !----------------------------------------------------------------------
480 :
481 : !!****f* m_paw_gaussfit/gaussfit_mpi_calc_deviation
482 : !! NAME
483 : !! gaussfit_mpi_calc_deviation
484 : !!
485 : !! FUNCTION
486 : !!
487 : !! INPUTS
488 : !!
489 : !! OUTPUT
490 : !!
491 : !! SOURCE
492 :
493 0 : subroutine gaussfit_mpi_calc_deviation(deviation,nproc,proc_load)
494 :
495 : !Arguments ------------------------------------
496 : integer,intent(in)::nproc
497 : integer,intent(in)::proc_load(nproc)
498 : integer,intent(out)::deviation
499 :
500 : !Local variables ------------------------------
501 : integer:: jproc,kproc,kload,jload
502 :
503 : !************************************************************************
504 :
505 : ! deviation=0
506 : ! do jproc=1,nproc
507 : ! deviation=deviation+abs(proc_load(jproc)-ideal)
508 : ! end do
509 :
510 0 : deviation=0
511 0 : do jproc=1,nproc
512 0 : jload=proc_load(jproc)
513 0 : do kproc=1,jproc
514 0 : kload=proc_load(kproc)
515 0 : deviation=deviation+abs(kload-jload)
516 : end do
517 : end do
518 :
519 0 : end subroutine gaussfit_mpi_calc_deviation
520 : !!***
521 :
522 : !----------------------------------------------------------------------
523 :
524 : !!****f* m_paw_gaussfit/gaussfit_mpi_swap
525 : !! NAME
526 : !! gaussfit_mpi_swap
527 : !!
528 : !! FUNCTION
529 : !!
530 : !! INPUTS
531 : !!
532 : !! OUTPUT
533 : !!
534 : !! SOURCE
535 :
536 0 : subroutine gaussfit_mpi_swap(iterm,jterm,&
537 0 : & nproc,nterm_bounds,proc_dist,proc_load)
538 :
539 : !Arguments ------------------------------------
540 : integer,intent(in)::iterm,jterm,nproc,nterm_bounds(2)
541 : integer,intent(inout)::proc_dist(nterm_bounds(1):nterm_bounds(2)),proc_load(nproc)
542 :
543 : !Local variables ------------------------------
544 : integer:: deviation1,deviation2
545 : integer:: iproc,jproc
546 :
547 : !************************************************************************
548 :
549 : !Calculate initial state
550 0 : call gaussfit_mpi_calc_deviation(deviation1,nproc,proc_load)
551 0 : iproc=proc_dist(iterm)
552 0 : jproc=proc_dist(jterm)
553 : !Swap terms:
554 0 : call gaussfit_mpi_add_item(jterm,proc_load(iproc))
555 0 : call gaussfit_mpi_remove_item(iterm,proc_load(iproc))
556 0 : call gaussfit_mpi_add_item(iterm,proc_load(jproc))
557 0 : call gaussfit_mpi_remove_item(jterm,proc_load(jproc))
558 : !Calculate final state
559 0 : call gaussfit_mpi_calc_deviation(deviation2,nproc,proc_load)
560 : !Swap them only if final state is better than the initial one
561 0 : if(deviation2<deviation1) then
562 0 : proc_dist(iterm)=jproc
563 0 : proc_dist(jterm)=iproc
564 : else
565 : ! Return work load to initial state
566 0 : call gaussfit_mpi_add_item(iterm,proc_load(iproc))
567 0 : call gaussfit_mpi_remove_item(jterm,proc_load(iproc))
568 0 : call gaussfit_mpi_add_item(jterm,proc_load(jproc))
569 0 : call gaussfit_mpi_remove_item(iterm,proc_load(jproc))
570 : ! write(*,*)'Back initial state'
571 : ! write(*,*)'proc_load',proc_load(:)
572 : end if
573 :
574 0 : end subroutine gaussfit_mpi_swap
575 : !!***
576 :
577 : !----------------------------------------------------------------------
578 :
579 : !!****f* m_paw_gaussfit/gaussfit_mpi_assign
580 : !! NAME
581 : !! gaussfit_mpi_assign
582 : !!
583 : !! FUNCTION
584 : !! Set task to a processor
585 : !!
586 : !! INPUTS
587 : !!
588 : !! OUTPUT
589 : !!
590 : !! SOURCE
591 :
592 0 : subroutine gaussfit_mpi_assign(iterm,nproc,nterm_bounds,&
593 0 : & proc_dist,proc_load)
594 :
595 : !Arguments ------------------------------------
596 : integer,intent(in)::iterm,nproc,nterm_bounds(2)
597 : integer,intent(inout)::proc_dist(nterm_bounds(1):nterm_bounds(2)),proc_load(nproc)
598 :
599 : !Local variables ------------------------------
600 : integer:: iproc,jproc,dev
601 0 : integer:: deviation(nproc),mindev
602 : character(len=100) :: msg
603 :
604 : !************************************************************************
605 :
606 0 : do iproc=1,nproc
607 : !add this term to iproc
608 0 : call gaussfit_mpi_add_item(iterm,proc_load(iproc))
609 : !calculate the deviation for this configuration
610 0 : call gaussfit_mpi_calc_deviation(dev,nproc,proc_load)
611 0 : deviation(iproc)=dev
612 : !remove this term from iproc
613 0 : call gaussfit_mpi_remove_item(iterm,proc_load(iproc))
614 : end do
615 :
616 : !assign to jproc, the proc with minimal deviation above:
617 : jproc=-1; mindev=999999999
618 0 : do iproc=1,nproc
619 0 : if(deviation(iproc)<mindev) then
620 0 : mindev=deviation(iproc)
621 0 : jproc=iproc
622 : end if
623 : end do
624 0 : if(jproc==-1) then
625 : ! One should not get here!
626 0 : msg = 'error in accomodate_mpi'
627 0 : LIBPAW_BUG(msg)
628 : end if
629 :
630 : !assign this term for jproc
631 0 : proc_dist(iterm)=jproc
632 0 : call gaussfit_mpi_add_item(iterm,proc_load(jproc))
633 :
634 0 : end subroutine gaussfit_mpi_assign
635 : !!***
636 :
637 : !----------------------------------------------------------------------
638 :
639 : !!****f* m_paw_gaussfit/gaussfit_mpi_main
640 : !! NAME
641 : !! gaussfit_mpi_main
642 : !!
643 : !! FUNCTION
644 : !! Set charge for each processor
645 : !!
646 : !! INPUTS
647 : !!
648 : !! OUTPUT
649 : !!
650 : !! SOURCE
651 :
652 0 : subroutine gaussfit_mpi_main(nproc,nterm_bounds,proc_dist)
653 :
654 : !Arguments ------------------------------------
655 : integer,intent(in)::nproc,nterm_bounds(2)
656 : integer,intent(out)::proc_dist(nterm_bounds(1):nterm_bounds(2))
657 :
658 : !Local variables ------------------------------
659 : integer:: dev1,dev2,ii
660 : integer:: iproc,iterm,jterm,ngauss,weight
661 0 : integer:: proc_load(nproc)
662 : character(len=500) :: msg
663 :
664 : !************************************************************************
665 :
666 0 : proc_load=0; proc_dist=0 !initializations
667 :
668 : !1) get a first-trial distribution:
669 0 : do iterm=nterm_bounds(2),nterm_bounds(1),-1
670 0 : call gaussfit_mpi_assign(iterm,nproc,nterm_bounds,proc_dist,proc_load)
671 : end do
672 :
673 : !Do the following 20 times
674 0 : do ii=1,20
675 : ! Calculate initial state
676 0 : call gaussfit_mpi_calc_deviation(dev1,nproc,proc_load)
677 : ! Try to swap tasks between two processors:
678 0 : do iterm=nterm_bounds(2),nterm_bounds(1),-1
679 0 : do jterm=nterm_bounds(2),nterm_bounds(1),-1
680 : call gaussfit_mpi_swap(iterm,jterm,&
681 0 : & nproc,nterm_bounds,proc_dist,proc_load)
682 : end do
683 : end do
684 : !! Try to reassign tasks to different processors
685 0 : do iterm=nterm_bounds(2),nterm_bounds(1),-1
686 0 : iproc=proc_dist(iterm)
687 : ! Remove this job from this node
688 0 : call gaussfit_mpi_remove_item(iterm,proc_load(iproc))
689 : ! Accomodate this again:
690 0 : call gaussfit_mpi_assign(iterm,nproc,nterm_bounds,proc_dist,proc_load)
691 : end do
692 : ! Calculate final state
693 0 : call gaussfit_mpi_calc_deviation(dev2,nproc,proc_load)
694 : ! If final state equals initial state, exit:
695 0 : if(dev2 == dev1) exit
696 : ! write(*,'(a)')'Deviation: ',dev2
697 : end do
698 :
699 : !Write down distribution:
700 0 : write(msg,'(3a)') 'MPI distribution',ch10,'N. gauss, iproc, weight '
701 0 : call wrtout(std_out,msg,'COLL')
702 0 : do iterm=nterm_bounds(2),nterm_bounds(1),-1
703 0 : ngauss=iterm*2
704 0 : call gaussfit_mpi_set_weight(weight,iterm)
705 0 : write(msg,'(3(i4,1x))') ngauss,proc_dist(iterm),weight
706 0 : call wrtout(std_out,msg,'COLL')
707 : end do
708 0 : write(msg,'(a)') 'Load per processor: '
709 0 : call wrtout(std_out,msg,'COLL')
710 0 : do iproc=1,nproc
711 0 : write(msg,'(i5,1x,i10)') iproc,proc_load(iproc)
712 0 : call wrtout(std_out,msg,'COLL')
713 : end do
714 :
715 0 : end subroutine gaussfit_mpi_main
716 : !!***
717 :
718 : !----------------------------------------------------------------------
719 :
720 : !!****f* m_paw_gaussfit/gaussfit_fit
721 : !! NAME
722 : !! gaussfit_fit
723 : !!
724 : !! FUNCTION
725 : !! Fits a given input function f(r) to a sum of gaussians
726 : !!
727 : !! INPUTS
728 : !! chisq= It measures how good is the fitting.
729 : !! It is defined here as sum_i^N_i f(x_i)-y(x_i)/N_i
730 : !! constrains= constraints for Gaussians
731 : !! limit(nparam)= it limits the widths of Gaussians
732 : !! maxiter=maximum number of iterations
733 : !! nparam= number of parameters (a constant times nterm)
734 : !! if(option==1)nparam=nterm*4
735 : !! if(option==2)nparam=nterm*6
736 : !! if(option==3)nparam=nterm*2
737 : !! if(option==4)nparam=nterm*4
738 : !! nterm= number of Gaussians
739 : !! nx=number of points along the x axis
740 : !! option=1 fit to a1 cos(a2 x^2)+ a3 sin( a4 x^2)
741 : !! 2 fit to a1 exp(-a2 x^2)*(a3 cos (a4 x^2) + a5 sin (a6 x^2) )
742 : !! 3 fit to a1 cos (k x^2) + a2 sin (k x^2)
743 : !! 4 fit to a1 exp(-a2 x^2)* (a3 cos(k x^2)+ a4 sin (k x^2))
744 : !! outfile= filename for output (only written if verbosity>1)
745 : !! verbosity= controls output volume
746 : !! weight(nparam)= weights for the fitting procedure
747 : !! x(nx)= points along the x axis
748 : !! y(nx)= function to be fitted
749 : !! rpaw ,optional= paw radius
750 : !!
751 : !! OUTPUT
752 : !! y_out(nx)= fitted function
753 : !!
754 : !! SIDE EFFECTS
755 : !! if(verbosity>1) output files are written with y(x) and y_out(x)
756 : !!
757 : !! SOURCE
758 :
759 0 : subroutine gaussfit_fit(chisq,constrains,&
760 0 : & limit,maxiter,nparam,nterm,nx,option,outfile,param,&
761 0 : & verbosity,weight,x,y,y_out)
762 :
763 : !Arguments ------------------------------------
764 : integer, intent(in) :: maxiter,nparam
765 : integer,intent(in) :: nterm,nx,option,verbosity
766 : !real(dp),optional,intent(in)::rpaw
767 : !arrays
768 : integer,intent(in)::constrains(nparam)
769 : real(dp),intent(in)::limit(nparam),weight(nparam)
770 : real(dp),intent(in)::x(nx),y(nx)
771 : real(dp),intent(inout)::param(nparam)
772 : real(dp),intent(out)::chisq,y_out(nx)
773 : character(80),intent(in)::outfile
774 :
775 : !Local variables ------------------------------
776 : integer, parameter :: wfn_unit=1007
777 : integer::ix
778 : real(dp)::rerror
779 0 : real(dp),allocatable::sy(:)
780 :
781 : ! *************************************************************************
782 :
783 0 : LIBPAW_ALLOCATE(sy,(nx))
784 :
785 0 : sy(:)=1.0d0
786 :
787 : call gaussfit_rlsf(&
788 : & chisq,constrains,limit,maxiter,&
789 : & nterm,nparam,nx,option,param(1:nparam),&
790 0 : & verbosity,weight,x,y)
791 : !
792 0 : if(verbosity>=1) then
793 0 : if(option==1) then
794 0 : call gaussfit_calc_deriv_c2(nparam,nterm,nx,1,param,x,y_out)
795 0 : elseif(option==2) then
796 0 : call gaussfit_calc_deriv_c(nparam,nterm,nx,1,param,x,y_out)
797 0 : elseif(option==3) then
798 0 : call gaussfit_calc_deriv_c3(nparam,nterm,nx,1,param,x,y_out)
799 0 : elseif(option==4) then
800 0 : call gaussfit_calc_deriv_c4(nparam,nterm,nx,1,param,x,y_out)
801 : end if
802 : !
803 : !
804 0 : open(wfn_unit,file=outfile,form='formatted',status='unknown')
805 : ! per_error=0.d0
806 0 : do ix=1, nx
807 0 : rerror=abs(y(ix)-y_out(ix))
808 0 : write(wfn_unit,'(6(e20.12,1x))')x(ix),y(ix),y_out(ix),rerror
809 : end do
810 0 : close(wfn_unit)
811 :
812 : end if
813 :
814 0 : LIBPAW_DEALLOCATE(sy)
815 :
816 0 : end subroutine gaussfit_fit
817 : !!***
818 :
819 : !----------------------------------------------------------------------
820 :
821 : !!****f* m_paw_gaussfit/gaussfit_calc_deriv_r
822 : !! NAME
823 : !! gaussfit_calc_deriv_r
824 : !!
825 : !! FUNCTION
826 : !! Calculate derivatives for Gaussians
827 : !! Only relevant for fitting Gaussians algorithm.
828 : !! The Gaussians expressions are defined in the comments of "gaussfit_main"
829 : !!
830 : !! INPUTS
831 : !!
832 : !! OUTPUT
833 : !!
834 : !! SOURCE
835 :
836 : subroutine gaussfit_calc_deriv_r(nterm,nparam,nx,opt,param,x,y_out,&
837 : & deriv) ! optional
838 :
839 : !Arguments -------------------------------
840 : integer,intent(in)::nx !number of point in the x grid
841 : integer,intent(in)::nparam !number of parameters
842 : integer,intent(in)::nterm !number of gaussian expressions
843 : integer,intent(in)::opt !option:
844 : !1) calculate only f(x)
845 : !2) calculate f(x) and its derivatives
846 : real(dp),intent(in)::param(nparam) !parameters
847 : real(dp),intent(in)::x(nx) !xgrid
848 : real(dp),intent(out)::y_out(nx) !f(x)
849 : real(dp),optional,intent(out)::deriv(nx,nparam) !derivatives
850 :
851 : !Local variables-------------------------------
852 : integer::iexp,ii
853 : real(dp)::alpha1(nterm),alpha2(nterm),alpha3(nterm)
854 : real(dp)::term1(nx,nterm)
855 : real(dp)::aux1(nx)
856 : !real(dp)::step
857 :
858 : ! *********************************************************************
859 :
860 : !
861 : !Initialize
862 : !
863 : y_out(:)=0.d0
864 : !
865 : !Get parameters from parameters array:
866 : !
867 : alpha1(:)=param(1:nterm)
868 : alpha2(:)=param(nterm+1:2*nterm)
869 : alpha3(:)=param(2*nterm+1:3*nterm)
870 : !
871 : !alpha3
872 : !set to constant values of x
873 : !step=rpaw/real(nterm,dp)
874 : !do ii=1,nterm
875 : !raux=step*real(ii,dp)
876 : !alpha3(ii)=raux
877 : !end do
878 : !
879 : !
880 : !
881 : !calculate useful quantities
882 : !
883 : do iexp=1,nterm
884 : aux1(:)=-alpha2(iexp)*(x(:)-alpha3(iexp))**2
885 : term1(:,iexp)=alpha1(iexp)*exp(aux1(:))
886 : end do
887 : !
888 : do iexp=1,nterm
889 : y_out(:)=y_out(:)+term1(:,iexp)
890 : end do
891 : !
892 : !Calculate derivatives:
893 : !
894 : if(opt==2) then
895 : !
896 : ! alpha1
897 : !
898 : do iexp=1,nterm
899 : aux1(:)=term1(:,iexp)/alpha1(iexp)
900 : deriv(:,iexp)=aux1(:)
901 : end do
902 : !
903 : ! alpha2
904 : !
905 : do iexp=1,nterm
906 : ii=nterm+iexp
907 : aux1(:)=-term1(:,iexp)*(x(:)-alpha3(iexp))
908 : deriv(:,ii)=aux1(:)
909 : deriv(:,ii)=0.1d0
910 : end do
911 : !
912 : ! alpha3
913 : !
914 : do iexp=1,nterm
915 : ii=2*nterm+iexp
916 : aux1(:)=term1(:,iexp)*2.d0*alpha2(iexp)
917 : aux1(:)=aux1(:)*(x(:)-alpha3(iexp))
918 : deriv(:,ii)=aux1(:)
919 : end do
920 : end if
921 :
922 : end subroutine gaussfit_calc_deriv_r
923 : !!***
924 :
925 : !----------------------------------------------------------------------
926 :
927 : !!****f* m_paw_gaussfit/gaussfit_calc_deriv_c3
928 : !! NAME
929 : !! gaussfit_calc_deriv_c3
930 : !!
931 : !! FUNCTION
932 : !! Calculate expressions and derivatives for Gaussians fitting.
933 : !! The Gaussians expressions are defined in the comments of "gaussfit_main"
934 : !!
935 : !! INPUTS
936 : !!
937 : !! OUTPUT
938 : !!
939 : !! SOURCE
940 :
941 0 : subroutine gaussfit_calc_deriv_c3(nparam,nterm,nx,opt,param,x,y_out,&
942 0 : & deriv) ! optional
943 :
944 : !Arguments -------------------------------
945 : integer,intent(in)::nparam !number of parameters
946 : integer,intent(in)::nterm !number of gaussian expressions
947 : integer,intent(in)::nx !number of point in the x grid
948 : integer,intent(in)::opt !option:
949 : !1) calculate only f(x)
950 : !2) calculate f(x) and its derivatives
951 : real(dp),intent(in)::param(nparam) !parameters
952 : real(dp),intent(in)::x(nx) !xgrid
953 : real(dp),intent(out)::y_out(nx) !f(x)
954 : real(dp),optional,intent(out)::deriv(nx,nparam) !derivatives
955 :
956 : !Local variables-------------------------------
957 : integer::iexp,ii
958 : real(dp)::sep
959 0 : real(dp)::alpha1(nterm),alpha2(nterm),alpha3(nterm)
960 0 : real(dp)::term1(nx,nterm)
961 0 : real(dp)::sin1(nx,nterm),cos1(nx,nterm)
962 0 : real(dp)::aux1(nx),aux2(nx)
963 :
964 : ! *********************************************************************
965 :
966 : !
967 : !Initialize
968 : !
969 0 : y_out(:)=0.d0
970 : !
971 : sep=1.2d0
972 : !
973 : !Get param from param array:
974 : !
975 0 : alpha1(:)=param(1:nterm)
976 0 : alpha2(:)=param(nterm+1:2*nterm)
977 : !
978 0 : do ii=1,nterm
979 0 : alpha3(ii)=sep**(ii)
980 : end do
981 : !
982 : !calculate useful quantities
983 : !
984 0 : do iexp=1,nterm
985 0 : aux1(:)=alpha3(iexp)*x(:)**2
986 : !
987 0 : sin1(:,iexp)=sin(aux1(:))
988 0 : cos1(:,iexp)=cos(aux1(:))
989 : end do
990 : !
991 0 : do iexp=1,nterm
992 0 : aux1(:)=alpha1(iexp)*sin1(:,iexp)
993 0 : aux2(:)=alpha2(iexp)*cos1(:,iexp)
994 0 : term1(:,iexp)=aux1(:)+aux2(:)
995 0 : y_out(:)=y_out(:)+term1(:,iexp)
996 : end do
997 : !
998 : !Calculate derivatives:
999 : !
1000 0 : if(opt==2) then
1001 : !
1002 : ! alpha1
1003 : !
1004 0 : do iexp=1,nterm
1005 0 : deriv(:,iexp)=sin1(:,iexp)
1006 : end do
1007 : !
1008 : ! alpha2
1009 : !
1010 0 : do iexp=1,nterm
1011 0 : ii=nterm+iexp
1012 0 : deriv(:,ii)=cos1(:,iexp)
1013 : end do
1014 : end if
1015 :
1016 0 : end subroutine gaussfit_calc_deriv_c3
1017 : !!***
1018 :
1019 : !----------------------------------------------------------------------
1020 :
1021 : !!****f* m_paw_gaussfit/gaussfit_calc_deriv_c2
1022 : !! NAME
1023 : !! gaussfit_calc_deriv_c2
1024 : !!
1025 : !! FUNCTION
1026 : !! Calculate expressions and derivatives for Gaussians fitting.
1027 : !! The Gaussians expressions are defined in the comments of "gaussfit_main"
1028 : !!
1029 : !! INPUTS
1030 : !!
1031 : !! OUTPUT
1032 : !!
1033 : !! SOURCE
1034 :
1035 0 : subroutine gaussfit_calc_deriv_c2(nparam,nterm,nx,opt,param,x,y_out,&
1036 0 : & deriv) ! optional
1037 :
1038 : !Arguments -------------------------------
1039 : integer,intent(in)::nparam !number of param
1040 : integer,intent(in)::nterm !number of gaussian expressions
1041 : integer,intent(in)::nx !number of point in the x grid
1042 : integer,intent(in)::opt !option:
1043 : !1) calculate only f(x)
1044 : !2) calculate f(x) and its derivatives
1045 : real(dp),intent(in)::param(nparam) !parameters
1046 : real(dp),intent(in)::x(nx) !xgrid
1047 : real(dp),intent(out)::y_out(nx) !f(x)
1048 : real(dp),optional,intent(out)::deriv(nx,nparam) !derivatives
1049 :
1050 : !Local variables-------------------------------
1051 : integer::iexp,ii
1052 0 : real(dp)::alpha1(nterm),alpha2(nterm),alpha3(nterm)
1053 0 : real(dp)::alpha4(nterm)
1054 0 : real(dp)::term1(nx,nterm)
1055 0 : real(dp)::sin1(nx,nterm),sin2(nx,nterm),cos1(nx,nterm),cos2(nx,nterm)
1056 0 : real(dp)::aux1(nx),aux2(nx)
1057 :
1058 : ! *********************************************************************
1059 :
1060 : !
1061 : !Initialize
1062 : !
1063 0 : y_out(:)=0.d0
1064 : !
1065 : !Get param from param array:
1066 : !
1067 0 : alpha1(:)=param(1:nterm)
1068 0 : alpha2(:)=param(nterm+1:2*nterm)
1069 0 : alpha3(:)=param(2*nterm+1:3*nterm)
1070 0 : alpha4(:)=param(3*nterm+1:4*nterm)
1071 : !
1072 : !calculate useful quantities
1073 : !
1074 : !
1075 0 : do iexp=1,nterm
1076 0 : aux1(:)=alpha2(iexp)*x(:)**2
1077 0 : sin1(:,iexp)=sin(aux1(:))
1078 : !
1079 0 : aux1(:)=alpha4(iexp)*x(:)**2
1080 0 : sin2(:,iexp)=sin(aux1(:))
1081 : !
1082 0 : aux1(:)=alpha2(iexp)*x(:)**2
1083 0 : cos1(:,iexp)=cos(aux1(:))
1084 : !
1085 0 : aux1(:)=alpha4(iexp)*x(:)**2
1086 0 : cos2(:,iexp)=cos(aux1(:))
1087 : end do
1088 : !
1089 0 : do iexp=1,nterm
1090 0 : aux1(:)=alpha1(iexp)*sin1(:,iexp)
1091 0 : aux2(:)=alpha3(iexp)*cos2(:,iexp)
1092 0 : term1(:,iexp)=aux1(:)+aux2(:)
1093 0 : y_out(:)=y_out(:)+term1(:,iexp)
1094 : end do
1095 : !
1096 : !Calculate derivatives:
1097 : !
1098 0 : if(opt==2) then
1099 : !
1100 : ! alpha1
1101 : !
1102 0 : do iexp=1,nterm
1103 0 : deriv(:,iexp)=sin1(:,iexp)
1104 : end do
1105 : !
1106 : ! alpha2
1107 : !
1108 0 : do iexp=1,nterm
1109 0 : ii=nterm+iexp
1110 0 : aux1(:)=alpha1(iexp)*cos1(:,iexp)*x(:)**2
1111 0 : deriv(:,ii)=aux1(:)
1112 : end do
1113 : !
1114 : ! alpha3
1115 : !
1116 0 : do iexp=1,nterm
1117 0 : ii=2*nterm+iexp
1118 0 : deriv(:,ii)=cos2(:,iexp)
1119 : end do
1120 : !
1121 : ! alpha4
1122 : !
1123 0 : do iexp=1,nterm
1124 0 : ii=3*nterm+iexp
1125 0 : aux1(:)=-alpha3(iexp)*sin2(:,iexp)*x(:)**2
1126 0 : deriv(:,ii)=aux1(:)
1127 : end do
1128 : end if
1129 :
1130 0 : end subroutine gaussfit_calc_deriv_c2
1131 : !!***
1132 :
1133 : !----------------------------------------------------------------------
1134 :
1135 : !!****f* m_paw_gaussfit/gaussfit_calc_deriv_c
1136 : !! NAME
1137 : !! gaussfit_calc_deriv_c
1138 : !!
1139 : !! FUNCTION
1140 : !! Calculate expressions and derivatives for Gaussians fitting.
1141 : !! The Gaussians expressions are defined in the comments of "gaussfit_main"
1142 : !!
1143 : !! INPUTS
1144 : !!
1145 : !! OUTPUT
1146 : !!
1147 : !! SOURCE
1148 :
1149 0 : subroutine gaussfit_calc_deriv_c(nparam,nterm,nx,opt,param,x,y_out,&
1150 0 : & deriv) ! optional
1151 :
1152 : !Arguments -------------------------------
1153 : integer,intent(in)::nparam !number of parameters
1154 : integer,intent(in)::nterm !number of gaussian expressions
1155 : integer,intent(in)::nx !number of point in the x grid
1156 : integer,intent(in)::opt !option:
1157 : !1) calculate only f(x)
1158 : !2) calculate f(x) and its derivatives
1159 : real(dp),intent(in)::param(nparam) !parameters
1160 : real(dp),intent(in)::x(nx) !xgrid
1161 : real(dp),intent(out)::y_out(nx) !f(x)
1162 : real(dp),optional,intent(out)::deriv(nx,nparam) !derivatives
1163 :
1164 : !Local variables-------------------------------
1165 : integer::iexp,ii
1166 0 : real(dp)::alpha1(nterm),alpha2(nterm),alpha3(nterm)
1167 0 : real(dp)::alpha4(nterm),alpha5(nterm),alpha6(nterm)
1168 0 : real(dp)::aux1(nx),aux2(nx)
1169 0 : real(dp)::cos1(nx,nterm),cos2(nx,nterm),sin1(nx,nterm),sin2(nx,nterm)
1170 0 : real(dp)::term1(nx,nterm),term2(nx,nterm)
1171 :
1172 : ! *********************************************************************
1173 :
1174 : !
1175 : !Initialize
1176 : !
1177 0 : y_out(:)=0.d0
1178 : !
1179 : !Get parameters from param array:
1180 : !
1181 0 : alpha1(:)=param(1:nterm)
1182 0 : alpha2(:)=param(nterm+1:2*nterm)
1183 0 : alpha3(:)=param(2*nterm+1:3*nterm)
1184 0 : alpha4(:)=param(3*nterm+1:4*nterm)
1185 0 : alpha5(:)=param(4*nterm+1:5*nterm)
1186 0 : alpha6(:)=param(5*nterm+1:6*nterm)
1187 : !
1188 : !calculate useful quantities
1189 : !
1190 0 : do iexp=1,nterm
1191 0 : aux1(:)=-alpha2(iexp)*x(:)**2
1192 0 : term1(:,iexp)=alpha1(iexp)*exp(aux1(:))
1193 : end do
1194 : !
1195 0 : do iexp=1,nterm
1196 0 : aux1(:)=alpha4(iexp)*x(:)**2
1197 0 : sin1(:,iexp)=sin(aux1(:))
1198 : !
1199 0 : aux1(:)=alpha6(iexp)*x(:)**2
1200 0 : sin2(:,iexp)=sin(aux1(:))
1201 : !
1202 0 : aux1(:)=alpha4(iexp)*x(:)**2
1203 0 : cos1(:,iexp)=cos(aux1(:))
1204 : !
1205 0 : aux1(:)=alpha6(iexp)*x(:)**2
1206 0 : cos2(:,iexp)=cos(aux1(:))
1207 : end do
1208 : !
1209 0 : do iexp=1,nterm
1210 0 : aux1(:)=alpha3(iexp)*sin1(:,iexp)
1211 0 : aux2(:)=alpha5(iexp)*cos2(:,iexp)
1212 0 : term2(:,iexp)=aux1(:)+aux2(:)
1213 0 : y_out(:)=y_out(:)+term1(:,iexp)*term2(:,iexp)
1214 : end do
1215 : !
1216 : !Calculate derivatives:
1217 : !
1218 0 : if(opt==2) then
1219 : !
1220 : ! alpha1
1221 : !
1222 0 : do iexp=1,nterm
1223 0 : aux1(:)=term1(:,iexp)/alpha1(iexp)
1224 0 : aux2(:)=aux1(:)*term2(:,iexp)
1225 0 : deriv(:,iexp)=aux2(:)
1226 : end do
1227 : !
1228 : ! alpha2
1229 : !
1230 0 : do iexp=1,nterm
1231 0 : ii=nterm+iexp
1232 0 : aux1(:)=-term1(:,iexp)*term2(:,iexp)
1233 0 : aux2(:)=aux1(:)*x(:)**2
1234 0 : deriv(:,ii)=aux2(:)
1235 : end do
1236 : !
1237 : ! alpha3
1238 : !
1239 0 : do iexp=1,nterm
1240 0 : ii=2*nterm+iexp
1241 0 : aux1(:)=term1(:,iexp)*sin1(:,iexp)
1242 0 : deriv(:,ii)=aux1(:)
1243 : end do
1244 : !
1245 : ! alpha4
1246 : !
1247 0 : do iexp=1,nterm
1248 0 : ii=3*nterm+iexp
1249 0 : aux1(:)=term1(:,iexp)*alpha3(iexp)
1250 0 : aux2(:)=cos1(:,iexp)*x(:)**2
1251 0 : deriv(:,ii)=aux2(:)*aux1(:)
1252 : end do
1253 : !
1254 : ! alpha5
1255 : !
1256 0 : do iexp=1,nterm
1257 0 : ii=4*nterm+iexp
1258 0 : aux1(:)=term1(:,iexp)*cos2(:,iexp)
1259 0 : deriv(:,ii)=aux1(:)
1260 : end do
1261 : !
1262 : ! alpha6
1263 : !
1264 0 : do iexp=1,nterm
1265 0 : ii=5*nterm+iexp
1266 0 : aux1(:)=-term1(:,iexp)*alpha5(iexp)
1267 0 : aux2(:)=sin2(:,iexp)*x(:)**2
1268 0 : deriv(:,ii)=aux1(:)*aux2(:)
1269 : end do
1270 : end if
1271 :
1272 0 : end subroutine gaussfit_calc_deriv_c
1273 : !!***
1274 :
1275 : !----------------------------------------------------------------------
1276 :
1277 : !!****f* m_paw_gaussfit/gaussfit_calc_deriv_c4
1278 : !! NAME
1279 : !! gaussfit_calc_deriv_c4
1280 : !!
1281 : !! FUNCTION
1282 : !! Calculate expressions and derivatives for Gaussians fitting.
1283 : !! The Gaussians expressions are defined in the comments of "gaussfit_main"
1284 : !!
1285 : !! INPUTS
1286 : !!
1287 : !! OUTPUT
1288 : !!
1289 : !! SOURCE
1290 :
1291 0 : subroutine gaussfit_calc_deriv_c4(nparam,nterm,nx,opt,param,x,y_out,&
1292 0 : & deriv) ! optional
1293 :
1294 : !Arguments -------------------------------
1295 : integer,intent(in)::nparam !number of parameters
1296 : integer,intent(in)::nterm !number of gaussian expressions
1297 : integer,intent(in)::nx !number of point in the x grid
1298 : integer,intent(in)::opt !option:
1299 : !1) calculate only f(x)
1300 : !2) calculate f(x) and its derivatives
1301 : real(dp),intent(in)::param(nparam) !parameters
1302 : real(dp),intent(in)::x(nx) !xgrid
1303 : real(dp),intent(out)::y_out(nx) !f(x)
1304 : real(dp),optional,intent(out)::deriv(nx,nparam) !derivatives
1305 :
1306 : !Local variables-------------------------------
1307 : integer::iexp,ii
1308 : real(dp)::raux,sep
1309 0 : real(dp)::alpha1(nterm),alpha2(nterm),alpha3(nterm)
1310 0 : real(dp)::alpha4(nterm),alpha5(nterm)
1311 0 : real(dp)::aux1(nx),aux2(nx)
1312 0 : real(dp)::cos1(nx,nterm),sin1(nx,nterm)
1313 0 : real(dp)::term1(nx,nterm),term2(nx,nterm)
1314 :
1315 : ! *********************************************************************
1316 :
1317 : !
1318 : !Initialize
1319 : !
1320 0 : sep=1.1d0
1321 0 : y_out(:)=0.d0
1322 :
1323 : !Get parameters from param array:
1324 : !
1325 0 : alpha1(:)=param(1:nterm)
1326 0 : alpha2(:)=param(nterm+1:2*nterm)
1327 0 : alpha3(:)=param(2*nterm+1:3*nterm)
1328 0 : alpha4(:)=param(3*nterm+1:4*nterm)
1329 : !
1330 : !
1331 0 : raux=(2.d0*pi)/real(nterm,dp)
1332 0 : do ii=1,nterm
1333 0 : alpha5(ii)=sep**(ii)
1334 : ! alpha5(ii)=raux*real(ii-1,dp)
1335 : end do
1336 : !
1337 : !calculate useful quantities
1338 : !
1339 0 : do iexp=1,nterm
1340 0 : aux1(:)=-alpha2(iexp)*x(:)**2
1341 0 : term1(:,iexp)=alpha1(iexp)*exp(aux1(:))
1342 : end do
1343 : !
1344 0 : do iexp=1,nterm
1345 0 : aux1(:)=alpha5(iexp)*x(:)**2
1346 : !
1347 0 : sin1(:,iexp)=sin(aux1(:))
1348 0 : cos1(:,iexp)=cos(aux1(:))
1349 : end do
1350 : !
1351 0 : do iexp=1,nterm
1352 0 : aux1(:)=alpha3(iexp)*sin1(:,iexp)
1353 0 : aux2(:)=alpha4(iexp)*cos1(:,iexp)
1354 0 : term2(:,iexp)=aux1(:)+aux2(:)
1355 0 : y_out(:)=y_out(:)+term1(:,iexp)*term2(:,iexp)
1356 : end do
1357 : !
1358 : !Calculate derivatives:
1359 : !
1360 0 : if(opt==2) then
1361 : !
1362 : ! alpha1
1363 : !
1364 0 : do iexp=1,nterm
1365 0 : aux1(:)=term1(:,iexp)/alpha1(iexp)
1366 0 : aux2(:)=aux1(:)*term2(:,iexp)
1367 0 : deriv(:,iexp)=aux2(:)
1368 : end do
1369 : !
1370 : ! alpha2
1371 : !
1372 0 : do iexp=1,nterm
1373 0 : ii=nterm+iexp
1374 0 : aux1(:)=-term1(:,iexp)*term2(:,iexp)
1375 0 : aux2(:)=aux1(:)*x(:)**2
1376 0 : deriv(:,ii)=aux2(:)
1377 : end do
1378 : !
1379 : ! alpha3
1380 : !
1381 0 : do iexp=1,nterm
1382 0 : ii=2*nterm+iexp
1383 0 : aux1(:)=term1(:,iexp)*sin1(:,iexp)
1384 0 : deriv(:,ii)=aux1(:)
1385 : end do
1386 : !
1387 : ! alpha4
1388 : !
1389 0 : do iexp=1,nterm
1390 0 : ii=3*nterm+iexp
1391 0 : aux1(:)=term1(:,iexp)*cos1(:,iexp)
1392 0 : deriv(:,ii)=aux1(:)
1393 : end do
1394 : end if
1395 :
1396 0 : end subroutine gaussfit_calc_deriv_c4
1397 : !!***
1398 :
1399 : !----------------------------------------------------------------------
1400 :
1401 : !!****f* m_paw_gaussfit/gaussfit_rlsf
1402 : !! NAME
1403 : !! gaussfit_rlsf
1404 : !!
1405 : !! FUNCTION
1406 : !! Fits a given function to a sum of Gaussians.
1407 : !! Uses the Levenberg-Marquardt algorithm.
1408 : !!
1409 : !! COPYRIGHT
1410 : !! Copyright (C) 2011-2026 ABINIT group (T. Rangel)
1411 : !! This file is distributed under the terms of the
1412 : !! GNU General Public License, see ~abinit/COPYING
1413 : !! or http://www.gnu.org/copyleft/gpl.txt .
1414 : !! The original Levemberg Marquardt routines were written by Armando Sole
1415 : !! These were modified for the ARPUS spectra in the BigDFT code by A. Mirone.
1416 : !! These were re-writen in Fortran and further modified in ABINIT for our particular needs.
1417 : !!
1418 : !! INPUTS
1419 : !! option=1 fit to a1 cos(a2 x^2)+ a3 sin( a4 x^2)
1420 : !! 2 fit to a1 exp(-a2 x^2)*(a3 cos (a4 x^2) + a5 sin (a6 x^2) )
1421 : !! 3 fit to a1 cos (k x^2) + a2 sin (k x^2)
1422 : !! 4 fit to a1 exp(-a2 x^2)* (a3 cos(k x^2)+ a4 sin (k x^2))
1423 : !! if(option==1)mparam=nterm_bounds(2)*4
1424 : !! if(option==2)mparam=nterm_bounds(2)*6
1425 : !! if(option==3)mparam=nterm_bounds(2)*2
1426 : !! if(option==4)mparam=nterm_bounds(2)*4
1427 : !!
1428 : !! OUTPUT
1429 : !!
1430 : !! SOURCE
1431 :
1432 0 : subroutine gaussfit_rlsf(&
1433 0 : &chisq,constrains,limit,maxiter,&
1434 0 : &nterm,nparam,nx,option,parameters,&
1435 0 : &verbosity,weight,x,y)
1436 :
1437 : !Arguments -------------------------------
1438 : real(dp),parameter::deltachi=tol10
1439 : integer, intent(in) ::maxiter,nparam,nterm,nx
1440 : integer, intent(in) ::option ,verbosity
1441 : integer, intent(in) ::constrains(nparam)
1442 : real(dp),intent(out)::chisq
1443 : !arrays
1444 : real(dp),intent(in)::limit(nparam),weight(nparam)
1445 : real(dp),intent(inout)::parameters(nparam)
1446 : real(dp),intent(in)::x(nx),y(nx)
1447 :
1448 : !Local variables-------------------------------
1449 : integer::flag,ii,info,iter,jj,niter
1450 : real(dp):: deltax
1451 : real(dp)::chisq0,flambda,eta,lastdeltachi
1452 0 : integer::ipvt(nparam)
1453 0 : real(dp)::alpha(nparam,nparam)
1454 0 : real(dp)::alpha0(nparam,nparam),beta(nparam)
1455 0 : real(dp)::deltapar(nparam)
1456 0 : real(dp)::tmp1(nparam,nparam)
1457 0 : real(dp)::work(nparam)
1458 0 : real(dp)::workpar(nparam)
1459 0 : real(dp)::yfit(nx)
1460 : character(len=500) :: msg
1461 :
1462 : ! *********************************************************************
1463 :
1464 : !
1465 : !flambda=1e-6
1466 0 : flambda=1e-7
1467 : !iter=maxiter !later it is changed
1468 0 : niter=0
1469 0 : deltax=x(2)-x(1) !we assume this is a linear grid
1470 : !
1471 0 : iter_loop: do iter=1,maxiter
1472 : !
1473 : call gaussfit_chisq_alpha_beta(alpha0,beta,chisq0,&
1474 0 : & nparam,nterm,nx,option,parameters,x,y)
1475 : !
1476 0 : flag=0
1477 0 : lastdeltachi=chisq0
1478 : !
1479 : !
1480 0 : while_flag: do
1481 : if(flag .ne. 0) exit while_flag
1482 : !
1483 0 : tmp1=0.d0
1484 0 : do ii=1,nparam
1485 0 : tmp1(ii,ii)=1.d0*flambda !identity matrix * flambda
1486 : end do
1487 0 : alpha=alpha0+tmp1*alpha0
1488 : ! Invert alpha matrix
1489 0 : tmp1=alpha
1490 0 : call dgetrf(nparam,nparam,tmp1,nparam,ipvt,info)
1491 0 : if (.not.info==0) then
1492 0 : if(verbosity>1) then
1493 0 : write(msg,'(a)')'Matrix is singular'
1494 0 : call wrtout(std_out,msg,'COLL')
1495 : end if
1496 0 : chisq=-1.d0
1497 0 : exit iter_loop
1498 : end if
1499 0 : call dgetri(nparam,tmp1,nparam,ipvt,work,nparam,info)
1500 0 : deltapar=0.d0
1501 0 : if (.not.info==0) then
1502 0 : if(verbosity>2) then
1503 0 : write(msg,'(a)')'Matrix is singular'
1504 0 : call wrtout(std_out,msg,'COLL')
1505 : end if
1506 0 : chisq=-1.d0
1507 0 : exit iter_loop
1508 : end if
1509 : !
1510 0 : if(tmp1(1,1) .ne. tmp1(1,1)) then !If is NaN
1511 0 : chisq=-1.d0
1512 0 : exit iter_loop
1513 : end if
1514 0 : if(abs(tmp1(1,1)) == tmp1(1,1)*tmp1(1,1)) then !If is infinity
1515 0 : chisq=-1.d0
1516 0 : exit iter_loop
1517 : end if
1518 : !
1519 0 : do ii=1,nparam
1520 0 : do jj=1,nparam
1521 0 : deltapar(ii)=deltapar(ii)+beta(jj)*tmp1(jj,ii)
1522 : end do
1523 : end do
1524 : ! apply constrains
1525 0 : workpar(1:nparam)=parameters(1:nparam)+deltapar(1:nparam)*weight(1:nparam)
1526 0 : call gaussfit_apply_constrains(constrains,limit,nparam,workpar)
1527 : !
1528 0 : if(option==1) then
1529 0 : call gaussfit_calc_deriv_c2(nparam,nterm,nx,1,workpar,x,yfit)
1530 0 : elseif(option==2) then
1531 0 : call gaussfit_calc_deriv_c(nparam,nterm,nx,1,workpar,x,yfit)
1532 0 : elseif(option==3) then
1533 0 : call gaussfit_calc_deriv_c3(nparam,nterm,nx,1,workpar,x,yfit)
1534 0 : elseif(option==4) then
1535 0 : call gaussfit_calc_deriv_c4(nparam,nterm,nx,1,workpar,x,yfit)
1536 : end if
1537 0 : chisq=0.d0
1538 0 : do ii=1,nx
1539 0 : chisq=chisq + ((y(ii)-yfit(ii)))**2
1540 : end do
1541 0 : chisq=chisq*deltax
1542 : !
1543 : ! write(*,'("chisq ",f12.5," chisq0 ",f12.5)')chisq,chisq0
1544 : !
1545 0 : if(chisq > chisq0) then
1546 0 : flambda=flambda*2.0d0
1547 0 : if( flambda > 1000.d0) then
1548 0 : flag=1
1549 : ! iter=0
1550 0 : if(verbosity>2) then
1551 0 : write(msg,'(a)')'flambda > 1000.d0'
1552 0 : call wrtout(std_out,msg,'COLL')
1553 : end if
1554 : exit iter_loop
1555 : end if
1556 : else
1557 0 : flag=1
1558 0 : parameters=workpar
1559 0 : eta=0.d0
1560 0 : lastdeltachi=(chisq0-chisq) !/(chisq0+eta)
1561 0 : if(lastdeltachi<deltachi) cycle
1562 0 : chisq0=chisq
1563 0 : flambda=flambda/2.d0
1564 0 : if(verbosity>2) then
1565 0 : write(msg,'("iter = ",i4," chisq = ",e15.6)')iter,chisq
1566 0 : call wrtout(std_out,msg,'COLL')
1567 : end if
1568 : end if
1569 : end do while_flag
1570 : end do iter_loop
1571 :
1572 0 : end subroutine gaussfit_rlsf
1573 : !!***
1574 :
1575 : !----------------------------------------------------------------------
1576 :
1577 : !!****f* m_paw_gaussfit/gaussfit_chisq_alpha_beta
1578 : !! NAME
1579 : !! gaussfit_chisq_alpha_beta
1580 : !!
1581 : !! FUNCTION
1582 : !! Finds chisq, alpha and beta parameters for LSF using the Levenberg-Marquardt algorithm.
1583 : !!
1584 : !! COPYRIGHT
1585 : !! Copyright (C) 2011-2026 ABINIT group (T. Rangel)
1586 : !! This file is distributed under the terms of the
1587 : !! GNU General Public License, see ~abinit/COPYING
1588 : !! or http://www.gnu.org/copyleft/gpl.txt .
1589 : !! The original Levemberg Marquardt routines were written by Armando Sole
1590 : !! These were modified for the ARPUS spectra in the BigDFT code by A. Mirone.
1591 : !! These were re-writen in Fortran and further modified in ABINIT for our particular needs.
1592 : !!
1593 : !! INPUTS
1594 : !!
1595 : !! OUTPUT
1596 : !!
1597 : !! SOURCE
1598 :
1599 0 : subroutine gaussfit_chisq_alpha_beta(alpha,beta,chisq,&
1600 0 : & nparam,nterm,nx,option,parameters,x,y)
1601 :
1602 : !Arguments -------------------------------
1603 : integer,intent(in)::nparam,nterm,nx
1604 : integer,intent(in)::option
1605 : real(dp),intent(out)::chisq
1606 : real(dp),intent(in)::parameters(nparam),x(nx),y(nx)
1607 : real(dp),intent(out)::alpha(nparam,nparam),beta(nparam)
1608 :
1609 : !Local variables-------------------------------
1610 : integer::ii,jj,kk
1611 : real(dp)::deltax,help1
1612 : !arrays
1613 0 : real(dp)::deltay(nx),deriv(nx,nparam),derivi(nx)
1614 0 : real(dp)::yfit(nx)
1615 0 : real(dp)::help0(nx),help2(nx),help3(nparam)
1616 :
1617 : ! *********************************************************************
1618 :
1619 0 : deltax=x(2)-x(1) !we assume a linear grid
1620 : !
1621 0 : if(option==1) then
1622 0 : call gaussfit_calc_deriv_c2(nparam,nterm,nx,2,parameters,x,yfit,deriv)
1623 0 : elseif(option==2) then
1624 0 : call gaussfit_calc_deriv_c(nparam,nterm,nx,2,parameters,x,yfit,deriv)
1625 0 : elseif(option==3) then
1626 0 : call gaussfit_calc_deriv_c3(nparam,nterm,nx,2,parameters,x,yfit,deriv)
1627 0 : elseif(option==4) then
1628 0 : call gaussfit_calc_deriv_c4(nparam,nterm,nx,2,parameters,x,yfit,deriv)
1629 : end if
1630 0 : deltay=y-yfit
1631 0 : help0=deltay
1632 : !
1633 0 : do ii=1,nparam
1634 0 : derivi(:)=deriv(:,ii)
1635 : help1=0.d0
1636 0 : do jj=1,nx
1637 0 : help1=help1+help0(jj)*derivi(jj)
1638 : end do
1639 0 : beta(ii)=help1
1640 : ! help1 = innerproduct(deriv,weight*derivi)
1641 : ! below I use help3 instead for the array dimenstions
1642 0 : help3=0.d0
1643 0 : do kk=1,nparam
1644 0 : do jj=1,nx
1645 0 : help3(kk)=help3(kk)+deriv(jj,kk)*derivi(jj)
1646 : end do
1647 : end do
1648 : ! !
1649 0 : alpha(:,ii)=help3(:)
1650 : end do
1651 : !
1652 0 : help2(:)=help0(:)*deltay(:)
1653 0 : chisq=sum(help2)
1654 0 : chisq=chisq*deltax
1655 :
1656 0 : end subroutine gaussfit_chisq_alpha_beta
1657 : !!***
1658 :
1659 : !----------------------------------------------------------------------
1660 :
1661 : !!****f* m_paw_gaussfit/gaussfit_set_param1
1662 : !! NAME
1663 : !! gaussfit_set_param1
1664 : !!
1665 : !! FUNCTION
1666 : !! Sets parameters for LSF
1667 : !!
1668 : !! INPUTS
1669 : !!
1670 : !! OUTPUT
1671 : !!
1672 : !! SOURCE
1673 :
1674 : subroutine gaussfit_set_param1(nterm,nparam,nx,param,sep,x,y)
1675 :
1676 : !Arguments -------------------------------
1677 : integer,intent(in)::nterm,nparam,nx
1678 : real(dp),intent(in)::sep
1679 : real(dp),intent(in)::x(nx),y(nx)
1680 : real(dp),intent(out)::param(nparam)
1681 :
1682 : !Local variables-------------------------------
1683 : integer::ii,jj
1684 : real(dp)::raux
1685 :
1686 : ! *********************************************************************
1687 :
1688 : !
1689 : param(:)=1.0d0
1690 : !exps=1.0/(x(nx)**2)
1691 : !
1692 : !alpha1
1693 :
1694 : !raux=maxval( y(:),nx )
1695 : !maxval gives problems in some architectures:
1696 : raux=-9999999
1697 : do ii=1,nx
1698 : if(raux<y(ii)) raux=y(ii)
1699 : end do
1700 : param(1:nterm)=raux
1701 : !
1702 : !alpha2
1703 : !
1704 : !y(r_c)=e^{-\alpha1 r_c}
1705 : raux=-log(abs(y(nx))+tol10)/(x(nx)**2)
1706 : param(nterm+1:nterm+2)=raux
1707 : !
1708 : !raux=0.5d0*pi/real(nterm,dp)
1709 : do jj=1,nterm
1710 : ii=jj+3*nterm
1711 : param(ii)=sep**(jj)
1712 : ! param(ii)=raux*real(jj,dp)
1713 : end do
1714 : !
1715 : do jj=1,nterm
1716 : ii=jj+5*nterm
1717 : param(ii)=sep**(jj)
1718 : ! param(ii)=raux*real(jj,dp)
1719 : end do
1720 :
1721 : end subroutine gaussfit_set_param1
1722 : !!***
1723 :
1724 : !----------------------------------------------------------------------
1725 :
1726 : !!****f* m_paw_gaussfit/gaussfit_set_param2
1727 : !! NAME
1728 : !! gaussfit_set_param2
1729 : !!
1730 : !! FUNCTION
1731 : !! Sets parameters for LSF
1732 : !!
1733 : !! INPUTS
1734 : !!
1735 : !! OUTPUT
1736 : !!
1737 : !! SOURCE
1738 :
1739 : subroutine gaussfit_set_param2(nterm,nparam,nx,param,rpaw,x,y)
1740 :
1741 : !Arguments -------------------------------
1742 : integer,intent(in)::nterm,nparam,nx
1743 : real(dp),intent(in)::rpaw
1744 : real(dp),intent(in)::x(nx),y(nx)
1745 : real(dp),intent(out)::param(nparam)
1746 :
1747 : !Local variables-------------------------------
1748 : integer::ii,jj
1749 : real(dp)::exps,raux,sig,step
1750 :
1751 : ! *************************************************************************
1752 :
1753 : step=rpaw/real(nterm-1,dp)
1754 : !exps=1.0/(rpaw/(real(nterm,dp)/2.d0))**2
1755 : exps=1.0/(step*1.0d0)**2
1756 : !alpha2 (width of gaussians)
1757 : !Set to exps*real(nterm,dp)**2, for a good guess
1758 : param(nterm+1:2*nterm)=exps !*real(nterm,dp)**2
1759 : !
1760 : do jj=1,nterm
1761 : ! alpha3
1762 : ! set to constant values of x
1763 : ii=jj+2*nterm
1764 : raux=step*real(jj-1,dp)
1765 : param(ii)=raux
1766 : ! alpha1
1767 : ! set to the value of y at that point
1768 : call gaussfit_param2_findsign()
1769 : param(jj)=sig
1770 : end do
1771 : !
1772 : contains
1773 : !!***
1774 :
1775 : !!****f* gaussfit_set_param2/gaussfit_param2_findsign
1776 : !! NAME
1777 : !! gaussfit_param2_findsign
1778 : !!
1779 : !! FUNCTION
1780 : !! Finds the value of y at a given point
1781 : !! This was taken out of gaussfit_set_param2 to make the code more
1782 : !! readable.
1783 : !!
1784 : !! INPUTS
1785 : !!
1786 : !! OUTPUT
1787 : !!
1788 : !! SOURCE
1789 :
1790 : subroutine gaussfit_param2_findsign()
1791 :
1792 : !Arguments -------------------------------
1793 : !Local variables-------------------------------
1794 : integer::ix,minx
1795 : real(dp)::dist,mindist,xx,yy
1796 :
1797 : ! *********************************************************************
1798 :
1799 : mindist=rpaw
1800 : do ix=1,nx
1801 : xx=x(ix)
1802 : dist=abs(raux-xx)
1803 : if(dist<mindist) then
1804 : mindist=dist
1805 : minx=ix
1806 : end if
1807 : end do
1808 : yy=y(minx)
1809 : sig=yy
1810 :
1811 : end subroutine gaussfit_param2_findsign
1812 :
1813 : end subroutine gaussfit_set_param2
1814 : !!***
1815 :
1816 : !----------------------------------------------------------------------
1817 :
1818 : !!****f* m_paw_gaussfit/gaussfit_set_param3
1819 : !! NAME
1820 : !! gaussfit_set_param3
1821 : !!
1822 : !! FUNCTION
1823 : !! Sets parameters for LSF
1824 : !!
1825 : !! INPUTS
1826 : !!
1827 : !! OUTPUT
1828 : !!
1829 : !! SOURCE
1830 :
1831 : subroutine gaussfit_set_param3(nterm,nparam,param,sep)
1832 :
1833 : !Arguments -------------------------------
1834 : integer,intent(in)::nterm,nparam
1835 : real(dp),intent(in)::sep
1836 : !real(dp),intent(in)::x(nx),y(nx)
1837 : real(dp),intent(out)::param(nparam)
1838 :
1839 : !Local variables-------------------------------
1840 : integer::ii,jj
1841 :
1842 : ! *********************************************************************
1843 :
1844 : param(:)=1.0d0
1845 : !
1846 : do jj=1,nterm
1847 : ii=jj+nterm
1848 : param(ii)=sep**(jj)
1849 : ! param(ii)=raux*real(i,dp)
1850 : end do
1851 : !
1852 : do jj=1,nterm
1853 : ii=jj+3*nterm
1854 : param(ii)=sep**(jj)
1855 : ! param(ii)=raux*real(i,dp)
1856 : end do
1857 :
1858 : end subroutine gaussfit_set_param3
1859 : !!***
1860 :
1861 : !----------------------------------------------------------------------
1862 :
1863 : !!****f* m_paw_gaussfit/gaussfit_set_param4
1864 : !! NAME
1865 : !! gaussfit_set_param4
1866 : !!
1867 : !! FUNCTION
1868 : !! Sets parameters for LSF
1869 : !!
1870 : !! INPUTS
1871 : !!
1872 : !! OUTPUT
1873 : !!
1874 : !! SOURCE
1875 :
1876 0 : subroutine gaussfit_set_param4(nparam,param)
1877 :
1878 : !Arguments -------------------------------
1879 : integer,intent(in)::nparam
1880 : real(dp),intent(out)::param(nparam)
1881 :
1882 : !Local variables-------------------------------
1883 :
1884 : ! *********************************************************************
1885 :
1886 0 : param(:)=1.0d0
1887 :
1888 : end subroutine gaussfit_set_param4
1889 : !!***
1890 :
1891 : !----------------------------------------------------------------------
1892 :
1893 : !!****f* m_paw_gaussfit/gaussfit_set_param5
1894 : !! NAME
1895 : !! gaussfit_set_param5
1896 : !!
1897 : !! FUNCTION
1898 : !! Sets parameters for LSF
1899 : !!
1900 : !! INPUTS
1901 : !!
1902 : !! OUTPUT
1903 : !!
1904 : !! SOURCE
1905 :
1906 0 : subroutine gaussfit_set_param5(nterm,nparam,nx,param,rpaw,y)
1907 :
1908 : !Arguments -------------------------------
1909 : integer,intent(in)::nterm,nparam,nx
1910 : real(dp),intent(in)::rpaw
1911 : real(dp),intent(in)::y(nx)
1912 : real(dp),intent(out)::param(nparam)
1913 :
1914 : !Local variables-------------------------------
1915 : integer::ix
1916 : real(dp)::raux,a1,r_c,m
1917 :
1918 : ! *********************************************************************
1919 :
1920 0 : param(:)=1.0d0
1921 : !
1922 : !alpha1
1923 : !a1=maxval( y(:),nx )
1924 : !maxval gives problems in some architectures:
1925 : a1=-9999999
1926 0 : do ix=1,nx
1927 0 : if(a1<y(ix)) a1=y(ix)
1928 : end do
1929 0 : param(1:nterm)=a1
1930 : !
1931 : !alpha2
1932 : !
1933 0 : r_c=rpaw+0.5d0 !paw sphere + a bit more.
1934 : !this is not arbitrary since it is an initial guess
1935 0 : m=0.01d0
1936 0 : raux=log(a1/m)/r_c**2
1937 0 : param(nterm+1:nterm*2)=raux
1938 :
1939 0 : end subroutine gaussfit_set_param5
1940 : !!***
1941 :
1942 : !----------------------------------------------------------------------
1943 :
1944 : !!****f* m_paw_gaussfit/gaussfit_constrains_init
1945 : !! NAME
1946 : !! gaussfit_constrains_init
1947 : !!
1948 : !! FUNCTION
1949 : !! Initialise constrains for LSF.
1950 : !! It will constrain the Gaussians width
1951 : !! It will also constraint the Delta use in the LSF algorithm, to jump slowly at each step.
1952 : !!
1953 : !! INPUTS
1954 : !!
1955 : !! OUTPUT
1956 : !!
1957 : !! SOURCE
1958 :
1959 0 : subroutine gaussfit_constrains_init(cons1,cons2,limit,nparam,nterm,nx,option,rpaw,y)
1960 :
1961 : !Arguments -------------------------------
1962 : integer,intent(in)::nterm,option,nparam,nx
1963 : integer,intent(out)::cons2(nparam)
1964 : real(dp),intent(in)::rpaw
1965 : real(dp),intent(in)::y(nx)
1966 : real(dp),intent(out)::cons1(nparam),limit(nparam)
1967 :
1968 : !Local variables-------------------------------
1969 : integer :: ix
1970 : real(dp)::rc,a1,mm,raux
1971 :
1972 : ! *********************************************************************
1973 :
1974 : !
1975 : !DEFAULT: no weight
1976 0 : cons1(:)=1.d0
1977 0 : limit(:)=0.d0
1978 0 : cons2=1
1979 : !
1980 0 : if(option==4) then
1981 0 : cons1(1:nterm)=0.2d0
1982 0 : cons1(nterm+1:nterm*2)=0.3d0
1983 : end if
1984 : !
1985 0 : if(option==4) then
1986 : ! parameters
1987 :
1988 : ! a1=maxval( y(:),nx)/real(nterm,dp)
1989 : ! maxval gives problems in some architectures:
1990 : a1=-9999999
1991 0 : do ix=1,nx
1992 0 : if(a1<y(ix)) a1=y(ix)
1993 : end do
1994 0 : a1=a1/real(nterm,dp)
1995 :
1996 0 : mm=0.01
1997 : !
1998 0 : rc=1.7d0*rpaw
1999 0 : raux=log(a1/mm)/rc**2
2000 : !
2001 : ! Constraint exponential of gaussians to be positive (multiplied by -1),
2002 : ! so that it decays to zero.
2003 : ! Constraint as well its value, so that it does not get too big
2004 : ! and it decays soon,
2005 : ! This prevents that a gaussian grows at a very large x value.
2006 0 : cons2(nterm+1:nterm*2)=restricted_and_positive
2007 0 : limit(nterm+1:nterm*2)=raux
2008 : end if
2009 :
2010 0 : end subroutine gaussfit_constrains_init
2011 : !!***
2012 :
2013 : !----------------------------------------------------------------------
2014 :
2015 : !!****f* m_paw_gaussfit/gaussfit_apply_constrains
2016 : !! NAME
2017 : !! gaussfit_apply_constrains
2018 : !!
2019 : !! FUNCTION
2020 : !! Apply constrains to get new set of parameters
2021 : !!
2022 : !! INPUTS
2023 : !!
2024 : !! OUTPUT
2025 : !!
2026 : !! SOURCE
2027 :
2028 0 : subroutine gaussfit_apply_constrains(const,limit,nparam,ioparams)
2029 :
2030 : !Arguments -------------------------------
2031 : integer,intent(in):: nparam
2032 : integer,intent(in):: const(nparam)
2033 : real(dp),intent(in):: limit(nparam)
2034 : real(dp),intent(inout):: ioparams(nparam)
2035 :
2036 : !Local variables-------------------------------
2037 : integer::ii
2038 :
2039 : ! *********************************************************************
2040 :
2041 0 : do ii=1,nparam
2042 0 : if(const(ii)==restricted .or. const(ii)==restricted_and_positive) then
2043 0 : if(ioparams(ii)<limit(ii)) ioparams(ii)=limit(ii)
2044 : end if
2045 0 : if(const(ii)==positive .or. const(ii)==restricted_and_positive ) ioparams(ii)=abs(ioparams(ii))
2046 :
2047 : end do
2048 :
2049 0 : end subroutine gaussfit_apply_constrains
2050 : !!***
2051 :
2052 : !----------------------------------------------------------------------
2053 :
2054 : !!****f* m_paw_gaussfit/gaussfit_projector
2055 : !! NAME
2056 : !! gaussfit_projector
2057 : !!
2058 : !! FUNCTION
2059 : !! Fit tproj to Gaussians
2060 : !!
2061 : !! INPUTS
2062 : !! basis_size= size of the PAW basis
2063 : !! orbitals= indicates the l quantum number for all orbitals.
2064 : !! rpaw= PAW radius
2065 : !! pawrad <type(pawrad_type)>=paw radial mesh and related data
2066 : !! tproj= projectors
2067 : !! maxterm= maximum number of terms used to fit the projectors.
2068 : !! mparam= maximum number of parameters (Gaussian coefficients and factors) used.
2069 : !!
2070 : !! OUTPUT
2071 : !! nparam_array= number of parameters found.
2072 : !! param = parameters found (Gaussian coefficients and factors).
2073 : !!
2074 : !! NOTES
2075 : !! chisq=accuracy_p= sum_x abs(f(x)-y(x))/nx.
2076 : !! nx is the number of points, f(x) and y(x) are the fitted and original functions.
2077 : !!
2078 : !! SOURCE
2079 :
2080 0 : subroutine gaussfit_projector(basis_size,mparam,nparam_array,nterm_bounds,orbitals,param,pawrad,&
2081 0 : & rpaw,tproj,comm_mpi)
2082 :
2083 : !Arguments ------------------------------------
2084 : integer,intent(in) :: basis_size
2085 : integer,intent(in) :: orbitals(basis_size)
2086 : integer, optional,intent(in) :: comm_mpi
2087 : real(dp),intent(in) :: rpaw
2088 : type(pawrad_type),intent(in) :: pawrad
2089 : real(dp),intent(in) :: tproj(:,:)
2090 : integer,intent(in) :: mparam,nterm_bounds(2)
2091 : integer,intent(out) :: nparam_array(basis_size)
2092 : real(dp),intent(out) :: param(mparam,basis_size)
2093 0 : type(pawrad_type)::mesh_tmp
2094 :
2095 : !Local variables ------------------------------
2096 : integer :: ibasis,ierr,il,ir
2097 : integer :: msz1,msz2,option
2098 : real(dp) :: raux(1),rr(1)
2099 0 : real(dp),allocatable :: d2(:),tproj_tmp1(:),tproj_tmp2(:)
2100 : character(len=500) :: msg
2101 : character(80) :: outfile
2102 : !debug: uncomment
2103 : !integer::i,nterm ,unitp
2104 : !real(dp),allocatable::y(:)
2105 : !end debug
2106 :
2107 : !************************************************************************
2108 :
2109 0 : if(size(tproj,2)<basis_size) then
2110 0 : msg = 'wrong size for tproj in gaussfit_projector!'
2111 0 : LIBPAW_BUG(msg)
2112 : end if
2113 :
2114 0 : option=4 !see gaussfit_main
2115 0 : nparam_array(:)=0
2116 0 : msz1=min(pawrad_ifromr(pawrad,rpaw)+2,size(tproj,1))
2117 : !msz1=pawrad%mesh_size
2118 :
2119 : !Augment the mesh size
2120 : !this is to make the Gaussians go to zero after paw_radius
2121 : !This is done by creating a new pawrad objet: mesh_tmp
2122 : !Change to a linear grid:
2123 0 : mesh_tmp%mesh_type=1 !linear grid
2124 0 : mesh_tmp%rstep=0.0005 !very fine grid
2125 0 : msz2=ceiling(pawrad%rmax*two/mesh_tmp%rstep)
2126 : mesh_tmp%lstep=zero !only needed for log grids
2127 : call pawrad_init(mesh_tmp,mesh_size=msz2,mesh_type=mesh_tmp%mesh_type,&
2128 0 : & rstep=mesh_tmp%rstep,lstep=mesh_tmp%lstep)
2129 :
2130 0 : LIBPAW_ALLOCATE(tproj_tmp1,(msz1))
2131 0 : LIBPAW_ALLOCATE(d2,(msz1))
2132 0 : LIBPAW_ALLOCATE(tproj_tmp2,(msz2))
2133 :
2134 0 : do ibasis=1,basis_size
2135 :
2136 0 : write(msg,'(a," - Fitting wfn ",i4," to Gaussians")')ch10,ibasis
2137 0 : call wrtout(std_out, msg,'COLL')
2138 :
2139 0 : tproj_tmp1=zero; d2=zero; tproj_tmp2=zero
2140 :
2141 : ! take out r^il factor:
2142 : ! il=psps%indlmn(1,ilmn,itypat)
2143 0 : il=orbitals(ibasis)
2144 :
2145 0 : tproj_tmp1(2:msz1)=tproj(2:msz1,ibasis)/((pawrad%rad(2:msz1)+tol8)**(il))
2146 :
2147 : ! take out 1/r factor from eq.(3) of M. Torrent CMS 42, 337 (2008)
2148 : ! since: <phi|proj>=1 from atompaw, and phi=phi*r, alors proj=proj/r
2149 :
2150 0 : tproj_tmp1(2:msz1)=tproj_tmp1(2:msz1)/(pawrad%rad(2:msz1))
2151 0 : call pawrad_deducer0(tproj_tmp1(1:msz1),msz1,pawrad)
2152 :
2153 : ! splint to a different mesh:
2154 : ! get second derivative of tproj and store it
2155 : call paw_spline(pawrad%rad,tproj_tmp1(:),msz1,&
2156 0 : & zero,zero,d2)
2157 :
2158 0 : do ir=2,msz2
2159 0 : rr=mesh_tmp%rad(ir)
2160 0 : if( rr(1)-rpaw > tol8 ) then
2161 : !after rpaw projectors are zero
2162 0 : raux=zero
2163 : else
2164 : call paw_splint(msz1,pawrad%rad,&
2165 : & tproj_tmp1(:),d2(:),&
2166 0 : & 1,rr,raux,ierr=ierr)
2167 : end if
2168 0 : tproj_tmp2(ir)=raux(1)
2169 : end do
2170 :
2171 : ! Obtain the name for the output file
2172 0 : if(ibasis<10) then
2173 0 : write(outfile,'("wfn",i1,".fit")')ibasis
2174 0 : elseif(ibasis<100) then
2175 0 : write(outfile,'("wfn",i2,".fit")')ibasis
2176 0 : write(msg,'(a,a,a,a)')ch10,&
2177 0 : & "ib (basis index) is too big!",ch10,&
2178 0 : & "Action: check your pseudopotentials"
2179 0 : LIBPAW_BUG(msg)
2180 : end if
2181 :
2182 0 : if(present(comm_mpi)) then
2183 : call gaussfit_main(mparam,nparam_array(ibasis),nterm_bounds,msz2,&
2184 0 : & param(:,ibasis),mesh_tmp,option,outfile,rpaw,tproj_tmp2,comm_mpi)
2185 : else
2186 : call gaussfit_main(mparam,nparam_array(ibasis),nterm_bounds,msz2,&
2187 0 : & param(:,ibasis),mesh_tmp,option,outfile,rpaw,tproj_tmp2)
2188 : end if
2189 :
2190 : ! check
2191 : ! LIBPAW_ALLOCATE(y,(mesh_tmp%mesh_size))
2192 : ! nterm=nparam_array(ibasis)/4
2193 : ! call calcgaussc4(nparam_array(ibasis),nterm,mesh_tmp%mesh_size,1,param(:,ibasis),&
2194 : ! & mesh_tmp%rad,y)
2195 : ! ! unitp=600+ibasis
2196 : ! ! do ir=1,mesh_tmp%mesh_size
2197 : ! ! write(unitp,'(2(f16.7,x,f16.7))')mesh_tmp%rad(ir),y(ir)
2198 : ! ! end do
2199 : ! LIBPAW_DEALLOCATE(y)
2200 :
2201 : end do
2202 :
2203 : !Deallocate
2204 0 : call pawrad_free(mesh_tmp)
2205 0 : LIBPAW_DEALLOCATE(tproj_tmp1)
2206 0 : LIBPAW_DEALLOCATE(tproj_tmp2)
2207 0 : LIBPAW_DEALLOCATE(d2)
2208 :
2209 0 : end subroutine gaussfit_projector
2210 : !!***
2211 :
2212 : !----------------------------------------------------------------------
2213 :
2214 : end module m_paw_gaussfit
2215 : !!***
|