BINANAParams.ts 23.3 KB
Newer Older
jdurrant's avatar
jdurrant committed
1
2
3
4
5
6
7
// This file is part of BINANA, released under the Apache 2.0 License. See
// LICENSE.md or go to https://opensource.org/licenses/Apache-2.0 for full
// details. Copyright 2020 Jacob D. Durrant.


import * as Utils from "../../Utils";
import * as BINANAInterface from "../../BINANAInterface";
jdurrant's avatar
jdurrant committed
8
9
10
11
import * as JSZip from "../../../node_modules/jszip/lib/index";
import * as Store from "../../Vue/Store";

var FileSaver = require('file-saver');
jdurrant's avatar
jdurrant committed
12
13
14
15
16
17
18
19
20
21

declare var Vue;

/** An object containing the vue-component computed functions. */
let computedFunctions = {
    /**
     * Gets text describing the current interaction coloring scheme.
     * @returns string  The text.
     */
    "colorByInteractionBtnTxt"(): string {
jdurrant's avatar
jdurrant committed
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
        switch (this.$store.state["colorByInteraction"]) {
            case Store.InteractionColoring.MOLECULE:
                return "By Molecule";
            case Store.InteractionColoring.INTERACTION:
                return "By Interaction";
            case Store.InteractionColoring.NONE:
                return "None";
        }
    },

    /**
     * Gets the text too use on the bond-visible buttton.
     * @returns string  The text to use.
     */
    "bondVisBtnTxt"(): string {
        if (this.$store.state["bondVisible"]) {
            return "Interactions";
jdurrant's avatar
jdurrant committed
39
        } else {
jdurrant's avatar
jdurrant committed
40
            return "<span style='text-decoration: line-through;'>Interactions</span>";
jdurrant's avatar
jdurrant committed
41
        }
jdurrant's avatar
jdurrant committed
42
    },
jdurrant's avatar
jdurrant committed
43
44
45
46
47
}

