Coverage for gpaw/fdtd/potential_couplers.py: 98%
62 statements
« prev ^ index » next coverage.py v7.7.1, created at 2025-07-12 00:18 +0000
« prev ^ index » next coverage.py v7.7.1, created at 2025-07-12 00:18 +0000
1"""Part of the module for electrodynamic simulations
3"""
6class PotentialCoupler():
7 def __init__(self,
8 qm, # PoissonOrganizer
9 cl, # PoissonOrganizer
10 index_offset_1,
11 index_offset_2,
12 extended_index_offset_1,
13 extended_index_offset_2,
14 extended_delta_index,
15 num_refinements,
16 remove_moment_qm,
17 remove_moment_cl,
18 rank):
19 self.qm = qm
20 self.cl = cl
21 self.index_offset_1 = index_offset_1
22 self.index_offset_2 = index_offset_2
23 self.extended_index_offset_1 = extended_index_offset_1
24 self.extended_index_offset_2 = extended_index_offset_2
25 self.extended_delta_index = extended_delta_index
26 self.num_refinements = num_refinements
27 self.remove_moment_qm = remove_moment_qm
28 self.remove_moment_cl = remove_moment_cl
29 self.rank = rank
31 # These are used to remember the previous solutions
32 self.old_local_phi_qm_qmgd = self.qm.gd.zeros()
33 self.old_local_phi_cl_clgd = self.cl.gd.zeros()
34 self.old_local_phi_qm_clgd = self.cl.gd.zeros()
36 # Add quantum and classical potentials
37 def couple(self,
38 qm_qmgd,
39 qm_clgd,
40 cl_qmgd,
41 cl_clgd):
42 tot_qmgd = cl_qmgd + qm_qmgd
43 tot_clgd = cl_clgd + qm_clgd
44 return tot_qmgd, tot_clgd
47# Coarsen quantum charge to suit the classical grid,
48# and refine classical potential to suit the quantum grid
49class RefinerPotentialCoupler(PotentialCoupler):
51 def __init__(self,
52 qm,
53 cl,
54 index_offset_1,
55 index_offset_2,
56 extended_index_offset_1,
57 extended_index_offset_2,
58 extended_delta_index,
59 num_refinements,
60 remove_moment_qm,
61 remove_moment_cl,
62 rank):
63 PotentialCoupler.__init__(self,
64 qm,
65 cl,
66 index_offset_1,
67 index_offset_2,
68 extended_index_offset_1,
69 extended_index_offset_2,
70 extended_delta_index,
71 num_refinements,
72 remove_moment_qm,
73 remove_moment_cl,
74 rank)
76 def getPotential(self, local_rho_qm_qmgd, local_rho_cl_clgd, **kwargs):
77 # Quantum potential
78 local_phi_qm_qmgd = self.old_local_phi_qm_qmgd
79 niter_qm = self.qm.poisson_solver.solve(phi=local_phi_qm_qmgd,
80 rho=local_rho_qm_qmgd,
81 **kwargs)
82 self.old_local_phi_qm_qmgd = local_phi_qm_qmgd.copy()
84 # Classical potential
85 local_phi_cl_clgd = self.old_local_phi_cl_clgd
86 niter_cl = self.cl.poisson_solver.solve(phi=local_phi_cl_clgd,
87 rho=local_rho_cl_clgd,
88 **kwargs)
89 self.old_local_phi_cl_clgd = local_phi_cl_clgd.copy()
91 # Transfer classical potential into quantum subsystem
92 global_phi_cl_clgd = self.cl.gd.collect(local_phi_cl_clgd)
93 local_phi_cl_qmgd = self.qm.gd.zeros()
94 global_phi_cl_qmgd = self.qm.gd.zeros(global_array=True)
96 if self.rank == 0:
97 # Extract the overlapping region from the classical potential
98 o1 = self.extended_index_offset_1
99 o2 = self.extended_index_offset_2
100 global_phi_cl_clgd_refined = global_phi_cl_clgd[
101 o1[0]:o2[0] - 1,
102 o1[1]:o2[1] - 1,
103 o1[2]:o2[2] - 1].copy()
105 for n in range(self.num_refinements):
106 global_phi_cl_clgd_refined = \
107 self.cl.extended_refiners[n].apply(
108 global_phi_cl_clgd_refined)
110 global_phi_cl_qmgd = global_phi_cl_clgd_refined[
111 self.extended_delta_index:-self.extended_delta_index,
112 self.extended_delta_index:-self.extended_delta_index,
113 self.extended_delta_index:-self.extended_delta_index]
115 self.qm.gd.distribute(global_phi_cl_qmgd, local_phi_cl_qmgd)
117 # Transfer quantum density into classical grid
118 global_rho_qm_qmgd = self.qm.gd.collect(local_rho_qm_qmgd)
119 global_rho_qm_clgd = self.cl.gd.zeros(global_array=True)
120 local_rho_qm_clgd = self.cl.gd.zeros()
122 if self.rank == 0:
123 # Coarsen the quantum density
124 global_rho_qm_qmgd_coarsened = global_rho_qm_qmgd
125 for n in range(self.num_refinements):
126 global_rho_qm_qmgd_coarsened = \
127 self.cl.coarseners[n].apply(global_rho_qm_qmgd_coarsened)
129 # Add the coarsened quantum density
130 o1 = self.index_offset_1
131 o2 = self.index_offset_2
132 global_rho_qm_clgd[o1[0]:o2[0] - 1,
133 o1[1]:o2[1] - 1,
134 o1[2]:o2[2] - 1] = \
135 global_rho_qm_qmgd_coarsened[:]
137 # Distribute the combined density to all processes
138 self.cl.gd.distribute(global_rho_qm_clgd, local_rho_qm_clgd)
140 # Solve quantum potential on classical grid
141 local_phi_qm_clgd = self.old_local_phi_qm_clgd
142 self.cl.poisson_solver.remove_moment = None
143 niter_qm_clgd = self.cl.poisson_solver.solve(phi=local_phi_qm_clgd,
144 rho=local_rho_qm_clgd,
145 **kwargs)
146 self.cl.poisson_solver.remove_moment = self.remove_moment_cl
147 self.old_local_phi_qm_clgd = local_phi_qm_clgd.copy()
149 # Sum quantum and classical potentials
150 local_phi_tot_qmgd, local_phi_tot_clgd = \
151 self.couple(qm_qmgd=local_phi_qm_qmgd,
152 qm_clgd=local_phi_qm_clgd,
153 cl_qmgd=local_phi_cl_qmgd,
154 cl_clgd=local_phi_cl_clgd)
156 return local_phi_tot_qmgd, local_phi_tot_clgd, \
157 (niter_qm, niter_cl, niter_qm_clgd)
160class MultipolesPotentialCoupler(PotentialCoupler):
161 def __init__(self, *args, **kwargs):
162 # The latest appearance of this class is in
163 # trac.fysik.dtu.dk/projects/gpaw/browser/
164 # branches/electrodynamics/gpaw/fdtd/potential_couplers.py?rev=11708
165 #
166 # Re-added here a dummy class for compatibility with FDTDPoissonSolver.
167 # See above code if you want to reintroduce the working code here.
168 raise RuntimeError("MultipolesPotentialCoupler not supported." +
169 "Check the code.")