/* * Project: MoleCuilder * Description: creates and alters molecular systems * Copyright (C) 2014 Frederik Heber. All rights reserved. * * * This file is part of MoleCuilder. * * MoleCuilder is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * MoleCuilder 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with MoleCuilder. If not, see . */ /* * SaturationDistanceMaximizer.cpp * * Created on: Jul 27, 2014 * Author: heber */ // include config.h #ifdef HAVE_CONFIG_H #include #endif //#include "CodePatterns/MemDebug.hpp" #include "SaturationDistanceMaximizer.hpp" #include #include #include #include "CodePatterns/Log.hpp" double func(const gsl_vector *x, void *adata) { // get the object whose functions we call SaturationDistanceMaximizer::Advocate *maximizer = static_cast(adata); // set alphas maximizer->setAlphas(x); // calculate function value and return return maximizer->calculatePenality(); } void jacf(const gsl_vector *x, void *adata, gsl_vector *g) { // get the object whose functions we call SaturationDistanceMaximizer::Advocate *maximizer = static_cast(adata); // set alphas maximizer->setAlphas(x); // calculate function gradient and return std::vector gradient = maximizer->calculatePenalityGradient(); for (unsigned int i=0;i(adata); // set alphas maximizer->setAlphas(x); // calculate function value and return *f = maximizer->calculatePenality(); std::vector gradient = maximizer->calculatePenalityGradient(); for (unsigned int i=0;i SaturationDistanceMaximizer::getAlphas() const { std::vector alphas; PositionContainers_t::iterator containeriter = PositionContainers.begin(); for (unsigned int i=0; ialpha ); return alphas; } void SaturationDistanceMaximizer::setAlphas(const gsl_vector *x) { PositionContainers_t::iterator containeriter = PositionContainers.begin(); for (unsigned int i=0; ialpha = gsl_vector_get(x,i); } void SaturationDistanceMaximizer::operator()() { // some control constants const double tolerance = 1e-6; const unsigned int MAXITERATIONS = 100; const gsl_multimin_fdfminimizer_type *T; gsl_multimin_fdfminimizer *s; gsl_vector *x; gsl_multimin_function_fdf my_func; const unsigned int N = PositionContainers.size(); my_func.n = N; my_func.f = &func; my_func.df = &jacf; my_func.fdf = &funcjacf; SaturationDistanceMaximizer::Advocate* const advocate = getAdvocate(); my_func.params = advocate; // allocate argument and set to zero x = gsl_vector_alloc(N); for (unsigned int i=0;igradient, tolerance); } while ((status = GSL_CONTINUE) && (iter < MAXITERATIONS)); // set to solution setAlphas(s->x); // print solution if (DoLog(4)) { std::stringstream sstream; sstream << "DEBUG: Minimal alphas are "; for (unsigned int i=0;ix,i) << ((i!= N-1) ? "," : ""); LOG(4, sstream.str()); } // free memory gsl_multimin_fdfminimizer_free(s); my_func.params = NULL; delete advocate; gsl_vector_free(x); } SaturationDistanceMaximizer::Advocate* SaturationDistanceMaximizer::getAdvocate() { return new Advocate(*this); } SaturationDistanceMaximizer::position_bins_t SaturationDistanceMaximizer::getAllPositionBins() const { position_bins_t position_bins; position_bins.reserve(PositionContainers.size()); for (PositionContainers_t::const_iterator containeriter = PositionContainers.begin(); containeriter != PositionContainers.end(); ++containeriter) position_bins.push_back( (*containeriter)->getPositions() ); return position_bins; } double SaturationDistanceMaximizer::calculatePenality() const { double penalty = 0.; LOG(6, "DEBUG: Current alphas are " << getAlphas()); // gather all positions position_bins_t position_bins = getAllPositionBins(); // go through both bins (but with ibegin(); firstpositioniter != firstbiniter->end(); ++firstpositioniter) { for (SaturatedBond::positions_t::const_iterator secondpositioniter = secondbiniter->begin(); secondpositioniter != secondbiniter->end(); ++secondpositioniter) { // Both iters are from different bins, can never be the same. // We do not penalize over positions from same bin as their positions // are fixed. // We penalize by one over the squared distance penalty += 1./(firstpositioniter->DistanceSquared(*secondpositioniter)); } } } } LOG(4, "DEBUG: Penalty is " << penalty); return penalty; } #ifdef HAVE_INLINE inline #else static #endif size_t calculateHydrogenNo( const SaturatedBond::positions_t::const_iterator &_start, const SaturatedBond::positions_t::const_iterator &_current) { const size_t HydrogenNo = std::distance(_start, _current); ASSERT( (HydrogenNo >= 0) && (HydrogenNo <= 2), "calculatePenalityGradient() - hydrogen no not in [0,2]."); return HydrogenNo; } std::vector SaturationDistanceMaximizer::calculatePenalityGradient() const { // gather all positions const position_bins_t position_bins = getAllPositionBins(); LOG(6, "DEBUG: Current alphas are " << getAlphas()); std::vector gradient(position_bins.size(), 0.); std::vector::iterator biniter = gradient.begin(); PositionContainers_t::const_iterator bonditer = PositionContainers.begin(); position_bins_t::const_iterator firstbiniter = position_bins.begin(); // go through each bond/gradient component/alpha for(; biniter != gradient.end(); ++biniter, ++bonditer, ++firstbiniter) { LOG(5, "DEBUG: Current bond is " << **bonditer << ", current bin is #" << std::distance(gradient.begin(), biniter) << ", set of positions are " << *firstbiniter); // skip bin if it belongs to a degree-1 bond (no alpha dependency here) if ((*bonditer)->saturated_bond.getDegree() == 1) { LOG(6, "DEBUG: Skipping due to degree 1."); continue; } // in the bin go through each position for (SaturatedBond::positions_t::const_iterator firstpositioniter = firstbiniter->begin(); firstpositioniter != firstbiniter->end(); ++firstpositioniter) { LOG(6, "DEBUG: Current position is " << *firstpositioniter); // count the hydrogen we are looking at: Each is placed at a different position! const size_t HydrogenNo = calculateHydrogenNo(firstbiniter->begin(), firstpositioniter); const double alpha = (*bonditer)->alpha + (double)HydrogenNo * 2.*M_PI/(double)(*bonditer)->saturated_bond.getDegree(); LOG(6, "DEBUG: HydrogenNo is " << HydrogenNo << ", alpha is " << alpha); // and go through each other bin for (position_bins_t::const_iterator secondbiniter = position_bins.begin(); secondbiniter != position_bins.end(); ++secondbiniter) { // distance between hydrogens in same bin is not affected by the angle // if (firstbiniter == secondbiniter) // continue; // in the other bin go through each position for (SaturatedBond::positions_t::const_iterator secondpositioniter = secondbiniter->begin(); secondpositioniter != secondbiniter->end(); ++secondpositioniter) { if (firstpositioniter == secondpositioniter) { LOG(7, "DEBUG: Skipping due to same positions."); continue; } LOG(7, "DEBUG: Second position is " << *secondpositioniter); // iters are from different bins, can never be the same const Vector distance = *firstpositioniter - *secondpositioniter; const double temp = -2./pow(distance.NormSquared(), 2); const Vector tempVector = (-sin(alpha)*(*bonditer)->vector_a) +(cos(alpha)*(*bonditer)->vector_b); const double result = temp * (distance.ScalarProduct(tempVector)); *biniter += 2.*result; //for x_i and x_j LOG(7, "DEBUG: Total is " << result << ", temp is " << temp << ", tempVector is " << tempVector << ", and bondVector is " << distance << ": bin = " << *biniter); } } } } LOG(4, "DEBUG: Gradient of penalty is " << gradient); return gradient; }