77import numpy as np
88
99from .. import common , elements , io
10+ from ..logging_utils import get_logger , get_perf_logger , perf_log_enabled
1011from ..PPPlot import plotImages
1112from . import field as FFcl
1213from . import oclUtils as oclu
1516
1617VALID_SIZES = np .array ([16 , 32 , 64 , 128 , 192 , 256 , 384 , 512 , 768 , 1024 , 1536 , 2048 ])
1718
19+ logger = get_logger ("AFMulator" )
20+ perf_logger = get_perf_logger ("AFMulator" )
21+
1822
1923class AFMulator :
2024 """
@@ -67,14 +71,12 @@ class AFMulator:
6771 """
6872
6973 bMergeConv = False # Should we use merged kernel relaxStrokesTilted_convZ or two separated kernells ( relaxStrokesTilted, convolveZ )
70- bRuntime = False # Print timings during execution
7174
7275 # --- Relaxation
7376 relaxParams = [0.5 , 0.1 , 0.1 * 0.2 , 0.1 * 5.0 ] # (dt,damp, .., .. ) parameters of relaxation, in the moment just dt and damp are used
7477
7578 # --- Output
7679 bSaveFF = False # Save debug ForceField as .xsf
77- verbose = 0 # Print information during excecution
7880
7981 # ==================== Methods =====================
8082
@@ -161,15 +163,13 @@ def eval(self, xyzs, Zs, qs, rho_sample=None, sample_lvec=None, rot=np.eye(3), r
161163 Returns:
162164 X: np.ndarray. Output AFM images. If input X is not None, this is the same array object as X with values overwritten.
163165 """
164- if self .bRuntime :
165- t0 = time .perf_counter ()
166+ t0 = time .perf_counter ()
166167 self .prepareFF (xyzs , Zs , qs , rho_sample , sample_lvec , rot , rot_center , REAs )
167168 self .prepareScanner ()
168169 X = self .evalAFM (X )
169170 if plot_to_dir :
170171 self .plot_images (X , outdir = plot_to_dir )
171- if self .bRuntime :
172- print ("runtime(AFMulator.eval) [s]: " , time .perf_counter () - t0 )
172+ perf_logger .info (f"eval [s]: { time .perf_counter () - t0 } " )
173173 return X
174174
175175 def __call__ (self , * args , ** kwargs ):
@@ -186,8 +186,7 @@ def eval_(self, mol):
186186 def setLvec (self , lvec = None , pixPerAngstrome = None ):
187187 """Set forcefield lattice vectors. If lvec is not given it is inferred from the scan window."""
188188
189- if self .bRuntime :
190- t0 = time .perf_counter ()
189+ t0 = time .perf_counter ()
191190
192191 if pixPerAngstrome is not None :
193192 self .pixPerAngstrome = pixPerAngstrome
@@ -207,14 +206,12 @@ def setLvec(self, lvec=None, pixPerAngstrome=None):
207206 FEin_shape = self .forcefield .nDim if (self ._old_nDim != self .forcefield .nDim ).any () else None
208207 self .scanner .prepareBuffers (lvec = self .lvec , FEin_shape = FEin_shape )
209208
210- if self .bRuntime :
211- print ("runtime(AFMulator.setLvec) [s]: " , time .perf_counter () - t0 )
209+ perf_logger .info (f"setLvec [s]: { time .perf_counter () - t0 } " )
212210
213211 def setScanWindow (self , scan_window = None , scan_dim = None , df_steps = None ):
214212 """Set scanner scan window."""
215213
216- if self .bRuntime :
217- t0 = time .perf_counter ()
214+ t0 = time .perf_counter ()
218215
219216 if scan_window is not None :
220217 self .scan_window = scan_window
@@ -241,8 +238,7 @@ def setScanWindow(self, scan_window=None, scan_dim=None, df_steps=None):
241238 self .scanner .updateBuffers (WZconv = self .dfWeight )
242239 self .scanner .preparePosBasis (start = self .scan_window [0 ][:2 ], end = self .scan_window [1 ][:2 ])
243240
244- if self .bRuntime :
245- print ("runtime(AFMulator.setScanWindow) [s]: " , time .perf_counter () - t0 )
241+ perf_logger .info (f"setScanWindow [s]: { time .perf_counter () - t0 } " )
246242
247243 def setRho (self , rho = None , sigma = 0.71 , B_pauli = 1.0 ):
248244 """Set tip charge distribution.
@@ -252,8 +248,7 @@ def setRho(self, rho=None, sigma=0.71, B_pauli=1.0):
252248 sigma: float. Tip charge density distribution when rho is a dict.
253249 B_pauli: float. Pauli repulsion exponent for tip density when using FDBM.
254250 """
255- if self .bRuntime :
256- t0 = time .perf_counter ()
251+ t0 = time .perf_counter ()
257252 if rho is not None :
258253 self .sigma = sigma
259254 self .B_pauli = B_pauli
@@ -270,8 +265,7 @@ def setRho(self, rho=None, sigma=0.71, B_pauli=1.0):
270265 if not isinstance (rho , TipDensity ):
271266 raise ValueError (f"rho should of type `TipDensity`, but got `{ type (rho )} `" )
272267 self .rho = rho
273- if self .verbose > 0 :
274- print ("AFMulator.setRho: Preparing buffers" )
268+ logger .debug ("setRho: Preparing buffers" )
275269 if not np .allclose (B_pauli , 1.0 ):
276270 rho_power = self .rho .power_positive (p = self .B_pauli , in_place = False )
277271 if self .minimize_memory :
@@ -282,13 +276,12 @@ def setRho(self, rho=None, sigma=0.71, B_pauli=1.0):
282276 self ._rho = None
283277 self .rho = None
284278 if self .forcefield .rho is not None :
285- if self .verbose > 0 :
286- print ("AFMulator.setRho: Releasing buffers" )
279+ logger .debug ("setRho: Releasing buffers" )
287280 self .forcefield .rho .release ()
288281 self .forcefield .rho = None
289- if self . bRuntime :
282+ if perf_log_enabled () :
290283 self .forcefield .queue .finish ()
291- print ( "runtime(AFMulator. setRho) [s]: " , time .perf_counter () - t0 )
284+ perf_logger . info ( f" setRho [s]: { time .perf_counter () - t0 } " )
292285
293286 def setBPauli (self , B_pauli = 1.0 ):
294287 """Set Pauli repulsion exponent used in FDBM."""
@@ -300,22 +293,18 @@ def setRhoDelta(self, rho_delta=None):
300293 Arguments:
301294 rho_delta: :class:`.TipDensity` or None. Tip electron delta-density. If None, the existing density is deleted.
302295 """
303- if self .bRuntime :
304- t0 = time .perf_counter ()
296+ t0 = time .perf_counter ()
305297 self .rho_delta = rho_delta
306298 if self .rho_delta is not None :
307299 if not isinstance (rho_delta , TipDensity ):
308300 raise ValueError (f"rho_delta should of type `TipDensity`, but got `{ type (rho_delta )} `" )
309- if self .verbose > 0 :
310- print ("AFMulator.setRhoDelta: Preparing buffers" )
301+ logger .debug ("setRhoDelta: Preparing buffers" )
311302 self .forcefield .prepareBuffers (rho_delta = self .rho_delta , bDirect = True , minimize_memory = self .minimize_memory )
312303 elif self .forcefield .rho_delta is not None :
313- if self .verbose > 0 :
314- print ("AFMulator.setRhoDelta: Releasing buffers" )
304+ logger .debug ("setRhoDelta: Releasing buffers" )
315305 self .forcefield .rho_delta .release ()
316306 self .forcefield .rho_delta = None
317- if self .bRuntime :
318- print ("runtime(AFMulator.setRhoDelta) [s]: " , time .perf_counter () - t0 )
307+ perf_logger .info (f"setRhoDelta [s]: { time .perf_counter () - t0 } " )
319308
320309 def setQs (self , Qs , QZs ):
321310 """Set tip point charges."""
@@ -348,18 +337,14 @@ def prepareFF(self, xyzs, Zs, qs, rho_sample=None, sample_lvec=None, rot=np.eye(
348337 rot_center: np.ndarray of shape (3,). Center for rotation. Defaults to center of atom coordinates.
349338 REAs: np.ndarray of shape (num_atoms, 4). Lennard Jones interaction parameters. Calculated automatically if None.
350339 """
351- if self .bRuntime :
352- t0 = time .perf_counter ()
340+ t0 = time .perf_counter ()
353341
354342 # Check if the scan window extends over any non-periodic boundaries and issue a warning if it does
355343 self .check_scan_window ()
356344
357345 # (Re)initialize force field if the size of the grid changed since last run.
358346 if (self ._old_nDim != self .forcefield .nDim ).any ():
359- if self .verbose > 0 :
360- print ("(Re)initializing force field buffers." )
361- if self .verbose > 1 :
362- print (f"old nDim: { self ._old_nDim } , new nDim: { self .forcefield .nDim } " )
347+ logger .debug (f"(Re)initializing force field buffers. Old nDim: { self ._old_nDim } , new nDim: { self .forcefield .nDim } " )
363348 self .forcefield .tryReleaseBuffers ()
364349 if self ._rho is not None :
365350 # The grid size changed so we need to recompute/reinterpolate the tip density grid
@@ -441,14 +426,12 @@ def prepareFF(self, xyzs, Zs, qs, rho_sample=None, sample_lvec=None, rot=np.eye(
441426 if self .bSaveFF :
442427 self .saveFF ()
443428
444- if self .bRuntime :
445- print ("runtime(AFMulator.prepareFF) [s]: " , time .perf_counter () - t0 )
429+ perf_logger .info (f"prepareFF [s]: { time .perf_counter () - t0 } " )
446430
447431 def prepareScanner (self ):
448432 """Prepare scanner. Run after preparing force field."""
449433
450- if self .bRuntime :
451- t0 = time .perf_counter ()
434+ t0 = time .perf_counter ()
452435
453436 # Copy forcefield array to scanner buffer
454437 self .scanner .updateFEin (self .forcefield .cl_FE )
@@ -459,8 +442,7 @@ def prepareScanner(self):
459442 # Prepare tip position array
460443 self .scanner .setScanRot (self .pos0 , rot = np .eye (3 ), tipR0 = self .tipR0 )
461444
462- if self .bRuntime :
463- print ("runtime(AFMulator.prepareScanner) [s]: " , time .perf_counter () - t0 )
445+ perf_logger .info (f"prepareScanner [s]: { time .perf_counter () - t0 } " )
464446
465447 def evalAFM (self , X = None ):
466448 """
@@ -474,8 +456,7 @@ def evalAFM(self, X=None):
474456 X: np.ndarray. Output AFM images. If input X is not None, this is the same array object as X with values overwritten.
475457 """
476458
477- if self .bRuntime :
478- t0 = time .perf_counter ()
459+ t0 = time .perf_counter ()
479460
480461 if self .bMergeConv :
481462 FEout = self .scanner .run_relaxStrokesTilted_convZ ()
@@ -493,8 +474,7 @@ def evalAFM(self, X=None):
493474 )
494475 X [:, :, :] = FEout [:, :, :, 2 ]
495476
496- if self .bRuntime :
497- print ("runtime(AFMulator.evalAFM) [s]: " , time .perf_counter () - t0 )
477+ perf_logger .info (f"evalAFM [s]: { time .perf_counter () - t0 } " )
498478
499479 return X
500480
@@ -597,15 +577,13 @@ def saveFF(self):
597577 FFx .flat [mask ] *= (Fbound / Fr ).flat [mask ]
598578 FFy .flat [mask ] *= (Fbound / Fr ).flat [mask ]
599579 FFz .flat [mask ] *= (Fbound / Fr ).flat [mask ]
600- if self .verbose > 0 :
601- print ("FF.shape " , FF .shape )
580+ logger .debug (f"FF.shape { FF .shape } " )
602581 self .saveDebugXSF_FF (self .saveFFpre + "FF_x.xsf" , FFx )
603582 self .saveDebugXSF_FF (self .saveFFpre + "FF_y.xsf" , FFy )
604583 self .saveDebugXSF_FF (self .saveFFpre + "FF_z.xsf" , FFz )
605584
606585 def saveDebugXSF_FF (self , fname , F ):
607- if self .verbose > 0 :
608- print ("saveDebugXSF : " , fname )
586+ logger .debug (f"saveDebugXSF: { fname } " )
609587 io .saveXSF (fname , F , self .lvec )
610588
611589 def check_scan_window (self ):
@@ -621,8 +599,8 @@ def check_scan_window(self):
621599 scan_start -= self .tipR0 [2 ]
622600 scan_end -= self .tipR0 [2 ]
623601 if (scan_start < lvec_start ) or (scan_end > lvec_end ):
624- print (
625- f"Warning: The edge of the scan window in { dim } dimension is very close or extends over "
602+ logger . warning (
603+ f"The edge of the scan window in { dim } dimension is very close or extends over "
626604 f"the boundary of the force-field grid which is not periodic in { dim } dimension. "
627605 "If you get artifacts in the images, please check the boundary conditions and "
628606 "the size of the scan window and the force field grid."
0 commit comments