Rotate molecule with Avogadro using python script

Hello list,

I have a question and I could not find an answer easily even if I tried
many things.

I would like to do a rotation of a loaded molecule within a python
script (I believe within the interface it is not yet possible).
I have searched within the API and found that:
http://avogadro.openmolecules.net/wiki/API_Documentation

I believe hte function I have to use is Avogadro.Navigate.rotate
Its help is:
rotate( (GLWidget)arg1, (object)arg2, (float)arg3, (float)arg4,
(float)arg5) -> None :
Rotate about center by deltaX, deltaY, and deltaZ in the x, y and z
axes A generalization of the rotate() and tilt() methods.

But I do not understand how to use it. What is that GLWidget? I think I
need to select the whole molecule or an atom?
Is there somewhere where we can find scripts that have been made in
python for Avogadro?

Thanks for your help,
Fabien

Hi Fabien,

On Thu, May 19, 2011 at 5:09 AM, Archambault Fabien
fabien.archambault@nanotimes.fr wrote:

I believe hte function I have to use is Avogadro.Navigate.rotate
Its help is:
rotate( (GLWidget)arg1, (object)arg2, (float)arg3, (float)arg4,
(float)arg5) → None :
Rotate about center by deltaX, deltaY, and deltaZ in the x, y and z
axes A generalization of the rotate() and tilt() methods.

That method will rotate the camera, not the molecule. To rotate the
molecule itself, you will need to manually set each atom’s position
using the Molecule.pos() and Molecule.setPos() functions (I think that
is the correct python syntax?).

There is a tutorial extension that shows how to rotate selected atoms
around an arbitrary vector – it is in C++, but should offer some help
as to how a rotation can be performed. The source code can be found in
libavogadro/examples/thirdPartyExtensions/04-RotateSelection/rotateselectionextension.cpp
of the avogadro master branch.

The function that actually performs the rotation is here:

The key bits are:

Eigen::AngleAxis rot (angle * DEG_TO_RAD, axis.normalized());

This essentially constructs a rotation matrix ‘rot’ using the
Eigen::AngleAxis transform from an angle and axis vector.

Then it’s a matter of iterating through the atoms and applying the rotation:

for (int i = 0; i < selected.size(); i++) {
  atom = qobject_cast<Atom*>(selected.at(i));
  // you'll probably want 'atom = mymolecule.atoms().at(i)' in your app
  // instead of the above line
  coord = *atom->pos(); // extract coordinate
  coord -= offset; // Optional: offset the rotation axis
  coord = rot * coord; // Apply rotation
  coord += offset; // reset offset
  atom->setPos(coord); // Set new coordinate
}

Hope this helps,

Dave

On 05/19/2011 02:00 PM, David Lonie wrote:

Hi Fabien,

On Thu, May 19, 2011 at 5:09 AM, Archambault Fabien
fabien.archambault@nanotimes.fr wrote:

I believe hte function I have to use is Avogadro.Navigate.rotate
Its help is:
rotate( (GLWidget)arg1, (object)arg2, (float)arg3, (float)arg4,
(float)arg5) → None :
Rotate about center by deltaX, deltaY, and deltaZ in the x, y and z
axes A generalization of the rotate() and tilt() methods.
That method will rotate the camera, not the molecule. To rotate the
molecule itself, you will need to manually set each atom’s position
using the Molecule.pos() and Molecule.setPos() functions (I think that
is the correct python syntax?).

There is a tutorial extension that shows how to rotate selected atoms
around an arbitrary vector – it is in C++, but should offer some help
as to how a rotation can be performed. The source code can be found in
libavogadro/examples/thirdPartyExtensions/04-RotateSelection/rotateselectionextension.cpp
of the avogadro master branch.

The function that actually performs the rotation is here:

avogadro/libavogadro/examples/thirdPartyExtensions/04-RotateSelection/rotateselectionextension.cpp at master · cryos/avogadro · GitHub

The key bits are:

Eigen::AngleAxis rot (angle * DEG_TO_RAD, axis.normalized());

This essentially constructs a rotation matrix ‘rot’ using the
Eigen::AngleAxis transform from an angle and axis vector.

Then it’s a matter of iterating through the atoms and applying the rotation:

 for (int i = 0; i<  selected.size(); i++) {
   atom = qobject_cast<Atom*>(selected.at(i));
   // you'll probably want 'atom = mymolecule.atoms().at(i)' in your app
   // instead of the above line
   coord = *atom->pos(); // extract coordinate
   coord -= offset; // Optional: offset the rotation axis
   coord = rot * coord; // Apply rotation
   coord += offset; // reset offset
   atom->setPos(coord); // Set new coordinate
 }

