File: hydrogenBond.C

package info (click to toggle)
ball 1.5.0%2Bgit20180813.37fc53c-6
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 239,888 kB
  • sloc: cpp: 326,149; ansic: 4,208; python: 2,303; yacc: 1,778; lex: 1,099; xml: 958; sh: 322; makefile: 95
file content (393 lines) | stat: -rw-r--r-- 10,899 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
// ----------------------------------------------------
// $Maintainer: Marcel Schumann $
// $Authors: Slick-development Team, Marcel Schumann $
// ----------------------------------------------------

#include <BALL/SCORING/COMPONENTS/hydrogenBond.h>
#include <BALL/SCORING/COMMON/scoringFunction.h>
#include <BALL/MOLMEC/COMMON/support.h>
#include <BALL/KERNEL/PTE.h>
#include <BALL/KERNEL/bond.h>
#include <BALL/DATATYPE/hashMap.h>

#include <BALL/SYSTEM/timer.h>

using namespace BALL;
using namespace std;

const char* HydrogenBond::Option::HB_IDEAL_LENGTH = "hb_ideal_length";
const char* HydrogenBond::Option::HB_IDEAL_ANGLE = "hb_ideal_angle";
const char* HydrogenBond::Option::HB_DIST_LOWER = "hb_dist_lower";
const char* HydrogenBond::Option::HB_DIST_UPPER = "hb_dist_upper";
const char* HydrogenBond::Option::HB_ANG_LOWER = "hb_ang_lower";
const char* HydrogenBond::Option::HB_ANG_UPPER = "hb_ang_upper";
const char* HydrogenBond::Option::VERBOSITY = "verbosity";

const float HydrogenBond::Default::HB_IDEAL_LENGTH = 1.85;
const float HydrogenBond::Default::HB_IDEAL_ANGLE = 180;
const float HydrogenBond::Default::HB_DIST_LOWER = 0.25;
const float HydrogenBond::Default::HB_DIST_UPPER = 0.65;
const float HydrogenBond::Default::HB_ANG_LOWER = 30;
const float HydrogenBond::Default::HB_ANG_UPPER = 80;
const Size HydrogenBond::Default::VERBOSITY = 0;


HydrogenBond::HydrogenBond(Mode mode)
	throw()
	:	ScoringComponent(),
		possible_hydrogen_bonds_()
{
	// set component name
	setName("HydrogenBond");
	receptor_fresno_types_ = 0;
	ligand_fresno_types_ = 0;
	mode_ = mode;
	type_name_ = "HB";
	charge_evaluation_enabled_ = false;

	if (mode_ == LIGAND_HYDROGENS)
	{
		gridable_ = false;
	}
}


HydrogenBond::HydrogenBond(ScoringFunction& sf, Mode mode)
	throw()
	:	ScoringComponent(sf),
		possible_hydrogen_bonds_()
{
	// set component name
	setName("HydrogenBond");
	receptor_fresno_types_ = 0;
	ligand_fresno_types_ = 0;
	mode_ = mode;
	type_name_ = "HB";
	charge_evaluation_enabled_ = false;

	if (mode_ == LIGAND_HYDROGENS)
	{
		gridable_ = false;
	}
}


HydrogenBond::HydrogenBond(const HydrogenBond& hb)
	throw()
	:	ScoringComponent(hb),
		possible_hydrogen_bonds_(hb.possible_hydrogen_bonds_),
		h_bond_distance_lower_(hb.h_bond_distance_lower_),
		h_bond_distance_upper_(hb.h_bond_distance_upper_),
		h_bond_angle_lower_(hb.h_bond_angle_lower_),
		h_bond_angle_upper_(hb.h_bond_angle_upper_)
{
	receptor_fresno_types_ = 0;
	ligand_fresno_types_ = 0;
	mode_ = hb.mode_;

	if (mode_ == LIGAND_HYDROGENS)
	{
		gridable_ = false;
	}
}


HydrogenBond::~HydrogenBond()
	throw()
{
	clear();
}


void HydrogenBond::clear()
	throw()
{
	possible_hydrogen_bonds_.clear();
	h_bond_distance_lower_ = 0.0;
	h_bond_distance_upper_ = 0.0;
	h_bond_angle_lower_ = 0.0;
	h_bond_angle_upper_ = 0.0;

	delete receptor_fresno_types_;
	delete ligand_fresno_types_;
}


void HydrogenBond::enableChargeEvaluation(bool b)
{
	charge_evaluation_enabled_ = b;
	if (charge_evaluation_enabled_) gridable_ = false;
	else
	{
		if (mode_ == LIGAND_HYDROGENS) gridable_ = false;
		else gridable_ = true;
	}
}


