예제 #1
0
파일: IO.cs 프로젝트: JohnGrime/DPD-CSharp
//
// 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");
        }
예제 #2
0
파일: IO.cs 프로젝트: JohnGrime/DPD-CSharp
//
// 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);
        }
예제 #3
0
        //
        // 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);
                }
            }
        }
예제 #4
0
        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."); }
        }
예제 #5
0
파일: IO.cs 프로젝트: JohnGrime/DPD-CSharp
//
// 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]);
            }
        }
예제 #6
0
        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;
            }
        }
예제 #7
0
        //
        // 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);
            }
        }
예제 #8
0
        //
        // 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);
                        }
                    }
                }
            }
        }
예제 #9
0
        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;
        }
예제 #10
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;
            }
        }
예제 #11
0
        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);
        }
예제 #12
0
파일: IO.cs 프로젝트: JohnGrime/DPD-CSharp
        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);
        }
예제 #13
0
파일: IO.cs 프로젝트: JohnGrime/DPD-CSharp
//
// 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");
        }
예제 #14
0
파일: IO.cs 프로젝트: JohnGrime/DPD-CSharp
//
// 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("");
        }
예제 #15
0
파일: IO.cs 프로젝트: JohnGrime/DPD-CSharp
        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);
        }