def setup_coulomb_potential(self): """Setups a Coulomb potential between the subsystems. Ewald calculation is automatically used for pbc-systems. Non-pbc systems use the ProductPotential to reproduce the Coulomb potential. """ parameters = self.info.electrostatic_parameters # Check that that should Ewald summation be used and if so, that all the # needed parameters are given if self.has_pbc: needed = ["k_cutoff", "real_cutoff", "sigma"] for param in needed: if param not in parameters: error( param + " not specified in Interaction.enable_coulomb_potential(). It is needed in order to calculate electrostatic interaction energy with Ewald summation in systems with periodic boundary conditions." ) return ewald = CoulombSummation() ewald.set_parameter_value("epsilon", parameters["epsilon"]) ewald.set_parameter_value("k_cutoff", parameters["k_cutoff"]) ewald.set_parameter_value("real_cutoff", parameters["real_cutoff"]) ewald.set_parameter_value("sigma", parameters["sigma"]) self.pbc_calculator.set_coulomb_summation(ewald) else: # Add coulomb force between all charged particles in secondary # system, and all atoms in primary system. It is assumed that the # combined system will be made so that the primary system comes # before the secondary in indexing. coulomb_pairs = [] for i, ai in enumerate(self.primary_subsystem.atoms_for_interaction): for j, aj in enumerate(self.secondary_subsystem.atoms_for_interaction): if not np.allclose(aj.charge, 0): coulomb_pairs.append([i, j + self.n_primary]) # There are no charges in the secondary system, and that can't # change unlike the charges in primary system if len(coulomb_pairs) is 0: warn( "There cannot be electrostatic interaction between the " "subsystems, because the secondary system does not have " "any initial charges", 2, ) return # The first potential given to the productpotential defines the # targets and cutoff kc = 1.0 / (4.0 * np.pi * parameters["epsilon"]) max_cutoff = np.linalg.norm(np.array(self.primary_subsystem.atoms_for_interaction.get_cell())) coul1 = Potential("power", indices=coulomb_pairs, parameters=[1, 1, 1], cutoff=max_cutoff) coul2 = Potential("charge_pair", parameters=[kc, 1, 1]) coulomb_potential = ProductPotential([coul1, coul2]) self.calculator.add_potential(coulomb_potential) self.has_coulomb_interaction = True
def setup_hydrogen_links(self, links): """Setup the hydrogen link atoms to the primary system. Parameters: link_parameters: list of tuples Contains the link atom parameters from the Interaction-object. Each tuple in the list is a link atom specification for a covalent bond of different type. The first item in the tuple is a list of tuples containing atom index pairs. The second item in the tuple is the CHL parameter for these links. """ self.link_atoms = Atoms(pbc=copy(self.full_system.get_pbc()), cell=copy(self.full_system.get_cell())) for bond in links: pairs = bond[0] CHL = bond[1] for link in pairs: # Extract the position of the boundary atoms q1_index = link[0] m1_index = link[1] iq1 = self.primary_subsystem.index_map.get(q1_index) im1 = self.secondary_subsystem.index_map.get(m1_index) if iq1 is None: error(("Invalid link: "+str(q1_index)+"-"+str(m1_index)+":\n" "The first index does not point to an atom in the primary system.")) if im1 is None: error(("Invalid link: "+str(q1_index)+"-"+str(m1_index)+":\n" "The second index does not point to an atom in the secondary system.")) q1 = self.primary_subsystem.atoms_for_subsystem[iq1] rq1 = q1.position # Calculate the separation between the host atoms from the full # system. We need to do this in the full system because the # subsystems may not have the same coordinate systems due to cell # size minimization. frq1 = self.full_system[q1_index].position frm1 = self.full_system[m1_index].position distance = CHL*(frm1 - frq1) # Calculate position for the hydrogen atom in both the primary # subsystem and in the system containing only link atoms. The link # atom system is used when calculating link atom corrections. r_primary = rq1 + distance r_link = frq1 + distance # Create a hydrogen atom in the primary subsystem and in the # full subsystem hydrogen_primary = Atom('H', position=r_primary) hydrogen_link = Atom('H', position=r_link) self.primary_subsystem.atoms_for_subsystem.append(hydrogen_primary) self.link_atoms.append(hydrogen_link) # Update the cell size after adding link atoms if self.primary_subsystem.cell_size_optimization_enabled: self.primary_subsystem.optimize_cell()
def setup_coulomb_potential(self): """Setups a Coulomb potential between the subsystems. Ewald calculation is automatically used for pbc-systems. Non-pbc systems use the ProductPotential to reproduce the Coulomb potential. """ parameters = self.info.electrostatic_parameters # Check that that should Ewald summation be used and if so, that all the # needed parameters are given if self.has_pbc: needed = ["k_cutoff", "real_cutoff", "sigma"] for param in needed: if param not in parameters: error(param + " not specified in Interaction.enable_coulomb_potential(). It is needed in order to calculate electrostatic interaction energy with Ewald summation in systems with periodic boundary conditions.") return ewald = CoulombSummation() ewald.set_parameter_value('epsilon', parameters['epsilon']) ewald.set_parameter_value('k_cutoff', parameters['k_cutoff']) ewald.set_parameter_value('real_cutoff', parameters['real_cutoff']) ewald.set_parameter_value('sigma', parameters['sigma']) self.pbc_calculator.set_coulomb_summation(ewald) else: # Add coulomb force between all charged particles in secondary # system, and all atoms in primary system. It is assumed that the # combined system will be made so that the primary system comes # before the secondary in indexing. coulomb_pairs = [] for i, ai in enumerate(self.primary_subsystem.atoms_for_interaction): for j, aj in enumerate(self.secondary_subsystem.atoms_for_interaction): if not np.allclose(aj.charge, 0): coulomb_pairs.append([i, j+self.n_primary]) # There are no charges in the secondary system, and that can't # change unlike the charges in primary system if len(coulomb_pairs) is 0: warn("There cannot be electrostatic interaction between the " "subsystems, because the secondary system does not have " "any initial charges", 2) return # The first potential given to the productpotential defines the # targets and cutoff kc = 1.0/(4.0*np.pi*parameters['epsilon']) max_cutoff = np.linalg.norm(np.array(self.primary_subsystem.atoms_for_interaction.get_cell())) coul1 = Potential('power', indices=coulomb_pairs, parameters=[1, 1, 1], cutoff=max_cutoff) coul2 = Potential('charge_pair', parameters=[kc, 1, 1]) coulomb_potential = ProductPotential([coul1, coul2]) self.calculator.add_potential(coulomb_potential) self.has_coulomb_interaction = True
def setup_hydrogen_links(self, links): """Setup the hydrogen link atoms to the primary system. Parameters: link_parameters: list of tuples Contains the link atom parameters from the Interaction-object. Each tuple in the list is a link atom specification for a covalent bond of different type. The first item in the tuple is a list of tuples containing atom index pairs. The second item in the tuple is the CHL parameter for these links. """ self.link_atoms = Atoms(pbc=copy(self.full_system.get_pbc()), cell=copy(self.full_system.get_cell())) for bond in links: pairs = bond[0] CHL = bond[1] for link in pairs: # Extract the position of the boundary atoms q1_index = link[0] m1_index = link[1] iq1 = self.primary_subsystem.index_map.get(q1_index) im1 = self.secondary_subsystem.index_map.get(m1_index) if iq1 is None: error( ( "Invalid link: " + str(q1_index) + "-" + str(m1_index) + ":\n" "The first index does not point to an atom in the primary system." ) ) if im1 is None: error( ( "Invalid link: " + str(q1_index) + "-" + str(m1_index) + ":\n" "The second index does not point to an atom in the secondary system." ) ) q1 = self.primary_subsystem.atoms_for_subsystem[iq1] rq1 = q1.position # Calculate the separation between the host atoms from the full # system. We need to do this in the full system because the # subsystems may not have the same coordinate systems due to cell # size minimization. frq1 = self.full_system[q1_index].position frm1 = self.full_system[m1_index].position distance = CHL * (frm1 - frq1) # Calculate position for the hydrogen atom in both the primary # subsystem and in the system containing only link atoms. The link # atom system is used when calculating link atom corrections. r_primary = rq1 + distance r_link = frq1 + distance # Create a hydrogen atom in the primary subsystem and in the # full subsystem hydrogen_primary = Atom("H", position=r_primary) hydrogen_link = Atom("H", position=r_link) self.primary_subsystem.atoms_for_subsystem.append(hydrogen_primary) self.link_atoms.append(hydrogen_link) # Update the cell size after adding link atoms if self.primary_subsystem.cell_size_optimization_enabled: self.primary_subsystem.optimize_cell()