Hope this helps,

Dave

Hi,

thanks for this reply.

I did not notice that it was for the camera. This explains the widget…

I tried to look at the code but I do not “speak” C++ so I believe I will
have a hard time to understand… The main problem, for me, is that the
class setPos does not exists in the python binding.
Here are all the available classes for the atom object (in python) :
for atom in mol.atoms:
print atom.
atom.class atom.init atom.sizeof
atom.forceVector atom.pos
atom.delattr atom.module atom.str
atom.formalCharge atom.residue
atom.dict atom.new atom.subclasshook
atom.id atom.residueId
atom.doc atom.reduce atom.weakref
atom.index atom.type
atom.format atom.reduce_ex atom.atomicNumber
atom.isHydrogen atom.update
atom.getattribute atom.repr atom.bond
atom.neighbors atom.valence
atom.hash atom.setattr atom.bonds
atom.partialCharge

The pos works but not the setPos.

My trial is on a water molecule (h2o.xyz):
$ python

import Avogadro as a
mol = a.MoleculeFile.readMolecule(‘h2o.xyz’)
for atom in mol.atoms:
… print atom.pos

[ 0.00369 2.73505 2.63908]
[-0.88715 2.29885 2.66616]
[-0.14964 3.67132 2.43027]

Perhaps this is somewhere else?

I also tried something I believed it should work but it did not move the
atoms:

mol.center
array([-0.34436667, 2.90174 , 2.57850333])
mol.translate(-mol.center)
mol.center
array([ 5.55111512e-17, -1.48029737e-16, 4.44089210e-16])
for atom in mol.atoms:
… print atom.pos

[ 0.34805667 -0.16669 0.06057667]
[-0.54278333 -0.60289 0.08765667]
[ 0.19472667 0.76958 -0.14823333]

The center seems to have moved but no atoms really moved…

If someone knows how to use python bindings in Avogadro and done some
tutorials it should be nice.

Fabien

On Thu, May 19, 2011 at 8:35 AM, Archambault Fabien
fabien.archambault@nanotimes.fr wrote:

I tried to look at the code but I do not “speak” C++ so I believe I will
have a hard time to understand… The main problem, for me, is that the
class setPos does not exists in the python binding.

Does ‘atom.pos = [new coordinate]’ work?

There’s also this:
http://avogadro.openmolecules.net/wiki/Category:Scripting

From that page, it looks like Molecule.setAtomPos should do what you need.

Dave

Here are all the available classes for the atom object (in python) :
for atom in mol.atoms:
print atom.
atom.class atom.init atom.sizeof
atom.forceVector atom.pos
atom.delattr atom.module atom.str
atom.formalCharge atom.residue
atom.dict atom.new atom.subclasshook
atom.id atom.residueId
atom.doc atom.reduce atom.weakref
atom.index atom.type
atom.format atom.reduce_ex atom.atomicNumber
atom.isHydrogen atom.update
atom.getattribute atom.repr atom.bond
atom.neighbors atom.valence
atom.hash atom.setattr atom.bonds
atom.partialCharge

The pos works but not the setPos.

My trial is on a water molecule (h2o.xyz):
$ python

import Avogadro as a
mol = a.MoleculeFile.readMolecule(‘h2o.xyz’)
for atom in mol.atoms:
… print atom.pos

[ 0.00369 2.73505 2.63908]
[-0.88715 2.29885 2.66616]
[-0.14964 3.67132 2.43027]

Perhaps this is somewhere else?

I also tried something I believed it should work but it did not move the
atoms:

mol.center
array([-0.34436667, 2.90174 , 2.57850333])
mol.translate(-mol.center)
mol.center
array([ 5.55111512e-17, -1.48029737e-16, 4.44089210e-16])
for atom in mol.atoms:
… print atom.pos

[ 0.34805667 -0.16669 0.06057667]
[-0.54278333 -0.60289 0.08765667]
[ 0.19472667 0.76958 -0.14823333]

The center seems to have moved but no atoms really moved…

If someone knows how to use python bindings in Avogadro and done some
tutorials it should be nice.

Fabien


What Every C/C++ and Fortran developer Should Know!
Read this article and learn how Intel has extended the reach of its
next-generation tools to help Windows* and Linux* C/C++ and Fortran
developers boost performance applications - including clusters.
http://p.sf.net/sfu/intel-dev2devmay


Avogadro-Discuss mailing list
Avogadro-Discuss@lists.sourceforge.net
avogadro-discuss List Signup and Options

