// // Write a DPD input file-style molecule definition. // private static void write_molecule_type(StreamWriter f, DPDMoleculeType mol, DPDSim sim) { var N_sites = mol.site_internal_ids.Count; var N_bonds = mol.bond_k.Count; var N_angles = mol.angle_k.Count; f.WriteLine("molecule"); f.WriteLine("\tname {0}", mol.name); f.WriteLine("\tcount {0}", mol.count); for (var si = 0; si < N_sites; si++) { var i = mol.site_internal_ids[si]; f.WriteLine("\tsite {0}", sim.site_types[i].name); } for (var bi = 0; bi < N_bonds; bi++) { var i = mol.bond_site_indices[bi * 2 + 0]; var j = mol.bond_site_indices[bi * 2 + 1]; f.WriteLine("\tbond\t{0}\t{1}\t\t{2}\t{3}\n", i, j, mol.bond_eq[bi], mol.bond_k[bi]); } for (var ai = 0; ai < N_angles; ai++) { var i = mol.angle_site_indices[ai * 3 + 0]; var j = mol.angle_site_indices[ai * 3 + 1]; var k = mol.angle_site_indices[ai * 3 + 2]; f.WriteLine("\tangle\t{0}\t{1}\t{2}\t\t{3}\t{4}\n", i, j, k, mol.angle_eq[ai], mol.angle_k[ai]); } f.WriteLine("end\n"); }
// // Internal helper routines // // // Return the internal site id ( i.e., the index sim.site_types[] ) for type "name" // private static int get_site_type_from_name(string name, DPDSim sim) { for (var i = 0; i < sim.site_types.Count; i++) { if (sim.site_types[i].name == name) { return(sim.site_types[i].internal_id); } } return(-1); }
// // This is the naive loop over pairs in the system. Simple, but // *extremely* inefficient ( ~ O(N^2) ). // public static void DoNonbondedSlow(DPDSim sim) { var N = sim.site_ids.Length; double cutsq = sim.rcut * sim.rcut; double sqrt_dt = Math.Sqrt(sim.delta_t); for (var i = 0; i < N; i++) { for (var j = i + 1; j < N; j++) { nonbonded_pair(i, j, cutsq, sqrt_dt, sim); } } }
private static void save_checkpoint_and_trajectory(DPDSim sim) { try { using (StreamWriter f = File.CreateText("output.checkpoint")) { DPDIO.SaveSim(f, sim); } } catch (Exception) { Console.WriteLine("Unable to write checkpoint."); } try { using (StreamWriter f = File.AppendText("output.lammpstrj")) { DPDIO.SaveTrajectoryFrame(f, sim); } } catch (Exception) { Console.WriteLine("Unable to write trajectory frame."); } }
// // Save trajectory snapshot in LAMMPS file format, for easy visualization with e.g. VMD. // public static void SaveTrajectoryFrame(StreamWriter f, DPDSim sim) { f.WriteLine("ITEM: TIMESTEP"); f.WriteLine("{0}", sim.step_no); f.WriteLine("ITEM: NUMBER OF ATOMS"); f.WriteLine("{0}", sim.site_ids.Length); f.WriteLine("ITEM: BOX BOUNDS pp pp pp"); f.WriteLine("{0:G} {1:G}", -sim.cell[0] / 2, +sim.cell[0] / 2); f.WriteLine("{0:G} {1:G}", -sim.cell[1] / 2, +sim.cell[1] / 2); f.WriteLine("{0:G} {1:G}", -sim.cell[2] / 2, +sim.cell[2] / 2); f.WriteLine("ITEM: ATOMS id type mol x y z"); for (var i = 0; i < sim.site_ids.Length; i++) { f.WriteLine("{0} {1} {2} {3:G} {4:G} {5:G}", i + 1, sim.site_ids[i] + 1, sim.molecule_ids[i] + 1, sim.r[(i * 3) + 0], sim.r[(i * 3) + 1], sim.r[(i * 3) + 2]); } }
static public void VelocityVerlet(DPDSim sim) { var N_sites = sim.site_ids.Length; double dt = sim.delta_t; double h_dt_sq = 0.5 * (dt * dt); // // Advance positions. // for (var site_i = 0; site_i < N_sites; site_i++) { var s = site_i * 3; // // Calculate new positions // sim.r[s + 0] += dt * sim.v[s + 0] + h_dt_sq * sim.f[s + 0]; sim.r[s + 1] += dt * sim.v[s + 1] + h_dt_sq * sim.f[s + 1]; sim.r[s + 2] += dt * sim.v[s + 2] + h_dt_sq * sim.f[s + 2]; // // Wrap new positions to periodic boundary // sim.r[s + 0] -= sim.cell[0] * Math.Round(sim.r[s + 0] / sim.cell[0], MidpointRounding.AwayFromZero); sim.r[s + 1] -= sim.cell[1] * Math.Round(sim.r[s + 1] / sim.cell[1], MidpointRounding.AwayFromZero); sim.r[s + 2] -= sim.cell[2] * Math.Round(sim.r[s + 2] / sim.cell[2], MidpointRounding.AwayFromZero); // // Store current velocities and forces // sim.v_[s + 0] = sim.v[s + 0]; sim.v_[s + 1] = sim.v[s + 1]; sim.v_[s + 2] = sim.v[s + 2]; sim.f_[s + 0] = sim.f[s + 0]; sim.f_[s + 1] = sim.f[s + 1]; sim.f_[s + 2] = sim.f[s + 2]; // // Calculate temporary velocity prediction // sim.v[s + 0] += sim.lambda * dt * sim.f[s + 0]; sim.v[s + 1] += sim.lambda * dt * sim.f[s + 1]; sim.v[s + 2] += sim.lambda * dt * sim.f[s + 2]; // // Zero force array; force routines treat it as an accumulator. // sim.f[s + 0] = 0.0; sim.f[s + 1] = 0.0; sim.f[s + 2] = 0.0; } // // Get new forces for these positions and temporary velocity prediction // if (sim.i_am_dumb == 1) { Forces.DoNonbondedSlow(sim); } else { Forces.DoNonbondedFast(sim); } Forces.DoBonds(sim); Forces.DoAngles(sim); // // At this point we have: // sim->v_ == original velocities for this step, sim->v == velocity prediction. // sim->f_ == original forces for this step, sim->f == forces at new positions and predicted velocities. // // // Correct the velocities using the two force arrays. // sim.kinetic_energy = 0.0; for (var site_i = 0; site_i < N_sites; site_i++) { var s = site_i * 3; sim.v[s + 0] = sim.v_[s + 0] + 0.5 * dt * (sim.f_[s + 0] + sim.f[s + 0]); sim.v[s + 1] = sim.v_[s + 1] + 0.5 * dt * (sim.f_[s + 1] + sim.f[s + 1]); sim.v[s + 2] = sim.v_[s + 2] + 0.5 * dt * (sim.f_[s + 2] + sim.f[s + 2]); // // Add kinetic contribution to the pressure tensor. // double pvx = 0.5 * (sim.v_[s + 0] + sim.v[s + 0]); double pvy = 0.5 * (sim.v_[s + 1] + sim.v[s + 1]); double pvz = 0.5 * (sim.v_[s + 2] + sim.v[s + 2]); sim.pressure[0] += pvx * pvx; sim.pressure[1] += pvx * pvy; sim.pressure[2] += pvx * pvz; sim.pressure[3] += pvy * pvx; sim.pressure[4] += pvy * pvy; sim.pressure[5] += pvy * pvz; sim.pressure[6] += pvz * pvx; sim.pressure[7] += pvz * pvy; sim.pressure[8] += pvz * pvz; sim.kinetic_energy += 0.5 * ((sim.v[s + 0] * sim.v[s + 0]) + (sim.v[s + 1] * sim.v[s + 1]) + (sim.v[s + 2] * sim.v[s + 2])); } // // Divide all pressure tensor elements by sim volume for correct units // double volume = sim.cell[0] * sim.cell[1] * sim.cell[2]; for (var i = 0; i < 9; i++) { sim.pressure[i] /= volume; } }
// // Harmonic angular potential function. // U = 0.5k( theta - theta_eq )^2. // public static void DoAngles(DPDSim sim) { const double theta_tol = 0.000001; var N_angles = sim.angle_site_indices.Length / 3; double dx_ij, dy_ij, dz_ij; double dx_jk, dy_jk, dz_jk; double fx_i, fy_i, fz_i; double fx_k, fy_k, fz_k; for (var angle_i = 0; angle_i < N_angles; angle_i++) { // // Angle formed by sites i-j-k // var i = sim.angle_site_indices[(angle_i * 3) + 0]; var j = sim.angle_site_indices[(angle_i * 3) + 1]; var k = sim.angle_site_indices[(angle_i * 3) + 2]; double theta_k = sim.angle_k[angle_i]; double theta_eq = sim.angle_eq[angle_i]; // // Vector connecting i->j, using minimum image convention // dx_ij = sim.r[(j * 3) + 0] - sim.r[(i * 3) + 0]; dy_ij = sim.r[(j * 3) + 1] - sim.r[(i * 3) + 1]; dz_ij = sim.r[(j * 3) + 2] - sim.r[(i * 3) + 2]; VecMinimumImage(dx_ij, dy_ij, dz_ij, ref dx_ij, ref dy_ij, ref dz_ij, ref sim.cell); double ij_mag = Math.Sqrt(dx_ij * dx_ij + dy_ij * dy_ij + dz_ij * dz_ij); // // Vector connecting k->j, using minimum image convention // dx_jk = sim.r[(j * 3) + 0] - sim.r[(k * 3) + 0]; dy_jk = sim.r[(j * 3) + 1] - sim.r[(k * 3) + 1]; dz_jk = sim.r[(j * 3) + 2] - sim.r[(k * 3) + 2]; VecMinimumImage(dx_jk, dy_jk, dz_jk, ref dx_jk, ref dy_jk, ref dz_jk, ref sim.cell); double jk_mag = Math.Sqrt(dx_jk * dx_jk + dy_jk * dy_jk + dz_jk * dz_jk); double ij_dot_jk = dx_ij * dx_jk + dy_ij * dy_jk + dz_ij * dz_jk; double ij_mag_jk = ij_mag * jk_mag; // // Following Gromacs; perhaps check cos_theta for -1 < cos_theta < 1? // double cos_theta = ij_dot_jk / ij_mag_jk; double theta = Math.Acos(cos_theta); double sin_theta = Math.Sin(theta); if (Math.Abs(sin_theta) < theta_tol) { sin_theta = theta_tol; } double st = theta_k * (theta - theta_eq) / sin_theta; double sth = st * cos_theta; double cik = st / (ij_mag * jk_mag); double cii = sth / (ij_mag * ij_mag); double ckk = sth / (jk_mag * jk_mag); fx_i = -cik * dx_jk + cii * dx_ij; fy_i = -cik * dy_jk + cii * dy_ij; fz_i = -cik * dz_jk + cii * dz_ij; fx_k = -cik * dx_ij + ckk * dx_jk; fy_k = -cik * dy_ij + ckk * dy_jk; fz_k = -cik * dz_ij + ckk * dz_jk; // // Force acting on the central site calculated form other forces; angle // potential is conservative and internal, so net acceleration on the 3 // sites from angle force should be zero. Hence, forces should cancel. // sim.f[(i * 3) + 0] += fx_i; sim.f[(i * 3) + 1] += fy_i; sim.f[(i * 3) + 2] += fz_i; sim.f[(j * 3) + 0] += -fx_i - fx_k; sim.f[(j * 3) + 1] += -fy_i - fy_k; sim.f[(j * 3) + 2] += -fz_i - fz_k; sim.f[(k * 3) + 0] += fx_k; sim.f[(k * 3) + 1] += fy_k; sim.f[(k * 3) + 2] += fz_k; // // Pressure tensor contribution // sim.pressure[0] += dx_ij * fx_i + dx_jk * fx_k; sim.pressure[1] += dx_ij * fy_i + dx_jk * fy_k; sim.pressure[2] += dx_ij * fz_i + dx_jk * fz_k; sim.pressure[3] += dy_ij * fx_i + dy_jk * fx_k; sim.pressure[4] += dy_ij * fy_i + dy_jk * fy_k; sim.pressure[5] += dy_ij * fz_i + dy_jk * fz_k; sim.pressure[6] += dz_ij * fx_i + dz_jk * fx_k; sim.pressure[7] += dz_ij * fy_i + dz_jk * fy_k; sim.pressure[8] += dz_ij * fz_i + dz_jk * fz_k; // // Add angle energy to accumulator // double delta = theta - theta_eq; sim.angle_energy += 0.5 * theta_k * (delta * delta); } }
// // Faster method to evaluate pair interactions using link cells ( ~ O(N) ). // Negelects Verlet lists for simplicity; instead, iterates over link cells every time. // Assumes periodic wrap applied before this routine is called. // public static void DoNonbondedFast(DPDSim sim) { var N = sim.site_ids.Length; double cutsq = sim.rcut * sim.rcut; double sqrt_dt = Math.Sqrt(sim.delta_t); var ncellx = (int)Math.Floor(sim.cell[0] / sim.rcut); var ncelly = (int)Math.Floor(sim.cell[1] / sim.rcut); var ncellz = (int)Math.Floor(sim.cell[2] / sim.rcut); if (ncellx < 3 || ncelly < 3 || ncellz < 3) { DPDError("A cell dimension has fewer than 3 cells; this is a linked list cell error."); } var ncells = ncellx * ncelly * ncellz; // // If we're using a dynamic simulation cell, regenerate if/when needed. // //SetupCells( sim ); if (sim.cell_head.Length != ncells) { DPDError("sim.cell_head.Length ({0}) != ncells ({1}); did you call SetupCells()?", sim.cell_head.Length, ncells); } // // Reset cell head indices. // for (var i = 0; i < sim.cell_head.Length; i++) { sim.cell_head[i] = -1; } // // Assign sites to cells, update cell head indices and contents. // if (sim.cell_next.Length != N) { Array.Resize(ref sim.cell_next, N); } for (var i = 0; i < N; i++) { var j = i * 3; var cellx = (int)Math.Floor(((sim.r[j + 0] / sim.cell[0]) + 0.5) * ncellx); var celly = (int)Math.Floor(((sim.r[j + 1] / sim.cell[1]) + 0.5) * ncelly); var cellz = (int)Math.Floor(((sim.r[j + 2] / sim.cell[2]) + 0.5) * ncellz); var cell_no = cellx + (celly * ncellx) + (cellz * ncelly * ncellx); sim.cell_next[i] = sim.cell_head[cell_no]; sim.cell_head[cell_no] = i; } // // Faster version of pairwise interactions using neighbour cells. // // // Loop over all cells // for (var cell_no = 0; cell_no < ncellx * ncelly * ncellz; cell_no++) { // // Loop over contents of current cell // for (var i = sim.cell_head[cell_no]; i != -1; i = sim.cell_next[i]) { // // Loop over contents of neighbour cells ( includes central cell at offset 0 in cell_neighbours ) // for (var k = 0; k < DPDSim.nneighbours; k++) { var j = k; // dummy initialization, to make sure correct type. Value overwritten below. if (k == 0) { j = sim.cell_next[i]; } // same cell: loop over j>i in current cell else { j = sim.cell_head[sim.cell_neighbours[(cell_no * DPDSim.nneighbours) + k]]; } // different cell: loop over all j in other cell for ( ; j != -1; j = sim.cell_next[j]) { nonbonded_pair(i, j, cutsq, sqrt_dt, sim); } } } } }
private static void nonbonded_pair(int i, int j, double cutsq, double sqrt_dt, DPDSim sim) { double dx, dy, dz; double dx_hat, dy_hat, dz_hat; double fx, fy, fz; double vx, vy, vz; var i_off = i * 3; var j_off = j * 3; // // Ignore bound sites. I should probably check generated code to see this is worth unrolling. // for (var k = 0; k < DPDSim.MaxExclusionEntries; k++) { if (sim.exclude[(i * DPDSim.MaxExclusionEntries) + k] == j) { return; } } // // Difference in particle positions (minimum image convention is applied) and velocities. // Try for the early skip, so we don't waste time reading velocities from memory if // we don't need to (should also help reduce cache pressure etc). // dx = sim.r[i_off + 0] - sim.r[j_off + 0]; dy = sim.r[i_off + 1] - sim.r[j_off + 1]; dz = sim.r[i_off + 2] - sim.r[j_off + 2]; VecMinimumImage(dx, dy, dz, ref dx, ref dy, ref dz, ref sim.cell); double r_mag = (dx * dx + dy * dy + dz * dz); // Avoid sqrt() until we know it's needed, compare squared distances instead if (r_mag > cutsq) { return; } vx = sim.v[i_off + 0] - sim.v[j_off + 0]; vy = sim.v[i_off + 1] - sim.v[j_off + 1]; vz = sim.v[i_off + 2] - sim.v[j_off + 2]; r_mag = Math.Sqrt(r_mag); dx_hat = dx / r_mag; dy_hat = dy / r_mag; dz_hat = dz / r_mag; double rhat_dot_v = (dx_hat * vx) + (dy_hat * vy) + (dz_hat * vz); // // Conservative and random weightings are the same, dissipative // weight = random weight^2 // double cons_weight = 1.0 - r_mag / sim.rcut; double rand_weight = cons_weight; double diss_weight = rand_weight * rand_weight; // // Conservative interaction parameters (interactions defined in kBT) // double a = sim.interactions[(sim.site_ids[i] * sim.site_types.Count) + sim.site_ids[j]]; sim.nonbonded_energy += a * (r_mag * ((r_mag / (2.0 * sim.rcut)) - 1) + (sim.rcut / 2.0)); // // Accumulate conservative force // fx = a * cons_weight * dx_hat; fy = a * cons_weight * dy_hat; fz = a * cons_weight * dz_hat; // // Accumulate dissipative force // fx += -sim.fric * diss_weight * rhat_dot_v * dx_hat; fy += -sim.fric * diss_weight * rhat_dot_v * dy_hat; fz += -sim.fric * diss_weight * rhat_dot_v * dz_hat; // // Accumulate random force - gasdev() returns zero mean, unit variance. // double random_number = (double)Ran1.gasdev(ref sim.ran1_value); fx += sim.sigma * rand_weight * random_number * dx_hat / sqrt_dt; fx += sim.sigma * rand_weight * random_number * dy_hat / sqrt_dt; fx += sim.sigma * rand_weight * random_number * dz_hat / sqrt_dt; // // Update sim force arrays // sim.f[i_off + 0] += fx; sim.f[i_off + 1] += fy; sim.f[i_off + 2] += fz; sim.f[j_off + 0] -= fx; sim.f[j_off + 1] -= fy; sim.f[j_off + 2] -= fz; // // Pressure tensor contribution // sim.pressure[0] += dx * fx; sim.pressure[1] += dx * fy; sim.pressure[2] += dx * fz; sim.pressure[3] += dy * fx; sim.pressure[4] += dy * fy; sim.pressure[5] += dy * fz; sim.pressure[6] += dz * fx; sim.pressure[7] += dz * fy; sim.pressure[8] += dz * fz; // // Maintain a tally of the number of pair interactions // sim.ninteractions += 1.0; }
// // Harmonic bonds: // U(r) = 0.5k( r - r_eq )**2 // public static void DoBonds(DPDSim sim) { double dx, dy, dz; double dx_hat, dy_hat, dz_hat; double fx, fy, fz; var N_bonds = sim.bond_site_indices.Length / 2; for (var bond_i = 0; bond_i < N_bonds; bond_i++) { var i = sim.bond_site_indices[(bond_i * 2) + 0]; var j = sim.bond_site_indices[(bond_i * 2) + 1]; dx = sim.r[(i * 3) + 0] - sim.r[(j * 3) + 0]; dy = sim.r[(i * 3) + 1] - sim.r[(j * 3) + 1]; dz = sim.r[(i * 3) + 2] - sim.r[(j * 3) + 2]; // // Minimum image separation // VecMinimumImage(dx, dy, dz, ref dx, ref dy, ref dz, ref sim.cell); double dr_mag = Math.Sqrt(dx * dx + dy * dy + dz * dz); dx_hat = dx / dr_mag; dy_hat = dy / dr_mag; dz_hat = dz / dr_mag; // // omega = energy, gamma = derivative of energy wrt particle separation // double K = sim.bond_k[bond_i]; double r0 = sim.bond_eq[bond_i]; double omega = 0.5 * K * ((dr_mag - r0) * (dr_mag - r0)); double gamma = K * (dr_mag - r0); // // Accumulate force on particles due to bond // fx = -gamma * dx_hat; fy = -gamma * dy_hat; fz = -gamma * dz_hat; sim.f[(i * 3) + 0] += fx; sim.f[(i * 3) + 1] += fy; sim.f[(i * 3) + 2] += fz; sim.f[(j * 3) + 0] -= fx; sim.f[(j * 3) + 1] -= fy; sim.f[(j * 3) + 2] -= fz; // // Accumulate bond energy // sim.bond_energy += omega; // // Accumulate contribution to virial // sim.pressure[0] += dx * fx; sim.pressure[1] += dx * fy; sim.pressure[2] += dx * fz; sim.pressure[3] += dy * fx; sim.pressure[4] += dy * fy; sim.pressure[5] += dy * fz; sim.pressure[6] += dz * fx; sim.pressure[7] += dz * fy; sim.pressure[8] += dz * fz; } }
static void Main(string[] args) { if (args.Length < 1) { Console.WriteLine("Pass in simulation definition file as first parameter!"); System.Environment.Exit(-1); } DPDSim sim = new DPDSim(); // // Load DPD sim data // try { using (StreamReader f = File.OpenText(args[0])) { DPDIO.LoadSim(f, sim); } } catch (Exception e) { Console.WriteLine(e); DPDError("Unable to open input file '{0}'", args[0]); } // // Print initial system info // Console.WriteLine("Friction coefficient is {0} ( as sigma = {1} )", sim.fric, sim.sigma); Console.WriteLine("Bead density is {0} per cubic Rc", ((double)sim.site_ids.Length) / (sim.cell[0] * sim.cell[1] * sim.cell[2])); { sim.ClearEnergyAndPressure(); if (sim.i_am_dumb == 1) { Forces.DoNonbondedSlow(sim); } else { Forces.DoNonbondedFast(sim); } Forces.DoBonds(sim); Forces.DoAngles(sim); DPDIO.PrintSimInfo(sim, 0.0); } // // Main integration loop // var time_start = DateTime.Now; for ( ; sim.step_no <= sim.max_steps; sim.step_no++) { sim.ClearEnergyAndPressure(); Integrator.VelocityVerlet(sim); if (sim.step_no % sim.save_every == 0) { save_checkpoint_and_trajectory(sim); } if (sim.step_no % sim.print_every == 0) { DPDIO.PrintSimInfo(sim, (DateTime.Now - time_start).TotalSeconds); } } // // Final information // Console.WriteLine(""); Console.WriteLine("Final information:"); Console.WriteLine(""); DPDIO.PrintSimInfo(sim, (DateTime.Now - time_start).TotalSeconds); save_checkpoint_and_trajectory(sim); }
private static void parse_dpd_sim(StreamReader f, DPDSim sim) { var delim = new char[] { ' ', ',', '\t' }; string linebuffer; bool cell_found = false; ParseState parse_state = ParseState.None; int site_upto = 0, line_no = 0; var site = new DPDSiteType(); var mol = new DPDMoleculeType(); mol.Clear(); sim.Clear(); while ((linebuffer = f.ReadLine()) != null) { line_no++; var tokens = linebuffer.Split(delim, StringSplitOptions.RemoveEmptyEntries); if (tokens.Length < 1) { continue; } if (tokens[0].Length < 1 || tokens[0][0] == '#') { continue; } // if we hit an end flag if (tokens[0] == "end") { if (parse_state == ParseState.None) { DPDError("Unexpected 'end' token"); } if (parse_state == ParseState.Molecule) { sim.molecule_types.Add(mol); mol = new DPDMoleculeType(); } parse_state = ParseState.None; } // if parsing the system settings ... else if (parse_state == ParseState.Settings) { var key = tokens[0]; if (key == "kBT") { sim.target_kBT = Convert.ToDouble(tokens[1]); } else if (key == "sigma") { sim.sigma = Convert.ToDouble(tokens[1]); } else if (key == "lambda") { sim.lambda = Convert.ToDouble(tokens[1]); } else if (key == "delta_t") { sim.delta_t = Convert.ToDouble(tokens[1]); } else if (key == "step_no") { sim.step_no = Convert.ToInt32(tokens[1]); } else if (key == "max_steps") { sim.max_steps = Convert.ToInt32(tokens[1]); } else if (key == "save_every") { sim.save_every = Convert.ToInt32(tokens[1]); } else if (key == "print_every") { sim.print_every = Convert.ToInt32(tokens[1]); } else if (key == "ran1") { sim.ran1_value = Convert.ToInt64(tokens[1]); } else if (key == "dumb") { sim.i_am_dumb = 1; } else if (key == "cell") { cell_found = true; sim.cell[0] = Convert.ToDouble(tokens[1]); sim.cell[1] = Convert.ToDouble(tokens[2]); sim.cell[2] = Convert.ToDouble(tokens[3]); } else { Console.WriteLine("Unknown entry {0} found on line {1} in settings; ignoring.", key, line_no); } } // if parsing the site declarations ... else if (parse_state == ParseState.Sites) { site.name = tokens[0]; site.internal_id = sim.site_types.Count; sim.site_types.Add(site); site = new DPDSiteType(); } // if parsing the nonbonded interaction parameters ... else if (parse_state == ParseState.Interactions) { var N_site_types = sim.site_types.Count; var i = get_site_type_from_name(tokens[0], sim); var j = get_site_type_from_name(tokens[1], sim); // j and l are the internal ids, so use them. sim.interactions[(i * N_site_types) + j] = Convert.ToDouble(tokens[2]); // symmetrical! sim.interactions[(j * N_site_types) + i] = sim.interactions[(i * N_site_types) + j]; } // if parsing a molecule ... else if (parse_state == ParseState.Molecule) { var key = tokens[0]; if (key == "name") { mol.name = tokens[1]; } else if (key == "count") { mol.count = Convert.ToInt32(tokens[1]); } else if (key == "site") { var i = get_site_type_from_name(tokens[1], sim); if (i == -1) { DPDError("Error on line {0}; unable to find a type id for molecule site of type {1} in {2}. Probably undefined.", line_no, tokens[1], mol.name); } mol.site_internal_ids.Add(i); } else if (key == "bond") { var N = mol.site_internal_ids.Count; // check sites exist! for (var i = 0; i < 2; i++) { var idx = Convert.ToInt32(tokens[1 + i]); if (idx < 1 || idx > N) { DPDError("Error on line {0}; bond index {1} is invalid.", line_no, idx); } mol.bond_site_indices.Add(idx); } mol.bond_eq.Add(Convert.ToDouble(tokens[3])); mol.bond_k.Add(Convert.ToDouble(tokens[4])); } else if (key == "angle") { var N = mol.site_internal_ids.Count; // check sites exist! for (var i = 0; i < 3; i++) { var idx = Convert.ToInt32(tokens[1 + i]); if (idx < 1 || idx > N) { DPDError("Error on line {0}; angle index {1} is invalid.", line_no, idx); } mol.angle_site_indices.Add(idx); } mol.angle_eq.Add(Convert.ToDouble(tokens[4])); mol.angle_k.Add(Convert.ToDouble(tokens[5])); } else { Console.WriteLine("Unknown entry {0} found on line {1} in molecule; ignoring.", key, line_no); } } // if parsing the coords ... else if (parse_state == ParseState.Coords) { if (site_upto > sim.site_ids.Length) { DPDError("Error on line {0}; this site should not exist", line_no); } var i = get_site_type_from_name(tokens[0], sim); if (i == -1) { DPDError("Error on line {0}; this site ( {1} ) is not recognised as a defined site type", line_no, tokens[0]); } sim.site_ids[site_upto] = i; sim.r[(site_upto * 3) + 0] = Convert.ToDouble(tokens[1]); sim.r[(site_upto * 3) + 1] = Convert.ToDouble(tokens[2]); sim.r[(site_upto * 3) + 2] = Convert.ToDouble(tokens[3]); // ignore velocity and force info if start of sim; this can also be used to force reset of info. if (sim.step_no > 0) { if (tokens.Length > 4) // try to get velocities from file { if (tokens.Length < 7) { DPDError("Error on line {0}; incomplete velocity entry for site! Only {1} value, and expecting 3 ( vx vy vz )", line_no, tokens.Length - 4); } sim.v[(site_upto * 3) + 0] = Convert.ToDouble(tokens[4]); sim.v[(site_upto * 3) + 1] = Convert.ToDouble(tokens[5]); sim.v[(site_upto * 3) + 2] = Convert.ToDouble(tokens[6]); } if (tokens.Length > 7) // try to get forces from file { if (tokens.Length < 10) { DPDError("Error on line {0}; incomplete force entry for site! Only {1} value, and expecting 3 ( fx fy fz )", line_no, tokens.Length - 7); } sim.f[(site_upto * 3) + 0] = Convert.ToDouble(tokens[7]); sim.f[(site_upto * 3) + 1] = Convert.ToDouble(tokens[8]); sim.f[(site_upto * 3) + 2] = Convert.ToDouble(tokens[9]); } } site_upto++; } // did we find the start of a defined parse section? else { string key = tokens[0]; if (key == "settings") { parse_state = ParseState.Settings; } else if (key == "sites") { parse_state = ParseState.Sites; } else if (key == "interactions") { var N_site_types = sim.site_types.Count; if (N_site_types < 1) { DPDError("Error on line {0}; attempting to define interactions without sites having been specified.", line_no); } Array.Resize(ref sim.interactions, N_site_types * N_site_types); for (var i = 0; i < sim.interactions.Length; i++) { sim.interactions[i] = 0.0; } parse_state = ParseState.Interactions; } else if (key == "molecule") { parse_state = ParseState.Molecule; } else if (key == "coords") { var N_sites = 0; foreach (var mt in sim.molecule_types) { N_sites += (mt.site_internal_ids.Count * mt.count); } Array.Resize(ref sim.site_ids, N_sites); Array.Resize(ref sim.molecule_ids, N_sites); Array.Resize(ref sim.r, N_sites * 3); Array.Resize(ref sim.v, N_sites * 3); Array.Resize(ref sim.f, N_sites * 3); Array.Resize(ref sim.v_, N_sites * 3); Array.Resize(ref sim.f_, N_sites * 3); parse_state = ParseState.Coords; } else { DPDError("Unknown parse section '{0}'' on line {1}", key, line_no); } } } // // Check for some obvious problems with the input. // if (!cell_found) { DPDError("cell not defined in DPD sim file"); } if (sim.cell[0] / 2.0 < sim.rcut || sim.cell[1] / 2.0 < sim.rcut || sim.cell[2] / 2.0 < sim.rcut) { DPDError("A cell dimension divided by two is smaller than rcut"); } if (sim.site_types.Count == 0) { DPDError("No sites defined in file"); } if (sim.molecule_types.Count == 0) { DPDError("No molecules defined in file"); } if (sim.interactions.Length == 0) { DPDError("No interactions defined in file"); } if (sim.site_ids.Length == 0) { DPDError("No site coordinates defined in file"); } if (site_upto != sim.site_ids.Length) { DPDError("Error in number of sites found; got {0}, wanted {1}\n", site_upto, sim.site_ids.Length); } // // Print some system information. // // // System settings // { Console.WriteLine("DPD simulation parameters:"); Console.WriteLine("\tstep_no is {0}", sim.step_no); Console.WriteLine("\tmax_steps is {0}", sim.max_steps); Console.WriteLine("\tsave_every is {0}", sim.save_every); Console.WriteLine("\tprint_every is {0}", sim.print_every); Console.WriteLine("\tdelta_t is {0}", sim.delta_t); Console.WriteLine("\tran1 initialised with {0}", sim.ran1_value); Console.WriteLine("\trcut is {0}", sim.rcut); Console.WriteLine("\tlambda is {0}", sim.lambda); Console.WriteLine("\tsigma is {0}", sim.sigma); Console.WriteLine("\tkBT is {0}", sim.target_kBT); Console.WriteLine("\tcell is {0}, {1}, {2}", sim.cell[0], sim.cell[1], sim.cell[2]); if (sim.i_am_dumb == 1) { Console.WriteLine("\t!!! This simulation is dumb regarding nonbonded interactions !!!"); } } // // Site types // Console.WriteLine("{0} site types:", sim.site_types.Count); for (var i = 0; i < sim.site_types.Count; i++) { Console.WriteLine("\t{0}; (internal {1})", sim.site_types[i].name, sim.site_types[i].internal_id); } // // Molecule types // Console.WriteLine("{0} molecule types:", sim.molecule_types.Count); for (int mi = 0; mi < sim.molecule_types.Count; mi++) { Console.WriteLine("\t{0}; {1} counts in system:", sim.molecule_types[mi].name, sim.molecule_types[mi].count); Console.WriteLine("\t\t{0} sites", sim.molecule_types[mi].site_internal_ids.Count); for (int si = 0; si < sim.molecule_types[mi].site_internal_ids.Count; si++) { var id = sim.molecule_types[mi].site_internal_ids[si]; Console.WriteLine("\t\t\t{0}, (id {1})", sim.site_types[id].name, sim.site_types[id].internal_id); } var n_bonds = sim.molecule_types[mi].bond_site_indices.Count / 2; Console.WriteLine("\t\t{0} bonds", n_bonds); for (var bi = 0; bi < n_bonds; bi++) { Console.WriteLine("\t\t\t{0} - {1} : eq length {2:F3}, k {3:F3}", sim.molecule_types[mi].bond_site_indices[bi * 2 + 0], sim.molecule_types[mi].bond_site_indices[bi * 2 + 1], sim.molecule_types[mi].bond_eq[bi], sim.molecule_types[mi].bond_k[bi]); } var n_angles = sim.molecule_types[mi].angle_site_indices.Count / 3; Console.WriteLine("\t\t{0} angles", n_angles); for (var ai = 0; ai < n_angles; ai++) { Console.WriteLine("\t\t\t{0} - {1} - {2} : eq length {3:F3}, k {4:F3}", sim.molecule_types[mi].angle_site_indices[ai * 2 + 0], sim.molecule_types[mi].angle_site_indices[ai * 2 + 1], sim.molecule_types[mi].angle_site_indices[ai * 2 + 1], sim.molecule_types[mi].angle_eq[ai], sim.molecule_types[mi].angle_k[ai]); } } // // Nonbonded interaction table // { var N_site_types = sim.site_types.Count; Console.Write("{0} interactions (defined in kBT):\n{1,12:S}", N_site_types, " "); for (var i = 0; i < N_site_types; i++) { Console.Write("\t{0,12:S}", sim.site_types[i].name); } Console.WriteLine(""); for (var i = 0; i < N_site_types; i++) { Console.Write("\t{0,12:S}", sim.site_types[i].name); for (var j = 0; j < N_site_types; j++) { Console.Write("\t{0,9:F3}", sim.interactions[(i * N_site_types) + j]); } Console.WriteLine(""); } } // // Check the list of sites agrees with the types expected from the molecule definitions // { var l = 0; for (var mi = 0; mi < sim.molecule_types.Count; mi++) { for (var j = 0; j < sim.molecule_types[mi].count; j++) { for (var k = 0; k < sim.molecule_types[mi].site_internal_ids.Count; k++) { var expected_type = sim.molecule_types[mi].site_internal_ids[k]; var actual_type = sim.site_ids[l]; var expected_name = sim.site_types[expected_type].name; var actual_name = sim.site_types[actual_type].name; if (actual_type != expected_type) { DPDError("Error in site id; wanted {0} ( \"{1}\" from molecule \"{2}\" number {3}, atom {4} ) but found {5} ( \"{6}\" )", expected_type, expected_name, sim.molecule_types[mi].name, j + 1, k + 1, actual_type, actual_name); } l++; } } } } Console.WriteLine("{0} sites", sim.site_ids.Length); }
// // Print some useful information to the console // public static void PrintSimInfo(DPDSim sim, double cpu_time) { var com = new double[3]; // centre of mass var mom = new double[3]; // net momentum var N_sites = sim.site_ids.Length; var N_bonds = sim.bond_site_indices.Length; var N_angles = sim.angle_site_indices.Length; // // Determine current centre of mass and net momentum of the system // com[0] = com[1] = com[2] = 0.0; mom[0] = mom[1] = mom[2] = 0.0; for (var i = 0; i < N_sites; i++) { com[0] += sim.r[(i * 3) + 0]; com[1] += sim.r[(i * 3) + 1]; com[2] += sim.r[(i * 3) + 2]; var vx = sim.v[(i * 3) + 0]; var vy = sim.v[(i * 3) + 1]; var vz = sim.v[(i * 3) + 2]; mom[0] += vx; mom[1] += vy; mom[2] += vz; } com[0] = com[0] / N_sites; com[1] = com[1] / N_sites; com[2] = com[2] / N_sites; // // Estimate kBT via ensemble average kinetic energy of particle ( KE_p = <1/2 m.v^2> ): // KE_p = 3/2 kBT ; kBT = 2/3 KE_p // var kBT = (2.0 / 3.0) * (sim.kinetic_energy / N_sites); Console.WriteLine("Step {0}/{1}, sim time {2:F2}, CPU time {3:F0}s:", sim.step_no, sim.max_steps, sim.step_no * sim.delta_t, cpu_time); Console.WriteLine("\tTotal energy : {0,12:F6}", sim.kinetic_energy + sim.nonbonded_energy + sim.bond_energy + sim.angle_energy); Console.WriteLine("\tKinetic energy : {0,12:F6} ( Average {1,12:F6}, target kBT {2,12:F6}, current kBT {3,12:F6}", sim.kinetic_energy, sim.kinetic_energy / N_sites, sim.target_kBT, kBT); Console.WriteLine("\tNonbonded energy : {0,12:F6} ( Average {1,12:F6} from {2:F0} collisions )", sim.nonbonded_energy, sim.nonbonded_energy / sim.ninteractions, sim.ninteractions); if (N_bonds > 0) { Console.WriteLine("\tBond energy : {0,12:F6} ( Average {1,12:F6} )", sim.bond_energy, sim.bond_energy / N_bonds); } else { Console.WriteLine("\tBond energy : 0"); } if (N_angles > 0) { Console.WriteLine("\tAngle energy : {0,12:F6} ( Average {1,12:F6} )", sim.angle_energy, sim.angle_energy / N_angles); } else { Console.WriteLine("\tangle energy : 0"); } Console.WriteLine("\tPressure : {0,12:F6} {1,12:F6} {2,12:F6}", sim.pressure[0], sim.pressure[1], sim.pressure[2]); Console.WriteLine("\t {0,12:F6} {1,12:F6} {2,12:F6}", sim.pressure[3], sim.pressure[4], sim.pressure[5]); Console.WriteLine("\t {0,12:F6} {1,12:F6} {2,12:F6}", sim.pressure[6], sim.pressure[7], sim.pressure[8]); Console.WriteLine("\tSystem centre of mass = {0,12:F6} {1,12:F6} {2,12:F6}", com[0], com[1], com[2]); Console.WriteLine("\tNet system momentum = {0,12:F6} {1,12:F6} {2,12:F6}", mom[0], mom[1], mom[2]); Console.WriteLine("\n"); }
// // Save a DPD sim file, suitable for loading in as a restart point. // public static void SaveSim(StreamWriter f, DPDSim sim) { var N_site_types = sim.site_types.Count; var N_mol_types = sim.molecule_types.Count; // // Settings // f.WriteLine("settings"); f.WriteLine("\tstep_no {0}", sim.step_no); f.WriteLine("\tmax_steps {0}", sim.max_steps); f.WriteLine("\tdelta_t {0}", sim.delta_t); f.WriteLine("\tlambda {0}", sim.lambda); f.WriteLine("\tsigma {0}", sim.sigma); f.WriteLine("\tkBT {0}", sim.target_kBT); f.WriteLine("\tran1 {0}", sim.ran1_value); f.WriteLine("\tsave_every {0}", sim.save_every); f.WriteLine("\tprint_every {0}", sim.print_every); f.WriteLine("\tcell {0:G} {1:G} {2:G}\n", sim.cell[0], sim.cell[1], sim.cell[2]); f.WriteLine("end"); f.WriteLine(""); // // Sites // f.WriteLine("sites"); for (var i = 0; i < N_site_types; i++) { f.WriteLine("\t{0}", sim.site_types[i].name); } f.WriteLine("end"); f.WriteLine(""); // // Interactions // f.WriteLine("interactions"); for (var i = 0; i < N_site_types; i++) { for (var j = i; j < N_site_types; j++) { f.WriteLine("\t{0}\t{1}\t{2}\n", sim.site_types[i].name, sim.site_types[j].name, sim.interactions[(i * N_site_types) + j]); } } f.WriteLine("end"); f.WriteLine(""); // // Molecules // for (var i = 0; i < N_mol_types; i++) { write_molecule_type(f, sim.molecule_types[i], sim); f.WriteLine(""); } // // Coords // f.WriteLine("coords"); for (var i = 0; i < sim.site_ids.Length; i++) { var site_id = sim.site_ids[i]; f.WriteLine("\t{0}", sim.site_types[site_id].name); f.WriteLine("\t{0,12:F6} {1,12:F6} {2,12:F6}", sim.r[(i * 3) + 0], sim.r[(i * 3) + 1], sim.r[(i * 3) + 2]); f.WriteLine("\t{0,12:F6} {1,12:F6} {2,12:F6}", sim.v[(i * 3) + 0], sim.v[(i * 3) + 1], sim.v[(i * 3) + 2]); f.WriteLine("\t{0,12:F6} {1,12:F6} {2,12:F6}", sim.f[(i * 3) + 0], sim.f[(i * 3) + 1], sim.f[(i * 3) + 2]); } f.WriteLine("end"); f.WriteLine(""); }
public static void LoadSim(StreamReader f, DPDSim sim) { parse_dpd_sim(f, sim); // // How many bonds and angles do we need, given the molecule definitions? // int N_bonds = 0; int N_angles = 0; foreach (var mol in sim.molecule_types) { N_bonds += mol.count * mol.bond_k.Count; N_angles += mol.count * mol.angle_k.Count; } Array.Resize(ref sim.bond_site_indices, N_bonds * 2); Array.Resize(ref sim.bond_eq, N_bonds); Array.Resize(ref sim.bond_k, N_bonds); Array.Resize(ref sim.angle_site_indices, N_angles * 3); Array.Resize(ref sim.angle_eq, N_angles); Array.Resize(ref sim.angle_k, N_angles); // // Populate system bond and angle arrays using molecule definitions and counts // int sys_bond_upto = 0; int sys_angle_upto = 0; int sys_molecule_id = 0; int offset = 0; // start index into system sites for the current molecule foreach (var mol in sim.molecule_types) { for (var mol_inst = 0; mol_inst < mol.count; mol_inst++) { var N = mol.bond_k.Count; for (var bi = 0; bi < N; bi++) { var i = offset + mol.bond_site_indices[(bi * 2) + 0]; var j = offset + mol.bond_site_indices[(bi * 2) + 1]; var b_eq = mol.bond_eq[bi]; var b_k = mol.bond_k[bi]; sim.bond_site_indices[sys_bond_upto * 2 + 0] = i - 1; // -1 : unit based index -> zero based index sim.bond_site_indices[sys_bond_upto * 2 + 1] = j - 1; sim.bond_eq[sys_bond_upto] = b_eq; sim.bond_k[sys_bond_upto] = b_k; sys_bond_upto++; } N = mol.angle_k.Count; for (var ai = 0; ai < N; ai++) { var i = offset + mol.angle_site_indices[(ai * 3) + 0]; var j = offset + mol.angle_site_indices[(ai * 3) + 1]; var k = offset + mol.angle_site_indices[(ai * 3) + 2]; var a_eq = mol.angle_eq[ai]; var a_k = mol.angle_k[ai]; sim.angle_site_indices[sys_angle_upto * 3 + 0] = i - 1; // -1 : unit based index -> zero based index sim.angle_site_indices[sys_angle_upto * 3 + 1] = j - 1; sim.angle_site_indices[sys_angle_upto * 3 + 2] = k - 1; sim.angle_eq[sys_angle_upto] = a_eq; sim.angle_k[sys_angle_upto] = a_k; sys_angle_upto++; } N = mol.site_internal_ids.Count; for (var i = 0; i < N; i++) { sim.molecule_ids[offset + i] = sys_molecule_id; } sys_molecule_id++; offset += mol.site_internal_ids.Count; // update current site offset for bond indices. } } // // Nonbonded exclusion lists; used in nonbonded force calculations. // MaxExclusionEntries suggested to be 4. // Only bonds used here; angles also trivial via i,k sites of angle i-j-k. // var MaxExclusions = DPDSim.MaxExclusionEntries; Array.Resize(ref sim.exclude, sim.site_ids.Length * MaxExclusions); for (var i = 0; i < sim.exclude.Length; i++) { sim.exclude[i] = -1; } for (var bi = 0; bi < sim.bond_k.Length; bi++) { var i = sim.bond_site_indices[(bi * 2) + 0]; var j = sim.bond_site_indices[(bi * 2) + 1]; // i exclusion entry for j var l = 0; while (l < MaxExclusions && sim.exclude[(i * MaxExclusions) + l] != -1) { l++; } if (l >= MaxExclusions) { DPDError("Too few exclusion entries defined (1); increase DPDsim.MaxExclusionEntries"); } sim.exclude[(i * MaxExclusions) + l] = j; // j exclusion entry for i l = 0; while (l < MaxExclusions && sim.exclude[(j * MaxExclusions) + l] != -1) { l++; } if (l >= MaxExclusions) { DPDError("Too few exclusion entries defined (2); increase DPDsim.MaxExclusionEntries"); } sim.exclude[(j * MaxExclusions) + l] = i; } sim.ZeroNetMomentum(); // // Should we initialize the system velocities, or leave the existing values? // if (sim.step_no < 1) { Console.WriteLine("step_no < 1, assuming system initialisation required; site velocities set from a Gaussian distribution."); sim.step_no = 1; sim.SetInitialVelocities(); } // // Wrap particle positions that lie outside the periodic cell // { for (var i = 0; i < sim.site_ids.Length; i++) { var j = i * 3; var x = sim.r[j + 0]; var y = sim.r[j + 1]; var z = sim.r[j + 2]; VecMinimumImage(x, y, z, ref x, ref y, ref z, ref sim.cell); sim.r[j + 0] = x; sim.r[j + 1] = y; sim.r[j + 2] = z; } } // // Link cell data only needs to be set up once if the cell is constant // sim.SetupCells(); // // Calculate friction coefficient from sigma; sigma^2 = 2*fric*kBT // sim.fric = (sim.sigma * sim.sigma) / (2.0 * sim.target_kBT); // // Initialize ran1() with the seed provided // Ran1.ran1(ref sim.ran1_value); }