Exemple #1
0
void PeptideCapProcessor::optimizeCapPosition(Chain& chain, bool start)
{
    Vector3 translation;
    Atom* axis   = NULL;
    Residue* cap = NULL;
    std::vector<Atom*> a;
    std::vector<Atom*> b;

    Size nr = chain.countResidues();

    // cap at the beginning of a peptide
    if (start)
    {
        // put ACE-C to the center
        for (AtomIterator it = chain.getResidue(1)->beginAtom(); +it; ++it)
        {
            if (it->getName() == "N")
            {
                translation = it->getPosition();
            }

            b.push_back(&*it);
        }

        cap = chain.getResidue(0);
        for (AtomIterator it = cap->beginAtom(); +it; ++it)
        {
            a.push_back(&*it);
            if (it->getName() == "C")
            {
            axis = &*it;
        }
    }
}
//cap at the end of a peptide
else
{
    for (AtomIterator it = chain.getResidue(nr-2)->beginAtom(); +it; ++it)
    {
        if (it->getName() == "C")
        {
            translation = it->getPosition();
        }

        b.push_back(&*it);
    }

    cap = chain.getResidue(nr-1);
    for (AtomIterator it = cap->beginAtom(); +it; ++it)
    {
        a.push_back(&*it);
        if (it->getName() == "N")
        {
            axis = &*it;
        }
    }
}

//translate the anchor to origin
TranslationProcessor tlp;
tlp.setTranslation(translation*-1.0);
chain.apply(tlp);

//try all torsions
float largest_distance = 0.0;
float tmp_distance = 0.0;
float torsion      = 0.0;
float step         = 2.0;

TransformationProcessor tfp;
Matrix4x4 m;
m.setRotation( Angle(step, false), axis->getPosition());
tfp.setTransformation(m);

for (Position r = step; r <= 360; r+=step)
{
    cap->apply(tfp);

    tmp_distance = computeDistance(a,b);

    if (largest_distance < tmp_distance)
    {
        largest_distance = tmp_distance;
        torsion = r;
    }
}

//apply best rotation angle
m.setRotation( Angle(torsion, false), axis->getPosition());
tfp.setTransformation(m);
cap->apply(tfp);

//now translate the protein back
tlp.setTranslation(translation);
chain.apply(tlp);
}
Exemple #2
0
	bool ResidueChecker::checkAtomPositions(const Residue& res, const String& res_name)
	{
		// Make sure we are suppose to do this.
		if (!isEnabled(NAN_POSITIONS) && !isEnabled(STRONGLY_OVERLAPPING_ATOMS) 
				&& !isEnabled(OVERLAPPING_ATOMS) && !isEnabled(DUPLICATE_ATOM_NAMES))
		{
			return true;
		}

		bool result = true;

		AtomConstIterator atom_it;
		for (atom_it = res.beginAtom(); +atom_it; ++atom_it)
		{
			// Check for illegal atom positions (NaNs in any of the coordinates).
			if (isEnabled(NAN_POSITIONS) 
					&& (Maths::isNan(atom_it->getPosition().x)
					|| Maths::isNan(atom_it->getPosition().y)
					|| Maths::isNan(atom_it->getPosition().z)))
			{
				Log.warn() << "ResidueChecker: illegal atom position (not a number) for atom "
									 << atom_it->getName() << " of " << res_name << endl;
				// Mark the atoms affected
				if (selection_)
				{
					const_cast<Atom&>(*atom_it).select();
				}
				result = false;
			}
			
			Vector3 pos(atom_it->getPosition());
			AtomConstIterator atom_it2;
			for (atom_it2 = atom_it, ++atom_it2; +atom_it2; ++atom_it2)
			{
	
				// Check for strongly overlapping atoms (closer than 0.2 Angstrom)
				if (isEnabled(STRONGLY_OVERLAPPING_ATOMS)
						&& (pos.getSquareDistance(atom_it2->getPosition()) < 0.04))
				{
					Log.warn() << "ResidueChecker: atoms far too close -- distance between " 
										 << atom_it->getName() << " and " << atom_it2->getName() 
										 << " in " << res_name << " is " << pos.getDistance(atom_it2->getPosition()) 
										 << " A." << std::endl;
					// Mark the atoms affected
					if (selection_)
					{
						const_cast<Atom&>(*atom_it).select();
						const_cast<Atom&>(*atom_it2).select();
					}
					result = false;
				}

				// Check for overlapping atoms (closer than vdW radii minus 0.5 Angstrom)
				if (isEnabled(OVERLAPPING_ATOMS) && (!atom_it->isBoundTo(*atom_it2)))
				{
					double radius1 = atom_it->getElement().getVanDerWaalsRadius();
					if (radius1 == 0.0)
					{
						radius1 = atom_it->getElement().getAtomicRadius();
					}
					double radius2 = atom_it2->getElement().getVanDerWaalsRadius();
					if (radius2 == 0.0)
					{
						radius2 = atom_it2->getElement().getAtomicRadius();
					}

					// Compute the square of the sum of the vdw radii minus 0.6 Angstrom
					// overlap.
					double min_dist = std::max(radius1 + radius2 - 0.6, 0.0);
					if (atom_it->isGeminal(*atom_it2))
					{
						min_dist = std::max(min_dist - 1.0, 0.0);
					}
					min_dist *= min_dist;


					// If the atoms are further apart, skip them.
					if (pos.getSquareDistance(atom_it2->getPosition()) > min_dist)
					{
						continue;
					}

					// Complain about the overlap and mark the two atoms.
					Log.warn() << "ResidueChecker: atoms too close -- distance between " 
										 << atom_it->getName() << " and " << atom_it2->getName() 
										 << " in " << res_name << " is " << pos.getDistance(atom_it2->getPosition()) 
										 << " A (min: " << sqrt(min_dist) << ")." << std::endl;

					// Mark the atoms affected
					if (selection_)
					{
						const_cast<Atom&>(*atom_it).select();
						const_cast<Atom&>(*atom_it2).select();
					}
					result = false;
				}

				// Check for identical names (OK, a bad place, but why not...)
				if (isEnabled(DUPLICATE_ATOM_NAMES)
						&& (atom_it->getName() == atom_it2->getName()))
				{
					Log.warn() << "ResidueChecker: duplicate atom name " << atom_it->getName()
										 << " in " << res_name << "." << std::endl;
					result = false;
					const_cast<Atom&>(*atom_it).select();
					const_cast<Atom&>(*atom_it2).select();
				}
			}
		}
										 			
		return result;
	}
