#include "../dat/DAT_ARRAY_CONSTS.hh"
#include "../dat/DAT_PHYSICS_CONSTS.hh"
#include "../med/Dielec_Continu.hh"
#include "../phi/Coordinates.hh"
#include "../phi/Scratch_Multipoles.hh"
#include "../phi/Spherical_Harmonics.hh"
#include "../str/Output_Streams.hh"
#include <string>
#include <vector>
#include <iostream>
#include <cstdlib>
#include <iomanip>
#include <cmath>
// MAC
////#include <Accelerate/Accelerate.h>
////#include <vecLib/clapack.h>
////// Linux
////extern "C" {
////#include <cblas.h>
////#include <clapack.h>
////}

class MEM_med_sig {
public:
   std::vector<int> o_D5ord;            //mapping dot index to order
   std::vector<double> o_D5x;           //
   std::vector<double> o_D5D5a;         //
   MEM_med_sig(){
   }
   int& D5ord(int i){
      return o_D5ord.at( i);  }
   double& D5x(int i){
      return o_D5x.at( i);  }
};

void Dielec_Continu::MED_SIG(const DAT_PHYSICS_CONSTS& physics_consts,
                             const DAT_ARRAY_CONSTS& array_consts,
                             Output_Streams& out){
   MEM_med_sig vv;
   double f=( (1.) -(80.))/((2.)*physics_consts.PI*( (1.) +(80.)));
   Scratch_Multipoles q1;               //
   Scratch_Multipoles q2;               //
   Scratch_Multipoles q3;               //
   Scratch_Multipoles QQ;               //
   Spherical_Harmonics H;               //
//
//
// (1/r)**(L+1) >(1e-4)/(L+1)(4**L)
//
   double Lr[ 8];                       //(1/r)**L
   double Lz[ 8];                       //(1e-4)/L*(4**(L-1))
   Lz[ 1]= (1.00e-4);
   for(int L=2;L<8;L++){
      Lz[L  ]= Lz[L-1]*(L-1)/((L  )*(4.));
   }
   double Lb[ 8];                       //(1e-4)/L*(b**(L-1))
//
//
// DOT[].qn, D5[].qn
//
   for(int iD5= 0;iD5<nD5;iD5++){
      int iDOTmin=D5[iD5].DOTa;
      int iDOTmax=(iDOTmin-1+D5[iD5].cDOT);
      q2.populate( 5,D5[iD5].n);
      int mA5;
      if( D5[iD5].bse>=0 ){
         D5[iD5].qn= bse_D5[D5[iD5].bse].qn;
         mA5= bse_nA5;
      }else{
         D5[iD5].qn= (0.00);
         mA5= 0;
      }
      double b=( D5[iD5].d>(4.00) )? D5[iD5].d: (4.00);
      b*=(4.00);
      Lb[ 1]= (1.00e-5);
      for(int L=2;L<8;L++){
         Lb[L  ]= Lb[L-1]*(L-1)/((L  )*b);
      }
      double qn= (0.00);
      for(int iA5=mA5;iA5<nA5;iA5++){
         int LTE1=A5[iA5].lte;
         q1.populate(LTE1,A5[iA5].q);
         Coordinates d=( A5[iA5].x -D5[iD5].x);
         double r= d.r();
         double z= (1.00)/r;
//       if( r<( 1.00) ){
//          int jDOT=D5[iD5].DOTa;
//          std::cerr<< std::fixed<< std::setprecision( 3);
//          std::cerr<<"FLAG: Short (surface element,atom) distance."
//                   <<"  r="<< std::setw( 7)<<r
//                   << std::endl;
//          std::cerr<<" iD5="<< std::setw( 5)<<iD5
//                   <<D5[iD5].x
//                   <<" typ="<< std::setw( 2)<<DOT[jDOT].typ
//                   <<" d="<< std::setw( 7)<<D5[iD5].d
//                   <<" a="<< std::setw( 7)<<D5[iD5].a
//                   << std::endl;
//          std::cerr<<" iA5="<< std::setw( 5)<<iA5
//                   <<A5[iA5].x
//                   <<' '<<A5[iA5].atm
//                   <<" sa="<< std::setw( 7)<<A5[iA5].sa
//                   << std::endl;
//       }
         int LTE=6;
         Lr[ 1]= z;
         for(int L=2;L<=(LTE+1);L++){
            Lr[L  ]= z*Lr[L-1];
            if( Lr[L  ]<Lb[L  ] )LTE=(L-2);
         }
         if( LTE<=5 ){
            double CT= (d(2)*z);
            double ST= std::sqrt( (1.00) -CT*CT);
            double CP,SP;
            if( ST>(1.00e-10) ){
               CP= (d(0)*z)/ST;
               SP= (d(1)*z)/ST;
            }else{
               CP= (1.00);
               SP= (0.00);
            }
            H.populate(array_consts,LTE,CT,ST,CP,SP);
            if( LTE1>0 ){
               QQ.populate(LTE);
               QQ.product(array_consts,q2,q1);
               for(int L=0;L<=LTE;L++){
                  double F= (0.00);
                  for(int M=-L;M<=L;M++){
                     F+=( QQ.r(L,M)*H.r(L,M)
                         -QQ.i(L,M)*H.i(L,M));
                  }
                  qn+=(Lr[L+1]*F);
               }
            }else{
               double G= (0.00);
               for(int L=0;L<=LTE;L++){
                  double F= (0.00);
                  for(int M=-L;M<=L;M++){
                     F+=( q2.r(L,M)*H.r(L,M)
                         -q2.i(L,M)*H.i(L,M));
                  }
                  G+=(Lr[L+1]*F);
               }
               qn+=(A5[iA5].q.r(0,0)*G);
            }
         }else{
            for(int iDOT=iDOTmin;iDOT<=iDOTmax;iDOT++){
               q3.populate( 1,DOT[iDOT].n);
               d=( DOT[iDOT].x -A5[iA5].x);
               r= d.r();
               z= (1.00)/r;
               LTE=(1+LTE1);
               Lr[ 1]= z;
               for(int L=2;L<=(LTE+1);L++){
                  Lr[L  ]= z*Lr[L-1];
                  if( Lr[L  ]<Lz[L  ] )LTE=(L-2);
               }
               double t= (0.00);
               if      ( LTE==0 ){
               }else if( LTE==1 ){
                  double Cthe= z*dot(d,DOT[iDOT].c);
                  t+=(Lr[ 2]*A5[iA5].q.r(0,0)*Cthe);
               }else{
                  double CT= d(2)*z;
                  double ST= std::sqrt( (1.00) -CT*CT);
                  double CP,SP;
                  if( ST>(1.00e-10) ){
                     CP= d(0)*z/ST;
                     SP= d(1)*z/ST;
                  }else{
                     CP= (1.00);
                     SP= (0.00);
                  }
                  QQ.populate(LTE);
                  QQ.product(array_consts,q1,q3);
                  H.populate(array_consts,LTE,CT,ST,CP,SP);
                  for(int L=0;L<=LTE;L++){
                     double F= (0.00);
                     for(int M=-L;M<=L;M++){
                        F+=( QQ.r(L,M)*H.r(L,M)
                            -QQ.i(L,M)*H.i(L,M));
                     }
                     t-=Lr[L+1]*F;
                  }
               }
               qn+=(DOT[iDOT].a*t);
            }
         }
      }
      qn*=f;
      D5[iD5].qn+=qn;
   }
//
//
// D5D5lu
//
   o_D5D5lu.resize(nD5*nD5,(0.00));
   for(int iD5= 0;iD5<nD5;iD5++){
      int iDOTmin=D5[iD5].DOTa;
      int iDOTmax=(iDOTmin-1+D5[iD5].cDOT);
      q1.populate( 5,D5[iD5].n);
      for(int jD5= 0;jD5<nD5;jD5++){
         int jDOTmin=D5[jD5].DOTa;
         int jDOTmax=(jDOTmin-1+D5[jD5].cDOT);
         if( (D5[iD5].bse>=0)&&(D5[jD5].bse>=0) ){
            D5D5lu(iD5,jD5)= D5D5ne(D5[iD5].bse,D5[jD5].bse);
         }else{
            double b=( D5[jD5].d>D5[iD5].d )? D5[jD5].d: D5[iD5].d;
            Coordinates d=( D5[jD5].x -D5[iD5].x);
            double r= d.r();
            if( r<(1.00e-6) )r= (1.00e-6);
            double z= (1.00)/r;
            int LTE=6;
            Lb[ 1]= (1.00e-4);
            Lr[ 1]= z;
            for(int L=2;L<=(LTE+1);L++){
               Lb[L  ]= Lb[L-1]*(L-1)/((L  )*b);
               Lr[L  ]= z*Lr[L-1];
               if( Lr[L  ]<Lb[L  ] )LTE=(L-2);
            }
            if( LTE<=5 ){
               q2.populate((LTE-1),D5[jD5].e);
               double CT= (d(2)*z);
               double ST= std::sqrt( (1.00) -CT*CT);
               double CP,SP;
               if( ST>(1.00e-10) ){
                  CP= (d(0)*z)/ST;
                  SP= (d(1)*z)/ST;
               }else{
                  CP= (1.00);
                  SP= (0.00);
               }
               QQ.populate(LTE);
               QQ.product(array_consts,q1,q2);
               H.populate(array_consts,LTE,CT,ST,CP,SP);
               for(int L=0;L<=LTE;L++){
                  double F= (0.00);
                  for(int M=-L;M<=L;M++){
                     F+=( QQ.r(L,M)*H.r(L,M)
                         -QQ.i(L,M)*H.i(L,M));
                  }
                  D5D5lu(iD5,jD5)+=Lr[L+1]*F;
               }
            }else{
               for(int iDOT=iDOTmin;iDOT<=iDOTmax;iDOT++){
                  double en= (0.00);
                  for(int jDOT=jDOTmin;jDOT<=jDOTmax;jDOT++){
                     if( jDOT==iDOT ){
                        if( DOT[jDOT].TILE ){
                        if      ( DOT[jDOT].typ==-1 ){
                           en-=((2.)*physics_consts.PI/std::sqrt(320.));
                        }else if( DOT[jDOT].typ== 0 ){
                        }else if( DOT[jDOT].typ== 1 ){
                           en+=((2.)*physics_consts.PI/std::sqrt(320.));
                        }
                        }
                     }else{
                        d=( DOT[iDOT].x -DOT[jDOT].x);
                        r= d.r();
                        if( r<(0.80) )continue;
                        z= (1.00)/r;
                        double s= MED_SWITCH( r);
                        double Cthe= z*dot(d,DOT[iDOT].c);
                        en+=(s*z*z*DOT[jDOT].a*Cthe);
                     }
                  }
                  D5D5lu(iD5,jD5)-=(DOT[iDOT].a*en);
               }
            }
            D5D5lu(iD5,jD5)*=f;
         }
      }
      D5D5lu(iD5,iD5)+=D5[iD5].a;
   }
//
//
// D5D5lu constrain adjacent sig
//
   for(int iD5= 0;iD5<nD5;iD5++){
      if( D5[iD5].a> (0.50) )continue;
      int iDOTmin=D5[iD5].DOTa;
      int iDOTmax=(iDOTmin-1+D5[iD5].cDOT);
      for(int jD5= 0;jD5<nD5;jD5++){
         if( jD5==iD5 )continue;
         if( D5[jD5].a< (2.00) )continue;
         int jDOTmin=D5[jD5].DOTa;
         int jDOTmax=(jDOTmin-1+D5[jD5].cDOT);
         Coordinates d=( D5[jD5].x -D5[iD5].x);
         double r= d.r();
         if( r> (5.00) )continue;
         bool ADJACENT=false;
         for(int iDOT=iDOTmin;iDOT<=iDOTmax&&(!ADJACENT);iDOT++){
            for(int jDOT=jDOTmin;jDOT<=jDOTmax&&(!ADJACENT);jDOT++){
               d=( DOT[iDOT].x -DOT[jDOT].x);
               r= d.r();
               if( r<(0.80) ){
                  double lam=( D5[iD5].qn*D5[iD5].qn
                              +D5[jD5].qn*D5[jD5].qn)*(25.e+4)/(32.);
                  D5D5lu(iD5,iD5)+=lam;
                  D5D5lu(iD5,jD5)-=lam;
                  D5D5lu(jD5,iD5)-=lam;
                  D5D5lu(jD5,jD5)+=lam;
                  ADJACENT=true;
               }
            }
         }
      }
   }
//
//
// factor D5D5lu
//
   double ZERO= (1.00e-16);
   for(int pD5= 0;pD5<nD5;pD5++){
      for(int iD5=pD5;iD5<nD5;iD5++){
         double z= D5D5lu(iD5,pD5);
         for(int kD5= 0;kD5<pD5;kD5++){
            z-=(D5D5lu(iD5,kD5)*D5D5lu(kD5,pD5));
         }
         D5D5lu(iD5,pD5)= z;
      }
      if( std::abs( D5D5lu(pD5,pD5))<ZERO ){
         D5D5lu(pD5,pD5)= ZERO;
         std::cerr<<"FLAG: Occurrence in LU decomposition of D5D5lu of"
                    " diagonal element\n with absolute value below zero"
                    " threshold.\n";
      }
      if( pD5<(nD5-1) ){
         double h= (1.00)/D5D5lu(pD5,pD5);
         for(int jD5=(pD5+1);jD5<nD5;jD5++){
            double z= D5D5lu(pD5,jD5);
            for(int kD5= 0;kD5<pD5;kD5++){
               z-=(D5D5lu(pD5,kD5)*D5D5lu(kD5,jD5));
            }
            D5D5lu(pD5,jD5)= h*z;
         }
      }
   }
//
//
// D5D5lu(i,j)*D5[j].sig= D5[i].qn
//
   vv.o_D5x.resize(nD5);
   for(int iD5= 0;iD5<nD5;iD5++){
      double z= D5[iD5].qn;
      for(int jD5= 0;jD5<iD5;jD5++){
         z-=(D5D5lu(iD5,jD5)*D5x[jD5]);
      }
      D5x[iD5]= z/D5D5lu(iD5,iD5);
   }
   for(int iD5=(nD5-1);iD5>= 0;iD5--){
      double z= D5x[iD5];
      for(int jD5=(iD5+1);jD5<nD5;jD5++){
         z-=(D5D5lu(iD5,jD5)*D5[jD5].sig);
      }
      D5[iD5].sig= z;
   }
   o_D5D5lu.clear();
   vv.o_D5x.clear();
//
//
// MAC LAPACK alternative path to D5[].sig
//
////   std::vector<__CLPK_doublereal> l_D5D5a(nD5*nD5); //
////   std::vector<__CLPK_doublereal> l_D5x(nD5);       //
////   for(int iD5= 0;iD5<nD5;iD5++){
////      l_D5x[iD5]= D5[iD5].qn;
////      for(int jD5= 0;jD5<nD5;jD5++){
////         l_D5D5a[iD5+jD5*nD5]= D5D5lu(iD5,jD5);
////      }
////   }
////   std::vector<__CLPK_integer> l_D5ord(nD5);        //
////   __CLPK_integer n=nD5;
////   __CLPK_integer m=1;
////   __CLPK_integer error_code;
////   dgesv_(&n,&m,&l_D5D5a[ 0],&n,&l_D5ord[ 0],&l_D5x[ 0],&n,&error_code);
////   for(int iD5= 0;iD5<nD5;iD5++){
////      D5[iD5].sig= l_D5x[iD5];
////   }
////   o_D5D5lu.clear();
////   l_D5D5a.clear();
////   l_D5x.clear();
////   l_D5ord.clear();
//
//
// Linux LAPACK alternative path to D5[].sig
//
////   vv.o_D5D5a.resize(nD5*nD5);
////   vv.o_D5x.resize(nD5);
////   for(int iD5= 0;iD5<nD5;iD5++){
////      vv.o_D5x[iD5]= D5[iD5].qn;
////      for(int jD5= 0;jD5<nD5;jD5++){
////         vv.o_D5D5a[iD5+jD5*nD5]= D5D5lu(iD5,jD5);
////      }
////   }
////   vv.o_D5ord.resize(nD5);
////   int n=nD5;
////   int m=1;
////   clapack_dgesv(CblasColMajor,n,m,&vv.o_D5D5a[ 0],n,&vv.o_D5ord[ 0],
////                 &vv.o_D5x[ 0],n);
////   for(int iD5= 0;iD5<nD5;iD5++){
////      D5[iD5].sig= vv.o_D5x[iD5];
////   }
////   o_D5D5lu.clear();
////   vv.o_D5D5a.clear();
////   vv.o_D5x.clear();
////   vv.o_D5ord.clear();
//
//
// bound D5[].sig to limit numerical error
//
   for(int iD5= 0;iD5<nD5;iD5++){
      if( D5[iD5].a<(0.10) ){
         if      ( D5[iD5].sig<(-1.00) ){
            D5[iD5].sig= (-1.00);
         }else if( D5[iD5].sig>( 1.00) ){
            D5[iD5].sig= ( 1.00);
         }
      }
   }
//
//
// DOT[].chg
//
   for(int iD5= 0;iD5<nD5;iD5++){
      int iDOTmin=D5[iD5].DOTa;
      int iDOTmax=(iDOTmin-1+D5[iD5].cDOT);
      for(int iDOT=iDOTmin;iDOT<=iDOTmax;iDOT++){
         DOT[iDOT].chg= D5[iD5].sig*DOT[iDOT].a;
      }
   }
//
//
// Fps, DOT[].qe, D5[].qe
//
   bool DUMP=false;
   Fps= (0.00);
   for(int iD5= 0;iD5<nD5;iD5++){
      int iDOTmin=D5[iD5].DOTa;
      int iDOTmax=(iDOTmin-1+D5[iD5].cDOT);
      q1.populate( 5,D5[iD5].e);
      int mA5;
      if( D5[iD5].bse>=0 ){
         D5[iD5].qe= bse_D5[D5[iD5].bse].qe;
         mA5= bse_nA5;
      }else{
         D5[iD5].qe= (0.00);
         mA5= 0;
      }
      double b=( D5[iD5].d>(4.00) )? D5[iD5].d: (4.00);
      Lb[ 1]= (1.00e-4);
      for(int L=2;L<8;L++){
         Lb[L  ]= Lb[L-1]*(L-1)/((L  )*b);
      }
      for(int iA5=mA5;iA5<nA5;iA5++){
         int LTE2=A5[iA5].lte;
         Coordinates d=( A5[iA5].x -D5[iD5].x);
         double r= d.r();
         double z= (1.00)/r;
         int LTE=6;
         Lr[ 1]= z;
         for(int L=2;L<=(LTE+1);L++){
            Lr[L  ]= z*Lr[L-1];
            if( Lr[L  ]<Lb[L  ] )LTE=(L-2);
         }
         if( LTE<=5 ){
            double CT= (d(2)*z);
            double ST= std::sqrt( (1.00) -CT*CT);
            double CP,SP;
            if( ST>(1.00e-10) ){
               CP= (d(0)*z)/ST;
               SP= (d(1)*z)/ST;
            }else{
               CP= (1.00);
               SP= (0.00);
            }
            H.populate(array_consts,LTE,CT,ST,CP,SP);
            if( LTE2>0 ){
               q2.populate(LTE2,A5[iA5].q);
               QQ.populate(LTE);
               QQ.product(array_consts,q1,q2);
               for(int L=0;L<=LTE;L++){
                  double F= (0.00);
                  for(int M=-L;M<=L;M++){
                     F+=( QQ.r(L,M)*H.r(L,M)
                         -QQ.i(L,M)*H.i(L,M));
                  }
                  D5[iD5].qe+=(Lr[L+1]*F);
               }
            }else{
               double G= (0.00);
               for(int L=0;L<=LTE;L++){
                  double F= (0.00);
                  for(int M=-L;M<=L;M++){
                     F+=( q1.r(L,M)*H.r(L,M)
                         -q1.i(L,M)*H.i(L,M));
                  }
                  G+=(Lr[L+1]*F);
               }
               D5[iD5].qe+=(A5[iA5].q.r(0,0)*G);
            }
         }else{
            for(int iDOT=iDOTmin;iDOT<=iDOTmax;iDOT++){
               double qe= (0.00);
               d=( DOT[iDOT].x -A5[iA5].x);
               r= d.r();
               z= (1.00)/r;
               LTE=LTE2;
               Lr[ 1]= z;
               for(int L=2;L<=(LTE+1);L++){
                  Lr[L  ]= z*Lr[L-1];
                  if( Lr[L  ]<Lz[L  ] )LTE=(L-2);
               }
               if( LTE==0 ){
                  qe+=(A5[iA5].q.r(0,0)*z);
               }else{
                  q2.populate(LTE,A5[iA5].q);
                  double CT= d(2)*z;
                  double ST= std::sqrt( (1.00) -CT*CT);
                  double CP,SP;
                  if( ST>(1.00e-10) ){
                     CP= d(0)*z/ST;
                     SP= d(1)*z/ST;
                  }else{
                     CP= (1.00);
                     SP= (0.00);
                  }
                  H.populate(array_consts,LTE,CT,ST,CP,SP);
                  for(int L=0;L<=LTE;L++){
                     double F= (0.00);
                     for(int M=-L;M<=L;M++){
                        F+=( q2.r(L,M)*H.r(L,M)
                            -q2.i(L,M)*H.i(L,M));
                     }
                     qe+=(Lr[L+1]*F);
                  }
               }
               D5[iD5].qe+=(DOT[iDOT].a*qe);
            }
         }
      }
      double ps= (D5[iD5].sig*D5[iD5].qe);
      if( D5[iD5].sig> (0.00)){
//       ps*=(1.0000);
      }else{
         ps*=(0.9625);
      }
      Fps+=ps;
      ps*=physics_consts.CAL;
      bool FLAG=false;
      if      ( D5[iD5].a<( .20) ){
         if( std::abs( ps)>(16.00) )FLAG=true;
      }else if( D5[iD5].a<(3.20) ){
         if( std::abs( ps)>(32.00) )FLAG=true;
      }else{
         if( std::abs( ps)>(48.00) )FLAG=true;
      }
      if( FLAG ){
/**/     DUMP=true;
         int jDOT=D5[iD5].DOTa;
         std::cerr<< std::fixed<< std::setprecision( 3);
         std::cerr<<"FLAG: Large (surface element,protein)"
                    " interaction energy."
                  <<"  e="<< std::setw( 8)<<ps
                  << std::endl;
         std::cerr<<" iD5="<< std::setw( 5)<<iD5
                  <<" typ="<< std::setw( 2)<<DOT[jDOT].typ
                  <<" d="<< std::setw( 7)<<D5[iD5].d
                  <<" a="<< std::setw( 7)<<D5[iD5].a
                  << std::endl;
      }
   }
//
//
// Fss, D5D5ee
//
   Fss= (0.00);
   for(int iD5= 0;iD5<nD5;iD5++){
      int iDOTmin=D5[iD5].DOTa;
      int iDOTmax=(iDOTmin-1+D5[iD5].cDOT);
      q1.populate( 5,D5[iD5].e);
      double ss= (0.00);
      for(int jD5=iD5;jD5<nD5;jD5++){
         int jDOTmin=D5[jD5].DOTa;
         int jDOTmax=(jDOTmin-1+D5[jD5].cDOT);
         double ee= (0.00);
         if( (D5[iD5].bse>=0)&&(D5[jD5].bse>=0) ){
            ee= D5D5ee(D5[iD5].bse,D5[jD5].bse);
         }else{
            double b=( D5[jD5].d>D5[iD5].d )? D5[jD5].d: D5[iD5].d;
            Coordinates d=( D5[jD5].x -D5[iD5].x);
            double r= d.r();
            if( r<(1.00e-6) )r= (1.00e-6);
            double z= (1.00)/r;
            int LTE=6;
            Lb[ 1]= (1.00e-4);
            Lr[ 1]= z;
            for(int L=2;L<=(LTE+1);L++){
               Lb[L  ]= Lb[L-1]*(L-1)/((L  )*b);
               Lr[L  ]= z*Lr[L-1];
               if( Lr[L  ]<Lb[L  ] )LTE=(L-2);
            }
            if( LTE<=5 ){
               q2.populate(LTE,D5[jD5].e);
               QQ.populate(LTE);
               QQ.product(array_consts,q1,q2);
               double CT= (d(2)*z);
               double ST= std::sqrt( (1.00) -CT*CT);
               double CP,SP;
               if( ST>(1.00e-10) ){
                  CP= (d(0)*z)/ST;
                  SP= (d(1)*z)/ST;
               }else{
                  CP= (1.00);
                  SP= (0.00);
               }
               H.populate(array_consts,LTE,CT,ST,CP,SP);
               for(int L=0;L<=LTE;L++){
                  double F= (0.00);
                  for(int M=-L;M<=L;M++){
                     F+=( QQ.r(L,M)*H.r(L,M)
                         -QQ.i(L,M)*H.i(L,M));
                  }
                  ee+=(Lr[L+1]*F);
               }
            }else{
               for(int iDOT=iDOTmin;iDOT<=iDOTmax;iDOT++){
                  double t= (0.00);
                  if( jD5==iD5 )jDOTmin=(iDOT+1);
                  for(int jDOT=jDOTmin;jDOT<=jDOTmax;jDOT++){
                     d=( DOT[iDOT].x -DOT[jDOT].x);
                     r= d.r();
                     if( r<(0.80) )continue;
                     double s= MED_SWITCH( r);
                     z= s/r;
                     t+=(DOT[jDOT].a*z);
                  }
                  ee+=(DOT[iDOT].a*t);
               }
            }
         }
         ss+=(ee*D5[iD5].sig*D5[jD5].sig);
      }
      Fss+=ss;
      ss*=physics_consts.CAL;
      bool FLAG=false;
      if      ( D5[iD5].a<( .20) ){
         if( std::abs( ss)>(16.00) )FLAG=true;
      }else if( D5[iD5].a<(3.20) ){
         if( std::abs( ss)>(24.00) )FLAG=true;
      }else{
         if( std::abs( ss)>(32.00) )FLAG=true;
      }
      if( FLAG ){
/**/     DUMP=true;
         int jDOT=D5[iD5].DOTa;
         std::cerr<< std::fixed<< std::setprecision( 3);
         std::cerr<<"FLAG: Large (surface element,boundary surface)"
                    " interaction energy."
                  <<"  e="<< std::setw( 8)<<ss
                  << std::endl;
         std::cerr<<" iD5="<< std::setw( 5)<<iD5
                  <<" typ="<< std::setw( 2)<<DOT[jDOT].typ
                  <<" d="<< std::setw( 7)<<D5[iD5].d
                  <<" a="<< std::setw( 7)<<D5[iD5].a
                  << std::endl;
      }
   }
//
//
// diagnostic output
//
   if( DUMP ){
      std::string filename;
      filename="../../"+out.FAMILY+"/dgn/boundaryflg."+out.PROTEIN+
               "."+out.CONFORMATION;
      out.FILE4.open(filename.c_str());
      out.FILE4<< std::fixed<< std::setprecision(2);
      out.FILE4<<"  iDOT"
                 " typ"
                 " grp"
                 "  elm"
                 " TIL"
                 "    a "
                 "    r "
                 "   D5"
                 " HIT"
                 "      chg"
               << std::endl;
      for(int iDOT= 0;iDOT<nDOT;iDOT++){
         out.FILE4<< std::setw( 6)<<iDOT
                  << std::setw( 4)<<DOT[iDOT].typ
                  << std::setw( 4)<<DOT[iDOT].grp
                  << std::setw( 5)<<DOT[iDOT].elm
                  << std::setw( 4)<<int(DOT[iDOT].TILE)
                  << std::setw( 6)<<DOT[iDOT].a
                  << std::setw( 6)<<DOT[iDOT].r
                  << std::setw( 5)<<DOT[iDOT].D5
                  << std::setw( 4)<<int(DOT[iDOT].HIT)
                  << std::setprecision(4)
                  << std::setw( 9)<<DOT[iDOT].chg
                  << std::setprecision(2)
                  << std::endl;
      }
      out.FILE4<< std::fixed<< std::setprecision(2);
      out.FILE4<<"   iD5"
                 " typ"
                 " DOTa "
                 "cDOT"
                 "    a "
                 "    d "
                 "      sig"
                 "       qn"
                 "       qe"
               << std::endl;
      for(int iD5= 0;iD5<nD5;iD5++){
         int jDOT=D5[iD5].DOTa;
         out.FILE4<< std::setw( 6)<<iD5
                  << std::setw( 4)<<DOT[jDOT].typ
                  << std::setw( 6)<<jDOT
                  << std::setw( 4)<<D5[iD5].cDOT
                  << std::setw( 6)<<D5[iD5].a
                  << std::setw( 6)<<D5[iD5].d
                  << std::setprecision(4)
                  << std::setw( 9)<<D5[iD5].sig
                  << std::setw( 9)<<D5[iD5].qn
                  << std::setw( 9)<<D5[iD5].qe
                  << std::setprecision(2)
                  << std::endl;
      }
      out.FILE4.close();
//
      double b= (0.00);
      for(int iDOT= 0;iDOT<nDOT;iDOT++){
         double z= std::abs( DOT[iDOT].chg);
         if( z>b )b= z;
      }
      b= (( 9.)/b);
      filename="../../"+out.FAMILY+"/dgn/boundarychg."+out.PROTEIN+
               "."+out.CONFORMATION;
      out.FILE4.open(filename.c_str());
      out.FILE4<< std::fixed<< std::setprecision(3);
      out.FILE4<<"DOTS"<< std::endl;
      for(int iDOT= 0;iDOT<nDOT;iDOT++){
         int i= std::floor( (.50) +b*DOT[iDOT].chg);
         std::string atm;
         if( DOT[iDOT].chg< (0.00) ){
            atm="XR";
            atm+=char('0'-i);
         }else{
            atm="XB";
            atm+=char('0'+i);
         }
         Coordinates x=(physics_consts.ANG*DOT[iDOT].x);
         out.FILE4<<"ATOM  "
                  << std::setw( 5)<<iDOT<<"  "<<atm
                  <<" DOT "<< std::setw( 5)<<DOT[iDOT].D5<<"    "
                  <<x
                  << std::endl;
      }
      out.FILE4<<"TER"<< std::endl;
      out.FILE4.close();
//
      b= (0.00);
      for(int iA5= 0;iA5<nA5;iA5++){
         double z= std::abs( A5[iA5].q.r(0,0));
         if( z>b )b= z;
      }
      b= (( 9.)/b);
      filename="../../"+out.FAMILY+"/dgn/boundaryatm."+out.PROTEIN+
               "."+out.CONFORMATION;
      out.FILE4.open(filename.c_str());
      out.FILE4<< std::fixed<< std::setprecision(3);
      out.FILE4<<"ATOMS"<< std::endl;
      for(int iA5= 0;iA5<nA5;iA5++){
         int i= std::floor( (.50) +b*A5[iA5].q.r(0,0));
         std::string atm;
         if( A5[iA5].q.r(0,0)< (0.00) ){
            atm="YR";
            atm+=char('0'-i);
         }else{
            atm="YB";
            atm+=char('0'+i);
         }
         Coordinates x=(physics_consts.ANG*A5[iA5].x);
         out.FILE4<<"ATOM  "
                  << std::setw( 5)<<iA5<<"  "<<atm
                  <<" ATM "<< std::setw( 5)<< 0<<"    "
                  <<x
                  << std::setw( 5)<<A5[iA5].typ
                  << std::endl;
      }
      out.FILE4<<"TER"<< std::endl;
      out.FILE4.close();
//
      filename="../../"+out.FAMILY+"/dgn/boundarydot."+out.PROTEIN+
               "."+out.CONFORMATION;
      out.FILE4.open(filename.c_str());
      out.FILE4<< std::fixed<< std::setprecision(3);
      out.FILE4<<"DOTS"<< std::endl;
      for(int iDOT= 0;iDOT<nDOT;iDOT++){
         int i=DOT[iDOT].typ;
         std::string atm;
         if      ( i< 0 ){
            atm="T00";
         }else if( i==0 ){
            atm="T01";
         }else if( i> 0 ){
            atm="T02";
         }
         Coordinates x=(physics_consts.ANG*DOT[iDOT].x);
         out.FILE4<<"ATOM  "
                  << std::setw( 5)<<iDOT<<"  "<<atm
                  <<" DOT "<< std::setw( 5)<< 0<<"    "
                  <<x
                  << std::endl;
      }
      out.FILE4<<"TER"<< std::endl;
      out.FILE4.close();
//
//    std::exit( 1);
   }
   return;
}
