<commit_before>// Lumol, an extensible molecular simulation engine
// Copyright (C) 2015-2016 Lumol's contributors — BSD license

use std::ops::{Deref, DerefMut};
use std::collections::BTreeMap;

use types::{Vector3D, Matrix3};

use energy::{PairInteraction, BondPotential, AnglePotential, DihedralPotential};
use energy::{GlobalPotential, CoulombicPotential};

use sys::{Configuration, Particle, ParticleKind, UnitCell};
use sys::{Composition, Interactions, EnergyEvaluator};

/// The `System` type hold all the data about a simulated system.
///
/// This data contains:
///
///   - an unit cell, containing the system;
///   - a list of particles in the system;
///   - a list of molecules in the system;
///   - a list of interactions, associating particles kinds and potentials
///
/// In the implementation, the particles contained in a molecule are guaranteed
/// to be contiguous in memory. This allow for faster access when iterating
/// over molecules, and easier molecule removal from the system.
#[derive(Clone)]
pub struct System {
    /// The system configuration
    configuration: Configuration,
    /// All the interactions in this system
    interactions: Interactions,
    /// Association particles names to particle kinds
    kinds: BTreeMap<String, ParticleKind>,
    /// The current simulation step
    step: u64,
    /// Externally managed temperature for the system
    external_temperature: Option<f64>,
}

impl System {
    /// Create a new empty `System`
    pub fn new() -> System {
        System::with_configuration(Configuration::new())
    }

    /// Create an empty system with a specific unit cell
    pub fn with_cell(cell: UnitCell) -> System {
        let mut configuration = Configuration::new();
        configuration.cell = cell;
        System::with_configuration(configuration)
    }

    /// Create a system with the specified `configuration`, and no interactions.
    fn with_configuration(configuration: Configuration) -> System {
        System {
            configuration: configuration,
            kinds: BTreeMap::new(),
            interactions: Interactions::new(),
            step: 0,
            external_temperature: None,
        }
    }

    fn get_kind(&mut self, name: &str) -> ParticleKind {
        if let Some(&kind) = self.kinds.get(name) {
            return kind;
        } else {
            let kind = ParticleKind(self.kinds.len() as u32);
            let _ = self.kinds.insert(String::from(name), kind);
            kind
        }
    }

    /// Insert a particle at the end of the internal list.
    pub fn add_particle(&mut self, mut particle: Particle) {
        if particle.kind == ParticleKind::invalid() {
            particle.kind = self.get_kind(particle.name());
        }
        self.configuration.add_particle(particle);
    }

    /// Get the number of particles of each kind in the configuration
    pub fn composition(&self) -> Composition {
        let mut composition = Composition::new();
        composition.resize(self.kinds.len());
        for particle in self.particles() {
            composition[particle.kind] += 1;
        }
        return composition;
    }

    /// Get a list of all the particles kinds in the system.
    pub fn particle_kinds(&self) -> Vec<ParticleKind> {
        self.kinds.values().cloned().collect()
    }

    /// Get the current step of the system
    pub fn step(&self) -> u64 {
        self.step
    }

    /// Increment the system step
    pub fn increment_step(&mut self) {
        self.step += 1;
    }

    /// Use an external temperature for all the system properties. Calling this
    /// with `Some(temperature)` will replace all the computation of the
    /// temperature from the velocities with the given values. Calling it with
    /// `None` will use the velocities.
    ///
    /// The default is to use the velocities unless this function is called.
    pub fn external_temperature(&mut self, temperature: Option<f64>) {
        if let Some(temperature) = temperature {
            assert!(temperature >= 0.0, "External temperature must be positive");
        }
        self.external_temperature = temperature;
    }



    /// Guess the bonds in the configuration using the chemfiles algorithm.
    ///
    /// This function removes any existing bond, and tries to guess them using
    /// a distance criteria. Because this function does a round trip to
    /// chemfiles, it might be costly when dealing with big systems.
    pub fn guess_bonds(&mut self) {
        use ::sys::chfl::{ToChemfiles, ToLumol};
        let mut frame = self.to_chemfiles().expect(
            "can not convert the configuration to a chemfiles frame"
        );
        frame.guess_topology().expect(
            "can not guess system topology in chemfiles"
        );
        *self = frame.to_lumol().expect(
            "can not convert the chemfiles frame to a configuration"
        );
    }
}

