@@ -300,6 +300,26 @@ struct NodeHolder {
300300 for (int no: range (N_ROT)) en += b[no] * logf ((1e-10f +b[no])*rcp (1e-10f +pr[no]));
301301 return en;
302302 }
303+
304+ // add by pengxd to split the potential and entropy
305+ template <int N_ROT, int EType>
306+ float node_entropy (int nn) {
307+ auto b = load_vec<N_ROT>(cur_belief,nn);
308+ b *= rcp (sum (b));
309+ auto pr = load_vec<N_ROT>(prob,nn);
310+
311+ float en = 0 ;
312+ if (EType == 0 ) {
313+ // average energy
314+ en = energy_offset[nn];
315+ for (int no: range (N_ROT)) en -= b[no] * logf ( 1e-10f +pr[no] );
316+ }
317+ else {
318+ // entropy
319+ for (int no: range (N_ROT)) en += b[no] * logf ( 1e-10f +b[no] );
320+ }
321+ return en;
322+ }
303323};
304324
305325constexpr static int simd_width = 4 ;
@@ -450,6 +470,33 @@ struct EdgeHolder {
450470 return en;
451471 }
452472
473+ // add by pengxd to split the potential and entropy
474+ template <int N_ROT1, int N_ROT2, int EType>
475+ float edge_entropy (int ne) {
476+ auto b1 = load_vec<N_ROT1>(nodes1.cur_belief , edge_indices1[ne]); // really marginal
477+ auto b2 = load_vec<N_ROT2>(nodes2.cur_belief , edge_indices2[ne]);
478+
479+ auto p = load_vec<N_ROT1* N_ROT2 >(marginal, ne);
480+ auto pr = load_vec<N_ROT1*ru (N_ROT2)>(prob, ne);
481+
482+ float en = 0 .f ;
483+ for (int no1: range (N_ROT1)) {
484+ for (int no2: range (N_ROT2)) {
485+ int i = no1*N_ROT2 + no2;
486+ if (EType == 0 ) {
487+ // average potential energy
488+ en -= p[i] * logf ( 1e-10f +pr[no1*ru (N_ROT2)+no2] );
489+ }
490+ else {
491+ // the mutual information
492+ en += p[i] * logf ( (1e-10f +p[i]) * rcp (1e-10f +b1[no1]*b2[no2]) );
493+ }
494+ }
495+ }
496+
497+ return en;
498+ }
499+
453500 template <int N_ROT1, int N_ROT2>
454501 void update_beliefs () {
455502 constexpr const int w1 = (N_ROT1+3 )/4 ;
@@ -598,6 +645,7 @@ struct RotamerSidechain: public PotentialNode {
598645 int max_iter;
599646 float tol;
600647 int iteration_chunk_size;
648+ int log_suffix;
601649
602650 bool energy_fresh_relative_to_derivative;
603651
@@ -627,14 +675,30 @@ struct RotamerSidechain: public PotentialNode {
627675 energy_cap (-4 .),
628676 energy_cap_width ( 1 .),
629677
630- damping (read_attribute<float >(grp, " ." , " damping" )),
631- max_iter (read_attribute<int >(grp, " ." , " max_iter" )),
632- tol (read_attribute<float >(grp, " ." , " tol" )),
678+ damping (read_attribute<float >(grp, " ." , " damping" )),
679+ max_iter (read_attribute<int >(grp, " ." , " max_iter" )),
680+ tol (read_attribute<float >(grp, " ." , " tol" )),
633681 iteration_chunk_size (read_attribute<int >(grp, " ." , " iteration_chunk_size" )),
682+ log_suffix (read_attribute<int > (grp, " ." , " log_suffix" , 0 )),
634683
635684 energy_fresh_relative_to_derivative (false ),
636685 n_bad_solve (0 )
637686 {
687+
688+ // Increment the suffix if another group exists
689+ // default_logger not created during python library call of engine, so must check for it first
690+ if (default_logger) {
691+ bool suff_exists = true ;
692+ while (suff_exists) {
693+ if (h5_exists (default_logger->logging_group .get (), (" rotamer_free_energy_" + to_string (log_suffix)).c_str ())) {
694+ log_suffix++;
695+ } else {
696+ suff_exists = false ;
697+ }
698+ }
699+ }
700+ // printf("log_suffix %i\n", log_suffix);
701+
638702 for (int i: range (UPPER_ROT)) node_holders_matrix[i] = nullptr ;
639703 node_holders_matrix[1 ] = &nodes1;
640704 node_holders_matrix[3 ] = &nodes3;
@@ -654,21 +718,41 @@ struct RotamerSidechain: public PotentialNode {
654718 " elements but the " + to_string (i) + " -th (0-indexed) probability node has only " +
655719 to_string (prob_nodes[i]->n_elem ) + " elements." );
656720
657- if (logging (LOG_DETAILED))
658- default_logger->add_logger <long >(" rotamer_bad_solves_cumulative" , {1 },
659- [&](long * buffer) {buffer[0 ]=n_bad_solve;});
660-
661721 if (logging (LOG_DETAILED)) {
662- default_logger->add_logger <float >(" rotamer_free_energy" , {nodes1.n_elem +nodes3.n_elem +nodes6.n_elem },
722+ string log_name = " rotamer_bad_solves_cumulative_" + to_string (log_suffix);
723+ default_logger->add_logger <long >(log_name.c_str (), {1 },
724+ [&](long * buffer) {buffer[0 ]=n_bad_solve;});
725+ }
726+ if (logging (LOG_BASIC)) {
727+ // add by pengxd to deal with multi-rotamer
728+ string log_name = " rotamer_free_energy_" + to_string (log_suffix);
729+ default_logger->add_logger <float >(log_name.c_str (), {nodes1.n_elem +nodes3.n_elem +nodes6.n_elem },
663730 [&](float * buffer) {
664731 auto en = residue_free_energies ();
665732 copy (begin (en), end (en), buffer);});
666733
667- for (int npn: range (n_prob_nodes))
668- default_logger->add_logger <float >((" rotamer_1body_energy" + to_string (npn)).c_str (),
734+ // add by pengxd to split the potential and entropy
735+ log_name = " rotamer_potential_" + to_string (log_suffix);
736+ default_logger->add_logger <float >(log_name.c_str (), {nodes1.n_elem +nodes3.n_elem +nodes6.n_elem },
737+ [&](float * buffer) {
738+ auto en = residue_entropy<0 >();
739+ copy (begin (en), end (en), buffer);});
740+
741+ // add by pengxd to split the potential and entropy
742+ log_name = " rotamer_entropy_" + to_string (log_suffix);
743+ default_logger->add_logger <float >(log_name.c_str (), {nodes1.n_elem +nodes3.n_elem +nodes6.n_elem },
744+ [&](float * buffer) {
745+ auto en = residue_entropy<1 >();
746+ copy (begin (en), end (en), buffer);});
747+
748+ // add by pengxd to deal with multi-rotamer
749+ for (int npn: range (n_prob_nodes)) {
750+ log_name = " rotamer_1body_energy_" + to_string (log_suffix);
751+ default_logger->add_logger <float >((log_name + to_string (npn)).c_str (),
669752 {nodes1.n_elem +nodes3.n_elem +nodes6.n_elem }, [npn,this ](float * buffer) {
670753 auto en = this ->rotamer_1body_energy (npn);
671754 copy (begin (en), end (en), buffer);});
755+ }
672756 }
673757 }
674758
@@ -903,6 +987,46 @@ struct RotamerSidechain: public PotentialNode {
903987 return arrange_energies (e1 ,e3 ,e6 );
904988 }
905989
990+ // add by pengxd to split the potential and entropy
991+ template <int EType>
992+ vector<float > residue_entropy () {
993+ vector<float > e1 (nodes1.n_elem , 0 .f );
994+ vector<float > e3 (nodes3.n_elem , 0 .f );
995+ vector<float > e6 (nodes6.n_elem , 0 .f );
996+
997+ for (int nn: range (nodes1 .n_elem )) {float en = nodes1.node_entropy <1 ,EType>(nn); e1 [nn] += en;}
998+ for (int nn: range (nodes3 .n_elem )) {float en = nodes3.node_entropy <3 ,EType>(nn); e3 [nn] += en;}
999+ for (int nn: range (nodes6 .n_elem )) {float en = nodes6.node_entropy <6 ,EType>(nn); e6 [nn] += en;}
1000+
1001+ if (EType == 0 ) {
1002+ for (int ne: range (edges11.nodes_to_edge .n_edge )) {
1003+ float en = -logf (edges11.prob (0 ,ne));
1004+ e1 [edges11.edge_indices1 [ne]] += 0.5 *en;
1005+ e1 [edges11.edge_indices2 [ne]] += 0.5 *en;
1006+ }
1007+ }
1008+
1009+ for (int ne: range (edges33.nodes_to_edge .n_edge )) {
1010+ float en = edges33.edge_entropy <3 ,3 ,EType>(ne);
1011+ e3 [edges33.edge_indices1 [ne]] += 0.5 *en;
1012+ e3 [edges33.edge_indices2 [ne]] += 0.5 *en;
1013+ }
1014+
1015+ for (int ne: range (edges36.nodes_to_edge .n_edge )) {
1016+ float en = edges36.edge_entropy <3 ,6 ,EType>(ne);
1017+ e3 [edges36.edge_indices1 [ne]] += 0.5 *en;
1018+ e6 [edges36.edge_indices2 [ne]] += 0.5 *en;
1019+ }
1020+
1021+ for (int ne: range (edges66.nodes_to_edge .n_edge )) {
1022+ float en = edges66.edge_entropy <6 ,6 ,EType>(ne);
1023+ e6 [edges66.edge_indices1 [ne]] += 0.5 *en;
1024+ e6 [edges66.edge_indices2 [ne]] += 0.5 *en;
1025+ }
1026+
1027+ return arrange_energies (e1 ,e3 ,e6 );
1028+ }
1029+
9061030 vector<float > rotamer_1body_energy (int prob_node_index) {
9071031 vector<float > e1 (nodes1.n_elem , 0 .f );
9081032 vector<float > e3 (nodes3.n_elem , 0 .f );
0 commit comments