def EISF(self, q_range=(0., 15.), subset=None, weights=None, random_vectors=15, first_mode=6): if subset is None: subset = self.universe if weights is None: weights = self.universe.getParticleScalar('b_incoherent') weights = weights * weights weights = weights * subset.booleanMask() total = weights.sumOverParticles() weights = weights / total first, last, step = (q_range + (None, ))[:3] if step is None: step = (last - first) / 50. q = N.arange(first, last, step) f = ParticleProperties.ParticleTensor(self.universe) for i in range(first_mode, self.nmodes): mode = self.rawMode(i) f = f + (1. / mode.inv_relaxation_time) * mode.dyadicProduct(mode) f = Units.k_B * self.temperature * f / self.friction eisf = N.zeros(q.shape, N.Float) random_vectors = Random.randomDirections(random_vectors) for v in random_vectors: for a in subset.atomList(): exp = N.exp(-v * (f[a] * v)) N.add(eisf, weights[a] * exp**(q * q), eisf) return InterpolatingFunction((q, ), eisf / len(random_vectors))
def EISF(self, q_range = (0., 15.), subset=None, weights = None, random_vectors = 15, first_mode = 6): if subset is None: subset = self.universe if weights is None: weights = self.universe.getParticleScalar('b_incoherent') weights = weights*weights weights = weights*subset.booleanMask() total = weights.sumOverParticles() weights = weights/total first, last, step = (q_range+(None,))[:3] if step is None: step = (last-first)/50. q = N.arange(first, last, step) f = ParticleProperties.ParticleTensor(self.universe) for i in range(first_mode, self.nmodes): mode = self.rawMode(i) f = f + (1./mode.inv_relaxation_time)*mode.dyadicProduct(mode) f = Units.k_B*self.temperature*f/self.friction eisf = N.zeros(q.shape, N.Float) random_vectors = Random.randomDirections(random_vectors) for v in random_vectors: for a in subset.atomList(): exp = N.exp(-v*(f[a]*v)) N.add(eisf, weights[a]*exp**(q*q), eisf) return InterpolatingFunction((q,), eisf/len(random_vectors))
def staticStructureFactor(self, q_range=(1., 15.), subset=None, weights=None, random_vectors=15, first_mode=6): """ :param q_range: the range of angular wavenumber values :type q_range: tuple :param subset: the subset of the universe used in the calculation (default: the whole universe) :type subset: :class:~MMTK.Collections.GroupOfAtoms :param weights: the weight to be given to each atom in the average (default: coherent scattering lengths) :type weights: :class:~MMTK.ParticleProperties.ParticleScalar :param random_vectors: the number of random direction vectors used in the orientational average :type random_vectors: int :param first_mode: the first mode to be taken into account for the fluctuation calculation. The default value of 6 is right for molecules in vacuum. :type first_mode: int :returns: the Static Structure Factor as a function of angular wavenumber :rtype: Scientific.Functions.Interpolation.InterpolatingFunction """ if subset is None: subset = self.universe if weights is None: weights = self.universe.getParticleScalar('b_coherent') mask = subset.booleanMask() weights = N.repeat(weights.array, mask.array) weights = weights / N.sqrt(N.add.reduce(weights * weights)) friction = N.repeat(self.friction.array, mask.array) r = N.repeat(self.universe.configuration().array, mask.array) first, last, step = (q_range + (None, ))[:3] if step is None: step = (last - first) / 50. q = N.arange(first, last, step) kT = Units.k_B * self.temperature natoms = subset.numberOfAtoms() sq = 0. random_vectors = Random.randomDirections(random_vectors) for v in random_vectors: sab = N.zeros((natoms, natoms), N.Float) for i in range(first_mode, self.nmodes): irt = self.rawMode(i).inv_relaxation_time d = N.repeat((self.rawMode(i)*v).array, mask.array) \ / N.sqrt(friction) sab = sab + (d[N.NewAxis, :] - d[:, N.NewAxis])**2 / irt sab = sab[N.NewAxis, :, :] * q[:, N.NewAxis, N.NewAxis]**2 phase = N.exp(-1.j*q[:, N.NewAxis] * N.dot(r, v.array)[N.NewAxis, :]) \ * weights[N.NewAxis, :] temp = N.sum(phase[:, :, N.NewAxis] * N.exp(-0.5 * kT * sab), 1) temp = N.sum(N.conjugate(phase) * temp, 1) sq = sq + temp.real return InterpolatingFunction((q, ), sq / len(random_vectors))
def staticStructureFactor(self, q_range = (1., 15.), subset=None, weights=None, random_vectors=15, first_mode = 6): """ :param q_range: the range of angular wavenumber values :type q_range: tuple :param subset: the subset of the universe used in the calculation (default: the whole universe) :type subset: :class:`~MMTK.Collections.GroupOfAtoms` :param weights: the weight to be given to each atom in the average (default: coherent scattering lengths) :type weights: :class:`~MMTK.ParticleProperties.ParticleScalar` :param random_vectors: the number of random direction vectors used in the orientational average :type random_vectors: int :param first_mode: the first mode to be taken into account for the fluctuation calculation. The default value of 6 is right for molecules in vacuum. :type first_mode: int :returns: the Static Structure Factor as a function of angular wavenumber :rtype: Scientific.Functions.Interpolation.InterpolatingFunction """ if subset is None: subset = self.universe if weights is None: weights = self.universe.getParticleScalar('b_coherent') mask = subset.booleanMask() weights = N.repeat(weights.array, mask.array) weights = weights/N.sqrt(N.add.reduce(weights*weights)) friction = N.repeat(self.friction.array, mask.array) r = N.repeat(self.universe.configuration().array, mask.array) first, last, step = (q_range+(None,))[:3] if step is None: step = (last-first)/50. q = N.arange(first, last, step) kT = Units.k_B*self.temperature natoms = subset.numberOfAtoms() sq = 0. random_vectors = Random.randomDirections(random_vectors) for v in random_vectors: sab = N.zeros((natoms, natoms), N.Float) for i in range(first_mode, self.nmodes): irt = self.rawMode(i).inv_relaxation_time d = N.repeat((self.rawMode(i)*v).array, mask.array) \ / N.sqrt(friction) sab = sab + (d[N.NewAxis,:]-d[:,N.NewAxis])**2/irt sab = sab[N.NewAxis,:,:]*q[:, N.NewAxis, N.NewAxis]**2 phase = N.exp(-1.j*q[:, N.NewAxis] * N.dot(r, v.array)[N.NewAxis, :]) \ * weights[N.NewAxis, :] temp = N.sum(phase[:, :, N.NewAxis]*N.exp(-0.5*kT*sab), 1) temp = N.sum(N.conjugate(phase)*temp, 1) sq = sq + temp.real return InterpolatingFunction((q,), sq/len(random_vectors))
def EISF(self, q_range=(0., 15.), subset=None, weights=None, random_vectors=15, first_mode=6): """ :param q_range: the range of angular wavenumber values :type q_range: tuple :param subset: the subset of the universe used in the calculation (default: the whole universe) :type subset: :class:~MMTK.Collections.GroupOfAtoms :param weights: the weight to be given to each atom in the average (default: incoherent scattering lengths) :type weights: :class:~MMTK.ParticleProperties.ParticleScalar :param random_vectors: the number of random direction vectors used in the orientational average :type random_vectors: int :param first_mode: the first mode to be taken into account for the fluctuation calculation. The default value of 6 is right for molecules in vacuum. :type first_mode: int :returns: the Elastic Incoherent Structure Factor (EISF) as a function of angular wavenumber :rtype: Scientific.Functions.Interpolation.InterpolatingFunction """ if subset is None: subset = self.universe if weights is None: weights = self.universe.getParticleScalar('b_incoherent') weights = weights * weights weights = weights * subset.booleanMask() total = weights.sumOverParticles() weights = weights / total first, last, step = (q_range + (None, ))[:3] if step is None: step = (last - first) / 50. q = N.arange(first, last, step) f = ParticleProperties.ParticleTensor(self.universe) for i in range(first_mode, self.nmodes): mode = self.rawMode(i) f = f + (1. / mode.inv_relaxation_time) * mode.dyadicProduct(mode) f = Units.k_B * self.temperature * f / self.friction eisf = N.zeros(q.shape, N.Float) random_vectors = Random.randomDirections(random_vectors) for v in random_vectors: for a in subset.atomList(): exp = N.exp(-v * (f[a] * v)) N.add(eisf, weights[a] * exp**(q * q), eisf) return InterpolatingFunction((q, ), eisf / len(random_vectors))
def EISF(self, q_range = (0., 15.), subset=None, weights = None, random_vectors = 15, first_mode = 6): """ :param q_range: the range of angular wavenumber values :type q_range: tuple :param subset: the subset of the universe used in the calculation (default: the whole universe) :type subset: :class:`~MMTK.Collections.GroupOfAtoms` :param weights: the weight to be given to each atom in the average (default: incoherent scattering lengths) :type weights: :class:`~MMTK.ParticleProperties.ParticleScalar` :param random_vectors: the number of random direction vectors used in the orientational average :type random_vectors: int :param first_mode: the first mode to be taken into account for the fluctuation calculation. The default value of 6 is right for molecules in vacuum. :type first_mode: int :returns: the Elastic Incoherent Structure Factor (EISF) as a function of angular wavenumber :rtype: Scientific.Functions.Interpolation.InterpolatingFunction """ if subset is None: subset = self.universe if weights is None: weights = self.universe.getParticleScalar('b_incoherent') weights = weights*weights weights = weights*subset.booleanMask() total = weights.sumOverParticles() weights = weights/total first, last, step = (q_range+(None,))[:3] if step is None: step = (last-first)/50. q = N.arange(first, last, step) f = ParticleProperties.ParticleTensor(self.universe) for i in range(first_mode, self.nmodes): mode = self.rawMode(i) f = f + (1./mode.inv_relaxation_time)*mode.dyadicProduct(mode) f = Units.k_B*self.temperature*f/self.friction eisf = N.zeros(q.shape, N.Float) random_vectors = Random.randomDirections(random_vectors) for v in random_vectors: for a in subset.atomList(): exp = N.exp(-v*(f[a]*v)) N.add(eisf, weights[a]*exp**(q*q), eisf) return InterpolatingFunction((q,), eisf/len(random_vectors))
def coherentScatteringFunction(self, q, time_range = (0., None, None), subset=None, weights=None, random_vectors=15, first_mode = 6): if subset is None: subset = self.universe if weights is None: weights = self.universe.getParticleScalar('b_coherent') mask = subset.booleanMask() weights = N.repeat(weights.array, mask.array) weights = weights/N.sqrt(N.add.reduce(weights*weights)) friction = N.repeat(self.friction.array, mask.array) r = N.repeat(self.universe.configuration().array, mask.array) first, last, step = (time_range + (None, None))[:3] if last is None: last = 3./self.rawMode(first_mode).inv_relaxation_time if step is None: step = (last-first)/300. time = N.arange(first, last, step) natoms = subset.numberOfAtoms() kT = Units.k_B*self.temperature fcoh = N.zeros((len(time),), N.Complex) random_vectors = Random.randomDirections(random_vectors) for v in random_vectors: phase = N.exp(-1.j*q*N.dot(r, v.array)) for ai in range(natoms): fbt = N.zeros((natoms, len(time)), N.Float) for i in range(first_mode, self.nmodes): irt = self.rawMode(i).inv_relaxation_time d = q * N.repeat((self.rawMode(i)*v).array, mask.array) \ / N.sqrt(friction) ft = N.exp(-irt*time)/irt N.add(fbt, d[ai] * d[:, N.NewAxis] * ft[N.NewAxis, :], fbt) N.add(fbt, (-0.5/irt) * (d[ai]**2 + d[:, N.NewAxis]**2), fbt) N.add(fcoh, weights[ai]*phase[ai] * N.dot(weights*N.conjugate(phase), N.exp(kT*fbt)), fcoh) return InterpolatingFunction((time,), fcoh.real/len(random_vectors))
def coherentScatteringFunction(self, q, time_range=(0., None, None), subset=None, weights=None, random_vectors=15, first_mode=6): if subset is None: subset = self.universe if weights is None: weights = self.universe.getParticleScalar('b_coherent') mask = subset.booleanMask() weights = N.repeat(weights.array, mask.array) weights = weights / N.sqrt(N.add.reduce(weights * weights)) friction = N.repeat(self.friction.array, mask.array) r = N.repeat(self.universe.configuration().array, mask.array) first, last, step = (time_range + (None, None))[:3] if last is None: last = 3. / self.rawMode(first_mode).inv_relaxation_time if step is None: step = (last - first) / 300. time = N.arange(first, last, step) natoms = subset.numberOfAtoms() kT = Units.k_B * self.temperature fcoh = N.zeros((len(time), ), N.Complex) random_vectors = Random.randomDirections(random_vectors) for v in random_vectors: phase = N.exp(-1.j * q * N.dot(r, v.array)) for ai in range(natoms): fbt = N.zeros((natoms, len(time)), N.Float) for i in range(first_mode, self.nmodes): irt = self.rawMode(i).inv_relaxation_time d = q * N.repeat((self.rawMode(i)*v).array, mask.array) \ / N.sqrt(friction) ft = N.exp(-irt * time) / irt N.add(fbt, d[ai] * d[:, N.NewAxis] * ft[N.NewAxis, :], fbt) N.add(fbt, (-0.5 / irt) * (d[ai]**2 + d[:, N.NewAxis]**2), fbt) N.add( fcoh, weights[ai] * phase[ai] * N.dot(weights * N.conjugate(phase), N.exp(kT * fbt)), fcoh) return InterpolatingFunction((time, ), fcoh.real / len(random_vectors))
def incoherentScatteringFunction(self, q, time_range = (0., None, None), subset=None, random_vectors=15, first_mode = 6): if subset is None: subset = self.universe mask = subset.booleanMask() weights_inc = self.universe.getParticleScalar('b_incoherent') weights_inc = N.repeat(weights_inc.array**2, mask.array) weights_inc = weights_inc/N.add.reduce(weights_inc) friction = N.repeat(self.friction.array, mask.array) mass = N.repeat(self.universe.masses().array, mask.array) r = N.repeat(self.universe.configuration().array, mask.array) first, last, step = (time_range + (None, None))[:3] if last is None: last = 3./self.weighedMode(first_mode).inv_relaxation_time if step is None: step = (last-first)/300. time = N.arange(first, last, step) natoms = subset.numberOfAtoms() kT = Units.k_B*self.temperature finc = N.zeros((len(time),), N.Float) eisf = 0. random_vectors = Random.randomDirections(random_vectors) for v in random_vectors: phase = N.exp(-1.j*q*N.dot(r, v.array)) faat = N.zeros((natoms, len(time)), N.Float) eisf_sum = N.zeros((natoms,), N.Float) for i in range(first_mode, self.nmodes): irt = self.rawMode(i).inv_relaxation_time d = q * N.repeat((self.rawMode(i)*v).array, mask.array) \ / N.sqrt(friction) ft = (N.exp(-irt*time)-1.)/irt N.add(faat, d[:, N.NewAxis]**2 * ft[N.NewAxis, :], faat) N.add(eisf_sum, -d**2/irt, eisf_sum) N.add(finc, N.sum(weights_inc[:, N.NewAxis] * N.exp(kT*faat), 0), finc) eisf = eisf + N.sum(weights_inc*N.exp(kT*eisf_sum)) return InterpolatingFunction((time,), finc/len(random_vectors))
def incoherentScatteringFunction(self, q, time_range=(0., None, None), subset=None, random_vectors=15, first_mode=6): if subset is None: subset = self.universe mask = subset.booleanMask() weights_inc = self.universe.getParticleScalar('b_incoherent') weights_inc = N.repeat(weights_inc.array**2, mask.array) weights_inc = weights_inc / N.add.reduce(weights_inc) friction = N.repeat(self.friction.array, mask.array) mass = N.repeat(self.universe.masses().array, mask.array) r = N.repeat(self.universe.configuration().array, mask.array) first, last, step = (time_range + (None, None))[:3] if last is None: last = 3. / self.weighedMode(first_mode).inv_relaxation_time if step is None: step = (last - first) / 300. time = N.arange(first, last, step) natoms = subset.numberOfAtoms() kT = Units.k_B * self.temperature finc = N.zeros((len(time), ), N.Float) eisf = 0. random_vectors = Random.randomDirections(random_vectors) for v in random_vectors: phase = N.exp(-1.j * q * N.dot(r, v.array)) faat = N.zeros((natoms, len(time)), N.Float) eisf_sum = N.zeros((natoms, ), N.Float) for i in range(first_mode, self.nmodes): irt = self.rawMode(i).inv_relaxation_time d = q * N.repeat((self.rawMode(i)*v).array, mask.array) \ / N.sqrt(friction) ft = (N.exp(-irt * time) - 1.) / irt N.add(faat, d[:, N.NewAxis]**2 * ft[N.NewAxis, :], faat) N.add(eisf_sum, -d**2 / irt, eisf_sum) N.add(finc, N.sum(weights_inc[:, N.NewAxis] * N.exp(kT * faat), 0), finc) eisf = eisf + N.sum(weights_inc * N.exp(kT * eisf_sum)) return InterpolatingFunction((time, ), finc / len(random_vectors))
def staticStructureFactor(self, q_range=(1., 15.), subset=None, weights=None, random_vectors=15, first_mode=6): if subset is None: subset = self.universe if weights is None: weights = self.universe.getParticleScalar('b_coherent') mask = subset.booleanMask() weights = N.repeat(weights.array, mask.array) weights = weights / N.sqrt(N.add.reduce(weights * weights)) friction = N.repeat(self.friction.array, mask.array) r = N.repeat(self.universe.configuration().array, mask.array) first, last, step = (q_range + (None, ))[:3] if step is None: step = (last - first) / 50. q = N.arange(first, last, step) kT = Units.k_B * self.temperature natoms = subset.numberOfAtoms() sq = 0. random_vectors = Random.randomDirections(random_vectors) for v in random_vectors: sab = N.zeros((natoms, natoms), N.Float) for i in range(first_mode, self.nmodes): irt = self.rawMode(i).inv_relaxation_time d = N.repeat((self.rawMode(i)*v).array, mask.array) \ / N.sqrt(friction) sab = sab + (d[N.NewAxis, :] - d[:, N.NewAxis])**2 / irt sab = sab[N.NewAxis, :, :] * q[:, N.NewAxis, N.NewAxis]**2 phase = N.exp(-1.j*q[:, N.NewAxis] * N.dot(r, v.array)[N.NewAxis, :]) \ * weights[N.NewAxis, :] temp = N.sum(phase[:, :, N.NewAxis] * N.exp(-0.5 * kT * sab), 1) temp = N.sum(N.conjugate(phase) * temp, 1) sq = sq + temp.real return InterpolatingFunction((q, ), sq / len(random_vectors))
def staticStructureFactor(self, q_range = (1., 15.), subset=None, weights=None, random_vectors=15, first_mode = 6): if subset is None: subset = self.universe if weights is None: weights = self.universe.getParticleScalar('b_coherent') mask = subset.booleanMask() weights = N.repeat(weights.array, mask.array) weights = weights/N.sqrt(N.add.reduce(weights*weights)) friction = N.repeat(self.friction.array, mask.array) r = N.repeat(self.universe.configuration().array, mask.array) first, last, step = (q_range+(None,))[:3] if step is None: step = (last-first)/50. q = N.arange(first, last, step) kT = Units.k_B*self.temperature natoms = subset.numberOfAtoms() sq = 0. random_vectors = Random.randomDirections(random_vectors) for v in random_vectors: sab = N.zeros((natoms, natoms), N.Float) for i in range(first_mode, self.nmodes): irt = self.rawMode(i).inv_relaxation_time d = N.repeat((self.rawMode(i)*v).array, mask.array) \ / N.sqrt(friction) sab = sab + (d[N.NewAxis,:]-d[:,N.NewAxis])**2/irt sab = sab[N.NewAxis,:,:]*q[:, N.NewAxis, N.NewAxis]**2 phase = N.exp(-1.j*q[:, N.NewAxis] * N.dot(r, v.array)[N.NewAxis, :]) \ * weights[N.NewAxis, :] temp = N.sum(phase[:, :, N.NewAxis]*N.exp(-0.5*kT*sab), 1) temp = N.sum(N.conjugate(phase)*temp, 1) sq = sq + temp.real return InterpolatingFunction((q,), sq/len(random_vectors))
def incoherentScatteringFunction(self, q, time_range=(0., None, None), subset=None, random_vectors=15, first_mode=6): """ :param q: the angular wavenumber :type q: float :param time_range: the time values at which the mean-square displacement is evaluated, specified as a range tuple (first, last, step). The defaults are first=0, last= 20 times the longest vibration perdiod, and step defined such that 300 points are used in total. :type time_range: tuple :param subset: the subset of the universe used in the calculation (default: the whole universe) :type subset: :class:~MMTK.Collections.GroupOfAtoms :param random_vectors: the number of random direction vectors used in the orientational average :type random_vectors: int :param first_mode: the first mode to be taken into account for the fluctuation calculation. The default value of 6 is right for molecules in vacuum. :type first_mode: int :returns: the Incoherent Scattering Function as a function of time :rtype: Scientific.Functions.Interpolation.InterpolatingFunction """ if subset is None: subset = self.universe mask = subset.booleanMask() weights_inc = self.universe.getParticleScalar('b_incoherent') weights_inc = N.repeat(weights_inc.array**2, mask.array) weights_inc = weights_inc / N.add.reduce(weights_inc) friction = N.repeat(self.friction.array, mask.array) mass = N.repeat(self.universe.masses().array, mask.array) r = N.repeat(self.universe.configuration().array, mask.array) first, last, step = (time_range + (None, None))[:3] if last is None: last = 3. / self.weighedMode(first_mode).inv_relaxation_time if step is None: step = (last - first) / 300. time = N.arange(first, last, step) natoms = subset.numberOfAtoms() kT = Units.k_B * self.temperature finc = N.zeros((len(time), ), N.Float) eisf = 0. random_vectors = Random.randomDirections(random_vectors) for v in random_vectors: phase = N.exp(-1.j * q * N.dot(r, v.array)) faat = N.zeros((natoms, len(time)), N.Float) eisf_sum = N.zeros((natoms, ), N.Float) for i in range(first_mode, self.nmodes): irt = self.rawMode(i).inv_relaxation_time d = q * N.repeat((self.rawMode(i)*v).array, mask.array) \ / N.sqrt(friction) ft = (N.exp(-irt * time) - 1.) / irt N.add(faat, d[:, N.NewAxis]**2 * ft[N.NewAxis, :], faat) N.add(eisf_sum, -d**2 / irt, eisf_sum) N.add(finc, N.sum(weights_inc[:, N.NewAxis] * N.exp(kT * faat), 0), finc) eisf = eisf + N.sum(weights_inc * N.exp(kT * eisf_sum)) return InterpolatingFunction((time, ), finc / len(random_vectors))
def coherentScatteringFunction(self, q, time_range=(0., None, None), subset=None, weights=None, random_vectors=15, first_mode=6): """ :param q: the angular wavenumber :type q: float :param time_range: the time values at which the mean-square displacement is evaluated, specified as a range tuple (first, last, step). The defaults are first=0, last= 20 times the longest vibration perdiod, and step defined such that 300 points are used in total. :type time_range: tuple :param subset: the subset of the universe used in the calculation (default: the whole universe) :type subset: :class:~MMTK.Collections.GroupOfAtoms :param weights: the weight to be given to each atom in the average (default: coherent scattering lengths) :type weights: :class:~MMTK.ParticleProperties.ParticleScalar :param random_vectors: the number of random direction vectors used in the orientational average :type random_vectors: int :param first_mode: the first mode to be taken into account for the fluctuation calculation. The default value of 6 is right for molecules in vacuum. :type first_mode: int :returns: the Coherent Scattering Function as a function of time :rtype: Scientific.Functions.Interpolation.InterpolatingFunction """ if subset is None: subset = self.universe if weights is None: weights = self.universe.getParticleScalar('b_coherent') mask = subset.booleanMask() weights = N.repeat(weights.array, mask.array) weights = weights / N.sqrt(N.add.reduce(weights * weights)) friction = N.repeat(self.friction.array, mask.array) r = N.repeat(self.universe.configuration().array, mask.array) first, last, step = (time_range + (None, None))[:3] if last is None: last = 3. / self.rawMode(first_mode).inv_relaxation_time if step is None: step = (last - first) / 300. time = N.arange(first, last, step) natoms = subset.numberOfAtoms() kT = Units.k_B * self.temperature fcoh = N.zeros((len(time), ), N.Complex) random_vectors = Random.randomDirections(random_vectors) for v in random_vectors: phase = N.exp(-1.j * q * N.dot(r, v.array)) for ai in range(natoms): fbt = N.zeros((natoms, len(time)), N.Float) for i in range(first_mode, self.nmodes): irt = self.rawMode(i).inv_relaxation_time d = q * N.repeat((self.rawMode(i)*v).array, mask.array) \ / N.sqrt(friction) ft = N.exp(-irt * time) / irt N.add(fbt, d[ai] * d[:, N.NewAxis] * ft[N.NewAxis, :], fbt) N.add(fbt, (-0.5 / irt) * (d[ai]**2 + d[:, N.NewAxis]**2), fbt) N.add( fcoh, weights[ai] * phase[ai] * N.dot(weights * N.conjugate(phase), N.exp(kT * fbt)), fcoh) return InterpolatingFunction((time, ), fcoh.real / len(random_vectors))
def incoherentScatteringFunction(self, q, time_range = (0., None, None), subset=None, random_vectors=15, first_mode = 6): """ :param q: the angular wavenumber :type q: float :param time_range: the time values at which the mean-square displacement is evaluated, specified as a range tuple (first, last, step). The defaults are first=0, last= 20 times the longest vibration perdiod, and step defined such that 300 points are used in total. :type time_range: tuple :param subset: the subset of the universe used in the calculation (default: the whole universe) :type subset: :class:`~MMTK.Collections.GroupOfAtoms` :param random_vectors: the number of random direction vectors used in the orientational average :type random_vectors: int :param first_mode: the first mode to be taken into account for the fluctuation calculation. The default value of 6 is right for molecules in vacuum. :type first_mode: int :returns: the Incoherent Scattering Function as a function of time :rtype: Scientific.Functions.Interpolation.InterpolatingFunction """ if subset is None: subset = self.universe mask = subset.booleanMask() weights_inc = self.universe.getParticleScalar('b_incoherent') weights_inc = N.repeat(weights_inc.array**2, mask.array) weights_inc = weights_inc/N.add.reduce(weights_inc) friction = N.repeat(self.friction.array, mask.array) mass = N.repeat(self.universe.masses().array, mask.array) r = N.repeat(self.universe.configuration().array, mask.array) first, last, step = (time_range + (None, None))[:3] if last is None: last = 3./self.weighedMode(first_mode).inv_relaxation_time if step is None: step = (last-first)/300. time = N.arange(first, last, step) natoms = subset.numberOfAtoms() kT = Units.k_B*self.temperature finc = N.zeros((len(time),), N.Float) eisf = 0. random_vectors = Random.randomDirections(random_vectors) for v in random_vectors: phase = N.exp(-1.j*q*N.dot(r, v.array)) faat = N.zeros((natoms, len(time)), N.Float) eisf_sum = N.zeros((natoms,), N.Float) for i in range(first_mode, self.nmodes): irt = self.rawMode(i).inv_relaxation_time d = q * N.repeat((self.rawMode(i)*v).array, mask.array) \ / N.sqrt(friction) ft = (N.exp(-irt*time)-1.)/irt N.add(faat, d[:, N.NewAxis]**2 * ft[N.NewAxis, :], faat) N.add(eisf_sum, -d**2/irt, eisf_sum) N.add(finc, N.sum(weights_inc[:, N.NewAxis] * N.exp(kT*faat), 0), finc) eisf = eisf + N.sum(weights_inc*N.exp(kT*eisf_sum)) return InterpolatingFunction((time,), finc/len(random_vectors))
def coherentScatteringFunction(self, q, time_range = (0., None, None), subset=None, weights=None, random_vectors=15, first_mode = 6): """ :param q: the angular wavenumber :type q: float :param time_range: the time values at which the mean-square displacement is evaluated, specified as a range tuple (first, last, step). The defaults are first=0, last= 20 times the longest vibration perdiod, and step defined such that 300 points are used in total. :type time_range: tuple :param subset: the subset of the universe used in the calculation (default: the whole universe) :type subset: :class:`~MMTK.Collections.GroupOfAtoms` :param weights: the weight to be given to each atom in the average (default: coherent scattering lengths) :type weights: :class:`~MMTK.ParticleProperties.ParticleScalar` :param random_vectors: the number of random direction vectors used in the orientational average :type random_vectors: int :param first_mode: the first mode to be taken into account for the fluctuation calculation. The default value of 6 is right for molecules in vacuum. :type first_mode: int :returns: the Coherent Scattering Function as a function of time :rtype: Scientific.Functions.Interpolation.InterpolatingFunction """ if subset is None: subset = self.universe if weights is None: weights = self.universe.getParticleScalar('b_coherent') mask = subset.booleanMask() weights = N.repeat(weights.array, mask.array) weights = weights/N.sqrt(N.add.reduce(weights*weights)) friction = N.repeat(self.friction.array, mask.array) r = N.repeat(self.universe.configuration().array, mask.array) first, last, step = (time_range + (None, None))[:3] if last is None: last = 3./self.rawMode(first_mode).inv_relaxation_time if step is None: step = (last-first)/300. time = N.arange(first, last, step) natoms = subset.numberOfAtoms() kT = Units.k_B*self.temperature fcoh = N.zeros((len(time),), N.Complex) random_vectors = Random.randomDirections(random_vectors) for v in random_vectors: phase = N.exp(-1.j*q*N.dot(r, v.array)) for ai in range(natoms): fbt = N.zeros((natoms, len(time)), N.Float) for i in range(first_mode, self.nmodes): irt = self.rawMode(i).inv_relaxation_time d = q * N.repeat((self.rawMode(i)*v).array, mask.array) \ / N.sqrt(friction) ft = N.exp(-irt*time)/irt N.add(fbt, d[ai] * d[:, N.NewAxis] * ft[N.NewAxis, :], fbt) N.add(fbt, (-0.5/irt) * (d[ai]**2 + d[:, N.NewAxis]**2), fbt) N.add(fcoh, weights[ai]*phase[ai] * N.dot(weights*N.conjugate(phase), N.exp(kT*fbt)), fcoh) return InterpolatingFunction((time,), fcoh.real/len(random_vectors))