On 05/19/2011 02:43 PM, David Lonie wrote:

On Thu, May 19, 2011 at 8:35 AM, Archambault Fabien
fabien.archambault@nanotimes.fr wrote:

I tried to look at the code but I do not “speak” C++ so I believe I will
have a hard time to understand… The main problem, for me, is that the
class setPos does not exists in the python binding.
Does ‘atom.pos = [new coordinate]’ work?
I tried but this rises an error.

import numpy # For array
zero = numpy.array( [0, 0, 0] )
for atom in mol.atoms:
… atom.pos = zero

Traceback (most recent call last):
File “”, line 2, in
Boost.Python.ArgumentError: Python argument types in
None.None(Atom, numpy.ndarray)
did not match C++ signature:
None(Avogadro::Atom {lvalue}, Eigen::Matrix<double, 3, 1, 2, 3, 1>)

There’s also this:
http://avogadro.openmolecules.net/wiki/Category:Scripting

From that page, it looks like Molecule.setAtomPos should do what you need.
I have seen this page but I do not understand where are those atomPos
and setAtomPos.
If I look in the classes available for my molecule:
mol.OBMol mol.addCube
mol.cubes mol.removeAtom
mol.class mol.addHydrogens
mol.currentConformer mol.removeBond
mol.delattr mol.addMesh
mol.dipoleMoment mol.removeCube
mol.dict mol.addResidue
mol.energies mol.removeHydrogens
mol.doc mol.addRing
mol.energy mol.removeMesh
mol.format mol.addZMatrix
mol.farthestAtom mol.removeResidue
mol.getattribute mol.atom
mol.fileName mol.removeRing
mol.hash mol.atomById
mol.id mol.removeZMatrix
mol.init mol.atoms
mol.index mol.residue
mol.module mol.bond
mol.mesh mol.residueById
mol.new mol.bondById
mol.meshById mol.residues
mol.reduce mol.bonds
mol.meshes mol.rings
mol.reduce_ex mol.calculateAromaticity
mol.normalVector mol.setAllConformers
mol.repr mol.calculatePartialCharges
mol.numAtoms mol.setConformer
mol.setattr mol.center
mol.numBonds mol.setEnergy
mol.sizeof mol.clear
mol.numConformers mol.translate
mol.str mol.clearConformers
mol.numCubes mol.type
mol.subclasshook mol.conformer
mol.numMeshes mol.update
mol.weakref mol.conformers
mol.numResidues mol.zMatrices
mol.addAtom mol.copy
mol.numRings mol.zMatrix
mol.addBond mol.cube mol.numZMatrices
mol.addConformer mol.cubeById mol.radius

Thanks for your replies. I keep on digging.

Fabien

Dave

Here are all the available classes for the atom object (in python) :
for atom in mol.atoms:
print atom.
atom.class atom.init atom.sizeof
atom.forceVector atom.pos
atom.delattr atom.module atom.str
atom.formalCharge atom.residue
atom.dict atom.new atom.subclasshook
atom.id atom.residueId
atom.doc atom.reduce atom.weakref
atom.index atom.type
atom.format atom.reduce_ex atom.atomicNumber
atom.isHydrogen atom.update
atom.getattribute atom.repr atom.bond
atom.neighbors atom.valence
atom.hash atom.setattr atom.bonds
atom.partialCharge

The pos works but not the setPos.

My trial is on a water molecule (h2o.xyz):
$ python

import Avogadro as a
mol = a.MoleculeFile.readMolecule(‘h2o.xyz’)
for atom in mol.atoms:
… print atom.pos

[ 0.00369 2.73505 2.63908]
[-0.88715 2.29885 2.66616]
[-0.14964 3.67132 2.43027]

Perhaps this is somewhere else?

I also tried something I believed it should work but it did not move the
atoms:

mol.center
array([-0.34436667, 2.90174 , 2.57850333])
mol.translate(-mol.center)
mol.center
array([ 5.55111512e-17, -1.48029737e-16, 4.44089210e-16])
for atom in mol.atoms:
… print atom.pos

[ 0.34805667 -0.16669 0.06057667]
[-0.54278333 -0.60289 0.08765667]
[ 0.19472667 0.76958 -0.14823333]

The center seems to have moved but no atoms really moved…

If someone knows how to use python bindings in Avogadro and done some
tutorials it should be nice.

Fabien

On May 19, 2011, at 8:54 AM, Archambault Fabien wrote:

None.None(Atom, numpy.ndarray)

did not match C++ signature:
None(Avogadro::Atom {lvalue}, Eigen::Matrix<double, 3, 1, 2, 3, 1>)

