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

1"""Part of the module for electrodynamic simulations 

2 

3""" 

4 

5 

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 

30 

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() 

35 

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 

45 

46 

47# Coarsen quantum charge to suit the classical grid, 

48# and refine classical potential to suit the quantum grid 

49class RefinerPotentialCoupler(PotentialCoupler): 

50 

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) 

75 

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() 

83 

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() 

90 

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) 

95 

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() 

104 

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) 

109 

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] 

114 

115 self.qm.gd.distribute(global_phi_cl_qmgd, local_phi_cl_qmgd) 

116 

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() 

121 

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) 

128 

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[:] 

136 

137 # Distribute the combined density to all processes 

138 self.cl.gd.distribute(global_rho_qm_clgd, local_rho_qm_clgd) 

139 

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() 

148 

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) 

155 

156 return local_phi_tot_qmgd, local_phi_tot_clgd, \ 

157 (niter_qm, niter_cl, niter_qm_clgd) 

158 

159 

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.")