https://github.com/feelpp/feelpp
Raw File
Tip revision: 94701fa62fba97dbfafab22e917f6b3bcfcf08d2 authored by Christophe Prud'homme on 03 March 2013, 10:33:36 UTC
Merge branch 'release/version-0.92'
Tip revision: 94701fa
pbeq.cpp
/* -*- mode: c++; coding: utf-8; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; show-trailing-whitespace: t -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4

  This file is part of the Feel library

  Author(s): Simone Deparis <simone.deparis@epfl.ch>
       Date: 2007-08-27

  Copyright (C) 2007 Unil

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 3.0 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/
/**
   \file pbeq.cpp
   \author Simone Deparis <simone.deparis@epfl.ch>
   \date 2007-08-27
 */

#include "pbeq.hpp"

//#include <boost/numeric/ublas/expression.hpp>

namespace Feel
{

void
Pbeq::loadFE()
{
    if ( this->vm().count( "help" ) )
    {
        std::cout << this->optionsDescription() << "\n";
        return;
    }

    changeToMeshRepository();

    /*
     * logs will be in <feel repo>/<app name>/<entity>/P<p>/h_<h>
     */
    this->setLogs();

    /**
     * load mesh and spaces
     */

    // the reference compuational domain is composed by a dense sphere
    M_pbeqspace.setMeshSize ( this->vm()["hsize"].as<value_type>() );
    M_pbeqspace.setFarFactor( this->vm()["farfactor"].as<value_type>() );
    M_pbeqspace.setFarBnd   ( this->vm()["farBnd"].as<value_type>() );


    if ( Application::processId() == 0 )
    {
        if ( !( this->vm().count( "meshReuse" ) && M_pbeqspace.loadMesh( ) ) )
            M_pbeqspace.createMesh( this->vm().count( "geoOnly" ) );
    }

    application_type::barrier();

    if ( Application::processId() != 0 )
    {
        if ( !M_pbeqspace.loadMesh( ) )
            throw std::logic_error( "could not load mesh on processor != 0" );
    }
}

template<typename Mat, typename Vec1, typename Vec2>
void
Pbeq::solve( Mat const& D,
             Vec1& u,
             Vec2 const& F,
             bool is_sym  )
{
    timers["solver"].first.restart();

    //M_backend->set_symmetric( is_sym );

    vector_ptrtype U( M_backend->newVector(  M_pbeqspace.Xh() ) );
    M_backend->solve( D, D, U, F, false );
    u = *U;

    timers["solver"].second = timers["solver"].first.elapsed();
    LOG(INFO) << "[timer] solve: " << timers["solver"].second << "\n";
} // Pbeq::solve

template<typename Etype, typename Ktype>
void
Pbeq::getPBMatrix( sparse_matrix_ptrtype& PB,
                   element_type const& u,
                   element_type const& v,
                   Etype const& Epsilon,
                   Ktype const& kappa2 /*,
                                        vector_ptrtype& F */ )
{
    using namespace Feel::vf;

    im_type im;

    size_type pattern = Pattern::COUPLED;
    form2( M_pbeqspace.Xh(), M_pbeqspace.Xh(), PB, _init=true, _pattern=pattern ) =
        integrate( elements( *M_pbeqspace.mesh() ), im,
                   Epsilon*( M_jacInvStr2[0] * dxt( u ) * dx( v ) +
                             M_jacInvStr2[1] * dyt( u ) * dy( v ) +
                             M_jacInvStr2[2] * dzt( u ) * dz( v ) )
                   +  kappa2*idt( u )*id( v ) );

    PB->close();

    if ( this->vm().count( "export-matlab" ) )
        PB->printMatlab( "PBnobc.m" );

#ifdef PBEQ_USE_PETSC
    /*
    value_type penalisation_bc = this->vm()["penalbc"].as<value_type>();

    form2( M_pbeqspace.Xh(), M_pbeqspace.Xh(), PB ) +=
        integrate( boundaryfaces(*M_pbeqspace.mesh()), im,
                   ( - trans(id(v))*(gradt(u)*N())
                     - trans(idt(u))*(grad(v)*N())
                     + penalisation_bc*trans(idt(u))*id(v)/hFace()) );

    */

#else
    // input/output: vector_ptrtype& F
    /*
      form2( M_pbeqspace.Xh(), M_pbeqspace.Xh(), PB ) +=
        on( boundaryfaces(*M_pbeqspace.mesh()), u, *F, constant(0.0) );
    */
#endif

    if ( this->vm().count( "export-matlab" ) )
        PB->printMatlab( "PB.m" );

} // getPBMatrix





int
Pbeq::initMolecule( std::string const& moleculeName,
                    molecule_type& _molecule ) const
{
    std::ostringstream file;
    file << this->vm()["molDir"].as<std::string>()
         << "/"
         << moleculeName;
    int mol_read( 1 );

    switch ( M_filetype )
    {
    case molecule_type::PQR:
        mol_read = _molecule.readPQRfile( file.str() );
        break;

    case molecule_type::CRD:
        mol_read = _molecule.readCRDfile( file.str() );
        break;
    }

    if ( mol_read == 0 )
    {
        LOG(INFO) << "Molecule " << moleculeName << " has " << _molecule.size() << " atoms \n";
        _molecule.showMe();
        return _molecule.size();
    }

    LOG(INFO) << "problem in reading "
          << file.str()
          << "\n";

    //_molecule.showMe();

    return 0;


} // initMolecule

void
Pbeq::setDomain( molecule_type const& _molecule )
{

    uint16_type const dim( pbeqspace_type::Dim );
    node_type _min( dim ),  _max( dim );
    node_type  stretch( dim ), translation( dim );
    FEELPP_ASSERT( this->vm()["farBnd"].as<value_type>() > 0 )( dim ).error( "invalid farBnd" );

    _molecule.domainMinMax( _min,_max );

    stretch     = ( _max - _min )/2;
    translation = ( _max + _min )/2;

    LOG(INFO) << "i  \tmin,   \tmax, \tstretch,\ttranslation " << "\n";

    for ( int i( 0 ); i < dim; i++ )
        LOG(INFO) << i <<"\t"<<  _min[i] <<"\t"<<  _max[i] <<"\t"<< stretch[i] <<"\t\t"<< translation[i]
              << "\n";

    M_detJac = stretch[0];

    for ( int i = 1; i < dim; i++ )
        M_detJac *= stretch[i];

    FEELPP_ASSERT( M_detJac > 0 )( dim ).error( "invalid sign of the Jacobian" );

    M_jacInvStr2.resize( dim );

    for ( int i = 0; i < dim; i++ )
        M_jacInvStr2[i] = M_detJac/( stretch[i]*stretch[i] );

    M_pbeqspace.setStretch( stretch );
    M_pbeqspace.setTranslation( translation );

}

void
Pbeq::setCoeffs()
{
    //Parameter values

    Kb   = this->vm()["Kb"].  as<value_type>();
    pdie = this->vm()["pdie"].as<value_type>();
    sdie = this->vm()["sdie"].as<value_type>();
    temp = this->vm()["temp"].as<value_type>();
    Kappab   = 8*3.1415926*this->vm()["IonStr"].  as<value_type>() / ( Kb*temp*sdie );


    // rhsCoeff = 4 \pi e_c / (Kb*T) * detJac
    ec = 0.0854245;
    rhsCoeff = 4.* 3.1415926 * ec / ( Kb * temp );

    M_pbeqspace.setSmoothWindow( this->vm()["smooth"].as<value_type>() );

}


int
Pbeq::setReceptor( std::string const& receptorName )
{

    changeToSolutionRepository( receptorName );
    setCoeffs();

    initMolecule( receptorName,M_receptor );

    setDomain( M_receptor );

    deltaAndHeavisyde( M_receptor, M_F_receptor, M_H_receptor );

    return M_receptor.size();

}

int
Pbeq::setLigand( std::string const& ligandName )
{
    return initMolecule( ligandName,M_ligand );
}

int
Pbeq::setReclusterFile( std::string const& reclusterName )
{

    std::ostringstream file;
    file << this->vm()["molDir"].as<std::string>()
         << "/"
         << reclusterName
         << ".pdb.dock4";

    M_dock4file.open( file.str().c_str(), std::ifstream::in );

    if ( M_dock4file.fail() )
    {
        LOG(INFO) << "setReclusterFile::failed to open *" << reclusterName << "*"
              << "\n at " << file.str()
              << "\n";
        return -1;
    }

    if ( M_dock4file.eof() ) return -1;

    return 0;
}

int
Pbeq::recluster()
{
    return M_ligand.readDock4file( M_dock4file );

}

void
Pbeq::deltaAndHeavisyde( molecule_type const       &myMolecule,
                         vector_ptrtype            &F,
                         heavyside_element_ptrtype &H )
{
    using namespace Feel::vf;

    /*
     * Construction of the right hand side
     */

    timers["assembly"].first.restart();

    F = M_backend->newVector( M_pbeqspace.Xh() );

    M_pbeqspace.intvrho( myMolecule,F );
    F->close();

    // Checking consistency of the right hand side
    LOG(INFO) << myMolecule.name() << " total charge = " << myMolecule.totalCharge() << " == " << F->sum() << " = sum(F)\n";

    FEELPP_ASSERT(  std::abs( myMolecule.totalCharge() -  F->sum() )
                    < ( myMolecule.totalAbsCharge() +  F->l1Norm() )  * 1.e-9  ).error( "total charge and sum(F) are different" );


    F->scale( rhsCoeff* M_detJac );

    timers["assembly"].second = timers["assembly"].first.elapsed();
    LOG(INFO) << "[timer] rhs assembly: " << timers["assembly"].second << "\n";

    // right hand side done


    /*
     * Construction of the heavyside function
     */

    timers["heavyside"].first.restart();

    H.reset( new heavyside_element_type( M_pbeqspace.fastHeavyside( myMolecule ) ) );
    //H.reset( new heavyside_element_type( M_pbeqspace.heavyside( myMolecule )) );

    // Checking consistency (to be checked agains other hsize's)
    im_type im;
    double domain_size = integrate( elements( *M_pbeqspace.mesh() ), im, constant( 1.0 ) ).evaluate()( 0,0 );
    double intH        = integrate( elements( *M_pbeqspace.mesh() ), im, idv( *H ) ).evaluate()( 0,0 );

    //

    LOG(INFO) << "domain_size = " << M_detJac*domain_size
          << " intH = " << M_detJac*intH
          << "\n";



    timers["heavyside"].second += timers["heavyside"].first.elapsed();
    LOG(INFO) << "[timer] heavyside: " << timers["heavyside"].second << "\n";

}




template<typename Etype, typename Ktype>
value_type
Pbeq::buildSystemAndSolve( element_type        & u,
                           element_type   const& v,
                           Etype          const& Epsilon,
                           Ktype          const& kappa2,
                           vector_ptrtype const& F )
{

    /* vector_ptrtype  F( M_backend->newVector(M_pbeqspace.Xh()) );
    *F = *_F;
    */

    timers["assembly"].first.restart();

    sparse_matrix_ptrtype PB;
    PB = M_backend->newMatrix( M_pbeqspace.Xh(), M_pbeqspace.Xh() );

    getPBMatrix( PB, u, v, Epsilon, kappa2 );

    timers["assembly"].second = timers["assembly"].first.elapsed();
    LOG(INFO) << "[timer] assembly: " << timers["assembly"].second << "\n";


    /*
     * solving the system
     */

    this->solve( PB, u, F, false );

    if ( this->vm().count( "export-matlab" ) )
    {
        std::ostringstream ostr;
        ostr.precision( 3 );
        ostr << "F.m" ;
        F->printMatlab( ostr.str() );

        if ( Application::processId() == 0 )
            std::cout  << "Returning now, only checking matrices \n"
                       << std::flush;

        exit( 0 );

    }

    return postProcess( u, F, rhsCoeff );

}

value_type
Pbeq::solveReceptor( std::string const& receptorName )
{
    using namespace Feel::vf;

    setReceptor( receptorName );
    FEELPP_ASSERT(  M_receptor.size() > 0 ).error( "Receptor has zero length" );

    element_type u( M_pbeqspace.Xh(), "u" );
    element_type v( M_pbeqspace.Xh(), "v" );

    /*
     * Construction of the left hand side components
     */

    value_type jacKbsquare ( M_detJac*Kappab*Kappab );
    AUTO( Epsilon, pdie + ( sdie-pdie )* idv( *M_H_receptor ) );
    AUTO( kappa2, jacKbsquare* idv( *M_H_receptor ) );

    // unused. Why?
    value_type K ( Kb/std::sqrt( sdie ) );

    /*
     *  solvated solution
     */

    value_type solvatedEnergy = buildSystemAndSolve( u, v, Epsilon, kappa2, M_F_receptor );


    /*
     *  Vacuum solution
     */
    v=u;
    value_type  vacuumEnergy = buildSystemAndSolve( v, u, pdie, kappa2, M_F_receptor );

    /*
     *  export results
     */

    if ( this->vm().count( "export" ) )
        exportResults( *M_H_receptor,*M_H_receptor,u,v, M_F_receptor );

    return solvatedEnergy - vacuumEnergy;

} // end solveReceptor

value_type
Pbeq::solveLigand()
{

    FEELPP_ASSERT(  M_receptor.size() > 0 ).error( "Receptor has zero length" );

    using namespace Feel::vf;

    vector_ptrtype F;
    heavyside_element_ptrtype H;

    deltaAndHeavisyde( M_ligand, F, H );

    *F += *M_F_receptor;

    /*
     * Construction of the left hand side components
     */

    value_type jacKbsquare ( M_detJac*Kappab*Kappab );
    AUTO( Epsilon, pdie + ( sdie-pdie ) * idv( *H ) * idv( *M_H_receptor ) );
    AUTO( kappa2, jacKbsquare * idv( *H ) * idv( *M_H_receptor ) );

    // unused. Why?
    value_type K ( Kb/std::sqrt( sdie ) );


    // solutions

    element_type u( M_pbeqspace.Xh(), "u" );
    element_type v( M_pbeqspace.Xh(), "v" );

    /*
     *  solvated solution
     */

    value_type solvatedEnergy = buildSystemAndSolve( u, v, Epsilon, kappa2, F );

    /*
     *  Vacuum solution
     */

    v=u;
    value_type  vacuumEnergy = buildSystemAndSolve( v, u, pdie, kappa2, F );

    /*
     *  export results
     */

    if ( this->vm().count( "export" ) )
        exportResults( *M_H_receptor,*H,u,v,F );

    return solvatedEnergy - vacuumEnergy;

} // end solveLigand


value_type
Pbeq::postProcess( element_type const& u, vector_ptrtype const& F, value_type const& rhsCoeff ) const
{
    using namespace Feel::vf;

    // Computing Energy and norms

    timers["output"].first.restart();

    /*
    im_type im;
    value_type l2norm = integrate( elements(*M_pbeqspace.mesh()), im, val( idv(u)^2  ) ).evaluate()(0,0);
    // value_type global_l2norm = 0;
    // mpi::all_reduce( Application::comm(), l2norm, global_l2norm, std::plus<value_type>() );
    // LOG(INFO) << "L2norm = " << math::sqrt( global_l2norm ) << "\n";
    LOG(INFO) << "L2norm = " << math::sqrt( l2norm ) << "\n";
    */

#ifdef PBEQ_USE_SERIAL
    //value_type output(boost::numeric::ublas::inner_prod( *F, u ));
    value_type output = F->dot( u );
#else
    value_type output( inner_product( *F, u ) );
#endif

    //\Delta G_{ele} = 1/2 K_B*T /ec * \int_\Omega u \rho
    /*
      if ( Application::processId() == 0 )
        std::cout << "inner_prod ( F, u ) = " << output << "\n" << std::flush;
    */
    LOG(INFO) << "Energy = " << 1./( 8.* 3.1415926 *rhsCoeff*rhsCoeff ) << "*" << output << "\n";

    output = 1./( 8.* 3.1415926 *rhsCoeff*rhsCoeff ) * output;

    LOG(INFO) << "Energy = " << output << "\n";
    /*
    if ( Application::processId() == 0 )
        std::cout <<  " Energy = " << output << "\n"
                  << std::flush;
    */

    timers["output"].second += timers["output"].first.elapsed();
    LOG(INFO) << "[timer] Energy: " << timers["output"].second << "\n";

    return output;

} // end postProcess

void
Pbeq::exportResults( heavyside_element_type& H0, heavyside_element_type& H1,
                     element_type& u, element_type& v,
                     vector_ptrtype F )
{
    timers["export"].first.restart();

    timeset_type::step_ptrtype timeStep = timeSet->step( M_countExports++ );
    timeStep->setMesh( H0.functionSpace()->mesh() );
    timeStep->add( "H0", H0 );
    timeStep->add( "H1", H1 );
    timeStep->add( "u", u );
    timeStep->add( "v", v );

    element_type f( M_pbeqspace.Xh(), "f" );
    f = *F;
    timeStep->add( "rho", f );


    exporter->save();

    timers["export"].second = timers["export"].first.elapsed();
    LOG(INFO) << "[timer] export: " << timers["export"].second << "\n";

} // Pbeq::exportResults


void
Pbeq::changeToMeshRepository()
{

    this->changeRepository( boost::format( "%1%/h_%2%/farF_%3%/farB_%4%/" )
                            % this->about().appName()
                            % this->vm()["hsize"].as<value_type>()
                            % this->vm()["farfactor"].as<value_type>()
                            % this->vm()["farBnd"].as<value_type>()
                          );
}

void
Pbeq::changeToSolutionRepository( std::string const& receptorName )
{
    this->changeRepository( boost::format( "%1%/h_%2%/farF_%3%/farB_%4%/%5%/" )
                            % this->about().appName()
                            % this->vm()["hsize"].as<value_type>()
                            % this->vm()["farfactor"].as<value_type>()
                            % this->vm()["farBnd"].as<value_type>()
                            % receptorName
                          );

}

} // end namespace Feel

back to top