[ase-users] Questions regarding the calculate() method

Ask Hjorth Larsen asklarsen at gmail.com
Tue Jan 16 18:51:14 CET 2018


Dear Ivan,

2018-01-16 18:34 GMT+01:00 Kondov, Ivan (SCC) <ivan.kondov at kit.edu>:
> Dear Ask,
>
> thanks a lot for your response. Yes I will try out the approach with the
> optimizer-like objects and as you suggest I will use the GULP calculator as a
> blueprint. I have in mind, I am going to adapt the NWChem and Turbomole
> calculators in this direction.

That sounds very nice.  We should also establish a general class for
these calculator-specific optimizers (else we implement the same thing
many times).  Don't hesitate to poke me when you have something and we
can think about it.

>
> However, the one issue (number 2, see below) is still there even without
> structure optimization. This code will return the 'AttributeError: 'NoneType'
> object has no attribute' (but actually it should work):
>
> from ase.build import molecule
> from ase.calculators.nwchem import NWChem
> atoms = molecule('NH3')
> calc = NWChem(atoms=atoms, xc='pbe0')
> calc.calculate()
>
> This is because the calculate() method of the base class uses uninitialized
> self.atoms. Following the inheritance chain I think the problem is in the
> __init__ of class Calculator which ignores the supplied atoms object. There
> should be one of these three:
>
> self.set_atoms(atoms) # the derived class decides
> self.atoms = atoms # in-place policy
> self.atoms = atoms.copy() # copy policy
>
> To implement this correctly I would like to understand the basic policy for
> self.atoms. Vasp and Turbomole have copy policy in their set_atoms() methods,
> and NWChem has no set_atoms() method.
>
> I hope now I could make the issue more clear.

Yes... I would actually prefer to clean the ASE calculator interface
so it either always gets the atoms reference, or doesn't have it at
all.

I'd recommend triggering a calculation with get_potential_energy()
rather than calculate() directly.

Best regards
Ask

>
> Best regards,
> Ivan
>
>> -----Original Message-----
>> From: Ask Hjorth Larsen [mailto:asklarsen at gmail.com]
>> Sent: Tuesday, January 16, 2018 3:52 PM
>> To: Kondov, Ivan (SCC)
>> Cc: ase-users at listserv.fysik.dtu.dk
>> Subject: Re: [ase-users] Questions regarding the calculate() method
>>
>> Dear Ivan,
>>
>> 2018-01-16 15:13 GMT+01:00 Kondov, Ivan (SCC) via ase-users
>> <ase-users at listserv.fysik.dtu.dk>:
>> > Dear all,
>> >
>> > I want to do a geometry optimization and get back the optimized
>> > structure, the energy and the forces. Here is an example:
>> >
>> > from ase.build import molecule
>> > from ase.calculators.nwchem import NWChem atoms = molecule('NH3') calc
>> > = NWChem(task='optimize', xc='pbe0')
>> > atoms.set_calculator(calc)
>> > print(atoms.get_positions())
>> > calc.calculate(atoms)
>> > print(print(atoms.get_potential_energy()))
>> > print(atoms.get_positions())
>> > print(atoms.get_forces())
>> >
>> > [[ 0.        0.        0.116489]
>> >  [ 0.        0.939731 -0.271808]
>> >  [ 0.813831 -0.469865 -0.271808]
>> >  [-0.813831 -0.469865 -0.271808]]
>> > -1528.1988692333646
>> > [[ 0.        0.        0.116489]
>> >  [ 0.        0.939731 -0.271808]
>> >  [ 0.813831 -0.469865 -0.271808]
>> >  [-0.813831 -0.469865 -0.271808]]
>> > [[ -1.02844134e-04   1.54266201e-04  -2.41683715e-03]
>> >  [  5.14220671e-05   1.54266201e-04   8.22753073e-04]
>> >  [  3.08532403e-04  -1.54266201e-04   7.71331006e-04]
>> >  [ -2.05688268e-04  -1.54266201e-04   8.22753073e-04]]
>> >
>> > The energy and the forces are correct but not the structure (it should
>> > be updated).
>> >
>> > 1) The reason for this behavior is that Calculator.calculate()  works
>> > on a copy of the atoms object if it has been supplied as argument:
>> >
>> > if atoms is not None:
>> >     self.atoms = atoms.copy()
>> >
>> > Is this the wished behavior? Because the only way to get to the
>> > updated atoms object is then using this detour:
>> > calc.atoms.get_positions() in the user function.
>> >
>> > 2) Then the solution would be to simply not specify the atoms in the call:
>> >
>> > calc.calculate()
>> >
>> > Then it will work on the atoms object associated with the
>> > set_calculator() method. Unfortunately, then I get the error:
>> >
>> >     calc.calculate()
>> >   File " /ase/calculators/calculator.py", line 644, in calculate
>> >     self.write_input(self.atoms, properties, system_changes)
>> >   File " /ase/calculators/nwchem.py", line 75, in write_input
>> >     p.initial_magmoms = atoms.get_initial_magnetic_moments().tolist()
>> > AttributeError: 'NoneType' object has no attribute
>> > 'get_initial_magnetic_moments'
>> >
>> > The reason is that write_input() is called with self.atoms that is None.
>> > Obviously the calculator does not have atoms object although
>> > atoms.set_calculator(calc) was called. This is because NWChem class
>> > has no
>> > set_atoms() method. Should we write this one?
>> >
>> > I tend to first fix the issue number (2). What about the first issue?
>> >
>>
>> The main problem is that calculators are not meant to act as optimizers.
>>
>> We discussed this for the GULP optimizer, see ase.calculators.gulp, which
>> solves
>> the problem by returning an object that resembles an ASE optimizer.  Thus it
>> should also work with other ASE machinery like NEB, BasinHopping, etc.
>> (Whether they *actually* work in this moment is a different question, but
>> using
>> an explicit optimizer-like object means that any problem to be solved.)
>>
>> Upon reviewing the code in the GULP calculator, I think it would be more
>> elegant to decorate the get_optimizer method with @classmethod.
>> Since this is not implemented by very many calculators anyway, we can
>> streamline it as necessary later.
>>
>> If it is a classmethod, we can do:
>>
>> atoms = ...
>> # The 'opti' keyword makes it run a relaxation:
>> opt = GULP.get_optimizer(atoms, keywords='opti conp', ....) # Now the
>> objects
>> are all created and linked: opt ->atoms -> calc
>> opt.run(fmax=0.05)
>> calc = atoms.get_calculator()
>> E = calc.get_potential_energy()
>>
>> Presently we do
>>
>> atoms = ...
>> # The 'opti' keyword makes it run a relaxation:
>> calc = GULP(keywords='opti conp', ....)
>> opt = calc.get_optimizer(atoms)
>> # Now the objects are all created and linked: opt ->atoms -> calc
>> opt.run(fmax=0.05)
>> calc = atoms.get_calculator()
>> E = calc.get_potential_energy()
>>
>> The gulp_opt.py test tests this, but obviously requires GULP.
>>
>> Best regards
>> Ask
>>
>>
>> > I will appreciate your feedback very much.
>> >
>> > Best regards,
>> > Ivan
>> >
>> >
>> > _______________________________________________
>> > ase-users mailing list
>> > ase-users at listserv.fysik.dtu.dk
>> > https://listserv.fysik.dtu.dk/mailman/listinfo/ase-users


More information about the ase-users mailing list