@@ -114,6 +114,38 @@ get_multipole_field(const vec_t *xyz, const struct multipole_pt *mult_pt,
114114 return field ;
115115}
116116
117+ static double
118+ get_multipole_elec_potential (const vec_t * xyz , const struct multipole_pt * mult_pt ,
119+ const struct swf * swf )
120+ {
121+ double elpot = 0.0 ;
122+
123+ vec_t dr = {
124+ xyz -> x - mult_pt -> x - swf -> cell .x ,
125+ xyz -> y - mult_pt -> y - swf -> cell .y ,
126+ xyz -> z - mult_pt -> z - swf -> cell .z
127+ };
128+
129+ double r = vec_len (& dr );
130+ double r3 = r * r * r ;
131+ double r5 = r3 * r * r ;
132+ double r7 = r5 * r * r ;
133+
134+ /* charge */
135+ elpot += swf -> swf * mult_pt -> monopole / r ;
136+
137+ /* dipole */
138+ elpot += swf -> swf * vec_dot (& mult_pt -> dipole , & dr ) / r3 ;
139+
140+ /* quadrupole */
141+ elpot += swf -> swf * quadrupole_sum (mult_pt -> quadrupole , & dr ) / r5 ;
142+
143+ /* octupole */
144+ elpot += swf -> swf * octupole_sum (mult_pt -> octupole , & dr ) / r7 ;
145+
146+ return elpot ;
147+ }
148+
117149static vec_t
118150get_elec_field (const struct efp * efp , size_t frag_idx , size_t pt_idx )
119151{
@@ -1259,3 +1291,78 @@ efp_get_electric_field(struct efp *efp, size_t frag_idx, const double *xyz,
12591291 * ((vec_t * )field ) = elec_field ;
12601292 return EFP_RESULT_SUCCESS ;
12611293}
1294+
1295+ EFP_EXPORT enum efp_result
1296+ efp_get_elec_potential (struct efp * efp , size_t frag_idx , const double * xyz ,
1297+ double * elec_potential )
1298+ {
1299+ assert (efp );
1300+ assert (frag_idx < efp -> n_frag );
1301+ assert (xyz );
1302+ assert (elec_potential );
1303+
1304+ const struct frag * frag = efp -> frags + frag_idx ;
1305+ double elpot = 0.0 ;
1306+
1307+ for (size_t i = 0 ; i < efp -> n_frag ; i ++ ) {
1308+ if (i == frag_idx || efp_skip_frag_pair (efp , i , frag_idx ))
1309+ continue ;
1310+
1311+ const struct frag * fr_i = efp -> frags + i ;
1312+ struct swf swf = efp_make_swf (efp , fr_i , frag , 0 );
1313+ if (swf .swf == 0.0 )
1314+ continue ;
1315+
1316+ /* potential due to nuclei */
1317+ for (size_t j = 0 ; j < fr_i -> n_atoms ; j ++ ) {
1318+ const struct efp_atom * at = fr_i -> atoms + j ;
1319+
1320+ vec_t dr = {
1321+ xyz [0 ] - at -> x - swf .cell .x ,
1322+ xyz [1 ] - at -> y - swf .cell .y ,
1323+ xyz [2 ] - at -> z - swf .cell .z
1324+ };
1325+
1326+ double r = vec_len (& dr );
1327+
1328+ elpot += swf .swf * at -> znuc / r ;
1329+ }
1330+
1331+ /* potential due to multipoles */
1332+ for (size_t j = 0 ; j < fr_i -> n_multipole_pts ; j ++ ) {
1333+ const struct multipole_pt * mpt = fr_i -> multipole_pts + j ;
1334+ elpot += get_multipole_elec_potential ((const vec_t * )xyz , mpt , & swf );
1335+ }
1336+
1337+ /* potential due to induced dipoles */
1338+ for (size_t j = 0 ; j < fr_i -> n_polarizable_pts ; j ++ ) {
1339+ struct polarizable_pt * pt_i = fr_i -> polarizable_pts + j ;
1340+ size_t idx = fr_i -> polarizable_offset + j ;
1341+
1342+ vec_t dr = {
1343+ xyz [0 ] - pt_i -> x - swf .cell .x ,
1344+ xyz [1 ] - pt_i -> y - swf .cell .y ,
1345+ xyz [2 ] - pt_i -> z - swf .cell .z
1346+ };
1347+
1348+ double r = vec_len (& dr );
1349+ double r3 = r * r * r ;
1350+
1351+ elpot += swf .swf * 0.5 * (vec_dot (& efp -> indip [idx ], & dr ) + vec_dot (& efp -> indipconj [idx ], & dr )) / r3 ;
1352+ }
1353+ }
1354+
1355+ if (efp -> opts .terms & EFP_TERM_AI_POL ) {
1356+ /* elec potential due to nuclei from ab initio subsystem */
1357+ for (size_t i = 0 ; i < efp -> n_ptc ; i ++ ) {
1358+ vec_t dr = vec_sub ((const vec_t * )xyz , efp -> ptc_xyz + i );
1359+
1360+ double r = vec_len (& dr );
1361+
1362+ elpot += efp -> ptc [i ] / r ;
1363+ }
1364+ }
1365+
1366+ * elec_potential = elpot ;
1367+ return EFP_RESULT_SUCCESS ;
1368+ }
0 commit comments