/** An object containing the vue-component methods functions. */
let methodsFunctions = {
    /**
jdurrant's avatar
jdurrant committed
48
     * Runs when user indicates theye want to use example BINANA files,
jdurrant's avatar
jdurrant committed
49
50
51
     * rather than provide their own.
     * @returns void
     */
jdurrant's avatar
jdurrant committed
52
    "useExampleInputFiles"(): void {
jdurrant's avatar
jdurrant committed
53
54
55
56
57
58
59
60
61
62
63
64
65
        this["showFileInputs"] = false;

        setTimeout(() => {  // Vue.nextTick doesn't work...
            // Update some values.
            this.$store.commit("setVar", {
                name: "receptorContents",
                val: this.$store.state["receptorContentsExample"]
            });

            this.$store.commit("setVar", {
                name: "ligandContents",
                val: this.$store.state["ligandContentsExample"]
            });
jdurrant's avatar
jdurrant committed
66

jdurrant's avatar
jdurrant committed
67
68
69
            // Also update file names so example BINANA command line is valid.
            this.$store.commit("updateFileName", { type: "ligand", filename: "ATP.pdbqt" });
            this.$store.commit("updateFileName", { type: "receptor", filename: "1xdn.pdbqt" });
jdurrant's avatar
jdurrant committed
70
71

            // These values should now validate.
jdurrant's avatar
jdurrant committed
72
            let validateVars = ["receptor", "ligand"];
jdurrant's avatar
jdurrant committed
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
            const validateVarsLen = validateVars.length;
            for (let i = 0; i < validateVarsLen; i++) {
                const validateVar = validateVars[i];
                this.$store.commit("setValidationParam", {
                    name: validateVar,
                    val: true
                });
            }
        }, 100);
    },

    /**
     * Highlights interactions in the 3Dmoljs viewer.
     * @param  {string} interactionName  The name of the interaction type to
     *                                   highlight.
     * @returns void
     */
    "highlight"(interactionName: string): void {
        if (interactionName === undefined) {
            interactionName = this.lastInteractionNameUsed;
        } else {
            this.lastInteractionNameUsed = interactionName;
        }

        if (interactionName !== undefined) {
            BINANAInterface.highlight(interactionName);
        }
    },

    /**
     * Clears the interactions currently displayed in the 3Dmoljs viewer.
     * @returns void
     */
    "clearInteraction"(): void {
        BINANAInterface.clearInteraction();
    },

    /**
     * Fires when the user indicates s/he would like to change the color
     * scheme.
     * @returns void
     */
    "onChangeColor"(): void {
jdurrant's avatar
jdurrant committed
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
        let newVal = undefined;
        switch (this.$store.state["colorByInteraction"]) {
            case Store.InteractionColoring.MOLECULE:
                newVal = Store.InteractionColoring.INTERACTION;
                break;
            case Store.InteractionColoring.INTERACTION:
                newVal = Store.InteractionColoring.NONE;

                // If none, make sure bonds are visible.
                this.$store.commit("setVar", {
                    name: "bondVisible",
                    val: true
                });

                break;
            case Store.InteractionColoring.NONE:
                newVal = Store.InteractionColoring.MOLECULE;
                break;
        }

jdurrant's avatar
jdurrant committed
136
137
        this.$store.commit("setVar", {
            name: "colorByInteraction",
jdurrant's avatar
jdurrant committed
138
            val: newVal
jdurrant's avatar
jdurrant committed
139
140
141
142
143
144
        });

        this["highlight"]();
    },

    /**
jdurrant's avatar
jdurrant committed
145
     * Runs when the bond-visibility button is pressed.
jdurrant's avatar
jdurrant committed
146
147
     * @returns void
     */
jdurrant's avatar
jdurrant committed
148
149
150
151
152
    "onBondVisChange"(): void {
        this.$store.commit("setVar", {
            name: "bondVisible",
            val: !this.$store.state["bondVisible"]
        });
jdurrant's avatar
jdurrant committed
153

jdurrant's avatar
jdurrant committed
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
        this["highlight"]();
    },

    /**
     * Runs when the save button is pressed.
     * @returns void
     */
    "onSaveFiles"(): void {
        var zip = new JSZip();
        zip["folder"]("binana_output")["file"]
            ("receptor.txt",
            this.$store.state["receptorContents"]
        )["file"](
            "ligand.txt",
            this.$store.state["ligandContents"]
        )["file"](
            "binana.json",
            this.$store.state["jsonOutput"]
        );
        zip["generateAsync"]({["type"]:"blob"}).then(
            function (blob) {
                FileSaver["saveAs"](blob, "binana_output.zip");
            }
        );
    },
jdurrant's avatar
jdurrant committed
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218

    /**
     * Determines whether all form values are valid.
     * @param  {boolean=true} modalWarning  Whether to show a modal if
     *                                      they are not valid.
     * @returns boolean  True if they are valid, false otherwise.
     */
    "validate"(modalWarning: boolean=true): boolean {
        let validations = this.$store.state["validation"];

        let pass = true;

        const paramName = Object.keys(validations);
        const paramNameLen = paramName.length;
        let badParams: string[] = [];
        for (let i = 0; i < paramNameLen; i++) {
            const name = paramName[i];

            if (name === "output") {
                // This one isn't part of the validation.
                continue;
            }

            const valid = validations[name];
            if (valid === false) {
                pass = false;
                badParams.push(name);
            }
        }

        if (pass === false) {
            if (modalWarning === true) {
                this.$store.commit("openModal", {
                    title: "Invalid Parameters!",
                    body: "<p>Please correct the following parameter(s) before continuing: <code>" + badParams.join(" ") + "</code></p>"
                });
            }
        }

        this.$store.commit("setVar", {
jdurrant's avatar
jdurrant committed
219
            name: "binanaParamsValidates",
jdurrant's avatar
jdurrant committed
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
            val: pass
        })

        return pass;
    },
}

/**
 * The vue-component mounted function.
 * @returns void
 */
function mountedFunction(): void {
    this["webAssemblyAvaialble"] = Utils.webAssemblySupported();
}

