def mass(self, mass): mass = np.asarray(mass) if mass.ndim != 1: raise pv_error.InputError('mass', 'Expected 1-dimensional array.') if self.natoms is None: self.natoms = mass.size elif mass.size != self.natoms: raise pv_error.InputError( 'mass', 'Mass vector does not have length == natoms.') self.__mass = mass
def nconstraints_per_molecule(self, nconstraints_per_molecule): nconstraints_per_molecule = np.array(nconstraints_per_molecule) if nconstraints_per_molecule.ndim != 1: raise pv_error.InputError('nconstraints_per_molecule', 'Expected 1-dimensional array.') if self.molecule_idx is not None: if nconstraints_per_molecule.shape != self.molecule_idx.shape: raise pv_error.InputError( 'nconstraints_per_molecule', 'Expected `nconstraints_per_molecule` to have' 'the same shape as `moldecule_idx`.') self.__nconstraints_per_molecule = nconstraints_per_molecule
def __init__(self, ensemble, natoms=None, mu=None, volume=None, pressure=None, energy=None, temperature=None): self.__ensemble = None self.__n = None self.__mu = None self.__v = None self.__p = None self.__e = None self.__t = None if ensemble not in self.ensembles(): raise pv_error.InputError('ensemble', 'Given ensemble unknown.') self.__ensemble = ensemble if ensemble == 'NVE': if natoms is None: warnings.warn(ensemble + ' with undefined natoms.') if volume is None: warnings.warn(ensemble + ' with undefined volume.') # if energy is None: # warnings.warn(ensemble + ' with undefined energy.') self.__n = natoms self.__v = volume self.__e = energy if ensemble == 'NVT': if natoms is None: warnings.warn(ensemble + ' with undefined natoms.') if volume is None: warnings.warn(ensemble + ' with undefined volume.') if temperature is None: warnings.warn(ensemble + ' with undefined temperature.') self.__n = natoms self.__v = volume self.__t = temperature if ensemble == 'NPT': if natoms is None: warnings.warn(ensemble + ' with undefined natoms.') if pressure is None: warnings.warn(ensemble + ' with undefined pressure.') if temperature is None: warnings.warn(ensemble + ' with undefined temperature.') self.__n = natoms self.__p = pressure self.__t = temperature if ensemble == 'muVT': if mu is None: warnings.warn(ensemble + ' with undefined mu.') if volume is None: warnings.warn(ensemble + ' with undefined volume.') if temperature is None: warnings.warn(ensemble + ' with undefined temperature.') self.__mu = mu self.__v = volume self.__t = temperature
def compatible(data_1, data_2): r"""Checks whether two simulations are compatible for common validation. Parameters ---------- data_1 : SimulationData data_2 : SimulationData Returns ------- result : bool """ if not isinstance(data_1, SimulationData): raise pv_error.InputError('data_1', 'Expected type SimulationData') if not isinstance(data_2, SimulationData): raise pv_error.InputError('data_2', 'Expected type SimulationData') return data_1.units == data_2.units
def molecule_idx(self, molecule_idx): molecule_idx = np.asarray(molecule_idx) if molecule_idx.ndim != 1: raise pv_error.InputError('molecule_idx', 'Expected 1-dimensional array.') if (self.nconstraints_per_molecule is not None and self.nconstraints_per_molecule.shape != molecule_idx.shape): warnings.warn( 'New `molecule_idx` does not have the same' 'shape as previously set `nconstraints_per_molecule`.' 'Setting `nconstraints_per_molecule = None` to avoid' 'errors.') self.__nconstraints_per_molecule = None self.__molecule_idx = molecule_idx
def position(self, pos): """Set position""" pos = np.array(pos) if pos.ndim == 2: # create 3-dimensional array pos = np.array([pos]) if pos.ndim != 3: warnings.warn('Expected 2- or 3-dimensional array.') if self.__nframes == 0 and self.__velocity is None: self.__nframes = pos.shape[0] elif self.__nframes != pos.shape[0]: raise pv_error.InputError( ['pos'], 'Expected equal number of frames as in velocity trajectory.') self.__position = pos
def velocity(self, vel): """Set velocity""" vel = np.array(vel) if vel.ndim == 2: # create 3-dimensional array vel = np.array([vel]) if vel.ndim != 3: warnings.warn('Expected 2- or 3-dimensional array.') if self.__nframes == 0 and self.__position is None: self.__nframes = vel.shape[0] elif self.__nframes != vel.shape[0]: raise pv_error.InputError( ['vel'], 'Expected equal number of frames as in position trajectory.') self.__velocity = vel
def constant_of_motion(self, constant_of_motion): """Set constant_of_motion""" if constant_of_motion is None: self.__constant_of_motion = None return constant_of_motion = np.array(constant_of_motion) if constant_of_motion.ndim != 1: raise pv_error.InputError("constant_of_motion", "Expected 1-dimensional array.") if self.nframes == -1: self.__nframes = constant_of_motion.size elif self.nframes != constant_of_motion.size: warnings.warn( "Mismatch in number of frames. Setting `nframes = None`.") self.__nframes = None self.__constant_of_motion = constant_of_motion
def temperature(self, temperature): """Set temperature""" if temperature is None: self.__temperature = None return temperature = np.array(temperature) if temperature.ndim != 1: raise pv_error.InputError("temperature", "Expected 1-dimensional array.") if self.nframes == -1: self.__nframes = temperature.size elif self.nframes != temperature.size: warnings.warn( "Mismatch in number of frames. Setting `nframes = None`.") self.__nframes = None self.__temperature = temperature
def pressure(self, pressure): """Set pressure""" if pressure is None: self.__pressure = None return pressure = np.array(pressure) if pressure.ndim != 1: raise pv_error.InputError("pressure", "Expected 1-dimensional array.") if self.nframes == -1: self.__nframes = pressure.size elif self.nframes != pressure.size: warnings.warn( "Mismatch in number of frames. Setting `nframes = None`.") self.__nframes = None self.__pressure = pressure
def volume(self, volume): """Set volume""" if volume is None: self.__volume = None return volume = np.array(volume) if volume.ndim != 1: raise pv_error.InputError("volume", "Expected 1-dimensional array.") if self.nframes == -1: self.__nframes = volume.size elif self.nframes != volume.size: warnings.warn( "Mismatch in number of frames. Setting `nframes = None`.") self.__nframes = None self.__volume = volume
def total_energy(self, total_energy): """Set total_energy""" if total_energy is None: self.__total_energy = None return total_energy = np.array(total_energy) if total_energy.ndim != 1: raise pv_error.InputError("total_energy", "Expected 1-dimensional array.") if self.nframes == -1: self.__nframes = total_energy.size elif self.nframes != total_energy.size: warnings.warn( "Mismatch in number of frames. Setting `nframes = None`.") self.__nframes = None self.__total_energy = total_energy
def kinetic_energy(self, kinetic_energy): """Set kinetic_energy""" if kinetic_energy is None: self.__kinetic_energy = None return kinetic_energy = np.array(kinetic_energy) if kinetic_energy.ndim != 1: raise pv_error.InputError("kinetic_energy", "Expected 1-dimensional array.") if self.nframes == -1: self.__nframes = kinetic_energy.size elif self.nframes != kinetic_energy.size: warnings.warn( "Mismatch in number of frames. Setting `nframes = None`.") self.__nframes = None self.__kinetic_energy = kinetic_energy
def potential_energy(self, potential_energy): """Set potential_energy""" if potential_energy is None: self.__potential_energy = None return potential_energy = np.array(potential_energy) if potential_energy.ndim != 1: raise pv_error.InputError('potential_energy', 'Expected 1-dimensional array.') if self.nframes == -1: self.__nframes = potential_energy.size elif self.nframes != potential_energy.size: warnings.warn('Mismatch in number of frames. ' 'Setting `nframes = None`.') self.__nframes = None self.__potential_energy = potential_energy
def get_simulation_data(self, mdp=None, top=None, edr=None, trr=None, gro=None): r""" Parameters ---------- mdp: str, optional A string pointing to a .mdp file top: str, optional A string pointing to a .top file edr: str, optional A string pointing to a .edr file trr: str, optional A string pointing to a .trr file gro: str, optional A string pointing to a .gro file (Note: if also trr is given, gro is ignored) Returns ------- result: SimulationData A SimulationData filled with the provided ensemble and topology objects as well as the trajectory data found in the edr and trr / gro files. """ result = simulation_data.SimulationData() result.units = self.units() # trajectories (might be used later for the box...) trajectory_dict = None if trr is not None: if gro is not None: warnings.warn('`trr` and `gro` given. Ignoring `gro`.') trajectory_dict = self.__interface.read_trr(trr) result.trajectory = simulation_data.TrajectoryData( trajectory_dict['position'], trajectory_dict['velocity']) elif gro is not None: trajectory_dict = self.__interface.read_gro(gro) result.trajectory = simulation_data.TrajectoryData( trajectory_dict['position'], trajectory_dict['velocity']) # simulation parameters & topology if mdp is not None and top is not None: mdp_options = self.__interface.read_mdp(mdp) define = None include = None if 'define' in mdp_options: define = mdp_options['define'] if 'include' in mdp_options: include = mdp_options['include'] molecules = self.__interface.read_system_from_top(top, define=define, include=include) if 'dt' in mdp_options: result.dt = float(mdp_options['dt']) natoms = 0 mass = [] constraints_per_molec = [] angles = ('constraints' in mdp_options and mdp_options['constraints'] == 'all-angles') angles_h = (angles or 'constraints' in mdp_options and mdp_options['constraints'] == 'h-angles') bonds = (angles_h or 'constraints' in mdp_options and mdp_options['constraints'] == 'all-bonds') bonds_h = (bonds or 'constraints' in mdp_options and mdp_options['constraints'] == 'h-bonds') molecule_idx = [] next_molec = 0 molec_bonds = [] molec_bonds_constrained = [] for molecule in molecules: natoms += molecule['nmolecs'] * molecule['natoms'] for n in range(0, molecule['nmolecs']): molecule_idx.append(next_molec) next_molec += molecule['natoms'] mass.extend(molecule['mass'] * molecule['nmolecs']) constraints = 0 constrained_bonds = [] all_bonds = molecule['bonds'] + molecule['bondsh'] if molecule['settles']: constraints = 3 constrained_bonds = all_bonds else: if bonds: constraints += molecule['nbonds'][0] constrained_bonds.extend(molecule['bonds']) if bonds_h: constraints += molecule['nbonds'][1] constrained_bonds.extend(molecule['bondsh']) if angles: constraints += molecule['nangles'][0] if angles_h: constraints += molecule['nangles'][1] constraints_per_molec.extend([constraints] * molecule['nmolecs']) molec_bonds.extend([all_bonds] * molecule['nmolecs']) molec_bonds_constrained.extend([constrained_bonds] * molecule['nmolecs']) topology = simulation_data.TopologyData() topology.natoms = natoms topology.mass = mass topology.molecule_idx = molecule_idx topology.nconstraints = np.sum(constraints_per_molec) topology.nconstraints_per_molecule = constraints_per_molec topology.ndof_reduction_tra = 3 topology.ndof_reduction_rot = 0 if 'comm-mode' in mdp_options: if mdp_options['comm-mode'] == 'Linear': topology.ndof_reduction_tra = 3 elif mdp_options['comm-mode'] == 'Angular': topology.ndof_reduction_tra = 3 topology.ndof_reduction_rot = 3 if mdp_options['comm-mode'] == 'None': topology.ndof_reduction_tra = 0 topology.bonds = molec_bonds topology.constrained_bonds = molec_bonds_constrained result.topology = topology thermostat = ('tcoupl' in mdp_options and mdp_options['tcoupl'] and mdp_options['tcoupl'] != 'no' and mdp_options['tcoupl'] != 'No') stochastic_dyn = ('integrator' in mdp_options and mdp_options['integrator'] in ['sd', 'sd2', 'bd']) constant_temp = thermostat or stochastic_dyn temperature = None if constant_temp: ref_t_key = 'ref-t' if ref_t_key not in mdp_options and 'ref_t' in mdp_options: ref_t_key = 'ref_t' ref_t = [float(t) for t in mdp_options[ref_t_key].split()] if len(ref_t) == 1 or np.allclose(ref_t, [ref_t[0]] * len(ref_t)): temperature = ref_t[0] else: raise pv_error.InputError( 'mdp', 'Ensemble definition ambiguous.') constant_press = ('pcoupl' in mdp_options and mdp_options['pcoupl'] and mdp_options['pcoupl'] != 'no' and mdp_options['pcoupl'] != 'No') volume = None pressure = None if constant_press: ref_p_key = 'ref-p' if ref_p_key not in mdp_options and 'ref_p' in mdp_options: ref_p_key = 'ref_p' pressure = float(mdp_options[ref_p_key]) else: if trajectory_dict is not None: box = trajectory_dict['box'][0] # Different box shapes? volume = box[0] * box[1] * box[2] else: warnings.warn( 'Constant volume simulation with undefined volume.') if constant_temp and constant_press: ens = 'NPT' elif constant_temp: ens = 'NVT' else: ens = 'NVE' if ens == 'NVE': self.__gmx_energy_names['constant_of_motion'] = 'Total-Energy' else: self.__gmx_energy_names['constant_of_motion'] = 'Conserved-En.' result.ensemble = simulation_data.EnsembleData( ens, natoms=natoms, volume=volume, pressure=pressure, temperature=temperature) if edr is not None: observable_dict = self.__interface.get_quantities( edr, self.__gmx_energy_names.values(), args=['-dp']) # constant volume simulations don't write out the volume in .edr file if (observable_dict['Volume'] is None and result.ensemble is not None and result.ensemble.volume is not None): nframes = observable_dict['Pressure'].size observable_dict['Volume'] = np.ones( nframes) * result.ensemble.volume result.observables = simulation_data.ObservableData() for key, gmxkey in self.__gmx_energy_names.items(): result.observables[key] = observable_dict[gmxkey] return result
def check(data_sim_one, data_sim_two, total_energy=False, screen=False, filename=None, quiet=False): r""" Check the ensemble. The correct check is inferred from the simulation data given. Parameters ---------- data_sim_one : SimulationData data_sim_two : SimulationData total_energy : bool screen : bool Plot distributions on screen. Default: False. filename : string Plot distributions to `filename`.pdf. Default: None. quiet : bool Turns off nearly all messages. Default: False. Returns ------- """ if not simulation_data.SimulationData.compatible(data_sim_one, data_sim_two): raise pv_error.InputError(['data_sim_one', 'data_sim_two'], 'Simulation data not compatible.') if data_sim_one.ensemble.ensemble != data_sim_two.ensemble.ensemble: raise pv_error.InputError( ['data_sim_one', 'data_sim_two'], 'The two simulations were sampling different ensembles. ' 'The simulations are expected to differ in state point ' '(e.g. target temperature, target pressure), but not ' 'in their sampled ensemble (e.g. NVT, NPT).') ensemble = data_sim_one.ensemble.ensemble if ensemble == 'NVE' or ensemble == 'muVE': raise pv_error.InputError(['data_sim_one', 'data_sim_two'], 'Test of ensemble ' + ensemble + ' is not implemented ' '(yet).') n1 = data_sim_one.observables.nframes n2 = data_sim_two.observables.nframes if total_energy: e1 = data_sim_one.observables.total_energy e2 = data_sim_two.observables.total_energy else: e1 = data_sim_one.observables.potential_energy e2 = data_sim_two.observables.potential_energy # padding the array - checkensemble requires same length if n1 < n2: e1 = np.append(e1, np.zeros(n2 - n1)) if n2 < n1: e2 = np.append(e2, np.zeros(n1 - n2)) number_of_samples = np.array([n1, n2]) energy = np.array([e1, e2]) do_linear_fit = True do_non_linear_fit = False do_max_likelhood = True do_maxwell = False quantiles = None if ensemble == 'NVT': temperatures = np.array([ data_sim_one.ensemble.temperature, data_sim_two.ensemble.temperature ]) analysis_type = 'dbeta-constV' ge = [] for e in energy: ge.append(timeseries.statisticalInefficiency(e, fast=False)) quantiles = checkensemble.ProbabilityAnalysis( number_of_samples, type=analysis_type, T_k=temperatures, P_k=None, mu_k=None, U_kn=energy, V_kn=None, N_kn=None, nbins=40, reptype=None, g=ge, bMaxwell=do_maxwell, bLinearFit=do_linear_fit, bNonLinearFit=do_non_linear_fit, bMaxLikelihood=do_max_likelhood, kB=data_sim_one.units.kb, units=data_sim_one.units, filename=filename, screen=screen, quiet=quiet) elif ensemble == 'NPT': temperatures = np.array([ data_sim_one.ensemble.temperature, data_sim_two.ensemble.temperature ]) pressures = np.array( [data_sim_one.ensemble.pressure, data_sim_two.ensemble.pressure]) equal_temps = temperatures[0] == temperatures[1] equal_press = pressures[0] == pressures[1] v1 = data_sim_one.observables.volume v2 = data_sim_two.observables.volume # padding the array - checkensemble requires same length if n1 < n2: v1 = np.append(v1, np.zeros(n2 - n1)) if n2 < n1: v2 = np.append(v2, np.zeros(n1 - n2)) volume = np.array([v1, v2]) if equal_press and not equal_temps: analysis_type = 'dbeta-constP' elif equal_temps and not equal_press: analysis_type = 'dpressure-constB' else: analysis_type = 'dbeta-dpressure' do_linear_fit = False do_non_linear_fit = False ge = [] for e in energy: ge.append(timeseries.statisticalInefficiency(e, fast=False)) gv = [] for v in volume: gv.append(timeseries.statisticalInefficiency(v, fast=False)) g = np.maximum(ge, gv) quantiles = checkensemble.ProbabilityAnalysis( number_of_samples, type=analysis_type, T_k=temperatures, P_k=pressures, mu_k=None, U_kn=energy, V_kn=volume, N_kn=None, kB=data_sim_one.units.kb, nbins=40, bMaxLikelihood=do_max_likelhood, bLinearFit=do_linear_fit, bNonLinearFit=do_non_linear_fit, reptype=None, g=g, bMaxwell=do_maxwell, units=data_sim_one.units, screen=screen, filename=filename, quiet=quiet) return quantiles