Exemple #3
0
	bool ResidueChecker::checkTemplate(const Residue& residue, const Residue& reference, const String& res_name)
	{
		// Make sure there's something to be done at all.
		if (!isEnabled(SUSPECT_BOND_LENGTHS) && !isEnabled(ELEMENTS))
		{
			return true;
		}

		bool result = true;

		// Check bond lengths (should be within +/- 15% of reference values).
		Atom::BondConstIterator bond_it;
		AtomConstIterator bond_atom_it;
		AtomConstIterator atom_it;
		BALL_FOREACH_BOND(reference, bond_atom_it, bond_it)
		{
			const Atom* first = 0;
			const Atom* second = 0;
			for (atom_it = residue.beginAtom(); +atom_it && (first == 0 || second == 0); ++atom_it)
			{
				if (atom_it->getName() == bond_it->getFirstAtom()->getName())
				{
					first = &*atom_it;
				}
				if (atom_it->getName() == bond_it->getSecondAtom()->getName())
				{
					second = &*atom_it;
				}
			}
			
			// if we found the bond atoms in residue, check the atom distance
			if ((first != 0) && (second != 0))
			{
				float distance = first->getPosition().getDistance(second->getPosition());
				float deviation = fabs(distance - bond_it->getLength()) / bond_it->getLength();
				if (isEnabled(SUSPECT_BOND_LENGTHS) && (deviation > 0.15))
				{
					Log.warn() << "ResidueChecker: in residue " << res_name << ": atom distance " 
										 << "between " << first->getName() << " and " << second->getName() << " suspect: " 
										 << distance << " A instead of " << bond_it->getLength() << " A" << endl;
					result = false;
					// If selection is enabled, mark the two atoms
					if (selection_)
					{
						const_cast<Atom*>(first)->select();
						const_cast<Atom*>(second)->select();
					}
				}

				// Check for the element type of each atom
				if (isEnabled(ELEMENTS)
						&& (first->getElement() != bond_it->getFirstAtom()->getElement()))
				{
					Log.warn() << "ResidueChecker: in residue " << res_name << ": atom "
										 << first->getName() << " is " 
										 << first->getElement().getSymbol() << " should be "
										 << bond_it->getFirstAtom()->getElement().getSymbol() << endl;
										 // This could be the anchor of a ResidueRectfifier...
										 // (const_cast<Atom*> (first))->setElement(bond_it->getFirstAtom()->getElement());
					result = false;
					// If selection is enabled, mark the atom
					if (selection_)
					{
						const_cast<Atom*>(first)->select();
					}
				}
				if (isEnabled(ELEMENTS)
						&& (second->getElement() != bond_it->getSecondAtom()->getElement()))
				{
					Log.warn() << "ResidueChecker: in residue " << res_name << ": atom "
										 << second->getName() << " is " 
										 << second->getElement().getSymbol() << " should be "
										 << bond_it->getSecondAtom()->getElement().getSymbol() << endl;
					result = false;
					// If selection is enabled, mark the atom
					if (selection_)
					{
						const_cast<Atom*>(second)->select();
					}
				}
			}
		}

		return result;
	}
