/// <summary> /// Calculate some additional parameters needed for simulations /// </summary> public void Prepare() { if (Error != "") { return; } // min/max values of local coordinates double xmin = 1.0e6, xmax = -1.0e6, ymin = 1.0e6, ymax = -1.0e6, zmin = 1.0e6, zmax = -1.0e6; for (int i = 0; i < NAtoms; i++) { xmin = Math.Min(xmin, XLocal[i]); xmax = Math.Max(xmax, XLocal[i]); ymin = Math.Min(ymin, YLocal[i]); ymax = Math.Max(ymax, YLocal[i]); zmin = Math.Min(zmin, ZLocal[i]); zmax = Math.Max(zmax, ZLocal[i]); MaxRadius = new Vector3(Math.Max(MaxRadius.X, Math.Sqrt(YLocal[i] * YLocal[i] + ZLocal[i] * ZLocal[i]) + vdWR[i]), Math.Max(MaxRadius.Y, Math.Sqrt(XLocal[i] * XLocal[i] + ZLocal[i] * ZLocal[i]) + vdWR[i]), Math.Max(MaxRadius.Z, Math.Sqrt(XLocal[i] * XLocal[i] + YLocal[i] * YLocal[i]) + vdWR[i])); } // moment(s) of inertia double ixx = 0.0, iyy = 0.0, izz = 0.0, ixy = 0.0, ixz = 0.0, iyz = 0.0; double m = 0.0, x2, y2, z2; for (int i = 0; i < NAtoms; i++) { m = AtomMass[i]; x2 = XLocal[i] * XLocal[i]; y2 = YLocal[i] * YLocal[i]; z2 = ZLocal[i] * ZLocal[i]; ixx += m * (y2 + z2); iyy += m * (x2 + z2); izz += m * (x2 + y2); ixy -= m * XLocal[i] * YLocal[i]; ixz -= m * XLocal[i] * ZLocal[i]; iyz -= m * YLocal[i] * ZLocal[i]; } SimpleI = Math.Max(Math.Max(ixx, ixy), ixz); FullI = new Matrix3(ixx, ixy, ixz, ixy, iyy, iyz, ixz, iyz, izz); // clusters of clustersize^3 angstrom const double clustersize = 10.0; int nx, ny, nz, nxoff, nyoff, nzoff; nx = (int)(Math.Ceiling(xmax / clustersize) + Math.Ceiling(-xmin / clustersize)); ny = (int)(Math.Ceiling(ymax / clustersize) + Math.Ceiling(-ymin / clustersize)); nz = (int)(Math.Ceiling(zmax / clustersize) + Math.Ceiling(-zmin / clustersize)); nxoff = (int)Math.Ceiling(-xmin / clustersize); nyoff = (int)Math.Ceiling(-ymin / clustersize); nzoff = (int)Math.Ceiling(-zmin / clustersize); int nclusters = nx * ny * nz; AtomCluster[] atomcluster_tmp = new AtomCluster[nx * ny * nz]; // sort atoms // first run: count atoms in each cluster int nc, cNAtomsmax = 0; double rcsize = 1.0 / clustersize; for (int i = 0; i < NAtoms; i++) { nc = (int)(ZLocal[i] * rcsize + nzoff) + nz * ((int)(YLocal[i] * rcsize + nyoff) + ny * ((int)(XLocal[i] * rcsize + nxoff))); atomcluster_tmp[nc].NAtoms++; cNAtomsmax = Math.Max(cNAtomsmax, atomcluster_tmp[nc].NAtoms); } // allocate index arrays int ncfull = 0; int[][] originalatomindex = new int[nclusters][]; for (nc = 0; nc < nclusters; nc++) { if (atomcluster_tmp[nc].NAtoms > 0) { originalatomindex[nc] = new int[atomcluster_tmp[nc].NAtoms]; ncfull++; } } // fill int[] atomcounters = new int[nclusters]; for (int i = 0; i < NAtoms; i++) { nc = (int)(ZLocal[i] * rcsize + nzoff) + nz * ((int)(YLocal[i] * rcsize + nyoff) + ny * ((int)(XLocal[i] * rcsize + nxoff))); originalatomindex[nc][atomcounters[nc]++] = i; } // remove empty AtomClusters = new AtomCluster[ncfull]; ncfull = 0; for (nc = 0; nc < nclusters; nc++) { if (atomcluster_tmp[nc].NAtoms > 0) { originalatomindex[ncfull] = originalatomindex[nc]; AtomClusters[ncfull++] = atomcluster_tmp[nc]; } } // optimize each double rmax, cx, cy, cz; int ilocal; Vector3 rlocal; for (nc = 0; nc < AtomClusters.Length; nc++) { // get the center cx = 0.0; cy = 0.0; cz = 0.0; for (int i = 0; i < AtomClusters[nc].NAtoms; i++) { ilocal = originalatomindex[nc][i]; cx += XLocal[ilocal]; cy += YLocal[ilocal]; cz += ZLocal[ilocal]; } cx /= (double)AtomClusters[nc].NAtoms; cy /= (double)AtomClusters[nc].NAtoms; cz /= (double)AtomClusters[nc].NAtoms; AtomClusters[nc].ClusterCenter = new Vector3(cx, cy, cz); // find the most distant atom rmax = -1.0; for (int i = 0; i < AtomClusters[nc].NAtoms; i++) { ilocal = originalatomindex[nc][i]; rlocal = new Vector3(cx - XLocal[ilocal], cy - YLocal[ilocal], cz - ZLocal[ilocal]); rmax = Math.Max(Vector3.Abs(rlocal) + vdWR[ilocal], rmax); } AtomClusters[nc].ClusterRadius = rmax; } // try an alternative method : find a pair of most distant atoms for each dimension, try as a center int jlocal; double absr; for (nc = 0; nc < AtomClusters.Length; nc++) { rmax = -1.0; rlocal = AtomClusters[nc]; for (int i = 0; i < AtomClusters[nc].NAtoms; i++) { ilocal = originalatomindex[nc][i]; cx = XLocal[ilocal]; cy = YLocal[ilocal]; cz = ZLocal[ilocal]; for (int j = i + 1; j < AtomClusters[nc].NAtoms; j++) { jlocal = originalatomindex[nc][j]; rlocal = new Vector3(XLocal[jlocal] - cx, YLocal[jlocal] - cy, ZLocal[jlocal] - cz); absr = Vector3.Abs(rlocal); if (rmax < absr + vdWR[ilocal] + vdWR[jlocal]) { rmax = absr + vdWR[ilocal] + vdWR[jlocal]; rlocal = (absr == 0.0) ? new Vector3(cx, cy, cz) : new Vector3(cx, cy, cz) + rlocal * ((0.5 * rmax - vdWR[ilocal]) / absr); } } } // find the most distant atom rmax = -1.0; cx = rlocal.X; cy = rlocal.Y; cz = rlocal.Z; for (int i = 0; i < AtomClusters[nc].NAtoms; i++) { ilocal = originalatomindex[nc][i]; rlocal = new Vector3(cx - XLocal[ilocal], cy - YLocal[ilocal], cz - ZLocal[ilocal]); rmax = Math.Max(Vector3.Abs(rlocal) + vdWR[ilocal], rmax); } if (rmax < AtomClusters[nc].ClusterRadius) { AtomClusters[nc].ClusterCenter = new Vector3(cx, cy, cz); AtomClusters[nc].ClusterRadius = rmax; } } #if DEBUG if (DebugData.SaveAtomClusters) { // for debugging: save clusters xyz using (StreamWriter sw = new StreamWriter(this.Name + ".cluster.xyz", false)) { sw.WriteLine(AtomClusters.Length.ToString()); sw.WriteLine("cluster"); for (int i = 0; i < AtomClusters.Length; i++) { sw.WriteLine("L" + i.ToString() + " " + AtomClusters[i].ClusterCenter.X.ToString("F3") + " " + AtomClusters[i].ClusterCenter.Y.ToString("F3") + " " + AtomClusters[i].ClusterCenter.Z.ToString("F3")); } sw.Close(); } using (StreamWriter sw = new StreamWriter(this.Name + ".cluster.pml", false)) { sw.WriteLine("select all"); sw.WriteLine("translate [" + CM.X.ToString("F3") + "," + CM.Y.ToString("F3") + "," + CM.Z.ToString("F3") + "]"); sw.WriteLine("deselect"); for (int i = 0; i < AtomClusters.Length; i++) { sw.WriteLine("alter (name L" + i.ToString() + "), vdw=" + AtomClusters[i].ClusterRadius.ToString("F3")); } sw.Close(); } } #endif ///////////////////////////////////////////////////////////////////////////////////////// // remove atoms which can never be approached int nnbr, nblocked = 0; double[] xLocalnbr = new double[NAtoms]; double[] yLocalnbr = new double[NAtoms]; double[] zLocalnbr = new double[NAtoms]; double[] rthresh2 = new double[NAtoms]; double[] z2plus = new double[NAtoms]; double[] z2minus = new double[NAtoms]; double x0, y0, z0, rmin = AtomData.vdWRMin; Boolean[] atom_blocked = new Boolean[NAtoms]; Boolean accesible, zplus_blocked, zminus_blocked; double xg, yg, zg, rg, rxy, drmax, dtheta, dphi; for (int i = 0; i < NAtoms; i++) { accesible = false; x0 = XLocal[i]; y0 = YLocal[i]; z0 = ZLocal[i]; rmax = 2.0 * rmin + vdWR[i]; // select neighbours within r1 + r2 + 2rmin nnbr = 0; for (int j = 0; j < NAtoms; j++) { x2 = (XLocal[j] - x0) * (XLocal[j] - x0); y2 = (YLocal[j] - y0) * (YLocal[j] - y0); z2 = (ZLocal[j] - z0) * (ZLocal[j] - z0); if (x2 + y2 + z2 < (rmax + vdWR[j]) * (rmax + vdWR[j])) { xLocalnbr[nnbr] = XLocal[j] - x0; yLocalnbr[nnbr] = YLocal[j] - y0; zLocalnbr[nnbr] = ZLocal[j] - z0; rthresh2[nnbr++] = (0.9 * rmin + vdWR[j]) * (0.9 * rmin + vdWR[j]); } } // spherical grid rg = vdWR[i] + rmin; drmax = 0.1 * rmin / rg; nz = (int)Math.Ceiling(Math.PI / drmax); dtheta = Math.PI / nz; for (double theta = Math.PI / 2.0; theta >= 0.0; theta -= dtheta) { zg = rg * Math.Sin(theta); for (int j = 0; j < nnbr; j++) { z2plus[j] = (zLocalnbr[j] - zg) * (zLocalnbr[j] - zg); z2minus[j] = (zLocalnbr[j] + zg) * (zLocalnbr[j] + zg); } rxy = rg * Math.Cos(theta); dphi = (rxy > 0.05 * rmin / Math.PI) ? 0.1 * rmin / rxy : 2.0 * Math.PI; for (double phi = 0.0; phi <= 2.0 * Math.PI; phi += dphi) { xg = rxy * Math.Cos(phi); yg = rxy * Math.Sin(phi); // check all neighbours at zg and -zg zplus_blocked = false; zminus_blocked = false; for (int j = 0; j < nnbr; j++) { x2 = (xLocalnbr[j] - xg) * (xLocalnbr[j] - xg); y2 = (yLocalnbr[j] - yg) * (yLocalnbr[j] - yg); zplus_blocked = zplus_blocked || (x2 + y2 + z2plus[j] < rthresh2[j]); zminus_blocked = zminus_blocked || (x2 + y2 + z2minus[j] < rthresh2[j]); if (zplus_blocked && zminus_blocked) { break; } } accesible = accesible || (!zplus_blocked) || (!zminus_blocked); if (accesible) { break; } } if (accesible) { break; } } atom_blocked[i] = !accesible; nblocked = accesible ? nblocked : nblocked + 1; } // finally remove blocked atoms and reorder int ai = 0, unblocked = NAtoms - nblocked; MaxAtomsInCluster = 0; for (nc = 0; nc < AtomClusters.Length; nc++) { // first run: count blocked atoms nblocked = 0; // now in cluster nc for (int i = 0; i < AtomClusters[nc].NAtoms; i++) { nblocked = atom_blocked[originalatomindex[nc][i]] ? nblocked + 1 : nblocked; } // second run: fill ai = 0; for (int i = 0; i < AtomClusters[nc].NAtoms; i++) { ilocal = originalatomindex[nc][i]; if (!atom_blocked[ilocal]) { originalatomindex[nc][ai++] = ilocal; } } AtomClusters[nc].NAtoms -= nblocked; MaxAtomsInCluster = Math.Max(MaxAtomsInCluster, AtomClusters[nc].NAtoms); } // fill cluster arrays this.ClusteredAtomXYZ = new Vector3[unblocked]; this.ClusteredAtomvdwR = new double[unblocked]; this.ClusteredAtomOriginalIndex = new int[unblocked]; if (XYZvdwRVectorArray != IntPtr.Zero) { Marshal.FreeHGlobal(XYZvdwRVectorArray); } XYZvdwRVectorArray = Marshal.AllocHGlobal((unblocked + 1) * sizeof(float) * 4); float[] XYZvdwRdata = new float[unblocked * 4]; int idata = 0, idata4 = 0, oi; for (nc = 0; nc < AtomClusters.Length; nc++) { AtomClusters[nc].StartIndexInClusterArrays = idata; for (int i = 0; i < AtomClusters[nc].NAtoms; i++) { oi = originalatomindex[nc][i]; ClusteredAtomXYZ[idata] = new Vector3(XLocal[oi], YLocal[oi], ZLocal[oi]); ClusteredAtomvdwR[idata] = vdWR[oi]; ClusteredAtomOriginalIndex[idata++] = oi; XYZvdwRdata[idata4++] = (float)XLocal[oi]; XYZvdwRdata[idata4++] = (float)YLocal[oi]; XYZvdwRdata[idata4++] = (float)ZLocal[oi]; XYZvdwRdata[idata4++] = (float)vdWR[oi]; } } Marshal.Copy(XYZvdwRdata, 0, FpsNativeWrapper.Aligned16(XYZvdwRVectorArray), XYZvdwRdata.Length); Prepared = true; }
private void SaveSimulationResult(SimulationResult sr, String fname, Boolean addpdbsave) { String converged = sr.Converged ? " (converged)" : " (not converged)"; String fullfname = fname + ".pml"; Vector3 u; Double theta; using (StreamWriter sw = new StreamWriter(fullfname, false)) { sw.WriteLine("# Energy = " + sr.E.ToString("F8") + converged); for (Int32 i = 0; i < molecules.Count; i++) { sw.WriteLine("load " + molecules[i].FullFileName); } for (Int32 i = 1; i < molecules.Count; i++) { theta = Matrix3.AngleAndAxis(sr.Rotation[i], out u) * 180.0 / Math.PI; sw.WriteLine("rotate [" + u.ToString() + "], " + theta.ToString("F3") + ", " + molecules[i].Name + ", origin=[" + molecules[i].CM.ToString() + "]"); sw.WriteLine("translate [" + sr.Translation[i].ToString() + "], " + molecules[i].Name); } if (_bestfit) { sw.WriteLine("select all"); sw.WriteLine("translate [" + sr.BestFitTranslation.ToString() + "], sele"); theta = Matrix3.AngleAndAxis(sr.BestFitRotation, out u) * 180.0 / Math.PI; sw.WriteLine("rotate [" + u.ToString() + "], " + theta.ToString("F3") + ", sele, origin=[0, 0, 0]"); } if (addpdbsave) { sw.WriteLine("select all"); sw.WriteLine("save " + fname + ".pdb, sele"); } String lpnames = ""; if (lpcheckBox.Checked) { Int32 im; Vector3 r; LabelingPosition lpref; foreach (LabelingPosition l in labelingpos) { im = molecules.FindIndex(l.Molecule); if ((sr.SimulationMethod & SimulationMethods.Refinement) != 0) { lpref = sr.RefinedLabelingPositions.Find(l.Name); } else { lpref = l; } r = sr.Rotation[im] * (lpref - molecules[im].CM) + molecules[im].CM + sr.Translation[im]; sw.WriteLine("pseudoatom " + l.Name + ", pos=[" + r.ToString() + "]"); sw.WriteLine("label " + l.Name + ", \"" + l.Name + "\""); sw.WriteLine("show spheres, " + l.Name); if (l.Dye == DyeType.Donor) { sw.WriteLine("color green, " + l.Name); } if (l.Dye == DyeType.Acceptor) { sw.WriteLine("color red, " + l.Name); } lpnames += " + " + l.Name; } } if (_bestfit && lpnames != String.Empty) { sw.WriteLine("deselect"); sw.WriteLine("select " + lpnames.Substring(3)); sw.WriteLine("translate [" + sr.BestFitTranslation.ToString() + "], sele"); theta = Matrix3.AngleAndAxis(sr.BestFitRotation, out u) * 180.0 / Math.PI; sw.WriteLine("rotate [" + u.ToString() + "], " + theta.ToString("F3") + ", sele, origin=[0, 0, 0]"); } sw.WriteLine("deselect"); sw.Close(); } }