bool HydrogenBond::setup()
{
	Timer timer;
	timer.start();

	ScoringFunction* scoring_function = getScoringFunction();
	if (scoring_function == 0)
	{
		Log.error() << "HydrogenBond::setup(): "
			<< "component not bound to scoring function." << std::endl;
		return false;
	}

	// clear the vector of possible hydrogen bonds
	possible_hydrogen_bonds_.clear();

	Options options = getScoringFunction()->getOptions();

	ideal_hbond_length_
		 = options.setDefaultReal(HydrogenBond::Option::HB_IDEAL_LENGTH,
				HydrogenBond::Default::HB_IDEAL_LENGTH);
	ideal_hbond_angle_
		 = options.setDefaultReal(HydrogenBond::Option::HB_IDEAL_ANGLE,
				HydrogenBond::Default::HB_IDEAL_ANGLE);
	h_bond_distance_lower_
		 = options.setDefaultReal(HydrogenBond::Option::HB_DIST_LOWER,
				HydrogenBond::Default::HB_DIST_LOWER);
	h_bond_distance_upper_
		 = options.setDefaultReal(HydrogenBond::Option::HB_DIST_UPPER,
				HydrogenBond::Default::HB_DIST_UPPER);
	h_bond_angle_lower_
		 = options.setDefaultReal(HydrogenBond::Option::HB_ANG_LOWER,
				HydrogenBond::Default::HB_ANG_LOWER);
	h_bond_angle_upper_
		 = options.setDefaultReal(HydrogenBond::Option::HB_ANG_UPPER,
				HydrogenBond::Default::HB_ANG_UPPER);
	verbosity_
		 = options.setDefaultInteger(HydrogenBond::Option::VERBOSITY,
				HydrogenBond::Default::VERBOSITY);

	delete receptor_fresno_types_;
	receptor_fresno_types_ = new FresnoTypes(getScoringFunction()->getReceptor());

	setupLigand();

	timer.stop();
	Log.info() << "HydrogenBond::setup(): "
		<< timer.getCPUTime() << " s" << std::endl;

	return true;
}


void HydrogenBond::setupLigand()
{
	delete ligand_fresno_types_;
	ligand_fresno_types_ = new FresnoTypes(getScoringFunction()->getLigand());
}


Size HydrogenBond::getType(Atom* atom)
{
	HashMap<const Atom*, Size>::const_iterator it = receptor_fresno_types_->getTypeMap()->find(atom);
	if (it != receptor_fresno_types_->getTypeMap()->end())
	{
		return it->second;
	}
	it = ligand_fresno_types_->getTypeMap()->find(atom);
	if (it != ligand_fresno_types_->getTypeMap()->end())
	{
		return it->second;
	}
	return FresnoTypes::UNKNOWN;
}


// If intermolecular H-bonds are to be evaluated, the _first_ atom of each pair must be a ligand atom and the second one a receptor atom.
// This is automatically done this way by ScoringFunction::createNonbondedPairVector()
void HydrogenBond::update(const vector<std::pair<Atom*, Atom*> >& pair_vector)
{
	possible_hydrogen_bonds_.clear();

	for (vector < std::pair < Atom*, Atom* > > ::const_iterator it = pair_vector.begin(); it != pair_vector.end(); it++)
	{
		// is there exactly one hydrogen? (tested here for speed-up only)
		bool h1 = (it->first->getElement().getSymbol() == "H");
		bool h2 = (it->second->getElement().getSymbol() == "H");
		if ( (!h1 && !h2) || (h1 && h2) )
		{
			continue;
		}

		// is there a hydrogen that is part of the ligand?
		bool ligand_hydrogen = h1;

		// HydrogenBonds with ligand-hydrogens cannot be precalculated (no donor-atom)
		if (mode_ == RECEPTOR_HYDROGENS && ligand_hydrogen)
		{
			continue;
		}

		// Scores for HydrogenBonds with receptor-hydrogens have already been precalculated by different HydrogenBond-component and are part of the score-grids
		else if (mode_ == LIGAND_HYDROGENS && !ligand_hydrogen)
		{
			continue;
		}

		int first_type = getType(it->first);
		int second_type = getType(it->second);
		if (first_type == FresnoTypes::UNKNOWN || second_type == FresnoTypes::UNKNOWN)
		{
			continue;
		}

		if ( first_type == FresnoTypes::HBOND_HYDROGEN
			&& (second_type == FresnoTypes::HBOND_ACCEPTOR_DONOR
			|| second_type == FresnoTypes::HBOND_ACCEPTOR) )

		{
			possible_hydrogen_bonds_.push_back(*it);
		}

		else if ( second_type == FresnoTypes::HBOND_HYDROGEN
			&& (first_type == FresnoTypes::HBOND_ACCEPTOR_DONOR
			|| first_type == FresnoTypes::HBOND_ACCEPTOR) )

		{
			possible_hydrogen_bonds_.push_back(make_pair(it->second, it->first));
		}
	}

	if (verbosity_ > 8)
	{
		Log.info() << "HydrogenBond update() statistics:" << std::endl;
		Log.info() << "Found " << possible_hydrogen_bonds_.size()
				<< " possible hydrogen bonds" << std::endl << std::endl;
	}
}