Exemple #4
0
	bool ResidueChecker::checkCompleteness
		(const Residue& residue, const Residue& reference, const String& res_name)
	{
		// Make sure we are suppose to do this.
		if (!isEnabled(EXTRA_ATOMS) && !isEnabled(MISSING_ATOMS))
		{
			return true;
		}

		bool result = true;

		// First, check for completeness
		HashSet<String> reference_names;
		AtomConstIterator atom_it;
		for (atom_it = reference.beginAtom(); +atom_it; ++atom_it)
		{
			reference_names.insert(atom_it->getName());
		}
		
		// Check for extra atoms in the residue.
		for (atom_it = residue.beginAtom(); +atom_it; ++atom_it)
		{
			if (reference_names.has(atom_it->getName()))
			{
				reference_names.erase(atom_it->getName());
			} 
			else if (isEnabled(EXTRA_ATOMS))
			{
				Log.warn() << "ResidueChecker: did not find atom " << atom_it->getName() << " of " 
									 << res_name  << " in the reference residue " << reference.getName() << endl;
				result = false;

				// If selection is enabled, mark the residue
				if (selection_)
				{
					const_cast<Residue&>(residue).select();
				}
			}
		}

		// Check for missing atoms in the residue.
		if (isEnabled(MISSING_ATOMS) && (reference_names.size() > 0))
		{
			Log.warn() << "ResidueChecker: did not find the following atoms in " << res_name << " : ";
			HashSet<String>::Iterator set_it = reference_names.begin();
			for (; set_it != reference_names.end(); ++set_it)
			{
				Log.warn() << *set_it << " ";
			}
			Log.warn() << " (template was " << reference.getName() << ")" << endl;
			result = false;

			// If selection is enabled, mark the residue
			if (selection_)
			{
				const_cast<Residue&>(residue).select();
			}
		}

		return result;
	}