/**
jdurrant's avatar
jdurrant committed
236
 * Setup the binana-params Vue commponent.
jdurrant's avatar
jdurrant committed
237
238
239
 * @returns void
 */
export function setup(): void {
jdurrant's avatar
jdurrant committed
240
    Vue.component('binana-params', {
jdurrant's avatar
jdurrant committed
241
242
        "template": `
            <div>
jdurrant's avatar
jdurrant committed
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
                <!-- <b-card
                    class="mb-2 text-center"
                    style="margin-bottom:1.4rem !important;"
                >
                    <b-card-text>
                        Use this tab to setup a analysis in your browser.
                        Specify the input files and BINANA parameters below.
                    </b-card-text>
                </b-card> -->

                <sub-section
                    v-if="$store.state.receptorContents === '' || $store.state.ligandContents === ''"
                >
                    <div role="tablist">
                        <b-card no-body class="mb-1">
                            <b-card-header header-tag="header" class="p-1" role="tab">
                                <b-button block href="#" v-b-toggle.accordion-3 variant="default">Advanced Parameters</b-button>
                            </b-card-header>
                            <b-collapse id="accordion-3" role="tabpanel">
                                <b-card-body>
                                    <b-card class="mb-2 text-center" style="margin-bottom:1.4rem !important;">
                                        <b-card-text>Parameters used to identify close contacts.</b-card-text>
                                        <numeric-input
jdurrant's avatar
jdurrant committed
266
                                            label="Closest Contacts Dist1 Cutoff"
jdurrant's avatar
jdurrant committed
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
                                            id="close_contacts_dist1_cutoff"
                                            description="Ligand/protein atoms that come within this number of
                                            angstroms are &quot;closest contacts.&quot;" placeholder="$store.state.close_contacts_dist1_cutoff"
                                        ></numeric-input>
                                        <numeric-input
                                            label="Close Contacts Dist2 Cutoff"
                                            id="close_contacts_dist2_cutoff"
                                            description="Ligand/protein atoms that come within this number of
                                            angstroms are &quot;close contacts.&quot;" placeholder="$store.state.close_contacts_dist2_cutoff"
                                        ></numeric-input>
                                    </b-card>
                                    <!-- <numeric-input
                                        label="Electrostatic Dist Cutoff"
                                        id="electrostatic_dist_cutoff"
                                        description="<b>???</b>" placeholder="$store.state.electrostatic_dist_cutoff"
                                    ></numeric-input> -->
                                    <!-- <numeric-input
                                        label="Active Site Flexibility Dist Cutoff"
                                        id="active_site_flexibility_dist_cutoff"
                                        description="<b>???</b>" placeholder="$store.state.active_site_flexibility_dist_cutoff"
                                    ></numeric-input> -->

                                    <b-card class="mb-2 text-center" style="margin-bottom:1.4rem !important;">
                                        <b-card-text>Parameters used to identify hydrogen bonds.</b-card-text>
                                        <numeric-input
                                            label="Hydrogen Bond Dist Cutoff"
                                            id="hydrogen_bond_dist_cutoff"
                                            description="A hydrogen bond is identified if the hydrogen-bond
                                            donor comes within this number of angstroms of the hydrogen-bond
                                            acceptor." placeholder="$store.state.hydrogen_bond_dist_cutoff"
                                        ></numeric-input>
                                        <numeric-input
                                            label="Hydrogen Bond Angle Cutoff"
                                            id="hydrogen_bond_angle_cutoff"
                                            description="A hydrogen bond is identified if the angle formed
                                            between the donor, the hydrogen atom, and the acceptor is no
                                            greater than this number of degrees." placeholder="$store.state.hydrogen_bond_angle_cutoff"
                                        ></numeric-input>
                                    </b-card>

                                    <b-card class="mb-2 text-center" style="margin-bottom:1.4rem !important;">
                                        <b-card-text>
                                            <div style='text-align:left;'>
                                                Parameters used to identify interactions between
                                                atomatic rings. Once an aromatic ring is identified, a plane is
                                                defined that passes through three ring atoms. The center of
                                                the ring is the average of all ring-atom coordinates,
                                                and the radius is the maximum distance between the center and
                                                any of those atoms. A ring disk is centered on the ring center
                                                point, oriented along the ring plane.
                                            </div>
                                        </b-card-text>

                                        <numeric-input
                                            label="π Padding Dist"
                                            id="pi_padding_dist"
                                            description="The radius of the ring disk is equal to that of the
                                            ring plus a small buffer (this number of angstroms)." placeholder="$store.state.pi_padding_dist"
                                        ></numeric-input>
                                        <numeric-input
                                            label="π-π Interacting Dist Cutoff"
                                            id="pi_pi_interacting_dist_cutoff"
                                            description="A π-π or T-stacking interaction is identified
                                            if the centers of two aromatic rings are within this number of
                                            angstroms." placeholder="$store.state.pi_pi_interacting_dist_cutoff"
                                        ></numeric-input>
                                        <numeric-input
                                            label="π-Stacking Angle Tolerance"
                                            id="pi_stacking_angle_tolerance"
                                            description="A π-π stacking interaction is identified if the
                                            angle between the normal vectors of two aromatic rings is less
                                            than this number of degrees." placeholder="$store.state.pi_stacking_angle_tolerance"
                                        ></numeric-input>
                                        <numeric-input
                                            label="T-Stacking Angle Tolerance"
                                            id="T_stacking_angle_tolerance"
                                            description="A T-stacking interaction is identified if the
                                            angle between the normal vectors of two aromatic rings is within
                                            this number of degrees of being perpendicular." placeholder="$store.state.T_stacking_angle_tolerance"
                                        ></numeric-input>
                                        <numeric-input
                                            label="T-Stacking Closest Dist Cutoff"
                                            id="T_stacking_closest_dist_cutoff"
                                            description="A T-stacking interaction is identified if two aromatic
                                            rings are within this number of angstroms at their nearest point (see
                                            also -pi_pi_interacting_dist_cutoff parameter above)." placeholder="$store.state.T_stacking_closest_dist_cutoff"
                                        ></numeric-input>
                                        <numeric-input
                                            label="Cation-π Dist Cutoff"
                                            id="cation_pi_dist_cutoff"
                                            description="A Cation-π interaction is identified if a charged functional
                                            group comes within this distance of an aromaic-ring center." placeholder="$store.state.cation_pi_dist_cutoff"
                                        ></numeric-input>
                                    </b-card>

                                    <b-card class="mb-2 text-center" style="margin-bottom:1.4rem !important;">
                                        <b-card-text>Parameters used to identify other notable interactions.</b-card-text>
                                        <numeric-input
                                            label="Salt Bridge Dist Cutoff"
                                            id="salt_bridge_dist_cutoff"
                                            description="Charged functional groups that come within this
                                            number of angstroms participate in &quot;electrostatic
                                            interactions.&quot;" placeholder="$store.state.salt_bridge_dist_cutoff"
                                        ></numeric-input>
                                        <numeric-input
                                            label="Hydrophobic Dist Cutoff"
                                            id="hydrophobic_dist_cutoff"
                                            description="Ligand/receptor carbon atoms that come within this
                                            number of angstroms participate in &quot;hydrophobic
                                            contacts.&quot;" placeholder="$store.state.hydrophobic_dist_cutoff"
                                        ></numeric-input>
                                    </b-card>
                                </b-card-body>
                            </b-collapse>
                        </b-card>
                    </div>
                </sub-section>

                <sub-section title="Input Files" v-if="showFileInputs">
                    <file-input
                        label="Receptor"
                        id="receptor"

                        description="Formats: PDB, PDBQT. Be sure to add polar hydrogen atoms if necessary."
                        accept=".pdb, .pdbqt"
jdurrant's avatar
jdurrant committed
392
                    >
jdurrant's avatar
jdurrant committed
393
394
395
396
397
398
399
400
                        <template v-slot:extraDescription></template>
                    </file-input>

                    <file-input
                        label="Ligand"
                        id="ligand"
                        description="Formats: PDB, PDBQT, SDF. Be sure to add polar hydrogen atoms if necessary."
                        accept=".pdb, .pdbqt, .sdf"
jdurrant's avatar
jdurrant committed
401
                    >
jdurrant's avatar
jdurrant committed
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
                    </file-input>

                    <form-button @click.native="useExampleInputFiles" cls="float-right">Use Example Files</form-button>  <!-- variant="default" -->
                </sub-section>

                <sub-section title="Molecular Viewer">
                    <form-group
                        label=""
                        id="input-group-receptor-3dmol"
                        description=""
                    >
                        <div class="bv-example-row container-fluid">
                            <b-row>
                                <b-col style="padding-left: 0; padding-right: 0;">
                                    <threedmol type="receptor"></threedmol>
jdurrant's avatar
jdurrant committed
417
418
                                </b-col>
                            </b-row>
jdurrant's avatar
jdurrant committed
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
                        </div>
                    </form-group>

                    <b-container
                        v-if="$store.state.receptorContents != '' && $store.state.ligandContents != ''"
                    >
                        <b-row no-gutters>
                            <b-col no-gutters>
                                <b-dropdown variant="primary" text="Common" block>
                                    <b-dropdown-item @click="highlight('hydrogenBonds');">Hydrogen Bonds</b-dropdown-item>
                                    <b-dropdown-item @click="highlight('hydrophobicContacts');">Hydrophobic</b-dropdown-item>
                                    <b-dropdown-item @click="highlight('saltBridges');">Salt Bridge</b-dropdown-item>
                                </b-dropdown>
                            </b-col>
                            <b-col no-gutters>
                                <b-dropdown variant="primary" text="Contacts" block>
                                    <b-dropdown-item @click="highlight('contactsWithin2.5A');">Close</b-dropdown-item>
                                    <b-dropdown-item @click="highlight('contactsWithin4.0A');">Closest</b-dropdown-item>
                                </b-dropdown>
                            </b-col>
                            <b-col no-gutters>
                                <b-dropdown variant="primary" text="Aromatic" block>
                                    <b-dropdown-item @click="highlight('piPiStackingInteractions');">π-π Stacking</b-dropdown-item>
                                    <b-dropdown-item @click="highlight('tStackingInteractions');">T Stacking</b-dropdown-item>
                                    <b-dropdown-item @click="highlight('cationPiInteractions');">Cation-π</b-dropdown-item>
                                </b-dropdown>
                            </b-col>
                            <b-col no-gutters>
                                <b-button variant="primary" @click="clearInteraction();" block>Clear</b-button>
                            </b-col>
                        </b-row>
                        <b-row no-gutters>
                            <b-col no-gutters @click="highlight();">
                                <b-button @click="onChangeColor();" block>
                                    {{colorByInteractionBtnTxt}}
                                </b-button>
                            </b-col>
                            <b-col no-gutters>
                                <b-button @click="onBondVisChange();" block v-html="bondVisBtnTxt">
                                </b-button>
                            </b-col>
                            <b-col no-gutters>
                                <b-button @click="onSaveFiles();" block>
                                    Save
                                </b-button>
                            </b-col>
                        </b-row>
                        <b-row v-if="this.$store.state.colorMessage !== ''" no-gutters>
                            <b-col no-gutters>
                                <p style="text-align:center;">({{this.$store.state.colorMessage}})</p>
                            </b-col>
                        </b-row>
                    </b-container>
                </sub-section>

                <span style="display:none;">{{validate(false)}}</span>  <!-- Hackish. Just to make reactive. -->
            </b-form>
jdurrant's avatar
jdurrant committed
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
        `,
        "props": {},
        "computed": computedFunctions,

        /**
         * Get the data associated with this component.
         * @returns any  The data.
         */
        "data"() {
            return {
                "showFileInputs": true,
                "webAssemblyAvaialble": true,
                lastInteractionNameUsed: undefined
            }
        },
        "methods": methodsFunctions,

        /**
         * Runs when the vue component is mounted.
         * @returns void
         */
        "mounted": mountedFunction
    })
}