double HydrogenBond::updateScore()
{

#ifdef DEBUG
	Timer timer;
	timer.start();
	Molecule debug_molecule;
#endif

	Size verbosity
		 = getScoringFunction()->getOptions().getInteger(Option::VERBOSITY);

	score_ = 0.0;
	float val = 0.0;
	float distance;
	float angle;
	const Atom* hydrogen;
	const Atom* acceptor;
	Vector3 h_bond;
	Vector3 h_connection;

	// iterate over all possible hydrogen bond std::pairs
	vector<pair<const Atom*, const Atom*> >::const_iterator it;
	for (it = possible_hydrogen_bonds_.begin(); it != possible_hydrogen_bonds_.end(); ++it)
	{
		hydrogen = it->first;

		// we could check for multiple scoring here, but it would cost a lot
		// of performance.
		acceptor = it->second;

		// h_bond is the vector of the hbond
		h_bond = acceptor->getPosition() - hydrogen->getPosition();
		distance = fabs(ideal_hbond_length_ - h_bond.getLength());

		// if the distance is too large, the product of g1 and g2 is zero, so
		// we can skip the rest
		if (distance <= h_bond_distance_upper_)
		{
			// calculate g1
			val = base_function_->calculate(distance,
				h_bond_distance_lower_, h_bond_distance_upper_);

			/// Use partial charges for detection of strong hydrogen-bonds.
			/// Maximal charge-difference will result in score being multiplied by three.
			if (charge_evaluation_enabled_)
			{
				double charge1 = hydrogen->getCharge();
				double charge2 = acceptor->getCharge();
				if ((charge1 < 0 && charge2 > 0) || (charge1 > 0 && charge2 < 0))
				{
					double abs_charge_diff = fabs(charge2-charge1);
					if (abs_charge_diff > 2) abs_charge_diff = 2;
					if (abs_charge_diff > 1) abs_charge_diff = 1+(1-abs_charge_diff)*2;
					val *= abs_charge_diff;
					cout<<"hb factor = "<<abs_charge_diff<<endl;
				}
			}

			// If this component is to be precalculated for a grid,
			/// use distance only if probe-atom is a hydrogen.
			/// If probe-atom is donor atom, angle-dependend score can be precalculated.
			if (gridable_ && hydrogen->countBonds() == 0)
			{
				score_ += val;
				continue;
			}

			// calculate the angle of the hbond. It is necessary to find out
			// which one of the atoms is the actual hydrogen in order to
			// calculate the vector of the connection (in contrast to h bond)
			// of the hydrogen to the molecule it is attached to
			if (hydrogen->getElement().getSymbol() == "H")
			{
				h_connection =
					hydrogen->getBond(0)->getPartner(*hydrogen)->getPosition()
					- hydrogen->getPosition();
			}
			else // PARANOIA
			{
				throw BALL::Exception::GeneralException(__FILE__, __LINE__, "HydrogenBond::updateScore() error!", "black magic: hydrogen bond without hydrogens");
			}


			// angle is the angle of the h bond
			angle = ideal_hbond_angle_ - h_bond.getAngle(h_connection).toDegree();

			// if angle is too large, skip the rest
			if (angle <= h_bond_angle_upper_)
			{
				val *= base_function_->calculate(angle,
					h_bond_angle_lower_, h_bond_angle_upper_);

				if (scoring_function_->storeInteractionsEnabled())
				{
					// negative score for good pose ...
					double scaled_atom_score = -val;
					scaled_atom_score = scaleScore(scaled_atom_score);
					Atom* a1 = const_cast<Atom*>(hydrogen);
					Atom* a2 = const_cast<Atom*>(acceptor);
					a1->addInteraction(acceptor, "HB", scaled_atom_score);
					a2->addInteraction(hydrogen, "HB", scaled_atom_score);
				}

				score_ += val;
			}
		}
	}

	if (verbosity > 0)
	{
		Log.info() << "HB: energy is " << score_ << std::endl;
	}

	// we want a negative score for a good pose, thus we will use the negative of the value computed above
	score_ *= -1;

	/*
	scaleScore();
	return score_;
	*/

	return getScaledScore();
}