Branch data Line data Source code
1 : : !!****m* ABINIT/m_model_screening
2 : : !! NAME
3 : : !! m_model_screening
4 : : !!
5 : : !! FUNCTION
6 : : !! Module containing functions for calculating and fitting model dielectric functions
7 : : !!
8 : : !! COPYRIGHT
9 : : !! Copyright (C) 2008-2026 ABINIT group (MS)
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 : : !! SOURCE
15 : :
16 : : #if defined HAVE_CONFIG_H
17 : : #include "config.h"
18 : : #endif
19 : :
20 : : #include "abi_common.h"
21 : :
22 : : MODULE m_model_screening
23 : :
24 : : use defs_basis
25 : : use m_errors
26 : : use m_abicore
27 : :
28 : : use m_io_tools, only : open_file
29 : :
30 : : implicit none
31 : :
32 : : private
33 : :
34 : : public :: im_screening ! Calc. Drude-Lorentz model function from parameters.
35 : : public :: re_screening ! Calc. Drude-Lorentz model function from parameters.
36 : : public :: re_and_im_screening ! Calc. Drude-Lorentz model function from parameters.
37 : : public :: re_and_im_screening_with_phase ! Calc. Drude-Lorentz model function from parameters.
38 : : ! with the addition of a phase
39 : : public :: sequential_fitting ! Fit poles one by one
40 : : public :: init_peaks_from_grid ! find approximate expression for parameters from
41 : : ! chi0 or eps^-1 on a grid in the complex plane.
42 : : public :: init_peaks_even_dist ! Initial guess from even distributuin of peaks
43 : : public :: init_single_peak ! Initialise a single peak from the maximum, the
44 : : ! origin, and the second value along the
45 : : ! imaginary axis
46 : : ! public :: int_screening ! Find the integral along real or complex axis
47 : : ! from parameters.
48 : : public :: remove_phase
49 : :
50 : : CONTAINS !==============================================================================
51 : : !!***
52 : :
53 : : !!****f* m_model_screening/im_screening
54 : : !! NAME
55 : : !! im_screening
56 : : !!
57 : : !! FUNCTION
58 : : !! Return the imaginary part of model dielectric / inverse dielectric
59 : : !! function as given by a Drude-Lorentx model
60 : : !!
61 : : !! The function is a sum in the complex plane:
62 : : !! f(z) = Sum_n f_n * Im[ ((w_n^2-z^2) - i*gamma*z)^-1 ], z=a-i*b
63 : : !!
64 : : !! Here, f_n is the oscillator strength, w_n the location of the peak for
65 : : !! the imaginary function, and gamma is related to the width
66 : : !!
67 : : !! INPUTS
68 : : !! omega = (complex) Real and imaginary part of the frequency points
69 : : !! coeff = The coefficients in order: f_1,w_1,gamma_1,f_2,w_2,gamma_2,
70 : : !! ...,f_n,w_n,gamma_n
71 : : !! nomega = number of fit points
72 : : !! ncoeff = number of coefficients
73 : : !!
74 : : !! OUTPUT
75 : : !!
76 : : !! NOTES
77 : : !!
78 : : !! SOURCE
79 : :
80 : 0 : subroutine im_screening(omega,fval,nomega,coeff,ncoeff)
81 : :
82 : : !Arguments ------------------------------------
83 : : !scalars
84 : : integer,intent(in) :: nomega,ncoeff
85 : : !arrays
86 : : complex(dp),intent(in) :: omega(nomega)
87 : : real(gwp) ,intent(in) :: coeff(ncoeff)
88 : : real(gwp) ,intent(out) :: fval(nomega)
89 : :
90 : : !Local variables-------------------------------
91 : : !scalars
92 : : integer :: io,ip
93 : : real(gwp) :: rez,imz,realp,imagp
94 : : real(gwp) :: fn,wn,gamman
95 : : ! *********************************************************************
96 : :
97 : : ! The expression is: -f_n*(2*rez*imz-rez*gamma_n)
98 : : ! /( (-imz*gamma_n+w_n^2+imz^2-rez^2)^2 + (2*rez*imz-rez*gamma_n)^2 )
99 : :
100 [ # # ]: 0 : do io=1,nomega
101 : 0 : fval(io) = 0.0
102 : 0 : rez = REAL(omega(io))
103 : 0 : imz = AIMAG(omega(io))
104 [ # # ]: 0 : do ip=1,ncoeff,3
105 : 0 : fn = coeff(ip)
106 : 0 : wn = coeff(ip+1)
107 : 0 : gamman = coeff(ip+2)
108 : 0 : realp = -imz*gamman+wn*wn+imz*imz-rez*rez
109 : 0 : imagp = rez*(two*imz-gamman)
110 : :
111 [ # # ]: 0 : fval(io) = fval(io)-fn*imagp/((realp*realp)+(imagp*imagp))
112 : :
113 : : end do
114 : : end do
115 : :
116 : 0 : end subroutine im_screening
117 : : !!***
118 : :
119 : : !!****f* m_model_screening/re_screening
120 : : !! NAME
121 : : !! re_screening
122 : : !!
123 : : !! FUNCTION
124 : : !! Return the real part of model dielectric / inverse dielectric
125 : : !! function as evaluated from pole coefficients.
126 : : !!
127 : : !! The function is a sum of poles in the complex plane:
128 : : !! f(z) = Sum_n[ A/(z-(B-iC)) - A/(z-(-B+iC)) ],
129 : : !! where each pole occurs twice in a time-ordered fashion.
130 : : !!
131 : : !! Here, the A are the oscillator strengths, B the real component of the position
132 : : !! of the pole, and C the imaginary component.
133 : : !!
134 : : !! INPUTS
135 : : !! omega = (complex) Real and imaginary part of the frequency points
136 : : !! coeff = The coefficients in order: A_1,B_1,C_1,A_2,B_2,C_2,...,A_n,B_n,C_n
137 : : !! nomega = number of fit points
138 : : !! ncoeff = number of coefficients
139 : : !!
140 : : !! OUTPUT
141 : : !!
142 : : !! NOTES
143 : : !!
144 : : !! SOURCE
145 : :
146 : 0 : subroutine re_screening(omega,fval,nomega,coeff,ncoeff)
147 : :
148 : : !Arguments ------------------------------------
149 : : !scalars
150 : : integer,intent(in) :: nomega,ncoeff
151 : : !arrays
152 : : complex(dp),intent(in) :: omega(nomega)
153 : : real(gwp) ,intent(in) :: coeff(ncoeff)
154 : : real(gwp) ,intent(out) :: fval(nomega)
155 : :
156 : : !Local variables-------------------------------
157 : : !scalars
158 : : integer :: io,ip
159 : : real(gwp) :: rez,imz,realp,imagp
160 : : real(gwp) :: fn,wn,gamman
161 : : ! *********************************************************************
162 : :
163 : : ! The expression is: fn*(-imz*gamma+w_n^2+imz^2-rez^2)
164 : : ! /( (-imz*gamma+w_n^2+imz^2-rez^2)^2 + (2*rez*imz-rez*gamma)^2 )
165 : :
166 [ # # ]: 0 : do io=1,nomega
167 : 0 : fval(io) = 0.0
168 : 0 : rez = REAL(omega(io))
169 : 0 : imz = AIMAG(omega(io))
170 [ # # ]: 0 : do ip=1,ncoeff,3
171 : 0 : fn = coeff(ip)
172 : 0 : wn = coeff(ip+1)
173 : 0 : gamman = coeff(ip+2)
174 : 0 : realp = -imz*gamman+wn*wn+imz*imz-rez*rez
175 : 0 : imagp = rez*(two*imz-gamman)
176 : :
177 [ # # ]: 0 : fval(io) = fval(io)-fn*realp/((realp*realp)+(imagp*imagp))
178 : :
179 : : end do
180 : : end do
181 : :
182 : 0 : end subroutine re_screening
183 : : !!***
184 : :
185 : : !!****f* m_model_screening/re_and_im_screening
186 : : !! NAME
187 : : !! re_and_im_screening
188 : : !!
189 : : !! FUNCTION
190 : : !! Return the real and imaginary part of model dielectric / inverse dielectric
191 : : !! function as evaluated from pole coefficients.
192 : : !!
193 : : !! The function is a sum of poles in the complex plane:
194 : : !! f(z) = Sum_n[ A/(z-(B-iC)) - A/(z-(-B+iC)) ],
195 : : !! where each pole occurs twice in a time-ordered fashion.
196 : : !!
197 : : !! Here, the A are the oscillator strengths, B the real component of the position
198 : : !! of the pole, and C the imaginary component.
199 : : !!
200 : : !! INPUTS
201 : : !! omega = (complex) Real and imaginary part of the frequency points
202 : : !! coeff = The coefficients in order: A_1,B_1,C_1,A_2,B_2,C_2,...,A_n,B_n,C_n
203 : : !! nomega = number of fit points
204 : : !! ncoeff = number of coefficients
205 : : !!
206 : : !! OUTPUT
207 : : !!
208 : : !! NOTES
209 : : !!
210 : : !! SOURCE
211 : :
212 : 0 : subroutine re_and_im_screening(omega,fval,nomega,coeff,ncoeff)
213 : :
214 : : !Arguments ------------------------------------
215 : : !scalars
216 : : integer,intent(in) :: nomega,ncoeff
217 : : !arrays
218 : : complex(dp) ,intent(in) :: omega(nomega)
219 : : real(gwp) ,intent(in) :: coeff(ncoeff)
220 : : complex(gwp),intent(out) :: fval(nomega)
221 : :
222 : : !Local variables-------------------------------
223 : : !scalars
224 : : integer :: io,ip
225 : : real(gwp) :: rez,imz,realp,imagp,refval,imfval
226 : : real(gwp) :: fn,wn,gamman
227 : : ! *********************************************************************
228 : :
229 : : ! The expression is: fn*(-imz*gamma+w_n^2+imz^2-rez^2)
230 : : ! /( (-imz*gamma+w_n^2+imz^2-rez^2)^2 + (2*rez*imz-rez*gamma)^2 )
231 : :
232 [ # # ]: 0 : do io=1,nomega
233 : 0 : fval(io) = 0.0
234 : 0 : rez = REAL(omega(io))
235 : 0 : imz = AIMAG(omega(io))
236 [ # # ]: 0 : do ip=1,ncoeff,3
237 : 0 : fn = coeff(ip)
238 : 0 : wn = coeff(ip+1)
239 : 0 : gamman = coeff(ip+2)
240 : 0 : realp = -imz*gamman+wn*wn+imz*imz-rez*rez
241 : 0 : imagp = rez*(two*imz-gamman)
242 : :
243 : 0 : refval = fn*realp/((realp*realp)+(imagp*imagp))
244 : 0 : imfval = fn*imagp/((realp*realp)+(imagp*imagp))
245 : :
246 [ # # ]: 0 : fval(io) = fval(io)-CMPLX(refval,imfval)
247 : :
248 : : end do
249 : : end do
250 : :
251 : 0 : end subroutine re_and_im_screening
252 : : !!***
253 : :
254 : : !!****f* m_model_screening/re_and_im_screening_with_phase
255 : : !! NAME
256 : : !! re_and_im_screening_with_phase
257 : : !!
258 : : !! FUNCTION
259 : : !! Return the real and imaginary part of model dielectric / inverse dielectric
260 : : !! function as evaluated from pole coefficients.
261 : : !!
262 : : !! The function is a sum of poles in the complex plane:
263 : : !! f(z) = Sum_n[ A/(z-(B-iC)) - A/(z-(-B+iC)) ],
264 : : !! where each pole occurs twice in a time-ordered fashion.
265 : : !!
266 : : !! Here, the A are the oscillator strengths, B the real component of the position
267 : : !! of the pole, and C the imaginary component.
268 : : !!
269 : : !! INPUTS
270 : : !! omega = (complex) Real and imaginary part of the frequency points
271 : : !! coeff = The coefficients in order: A_1,B_1,C_1,A_2,B_2,C_2,...,A_n,B_n,C_n
272 : : !! nomega = number of fit points
273 : : !! ncoeff = number of coefficients
274 : : !!
275 : : !! OUTPUT
276 : : !!
277 : : !! NOTES
278 : : !!
279 : : !! SOURCE
280 : :
281 : 0 : subroutine re_and_im_screening_with_phase(omega,fval,nomega,coeff,ncoeff)
282 : :
283 : : !Arguments ------------------------------------
284 : : !scalars
285 : : integer,intent(in) :: nomega,ncoeff
286 : : !arrays
287 : : complex(dp) ,intent(in) :: omega(nomega)
288 : : real(gwp) ,intent(in) :: coeff(ncoeff)
289 : : complex(gwp),intent(out) :: fval(nomega)
290 : :
291 : : !Local variables-------------------------------
292 : : !scalars
293 : : integer :: io,ip,npoles
294 : : real(gwp) :: rez,imz,realp,imagp,refval,imfval,retemp,imtemp
295 : : real(gwp) :: fn,wn,gamman,imrot,rerot
296 : : ! *********************************************************************
297 : :
298 : : ! The expression is: fn*(-imz*gamma+w_n^2+imz^2-rez^2)
299 : : ! /( (-imz*gamma+w_n^2+imz^2-rez^2)^2 + (2*rez*imz-rez*gamma)^2 )
300 : 0 : npoles = (ncoeff-1)/3
301 : :
302 [ # # ]: 0 : do io=1,nomega
303 : 0 : fval(io) = 0.0
304 : 0 : rez = REAL(omega(io))
305 : 0 : imz = AIMAG(omega(io))
306 [ # # ]: 0 : do ip=1,(ncoeff-1),3
307 : 0 : fn = coeff(ip)
308 : 0 : wn = coeff(ip+1)
309 : 0 : gamman = coeff(ip+2)
310 : 0 : realp = -imz*gamman+wn*wn+imz*imz-rez*rez
311 : 0 : imagp = rez*(two*imz-gamman)
312 : :
313 : 0 : refval = fn*realp/((realp*realp)+(imagp*imagp))
314 : 0 : imfval = fn*imagp/((realp*realp)+(imagp*imagp))
315 : :
316 [ # # ]: 0 : fval(io) = fval(io)-CMPLX(refval,imfval)
317 : :
318 : : end do
319 : : ! Restore phase
320 : 0 : rerot = COS(coeff(npoles*3+1))
321 : 0 : imrot = SIN(coeff(npoles*3+1))
322 : 0 : retemp = REAL(fval(io))
323 : 0 : imtemp = AIMAG(fval(io))
324 : 0 : fval(io) = CMPLX(rerot*retemp-imrot*imtemp,rerot*imtemp + imrot*retemp)
325 : : end do
326 : :
327 : 0 : end subroutine re_and_im_screening_with_phase
328 : : !!***
329 : :
330 : :
331 : : !!****f* m_model_screening/sequential_fitting
332 : : !! NAME
333 : : !! sequential_fitting
334 : : !!
335 : : !! FUNCTION
336 : : !! Fit a function in the complex plane pole-by-pole in such
337 : : !! a way as to increasingly minimise the error
338 : : !!
339 : : !! INPUTS
340 : : !! omega = (complex) Real and imaginary part of the frequency points
341 : : !! refval = Real part of function to be fitted
342 : : !! imfval = imaginary part of function to be fitted
343 : : !! nomega = Total number of points in the complex plane
344 : : !! nfreqre = Number of points along real axis
345 : : !! nfreqim = Number of points along imaginary axis
346 : : !! coeff = The coefficients in order: A_1,B_1,C_1,A_2,B_2,C_2,...,A_n,B_n,C_n
347 : : !! ncoeff = number of coefficients
348 : : !! prtvol = Diagnostics verbose level
349 : : !!
350 : : !! OUTPUT
351 : : !!
352 : : !! NOTES
353 : : !!
354 : : !! SOURCE
355 : :
356 : 0 : subroutine sequential_fitting(omega,refval,imfval,nomega,nfreqre,coeff,&
357 : : & ncoeff,prtvol,startcoeff)
358 : :
359 : : !Arguments ------------------------------------
360 : : !scalars
361 : : integer,intent(in) :: nomega,nfreqre,ncoeff,prtvol
362 : : !arrays
363 : : complex(dp),intent(in) :: omega(nomega)
364 : : real(gwp) ,intent(out) :: coeff(ncoeff)
365 : : real(gwp) ,intent(inout) :: refval(nomega),imfval(nomega)
366 : : real(gwp),optional,intent(out) :: startcoeff(ncoeff)
367 : :
368 : : !Local variables-------------------------------
369 : : !scalars
370 : : integer :: ip,npoles,idx
371 : : real(gwp) :: thiscoeff(3),norm,invnorm
372 : 0 : real(dp) :: re_zvals(nomega),im_zvals(nomega)
373 : : ! real(dp) :: orig_refval(nomega),orig_imfval(nomega)
374 : 0 : complex(gwp) :: pole_func(nomega)
375 : : ! *********************************************************************
376 : :
377 : 0 : npoles = ncoeff/3
378 [ # # ]: 0 : re_zvals(:) = REAL(omega(:))
379 [ # # ]: 0 : im_zvals(:) = AIMAG(omega(:))
380 : :
381 : : ! Normalise
382 [ # # # # : 0 : norm = MAXVAL(ABS(imfval))
# # # # ]
383 : 0 : invnorm = 1.0_gwp/norm
384 [ # # ]: 0 : refval = invnorm*refval
385 [ # # ]: 0 : imfval = invnorm*imfval
386 : :
387 : : ! Loop over poles to fit
388 [ # # ]: 0 : do ip=1,npoles
389 : 0 : idx = 3*(ip-1)+1
390 : : ! Initialise pole
391 : 0 : call init_single_peak(omega,refval,imfval,nomega,nfreqre,thiscoeff,prtvol)
392 [ # # ]: 0 : if (present(startcoeff)) then
393 [ # # ]: 0 : startcoeff(idx:idx+2) = thiscoeff(1:3)
394 : : end if
395 : : ! Make fit
396 : : #ifdef HAVE_LEVMAR
397 : : call dfit_re_and_im_screening(re_zvals,im_zvals,imfval,refval,&
398 : : & nomega,3,thiscoeff,prtvol)
399 : : #else
400 : 0 : ABI_ERROR(' ABINIT was not compiled with the levmar library!')
401 : : #endif
402 : : ! Remove current fit
403 : 0 : call re_and_im_screening(omega,pole_func,nomega,thiscoeff,3)
404 [ # # ]: 0 : refval(:) = refval(:) - REAL(pole_func(:))
405 [ # # ]: 0 : imfval(:) = imfval(:) - AIMAG(pole_func(:))
406 [ # # ]: 0 : coeff(idx:idx+2) = thiscoeff(1:3)
407 : 0 : coeff(idx) = norm*coeff(idx)
408 : : end do
409 : :
410 : 0 : end subroutine sequential_fitting
411 : : !!***
412 : :
413 : : !!****f* m_model_screening/init_peaks_from_grid
414 : : !! NAME
415 : : !! init_peaks_from_grid
416 : : !!
417 : : !! FUNCTION
418 : : !!
419 : : !! Find an initial guess of coefficents from the "valleys" and "hills" in
420 : : !! the complex plane.
421 : : !!
422 : : !! INPUTS
423 : : !! omega = (complex) Real and imaginary part of the frequency points
424 : : !! yvals = The function to be fitted in the complex plane
425 : : !! coeff = The coefficients in order: A_1,B_1,C_1,A_2,B_2,C_2,...,A_n,B_n,C_n
426 : : !! nomega = number of fit points
427 : : !! ncoeff = number of coefficients
428 : : !! prtvol = Verbosity of diagnostics
429 : : !!
430 : : !! OUTPUT
431 : : !!
432 : : !! NOTES
433 : : !!
434 : : !! SOURCE
435 : :
436 : 0 : subroutine init_peaks_from_grid(omega,fval,nomega,nfreqre,nfreqim,coeff,ncoeff,prtvol)
437 : :
438 : : !Arguments ------------------------------------
439 : : !scalars
440 : : integer,intent(in) :: nomega,nfreqre,nfreqim,ncoeff,prtvol
441 : : !arrays
442 : : complex(dp) ,intent(in) :: omega(nomega)
443 : : real(gwp) ,intent(out) :: coeff(ncoeff)
444 : : complex(gwp),intent(in) :: fval(nomega)
445 : :
446 : : !Local variables-------------------------------
447 : : !scalars
448 : : integer :: npoles,iline,idx,ip
449 : : real(gwp) :: pol,gam,maxv,df,dk,val2,b2,osc,val1
450 : : real(gwp) :: temp1,temp2,temp3
451 : :
452 : : !arrays
453 : 0 : integer :: ploc(ncoeff/3)
454 : : ! *********************************************************************
455 : :
456 : 0 : npoles = ncoeff/3
457 : :
458 : : ! Map the evolution of peaks if prtvol>10
459 [ # # ]: 0 : if (prtvol>10) then
460 : 0 : call print_peaks(omega,fval,nomega,nfreqre,nfreqim)
461 : : end if ! prtvol>10
462 : :
463 : : ! Count the number of peaks per line and find the location of the
464 : : ! constant-imaginary frequency line wich has at least a number of
465 : : ! peaks commensurate with the requested number of poles
466 : 0 : call find_peaks(fval,nomega,nfreqre,nfreqim,ploc,npoles,iline)
467 : 0 : write(std_out,*) ' Optimum peak locations:',ploc
468 : 0 : write(std_out,*) ' on iline:',iline
469 : : ! Now fit the peaks. A linear interpolation along the imaginary
470 : : ! direction is used to get a rough estimate of the width of
471 : : ! the peak.
472 [ # # ]: 0 : do ip=1,npoles
473 : 0 : pol = REAL(omega(ploc(ip)))
474 : 0 : maxv = AIMAG(fval(ploc(ip)))
475 : 0 : write(std_out,*) ' maxv:',maxv
476 [ # # ]: 0 : if (ploc(ip)<nfreqre+1) then ! We are right on the real axis
477 [ # # ]: 0 : if (ploc(ip)==1) then ! Peak is at origin (Drude peak, i.e. metal)
478 : 0 : b2 = AIMAG(omega(nfreqre+1))
479 : 0 : val2 = AIMAG(fval(nfreqre+1))
480 : 0 : write(std_out,*) '1: ploc:',ploc(ip),' b2:',b2,' val2:',val2
481 : : else ! Second value will be in c-plane
482 : 0 : idx = nfreqre+nfreqim+ploc(ip)-1
483 : 0 : b2 = AIMAG(omega(idx))
484 : 0 : val2 = AIMAG(fval(idx))
485 : 0 : write(std_out,*) '2: ploc:',ploc(ip),' b2:',b2,' val2:',val2
486 : : end if
487 [ # # ]: 0 : else if (ploc(ip)<nfreqre+nfreqim+1) then ! We are right on the imaginary axis
488 [ # # ]: 0 : if (ploc(ip)==nfreqre+nfreqim) then
489 : 0 : ABI_ERROR(' Peak in upper left corner. This should never happen')
490 : : end if
491 : 0 : b2 = AIMAG(omega(ploc(ip)+1))
492 : 0 : val2 = AIMAG(fval(ploc(ip)+1))
493 : 0 : write(std_out,*) '3: ploc:',ploc(ip),' b2:',b2,' val2:',val2
494 : : else ! We are in the complex plane
495 : 0 : idx = ploc(ip)+nfreqre-1
496 : 0 : b2 = AIMAG(omega(idx))
497 : 0 : val2 = AIMAG(fval(idx))
498 : 0 : write(std_out,*) '4: ploc:',ploc(ip),' idx:',idx,' b2:',b2,' val2:',val2
499 : : end if
500 : 0 : df = ABS(val2 - maxv)
501 : 0 : dk = df/b2
502 : 0 : gam = -ABS(val2/dk)
503 : : !temp1 = SQRT(-b2*b2*val2*(val2+maxv)+(maxv*maxv)**2)
504 : : !temp2 = b2*(two*pol*pol+b2*b2)*val2-b2*maxv*pol*pol
505 : : !temp3 = (pol*pol+b2*b2)*val2+maxv*pol*pol
506 : : !gam = -((temp1-temp2)/temp3)
507 [ # # ]: 0 : if (gam>zero) gam = ((temp1+temp2)/temp3)
508 : 0 : osc = maxv*gam*pol
509 : 0 : idx = 3*(ip-1)+1
510 : 0 : coeff(idx ) = osc ! Oscillator strength
511 : 0 : coeff(idx+1) = pol ! Position of maximum
512 : 0 : coeff(idx+2) = gam ! Spread of function
513 [ # # ]: 0 : if (prtvol>9) then
514 : 0 : write(std_out,'(a,a,i0)') ch10,' Pole no,: ',ip
515 : 0 : write(std_out,'(a,ES16.8)') ' Osc. strength:',osc
516 : 0 : write(std_out,'(a,ES16.8,a)') ' Peak location:',pol*Ha_eV,' eV'
517 : 0 : write(std_out,'(a,ES16.8,a)') ' Peak width:',gam*Ha_eV,' eV'
518 : 0 : val2 = gam*half
519 : 0 : val1 = SIGN(1.0_gwp,pol*pol-val2*val2)*SQRT(ABS(pol*pol-val2*val2))
520 : 0 : write(std_out,'(a,ES16.8,a)') ' Re[z] for pole:',val1*Ha_eV,' eV'
521 : 0 : write(std_out,'(a,ES16.8,a)') ' Im[z] for pole:',val2*Ha_eV,' eV'
522 : 0 : write(std_out,'(a,ES16.8)') ' Amplitude:',osc*half/ABS(val1)
523 : : end if
524 : : end do
525 : :
526 : 0 : end subroutine init_peaks_from_grid
527 : : !!***
528 : :
529 : : !!****f* m_model_screening/init_single_peak
530 : : !! NAME
531 : : !! init_single_peak
532 : : !!
533 : : !! FUNCTION
534 : : !! Initialise a single peak by using the behaviour along the imaginary axis
535 : : !! and the main peak
536 : : !!
537 : : !! INPUTS
538 : : !! omega = (complex) Real and imaginary part of the frequency points
539 : : !! yvals = The function to be fitted in the complex plane
540 : : !! coeff = The coefficients in order: A_1,B_1,C_1,A_2,B_2,C_2,...,A_n,B_n,C_n
541 : : !! nomega = number of fit points
542 : : !! ncoeff = number of coefficients
543 : : !! prtvol = Verbosity of diagnostics
544 : : !!
545 : : !! OUTPUT
546 : : !!
547 : : !! NOTES
548 : : !!
549 : : !! SOURCE
550 : :
551 : 0 : subroutine init_single_peak(omega,refval,imfval,nomega,nfreqre,coeff,prtvol)
552 : :
553 : : !Arguments ------------------------------------
554 : : !scalars
555 : : integer,intent(in) :: nomega,nfreqre,prtvol
556 : : !arrays
557 : : complex(dp),intent(in) :: omega(nomega)
558 : : real(gwp) ,intent(out) :: coeff(3)
559 : : real(gwp) ,intent(in) :: refval(nomega),imfval(nomega)
560 : :
561 : : !Local variables-------------------------------
562 : : !scalars
563 : : integer :: maxpos,idx
564 : : real(gwp) :: pol,osc,gam,val1,val2,pol_sq
565 : :
566 : : ! *********************************************************************
567 : :
568 [ # # # # : 0 : maxpos = MAXLOC(ABS(imfval(1:nfreqre)),1)
# # # # #
# ]
569 [ # # # # : 0 : if (maxpos==1) maxpos = MAXLOC(ABS(imfval(2:nfreqre)),1)
# # # # #
# # # ]
570 : 0 : pol = REAL(omega(maxpos))
571 : 0 : pol_sq = pol*pol
572 : 0 : osc = -refval(1)*pol_sq
573 : 0 : idx = nfreqre+1
574 : 0 : val2 = refval(idx)
575 : 0 : val1 = osc+val2*pol_sq+val2*AIMAG(omega(idx))*AIMAG(omega(idx))
576 : 0 : gam = -ABS(val1/(AIMAG(omega(idx))*val2))
577 : :
578 : 0 : coeff(1) = osc
579 : 0 : coeff(2) = pol
580 : 0 : coeff(3) = gam
581 : :
582 [ # # ]: 0 : if (prtvol>9) then
583 : 0 : write(std_out,'(a,ES16.8)') ' Osc. strength:',osc
584 : 0 : write(std_out,'(a,ES16.8,a)') ' Peak location:',pol*Ha_eV,' eV'
585 : 0 : write(std_out,'(a,ES16.8,a)') ' Peak width:',gam*Ha_eV,' eV'
586 : 0 : val2 = gam*half
587 : 0 : val1 = SIGN(1.0_gwp,pol*pol-val2*val2)*SQRT(ABS(pol*pol-val2*val2))
588 : 0 : write(std_out,'(a,ES16.8,a)') ' Re[z] for pole:',val1*Ha_eV,' eV'
589 : 0 : write(std_out,'(a,ES16.8,a)') ' Im[z] for pole:',val2*Ha_eV,' eV'
590 : 0 : write(std_out,'(a,ES16.8)') ' Amplitude:',osc*half/ABS(val1)
591 : : end if
592 : :
593 : 0 : end subroutine init_single_peak
594 : : !!***
595 : :
596 : : !!****f* m_model_screening/init_peaks_even_dist
597 : : !! NAME
598 : : !! init_peaks_even_dist
599 : : !!
600 : : !! FUNCTION
601 : : !!
602 : : !! Distribute the peaks evenly along a line in the complex plane and
603 : : !! normalise.
604 : : !!
605 : : !! INPUTS
606 : : !! omega = (complex) Real and imaginary part of the frequency points
607 : : !! yvals = The function to be fitted in the complex plane
608 : : !! coeff = The coefficients in order: A_1,B_1,C_1,A_2,B_2,C_2,...,A_n,B_n,C_n
609 : : !! nomega = number of fit points
610 : : !! ncoeff = number of coefficients
611 : : !! prtvol = Verbosity of diagnostics
612 : : !!
613 : : !! OUTPUT
614 : : !!
615 : : !! NOTES
616 : : !!
617 : : !! SOURCE
618 : :
619 : 0 : subroutine init_peaks_even_dist(omega,fval,nomega,nfreqre,coeff,ncoeff,prtvol)
620 : :
621 : : !Arguments ------------------------------------
622 : : !scalars
623 : : integer,intent(in) :: nomega,nfreqre,ncoeff,prtvol
624 : : !arrays
625 : : complex(dp) ,intent(in) :: omega(nomega)
626 : : real(gwp) ,intent(out) :: coeff(ncoeff)
627 : : complex(gwp),intent(in) :: fval(nomega)
628 : :
629 : : !Local variables-------------------------------
630 : : !scalars
631 : : integer :: npoles,ip,idx,iw
632 : : real(gwp) :: delta,norm,div,val1,val2,osc,pol,gam
633 : : ! *********************************************************************
634 : :
635 : 0 : npoles = ncoeff/3
636 : 0 : div = real(npoles,gwp)
637 : :
638 : 0 : delta = (omega(nfreqre)-omega(1))/(div+1.0_gwp)
639 : : ! Integrate function along real axis (trapezoid rule) and have normalised
640 : : ! oscillator strengths
641 : 0 : norm = fval(1)*half
642 [ # # ]: 0 : do iw=2,nfreqre-1
643 : 0 : norm = norm + fval(iw)
644 : : end do
645 : 0 : norm = norm + fval(nfreqre)*half
646 : 0 : norm = norm*(omega(nfreqre)-omega(1))/real(nfreqre,gwp)
647 : 0 : norm = norm/div
648 : :
649 [ # # ]: 0 : do ip=1,npoles
650 : 0 : idx = 3*(ip-1)+1
651 : 0 : pol = delta*ip ! Position of maximum
652 : 0 : gam = 0.1_gwp ! Spread of function
653 : 0 : val2 = gam*half
654 : 0 : val1 = SQRT(pol*pol-val2*val2)
655 : 0 : osc = norm*val1*two
656 : 0 : coeff(idx ) = osc!*(-1.0_gwp)**(ip-1)
657 : 0 : coeff(idx+1) = pol ! Position of maximum
658 : 0 : coeff(idx+2) = -gam ! Spread of function
659 [ # # ]: 0 : if (prtvol>9) then
660 : 0 : write(std_out,'(a,a,i0)') ch10,' Pole no,: ',ip
661 : 0 : write(std_out,'(a,ES16.8)') ' Osc. strength:',osc
662 : 0 : write(std_out,'(a,ES16.8,a)') ' Peak location:',pol*Ha_eV,' eV'
663 : 0 : write(std_out,'(a,ES16.8,a)') ' Peak width:',gam*Ha_eV,' eV'
664 : 0 : val2 = gam*half
665 : 0 : val1 = SIGN(1.0_gwp,pol*pol-val2*val2)*SQRT(ABS(pol*pol-val2*val2))
666 : 0 : write(std_out,'(a,ES16.8,a)') ' Re[z] for pole:',val1*Ha_eV,' eV'
667 : 0 : write(std_out,'(a,ES16.8,a)') ' Im[z] for pole:',val2*Ha_eV,' eV'
668 : 0 : write(std_out,'(a,ES16.8)') ' Amplitude:',osc*half/ABS(val1)
669 : : end if
670 : : end do
671 : :
672 : 0 : end subroutine init_peaks_even_dist
673 : : !!***
674 : :
675 : : !!****f* m_model_screening/print_peaks
676 : : !! NAME
677 : : !! print_peaks
678 : : !!
679 : : !! FUNCTION
680 : : !!
681 : : !! Find and output the location of peaks on the grid in a file
682 : : !!
683 : : !! INPUTS
684 : : !! omega = (complex) Real and imaginary part of the frequency points
685 : : !! fvals = The function to be fitted in the complex plane
686 : : !! nomega = number of fit points
687 : : !! nfreqre = number or imaginary gridlines
688 : : !! nfreqim = number of real gridlines
689 : : !!
690 : : !! OUTPUT
691 : : !!
692 : : !! NOTES
693 : : !!
694 : : !! SOURCE
695 : :
696 : 0 : subroutine print_peaks(omega,fval,nomega,nfreqre,nfreqim)
697 : :
698 : : !Arguments ------------------------------------
699 : : !scalars
700 : : integer,intent(in) :: nomega,nfreqre,nfreqim
701 : : !arrays
702 : : complex(dp) ,intent(in) :: omega(nomega)
703 : : complex(gwp),intent(in) :: fval(nomega)
704 : :
705 : : !Local variables-------------------------------
706 : : !scalars
707 : : integer :: ire,iim,unt_tmp
708 : : integer :: idx1,idx2,idx3
709 : : real(gwp) :: rez,imz,val1,val2,val3
710 : : character(len=500) :: msg
711 : : ! *********************************************************************
712 : :
713 [ # # ]: 0 : if (open_file("grid_peak_tree.dat", msg, newunit=unt_tmp) /= 0) then
714 : 0 : ABI_ERROR(msg)
715 : : end if
716 : :
717 [ # # ]: 0 : do iim=nfreqim,1,-1
718 : : ! write(std_out,*) ' iim:',iim
719 : : ! Check first points
720 : 0 : idx1 = nfreqre+iim
721 : 0 : idx2 = nfreqre+nfreqim+1+(nfreqre-1)*(iim-1)
722 : : ! write(std_out,*) ' idx1:',idx1,' idx2:',idx2
723 : 0 : val1 = AIMAG(fval(idx1))
724 : 0 : val2 = AIMAG(fval(idx2))
725 [ # # ]: 0 : if (ABS(val1)>ABS(val2)) then
726 : 0 : rez = REAL(omega(idx1))
727 : 0 : imz = AIMAG(omega(idx1))
728 : 0 : write(unt_tmp,'(2f8.2,4x,ES16.8)') rez*Ha_eV,imz*Ha_eV,val1
729 : : end if
730 : : ! Do all but the last
731 [ # # ]: 0 : do ire=1,nfreqre-4
732 : 0 : idx1 = nfreqre+nfreqim+1+(nfreqre-1)*(iim-1)+ire
733 : 0 : idx2 = idx1+1
734 : 0 : idx3 = idx1+2
735 : : ! write(std_out,*) ' idx1:',idx1,' idx2:',idx2,' idx3:',idx3
736 : 0 : rez = REAL(omega(idx2))
737 : 0 : imz = AIMAG(omega(idx2))
738 : 0 : val1 = AIMAG(fval(idx1))
739 : 0 : val2 = AIMAG(fval(idx2))
740 : 0 : val3 = AIMAG(fval(idx3))
741 [ # # # # ]: 0 : if (((val1<val2).AND.(val2>val3))) then
742 [ # # ]: 0 : if (sign(1.0_gwp,val2)<zero) CYCLE
743 : 0 : write(unt_tmp,'(2f8.2,4x,ES16.8)') rez*Ha_eV,imz*Ha_eV,val2
744 [ # # # # ]: 0 : else if (((val1>val2).AND.(val2<val3))) then
745 [ # # ]: 0 : if (sign(1.0_gwp,val2)>zero) CYCLE
746 : 0 : write(unt_tmp,'(2f8.2,4x,ES16.8)') rez*Ha_eV,imz*Ha_eV,val2
747 : : end if
748 : : end do
749 : : ! Check last point
750 : 0 : idx1 = nfreqre+nfreqim+1+(nfreqre-1)*(iim-1)+nfreqre-3
751 : 0 : idx2 = idx1 + 1
752 : : ! write(std_out,*) ' idx1:',idx1,' idx2:',idx2
753 : 0 : rez = REAL(omega(idx2))
754 : 0 : imz = AIMAG(omega(idx2))
755 : 0 : val1 = AIMAG(fval(idx1))
756 : 0 : val2 = AIMAG(fval(idx2))
757 [ # # ]: 0 : if (ABS(val1)<ABS(val2)) then
758 : 0 : write(unt_tmp,'(2f8.2,4x,ES16.8)') rez*Ha_eV,imz*Ha_eV,val2
759 : : end if
760 : : end do
761 : : ! finally, do the purely real axis
762 : : ! Check first points
763 : 0 : idx1 = 1; idx2 = 2
764 : 0 : val1 = AIMAG(fval(idx1)); val2 = AIMAG(fval(idx2))
765 [ # # ]: 0 : if (ABS(val1)>ABS(val2)) then
766 : 0 : rez = REAL(omega(idx1))
767 : 0 : imz = AIMAG(omega(idx1))
768 : 0 : write(unt_tmp,'(2f8.2,4x,ES16.8)') rez*Ha_eV,imz*Ha_eV,val1
769 : : end if
770 [ # # ]: 0 : do ire=2,nfreqre-3
771 : 0 : idx1 = ire; idx2 = idx1+1; idx3 = idx1+2
772 : 0 : rez = REAL(omega(idx2))
773 : 0 : imz = AIMAG(omega(idx2))
774 : 0 : val1 = AIMAG(fval(idx1))
775 : 0 : val2 = AIMAG(fval(idx2))
776 : 0 : val3 = AIMAG(fval(idx3))
777 [ # # # # ]: 0 : if (((val1<val2).AND.(val2>val3))) then
778 [ # # ]: 0 : if (sign(1.0_gwp,val2)<zero) CYCLE
779 : 0 : write(unt_tmp,'(2f8.2,4x,ES16.8)') rez*Ha_eV,imz*Ha_eV,val2
780 [ # # # # ]: 0 : else if (((val1>val2).AND.(val2<val3))) then
781 [ # # ]: 0 : if (sign(1.0_gwp,val2)>zero) CYCLE
782 : 0 : write(unt_tmp,'(2f8.2,4x,ES16.8)') rez*Ha_eV,imz*Ha_eV,val2
783 : : end if
784 : : end do
785 : : ! Check last point
786 : 0 : idx1 = nfreqre-2
787 : 0 : idx2 = idx1 + 1
788 : : ! write(std_out,*) ' idx1:',idx1,' idx2:',idx2
789 : 0 : rez = REAL(omega(idx2))
790 : 0 : imz = AIMAG(omega(idx2))
791 : 0 : val1 = AIMAG(fval(idx1))
792 : 0 : val2 = AIMAG(fval(idx2))
793 [ # # ]: 0 : if (ABS(val1)<ABS(val2)) then
794 : 0 : write(unt_tmp,'(2f8.2,4x,ES16.8)') rez*Ha_eV,imz*Ha_eV,val2
795 : : end if
796 : :
797 : 0 : close(unt_tmp)
798 : :
799 : 0 : end subroutine print_peaks
800 : : !!***
801 : :
802 : : !!****f* m_model_screening/find_peaks
803 : : !! NAME
804 : : !! find_peaks
805 : : !!
806 : : !! FUNCTION
807 : : !!
808 : : !! Find the location of the highest peaks along gridlines starting at the real axis
809 : : !! and then moving towards higher imaginary frequencies. Stop when enough
810 : : !! peaks to satisfy the number of poles needed has been found
811 : : !!
812 : : !! INPUTS
813 : : !! omega = (complex) Real and imaginary part of the frequency points
814 : : !! fvals = The function to be fitted in the complex plane
815 : : !! nomega = number of fit points
816 : : !! nfreqre = number or imaginary gridlines
817 : : !! nfreqim = number of real gridlines
818 : : !!
819 : : !! OUTPUT
820 : : !!
821 : : !! NOTES
822 : : !!
823 : : !! SOURCE
824 : :
825 : 0 : subroutine find_peaks(fval,nomega,nfreqre,nfreqim,ploc,npoles,iline)
826 : :
827 : : !Arguments ------------------------------------
828 : : !scalars
829 : : integer,intent(in) :: nomega,nfreqre,nfreqim,npoles
830 : : integer, intent(inout) :: iline
831 : : !arrays
832 : : integer ,intent(inout) :: ploc(npoles)
833 : : complex(gwp), intent(in) :: fval(nomega)
834 : :
835 : : !Local variables-------------------------------
836 : : !scalars
837 : : integer :: ire,iim,ipoles
838 : : integer :: idx1,idx2,idx3,ipol
839 : : real(gwp) :: val1,val2,val3
840 : : !arrays
841 : 0 : integer :: ploc_prev(npoles)
842 : 0 : real :: pval(npoles),pval_prev(npoles)
843 : : ! *********************************************************************
844 : :
845 [ # # # # ]: 0 : ploc=-1; ploc_prev=-1
846 [ # # # # ]: 0 : pval=zero; pval_prev=zero; ipol=1; ipoles=0
847 : :
848 : : ! First do a line along the real axis
849 : 0 : idx1 = 1; idx2 = 2
850 : 0 : val1 = AIMAG(fval(idx1)); val2 = AIMAG(fval(idx2))
851 [ # # ]: 0 : if (ABS(val1)>ABS(val2)) then
852 : 0 : ipoles = ipoles + 1
853 : 0 : ploc(1)=idx1; pval(1)=val1
854 : 0 : write(std_out,*) ' pval:',pval
855 : 0 : write(std_out,*) ' ploc:',ploc
856 : : end if
857 [ # # ]: 0 : do ire=2,nfreqre-3
858 : 0 : idx1 = ire; idx2 = idx1+1; idx3 = idx1+2
859 : 0 : val1 = AIMAG(fval(idx1))
860 : 0 : val2 = AIMAG(fval(idx2))
861 : 0 : val3 = AIMAG(fval(idx3))
862 [ # # # # ]: 0 : if (((val1<val2).AND.(val2>val3))) then
863 [ # # ]: 0 : if (sign(1.0_gwp,val2)<zero) CYCLE
864 : 0 : ipoles = ipoles + 1
865 [ # # # # : 0 : if (ANY( ABS(pval(:))<ABS(val2) )) then
# # ]
866 [ # # # # : 0 : ipol = MINLOC(ABS(pval(:)),1)
# # # # #
# ]
867 : 0 : ploc(ipol)=idx2; pval(ipol)=val2
868 : 0 : write(std_out,*) ' pval:',pval
869 : 0 : write(std_out,*) ' ploc:',ploc
870 : : end if
871 [ # # # # ]: 0 : else if (((val1>val2).AND.(val2<val3))) then
872 [ # # ]: 0 : if (sign(1.0_gwp,val2)>zero) CYCLE
873 : 0 : ipoles = ipoles + 1
874 [ # # # # : 0 : if (ANY( ABS(pval(:))<ABS(val2) )) then
# # ]
875 [ # # # # : 0 : ipol = MINLOC(ABS(pval(:)),1)
# # # # #
# ]
876 : 0 : ploc(ipol)=idx2; pval(ipol)=val2
877 : 0 : write(std_out,*) ' pval:',pval
878 : 0 : write(std_out,*) ' ploc:',ploc
879 : : end if
880 : : end if
881 : : end do
882 : : ! Check last point
883 : 0 : idx1 = nfreqre-2
884 : 0 : idx2 = idx1 + 1
885 : : ! write(std_out,*) ' idx1:',idx1,' idx2:',idx2
886 : 0 : val1 = AIMAG(fval(idx1))
887 : 0 : val2 = AIMAG(fval(idx2))
888 [ # # ]: 0 : if (ABS(val1)<ABS(val2)) then
889 : 0 : ipoles = ipoles + 1
890 [ # # # # : 0 : if (ANY( ABS(pval(:))<ABS(val2) )) then
# # ]
891 [ # # # # : 0 : ipol = MINLOC(ABS(pval(:)),1)
# # # # #
# ]
892 : 0 : ploc(ipol)=idx2; pval(ipol)=val2
893 : 0 : write(std_out,*) ' pval:',pval
894 : 0 : write(std_out,*) ' ploc:',ploc
895 : : end if
896 : : end if
897 : 0 : write(std_out,'(a,i0)') ' Number of poles real axis:',ipoles
898 : :
899 : :
900 [ # # # # ]: 0 : ploc_prev = ploc; pval_prev = pval
901 : :
902 : : ! Do the rest of the imaginary grid until total
903 : : ! number of peaks found equals npoles or less
904 [ # # ]: 0 : do iim=1,nfreqim-1
905 [ # # # # ]: 0 : ploc=-1; pval=zero; ipol=1; ipoles=0
906 : 0 : idx1 = nfreqre+iim
907 : 0 : idx2 = nfreqre+nfreqim+1+(nfreqre-1)*(iim-1)
908 : : ! write(std_out,*) ' idx1:',idx1,' idx2:',idx2
909 : 0 : val1 = AIMAG(fval(idx1))
910 : 0 : val2 = AIMAG(fval(idx2))
911 [ # # ]: 0 : if (ABS(val1)>ABS(val2)) then
912 : 0 : ipoles = ipoles + 1
913 : 0 : ploc(1)=idx1; pval(1)=val1
914 : 0 : write(std_out,*) ' pval:',pval
915 : 0 : write(std_out,*) ' ploc:',ploc
916 : : end if
917 : : ! Do all but the last
918 [ # # ]: 0 : do ire=1,nfreqre-4
919 : 0 : idx1 = nfreqre+nfreqim+1+(nfreqre-1)*(iim-1)+ire
920 : 0 : idx2 = idx1+1
921 : 0 : idx3 = idx1+2
922 : : ! write(std_out,*) ' idx1:',idx1,' idx2:',idx2,' idx3:',idx3
923 : 0 : val1 = AIMAG(fval(idx1))
924 : 0 : val2 = AIMAG(fval(idx2))
925 : 0 : val3 = AIMAG(fval(idx3))
926 [ # # # # ]: 0 : if (((val1<val2).AND.(val2>val3))) then
927 [ # # ]: 0 : if (sign(1.0_gwp,val2)<zero) CYCLE
928 : 0 : ipoles = ipoles + 1
929 [ # # # # : 0 : if (ANY( ABS(pval(:))<ABS(val2) )) then
# # ]
930 [ # # # # : 0 : ipol = MINLOC(ABS(pval(:)),1)
# # # # #
# ]
931 : 0 : ploc(ipol)=idx2; pval(ipol)=val2
932 : 0 : write(std_out,*) ' pval:',pval
933 : 0 : write(std_out,*) ' ploc:',ploc
934 : : end if
935 [ # # # # ]: 0 : else if (((val1>val2).AND.(val2<val3))) then
936 [ # # ]: 0 : if (sign(1.0_gwp,val2)>zero) CYCLE
937 : 0 : ipoles = ipoles + 1
938 [ # # # # : 0 : if (ANY( ABS(pval(:))<ABS(val2) )) then
# # ]
939 [ # # # # : 0 : ipol = MINLOC(ABS(pval(:)),1)
# # # # #
# ]
940 : 0 : ploc(ipol)=idx2; pval(ipol)=val2
941 : 0 : write(std_out,*) ' pval:',pval
942 : 0 : write(std_out,*) ' ploc:',ploc
943 : : end if
944 : : end if
945 : : end do
946 : : ! Check last point
947 : 0 : idx1 = nfreqre+nfreqim+1+(nfreqre-1)*(iim-1)+nfreqre-3
948 : 0 : idx2 = idx1 + 1
949 : : ! write(std_out,*) ' idx1:',idx1,' idx2:',idx2
950 : 0 : val1 = AIMAG(fval(idx1))
951 : 0 : val2 = AIMAG(fval(idx2))
952 [ # # ]: 0 : if (ABS(val1)<ABS(val2)) then
953 : 0 : ipoles = ipoles + 1
954 [ # # # # : 0 : if (ANY( ABS(pval(:))<ABS(val2) )) then
# # ]
955 [ # # # # : 0 : ipol = MINLOC(ABS(pval(:)),1)
# # # # #
# ]
956 : 0 : ploc(ipol)=idx2; pval(ipol)=val2
957 : 0 : write(std_out,*) ' pval:',pval
958 : 0 : write(std_out,*) ' ploc:',ploc
959 : : end if
960 : : end if
961 : 0 : write(std_out,'(2(a,i0))') ' Line,:',iim,' ipoles:',ipoles
962 [ # # ]: 0 : if (ipoles<=npoles) then
963 : 0 : iline = iim - 1
964 [ # # ]: 0 : ploc = ploc_prev
965 : : EXIT
966 : : end if
967 : :
968 [ # # # # ]: 0 : ploc_prev = ploc; pval_prev = pval
969 : :
970 : : end do
971 : :
972 : 0 : end subroutine find_peaks
973 : : !!***
974 : :
975 : : !!****f* m_model_screening/remove_phase
976 : : !! NAME
977 : : !! remove_phase
978 : : !!
979 : : !! FUNCTION
980 : : !! Find out what the complex phase factor is for off-diagonal elements
981 : : !! and unmix the components.
982 : : !!
983 : : !! INPUTS
984 : : !! fvals = The function to be fitted in the complex plane.
985 : : !! nomega = Number of fit points.
986 : : !! nfreqre = number or imaginary gridlines
987 : : !! phase = The phase angle.
988 : : !!
989 : : !! OUTPUT
990 : : !!
991 : : !! NOTES
992 : : !!
993 : : !! SOURCE
994 : :
995 : 0 : subroutine remove_phase(fval,nomega,phase)
996 : :
997 : : !Arguments ------------------------------------
998 : : !scalars
999 : : integer, intent(in) :: nomega
1000 : : real(gwp), intent(out) :: phase
1001 : : !arrays
1002 : : complex(gwp), intent(inout) :: fval(nomega)
1003 : :
1004 : : !Local variables-------------------------------
1005 : : !scalars
1006 : : integer :: io
1007 : : real(gwp) :: a,b,retemp,imtemp
1008 : : ! *********************************************************************
1009 : :
1010 : : ! The phase can be found by checking when the function is
1011 : : ! identically zero along the imaginary axis
1012 [ # # ]: 0 : if (ABS(AIMAG(fval(1)))<tol14) then ! Phase is zero
1013 : 0 : phase = zero
1014 : 0 : RETURN
1015 [ # # ]: 0 : else if (ABS(REAL(fval(1)))<tol14) then ! Phase is exactly pi/2
1016 : 0 : phase = pi*half
1017 : 0 : a = zero
1018 : 0 : b = -1.0_gwp
1019 : : else
1020 : 0 : phase = ATAN(AIMAG(fval(1))/REAL(fval(1)))
1021 : 0 : a = COS(phase)
1022 : 0 : b = -SIN(phase)
1023 : : end if
1024 : : ! Rotate values
1025 [ # # ]: 0 : do io=1,nomega
1026 : 0 : retemp = REAL(fval(io))
1027 : 0 : imtemp = AIMAG(fval(io))
1028 : 0 : fval(io) = CMPLX(a*retemp-b*imtemp,a*imtemp+b*retemp)
1029 : : end do
1030 : :
1031 : : end subroutine remove_phase
1032 : : !!***
1033 : :
1034 : : END MODULE m_model_screening
1035 : : !!***
|