Exemple #5
0
	bool ResidueChecker::checkCharge(const Residue& residue, const String& res_name)
	{
		// Make sure we are suppose to do this.
		if (!isEnabled(LARGE_NET_CHARGE) && !isEnabled(LARGE_CHARGES) && !isEnabled(NON_INTEGRAL_NET_CHARGE))
		{
			return true;
		}

		bool result = true;

		// checking charge: charge should be integral and -2 <= charge <= 2
		float total_charge = 0.0;
		AtomConstIterator atom_it = residue.beginAtom();
		for (; +atom_it; ++atom_it)
		{
			total_charge += atom_it->getCharge();
			// warn for too large charges (above +/- 4 e0)
			if (isEnabled(LARGE_CHARGES) && (fabs(atom_it->getCharge()) > 4.0))
			{
				Log.warn() << "ResidueChecker: suspect charge of " << atom_it->getCharge()
					<< " for " << atom_it->getName() << " in " << res_name << std::endl;
				result = false;
				// If selection is enabled, mark the atom
				if (selection_)
				{
					const_cast<Atom&>(*atom_it).select();
				}
			}
		}

		// check for very large absolute charges
		if (isEnabled(LARGE_NET_CHARGE) && (total_charge < -2.0))
		{
			Log.warn() << "ResidueChecker: in residue " << res_name << ": total charge of " 
								 << total_charge << " is too negative." << endl;
			result = false;
			// If selection is enabled, mark the residue
			if (selection_)
			{
				const_cast<Residue&>(residue).select();
			}
		}

		if (isEnabled(LARGE_NET_CHARGE) && (total_charge > 2.0))
		{
			Log.warn() << "ResidueChecker: in residue " << res_name << ": total charge of " 
								 << total_charge << " is too positive." << endl;
			result = false;
			// If selection is enabled, mark the residue
			if (selection_)
			{
				const_cast<Residue&>(residue).select();
			}
		}

		// check for integrality of charges
		float tmp = fabs(fabs(total_charge) - (float)((int)(fabs(total_charge) + 0.5)));
		if (isEnabled(NON_INTEGRAL_NET_CHARGE) && (tmp > 0.05))
		{
			Log.warn() << "ResidueChecker: in residue " << res_name << ": residue total charge of " 
								 << total_charge << " is not integral." << endl;
			result = false;
			// If selection is enabled, mark the residue
			if (selection_)
			{
				const_cast<Residue&>(residue).select();
			}
		}
	
		return result;
	}
Exemple #6
0
		void EditMode::addStructure_()
		{
			QAction* action = dynamic_cast<QAction*>(sender());
			if (action == 0) return;

			String name = ascii(action->text());

			scene_->deselect();

			if (!fragment_db_)
			{
				fragment_db_ = new FragmentDB("fragments/Editing-Fragments.db");
			}

			list<AtomContainer*> containers = scene_->getContainers();
			if (containers.size() == 0) return;

			Residue* residue = fragment_db_->getResidueCopy(name);
			if (residue == 0)
			{
				residue = fragment_db_->getResidueCopy(name + "-Skeleton");
				if (residue == 0) return;
			}

			Vector3 p;
			Size nr = 0;
			AtomIterator ait = residue->beginAtom();
			for (;+ait; ++ait)
			{
				p += ait->getPosition();
				nr++;
			}

			if (nr == 0)
			{
				BALLVIEW_DEBUG
					delete residue;
				return;
			}

			p /= (float) nr;

			QPoint pos = scene_->mapFromGlobal(mouse_pos_new_);

			Matrix4x4 m;
			Vector3 x = scene_->mapViewportTo3D(pos.x(), pos.y());
			TransformationProcessor tf;

			Vector3 vv = scene_->getStage()->getCamera().getViewVector();
			float l = vv.getLength();
			if (!Maths::isZero(l)) vv /= l;
			Vector3 axis = Vector3(1,0,0) % vv;
			if (axis.getSquareLength() != 0)
			{
				Angle a = vv.getAngle(Vector3(1,0,0));
				m.setRotation(a, axis);
				tf.setTransformation(m);
				residue->apply(tf);
			}

			m.setTranslation(x - p);
			tf.setTransformation(m);
			residue->apply(tf);

			AtomContainer* s = *containers.begin();
			if (RTTI::isKindOf<System>(*s))
			{
				System* system = (System*) s;
				Molecule* mol = system->getMolecule(0);
				if (mol == 0)
				{
					mol = new Molecule();
					system->insert(*mol);
				}
				s = mol;
			}

			s->insert(*residue);
			scene_->getMainControl()->deselectCompositeRecursive(s, true);
			scene_->getMainControl()->selectCompositeRecursive(residue, true);
			scene_->getMainControl()->update(*s);
			scene_->notify(new NewSelectionMessage);
//			setMode(MOVE__MODE);
		}
