donaldlab / OSPREY3

Open Source Protein REdesign for You v3
GNU General Public License v2.0
47 stars 15 forks source link

No library rotamers for a residue causes crash, even when WT added #130

Open gusennan opened 4 years ago

gusennan commented 4 years ago

The attached example crashes when the trying to use PTR in residue #6 on the ligand because there are no rotamers for PTR, even though we want to use the WT rotamer.

The field that is causing the NPE is ResidueConf.rotamerIndex.

PTR-no-rotamers-osprey-crash.tar.gz

Voxel reduced resid: 0.010657673967267902
Free DOF resid: 1.391044029191979E-28     
Voxel reduced resid: 0.001861377757440361
Free DOF resid: 1.2495928168047249E-28    
Voxel reduced resid: 2.0811815258843638E-4                                                                            
Free DOF resid: 1.3608867065860533E-28                
Voxel reduced resid: 3.454272927076653E-5                                                                             
### Started: edu.duke.cs.osprey.kstar.BBKStar$ConfSpaceInfo@779b4f9c                                                  
Calculating reference energies for 23 residue confs...                                                                
Progress:  100.0%   ETA: 69.0 ms                                                                                      
Finished in 871.2 ms                                                                                                  
read energy matrix from file: /home/nsg/tmp/script+structure/emat.protein.dat
read energy matrix from file: /home/nsg/tmp/script+structure/emat.protein.rigid.dat                                   
### Started: edu.duke.cs.osprey.kstar.BBKStar$ConfSpaceInfo@5cd71ee2                                                  
Calculating reference energies for 2 residue confs...                                                                 
edu.duke.cs.osprey.parallelism.TaskExecutor$TaskException: A task failed, no new tasks can be submitted     
edu.duke.cs.osprey.parallelism.TaskExecutor$TaskException: A task failed, no new tasks can be submitted               
        at edu.duke.cs.osprey.parallelism.ConcurrentTaskExecutor.recordException(ConcurrentTaskExecutor.java:106)     
        at edu.duke.cs.osprey.parallelism.ConcurrentTaskExecutor.taskFailure(ConcurrentTaskExecutor.java:87)
        at edu.duke.cs.osprey.parallelism.ThreadPoolTaskExecutor.lambda$submit$1(ThreadPoolTaskExecutor.java:109)
Listening for transport dt_socket at address: 12999       
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630)
        at java.base/java.lang.Thread.run(Thread.java:832)                                                            
Caused by: java.lang.NullPointerException                                                                             
        at edu.duke.cs.osprey.confspace.SimpleConfSpace.makeMolecule(SimpleConfSpace.java:756)                        
        at edu.duke.cs.osprey.energy.ConfEnergyCalculator.calcEnergy(ConfEnergyCalculator.java:276)
        at edu.duke.cs.osprey.energy.ConfEnergyCalculator.calcIntraEnergy(ConfEnergyCalculator.java:233)
        at edu.duke.cs.osprey.ematrix.SimplerEnergyMatrixCalculator.lambda$calcReferenceEnergies$6(SimplerEnergyMatrixCalculator.java:520)
        at edu.duke.cs.osprey.parallelism.TaskExecutor.runTask(TaskExecutor.java:168)
        at edu.duke.cs.osprey.parallelism.ThreadPoolTaskExecutor.lambda$submit$1(ThreadPoolTaskExecutor.java:101)
        ... 3 more    
cuchaz commented 4 years ago

Interesting... I don't think anyone has tried to configure continuous flexibility without also having discrete flexibility before.

Assuming the custom template you made has exactly one "rotamer" in it, an addition to ResidueTemplate like this might solve the issue:

public double getRotamericDihedrals(Integer rotNum, int dihedralNum) {

    if (rotNum != null) {
        return getRotamericDihedrals(rotNum, dihedralNum);
    }

    // conformation has no rotamer number,
    // so hope the template has exactly one rotamer and try to match that
    var dihedralsByRotamer = rotamericDihedrals[0][0];
    if (dihedralsByRotamer.length == 1) {
        return dihedralsByRotamer[0][dihedralNum];
    }

    // don't know how to find the angle for this dihedral
    throw new IllegalStateException(String.format("don't know how to find angle for dihedral"
        + "\nrotNum = %s, dihedralNum = %d, template = %s, rotamers = %d",
        rotNum, dihedralNum, name, dihedralsByRotamer.length
    ));
}
gusennan commented 4 years ago

Does this analysis change if there isn't continuous flexibility? Here's the spec of the ligand which caused the problem:

# define the ligand strand
ligand = osprey.Strand(mol, templateLib=templateLib, residues=['1', '12'])
# ligand.flexibility['6'].setLibraryRotamers('TYR').addWildTypeRotamers()
ligand.flexibility['6'].setLibraryRotamers(osprey.WILD_TYPE).addWildTypeRotamers()#.setContinuous()

ligandStrandAndFlex = [ligand]
ligandConfSpace = osprey.ConfSpace([ligandStrandAndFlex])

Wild-type here is PTR, the residue that there are 0 rotamers for, except the one that is in the structure.

cuchaz commented 4 years ago

If there's no flexibility of any kind at that design position, then probably that design position can just be deleted?

gusennan commented 4 years ago

That's true. I think part of the issue is that the user didn't know there were no rotamers there and osprey crashed on a NPE instead. With the task-based parallelism it's a bit challenging to get at the underlying exception from python world, but that wouldn't necessarily have helped anyway without a message saying what's wrong.

With continuous flexibility the design appears to work as-is.

cuchaz commented 4 years ago

Ah, ok. If that's the case, then we just need a friendlier error message so the user can understand how to fix the problem.

gusennan commented 4 years ago

I think that, and a general method for percolating up the Java exceptions to the user, would do the trick. These more detailed stack exceptions, such as that one shown above, are only available because whatever's throwing the exception is wrapped in a try: ... except: ... with the ex.printStackTrace() explicitly called, e.g:

import jpype
import jpype.imports
from jpype.types import *
import java.lang

# run BBK*
try:
    scoredSequences = bbkstar.run(minimizingEcalc.tasks)
except java.lang.Exception as ex:
    print(ex)
    ex.printStackTrace()