The problem seems to be that the conversion between numpy and the vector library Eigen isn’t working. I’m not sure if there’s a good solution to that directly.

OTOH, you can always use mol.OBMol to get an OBMol, use the Open Babel or Pybel libraries to change the coordinates, and then update the Avogadro molecule.

http://openbabel.org/docs/dev/UseTheLibrary/Python_PybelAPI.html
http://openbabel.org/docs/dev/UseTheLibrary/PythonExamples.html

I can’t say I’ve used the Avogadro python integration much, but I’ll see what I can do with the Eigen bindings.

Hope that helps,
-Geoff

2011/5/19 Archambault Fabien fabien.archambault@nanotimes.fr

On 05/19/2011 02:43 PM, David Lonie wrote:

On Thu, May 19, 2011 at 8:35 AM, Archambault Fabien
fabien.archambault@nanotimes.fr wrote:

I tried to look at the code but I do not “speak” C++ so I believe I will
have a hard time to understand… The main problem, for me, is that the
class setPos does not exists in the python binding.
Does ‘atom.pos = [new coordinate]’ work?
I tried but this rises an error.

import numpy # For array
zero = numpy.array( [0, 0, 0] )
for atom in mol.atoms:
… atom.pos = zero

Traceback (most recent call last):
File “”, line 2, in
Boost.Python.ArgumentError: Python argument types in
None.None(Atom, numpy.ndarray)
did not match C++ signature:
None(Avogadro::Atom {lvalue}, Eigen::Matrix<double, 3, 1, 2, 3, 1>)

There’s also this:
http://avogadro.openmolecules.net/wiki/Category:Scripting

From that page, it looks like Molecule.setAtomPos should do what you
need.
I have seen this page but I do not understand where are those atomPos
and setAtomPos.
If I look in the classes available for my molecule:
mol.OBMol mol.addCube
mol.cubes mol.removeAtom
mol.class mol.addHydrogens
mol.currentConformer mol.removeBond
mol.delattr mol.addMesh
mol.dipoleMoment mol.removeCube
mol.dict mol.addResidue
mol.energies mol.removeHydrogens
mol.doc mol.addRing
mol.energy mol.removeMesh
mol.format mol.addZMatrix
mol.farthestAtom mol.removeResidue
mol.getattribute mol.atom
mol.fileName mol.removeRing
mol.hash mol.atomById
mol.id mol.removeZMatrix
mol.init mol.atoms
mol.index mol.residue
mol.module mol.bond
mol.mesh mol.residueById
mol.new mol.bondById
mol.meshById mol.residues
mol.reduce mol.bonds
mol.meshes mol.rings
mol.reduce_ex mol.calculateAromaticity
mol.normalVector mol.setAllConformers
mol.repr mol.calculatePartialCharges
mol.numAtoms mol.setConformer
mol.setattr mol.center
mol.numBonds mol.setEnergy
mol.sizeof mol.clear
mol.numConformers mol.translate
mol.str mol.clearConformers
mol.numCubes mol.type
mol.subclasshook mol.conformer
mol.numMeshes mol.update
mol.weakref mol.conformers
mol.numResidues mol.zMatrices
mol.addAtom mol.copy
mol.numRings mol.zMatrix
mol.addBond mol.cube mol.numZMatrices
mol.addConformer mol.cubeById mol.radius

Thanks for your replies. I keep on digging.

Fabien

Dave

Here are all the available classes for the atom object (in python) :
for atom in mol.atoms:
print atom.
atom.class atom.init atom.sizeof
atom.forceVector atom.pos
atom.delattr atom.module atom.str
atom.formalCharge atom.residue
atom.dict atom.new atom.subclasshook
atom.id atom.residueId
atom.doc atom.reduce atom.weakref
atom.index atom.type
atom.format atom.reduce_ex atom.atomicNumber
atom.isHydrogen atom.update
atom.getattribute atom.repr atom.bond
atom.neighbors atom.valence
atom.hash atom.setattr atom.bonds
atom.partialCharge

The pos works but not the setPos.

My trial is on a water molecule (h2o.xyz):
$ python

import Avogadro as a
mol = a.MoleculeFile.readMolecule(‘h2o.xyz’)
for atom in mol.atoms:
… print atom.pos

[ 0.00369 2.73505 2.63908]
[-0.88715 2.29885 2.66616]
[-0.14964 3.67132 2.43027]

Perhaps this is somewhere else?

I also tried something I believed it should work but it did not move the
atoms:

mol.center
array([-0.34436667, 2.90174 , 2.57850333])
mol.translate(-mol.center)
mol.center
array([ 5.55111512e-17, -1.48029737e-16, 4.44089210e-16])
for atom in mol.atoms:
… print atom.pos

[ 0.34805667 -0.16669 0.06057667]
[-0.54278333 -0.60289 0.08765667]
[ 0.19472667 0.76958 -0.14823333]

The center seems to have moved but no atoms really moved…

If someone knows how to use python bindings in Avogadro and done some
tutorials it should be nice.

Fabien

Hi again,

I believe I moved forward but I am still not able to do what I want… I
have found that it exists addAtom and removeAtom so I thought it will be
possible to loop over all atoms then change the coordinates then put again
the atom…

import Avogadro as a
mol = a.MoleculeFile.readMolecule(‘h2o.xyz’)
for atom in mol.atoms:
… saveAtom = atom
… mol.removeAtom(atom.id)
… mol.addAtom(saveAtom, saveAtom.id)

Traceback (most recent call last):
File “”, line 4, in
Boost.Python.ArgumentError: Python argument types in
Molecule.addAtom(Molecule, Atom, int)
did not match C++ signature:
addAtom(Avogadro::Molecule {lvalue}, unsigned long)
addAtom(Avogadro::Molecule {lvalue})

I also tried, as it says that I need to specify the molecule:
mol.addAtom(mol,saveAtom, saveAtom.id)
But it is still incorrect… As I have very few knowledge of C++ it is hard
to understand what they need and how to transform it to python…

Fabien

On 05/19/2011 04:32 PM, Geoffrey Hutchison wrote:

On May 19, 2011, at 8:54 AM, Archambault Fabien wrote:

 None.None(Atom, numpy.ndarray)

did not match C++ signature:
None(Avogadro::Atom {lvalue}, Eigen::Matrix<double, 3, 1, 2, 3, 1>)
The problem seems to be that the conversion between numpy and the vector library Eigen isn’t working. I’m not sure if there’s a good solution to that directly.

OTOH, you can always use mol.OBMol to get an OBMol, use the Open Babel or Pybel libraries to change the coordinates, and then update the Avogadro molecule.

http://openbabel.org/docs/dev/UseTheLibrary/Python_PybelAPI.html
http://openbabel.org/docs/dev/UseTheLibrary/PythonExamples.html

I can’t say I’ve used the Avogadro python integration much, but I’ll see what I can do with the Eigen bindings.

Hope that helps,
-Geoff

Hi again,

thanks for the tip about the openbabel but I was not yet able to use it
correctly but I am now able to modify the position of the atoms as I
need so I believe I will be soon able to rotate as I need (just a matter
of matrices).

Here is the trick I was using array but in fact it is a ndarray from
numpy. So:

import Avogadro as a
import numpy as np
mol = a.MoleculeFile.readMolecule(‘h2o.xyz’)
zero = np.ndarray((3,), buffer=np.array([0.,0.,0.]), dtype=float)
for atom in mol.atoms:
… print atom.pos

[ 0.00369 2.73505 2.63908]
[-0.88715 2.29885 2.66616]
[-0.14964 3.67132 2.43027]
for atom in mol.atoms:
… atom.pos = zero

for atom in mol.atoms:
… print atom.pos

[ 0. 0. 0.]
[ 0. 0. 0.]
[ 0. 0. 0.]

This was not that hard! I should have thought at those ndarrays…

Thanks for the help again!

Fabien

On 19 May 2011 13:35, Archambault Fabien
fabien.archambault@nanotimes.fr wrote:

My trial is on a water molecule (h2o.xyz):
$ python

import Avogadro as a
mol = a.MoleculeFile.readMolecule(‘h2o.xyz’)
for atom in mol.atoms:
… print atom.pos

[ 0.00369 2.73505 2.63908]
[-0.88715 2.29885 2.66616]
[-0.14964 3.67132 2.43027]

Perhaps this is somewhere else?

I also tried something I believed it should work but it did not move the
atoms:

mol.center
array([-0.34436667, 2.90174 , 2.57850333])
mol.translate(-mol.center)
mol.center
array([ 5.55111512e-17, -1.48029737e-16, 4.44089210e-16])
for atom in mol.atoms:
… print atom.pos

[ 0.34805667 -0.16669 0.06057667]
[-0.54278333 -0.60289 0.08765667]
[ 0.19472667 0.76958 -0.14823333]

The center seems to have moved but no atoms really moved…

Actually - it did work, if you compare the figures above. All of the
atoms were translated by -mol.center. You need to have more faith in
yourself!

  • Noel