icn3d 3.54.6 → 3.54.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/icn3d.js +480 -297
  2. package/icn3d.min.js +12 -6
  3. package/icn3d.module.js +480 -297
  4. package/package.json +1 -1
package/icn3d.module.js CHANGED
@@ -172,7 +172,8 @@ $NGL_shaderTextHash['SphereImpostor.frag'] = ["#define STANDARD",
172
172
  " float depth = gl_FragCoord.z / gl_FragCoord.w;",
173
173
  " #endif",
174
174
  " #ifdef FOG_EXP2",
175
- " float fogFactor = whiteCompliment( exp2( - fogDensity * fogDensity * depth * depth * LOG2 ) );",
175
+ " //float fogFactor = whiteCompliment( exp2( - fogDensity * fogDensity * depth * depth * LOG2 ) );",
176
+ " float fogFactor = ( 1.0 - exp2( - fogDensity * fogDensity * depth * depth * 1.442695 ) );",
176
177
  " #else",
177
178
  " float fogFactor = smoothstep( fogNear, fogFar, depth );",
178
179
  " #endif",
@@ -636,7 +637,8 @@ $NGL_shaderTextHash['CylinderImpostor.frag'] = ["#define STANDARD",
636
637
  " float depth = gl_FragCoord.z / gl_FragCoord.w;",
637
638
  " #endif",
638
639
  " #ifdef FOG_EXP2",
639
- " float fogFactor = whiteCompliment( exp2( - fogDensity * fogDensity * depth * depth * LOG2 ) );",
640
+ " //float fogFactor = whiteCompliment( exp2( - fogDensity * fogDensity * depth * depth * LOG2 ) );",
641
+ " float fogFactor = ( 1.0 - exp2( - fogDensity * fogDensity * depth * depth * 1.442695 ) );",
640
642
  " #else",
641
643
  " float fogFactor = smoothstep( fogNear, fogFar, depth );",
642
644
  " #endif",
@@ -2606,13 +2608,33 @@ var CIFTools;
2606
2608
  /**
2607
2609
  * Options for filling the unit cell of a core CIF by lattice translation
2608
2610
  * (applied after the symmetry operators have generated the contents of one cell).
2609
- * nx, ny, nz : number of unit cells along a, b, c (supercell); default 1 1 1
2610
- * boundary : also emit the periodic image of every atom lying on a cell face/edge/corner
2611
- * (e.g. NaCl -> 14 Na + 13 Cl instead of 4 Na + 4 Cl); default true.
2612
- * Set to false to get the original behavior (atoms wrapped into [0,1) only).
2613
- * Usage (before loading the file): CIFTools.Text.coreCifOptions = {nx: 2, ny: 2, nz: 2, boundary: true};
2611
+ * nx, ny, nz : number of unit cells along a, b, c (supercell); default 1 1 1
2612
+ * wholeMolecules : keep every molecule / discrete chemical species intact. Atoms are grouped into
2613
+ * bonded fragments (covalent radii + bondTolerance, periodic), each fragment is
2614
+ * "unwrapped" so that it is contiguous (it may stick out of the unit cell), and the
2615
+ * fragment is placed in the cell that contains its centre. Fragments that are
2616
+ * infinite (chains, layers, frameworks, ionic lattices such as NaCl) cannot be made
2617
+ * whole and are handled as before (wrapped into the cell, see 'boundary'). default true
2618
+ * bondTolerance : extra distance (Angstrom) added to the sum of covalent radii when detecting bonds; default 0.4
2619
+ * boundary : for atoms that are NOT part of a whole molecule, also emit the periodic image of every
2620
+ * atom lying on a cell face/edge/corner (e.g. NaCl -> 14 Na + 13 Cl instead of 4 Na + 4 Cl);
2621
+ * default true.
2622
+ * Usage (before loading the file): CIFTools.Text.coreCifOptions = {nx: 2, ny: 2, nz: 2, wholeMolecules: true};
2614
2623
  */
2615
- Text.coreCifOptions = { nx: 1, ny: 1, nz: 1, boundary: true };
2624
+ Text.coreCifOptions = {
2625
+ nx: 1, ny: 1, nz: 1,
2626
+ wholeMolecules: true, // new; set false for the old wrapped behaviour
2627
+ bondTolerance: 0.4, // new; raise it if bonds are missed, lower it if unrelated atoms get joined, default 0.4
2628
+ boundary: true
2629
+ };
2630
+ // covalent radii (Angstrom, Cordero et al. 2008) used for bond detection
2631
+ var coreCovRadii = { H: 0.31, D: 0.31, He: 0.28, Li: 1.28, Be: 0.96, B: 0.84, C: 0.76, N: 0.71, O: 0.66, F: 0.57, Ne: 0.58,
2632
+ Na: 1.66, Mg: 1.41, Al: 1.21, Si: 1.11, P: 1.07, S: 1.05, Cl: 1.02, Ar: 1.06, K: 2.03, Ca: 1.76, Sc: 1.70, Ti: 1.60, V: 1.53,
2633
+ Cr: 1.39, Mn: 1.39, Fe: 1.32, Co: 1.26, Ni: 1.24, Cu: 1.32, Zn: 1.22, Ga: 1.22, Ge: 1.20, As: 1.19, Se: 1.20, Br: 1.20, Kr: 1.16,
2634
+ Rb: 2.20, Sr: 1.95, Y: 1.90, Zr: 1.75, Nb: 1.64, Mo: 1.54, Tc: 1.47, Ru: 1.46, Rh: 1.42, Pd: 1.39, Ag: 1.45, Cd: 1.44, In: 1.42,
2635
+ Sn: 1.39, Sb: 1.39, Te: 1.38, I: 1.39, Xe: 1.40, Cs: 2.44, Ba: 2.15, La: 2.07, Ce: 2.04, Pr: 2.03, Nd: 2.01, Sm: 1.98, Eu: 1.98,
2636
+ Gd: 1.96, Tb: 1.94, Dy: 1.92, Ho: 1.92, Er: 1.89, Tm: 1.90, Yb: 1.87, Lu: 1.87, Hf: 1.75, Ta: 1.70, W: 1.62, Re: 1.51, Os: 1.44,
2637
+ Ir: 1.41, Pt: 1.36, Au: 1.36, Hg: 1.32, Tl: 1.45, Pb: 1.46, Bi: 1.48 };
2616
2638
  // g: fractional coordinates wrapped into [0,1). Returns all translated copies of g.
2617
2639
  function coreLatticeImages(g, nx, ny, nz, bBoundary) {
2618
2640
  var eps = 1e-3, n = [nx, ny, nz], ranges = [], out = [], k, i, r, x, y, z;
@@ -2628,6 +2650,60 @@ var CIFTools;
2628
2650
  out.push([ranges[0][x], ranges[1][y], ranges[2][z]]);
2629
2651
  return out;
2630
2652
  }
2653
+ /**
2654
+ * Group atoms (fractional coordinates wrapped into the cell) into bonded fragments, taking periodic
2655
+ * images into account. Every atom of a fragment gets an integer lattice translation T so that
2656
+ * (g + T) forms a contiguous molecule. A fragment that reaches its own periodic image
2657
+ * (chain / layer / framework) is flagged as infinite.
2658
+ * atoms : [{el, g:[fx,fy,fz]}] toCart : fractional -> Cartesian (linear part only)
2659
+ * h : interplanar spacings of the cell along a, b, c tol : bond tolerance (Angstrom)
2660
+ */
2661
+ function coreFindMolecules(atoms, toCart, h, tol) {
2662
+ var N = atoms.length, nb = [], rad = [], i, j, k, e, m, q;
2663
+ for (i = 0; i < N; i++) { nb.push([]); rad.push(coreCovRadii[atoms[i].el] || 1.5); }
2664
+ for (i = 0; i < N; i++) {
2665
+ for (j = i; j < N; j++) {
2666
+ var d = [atoms[j].g[0] - atoms[i].g[0], atoms[j].g[1] - atoms[i].g[1], atoms[j].g[2] - atoms[i].g[2]];
2667
+ var rc = rad[i] + rad[j] + tol, cand = [[], [], []], dt, t;
2668
+ for (k = 0; k < 3; k++) {
2669
+ var base = -Math.round(d[k]);
2670
+ for (dt = -1; dt <= 1; dt++) {
2671
+ t = base + dt;
2672
+ if (Math.abs(d[k] + t) * h[k] <= rc) cand[k].push(t);
2673
+ }
2674
+ }
2675
+ for (var a = 0; a < cand[0].length; a++) for (var b = 0; b < cand[1].length; b++) for (var c = 0; c < cand[2].length; c++) {
2676
+ var tv = [cand[0][a], cand[1][b], cand[2][c]];
2677
+ if (i === j) { // bond to own image: record each translation pair only once
2678
+ if (tv[0] === 0 && tv[1] === 0 && tv[2] === 0) continue;
2679
+ if (tv[0] < 0 || (tv[0] === 0 && (tv[1] < 0 || (tv[1] === 0 && tv[2] < 0)))) continue;
2680
+ }
2681
+ var cc = toCart([d[0] + tv[0], d[1] + tv[1], d[2] + tv[2]]);
2682
+ var d2 = cc[0] * cc[0] + cc[1] * cc[1] + cc[2] * cc[2];
2683
+ if (d2 < rc * rc && d2 > 0.25) { // > 0.5 A: closer atoms are disorder alternatives, not bonds
2684
+ nb[i].push({ j: j, t: tv });
2685
+ nb[j].push({ j: i, t: [-tv[0], -tv[1], -tv[2]] });
2686
+ }
2687
+ }
2688
+ }
2689
+ }
2690
+ var T = new Array(N), comps = [], s, queue, members, infinite, cur, tj, o;
2691
+ for (s = 0; s < N; s++) {
2692
+ if (T[s]) continue;
2693
+ T[s] = [0, 0, 0]; queue = [s]; members = [s]; infinite = false;
2694
+ for (q = 0; q < queue.length; q++) {
2695
+ cur = queue[q];
2696
+ for (e = 0; e < nb[cur].length; e++) {
2697
+ o = nb[cur][e];
2698
+ tj = [T[cur][0] + o.t[0], T[cur][1] + o.t[1], T[cur][2] + o.t[2]];
2699
+ if (!T[o.j]) { T[o.j] = tj; queue.push(o.j); members.push(o.j); }
2700
+ else if (T[o.j][0] !== tj[0] || T[o.j][1] !== tj[1] || T[o.j][2] !== tj[2]) infinite = true;
2701
+ }
2702
+ }
2703
+ comps.push({ members: members, infinite: infinite });
2704
+ }
2705
+ return { T: T, comps: comps };
2706
+ }
2631
2707
  function convertCoreCif(data) {
2632
2708
  var tk = coreTokens(data), i = 0, n = tk.length, single = {}, loops = [], name = 'data_core', t, cols, rows, cur;
2633
2709
  function isTag(x) { return x && !x.t && x.v.charAt(0) === '_'; }
@@ -2681,12 +2757,21 @@ var CIFTools;
2681
2757
  '_atom_site.label_comp_id', '_atom_site.label_asym_id', '_atom_site.label_entity_id', '_atom_site.label_seq_id',
2682
2758
  '_atom_site.Cartn_x', '_atom_site.Cartn_y', '_atom_site.Cartn_z', '_atom_site.occupancy', '_atom_site.B_iso_or_equiv',
2683
2759
  '_atom_site.auth_seq_id', '_atom_site.auth_asym_id', '_atom_site.pdbx_PDB_model_num');
2684
- var serial = 0, seen = [], r, s, f, g, k, dup, j, sym, el, lab, cart;
2760
+ var serial = 0, r, s, f, g, k, dup, j, sym, el, lab, cart;
2685
2761
  var o = Text.coreCifOptions || {}, images, im;
2686
2762
  var opt = {
2687
2763
  nx: Math.max(1, parseInt(o.nx) || 1), ny: Math.max(1, parseInt(o.ny) || 1), nz: Math.max(1, parseInt(o.nz) || 1),
2688
- boundary: (o.boundary === undefined) ? true : !!o.boundary
2764
+ boundary: (o.boundary === undefined) ? true : !!o.boundary,
2765
+ wholeMolecules: (o.wholeMolecules === undefined) ? true : !!o.wholeMolecules,
2766
+ bondTolerance: (o.bondTolerance === undefined || isNaN(parseFloat(o.bondTolerance))) ? 0.4 : parseFloat(o.bondTolerance)
2689
2767
  };
2768
+ function emit(at, frac) {
2769
+ var cart = toCart(frac);
2770
+ out.push(['HETATM', ++serial, at.el, at.lab, '.', 'MOL', 'A', 1, '.', cart[0].toFixed(3), cart[1].toFixed(3), cart[2].toFixed(3),
2771
+ at.occ, '0.00', 1, 'A', 1].join(' '));
2772
+ }
2773
+ // 1) all symmetry-generated atoms of one cell, wrapped into [0,1)
2774
+ var list = [];
2690
2775
  for (r = 0; r < atoms.rows.length; r++) {
2691
2776
  var row = atoms.rows[r];
2692
2777
  if (get(row, '_atom_site_calc_flag') === 'dum') continue; // dummy atoms
@@ -2695,6 +2780,7 @@ var CIFTools;
2695
2780
  sym = get(row, '_atom_site_type_symbol'); if (sym === '?') sym = lab;
2696
2781
  el = (sym.match(/^[A-Za-z]{1,2}/) || ['X'])[0];
2697
2782
  el = el.charAt(0).toUpperCase() + el.substr(1).toLowerCase();
2783
+ var occ = coreToNumber(get(row, '_atom_site_occupancy') === '?' ? 1 : get(row, '_atom_site_occupancy'));
2698
2784
  var mySeen = [];
2699
2785
  for (s = 0; s < symops.length; s++) {
2700
2786
  g = symops[s](f).map(function (v) { return v - Math.floor(v + 1e-6); });
@@ -2704,15 +2790,51 @@ var CIFTools;
2704
2790
  }
2705
2791
  if (dup) continue;
2706
2792
  mySeen.push(g);
2707
- // fill the cell (and optional supercell) by lattice translation of the symmetry-generated site
2708
- images = coreLatticeImages(g, opt.nx, opt.ny, opt.nz, opt.boundary);
2709
- for (im = 0; im < images.length; im++) {
2710
- cart = toCart(images[im]);
2711
- out.push(['HETATM', ++serial, el, lab, '.', 'MOL', 'A', 1, '.', cart[0].toFixed(3), cart[1].toFixed(3), cart[2].toFixed(3),
2712
- coreToNumber(get(row, '_atom_site_occupancy') === '?' ? 1 : get(row, '_atom_site_occupancy')), '0.00', 1, 'A', 1].join(' '));
2793
+ list.push({ el: el, lab: lab, occ: occ, g: g });
2794
+ }
2795
+ }
2796
+ // 2) emit them, either as whole molecules or simply wrapped into the cell
2797
+ var mol = null;
2798
+ if (opt.wholeMolecules && list.length) {
2799
+ var Vc = a * b * cc * vol, sinal = Math.sqrt(1 - cosa * cosa), sinbe = Math.sqrt(1 - cosb * cosb);
2800
+ var hh = [Vc / (b * cc * sinal), Vc / (a * cc * sinbe), Vc / (a * b * sing)];
2801
+ if (isFinite(hh[0] + hh[1] + hh[2]) && hh[0] > 0 && hh[1] > 0 && hh[2] > 0) mol = coreFindMolecules(list, toCart, hh, opt.bondTolerance);
2802
+ }
2803
+ var ci, m, at, ix, iy, iz, mean, shift;
2804
+ if (mol) {
2805
+ for (ci = 0; ci < mol.comps.length; ci++) {
2806
+ var comp = mol.comps[ci];
2807
+ if (comp.infinite) { // cannot be made whole: wrap into the cell as before
2808
+ for (m = 0; m < comp.members.length; m++) {
2809
+ at = list[comp.members[m]];
2810
+ images = coreLatticeImages(at.g, opt.nx, opt.ny, opt.nz, opt.boundary);
2811
+ for (im = 0; im < images.length; im++) emit(at, images[im]);
2812
+ }
2813
+ continue;
2814
+ }
2815
+ // contiguous molecule: place it in the cell that holds its centre, keep all atoms together
2816
+ mean = [0, 0, 0];
2817
+ for (m = 0; m < comp.members.length; m++) {
2818
+ at = list[comp.members[m]];
2819
+ for (k = 0; k < 3; k++) mean[k] += (at.g[k] + mol.T[comp.members[m]][k]) / comp.members.length;
2820
+ }
2821
+ shift = [-Math.floor(mean[0] + 1e-6), -Math.floor(mean[1] + 1e-6), -Math.floor(mean[2] + 1e-6)];
2822
+ for (ix = 0; ix < opt.nx; ix++) for (iy = 0; iy < opt.ny; iy++) for (iz = 0; iz < opt.nz; iz++) {
2823
+ for (m = 0; m < comp.members.length; m++) {
2824
+ at = list[comp.members[m]];
2825
+ var tt = mol.T[comp.members[m]];
2826
+ emit(at, [at.g[0] + tt[0] + shift[0] + ix, at.g[1] + tt[1] + shift[1] + iy, at.g[2] + tt[2] + shift[2] + iz]);
2827
+ }
2713
2828
  }
2714
2829
  }
2715
2830
  }
2831
+ else {
2832
+ for (m = 0; m < list.length; m++) {
2833
+ at = list[m];
2834
+ images = coreLatticeImages(at.g, opt.nx, opt.ny, opt.nz, opt.boundary);
2835
+ for (im = 0; im < images.length; im++) emit(at, images[im]);
2836
+ }
2837
+ }
2716
2838
  out.push('#');
2717
2839
  return out.join('\n') + '\n';
2718
2840
  }
@@ -3011,7 +3133,7 @@ var CIFTools;
3011
3133
  // This approach to binary parsing wastes a bit of memory to trade for speed compared to:
3012
3134
  //
3013
3135
  // let value = buffer.subarray(offset, offset + length); //new Uint8Array(buffer.buffer, offset, length);
3014
- //
3136
+ //
3015
3137
  // It turns out that using the view created by subarray probably uses DataView
3016
3138
  // in the background, which causes the element access to be several times slower
3017
3139
  // than creating the new byte array.
@@ -4335,7 +4457,7 @@ var CIFTools;
4335
4457
  if (index === void 0) {
4336
4458
  // increment the length
4337
4459
  accLength += s.length;
4338
- // store the string and index
4460
+ // store the string and index
4339
4461
  index = strings.length;
4340
4462
  strings[index] = s;
4341
4463
  map[s] = index;
@@ -56304,7 +56426,7 @@ class UtilsCls {
56304
56426
  }
56305
56427
 
56306
56428
  //Convert a three-letter residue name to a one-letter residue abbreviation, e.g., 'LYS' to 'K', or ' A' to 'A' for nucleotides.
56307
- residueName2Abbr(residueName) { this.icn3dui;
56429
+ residueName2Abbr(residueName, bOneLetter) { this.icn3dui;
56308
56430
  let pos = residueName.indexOf(' ');
56309
56431
  if(pos > 0) {
56310
56432
  residueName = residueName.substr(0, pos);
@@ -56399,7 +56521,12 @@ class UtilsCls {
56399
56521
  return 'O';
56400
56522
 
56401
56523
  default:
56402
- return residueName.trim();
56524
+ if(bOneLetter) {
56525
+ return 'X';
56526
+ }
56527
+ else {
56528
+ return residueName.trim();
56529
+ }
56403
56530
  }
56404
56531
  }
56405
56532
 
@@ -56475,15 +56602,20 @@ class UtilsCls {
56475
56602
  }
56476
56603
 
56477
56604
  getIdArray(resid) { this.icn3dui;
56478
- //var idArray = resid.split('_');
56479
56605
  let idArray = [];
56480
56606
 
56481
56607
  if(resid) {
56482
- let pos1 = resid.indexOf('_');
56483
- let pos2 = resid.lastIndexOf('_');
56484
- idArray.push(resid.substr(0, pos1));
56485
- idArray.push(resid.substr(pos1 + 1, pos2 - pos1 - 1));
56486
- idArray.push(resid.substr(pos2 + 1));
56608
+ let itemArray = resid.split('_');
56609
+
56610
+ if(resid.indexOf('pdb_') == 0 ) { // e.g., pdb_00001GPK_A_15
56611
+ idArray.push(itemArray[0] + '_' + itemArray[1]);
56612
+ for(let i = 2, il = itemArray.length; i < il; ++i) {
56613
+ idArray.push(itemArray[i]);
56614
+ }
56615
+ }
56616
+ else {
56617
+ idArray = itemArray;
56618
+ }
56487
56619
  }
56488
56620
 
56489
56621
  return idArray;
@@ -56494,12 +56626,12 @@ class UtilsCls {
56494
56626
  let bArray = b.split(',');
56495
56627
  let aIdArray, bIdArray;
56496
56628
  if(type == 'save1') {
56497
- aIdArray = me.utilsCls.getIdArray(aArray[0]); //aArray[0].split('_');
56498
- bIdArray = me.utilsCls.getIdArray(bArray[0]); //bArray[0].split('_');
56629
+ aIdArray = me.utilsCls.getIdArray(aArray[0]);
56630
+ bIdArray = me.utilsCls.getIdArray(bArray[0]);
56499
56631
  }
56500
56632
  else if(type == 'save2') {
56501
- aIdArray = me.utilsCls.getIdArray(aArray[1]); //aArray[1].split('_');
56502
- bIdArray = me.utilsCls.getIdArray(bArray[1]); //bArray[1].split('_');
56633
+ aIdArray = me.utilsCls.getIdArray(aArray[1]);
56634
+ bIdArray = me.utilsCls.getIdArray(bArray[1]);
56503
56635
  }
56504
56636
  let aChainid = aIdArray[0] + '_' + aIdArray[1];
56505
56637
  let bChainid = bIdArray[0] + '_' + bIdArray[1];
@@ -58414,6 +58546,9 @@ class ClickMenu {
58414
58546
  me.myEventCls.onIds("#" + me.pre + "mn1_mmcifid", "click", function(e) { me.icn3d; //e.preventDefault();
58415
58547
  me.htmlCls.dialogCls.openDlg('dl_mmcifid', 'Please input mmCIF ID');
58416
58548
  });
58549
+ me.myEventCls.onIds("#" + me.pre + "mn1_codid", "click", function(e) { me.icn3d; //e.preventDefault();
58550
+ me.htmlCls.dialogCls.openDlg('dl_codid', 'Please input COD ID');
58551
+ });
58417
58552
 
58418
58553
  me.myEventCls.onIds("#" + me.pre + "mn1_mmdbid", "click", function(e) { me.icn3d; //e.preventDefault();
58419
58554
  me.htmlCls.dialogCls.openDlg('dl_mmdbid', 'Please input MMDB or PDB ID');
@@ -58953,7 +59088,7 @@ class ClickMenu {
58953
59088
  thisClass.setLogCmd("link to compounds with structure similar to CID " + ic.inputid + ": " + url, false);
58954
59089
  }
58955
59090
  else {
58956
- let idArray = ic.inputid.split('_');
59091
+ let idArray = me.utilsCls.getIdArray(ic.inputid);
58957
59092
 
58958
59093
  if(idArray.length === 1) {
58959
59094
  url = me.htmlCls.baseUrl + "vastplus/vastplus.cgi?uid=" + ic.inputid;
@@ -60015,17 +60150,14 @@ class ClickMenu {
60015
60150
 
60016
60151
  }
60017
60152
 
60018
- async setSupercell(n) { let me = this.icn3dui, ic = me.icn3d;
60019
- ic.loadCIFCls.loadCIF(ic.cifData, undefined, ic.cifText, false, n);
60020
-
60021
- if(Object.keys(ic.proteins).length == 0 || Object.keys(ic.nucleotides).length == 0) {
60022
- ic.pk = 1;
60023
- ic.opts['pk'] = 'atom';
60153
+ setSupercell(n) { let me = this.icn3dui, ic = me.icn3d;
60154
+ if(ic.cifData) {
60155
+ ic.loadCIFCls.loadCIF(ic.cifData, undefined, ic.cifText, false, n);
60156
+
60157
+ ic.setStyleCls.setAtomStyleByOptions(ic.opts);
60158
+ ic.setColorCls.setColorByOptions(ic.opts, ic.atoms);
60159
+ ic.drawCls.draw();
60024
60160
  }
60025
-
60026
- ic.setStyleCls.setAtomStyleByOptions(ic.opts);
60027
- ic.setColorCls.setColorByOptions(ic.opts, ic.atoms);
60028
- await ic.ParserUtilsCls.renderStructure();
60029
60161
  }
60030
60162
 
60031
60163
  clickMenu6() { let me = this.icn3dui, ic = me.icn3d;
@@ -60045,20 +60177,20 @@ class ClickMenu {
60045
60177
  ic.drawCls.draw();
60046
60178
  });
60047
60179
 
60048
- me.myEventCls.onIds("#" + me.pre + "mn6_assembly0", "click", async function(e) { me.icn3d; //e.preventDefault();
60049
- await thisClass.setSupercell(0);
60180
+ me.myEventCls.onIds("#" + me.pre + "mn6_assembly0", "click", function(e) { me.icn3d; //e.preventDefault();
60181
+ thisClass.setSupercell(0);
60050
60182
  thisClass.setLogCmd('set supercell 0', true);
60051
60183
  });
60052
- me.myEventCls.onIds("#" + me.pre + "mn6_assembly1", "click", async function(e) { me.icn3d; //e.preventDefault();
60053
- await thisClass.setSupercell(1);
60184
+ me.myEventCls.onIds("#" + me.pre + "mn6_assembly1", "click", function(e) { me.icn3d; //e.preventDefault();
60185
+ thisClass.setSupercell(1);
60054
60186
  thisClass.setLogCmd('set supercell 1', true);
60055
60187
  });
60056
- me.myEventCls.onIds("#" + me.pre + "mn6_assembly2", "click", async function(e) { me.icn3d; //e.preventDefault();
60057
- await thisClass.setSupercell(2);
60188
+ me.myEventCls.onIds("#" + me.pre + "mn6_assembly2", "click", function(e) { me.icn3d; //e.preventDefault();
60189
+ thisClass.setSupercell(2);
60058
60190
  thisClass.setLogCmd('set supercell 2', true);
60059
60191
  });
60060
- me.myEventCls.onIds("#" + me.pre + "mn6_assembly3", "click", async function(e) { me.icn3d; //e.preventDefault();
60061
- await thisClass.setSupercell(3);
60192
+ me.myEventCls.onIds("#" + me.pre + "mn6_assembly3", "click", function(e) { me.icn3d; //e.preventDefault();
60193
+ thisClass.setSupercell(3);
60062
60194
  thisClass.setLogCmd('set supercell 3', true);
60063
60195
  });
60064
60196
 
@@ -61416,6 +61548,7 @@ class SetMenu {
61416
61548
  html += this.getLink('mn1_opmid', 'OPM PDB ID ' + me.htmlCls.wifiStr, undefined, 2);
61417
61549
  html += this.getLink('mn1_mmcifid', 'RCSB mmCIF ID ' + me.htmlCls.wifiStr, undefined, 2);
61418
61550
  //html += this.getLink('mn1_gi', 'NCBI gi ' + me.htmlCls.wifiStr, undefined, 2);
61551
+ // html += this.getLink('mn1_codid', 'COD ID ' + me.htmlCls.wifiStr, 1, 2);
61419
61552
 
61420
61553
  html += this.getLink('mn1_cid', 'PubChem CID/Name/InChI ' + me.htmlCls.wifiStr, 1, 2);
61421
61554
  html += this.getLink('mn1_smiles', 'Chemical SMILES ', undefined, 2);
@@ -62656,16 +62789,17 @@ class SetMenu {
62656
62789
 
62657
62790
  html += this.getLink('mn6_DSSP', 'DSSP Secondary', undefined, 1);
62658
62791
 
62659
- let bInputid = me.cfg.mmtfid !== undefined || me.cfg.pdbid !== undefined || me.cfg.opmid !== undefined || me.cfg.mmcifid !== undefined || me.cfg.bcifid !== undefined || me.cfg.mmdbid !== undefined || me.cfg.mmdbafid !== undefined || me.cfg.gi !== undefined || me.cfg.blast_rep_id !== undefined;
62792
+ let bInputid = me.cfg.mmtfid !== undefined || me.cfg.pdbid !== undefined || me.cfg.opmid !== undefined || me.cfg.mmcifid !== undefined || me.cfg.bcifid !== undefined || me.cfg.mmtfid !== undefined || me.cfg.mmdbid !== undefined || me.cfg.mmdbafid !== undefined || me.cfg.gi !== undefined || me.cfg.blast_rep_id !== undefined;
62660
62793
 
62661
62794
  //if(bInputid) {
62662
62795
  html += this.getMenuText('assemblyWrapper', 'Assembly', undefined, 1, 1);
62663
62796
  html += "<ul>";
62664
62797
 
62665
- if(!bInputid || me.cfg.mmcifid !== undefined || me.cfg.bcifid !== undefined) { // e.g., cif file input
62666
- html += this.getRadio('mn6_assembly', 'mn6_assembly0', 'Original Assembly', undefined, 1, 2);
62798
+ if(!bInputid || me.cfg.mmcifid !== undefined || me.cfg.bcifid !== undefined || me.cfg.mmtfid !== undefined) { // e.g., cif file input
62799
+ html += this.getRadio('mn6_assembly', 'mn6_assembly0', 'Biological Assembly', undefined, 1, 2);
62800
+ html += this.getRadio('mn6_assembly', 'mn6_assemblyNo', 'Asymmetric Unit', undefined, 1, 2);
62667
62801
  html += this.getRadio('mn6_assembly', 'mn6_assembly1', '1 x 1 x 1', true, 1, 2);
62668
- html += this.getRadio('mn6_assembly', 'mn6_assembly2', '2 x 2 x 2', undefined, 1, 2);
62802
+ html += this.getRadio('mn6_assembly', 'mn6_assembly2', '2 x 2 x 2', undefined, undefined, 2);
62669
62803
  html += this.getRadio('mn6_assembly', 'mn6_assembly3', '3 x 3 x 3', undefined, 1, 2);
62670
62804
  }
62671
62805
  else if(!me.cfg.bu) {
@@ -63921,6 +64055,12 @@ class SetDialog {
63921
64055
  html += me.htmlCls.buttonStr + "reload_mmcif'>Load</button>";
63922
64056
  html += "</div>";
63923
64057
 
64058
+ html += me.htmlCls.divStr + "dl_codid' class='" + dialogClass + "'>";
64059
+ html += this.addNotebookTitle('dl_codid', 'Please input a COD ID');
64060
+ html += "COD ID: " + me.htmlCls.inputTextStr + "id='" + me.pre + "codid' value='1000041' size=8> ";
64061
+ html += me.htmlCls.buttonStr + "reload_cod'>Load</button>";
64062
+ html += "</div>";
64063
+
63924
64064
  html += me.htmlCls.divStr + "dl_mmdbid' class='" + dialogClass + "' style='max-width:500px'>";
63925
64065
  html += this.addNotebookTitle('dl_mmdbid', 'Please input an MMDB ID');
63926
64066
  html += "MMDB or PDB ID: " + me.htmlCls.inputTextStr + "id='" + me.pre + "mmdbid' value='1TUP' size=8> <br><br>";
@@ -65583,7 +65723,7 @@ class Events {
65583
65723
  let idArray = ids.split(',');
65584
65724
 
65585
65725
  if(!bAppend) {
65586
- if(idArray.length == 1 && (idArray[0].length == 4 || !isNaN(idArray[0])) ) {
65726
+ if(idArray.length == 1 && (idArray[0].length == 4 || idArray[0].indexOf('pdb_') == 0 || !isNaN(idArray[0])) ) {
65587
65727
  thisClass.setLogCmd("load mmdb" + flag + " " + ids, false);
65588
65728
  let urlTarget = (ic.structures && Object.keys(ic.structures).length > 0) ? '_blank' : '_self';
65589
65729
  window.open(hostUrl + '?mmdbid=' + ids + '&bu=' + flag, urlTarget);
@@ -65595,8 +65735,8 @@ class Events {
65595
65735
  }
65596
65736
  }
65597
65737
  else {
65598
- // single MMDB ID could show memebranes
65599
- if(!ic.structures && idArray.length == 1 && (idArray[0].length == 4 || !isNaN(idArray[0])) ) {
65738
+ // single MMDB ID could show membranes
65739
+ if(!ic.structures && idArray.length == 1 && (idArray[0].length == 4 || idArray[0].indexOf('pdb_') == 0 || !isNaN(idArray[0])) ) {
65600
65740
  thisClass.setLogCmd("load mmdb" + flag + " " + ids, false);
65601
65741
  let urlTarget = (ic.structures && Object.keys(ic.structures).length > 0) ? '_blank' : '_self';
65602
65742
  window.open(hostUrl + '?mmdbid=' + ids + '&bu=' + flag, urlTarget);
@@ -66084,7 +66224,7 @@ class Events {
66084
66224
  if(!me.cfg.notebook) dialog.dialog( "close" );
66085
66225
  thisClass.setLogCmd("load mmtf " + $("#" + me.pre + "mmtfid").val(), false);
66086
66226
  let urlTarget = (ic.structures && Object.keys(ic.structures).length > 0) ? '_blank' : '_self';
66087
- window.open(hostUrl + '?mmtfid=' + $("#" + me.pre + "mmtfid").val(), urlTarget);
66227
+ window.open(hostUrl + '?bcifid=' + $("#" + me.pre + "mmtfid").val(), urlTarget);
66088
66228
  }
66089
66229
  });
66090
66230
 
@@ -66428,7 +66568,7 @@ class Events {
66428
66568
  await ic.scapCls.retrieveScap(snp, bInteraction);
66429
66569
  thisClass.setLogCmd('scap interaction ' + snp, true);
66430
66570
 
66431
- let idArray = snp.split('_'); //stru_chain_resi_snp
66571
+ let idArray = me.utilsCls.getIdArray(snp); //stru_chain_resi_snp
66432
66572
  let select = '.' + idArray[1] + ':' + idArray[2];
66433
66573
  let name = 'snp_' + idArray[1] + '_' + idArray[2];
66434
66574
  thisClass.setLogCmd("select " + select + " | name " + name, true);
@@ -66467,7 +66607,6 @@ class Events {
66467
66607
  let urlTarget = (ic.structures && Object.keys(ic.structures).length > 0) ? '_blank' : '_self';
66468
66608
  window.open(hostUrl + '?mmcifid=' + $("#" + me.pre + "mmcifid").val(), urlTarget);
66469
66609
  });
66470
-
66471
66610
  me.myEventCls.onIds("#" + me.pre + "mmcifid", "keyup", function(e) { let ic = me.icn3d;
66472
66611
  if (e.keyCode === 13) {
66473
66612
  e.preventDefault();
@@ -66478,6 +66617,23 @@ class Events {
66478
66617
  }
66479
66618
  });
66480
66619
 
66620
+ me.myEventCls.onIds("#" + me.pre + "reload_cod", "click", function(e) { let ic = me.icn3d;
66621
+ e.preventDefault();
66622
+ if(!me.cfg.notebook) dialog.dialog( "close" );
66623
+ thisClass.setLogCmd("load cod " + $("#" + me.pre + "codid").val(), false);
66624
+ let urlTarget = (ic.structures && Object.keys(ic.structures).length > 0) ? '_blank' : '_self';
66625
+ window.open(hostUrl + '?codid=' + $("#" + me.pre + "codid").val(), urlTarget);
66626
+ });
66627
+ me.myEventCls.onIds("#" + me.pre + "codid", "keyup", function(e) { let ic = me.icn3d;
66628
+ if (e.keyCode === 13) {
66629
+ e.preventDefault();
66630
+ if(!me.cfg.notebook) dialog.dialog( "close" );
66631
+ thisClass.setLogCmd("load cod " + $("#" + me.pre + "codid").val(), false);
66632
+ let urlTarget = (ic.structures && Object.keys(ic.structures).length > 0) ? '_blank' : '_self';
66633
+ window.open(hostUrl + '?codid=' + $("#" + me.pre + "codid").val(), urlTarget);
66634
+ }
66635
+ });
66636
+
66481
66637
 
66482
66638
  me.myEventCls.onIds("#" + me.pre + "reload_mmdb", "click", function(e) { let ic = me.icn3d;
66483
66639
  e.preventDefault();
@@ -69063,7 +69219,7 @@ class Events {
69063
69219
  await ic.scapCls.retrieveScap(snp, bInteraction);
69064
69220
  thisClass.setLogCmd('scap interaction ' + snp, true);
69065
69221
 
69066
- let idArray = snp.split('_'); //stru_chain_resi_snp
69222
+ let idArray = me.utilsCls.getIdArray(snp); //stru_chain_resi_snp
69067
69223
  let select = '.' + idArray[1] + ':' + idArray[2];
69068
69224
  let name = 'snp_' + idArray[1] + '_' + idArray[2];
69069
69225
  thisClass.setLogCmd("select " + select + " | name " + name, true);
@@ -79087,6 +79243,43 @@ class Camera {
79087
79243
  // }
79088
79244
  }
79089
79245
 
79246
+ // Keep the slab plane at the same position relative to the molecule when zooming.
79247
+ // In perspective mode zooming moves the camera along the view direction, so the near plane
79248
+ // (distance from the camera) has to move with it. In orthographic mode zooming only changes
79249
+ // the frustum size and the camera does not move, so the slab plane already stays fixed.
79250
+ updateSlabByZoom() { let ic = this.icn3d, me = ic.icn3dui;
79251
+ if(ic.opts['slab'] !== 'yes' || me.bNode) return;
79252
+ if(ic.opts.camera.toLowerCase() !== 'perspective') return;
79253
+
79254
+ let bInstance = (ic.biomtMatrices !== undefined && ic.biomtMatrices.length * ic.cnt > ic.maxatomcnt) ? true : false;
79255
+ if(bInstance) return; // near plane is fixed at 0.1 for instancing
79256
+
79257
+ let cam = (ic.bControlGl) ? window.cam : ic.cam;
79258
+ let controls = (ic.bControlGl) ? window.controls : ic.controls;
79259
+
79260
+ // at zoom = 1 the slab plane is ic.maxD * camMaxDFactor from the camera, i.e. the plane through
79261
+ // the center (or 10 angstroms in front of it when fog is on to keep some surrounding residues)
79262
+ let offset = (ic.camMaxDFactorFog !== undefined) ? 10 : 0;
79263
+
79264
+ // current distance from the camera to the center of rotation, which changes with zooming
79265
+ let dist = cam.position.distanceTo(controls.target);
79266
+
79267
+ // keep the plane at the same position relative to the molecule
79268
+ let nearClip = Math.max(0.1, dist - offset);
79269
+
79270
+ if(Math.abs(cam.near - nearClip) > 1e-6) {
79271
+ cam.near = nearClip;
79272
+ cam.updateProjectionMatrix();
79273
+ if(ic.cam && ic.cam !== cam) {
79274
+ ic.cam.near = nearClip;
79275
+ ic.cam.updateProjectionMatrix();
79276
+ }
79277
+ }
79278
+
79279
+ // the impostor shaders (spheres, cylinders) clip with the nearClip uniform
79280
+ if(ic.uniforms && ic.uniforms.nearClip) ic.uniforms.nearClip.value = nearClip;
79281
+ }
79282
+
79090
79283
  setSlab() { let ic = this.icn3d, me = ic.icn3dui;
79091
79284
  if(ic.bControlGl && !me.bNode) {
79092
79285
  let maxD = ic.maxD;
@@ -79202,7 +79395,8 @@ class Fog {
79202
79395
  else {
79203
79396
  // adjust
79204
79397
  let zoomFactor = (ic._zoomFactor > 1) ? ic._zoomFactor * 1.0 : ic._zoomFactor;
79205
- ic.scene.fog = new Fog$1(background, 2.5 * ic.maxD * zoomFactor, 4 * ic.maxD * zoomFactor);
79398
+ let fogStrength = 2; // 1 = current, >1 = stronger
79399
+ ic.scene.fog = new Fog$1(background, (3 - 0.5 / fogStrength) * ic.maxD * zoomFactor, (3 + 1.0 / fogStrength) * ic.maxD * zoomFactor);
79206
79400
  ic.bSetFog = true;
79207
79401
  ic.camMaxDFactorFog = 3;
79208
79402
  }
@@ -81427,6 +81621,8 @@ class Tube {
81427
81621
 
81428
81622
  let prevAxis1 = new Vector3$1(), prevAxis2;
81429
81623
  for (let i = 0, lim = pnts.length; i < lim; ++i) {
81624
+ if(!pnts[i]) continue;
81625
+
81430
81626
  let r, idx = (i - 1) * axisDivInv;
81431
81627
 
81432
81628
  if (i === 0) {
@@ -81459,7 +81655,7 @@ class Tube {
81459
81655
  }
81460
81656
 
81461
81657
  let delta, axis1, axis2;
81462
- if (i < lim - 1) {
81658
+ if (i < lim - 1 && pnts[i + 1]) {
81463
81659
  delta = pnts[i].clone().sub(pnts[i + 1]);
81464
81660
  axis1 = new Vector3$1(0, -delta.z, delta.y).normalize().multiplyScalar(r);
81465
81661
  axis2 = delta.clone().cross(axis1).normalize().multiplyScalar(r);
@@ -85445,7 +85641,6 @@ class Surface {
85445
85641
  let chainStr = (Object.keys(chainHash).length > 1) ? '<th>Chain</th>' : '';
85446
85642
  html += '<tr>' + structureStr + chainStr + '<th>Residue</th><th>Number</th><th>SASA (&#8491;<sup>2</sup>)</th><th>Percent Out</th><th>In/Out</th></tr>';
85447
85643
  for(let resid in ic.resid2area) {
85448
- //var idArray = resid.split('_');
85449
85644
  let pos = resid.lastIndexOf('_');
85450
85645
  let resn = resid.substr(pos + 1);
85451
85646
 
@@ -86099,6 +86294,8 @@ class ApplyClbonds {
86099
86294
  // only apply to displayed atoms
86100
86295
  // if(!ic.dAtoms.hasOwnProperty(line.serial1) || !ic.dAtoms.hasOwnProperty(line.serial2)) continue;
86101
86296
 
86297
+ if(!ic.atoms[line.serial1] || !ic.atoms[line.serial2]) continue;
86298
+
86102
86299
  line.position1 = ic.atoms[line.serial1].coord;
86103
86300
  line.position2 = ic.atoms[line.serial2].coord;
86104
86301
 
@@ -86229,6 +86426,7 @@ class ApplyClbonds {
86229
86426
  if(type == 'chemical') continue; // just connect checmicals together
86230
86427
 
86231
86428
  if(ic.clbondpnts[atom0.structure] === undefined) ic.clbondpnts[atom0.structure] = [];
86429
+ if(ic.clbondpnts[atom1.structure] === undefined) ic.clbondpnts[atom1.structure] = [];
86232
86430
  ic.clbondpnts[atom0.structure].push(resid0);
86233
86431
  ic.clbondpnts[atom1.structure].push(resid1);
86234
86432
 
@@ -86774,9 +86972,9 @@ class ApplyOther {
86774
86972
  }
86775
86973
  }
86776
86974
 
86777
- ic.lineCls.createLines(ic.lines);
86778
- if(!ic.planes) ic.planes = [];
86779
- ic.cylinderCls.createPlanes(ic.planes);
86975
+ // ic.lineCls.createLines(ic.lines);
86976
+ // if(!ic.planes) ic.planes = [];
86977
+ // ic.cylinderCls.createPlanes(ic.planes);
86780
86978
  // }
86781
86979
 
86782
86980
  // distance sets
@@ -86899,6 +87097,10 @@ class ApplyOther {
86899
87097
  ic.pk = 3;
86900
87098
  break;
86901
87099
  }
87100
+
87101
+ ic.lineCls.createLines(ic.lines);
87102
+ if(!ic.planes) ic.planes = [];
87103
+ ic.cylinderCls.createPlanes(ic.planes);
86902
87104
  }
86903
87105
 
86904
87106
  applyChemicalbindingOptions(options) { let ic = this.icn3d, me = ic.icn3dui;
@@ -88045,6 +88247,8 @@ class Impostor {
88045
88247
 
88046
88248
  let shiness = ic.shininess / 100.0 * 0.5;
88047
88249
 
88250
+ let fogRGB = background.clone().convertLinearToSRGB();
88251
+
88048
88252
  ic.uniforms = UniformsUtils.merge([
88049
88253
  UniformsLib.common,
88050
88254
  {
@@ -88065,7 +88269,8 @@ class Impostor {
88065
88269
  nearClip: { type: "f", value: nearClip },
88066
88270
  ortho: { type: "f", value: 0.0 },
88067
88271
  shrink: { type: "f", value: 0.13 },
88068
- fogColor: { type: "v3", value: [background.r, background.g, background.b] },
88272
+ //fogColor: { type: "v3", value: [background.r, background.g, background.b] },
88273
+ fogColor: { type: "v3", value: [fogRGB.r, fogRGB.g, fogRGB.b] },
88069
88274
  fogNear: { type: "f", value: near },
88070
88275
  fogFar: { type: "f", value: far },
88071
88276
  fogDensity: { type: "f", value: 2.0 }
@@ -106298,6 +106503,9 @@ class WebGLPathTracer {
106298
106503
 
106299
106504
  cam = this.setDirectLight(cam);
106300
106505
 
106506
+ // move the slab plane according to the zoom
106507
+ if(ic.opts['slab'] === 'yes') ic.cameraCls.updateSlabByZoom();
106508
+
106301
106509
  if(!ic.bVr) ic.renderer.setPixelRatio( window.devicePixelRatio ); // r71
106302
106510
 
106303
106511
  if(ic.bVr) {
@@ -109861,7 +110069,7 @@ class AnnoCddSite {
109861
110069
  ic.bAjaxCddSite = true;
109862
110070
  }
109863
110071
 
109864
- getResiArrayStr(resiNCBIArray, chainid) { let ic = this.icn3d; ic.icn3dui;
110072
+ getResiArrayStr(resiNCBIArray, chainid) { let ic = this.icn3d, me = ic.icn3dui;
109865
110073
  let resiArrayStr = '';
109866
110074
  for(let i = 0, il = resiNCBIArray.length; i < il; ++i) {
109867
110075
  let resiNCBI = resiNCBIArray[i] + 1; // zero-based
@@ -109869,7 +110077,8 @@ class AnnoCddSite {
109869
110077
  let resid = ic.ncbi2resid[residNCBI];
109870
110078
  if(!resid) resid = residNCBI; // this happens sometimes, e.g., Q9Y4K1
109871
110079
 
109872
- let resi = resid.split('_')[2];
110080
+ let idArray = me.utilsCls.getIdArray(resid);
110081
+ let resi = idArray[2];
109873
110082
  if(i > 0) resiArrayStr += ',';
109874
110083
  resiArrayStr += resi;
109875
110084
  }
@@ -110965,7 +111174,8 @@ class AnnoIg {
110965
111174
  let residArray = Object.keys(residHash);
110966
111175
 
110967
111176
  // delete the following loops
110968
- let lastPos = ic.setSeqAlignCls.getPosFromResi(chnid, residArray[residArray.length - 1].split('_')[2]);
111177
+ let idArray = me.utilsCls.getIdArray(residArray[residArray.length - 1]);
111178
+ let lastPos = ic.setSeqAlignCls.getPosFromResi(chnid, idArray[2]);
110969
111179
 
110970
111180
  for(let j = lastPos + 1, jl = ic.chainsSeq[chnid].length; j < jl; ++j) {
110971
111181
  let resi = ic.chainsSeq[chnid][j].resi;
@@ -110981,7 +111191,8 @@ class AnnoIg {
110981
111191
  }
110982
111192
 
110983
111193
  // delete the previous loops
110984
- ic.setSeqAlignCls.getPosFromResi(chnid, residArray[0].split('_')[2]);
111194
+ idArray = me.utilsCls.getIdArray(residArray[0]);
111195
+ ic.setSeqAlignCls.getPosFromResi(chnid, idArray[2]);
110985
111196
 
110986
111197
  for(let j = lastPos - 1; j >= 0; --j) {
110987
111198
  let resi = ic.chainsSeq[chnid][j].resi;
@@ -111984,8 +112195,9 @@ class AnnoSnpClinVar {
111984
112195
  let residHash = ic.firstAtomObjCls.getResiduesFromAtoms(ic.chains[chnid]);
111985
112196
  // for(let i = 1, il = ic.giSeq[chnid].length; i <= il; ++i) {
111986
112197
  for(let resid in residHash) {
111987
- let i = resid.split('_')[2];
111988
-
112198
+ let idArray = me.utilsCls.getIdArray(resid);
112199
+ let i = idArray[2];
112200
+
111989
112201
  if(resi2index[i] !== undefined) {
111990
112202
  ++snpCnt;
111991
112203
  let allDiseaseTitle = '';
@@ -114178,7 +114390,6 @@ class Domain3d {
114178
114390
  // if(fromPos >= start && toPos <= end) {
114179
114391
  if(ssCnt > 0) jsonStr += ', ';
114180
114392
  jsonStr += '[' + sstype + ',' + fromPos + ',' + toPos + ',' + substruct[k].x1.toFixed(2) + ',' + substruct[k].y1.toFixed(2) + ',';
114181
- // jsonStr += '[' + sstype + ',' + residFrom.split('_')[2] + ',' + residTo.split('_')[2] + ',' + substruct[k].x1.toFixed(2) + ',' + substruct[k].y1.toFixed(2) + ',';
114182
114393
  jsonStr += substruct[k].z1.toFixed(2) + ',' + substruct[k].x2.toFixed(2) + ',' + substruct[k].y2.toFixed(2) + ',' + substruct[k].z2.toFixed(2) + ']';
114183
114394
  ++ssCnt;
114184
114395
  // }
@@ -114195,7 +114406,6 @@ class Domain3d {
114195
114406
  for(let j = startAll; j <= endAll; ++j) {
114196
114407
  let ncbiResid = chnid + '_' + j;
114197
114408
  let resid = ic.ncbi2resid[ncbiResid];
114198
- resid.split('_')[2];
114199
114409
 
114200
114410
  let pos = j;
114201
114411
 
@@ -114203,7 +114413,6 @@ class Domain3d {
114203
114413
 
114204
114414
  if(!residueHash.hasOwnProperty(resid)) {
114205
114415
  jsonStr += '[' + pos + ',' + 0 + ',' + fakeCoord + ',' + fakeCoord + ',' + fakeCoord + ']';
114206
- // jsonStr += '[' + resi + ',' + 0 + ',' + fakeCoord + ',' + fakeCoord + ',' + fakeCoord + ']';
114207
114416
  }
114208
114417
  else {
114209
114418
  let atom = ic.firstAtomObjCls.getFirstCalphaAtomObj(ic.residues[resid]);
@@ -114212,7 +114421,6 @@ class Domain3d {
114212
114421
  let restype = (me.parasCls.resn2restype[atom.resn]) ? me.parasCls.resn2restype[atom.resn] : 0;
114213
114422
 
114214
114423
  jsonStr += '[' + pos + ',' + restype + ',' + atom.coord.x.toFixed(2) + ',' + atom.coord.y.toFixed(2) + ',' + atom.coord.z.toFixed(2) + ']';
114215
- // jsonStr += '[' + resi + ',' + restype + ',' + atom.coord.x.toFixed(2) + ',' + atom.coord.y.toFixed(2) + ',' + atom.coord.z.toFixed(2) + ']';
114216
114424
  }
114217
114425
 
114218
114426
  ++domainCnt;
@@ -120050,7 +120258,6 @@ class GetGraph {
120050
120258
  for(let i = 0, il = graphJson.nodes.length; i < il; ++i) {
120051
120259
  let node = graphJson.nodes[i];
120052
120260
  //node.r: 1_1_1KQ2_A_1
120053
- //var idArray = node.r.split('_');
120054
120261
  let idArray = [];
120055
120262
  idArray.push('');
120056
120263
  idArray.push('');
@@ -120229,8 +120436,8 @@ class GetGraph {
120229
120436
  compNode(a, b, bReverseChain) { let ic = this.icn3d, me = ic.icn3dui;
120230
120437
  let resid1 = a.r.substr(4); // 1_1_1KQ2_A_1
120231
120438
  let resid2 = b.r.substr(4); // 1_1_1KQ2_A_1
120232
- let aIdArray = me.utilsCls.getIdArray(resid1); //resid1.split('_');
120233
- let bIdArray = me.utilsCls.getIdArray(resid2); //resid2.split('_');
120439
+ let aIdArray = me.utilsCls.getIdArray(resid1);
120440
+ let bIdArray = me.utilsCls.getIdArray(resid2);
120234
120441
  let aChainid = aIdArray[0] + '_' + aIdArray[1];
120235
120442
  let bChainid = bIdArray[0] + '_' + bIdArray[1];
120236
120443
  let aResi = parseInt(aIdArray[2]);
@@ -121283,7 +121490,7 @@ class ViewInterPairs {
121283
121490
  residname2 =(type == 'save1') ? residname1_residname2[1] : residname1_residname2[0];
121284
121491
 
121285
121492
  // stru_chain_resi_resn
121286
- let ids = residname1.split('_');
121493
+ let ids = me.utilsCls.getIdArray(residname1);
121287
121494
  if(i > 0 && residname1 != prevResidname1) {
121288
121495
  bondCnt.push({res1: prevResidname1, res2: residname2List, cntHbond: cntHbond, cntIonic: cntIonic, cntContact: cntContact, cntHalegen: cntHalegen, cntPication: cntPication, cntPistacking: cntPistacking});
121289
121496
 
@@ -122684,8 +122891,8 @@ class AlignParser {
122684
122891
  //var scale = data2.transform.scale / factor;
122685
122892
  let tMaster = data2.transform.translate.master;
122686
122893
  let tMVector = new Vector3$1(tMaster[0] / factor, tMaster[1] / factor, tMaster[2] / factor);
122687
- let tSlave = data2.transform.translate.slave;
122688
- let tSVector = new Vector3$1(tSlave[0] / factor, tSlave[1] / factor, tSlave[2] / factor);
122894
+ let tQuery = data2.transform.translate.slave; // actually means query protein
122895
+ let tSVector = new Vector3$1(tQuery[0] / factor, tQuery[1] / factor, tQuery[2] / factor);
122689
122896
  let rotation = data2.transform.rotate;
122690
122897
  let rMatrix = [];
122691
122898
  for(let i = 0, il = rotation.length; i < il; ++i) { // 9 elements
@@ -122929,44 +123136,6 @@ class ChainalignParser {
122929
123136
  // calculate secondary structures with applyCommandDssp
122930
123137
  //$.when(ic.pdbParserCls.applyCommandDssp(true)).then(function() {
122931
123138
  await ic.pdbParserCls.applyCommandDssp(true);
122932
- //!!!
122933
- /*
122934
- // original version =============
122935
- // align PDB chains
122936
- for(let index in ic.pdbChainIndexHash) {
122937
- //ic.pdbChainIndexHash[index] = mmdbid_q_tmp + "_" + ic.chain_q + "_" + ic.mmdbid_t + "_" + ic.chain_t;
122938
- let idArray = ic.pdbChainIndexHash[index].split('_');
122939
- mmdbid_q = idArray[0];
122940
- let chain_q = idArray[1];
122941
- mmdbid_t = idArray[2];
122942
- let chain_t = idArray[3];
122943
-
122944
- thisClass.transformStructure(mmdbid_q, index-1, 'query');
122945
- }
122946
-
122947
- // dynamically align pairs in ic.afChainIndexHash
122948
- let ajaxArray = [], indexArray = [], struArray = [];
122949
- let urlalign = me.htmlCls.baseUrl + "vastdyn/vastdyn.cgi";
122950
- let urltmalign = me.htmlCls.baseUrl + "tmalign/tmalign.cgi";
122951
-
122952
- let resRangeArray = (me.cfg.resrange) ? decodeURIComponent(me.cfg.resrange).split(' | ') : [];
122953
-
122954
- for(let index in ic.afChainIndexHash) {
122955
- let idArray = ic.afChainIndexHash[index].split('_');
122956
- mmdbid_q = idArray[0];
122957
- let chain_q = idArray[1];
122958
- let chainid_q = mmdbid_q + '_' + chain_q;
122959
-
122960
- mmdbid_t = idArray[2];
122961
- let chain_t = idArray[3];
122962
- let chainid_t = mmdbid_t + '_' + chain_t;
122963
-
122964
- // let atomSet_t = (resRangeArray[0]) ? ic.realignParserCls.getSeqCoorResid(resRangeArray[0].split(','), chainid_t, true).hAtoms : ic.chains[chainid_t];
122965
- // let atomSet_q = (resRangeArray[index]) ? ic.realignParserCls.getSeqCoorResid(resRangeArray[index].split(','), chainid_q, true).hAtoms : ic.chains[chainid_q];
122966
- let atomSet_t = (resRangeArray[0]) ? ic.realignParserCls.getSeqCoorResid([resRangeArray[0]], chainid_t, true).hAtoms : ic.chains[chainid_t];
122967
- let atomSet_q = (resRangeArray[index]) ? ic.realignParserCls.getSeqCoorResid([resRangeArray[index]], chainid_q, true).hAtoms : ic.chains[chainid_q];
122968
- // end of original version =============
122969
- */
122970
123139
 
122971
123140
  // new version to be done for VASTsrv ==============
122972
123141
  // dynamically align pairs in all chainids
@@ -123435,10 +123604,10 @@ class ChainalignParser {
123435
123604
  return chainidArray;
123436
123605
  }
123437
123606
 
123438
- addPostfixForStructureids(structArray) { let ic = this.icn3d; ic.icn3dui;
123607
+ addPostfixForStructureids(structArray) { let ic = this.icn3d, me = ic.icn3dui;
123439
123608
  let struct2cnt = {};
123440
123609
  for(let i = 0, il = structArray.length; i < il; ++i) {
123441
- if(structArray[i].toLowerCase().toLowerCase().substr(0,8) == 'pdb_0000') structArray[i] = structArray[i].substr(8); // temperary support long PDB ID such as pdb_00001tup
123610
+ if((me.cfg.mmdbid != undefined || me.cfg.pdbid != undefined) && structArray[i].toLowerCase().toLowerCase().substr(0,8) == 'pdb_0000') structArray[i] = structArray[i].substr(8); // temperary support long PDB ID such as pdb_00001tup
123442
123611
 
123443
123612
  let struct = structArray[i].toUpperCase();
123444
123613
 
@@ -123462,6 +123631,8 @@ class ChainalignParser {
123462
123631
 
123463
123632
  ic.opts['proteins'] = 'c alpha trace';
123464
123633
 
123634
+ if(!chainalign) return;
123635
+
123465
123636
  let alignArray = chainalign.split(',');
123466
123637
  let domainArray = (me.cfg.domainids) ? me.cfg.domainids.split(',') : [];
123467
123638
  if(domainArray.length < alignArray.length) domainArray = [];
@@ -123534,7 +123705,7 @@ class ChainalignParser {
123534
123705
  let domainalign = (domainArray.length > 0) ? domainArray[index] + "," + domainArray[0] : undefined;
123535
123706
 
123536
123707
  // TM-align (me.cfg.aligntool == 'tmalign') needs to input PDB
123537
- if(me.cfg.aligntool != 'tmalign' && ic.mmdbid_t.length == 4 && ic.mmdbid_q.length == 4) {
123708
+ if(me.cfg.aligntool != 'tmalign' && (ic.mmdbid_t.length == 4 || ic.mmdbid_t.indexOf('pdb_') == 0) && (ic.mmdbid_q.length == 4 || ic.mmdbid_q.indexOf('pdb_') == 0)) {
123538
123709
  let urlalign;
123539
123710
 
123540
123711
  if(domainArray.length > 0) {
@@ -123823,7 +123994,7 @@ class ChainalignParser {
123823
123994
  }
123824
123995
  else {
123825
123996
  for(let i = 0, il = structArrayTmp.length; i < il; ++i) {
123826
- if(structArrayTmp[i].toLowerCase().substr(0,8) == 'pdb_0000') structArrayTmp[i] = structArrayTmp[i].substr(8); // temperary support long PDB ID such as pdb_00001tup
123997
+ if((me.cfg.mmdbid != undefined || me.cfg.pdbid != undefined) && structArrayTmp[i].toLowerCase().substr(0,8) == 'pdb_0000') structArrayTmp[i] = structArrayTmp[i].substr(8); // temperary support long PDB ID such as pdb_00001tup
123827
123998
 
123828
123999
  let id = structArrayTmp[i].toUpperCase();
123829
124000
  if(!ic.structures.hasOwnProperty(id)) structArray.push(structArrayTmp[i]);
@@ -125354,6 +125525,19 @@ class MmcifParser {
125354
125525
  await ic.opmParserCls.loadOpmData(data, mmcifid, undefined, 'mmcif', undefined, bText);
125355
125526
  }
125356
125527
 
125528
+ async downloadCod(codid) { let ic = this.icn3d, me = ic.icn3dui;
125529
+ //ic.bCid = undefined;
125530
+
125531
+ ic.ParserUtilsCls.setYourNote(codid.toUpperCase() + '(COD) in iCn3D');
125532
+
125533
+ let url = "https://www.crystallography.net/cod/" + codid + ".cif";
125534
+ // let url = "https://www.crystallography.net/cif/1/00/00/1000041.cif";
125535
+ let data = await me.getAjaxPromise(url, 'text', true);
125536
+
125537
+ let bText = true;
125538
+ ic.loadCIFCls.loadCIF(data, codid, bText);
125539
+ }
125540
+
125357
125541
  async downloadMmcifSymmetry(mmcifid, type) { let ic = this.icn3d, me = ic.icn3dui;
125358
125542
  try {
125359
125543
  // let url = "https://files.rcsb.org/download/" + mmcifid + ".cif";
@@ -125467,6 +125651,11 @@ class MmcifParser {
125467
125651
  ic.opts['color'] = 'structure';
125468
125652
  }
125469
125653
 
125654
+ if(Object.keys(ic.proteins).length == 0 || Object.keys(ic.nucleotides).length == 0) {
125655
+ ic.pk = 1;
125656
+ ic.opts['pk'] = 'atom';
125657
+ }
125658
+
125470
125659
  ic.opmParserCls.modifyUIMapAssembly();
125471
125660
 
125472
125661
  await ic.pdbParserCls.addSecondary(bAppend);
@@ -125560,9 +125749,10 @@ class MmdbParser {
125560
125749
  me.cfg.query_id = idArray[0];
125561
125750
  me.cfg.blast_rep_id = idArray[1];
125562
125751
 
125563
- let mmdbid = me.cfg.blast_rep_id.split('_')[0]; // 1TSR_A, XP_003256700.1, Q9H3D4.1
125752
+ let textArray = me.utilsCls.getIdArray(me.cfg.blast_rep_id);
125753
+ let mmdbid = textArray[0]; // 1TSR_A, XP_003256700.1, Q9H3D4.1
125564
125754
 
125565
- if(mmdbid.length == 4) { // pdb
125755
+ if(mmdbid.length == 4 || mmdbid.indexOf('pdb_') == 0) { // pdb
125566
125756
  await this.downloadMmdb(mmdbid);
125567
125757
  }
125568
125758
  else {
@@ -125714,7 +125904,7 @@ class MmdbParser {
125714
125904
  if(ic.chainid2sid[chainid] == me.cfg.ligand.substr(3)) {
125715
125905
  // save a set named me.cfg.ligand
125716
125906
  let residueHash = ic.firstAtomObjCls.getResiduesFromAtoms(ic.chains[chainid]);
125717
- let idArray = Object.keys(residueHash)[0].split('_');
125907
+ let idArray = me.utilsCls.getIdArray(Object.keys(residueHash)[0]);
125718
125908
  let select = '.' + idArray[1] + ':' + idArray[2];
125719
125909
 
125720
125910
  await ic.selByCommCls.selectByCommand(select, me.cfg.ligand, me.cfg.ligand);
@@ -126091,7 +126281,7 @@ class BcifParser {
126091
126281
 
126092
126282
  if (parsed.isError) {
126093
126283
  // report error:
126094
- var aaa = 1; //alert("The Binary CIF data can NOT be parsed: " + parsed.toString());
126284
+ var aaa = 1; //alert("1 The Binary CIF data can NOT be parsed: " + parsed.toString());
126095
126285
  return;
126096
126286
  }
126097
126287
 
@@ -127056,7 +127246,8 @@ class OpmParser {
127056
127246
  if(!pdbid) pdbid = ic.defaultPdbId;
127057
127247
 
127058
127248
  //if(me.cfg.mmtfid === undefined && me.cfg.bcifid === undefined) { // skip opm for bcif files
127059
- let url = me.htmlCls.baseUrl + "mmdb/mmdb_strview.cgi?v=2&program=icn3d&opm&uid=" + pdbid.toLowerCase();
127249
+ let shortPdbid = pdbid.indexOf('pdb_0000') == 0 ? pdbid.substr(8) : pdbid;
127250
+ let url = me.htmlCls.baseUrl + "mmdb/mmdb_strview.cgi?v=2&program=icn3d&opm&uid=" + shortPdbid.toLowerCase();
127060
127251
 
127061
127252
  let opmdata = await me.getAjaxPromise(url, 'jsonp', false);
127062
127253
 
@@ -128132,7 +128323,7 @@ class DcdParser {
128132
128323
  }
128133
128324
 
128134
128325
  for(let j in residuesOri) {
128135
- let idArray = j.split('_');
128326
+ let idArray = me.utilsCls.getIdArray(j);
128136
128327
  let structure2 = idArray[0] + molNum;
128137
128328
  let residid2 = structure2 + '_' + idArray[1] + '_' + idArray[2];
128138
128329
  ic.residues[residid2] = {};
@@ -128143,7 +128334,7 @@ class DcdParser {
128143
128334
  }
128144
128335
 
128145
128336
  for(let j in chainsOri) {
128146
- let idArray = j.split('_');
128337
+ let idArray = me.utilsCls.getIdArray(j);
128147
128338
  let structure2 = idArray[0] + molNum;
128148
128339
  let chainid2 = structure2 + '_' + idArray[1];
128149
128340
 
@@ -128174,7 +128365,7 @@ class DcdParser {
128174
128365
 
128175
128366
  // set ic.ncbi2resid and ic.resid2ncbi
128176
128367
  for(let chainid in chainsOri) {
128177
- let idArray = chainid.split('_');
128368
+ let idArray = me.utilsCls.getIdArray(chainid);
128178
128369
  let structure2 = idArray[0] + molNum;
128179
128370
  let chainid2 = structure2 + '_' + idArray[1];
128180
128371
 
@@ -128738,7 +128929,7 @@ class XtcParser {
128738
128929
  }
128739
128930
 
128740
128931
  for(let j in residuesOri) {
128741
- let idArray = j.split('_');
128932
+ let idArray = me.utilsCls.getIdArray(j);
128742
128933
  let structure2 = idArray[0] + molNum;
128743
128934
  let residid2 = structure2 + '_' + idArray[1] + '_' + idArray[2];
128744
128935
  ic.residues[residid2] = {};
@@ -128749,7 +128940,7 @@ class XtcParser {
128749
128940
  }
128750
128941
 
128751
128942
  for(let j in chainsOri) {
128752
- let idArray = j.split('_');
128943
+ let idArray = me.utilsCls.getIdArray(j);
128753
128944
  let structure2 = idArray[0] + molNum;
128754
128945
  let chainid2 = structure2 + '_' + idArray[1];
128755
128946
 
@@ -128780,7 +128971,7 @@ class XtcParser {
128780
128971
 
128781
128972
  // set ic.ncbi2resid and ic.resid2ncbi
128782
128973
  for(let chainid in chainsOri) {
128783
- let idArray = chainid.split('_');
128974
+ let idArray = me.utilsCls.getIdArray(chainid);
128784
128975
  let structure2 = idArray[0] + molNum;
128785
128976
  let chainid2 = structure2 + '_' + idArray[1];
128786
128977
 
@@ -129006,9 +129197,8 @@ class MsaParser {
129006
129197
 
129007
129198
  // realign based on residue by residue
129008
129199
  let alignment_final = ic.inputChainidArray.join(',');
129009
-
129010
129200
  if(predefinedres && (alignment_final.split(',').length - 1) != predefinedres.split(': ').length) {
129011
- var aaa = 1; //alert("Please make sure the number of chains and the lines of predefined residues are the same...");
129201
+ var aaa = 1; //alert("Please make sure the number of chains " + (alignment_final.split(',').length - 1) + " and the lines of predefined residues " + predefinedres.split(': ').length + " are the same...");
129012
129202
  return;
129013
129203
  }
129014
129204
 
@@ -129066,7 +129256,7 @@ class MsaParser {
129066
129256
  }
129067
129257
 
129068
129258
  if(type == 'clustalw') {
129069
- if(line.substr(0, 1) != ' ' && line.substr(0, 1) != '\t') {
129259
+ if(line.substr(0, 1) != '.' && line.substr(0, 1) != '*') {
129070
129260
  let chainid_seq = line.split(/\s+/);
129071
129261
  let idArray = chainid_seq[0].split('|');
129072
129262
  let result = this.getChainid(idArray, bStart && !bSecBlock);
@@ -129091,9 +129281,11 @@ class MsaParser {
129091
129281
  seq = '';
129092
129282
 
129093
129283
  let pos = line.indexOf(' ');
129284
+ if(pos == -1) pos = line.length;
129094
129285
  let idArray = line.substr(1, pos).split('|');
129095
-
129286
+
129096
129287
  if(idArray.length == 1) {
129288
+ bFound = true;
129097
129289
  chainid = idArray[0];
129098
129290
  }
129099
129291
  else {
@@ -129157,8 +129349,9 @@ class MsaParser {
129157
129349
  ic.inputChainidArray.push(chainid + '_A');
129158
129350
  }
129159
129351
  }
129160
- else if(chainid.indexOf('_') != -1) { // PDB ID
129161
- let stru = chainid.substr(0, chainid.indexOf('_')).substr(0, 4);
129352
+ else if(chainid.indexOf('_') != -1 || chainid.indexOf('pdb_') != -1) { // PDB ID
129353
+ let idArray = me.utilsCls.getIdArray(chainid);
129354
+ let stru = idArray[0];
129162
129355
  ic.struArray.push(stru);
129163
129356
  ic.inputChainidArray.push(chainid);
129164
129357
  }
@@ -129240,7 +129433,7 @@ class RealignParser {
129240
129433
  }
129241
129434
 
129242
129435
  // ic.realignResid[chainid].push({'resid': chainid + '_' + atom.resi, 'resn': me.utilsCls.residueName2Abbr(atom.resn.substr(0, 3)).substr(0, 1)});
129243
- ic.realignResid[chainid].push({'resid': chainid + '_' + atom.resi, 'resn': me.utilsCls.residueName2Abbr(atom.resn).substr(0, 1)});
129436
+ ic.realignResid[chainid].push({'resid': chainid + '_' + atom.resi, 'resn': me.utilsCls.residueName2Abbr(atom.resn, true)});
129244
129437
 
129245
129438
  struct2chain[atom.structure] = atom.structure + '_' + atom.chain;
129246
129439
 
@@ -129283,7 +129476,8 @@ class RealignParser {
129283
129476
 
129284
129477
  async parseChainRealignPredefined(chainidArray, struct2SeqHash, struct2CoorHash, struct2resid) { let ic = this.icn3d, me = ic.icn3dui;
129285
129478
 
129286
- let toStruct = chainidArray[0].substr(0, chainidArray[0].indexOf('_')); //.toUpperCase();
129479
+ let itemArray1 = me.utilsCls.getIdArray(chainidArray[0]);
129480
+ let toStruct = itemArray1[0];
129287
129481
 
129288
129482
  let hAtoms = {}, rmsd;
129289
129483
 
@@ -129296,13 +129490,14 @@ class RealignParser {
129296
129490
  ic.qt_start_end = [];
129297
129491
 
129298
129492
  let chainidHash = {};
129299
- for(let index = 0, indexl = chainidArray.length - 1; index < indexl; ++index) {
129300
- let fromStruct = chainidArray[index + 1].substr(0, chainidArray[index + 1].indexOf('_')); //.toUpperCase();
129493
+ for(let index = 0, indexl = chainidArray.length - 1; index < indexl; ++index) {
129494
+ let itemArray2 = me.utilsCls.getIdArray(chainidArray[index + 1]);
129495
+ let fromStruct = itemArray2[0];
129301
129496
 
129302
129497
  //if(toStruct == fromStruct) fromStruct += me.htmlCls.postfix;
129303
129498
 
129304
- let chainTo = toStruct + chainidArray[0].substr(chainidArray[0].indexOf('_'));
129305
- let chainFrom = fromStruct + chainidArray[index + 1].substr(chainidArray[index + 1].indexOf('_'));
129499
+ let chainTo = toStruct + '_' + itemArray1[1];
129500
+ let chainFrom = fromStruct + '_' + itemArray2[1];
129306
129501
  chainidHash[chainTo] = 1;
129307
129502
  chainidHash[chainFrom] = 1;
129308
129503
 
@@ -129337,7 +129532,7 @@ class RealignParser {
129337
129532
 
129338
129533
  hAtoms = me.hashUtilsCls.unionHash(hAtoms, result.hAtoms);
129339
129534
  rmsd = parseFloat(result.rmsd);
129340
- }
129535
+ }
129341
129536
 
129342
129537
  // If rmsd from vastsrv is too large, realign the chains
129343
129538
  //if(me.cfg.chainalign && !me.cfg.usepdbnum && me.cfg.resdef && rmsd > 5) {
@@ -129559,15 +129754,6 @@ class RealignParser {
129559
129754
  prevChainid = chainidArrayTmp[i];
129560
129755
  }
129561
129756
 
129562
- // use the model from Membranome as template
129563
- // if(ic.bAfMem && chainidArray.length == 2) {
129564
- // if(chainidArray[1].split('_')[0] == pdbidTemplate) {
129565
- // let tmp = chainidArray[0];
129566
- // chainidArray[0] = chainidArray[1];
129567
- // chainidArray[1] = tmp;
129568
- // }
129569
- // }
129570
-
129571
129757
  let bRealign = true;
129572
129758
  ic.qt_start_end = []; // reset the alignment
129573
129759
 
@@ -129812,12 +129998,12 @@ let resRangeArray = (me.cfg.resrange) ? decodeURIComponent(me.cfg.resrange).spli
129812
129998
  let predefinedResArray, predefinedResPair;
129813
129999
 
129814
130000
  if(bPredefined) {
129815
- me.cfg.resdef.replace(/; /gi, ': ');
129816
- predefinedResArray = decodeURIComponent(me.cfg.resdef).trim().replace(/\+/gi, ' ').split(': ');
129817
- // predefinedResArray = decodeURIComponent(me.cfg.resdef).trim().replace(/\+/gi, ' ').split('; ');
129818
-
130001
+ let tmpStr = me.cfg.resdef.replace(/; /gi, ': ');
130002
+ // predefinedResArray = decodeURIComponent(tmpStr).trim().replace(/\+/gi, ' ').split(': ');
130003
+ predefinedResArray = tmpStr.replace(/\+/gi, ' ').split(': ');
130004
+
129819
130005
  if(predefinedResArray.length != chainidArray.length - 1) {
129820
- var aaa = 1; //alert("Please make sure the number of chains and the lines of predefined residues are the same...");
130006
+ var aaa = 1; //alert("Please make sure the number of chains " + (chainidArray.length - 1) + " and the lines of predefined residues " + predefinedResArray.length + " are the same...");
129821
130007
  return;
129822
130008
  }
129823
130009
  }
@@ -129826,8 +130012,8 @@ let resRangeArray = (me.cfg.resrange) ? decodeURIComponent(me.cfg.resrange).spli
129826
130012
  for(let i = 0, il = chainidArray.length; i < il; ++i) {
129827
130013
  //if(bPredefined) predefinedRes = predefinedResArray[i].trim();
129828
130014
 
129829
- let pos = chainidArray[i].indexOf('_');
129830
- let mmdbid = chainidArray[i].substr(0, pos); //.toUpperCase();
130015
+ let itemArray = me.utilsCls.getIdArray(chainidArray[i]);
130016
+ let mmdbid = itemArray[0]; //.toUpperCase();
129831
130017
 
129832
130018
  // if(!bRealign) mmdbid = mmdbid.toUpperCase();
129833
130019
 
@@ -129835,7 +130021,7 @@ let resRangeArray = (me.cfg.resrange) ? decodeURIComponent(me.cfg.resrange).spli
129835
130021
  mmdbid_t = mmdbid;
129836
130022
  }
129837
130023
 
129838
- let chainid = mmdbid + chainidArray[i].substr(pos);
130024
+ let chainid = mmdbid + '_' + itemArray[1];
129839
130025
  if(i == 0) chainid_t = chainid;
129840
130026
 
129841
130027
  if(!ic.chainsSeq || !ic.chainsSeq[chainid]) {
@@ -129864,7 +130050,7 @@ let resRangeArray = (me.cfg.resrange) ? decodeURIComponent(me.cfg.resrange).spli
129864
130050
  if(!struct2CoorHash[chainidpair]) struct2CoorHash[chainidpair] = {};
129865
130051
  if(!struct2resid[chainidpair]) struct2resid[chainidpair] = {};
129866
130052
 
129867
- // master
130053
+ // template
129868
130054
  resiArray = predefinedResPair[0].split(",");
129869
130055
 
129870
130056
  result = thisClass.getSeqCoorResid(resiArray, chainid_t);
@@ -129879,7 +130065,7 @@ let resRangeArray = (me.cfg.resrange) ? decodeURIComponent(me.cfg.resrange).spli
129879
130065
  struct2CoorHash[chainidpair][mmdbid_t] = struct2CoorHash[chainidpair][mmdbid_t].concat(result.coor);
129880
130066
  struct2resid[chainidpair][mmdbid_t] = struct2resid[chainidpair][mmdbid_t].concat(result.resid);
129881
130067
 
129882
- // slave
130068
+ // query
129883
130069
  resiArray = predefinedResPair[1].split(",");
129884
130070
 
129885
130071
  result = thisClass.getSeqCoorResid(resiArray, chainid);
@@ -129907,7 +130093,7 @@ let resRangeArray = (me.cfg.resrange) ? decodeURIComponent(me.cfg.resrange).spli
129907
130093
  }
129908
130094
  }
129909
130095
  else {
129910
- if(i == 0) { // master
130096
+ if(i == 0) { // template
129911
130097
  //base = parseInt(ic.chainsSeq[chainid][0].resi);
129912
130098
 
129913
130099
  resiArray = [];
@@ -129947,7 +130133,7 @@ let resRangeArray = (me.cfg.resrange) ? decodeURIComponent(me.cfg.resrange).spli
129947
130133
  bSelectedBoth = true;
129948
130134
 
129949
130135
  let resn = ic.firstAtomObjCls.getFirstAtomObj(ic.residues[resid]).resn;
129950
- struct2SeqHash[chainid] += me.utilsCls.residueName2Abbr(resn);
130136
+ struct2SeqHash[chainid] += me.utilsCls.residueName2Abbr(resn, true);
129951
130137
 
129952
130138
  struct2CoorHash[chainid] = struct2CoorHash[chainid].concat(this.getResCoorArray(resid));
129953
130139
 
@@ -132262,9 +132448,6 @@ class LoadAtomData {
132262
132448
  atm.coord = new Vector3$1(atm.coord.x, atm.coord.y, atm.coord.z);
132263
132449
  }
132264
132450
 
132265
- // let oneLetterRes = me.utilsCls.residueName2Abbr(atm.resn.substr(0, 3));
132266
- let oneLetterRes = me.utilsCls.residueName2Abbr(atm.resn);
132267
-
132268
132451
  if((type === 'mmdbid' || type === 'align') && ic.bFullUi ) {
132269
132452
  // set ic.mmdbMolidResid2mmdbChainResi
132270
132453
  if(ic.mmdbMolidResid2mmdbChainResi === undefined) ic.mmdbMolidResid2mmdbChainResi = {};
@@ -132406,6 +132589,8 @@ class LoadAtomData {
132406
132589
  }
132407
132590
  }
132408
132591
 
132592
+ // let oneLetterRes = me.utilsCls.residueName2Abbr(atm.resn.substr(0, 3));
132593
+ let oneLetterRes = (atm.het) ? me.utilsCls.residueName2Abbr(atm.resn) : me.utilsCls.residueName2Abbr(atm.resn, true);
132409
132594
  ic.residueId2Name[residueid] = oneLetterRes;
132410
132595
 
132411
132596
  let secondaries = '-';
@@ -132753,11 +132938,11 @@ class SetSeqAlign {
132753
132938
  ic.nconsHash2 = {};
132754
132939
  ic.nalignHash2 = {};
132755
132940
 
132756
- let msaSameColor = [];
132757
- // assume all aligned seq are the same. If any aligned res is different,set it to false (0)
132758
- for(let i = 0, il = seqalign[0].length; i < il; ++i) {
132759
- msaSameColor.push(1);
132760
- }
132941
+ // let msaSameColor = [];
132942
+ // // assume all aligned seq are the same. If any aligned res is different,set it to false (0)
132943
+ // for(let i = 0, il = seqalign[0].length; i < il; ++i) {
132944
+ // msaSameColor.push(1);
132945
+ // }
132761
132946
 
132762
132947
  for(let i = 0, il = seqalign.length; i < il; ++i) {
132763
132948
  // first sequence
@@ -132766,44 +132951,30 @@ class SetSeqAlign {
132766
132951
 
132767
132952
  let chain1 = ic.pdbid_molid2chain[mmdbid1 + '_' + molid1];
132768
132953
  chainid1 = mmdbid1 + '_' + chain1;
132769
-
132770
- let id2aligninfo = {};
132771
- let start = alignData.sequence.length, end = -1;
132772
- let bStart = false;
132954
+ alignData.sequence.length;
132773
132955
  for(let j = 0, jl = alignData.sequence.length; j < jl; ++j) {
132774
132956
  // 0: internal resi id, 1: pdb resi id, 2: resn, 3: aligned or not
132775
- let resi =(ic.bUsePdbNum) ? ic.ParserUtilsCls.getResi(chainid1, alignData.sequence[j][0] - 1) : alignData.sequence[j][0];
132776
- let resn =(alignData.sequence[j][2] === '~') ? '-' : alignData.sequence[j][2];
132777
- resn =(resn === ' ' || resn === '') ? 'X' : resn;
132778
-
132779
- let aligned =(alignData.sequence[j][3]) ? 1 : 0;
132780
-
132781
- if(aligned == 1) {
132782
- if(j < start && !bStart) {
132783
- start = j;
132784
- bStart = true; // set start just once
132785
- }
132786
- if(j > end) end = j;
132787
- }
132957
+ (ic.bUsePdbNum) ? ic.ParserUtilsCls.getResi(chainid1, alignData.sequence[j][0] - 1) : alignData.sequence[j][0];
132958
+ (alignData.sequence[j][2] === '~') ? '-' : alignData.sequence[j][2];
132788
132959
 
132789
- id2aligninfo[j] = {"resi": resi, "resn": resn, "aligned": aligned};
132960
+ (alignData.sequence[j][3]) ? 1 : 0;
132790
132961
  }
132791
132962
 
132792
132963
  // second sequence
132793
132964
  alignData = seqalign[i][1];
132794
132965
 
132795
- for(let j = start; j <= end; ++j) {
132796
- // 0: internal resi id, 1: pdb resi id, 2: resn, 3: aligned or not
132797
- let alignedTmp =(alignData.sequence[j][3]) ? 1 : 0;
132966
+ // for(let j = start; j <= end; ++j) {
132967
+ // // 0: internal resi id, 1: pdb resi id, 2: resn, 3: aligned or not
132968
+ // let alignedTmp =(alignData.sequence[j][3]) ? 1 : 0;
132798
132969
 
132799
- let aligned = id2aligninfo[j].aligned + alignedTmp; // 0 or 2
132970
+ // let aligned = id2aligninfo[j].aligned + alignedTmp; // 0 or 2
132800
132971
 
132801
- if(aligned === 2) { // aligned
132802
- if(id2aligninfo[j].resn != resn) {
132803
- msaSameColor[j] = 0;
132804
- }
132805
- }
132806
- }
132972
+ // if(aligned === 2) { // aligned
132973
+ // if(id2aligninfo[j].resn != resn) {
132974
+ // msaSameColor[j] = 0;
132975
+ // }
132976
+ // }
132977
+ // }
132807
132978
  }
132808
132979
 
132809
132980
  for(let i = 0, il = seqalign.length; i < il; ++i) {
@@ -132902,7 +133073,7 @@ class SetSeqAlign {
132902
133073
  ic.nconsHash2[chainid2 + '_' + resi] = 1;
132903
133074
  }
132904
133075
 
132905
- color = (msaSameColor[j] == 0) ? '#0000FF' : '#FF0000';
133076
+ // color = (msaSameColor[j] == 0) ? '#0000FF' : '#FF0000';
132906
133077
 
132907
133078
  // mapping, use the firstsequence as the reference structure
132908
133079
  ic.chainsMapping[chainid1][chainid1 + '_' + id2aligninfo[j].resi] = id2aligninfo[j].resn + id2aligninfo[j].resi;
@@ -132921,7 +133092,7 @@ class SetSeqAlign {
132921
133092
  ic.nalignHash1[chainid1 + '_' + id2aligninfo[j].resi] = 1;
132922
133093
  ic.nalignHash2[chainid2 + '_' + resi] = 1;
132923
133094
 
132924
- msaSameColor[j] = 2; // not aligned
133095
+ // msaSameColor[j] = 2; // not aligned
132925
133096
  }
132926
133097
 
132927
133098
  // chain1
@@ -133046,8 +133217,7 @@ class SetSeqAlign {
133046
133217
  return pos;
133047
133218
  }
133048
133219
 
133049
- getResnFromResi(chainid, resi) { let ic = this.icn3d; ic.icn3dui;
133050
- /*
133220
+ getResnFromResi(chainid, resi) { let ic = this.icn3d, me = ic.icn3dui;
133051
133221
  let pos = this.getPosFromResi(chainid, resi);
133052
133222
  if(!pos) return '?';
133053
133223
 
@@ -133062,8 +133232,8 @@ class SetSeqAlign {
133062
133232
  }
133063
133233
 
133064
133234
  return resn;
133065
- */
133066
133235
 
133236
+ /*
133067
133237
  let resid = chainid + '_' + resi;
133068
133238
  let resn = ic.residueId2Name[resid];
133069
133239
  if(!resn) {
@@ -133071,6 +133241,7 @@ class SetSeqAlign {
133071
133241
  }
133072
133242
 
133073
133243
  return resn;
133244
+ */
133074
133245
  }
133075
133246
 
133076
133247
  getResiAferAlign(chainid, bRealign, pos) { let ic = this.icn3d, me = ic.icn3dui;
@@ -133415,7 +133586,7 @@ class SetSeqAlign {
133415
133586
  let start1, end1;
133416
133587
 
133417
133588
  //ic.qt_start_end is zero-based
133418
- if(!bRealign && me.cfg.aligntool != 'tmalign') { // vast alignment
133589
+ if(!bRealign && me.cfg.aligntool != 'tmalign') { // vast alignment or seqalign
133419
133590
  start1 = parseInt(ic.qt_start_end[chainIndex][i].t_start) - 1;
133420
133591
  end1 = parseInt(ic.qt_start_end[chainIndex][i].t_end) - 1;
133421
133592
  }
@@ -133450,15 +133621,18 @@ class SetSeqAlign {
133450
133621
 
133451
133622
  let resid2rangeArray = Object.keys(resid2range_t);
133452
133623
  resid2rangeArray.sort(function(a, b) {
133453
- return parseInt(a.split('_')[2]) - parseInt(b.split('_')[2]);
133624
+ let idArray1 = me.utilsCls.getIdArray(a);
133625
+ let idArray2 = me.utilsCls.getIdArray(b);
133626
+ return parseInt(idArray1[2]) - parseInt(idArray2[2]);
133454
133627
  });
133455
133628
 
133456
133629
  // assign range to each resi
133457
133630
  let prevResi = -999, start = 0, end = 0, residArray = [], prevEnd = 0;
133458
133631
  for(let i = 0, il = resid2rangeArray.length; i < il; ++i) {
133459
133632
  let resid = resid2rangeArray[i];
133460
- let resi = resid.split('_')[2];
133461
-
133633
+ let idArray = me.utilsCls.getIdArray(resid);
133634
+ let resi = idArray[2];
133635
+
133462
133636
  if(i == 0) {
133463
133637
  start = resi;
133464
133638
  }
@@ -133497,7 +133671,9 @@ class SetSeqAlign {
133497
133671
  let resid = chainid1 + '_' + resi;
133498
133672
 
133499
133673
  // let jAdjusted = (me.cfg.aligntool != 'tmalign') ? j : j + baseResi;
133500
- let jAdjusted = ic.ParserUtilsCls.getResiNCBI(chainid1, resi) - 1;
133674
+ //let jAdjusted = ic.ParserUtilsCls.getResiNCBI(chainid1, resi) - 1;
133675
+ //!!!
133676
+ let jAdjusted = (me.cfg.aligntool != 'tmalign') ? j : ic.ParserUtilsCls.getResiNCBI(chainid1, resi) - 1;
133501
133677
 
133502
133678
  //if(j + baseResi < start_t || j + baseResi > end_t) {
133503
133679
  if(jAdjusted < start_t || jAdjusted > end_t) {
@@ -133698,21 +133874,23 @@ class SetSeqAlign {
133698
133874
  }
133699
133875
  }
133700
133876
 
133701
- getTemplatePosFromOriResi(chainid1, start, end, bRealign) { let ic = this.icn3d, me = ic.icn3dui;
133702
- // let startResi = ic.ParserUtilsCls.getResi(chainid1, start);
133703
- // let endResi = ic.ParserUtilsCls.getResi(chainid1, end);
133704
- if(bRealign && me.cfg.aligntool == 'tmalign') { // vast alignment
133705
- let startResi = start;
133706
- let endResi = end;
133877
+ getTemplatePosFromOriPos(chainid1, start, end, bRealign) { let ic = this.icn3d; ic.icn3dui;
133878
+ //!!!
133879
+ let startResi = ic.ParserUtilsCls.getResi(chainid1, start);
133880
+ let endResi = ic.ParserUtilsCls.getResi(chainid1, end);
133881
+
133882
+ // if(bRealign && me.cfg.aligntool == 'tmalign') { // vast alignment
133883
+ // let startResi = start;
133884
+ // let endResi = end;
133707
133885
 
133708
133886
  let result1 = this.getResiPosInTemplate(chainid1, startResi);
133709
133887
  let result2 = this.getResiPosInTemplate(chainid1, endResi);
133710
133888
 
133711
133889
  return {"pos1": result1.pos, "pos2": result2.pos};
133712
- }
133713
- else {
133714
- return {"pos1": start, "pos2": end};
133715
- }
133890
+ // }
133891
+ // else {
133892
+ // return {"pos1": start, "pos2": end};
133893
+ // }
133716
133894
  }
133717
133895
 
133718
133896
  mergeTwoSeqForAll(chainidArray, index, alignedChainIndice, resid2range_t, start_t, end_t, bRealign) { let ic = this.icn3d, me = ic.icn3dui;
@@ -133784,11 +133962,11 @@ class SetSeqAlign {
133784
133962
  start_t = ic.ParserUtilsCls.getResi(chainid1, start_t);
133785
133963
  end_t = ic.ParserUtilsCls.getResi(chainid1, end_t);
133786
133964
  }
133787
-
133965
+ console.log("### me.cfg.aligntool " + me.cfg.aligntool + " bRealign " + bRealign );
133788
133966
  for(let i = 0, il = ic.qt_start_end[chainIndex].length; i < il; ++i) {
133789
- let start1, start2, end1, end2, resiStart1, start1Pos;
133967
+ let start1, start2, end1, end2, resiStart1, start1Pos, end1Pos;
133790
133968
 
133791
- if(bRealign && me.cfg.aligntool == 'tmalign') { // real residue numbers are stored
133969
+ if(bRealign && (me.cfg.aligntool == 'tmalign')) { // real residue numbers are stored
133792
133970
  start1 = parseInt(ic.qt_start_end[chainIndex][i].t_start);
133793
133971
  start2 = parseInt(ic.qt_start_end[chainIndex][i].q_start);
133794
133972
  end1 = parseInt(ic.qt_start_end[chainIndex][i].t_end);
@@ -133802,7 +133980,7 @@ class SetSeqAlign {
133802
133980
  // 1. before the mapped residues
133803
133981
  resiStart1 = start1;
133804
133982
  start1Pos = this.getPosFromResi(chainid1, ic.qt_start_end[chainIndex][i].t_start);
133805
- this.getPosFromResi(chainid1, ic.qt_start_end[chainIndex][i].t_end);
133983
+ end1Pos = this.getPosFromResi(chainid1, ic.qt_start_end[chainIndex][i].t_end);
133806
133984
  }
133807
133985
  else {
133808
133986
  start1 = parseInt(ic.qt_start_end[chainIndex][i].t_start - 1);
@@ -133813,6 +133991,7 @@ class SetSeqAlign {
133813
133991
  // 1. before the mapped residues
133814
133992
  resiStart1 = ic.ParserUtilsCls.getResi(chainid1, start1);
133815
133993
  start1Pos = start1;
133994
+ end1Pos = end1;
133816
133995
  }
133817
133996
  //let range = resid2range_t[chainid1 + '_' + resiStart1];
133818
133997
 
@@ -133820,13 +133999,15 @@ class SetSeqAlign {
133820
133999
  if(i == 0) {
133821
134000
  startPosInTemplate = start1Pos;
133822
134001
 
133823
- result = this.getTemplatePosFromOriResi(chainid1, start_t, start1, bRealign);
133824
- //result = this.getTemplatePosFromOriResi(chainid1, start_t, start1Pos, bRealign);
134002
+ //!!!
134003
+ // result = this.getTemplatePosFromOriPos(chainid1, start_t, start1, bRealign);
134004
+ result = this.getTemplatePosFromOriPos(chainid1, start_t, start1Pos, bRealign);
133825
134005
  pos1 = result.pos1;
133826
134006
  pos2 = result.pos2;
133827
134007
 
133828
- if(start1 > start_t) {
133829
- //if(start1Pos > start_t) {
134008
+ //!!!
134009
+ // if(start1 > start_t) {
134010
+ if(start1Pos > start_t) {
133830
134011
  for(let j = 0, jl = pos2 - pos1; j < jl; ++j) {
133831
134012
  ic.alnChainsSeq[chainid2].push(gapResObject2);
133832
134013
  }
@@ -133834,7 +134015,7 @@ class SetSeqAlign {
133834
134015
  }
133835
134016
  else {
133836
134017
  //let notAlnLen1 = start1 - (prevIndex1 + 1);
133837
- result = this.getTemplatePosFromOriResi(chainid1, prevIndex1, start1, bRealign);
134018
+ result = this.getTemplatePosFromOriPos(chainid1, prevIndex1, start1, bRealign);
133838
134019
  pos1 = result.pos1;
133839
134020
  pos2 = result.pos2;
133840
134021
  let notAlnLen1 = pos2 - (pos1 + 1);
@@ -133859,15 +134040,16 @@ class SetSeqAlign {
133859
134040
  }
133860
134041
 
133861
134042
  // 2. In the mapped residues
133862
- result = this.getTemplatePosFromOriResi(chainid1, start1, end1, bRealign);
133863
- //result = this.getTemplatePosFromOriResi(chainid1, start1Pos, end1Pos, bRealign);
134043
+ // result = this.getTemplatePosFromOriPos(chainid1, start1, end1, bRealign);
134044
+ result = this.getTemplatePosFromOriPos(chainid1, start1Pos, end1Pos, bRealign);
133864
134045
  pos1 = result.pos1;
133865
134046
  pos2 = result.pos2;
133866
134047
 
133867
134048
  let k = 0;
133868
134049
  if(!ic.chainsMapping[chainid1]) ic.chainsMapping[chainid1] = {};
133869
134050
  if(!ic.chainsMapping[chainid2]) ic.chainsMapping[chainid2] = {};
133870
- let resiAdjust = (bRealign && me.cfg.aligntool == 'tmalign') ? 0 : - startPosInTemplate + nGapInTemplate;
134051
+ //!!!!!!
134052
+ let resiAdjust = ((bRealign && me.cfg.aligntool == 'tmalign') || me.cfg.aligntool == 'seqalign') ? 0 : - startPosInTemplate + nGapInTemplate;
133871
134053
  for(let j = pos1; j <= pos2; ++j) {
133872
134054
  // inherit the gaps from the template
133873
134055
  if(ic.alnChainsSeq[chainid1][j + resiAdjust].resn == '-') {
@@ -133902,7 +134084,7 @@ class SetSeqAlign {
133902
134084
  }
133903
134085
 
133904
134086
  // add gaps at the end
133905
- result = this.getTemplatePosFromOriResi(chainid1, prevIndex1, end_t, bRealign);
134087
+ result = this.getTemplatePosFromOriPos(chainid1, prevIndex1, end_t, bRealign);
133906
134088
  pos1 = result.pos1;
133907
134089
  pos2 = result.pos2;
133908
134090
  for(let i = pos1; i < pos2; ++i) {
@@ -134238,7 +134420,7 @@ class SetSeqAlign {
134238
134420
  }
134239
134421
  }
134240
134422
 
134241
- setMsaFormat(chainidArray) { let ic = this.icn3d; ic.icn3dui;
134423
+ setMsaFormat(chainidArray) { let ic = this.icn3d, me = ic.icn3dui;
134242
134424
  //set MSA
134243
134425
  let fastaFormat = '', clustalwFormat = 'CLUSTALWW\n\n', resbyresFormat = '';
134244
134426
  let chainArrayClustal = [];
@@ -134250,7 +134432,9 @@ class SetSeqAlign {
134250
134432
  fastaFormat += '>' + chainid + '\n';
134251
134433
 
134252
134434
  let clustalwArray = [];
134253
- let clustalwLine = chainid.padEnd(20, ' ');
134435
+ let itemArray = me.utilsCls.getIdArray(chainid);
134436
+ let chainidStr = 'pdb|' + itemArray[0] + '|' + itemArray[1];
134437
+ let clustalwLine = chainidStr.padEnd(20, ' ');
134254
134438
  let consLine = ''.padEnd(20, ' ');
134255
134439
 
134256
134440
  let resiArrayTarget = [], resiArrayQuery = [];
@@ -134790,7 +134974,7 @@ class LoadPDB {
134790
134974
  //if(residueNum !== prevResidueNum) {
134791
134975
 
134792
134976
  if(oriResidueNum !== prevOriResidueNum) {
134793
- let residue = me.utilsCls.residueName2Abbr(resn);
134977
+ let residue = (atomDetails.het) ? me.utilsCls.residueName2Abbr(resn) : me.utilsCls.residueName2Abbr(resn, true);
134794
134978
  ic.residueId2Name[residueNum] = residue;
134795
134979
 
134796
134980
  if(serial !== 1 && prevResidueNum !== '') ic.residues[prevResidueNum] = residuesTmp;
@@ -135237,7 +135421,7 @@ class LoadPDB {
135237
135421
 
135238
135422
  for(let chainid in chains) {
135239
135423
  if(pdbid !== undefined) {
135240
- let textArray = chainid.split('_');
135424
+ let textArray = me.utilsCls.getIdArray(chainid);
135241
135425
  if(textArray[0] !== pdbid) continue; // skip different chain
135242
135426
  }
135243
135427
 
@@ -135345,15 +135529,15 @@ class LoadCIF {
135345
135529
  loadCIF(bcifData, bcifid, bText, bAppend, supercell) { let ic = this.icn3d, me = ic.icn3dui;
135346
135530
  ic.cifText = bText;
135347
135531
  ic.cifData = bcifData;
135348
-
135532
+
135349
135533
  if(supercell === undefined) {
135350
- CIFTools.Text.coreCifOptions = { nx: 1, ny: 1, nz: 1, boundary: true };
135534
+ CIFTools.Text.coreCifOptions = { nx: 1, ny: 1, nz: 1, boundary: true, wholeMolecules: true, bondTolerance: 0.4 };
135351
135535
  }
135352
135536
  else if(supercell === 0) {
135353
- CIFTools.Text.coreCifOptions = { nx: 1, ny: 1, nz: 1, boundary: false };
135537
+ CIFTools.Text.coreCifOptions = { nx: 1, ny: 1, nz: 1, boundary: true, wholeMolecules: true, bondTolerance: 0.4 };
135354
135538
  }
135355
135539
  else {
135356
- CIFTools.Text.coreCifOptions = { nx: supercell, ny: supercell, nz: supercell, boundary: true };
135540
+ CIFTools.Text.coreCifOptions = { nx: supercell, ny: supercell, nz: supercell, boundary: true, wholeMolecules: true, bondTolerance: 0.4 };
135357
135541
  }
135358
135542
 
135359
135543
  let hAtoms = {};
@@ -135369,7 +135553,7 @@ class LoadCIF {
135369
135553
  let serial, moleculeNum;
135370
135554
  // if(!bMutation && !bAppend) {
135371
135555
  if(!bAppend) {
135372
- ic.init();
135556
+ ic.init(undefined, true); // keep original configurations, such as color, style, etc. when loading multiple structures
135373
135557
  moleculeNum = 0; //1;
135374
135558
  serial = 0;
135375
135559
  }
@@ -135413,11 +135597,13 @@ class LoadCIF {
135413
135597
 
135414
135598
  if (parsed.isError) {
135415
135599
  // report error:
135416
- var aaa = 1; //alert("The Binary CIF data can NOT be parsed: " + parsed.toString());
135600
+ var aaa = 1; //alert("2 The Binary CIF data can NOT be parsed: " + parsed.toString());
135417
135601
  return;
135418
135602
  }
135419
135603
 
135420
135604
  let block = parsed.result.dataBlocks[0];
135605
+
135606
+ if(!block) continue;
135421
135607
 
135422
135608
  if(block.getCategory("_entry")) {
135423
135609
  id = block.getCategory("_entry").getColumn("id").getString(0);
@@ -135656,6 +135842,8 @@ class LoadCIF {
135656
135842
  ic.cell.angle_alpha = parseFloat(block.getCategory("_cell").getColumn("angle_alpha").getString(0));
135657
135843
  ic.cell.angle_beta = parseFloat(block.getCategory("_cell").getColumn("angle_beta").getString(0));
135658
135844
  ic.cell.angle_gamma = parseFloat(block.getCategory("_cell").getColumn("angle_gamma").getString(0));
135845
+
135846
+ me.htmlCls.clickMenuCls.setLogCmd("define unitcell | " + ic.cell.length_a + " | " + ic.cell.length_b + " | " + ic.cell.length_c + " | " + ic.cell.angle_alpha + " | " + ic.cell.angle_beta + " | " + ic.cell.angle_gamma, true);
135659
135847
  }
135660
135848
 
135661
135849
  // if (record === 'ENDMDL') {
@@ -136000,7 +136188,7 @@ class LoadCIF {
136000
136188
 
136001
136189
  // if(oriResidueNum !== prevOriResidueNum) {
136002
136190
  if(oriResidueNum !== prevOriResidueNum || chain + "_" + resn != prevResn || prevAutochain != autochain) {
136003
- let residue = me.utilsCls.residueName2Abbr(resn);
136191
+ let residue = (atomDetails.het) ? me.utilsCls.residueName2Abbr(resn) : me.utilsCls.residueName2Abbr(resn, true);
136004
136192
 
136005
136193
  ic.residueId2Name[residueNum] = residue;
136006
136194
 
@@ -137299,6 +137487,16 @@ class ApplyCommand {
137299
137487
  ic.opts['unitcell'] = 'no';
137300
137488
  ic.drawCls.draw();
137301
137489
  }
137490
+ else if(command.indexOf('define unitcell') !== -1) {
137491
+ let itemArray = command.split(' | ');
137492
+ ic.cell = {};
137493
+ ic.cell.length_a = parseFloat(itemArray[1]);
137494
+ ic.cell.length_b = parseFloat(itemArray[2]);
137495
+ ic.cell.length_c = parseFloat(itemArray[3]);
137496
+ ic.cell.angle_alpha = parseFloat(itemArray[4]);
137497
+ ic.cell.angle_beta = parseFloat(itemArray[5]);
137498
+ ic.cell.angle_gamma = parseFloat(itemArray[6]);
137499
+ }
137302
137500
  else if(command == 'set fog on') {
137303
137501
  ic.opts['fog'] = 'yes';
137304
137502
  ic.fogCls.setFog(true);
@@ -137329,7 +137527,7 @@ class ApplyCommand {
137329
137527
  let pos = command.lastIndexOf(' ');
137330
137528
  let supercell = parseInt(command.substr(pos + 1));
137331
137529
 
137332
- await me.htmlCls.clickMenuCls.setSupercell(supercell);
137530
+ me.htmlCls.clickMenuCls.setSupercell(supercell);
137333
137531
  }
137334
137532
  else if(command == 'set chemicalbinding show') {
137335
137533
  ic.setOptionCls.setOption('chemicalbinding', 'show');
@@ -137764,7 +137962,8 @@ class ApplyCommand {
137764
137962
  else if(commandOri.indexOf('select interaction') == 0) {
137765
137963
  let idArray = commandOri.substr(commandOri.lastIndexOf(' ') + 1).split(',');
137766
137964
  if(idArray !== null) {
137767
- let mmdbid = idArray[0].split('_')[0];
137965
+ let itemArray = me.utilsCls.getIdArray(idArray[0]);
137966
+ let mmdbid = itemArray[0];
137768
137967
  if(!ic.b2DShown) ic.ParserUtilsCls.download2Ddgm(mmdbid.toUpperCase());
137769
137968
 
137770
137969
  ic.diagram2dCls.selectInteraction(idArray[0], idArray[1]);
@@ -139610,7 +139809,7 @@ class DefinedSets {
139610
139809
 
139611
139810
  }
139612
139811
 
139613
- selectCombinedSets(strSets, commandname) { let ic = this.icn3d; ic.icn3dui;
139812
+ selectCombinedSets(strSets, commandname) { let ic = this.icn3d, me = ic.icn3dui;
139614
139813
  let idArray = strSets.split(' ');
139615
139814
 
139616
139815
  let orArray = [], andArray = [], notArray = [];
@@ -139618,7 +139817,7 @@ class DefinedSets {
139618
139817
 
139619
139818
  for(let i = 0, il = idArray.length; i < il; ++i) {
139620
139819
  // replace 1CD8_A_1 with 1CD8_A1
139621
- let tmpArray = idArray[i].split('_');
139820
+ let tmpArray = me.utilsCls.getIdArray(idArray[i]);
139622
139821
  if(tmpArray.length == 3 && !isNaN(tmpArray[2])) {
139623
139822
  idArray[i] = tmpArray[0] + '_' + tmpArray[1] + tmpArray[2];
139624
139823
  }
@@ -140620,7 +140819,7 @@ class LoadScript {
140620
140819
 
140621
140820
  // load pdb, mmcif, mmdb, cid
140622
140821
  let id = loadStr.substr(loadStr.lastIndexOf(' ') + 1);
140623
- if(id.length == 4) id = id.toUpperCase();
140822
+ if(id.length == 4 || id.indexOf('pdb_') == 0) id = id.toUpperCase();
140624
140823
 
140625
140824
  // skip loading the structure if
140626
140825
  // 1. PDB was in the iCn3D PNG Image file
@@ -140667,6 +140866,10 @@ class LoadScript {
140667
140866
  me.cfg.mmcifid = id;
140668
140867
  await ic.mmcifParserCls.downloadMmcif(id);
140669
140868
  }
140869
+ else if(command.indexOf('load cod') !== -1) {
140870
+ me.cfg.codid = id;
140871
+ await ic.mmcifParserCls.downloadCod(id);
140872
+ }
140670
140873
  else if(command.indexOf('load mmdb ') !== -1 || command.indexOf('load mmdb1 ') !== -1) {
140671
140874
  me.cfg.mmdbid = id;
140672
140875
  me.cfg.bu = 1;
@@ -141181,7 +141384,7 @@ class SelectByCommand {
141181
141384
 
141182
141385
  // convert 1TOP_A:20 to $1TOP.A:20
141183
141386
  if(commandArray[i].indexOf('_') !== -1) {
141184
- let itemArray = commandArray[i].split('_');
141387
+ let itemArray = me.utilsCls.getIdArray(commandArray[i]);
141185
141388
  if(itemArray.length ==2 ) {
141186
141389
  commandArray[i] = '$' + itemArray[0] + '.' + itemArray[1];
141187
141390
  }
@@ -144062,24 +144265,6 @@ class Dssp {
144062
144265
  if(!me.bNode) console.log("domainid: " + domainid);
144063
144266
  }
144064
144267
 
144065
- // count the number of matched strands
144066
- // let strandHash = {};
144067
- // for(let j = 0, jl = queryData[0].segs.length; j < jl; ++j) {
144068
- // let seg = queryData[0].segs[j];
144069
- // let q_start = parseInt(seg.q_start)
144070
-
144071
- // let strand = this.getStrandFromRefnum(q_start);
144072
- // strandHash[strand] = 1;
144073
- // }
144074
-
144075
- // let tmAdjust = 0.1;
144076
-
144077
- // if the TM score difference is within 0.1 and more strands are found, use the template with more strands
144078
- // if(!domainid2segs.hasOwnProperty(domainid) ||
144079
- // (score >= parseFloat(ic.domainid2score[domainid].split('_')[0]) + tmAdjust)
144080
- // || (score >= parseFloat(ic.domainid2score[domainid].split('_')[0]) - tmAdjust && score < parseFloat(ic.domainid2score[domainid].split('_')[0]) + tmAdjust && Object.keys(strandHash).length > domainid2strandcnt[domainid])
144081
- // ) {
144082
-
144083
144268
  // use TM-score alone
144084
144269
  if(!domainid2segs.hasOwnProperty(domainid) || score >= parseFloat(ic.domainid2score[domainid].split('_')[0])) {
144085
144270
  ic.domainid2score[domainid] = queryData[0].score + '_' + queryData[0].frac_identical + '_' + queryData[0].num_res + '_' + queryData[0].score2;
@@ -145411,7 +145596,7 @@ class Scap {
145411
145596
  let snpArray = snp.split(','); //stru_chain_resi_snp
145412
145597
  let atomHash = {}, snpResidArray = [], chainResi2pdb = {};
145413
145598
  for(let i = 0, il = snpArray.length; i < il; ++i) {
145414
- let idArray = snpArray[i].split('_'); //stru_chain_resi_snp
145599
+ let idArray = me.utilsCls.getIdArray(snpArray[i]); //stru_chain_resi_snp
145415
145600
 
145416
145601
  let resid = idArray[0] + '_' + idArray[1] + '_' + idArray[2];
145417
145602
  atomHash = me.hashUtilsCls.unionHash(atomHash, ic.residues[resid]);
@@ -148563,7 +148748,8 @@ class Diagram2d {
148563
148748
  if(refnumLabel) {
148564
148749
  refnumStr = ic.refnumCls.rmStrandFromRefnumlabel(refnumLabel);
148565
148750
  if(!ic.refnum2resn[domainid]) ic.refnum2resn[domainid] = {};
148566
- ic.refnum2resn[domainid][refnumStr] = resn + resid.split('_')[2];
148751
+ let idArray = me.utilsCls.getIdArray(resid);
148752
+ ic.refnum2resn[domainid][refnumStr] = resn + idArray[2];
148567
148753
  }
148568
148754
  }
148569
148755
 
@@ -150063,7 +150249,8 @@ class ResizeCanvas {
150063
150249
  let width = me.htmlCls.WIDTH; // - me.htmlCls.LESSWIDTH_RESIZE;
150064
150250
  let height = me.htmlCls.HEIGHT; // - me.htmlCls.LESSHEIGHT - me.htmlCls.EXTRAHEIGHT;
150065
150251
 
150066
- if(ic !== undefined && !ic.bFullscreen) thisClass.resizeCanvas(width, height);
150252
+ // if(ic !== undefined && !ic.bFullscreen) thisClass.resizeCanvas(width, height);
150253
+ if(ic !== undefined && !ic.bFullscreen) thisClass.resizeCanvas(width, height, true, true);
150067
150254
  });
150068
150255
  }
150069
150256
  }
@@ -154813,8 +155000,8 @@ class iCn3D {
154813
155000
  }
154814
155001
  }
154815
155002
  //When users first load a structure, call this function to empty previous settings.
154816
- iCn3D.prototype.init = function (bKeepCmd) {
154817
- this.init_base();
155003
+ iCn3D.prototype.init = function (bKeepCmd, bKeepConfig) {
155004
+ this.init_base(bKeepCmd, bKeepConfig);
154818
155005
 
154819
155006
  this.molTitle = "";
154820
155007
 
@@ -154834,8 +155021,8 @@ iCn3D.prototype.init = function (bKeepCmd) {
154834
155021
  this.axes = [];
154835
155022
  };
154836
155023
 
154837
- iCn3D.prototype.init_base = function (bKeepCmd) {
154838
- this.resetConfig();
155024
+ iCn3D.prototype.init_base = function (bKeepCmd, bKeepConfig) {
155025
+ if(!bKeepConfig) this.resetConfig();
154839
155026
 
154840
155027
  this.structures = {}; // structure name -> array of chains
154841
155028
  this.chains = {}; // structure_chain name -> atom hash
@@ -155025,7 +155212,7 @@ class iCn3DUI {
155025
155212
  //even when multiple iCn3D viewers are shown together.
155026
155213
  this.pre = this.cfg.divid + "_";
155027
155214
 
155028
- this.REVISION = '3.54.3';
155215
+ this.REVISION = '3.54.4';
155029
155216
 
155030
155217
  // In nodejs, iCn3D defines "window = {navigator: {}}", and added window = {navigator: {}, "__THREE__":"177"}
155031
155218
  this.bNode = (Object.keys(window).length < 3) ? true : false;
@@ -155227,7 +155414,7 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
155227
155414
  let domainidArray = me.cfg.matchedchains.split(',');
155228
155415
  let chainidArray = [];
155229
155416
  for(let i = 0, il = domainidArray.length; i < il; ++i) {
155230
- let idArray = domainidArray[i].split('_');
155417
+ let idArray = me.utilsCls.getIdArray(domainidArray[i]);
155231
155418
  chainidArray.push(idArray[0] + '_' + idArray[1]);
155232
155419
  }
155233
155420
 
@@ -155270,14 +155457,14 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
155270
155457
  await ic.pdbParserCls.downloadUrl(url, type, me.cfg.command);
155271
155458
  }
155272
155459
  else if(me.cfg.mmtfid !== undefined) {
155273
- if(me.cfg.mmtfid.toLowerCase().substr(0,8) == 'pdb_0000') me.cfg.mmtfid = me.cfg.mmtfid.substr(8); // temperary support long PDB ID such as pdb_00001tup
155460
+ // if(me.cfg.mmtfid.toLowerCase().substr(0,8) == 'pdb_0000') me.cfg.mmtfid = me.cfg.mmtfid.substr(8); // temperary support long PDB ID such as pdb_00001tup
155274
155461
  ic.inputid = me.cfg.mmtfid;
155275
155462
  ic.loadCmd = 'load mmtf ' + me.cfg.mmtfid;
155276
155463
  me.htmlCls.clickMenuCls.setLogCmd(ic.loadCmd, true);
155277
155464
  await ic.bcifParserCls.downloadBcif(me.cfg.mmtfid);
155278
155465
  }
155279
155466
  else if(me.cfg.bcifid !== undefined) {
155280
- if(me.cfg.bcifid.toLowerCase().substr(0,8) == 'pdb_0000') me.cfg.bcifid = me.cfg.bcifid.substr(8); // temperary support long PDB ID such as pdb_00001tup
155467
+ // if(me.cfg.bcifid.toLowerCase().substr(0,8) == 'pdb_0000') me.cfg.bcifid = me.cfg.bcifid.substr(8); // temperary support long PDB ID such as pdb_00001tup
155281
155468
  ic.inputid = me.cfg.bcifid;
155282
155469
  ic.loadCmd = 'load bcif ' + me.cfg.bcifid;
155283
155470
  me.htmlCls.clickMenuCls.setLogCmd(ic.loadCmd, true);
@@ -155452,6 +155639,12 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
155452
155639
  me.htmlCls.clickMenuCls.setLogCmd(ic.loadCmd, true);
155453
155640
  await ic.mmcifParserCls.downloadMmcif(me.cfg.mmcifid);
155454
155641
  }
155642
+ else if(me.cfg.codid !== undefined) {
155643
+ ic.inputid = me.cfg.codid;
155644
+ ic.loadCmd = 'load cod ' + me.cfg.codid;
155645
+ me.htmlCls.clickMenuCls.setLogCmd(ic.loadCmd, true);
155646
+ await ic.mmcifParserCls.downloadCod(me.cfg.codid);
155647
+ }
155455
155648
  else if(me.cfg.align !== undefined) {
155456
155649
  // ic.bNCBI = true;
155457
155650
  if(me.cfg.align.indexOf('185055,') != -1) {
@@ -155612,6 +155805,8 @@ iCn3DUI.prototype.getXMLHttpRqstPromise = function(url, dataType, responseType,
155612
155805
 
155613
155806
  reject('error');
155614
155807
  }
155808
+
155809
+ me.icn3d.ParserUtilsCls.hideLoading();
155615
155810
  }
155616
155811
  else {
155617
155812
  me.icn3d.ParserUtilsCls.showLoading();
@@ -155764,18 +155959,6 @@ iCn3DUI.prototype.setDialogAjax = function() { let me = this;
155764
155959
  });
155765
155960
  };
155766
155961
 
155767
- /*
155768
- iCn3DUI.prototype.setIcn3dui = function(id) { let me = this;
155769
- let idArray = id.split('_'); // id: div0_reload_pdbfile
155770
- ic.pre = idArray[0] + "_";
155771
- if(window.icn3duiHash !== undefined && window.icn3duiHash.hasOwnProperty(idArray[0])) { // for multiple 3D display
155772
- me = window.icn3duiHash[idArray[0]];
155773
- }
155774
- return me;
155775
- };
155776
- */
155777
-
155778
-
155779
155962
  // required by npm
155780
155963
  class printMsg {
155781
155964
  constructor() {