Exemple #7
0
	//TODO switch to real Angle
	float calculateResidueChiAngles(const Residue& residue)
	{
		// some variables
		Atom const* N = 0;
		Atom const* CA = 0;
		Atom const* CB = 0;
		Atom const* X = 0;

		int num_of_atoms = 0;
		float angle =  0;//FLOAT_VALUE_NA;
	
		String residue_name = residue.getName();

		// we assume that GLY has no typical CHI_1 - angle
		if (residue_name == "GLY" )
		{	
			return angle;
		}

		AtomConstIterator r_it = residue.beginAtom();
		for (; r_it != residue.endAtom(); ++r_it)
		{	
			String name = r_it->getName();
			if (name == "N")
			{
				N = &(*r_it);
				num_of_atoms += 1;
			}
			else if (name == "CA")
			{
				CA = &(*r_it);
				num_of_atoms += 1;
			}
			else if (name == "CB")
			{ 
				CB = &(*r_it);
				num_of_atoms += 1;
			}
		}

		if (num_of_atoms != 3)
		{
			Log.info() << "calculateResidueChiAngles: Torsion angle of " << residue_name<< std::endl;
			return angle;
		}

		// determine the missing atom X
		/* Sidechain dihedral angle chi1 is defined
			 (for non-Gly residues) as follows:

				Chi1:	N(i)-CA(i)-CB(i)-X(i)

				where X is the following atom for the following
				residue types:

				X				Residue type
				----		----------------------------
				HB1			Ala (for models with protons,labelled 1HB in PDB files).
				SG			Cys
				CG			Asp, Glu, Phe, His, Lys, Leu, Met,
				Asn, Pro, Gln, Arg, Trp, Tyr
				CG1			Ile, Val
				OG			Ser
				OG1			Thr

		In order to be conform with ShiftX we leave out GLY and ALA
		*/
		
		if (residue_name == "GLY")
		{ 
			Log.info() << "calculateResidueChiAngles: Torsion angle of a Glycine could not be computed!" << std::endl;
			return angle;
		}
		else if (residue_name == "ALA")
		{
			r_it = residue.beginAtom();
			for (;r_it != residue.endAtom(); ++r_it)
			{	
				if (r_it->getName() == "HB1" || r_it->getName() == "1HB")
				{
					X = &(*r_it);
					num_of_atoms += 1;
					break;
				}
			}
		}
		else if (residue_name == "CYS")
		{
			r_it = residue.beginAtom();
			for (;r_it != residue.endAtom(); ++r_it)
			{	
				if (r_it->getName() == "SG")
				{
					X = &(*r_it);	
					num_of_atoms += 1;
					break;
				}
			}
		}
		else if (residue_name == "ASP" || residue_name ==  "GLU" || 
				residue_name == "PHE" || residue_name ==  "HIS" || 
				residue_name == "LYS" || residue_name ==  "LEU" ||
				residue_name == "MET" || residue_name ==  "ASN" ||
				residue_name == "PRO" || residue_name ==  "GLN" ||
				residue_name == "ARG" || residue_name ==  "TRP" ||  residue_name == "TYR")
		{
			r_it = residue.beginAtom();
			for (;r_it != residue.endAtom(); ++r_it)
			{	
				if (r_it->getName() == "CG")
				{
					X = &(*r_it);	
					num_of_atoms += 1;
					break;
				}
			}
		}
		else if (residue_name == "VAL" || residue_name ==  "ILE")
		{									
			r_it = residue.beginAtom();
			for (;r_it != residue.endAtom(); ++r_it)
			{	
				if (r_it->getName() == "CG1")
				{
					X = &(*r_it); 	
					num_of_atoms += 1;
					break;
				}
			}
		}
		else if (residue_name == "SER") 
		{									
			r_it = residue.beginAtom();
			for (;r_it != residue.endAtom(); ++r_it)
			{	
				if (r_it->getName() == "OG")
				{
					X = &(*r_it);	
					num_of_atoms += 1;
					break;
				}
			}
		}
		else if (residue_name == "THR") 
		{									
			r_it = residue.beginAtom();
			for (;r_it != residue.endAtom(); ++r_it)
			{	
				if (r_it->getName() == "OG1")
				{
					X = &(*r_it);
					num_of_atoms += 1;
					break;
				}
			}
		}

		if (num_of_atoms != 4)
		{
			Log.info() << "calculateResidueChiAngles: Chi torsion angle of " << residue.getID() << "-"<<  residue.getName() << " could not be computed!" << std::endl;
			return angle;
		}

		Vector3 a = N->getPosition();
		Vector3 b = CA->getPosition();
		Vector3 c = CB->getPosition();
		Vector3 d = X->getPosition();

		//angle = getTorsionAngle(a.x, a.y, a.z, b.x, b.y, b.z, 
		//											 c.x, c.y, c.z, d.x, d.y, d.z)*180./M_PI;

		angle = calculateTorsionAngle(*N,*CA,*CB,*X).toRadian();
		while (angle < 0.)
		{
			angle = angle + 2*BALL::Constants::PI;
		}

		return angle; // TODO return real angle
	}
