T0882 example in advanced MREMD, checking of residue names in pdb
[django_unres.git] / django_simple / todo / forms.py
1 from django import forms
2 from .models import Task
3 from .models import MIN_CHOICE
4 from .models import MD_START
5 from .models import MD_LANG
6 from .models import FF_CHOICE
7 import json
8 import urllib
9
10 aa_3letter = [
11      'DPR','DLY','DAR','DHI','DAS','DGL','DSG','DGN','DSN','DTH',
12      'DYY','DAL','DTY','DTR','DVA','DLE','DIL','DPN','MED','DCY',
13      'CYS','MET','PHE','ILE','LEU','VAL','TRP','TYR','ALA','GLY','THR',
14      'SER','GLN','ASN','GLU','ASP','HIS','ARG','LYS','PRO']
15
16
17 def pdb_code_chain(pdbid):
18
19     msg=''
20     chain=''
21     if len(pdbid)>4:
22        if pdbid[4]!=':':
23          return('use : between pdb code and chain id, like 5G3Q:B to select single chain')
24        chain=pdbid[5]
25        pdbid=pdbid[:4]    
26     
27     test=urllib.urlopen('http://files.rcsb.org/download/'+pdbid+'.pdb')     
28     if test.code != 200:
29           msg = 'wrong pdb code'
30     else:
31           msg=pdb_missing_res_chain(test,chain)
32     test.close()
33     return(msg)
34
35 def pdb_missing_res_chain(file,chain):
36    msg=''
37    newchain = True
38    ires=[]
39    for line in file:
40       if line[0:6] == 'ATOM  ' and line[13:15] == 'CA' and (line[21] == chain or chain==''):
41                i = int(line[22:26])
42                ch = line[21]
43                if line[17:20] not in aa_3letter:
44                  msg='residue '+line[17:20]+' '+str(i)+' not recognized'
45                  return(msg)
46                if ires and i==ires[-1]:
47                  continue
48                if newchain or i==ires[-1]+1:
49                  ires.append(i)
50                  newchain = False
51                else:
52                  msg = 'chain breaks between residues '+\
53                    str(ires[-1])+' and '+str(i)+' of chain '+ch+\
54                    ', server cannot add missing residues to PDB file - please repair the structure using e.g. Modeller'
55                  break
56       if line[0:3] == 'TER':
57                newchain = True
58       if line[0:3] == 'END':
59                break
60    
61    if len(ires) == 0:
62         if chain == '':
63                msg='no CA atoms in this pdb'
64         else:
65                msg='wrong chain id'
66    return(msg)
67
68
69 def code_2d(line):
70    msg=''
71    set ='HEC-'
72    line2 = ''.join([c for c in line if c in set])
73    if line2 != line:
74     msg='use only H,E,C or - letters'
75    return(msg)
76
77
78 class MultiWidgetBasic(forms.MultiWidget):
79     def __init__(self, count, attrs=None):
80         self.count=count
81         widgets = []
82         for i in range(self.count):
83            widgets.append(forms.TextInput())
84         super(MultiWidgetBasic, self).__init__(widgets, attrs)
85
86     template_name = 'multi.html'
87
88     def decompress(self, value):
89         if value:
90             return json.loads(value)
91         else:
92             return ['', '']
93
94
95 class MultiExampleField(forms.fields.MultiValueField):
96     def __init__(self, count, *args, **kwargs):
97         self.count=count
98         self.widget = MultiWidgetBasic(self.count)
99         list_fields = []
100         for i in range(self.count):
101            list_fields.append(forms.fields.CharField(max_length=15))
102         super(MultiExampleField, self).__init__(list_fields, *args, **kwargs)
103
104     def compress(self, values):
105         ## compress list to single object                                               
106         return json.dumps(values)
107
108
109 class TaskForm(forms.Form):
110     name = forms.CharField(max_length=20)
111
112
113 class TaskForm_min(forms.Form):
114      name = forms.CharField(max_length=20)
115      file1 = forms.FileField(label='Upload a PDB file',required=False,
116       help_text='continuous (without breaks) protein chains,use TER to divide chains')
117      pdbid = forms.CharField(min_length=4,max_length=6,required=False,
118       widget=forms.TextInput(attrs={'size':6, 'maxlength':6, 'title':'PDB code or PDB code:chain id'}),
119       label='or PDB code (:chain)')                   
120
121      def clean(self):
122              cleaned_data = super(TaskForm_min, self).clean()
123
124              pdbid = cleaned_data.get("pdbid") 
125              file1 = cleaned_data.get("file1")
126               
127              if not pdbid and not file1:
128                 msg = 'provide pdb file or pdb code'
129                 self.add_error('file1', msg)
130               
131              if pdbid:
132                msg=pdb_code_chain(pdbid)
133                if msg != '':
134                    self.add_error('pdbid',msg)
135                
136              if file1:
137                  msg=pdb_missing_res_chain(file1,'')
138                  if msg != '':
139                    self.add_error('file1',msg)
140
141             
142 class TaskForm_min_a(forms.Form):
143      name = forms.CharField(max_length=20)
144
145      unres_ff = forms.ChoiceField(choices=FF_CHOICE,widget=forms.RadioSelect,
146                            label='Force Field',initial='FF2')
147 #     min_choice = forms.ChoiceField(choices=MIN_CHOICE,label='minimization algorithm')
148      min_overlap = forms.BooleanField(required=False,label='remove overlap')
149      min_searchsc = forms.BooleanField(required=False,label='MC for sidechain overlap')
150      min_maxmin = forms.IntegerField(label='MAXMIN',initial=10000,
151                   help_text='maximum number of iterations')
152      min_maxfun = forms.IntegerField(label='MAXFUN',initial=15000,
153                   help_text='maximum number of function evaluations')
154      file1 = forms.FileField(label='Upload a PDB file',required=False,
155         help_text='continuous (without breaks) protein chains,use TER to divide chains')
156      pdbid = forms.CharField(min_length=4,max_length=6,required=False,
157       widget=forms.TextInput(attrs={'size':6, 'maxlength':6, 'title':'PDB code or PDB code:chain id'}),
158       label='or PDB code (:chain)')                   
159
160      min_unres_pdb = forms.BooleanField(required=False,label='uploaded input unres PDB',
161                   help_text='(CA and CB atoms only, CB represents SC in UNRES)')
162      min_pdbout = forms.BooleanField(required=False,label='output PDB',initial='true')
163      boxx = forms.FloatField(label='Box X',initial=1000.0,
164                        help_text='box x dimension')
165      boxy = forms.FloatField(label='Box Y',initial=1000.0,
166                        help_text='box y dimension')
167      boxz = forms.FloatField(label='Box Z',initial=1000.0,
168                        help_text='box z dimension')
169
170      def clean(self):
171              cleaned_data = super(TaskForm_min_a, self).clean()
172
173              pdbid = cleaned_data.get("pdbid") 
174              file1 = cleaned_data.get("file1")
175               
176              if not pdbid and not file1:
177                 msg = 'provide pdb file or pdb code'
178                 self.add_error('file1', msg)
179               
180              if pdbid:
181                  msg=pdb_code_chain(pdbid)
182                  if msg != '':
183                    self.add_error('pdbid',msg)
184                
185              if file1:
186                  msg=pdb_missing_res_chain(file1,'')
187                  if msg != '':
188                    self.add_error('file1',msg)
189
190
191 class TaskForm_md(forms.Form):
192      name = forms.CharField(max_length=20)
193
194      md_start = forms.ChoiceField(choices=MD_START,widget=forms.RadioSelect,
195                       label='starting structure',initial='extconf')
196      md_seq = forms.CharField(label='Sequence',
197                      help_text='aminoacid sequence using one letter code<br>'+
198                      'field is ignored when uploading starting/reference PDB file',
199                      required=False,
200                      widget=forms.Textarea(attrs={'cols': 70, 'rows': 2}))
201      file1 = forms.FileField(label='Upload a PDB file',required=False,
202                   help_text='starting structure for pdbstart/reference structure')
203      pdbid = forms.CharField(min_length=4,max_length=6,required=False,
204       widget=forms.TextInput(attrs={'size':6, 'maxlength':6, 'title':'PDB code or PDB code:chain id'}),
205       label='or PDB code (:chain)')                   
206      md_pdbref = forms.BooleanField(required=False,label='PDB reference structure')
207      md_temp = forms.FloatField(label='temperature',initial=300,
208                   help_text='bath temperature')
209      md_nstep = forms.IntegerField(label='NSTEP',initial=200000,
210                   help_text='total number of steps')
211      md_seed = forms.IntegerField(label='SEED',initial=-39912345,
212                   help_text='seed for random number generator')
213                   
214      def clean(self):
215              cleaned_data = super(TaskForm_md, self).clean()
216
217              md_start = cleaned_data.get("md_start") 
218              file1 = cleaned_data.get("file1")
219              pdbid = cleaned_data.get("pdbid")
220              md_seq = cleaned_data.get("md_seq")
221              md_pdbref = cleaned_data.get("md_pdbref")
222               
223              if md_start == 'pdbstart' and not (file1 or pdbid):
224                 msg = 'pdbstart with no PDB file or code'
225                 self.add_error('file1', msg)
226
227              if md_pdbref and not (file1 or pdbid):
228                 msg = 'pdbref with no PDB file or code'
229                 self.add_error('file1', msg)
230
231
232              if md_start != 'pdbstart' and not md_pdbref and not md_seq:
233                 msg = 'extended/random chain with no sequence'
234                 self.add_error('md_seq', msg)
235
236              if pdbid:
237                  msg=pdb_code_chain(pdbid)
238                  if msg != '':
239                    self.add_error('pdbid',msg)
240                
241              if file1:
242                  msg=pdb_missing_res_chain(file1,'')
243                  if msg != '':
244                    self.add_error('file1',msg)
245
246                         
247 class TaskForm_md_a(forms.Form):
248      name = forms.CharField(max_length=20)
249
250      unres_ff = forms.ChoiceField(choices=FF_CHOICE,widget=forms.RadioSelect,
251                            label='Force Field',initial='FF2')
252      md_start = forms.ChoiceField(choices=MD_START,widget=forms.RadioSelect,
253                       label='starting structure',initial='extconf')
254      md_seq = forms.CharField(label='Sequence',
255                      help_text='aminoacid sequence using one letter code<br>'+
256                      'field is ignored when uploading starting/reference PDB file',
257                      required=False,
258                      widget=forms.Textarea(attrs={'cols': 70, 'rows': 2}))
259      md_2d = forms.CharField(label='Secondary structure restraints',
260                      help_text='single letter code: H - helix, E - extended/beta, C or - no restraints',
261                      required=False,
262                      widget=forms.Textarea(attrs={'cols': 70, 'rows': 2}))
263
264      file1 = forms.FileField(label='Upload a PDB file',required=False,
265                   help_text='starting structure for pdbstart/reference structure')
266      pdbid = forms.CharField(min_length=4,max_length=6,required=False,
267       widget=forms.TextInput(attrs={'size':6, 'maxlength':6, 'title':'PDB code or PDB code:chain id'}),
268       label='or PDB code (:chain)')                   
269      md_pdbref = forms.BooleanField(required=False,label='PDB reference structure')                  
270      md_temp = forms.FloatField(label='temperature',initial=300,
271                   help_text='bath temperature')
272      md_nstep = forms.IntegerField(label='NSTEP',initial=200000,
273                   help_text='total number of steps')
274      md_seed = forms.IntegerField(label='SEED',initial=-39912345,
275                   help_text='seed for random number generator')
276
277      md_ntwe = forms.IntegerField(label='NTWE',initial=1000,
278                help_text='write statfile every ntwe steps')
279      md_ntwx = forms.IntegerField(label='NTWX',initial=1000,
280                help_text='write trajectory every ntwe steps')
281      md_dt = forms.FloatField(label='DT',initial=0.2,
282                   help_text='time step [mtu=48.9 fs]')
283      md_lang = forms.ChoiceField(choices=MD_LANG,label='thermostat')
284      md_tau = forms.FloatField(label='tau_bath',initial=1.0,
285                   help_text='coupling to the thermal bath (Berendsen)')
286      md_scal_fric = forms.FloatField(label='scal_froc',initial=0.02,
287                   help_text='scaling of the friction coefficients (Langevin)')
288      md_respa = forms.BooleanField(required=False,initial=True,label='RESPA')
289      md_mdpdb = forms.BooleanField(required=False,label='trajectory as PDB')
290
291      boxx = forms.FloatField(label='Box X',initial=1000.0,
292                        help_text='box x dimension')
293      boxy = forms.FloatField(label='Box Y',initial=1000.0,
294                        help_text='box y dimension')
295      boxz = forms.FloatField(label='Box Z',initial=1000.0,
296                        help_text='box z dimension')
297
298      def clean(self):
299              cleaned_data = super(TaskForm_md_a, self).clean()
300
301              md_start = cleaned_data.get("md_start") 
302              file1 = cleaned_data.get("file1")
303              pdbid = cleaned_data.get("pdbid")
304              md_seq = cleaned_data.get("md_seq")
305              md_pdbref = cleaned_data.get("md_pdbref")
306              md_2d = cleaned_data.get("md_2d")
307               
308              if md_start == 'pdbstart' and not (file1 or pdbid):
309                 msg = 'pdbstart with no PDB file or code'
310                 self.add_error('file1', msg)
311
312              if md_pdbref and not (file1 or pdbid):
313                 msg = 'pdbref with no PDB file or code'
314                 self.add_error('file1', msg)
315
316
317              if md_start != 'pdbstart' and not md_pdbref and not md_seq:
318                 msg = 'extended/random chain with no sequence'
319                 self.add_error('md_seq', msg)
320
321              if pdbid:
322                  msg=pdb_code_chain(pdbid)
323                  if msg != '':
324                    self.add_error('pdbid',msg)
325                
326              if file1:
327                  msg=pdb_missing_res_chain(file1,'')
328                  if msg != '':
329                    self.add_error('file1',msg)
330              
331              if md_2d:
332                  msg=code_2d(md_2d)
333                  if msg != '':
334                    self.add_error('md_2d',msg)
335
336 class TaskForm_remd(forms.Form):
337      name = forms.CharField(max_length=20)
338
339      md_start = forms.ChoiceField(choices=MD_START,widget=forms.RadioSelect,
340                       label='starting structure',initial='extconf')
341      md_seq = forms.CharField(label='Sequence',
342                      help_text='aminoacid sequence using one letter code<br>'+
343                         'field is ignored when uploading starting/reference PDB file',
344                      required=False,
345                      widget=forms.Textarea(attrs={'cols': 70, 'rows': 2}))
346      file1 = forms.FileField(label='Upload a PDB file',required=False,
347                   help_text='starting structure for pdbstart/reference structure')
348      pdbid = forms.CharField(min_length=4,max_length=6,required=False,
349       widget=forms.TextInput(attrs={'size':6, 'maxlength':6, 'title':'PDB code or PDB code:chain id'}),
350       label='or PDB code (:chain)')                   
351      md_pdbref = forms.BooleanField(required=False,label='PDB reference structure')                  
352      md_nstep = forms.IntegerField(label='NSTEP',initial=200000,
353                   help_text='total number of steps')
354      md_seed = forms.IntegerField(label='SEED',initial=-39912345,
355                   help_text='seed for random number generator')
356                   
357      def clean(self):
358              cleaned_data = super(TaskForm_remd, self).clean()
359
360              md_start = cleaned_data.get("md_start") 
361              file1 = cleaned_data.get("file1")
362              pdbid = cleaned_data.get("pdbid")
363              md_seq = cleaned_data.get("md_seq")
364              md_pdbref = cleaned_data.get("md_pdbref")
365               
366              if md_start == 'pdbstart' and not (file1 or pdbid):
367                 msg = 'pdbstart with no PDB file or code'
368                 self.add_error('file1', msg)
369
370              if md_pdbref and not (file1 or pdbid):
371                 msg = 'pdbref with no PDB file or code'
372                 self.add_error('file1', msg)
373
374              if md_start != 'pdbstart' and not md_pdbref and not md_seq:
375                 msg = 'extended/random chain with no sequence'
376                 self.add_error('md_seq', msg)
377
378              if pdbid:
379                  msg=pdb_code_chain(pdbid)
380                  if msg != '':
381                    self.add_error('pdbid',msg)
382                
383              if file1:
384                  msg=pdb_missing_res_chain(file1,'')
385                  if msg != '':
386                    self.add_error('file1',msg)
387
388                              
389 class TaskForm_remd_a(forms.Form):
390      name = forms.CharField(max_length=20)
391
392      unres_ff = forms.ChoiceField(choices=FF_CHOICE,widget=forms.RadioSelect,
393                            label='Force Field',initial='FF2')
394      md_start = forms.ChoiceField(choices=MD_START,widget=forms.RadioSelect,
395                       label='starting structure',initial='extconf')
396      md_seq = forms.CharField(label='Sequence',
397                      help_text='aminoacid sequence using one letter code<br>'+
398                       'field is ignored when uploading starting/reference PDB file',
399                      required=False,
400                      widget=forms.Textarea(attrs={'cols': 70, 'rows': 2}))
401      md_2d = forms.CharField(label='Secondary structure restraints',
402                      help_text='single letter code: H - helix, E - extended/beta, C or - no restraints',
403                      required=False,
404                      widget=forms.Textarea(attrs={'cols': 70, 'rows': 2}))
405      file1 = forms.FileField(label='Upload a PDB file',required=False,
406                   help_text='starting structure for pdbstart/reference structure')
407      pdbid = forms.CharField(min_length=4,max_length=6,required=False,
408       widget=forms.TextInput(attrs={'size':6, 'maxlength':6, 'title':'PDB code or PDB code:chain id'}),
409       label='or PDB code (:chain)')                   
410      md_pdbref = forms.BooleanField(required=False,label='PDB reference structure')                  
411      md_nstep = forms.IntegerField(label='NSTEP',initial=200000,
412                   help_text='total number of steps')
413      md_seed = forms.IntegerField(label='SEED',initial=-39912345,
414                   help_text='seed for random number generator')
415      md_ntwe = forms.IntegerField(label='NTWE',initial=1000,
416                help_text='write statfile every ntwe steps')
417      md_dt = forms.FloatField(label='DT',initial=0.2,
418                   help_text='time step [mtu = 48.9 fs]')
419      md_lang = forms.ChoiceField(choices=MD_LANG,label='thermostat')
420      md_tau = forms.FloatField(label='tau_bath',initial=1.0,
421                   help_text='coupling to the thermal bath (Berendsen)')
422      md_scal_fric = forms.FloatField(label='scal_froc',initial=0.02,
423                   help_text='scaling of the friction coefficients (Langevin)')
424      remd_nrep = forms.IntegerField(label='NREP',initial=8,
425                   help_text='number of replicas')
426      remd_nstex = forms.IntegerField(label='NSTEX',initial=1000,
427                   help_text='exchange and write trajectory every nstex steps')
428      md_ntwx = forms.IntegerField(label='NTWX',initial=1000,
429                help_text='write trajectory every ntwx steps')
430      remd_cluter_temp = forms.FloatField(label='TEMPER',
431                   help_text='temperature for cluster analysis',initial=280)                  
432 #     remd_traj1file = forms.BooleanField(required=False,label='single trajectory file',initial='true')
433 #     remd_rest1file = forms.BooleanField(required=False,label='single restart file',initial='true')
434
435      md_respa = forms.BooleanField(required=False,initial=True,label='RESPA')
436
437      boxx = forms.FloatField(label='Box X',initial=1000.0,
438                        help_text='box x dimension')
439      boxy = forms.FloatField(label='Box Y',initial=1000.0,
440                        help_text='box y dimension')
441      boxz = forms.FloatField(label='Box Z',initial=1000.0,
442                        help_text='box z dimension')
443
444
445      wsaxs = forms.FloatField(label='SAXS weight',initial=100.0,
446                             help_text='weight for SAXS restraint term')
447      scal_rad = forms.FloatField(label='Scal_rad (SAXS)',initial=1.0,
448                             help_text='downscaling factor of residue radii used in SAXS restraints')
449      saxs_data = forms.CharField(label='P(r) SAXS data',
450                      help_text='distance distribution from SAXS, two columns: r and P(r)',
451                      required=False,
452                      widget=forms.Textarea(attrs={'cols': 25, 'rows': 20}))
453
454
455      def clean(self):
456              cleaned_data = super(TaskForm_remd_a, self).clean()
457
458              md_start = cleaned_data.get("md_start") 
459              file1 = cleaned_data.get("file1")
460              pdbid = cleaned_data.get("pdbid")
461              md_seq = cleaned_data.get("md_seq")
462              md_pdbref = cleaned_data.get("md_pdbref")
463              md_2d = cleaned_data.get("md_2d")
464               
465              if md_start == 'pdbstart' and not (file1 or pdbid):
466                 msg = 'pdbstart with no PDB file or code'
467                 self.add_error('file1', msg)
468
469              if md_pdbref and not (file1 or pdbid):
470                 msg = 'pdbref with no PDB file or code'
471                 self.add_error('file1', msg)
472
473
474              if md_start != 'pdbstart' and not md_pdbref and not md_seq:
475                 msg = 'extended/random chain with no sequence'
476                 self.add_error('md_seq', msg)
477
478              if pdbid:
479                  msg=pdb_code_chain(pdbid)
480                  if msg != '':
481                    self.add_error('pdbid',msg)
482                
483              if file1:
484                  msg=pdb_missing_res_chain(file1,'')
485                  if msg != '':
486                    self.add_error('file1',msg)
487
488              if md_2d:
489                  msg=code_2d(md_2d)
490                  if msg != '':
491                    self.add_error('md_2d',msg)
492
493
494
495 class TaskForm_list(forms.Form):
496     name = forms.CharField(max_length=20,disabled=True,required=False)
497     nrep = forms.IntegerField(disabled=True,required=False,label='NREP')
498
499     def __init__(self, count, *args, **kwargs):
500         super(TaskForm_list, self).__init__(*args, **kwargs)
501         self.count=count
502         self.fields['temperatures'] = MultiExampleField(self.count)
503         self.fields['multiplexing'] = MultiExampleField(self.count)        
504      
505
506