/// Functions related to interactions
impl System {
    /// Get an helper struct to evaluate the energy of this system.
    pub fn energy_evaluator(&self) -> EnergyEvaluator {<commit_msg>Move the guess_bonds function to the System<commit_after>// Lumol, an extensible molecular simulation engine
// Copyright (C) 2015-2016 Lumol's contributors — BSD license

use std::ops::{Deref, DerefMut};
use std::collections::BTreeMap;

use types::{Vector3D, Matrix3};

use energy::{PairInteraction, BondPotential, AnglePotential, DihedralPotential};
use energy::{GlobalPotential, CoulombicPotential};

use sys::{Configuration, Particle, ParticleKind, UnitCell};
use sys::{Composition, Interactions, EnergyEvaluator};

/// The `System` type hold all the data about a simulated system.
///
/// This data contains:
///
///   - an unit cell, containing the system;
///   - a list of particles in the system;
///   - a list of molecules in the system;
///   - a list of interactions, associating particles kinds and potentials
///
/// In the implementation, the particles contained in a molecule are guaranteed
/// to be contiguous in memory. This allow for faster access when iterating
/// over molecules, and easier molecule removal from the system.
#[derive(Clone)]
pub struct System {
    /// The system configuration
    configuration: Configuration,
    /// All the interactions in this system
    interactions: Interactions,
    /// Association particles names to particle kinds
    kinds: BTreeMap<String, ParticleKind>,
    /// The current simulation step
    step: u64,
    /// Externally managed temperature for the system
    external_temperature: Option<f64>,
}

impl System {
    /// Create a new empty `System`
    pub fn new() -> System {
        System::with_configuration(Configuration::new())
    }

    /// Create an empty system with a specific unit cell
    pub fn with_cell(cell: UnitCell) -> System {
        let mut configuration = Configuration::new();
        configuration.cell = cell;
        System::with_configuration(configuration)
    }

    /// Create a system with the specified `configuration`, and no interactions.
    fn with_configuration(configuration: Configuration) -> System {
        System {
            configuration: configuration,
            kinds: BTreeMap::new(),
            interactions: Interactions::new(),
            step: 0,
            external_temperature: None,
        }
    }

    fn get_kind(&mut self, name: &str) -> ParticleKind {
        if let Some(&kind) = self.kinds.get(name) {
            return kind;
        } else {
            let kind = ParticleKind(self.kinds.len() as u32);
            let _ = self.kinds.insert(String::from(name), kind);
            kind
        }
    }

    /// Insert a particle at the end of the internal list.
    pub fn add_particle(&mut self, mut particle: Particle) {
        if particle.kind == ParticleKind::invalid() {
            particle.kind = self.get_kind(particle.name());
        }
        self.configuration.add_particle(particle);
    }

    /// Get the number of particles of each kind in the configuration
    pub fn composition(&self) -> Composition {
        let mut composition = Composition::new();
        composition.resize(self.kinds.len());
        for particle in self.particles() {
            composition[particle.kind] += 1;
        }
        return composition;
    }

    /// Get a list of all the particles kinds in the system.
    pub fn particle_kinds(&self) -> Vec<ParticleKind> {
        self.kinds.values().cloned().collect()
    }

    /// Get the current step of the system
    pub fn step(&self) -> u64 {
        self.step
    }

    /// Increment the system step
    pub fn increment_step(&mut self) {
        self.step += 1;
    }

    /// Use an external temperature for all the system properties. Calling this
    /// with `Some(temperature)` will replace all the computation of the
    /// temperature from the velocities with the given values. Calling it with
    /// `None` will use the velocities.
    ///
    /// The default is to use the velocities unless this function is called.
    pub fn external_temperature(&mut self, temperature: Option<f64>) {
        if let Some(temperature) = temperature {
            assert!(temperature >= 0.0, "External temperature must be positive");
        }
        self.external_temperature = temperature;
    }



    /// Guess the bonds in the configuration using the chemfiles algorithm.
    ///
    /// This function remove any existing bond, and try to guess them using a
    /// distance criteria. Because this function does a round trip to
    /// chemfiles, it might be costly when dealing with big systems.
    pub fn guess_bonds(&mut self) {
        use ::sys::chfl::{ToChemfiles, ToLumol};
        let mut frame = self.to_chemfiles().expect(
            "can not convert the configuration to a chemfiles frame"
        );
        frame.guess_topology().expect(
            "can not guess system topology in chemfiles"
        );
        *self = frame.to_lumol().expect(
            "can not convert the chemfiles frame to a configuration"
        );
    }
}

/// Functions related to interactions
impl System {
    /// Get an helper struct to evaluate the energy of this system.
    pub fn energy_evaluator(&self) -> EnergyEvaluator {
{'fraction_non_alphanumeric': 0.10184732675202815, 'fraction_numerical': 0.00488710780959828, 'mean_word_length': 2.5466204506065857, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '487472', 'n_tokens_mistral': 2725, 'n_tokens_neox': 2619, 'n_words': 994}