Exemple #8
0
	//TODO switch to real Angle
	float calculateResidueChi2Angles(const Residue& residue) 
	{
		// some variables	
		Atom const* CA = 0;
		Atom const* CB = 0;
		Atom const* CG = 0;
		Atom const* XG = 0;

		int num_of_atoms = 0;
		float angle = 0; // FLOAT_VALUE_NA;
		String residue_name = residue.getName();

		// GLY, ALA, SER and CYS have no typical CHI2 - angle
		if ( 	 (residue_name == "ALA") 
				|| (residue_name == "GLY") 
				|| (residue_name == "SER") 
				|| (residue_name == "CYS"))
		{
			Log.info() << "calculateResidueChi2Angles: Chi torsion angle of " << residue.getID() << "-"<< residue.getName() << " could not be computed!" << std::endl;
			return angle;
		}

		//  Sidechain dihedral angle chi2 is defined as follows:
		//  
		// 	Chi2:	CA(i)-CB(i)-CG(i)-XG(i)
		//  where XG is the following atom for the following
		//	residue types:
		//
		//	CG     XG     residue 
		//	-------------------------------------
		// 	CG     CD     PRO, GLN,  GLU, LYS, ARG
		// 		     CD1    LEU,TRP,PHE,TYR, 
		//  		   OD1    ASN, ASP
		//  		   ND1		HIS	 
		//         SD     MET 
		//  CG1    CD1    ILE
		//         1HG1   VAL
		//	CG2	   (1HG2   VAL)
		//				 1HG2		THR
		//	
		//  Note: in some amino acids the atom names can be switched, i.e.
		// 				for chi2 in amino acids PHE:  CD1 <-> CD2
		//          				              TYR:  CD1 <-> CD2
		//        	        			 	      ASP:  OD1 <-> OD2


		AtomConstIterator r_it = residue.beginAtom();
		for (; r_it != residue.endAtom(); ++r_it)
		{	
			String name = r_it->getName();
			if (name == "CA")
			{
				CA = &(*r_it);
				num_of_atoms += 1;
			}
			else if (name == "CB")
			{ 
				CB = &(*r_it);
				num_of_atoms += 1;	
			}
			if (name == "CG")
			{
				CG = &(*r_it);
				num_of_atoms += 1;
			}
		}

		//look for XG
		if (   (residue_name == "ARG") || (residue_name == "GLN") 
				|| (residue_name == "GLU") || (residue_name == "LYS") 
				|| (residue_name == "PRO"))
		{
			r_it = residue.beginAtom();
			for (;r_it != residue.endAtom(); ++r_it)
			{	
				if (r_it->getName() == "CD")
				{
					XG = &(*r_it);
					num_of_atoms += 1;
					break;
				}
			}
		}
		else if ( (residue_name == "ASN") || (residue_name == "ASP") )
		{
			r_it = residue.beginAtom();
			for (;r_it != residue.endAtom(); ++r_it)
			{	
				if (r_it->getName() == "OD1")
				{
					XG = &(*r_it);
					num_of_atoms += 1;
					break;
				}
			}
		}
		else if ( (residue_name == "LEU") || (residue_name == "TRP") 
				||(residue_name == "PHE") || (residue_name == "TYR") )
		{
			r_it = residue.beginAtom();
			for (;r_it != residue.endAtom(); ++r_it)
			{	
				if (r_it->getName() == "CD1")
				{
					XG = &(*r_it);
					num_of_atoms += 1;
					break;
				}
			}
		}	
		else if (residue_name == "HIS") 
		{
			r_it = residue.beginAtom();
			for (;r_it != residue.endAtom(); ++r_it)
			{	
				if (r_it->getName() == "ND1")
				{
					XG = &(*r_it);
					num_of_atoms += 1;
					break;
				}
			}
		}
		else if(residue_name == "MET") 	
		{
			r_it = residue.beginAtom();
			for (;r_it != residue.endAtom(); ++r_it)
			{	
				if (r_it->getName() == "SD")
				{
					XG = &(*r_it);
					num_of_atoms += 1;
					break;
				}
			}
		}
		// we have to take special care about ILE, VAL and THR
		else if(residue_name == "ILE") 	
		{
			r_it = residue.beginAtom();
			for (;r_it != residue.endAtom(); ++r_it)
			{	
				if (r_it->getName() == "CG1")
				{
					CG = &(*r_it);
					num_of_atoms += 1;
				}
				else if (r_it->getName() == "CD1")
				{
					XG = &(*r_it);
					num_of_atoms += 1;
				}
			}
		}
		else if(residue_name == "VAL") 	
		{
			r_it = residue.beginAtom();
			for (;r_it != residue.endAtom(); ++r_it)
			{	
				if (r_it->getName() == "1HG1")
				{
					XG = &(*r_it);
					num_of_atoms += 1;
				}
				else if (r_it->getName() == "CG1")
				{
					CG = &(*r_it);
					num_of_atoms += 1;
				}
			}
		}
		else if(residue_name == "THR") 	
		{
			r_it = residue.beginAtom();
			for (;r_it != residue.endAtom(); ++r_it)
			{	
				if (r_it->getName() == "1HG2")
				{
					XG = &(*r_it);
					num_of_atoms += 1;
				}
				else if (r_it->getName() == "CG2")
				{
					CG = &(*r_it);
					num_of_atoms += 1;
				}
			}
		} 

		if (num_of_atoms != 4)
		{
			Log.info() << "calculateResidueChi2Angles: Chi torsion angle of " << residue.getID() << "-"<<  residue.getName() << " could not be computed!" << std::endl;
			return angle;
		}

		Vector3 a = CA->getPosition();
		Vector3 b = CB->getPosition();
		Vector3 c = CG->getPosition();
		Vector3 d = XG->getPosition();

		angle = calculateTorsionAngle(*CA,*CB,*CG,*XG).toRadian();
		while (angle < 0.)
		{
			angle = angle + 2*BALL::Constants::PI;
		}
		return angle; // TODO return real angle
	}