def merge_virtual_particles(frm): """ Merges the virtual particle species X1,X2 in a base.Container() instance. Modifies the base.Container() instance in-place. """ assert isinstance(frm, base.Container) # --- sum up the distance histograms if frm.contains_key(base.loc_histograms): histgrms = frm.get_data(base.loc_histograms) for key in list(histgrms.keys()): # Use StripVirtualParticles() earlier in the pipeline! assert (key not in blacklist) elements = util.get_elements(list(histgrms.keys())) if ('X1' in elements) and ('X2' in elements): all_X1 = [] all_X2 = [] for key in list(histgrms.keys()): if 'X1' in key: all_X1.append(key) elif 'X2' in key: all_X2.append(key) all_X1X2 = sorted(set(all_X1 + all_X2)) for key in all_X1X2: key_new = key.replace('X1', 'X').replace('X2', 'X') # print "###", key, key_new if key_new not in list(histgrms.keys()): histgrms[key_new] = np.zeros_like(histgrms[key]) histgrms[key_new] += histgrms[key] del histgrms[key] # --- sum up the particle number arrays if frm.contains_key(base.loc_nr_particles): partnums = frm.get_data(base.loc_nr_particles) elements = util.get_elements(list(partnums.keys())) if ('X1' in elements) and ('X2' in elements): X1 = partnums['X1'] X2 = partnums['X2'] X = X1 + X2 partnums['X'] = X.copy() del X del partnums['X1'] del partnums['X2'] # --- sum up the length histogram arrays if frm.contains_key(base.loc_len_histograms): lenhists = frm.get_data(base.loc_len_histograms) elements = util.get_elements(list(lenhists.keys())) if ('X1' in elements) and ('X2' in elements): X1 = lenhists['X1'] X2 = lenhists['X2'] X = X1 + X2 lenhists['X'] = X.copy() del X del lenhists['X1'] del lenhists['X2']
def __next__(self): for frm in next(self.src): if frm is not None: assert isinstance(frm, base.Container) histgrms = frm.get_data(base.loc_histograms) elements = util.get_elements(list(histgrms.keys())) if ('X1' in elements) and ('X2' in elements): for key in blacklist: if key in list(histgrms.keys()): del histgrms[key] frm.put_meta(self.get_meta()) if self.verb: print("StripVirtualParticles.next() :", frm.i) yield frm else: yield None
def __next__(self): for frm in next(self.src): if frm is not None: assert isinstance(frm, base.Container) # --- histos = frm.get_data(base.loc_histograms) elements = util.get_elements(list(histos.keys())) if ('X1' in elements) and ('X2' in elements): selection.merge_virtual_particles(frm) # --- frm.put_meta(self.get_meta()) if self.verb: print("MergeVirtualParticles.next() :", frm.i) yield frm else: yield None
def scaleVirtualHistograms(frm): """ When using the MultiReferenceStructure filter, histograms containing virtual particles have to be properly scaled before averaging. The reason beeing that the volumes of the observation volumes vary for each frame. This scaling should also work when using a single reference structure, where the volume is constant for each frame. To facilitate solvent matching, we properly scale the X,X histograms of the shell and save them separately from the original histograms for later use. Precondition: o Each frames contains a single histogram only (sample=1 in histograms.yaml), because the volume varies for each frame. Scale factors for the 'gas' and 'lattice' methods are different because in the 'lattice' method we evaluate distances between two separate sets of particles (called X1 and X2). Note that because of the scaling applied here the norms of the cross, core, and shell histograms are no longer meaningfull. Only the norm of the full histogram is. """ virtual_param = frm.query_meta('VirtualParticles') if (virtual_param is not None): method = virtual_param['method'] xrho = virtual_param['x_density'] else: return frm geom = frm.get_geometry() meta = frm.query_meta(geom) if method == 'gas': nrPart = frm.get_data(base.loc_nr_particles) nx = nrPart['X'][0] # print " nx =", nx if meta['shell_width'] > 0: shell_Hxx = frm.get_data(base.loc_histograms + "/X.s,X.s") frm.put_data(base.loc_shell_Hxx, {'X.s,X.s': shell_Hxx}) nXs = (frm.get_data(base.loc_nr_particles))['X.s'][0] shell_Hxx = frm.get_data(base.loc_shell_Hxx) dict_util.scale_values(shell_Hxx, scaleFactorXX(nXs, xrho)) histgrms = frm.get_data(base.loc_histograms) elements = util.get_elements(list(histgrms.keys())) # The scaling is the same for core, cross, shell, and full, because # full is given by a linear combination of core, cross, and shell. # We identify $H_{ix}(r)$ and $H_{xx}(r)$ by counting 'X' in the keys # (only works if there is no species a name with multiple 'X'). for key in frm.get_keys(base.loc_histograms): XCounter = key.count('X') if XCounter == 1: histgrms[key] /= xrho elif XCounter == 2: # print histgrms[key].sum(), (nx**2-nx) histgrms[key] *= scaleFactorXX(nx, xrho) frm.put_data(base.loc_histograms, histgrms) elif method == 'lattice': nrPart = frm.get_data(base.loc_nr_particles) nx1 = nrPart['X1'][0] + nrPart['X1.s'][0] nx2 = nrPart['X2'][0] + nrPart['X2.s'][0] nx = nx1 + nx2 if meta['shell_width'] > 0: shell_Hxx = frm.get_data(base.loc_histograms + "/X1.s,X2.s") frm.put_data(base.loc_shell_Hxx, {'X.s,X.s': shell_Hxx}) nXs1 = nrPart['X1.s'][0] nXs2 = nrPart['X2.s'][0] shell_Hxx = frm.get_data(base.loc_shell_Hxx) # shell_Hxx is normalized in the Solvent filter. A constant scale factor # does not have any influence. dict_util.scale_values(shell_Hxx, scaleFactorX1X2(nXs1, nXs2, xrho)) histgrms = frm.get_data(base.loc_histograms) elements = util.get_elements(list(histgrms.keys())) for key in frm.get_keys(base.loc_histograms): XCounter = key.count('X') if XCounter == 1: histgrms[key] /= xrho elif XCounter == 2: histgrms[key] *= scaleFactorX1X2(nx1, nx2, xrho) frm.put_data(base.loc_histograms, histgrms) return frm
def _process_frame(self, frm): """Compute the radial distribution function. """ # This implementation follows <legacy/getRDFFromPBC.py> by Juergen Koefinger assert (frm.contains_key(base.loc_volumes)) assert (frm.contains_key(base.loc_nr_particles)) # obtain array of box volumes from the original trajectory frames _volumes = frm.get_data(base.loc_volumes) box_volumes = _volumes['box'] if hasattr(box_volumes, "__len__"): n_samples = len(box_volumes) else: n_samples = 1 # obtain arrays of the numbers of particles present in the original trajectory frame nr_particles = frm.get_data(base.loc_nr_particles) for key in nr_particles: assert (n_samples == (nr_particles[key]).shape[0]) histograms = frm.get_data(base.loc_histograms) dr = frm.query_meta('histograms/histogram/dr') # consistency check if the histogram labels match with the particle numbers _species_h = set(util.get_elements(list(histograms.keys()))) _species_p = set(nr_particles.keys()) assert (_species_h == _species_p) radii = histograms['radii'] histogram_keys = list(histograms.keys()) histogram_keys.remove('radii') vol = np.sum(box_volumes) vol /= n_samples # QUESTION: 'norm' in the original code, is this just the number of samples? vol_inv = np.sum(np.reciprocal(box_volumes)) vol_inv /= n_samples # QUESTION: 'norm' in the original code, is this just the number of samples? # coefficients repeatedly used by the nested loop below coeff = 4.0 * np.pi * dr * vol_inv * np.multiply(radii, radii) rdf = {} for key in histogram_keys: species_1, species_2 = tuple(key.split(',')) nr_1 = np.sum(nr_particles[species_1]) / float(n_samples) nr_2 = np.sum(nr_particles[species_2]) / float(n_samples) # the particle number in the box is constant, therefor densities are calculated as rho_1 = nr_1 * vol_inv rho_2 = nr_2 * vol_inv if (nr_1 * nr_2 > 0): if (species_1 == species_2): fac = 1.0 else: fac = 2.0 histo = np.copy(histograms[key]) for i in range(len(radii)): histo[i] /= fac * nr_1 * nr_2 * coeff[i] # Factor 2 because distances are only counted once in histograms (r_{ij} and r_{ji} are counted as a single distance) rdf[key] = 2 * histo if (species_1 == species_2): rdf[key][0] = rho_1 else: if self.verb: print(" RDF: skipping " + key) rdf['radii'] = radii # --- if self.verb: print(" RDF: average inverse volume =", vol_inv) print(" RDF: inverse average volume =", 1. / vol) print(" RDF: ratio =", vol_inv * vol) # --- frm.put_data(base.loc_rdf, rdf)
def __next__(self): for hs in next(self.src): # hs was chosen to mean 'histogram set' ... if hs is not None: assert isinstance(hs, base.Container) # --- obtain information from the pipeline log dr = hs.query_meta('histograms/histogram/dr') assert (dr is not None) # --- self.geometry = hs.get_geometry() assert (self.geometry is not None) geometry_param = hs.query_meta(self.geometry) assert (geometry_param is not None) if (self.geometry == 'Sphere' or self.geometry == 'Cuboid' or self.geometry == 'Ellipsoid'): V = geometry_param['volume'] assert (V is not None) # VAvg is neede below for MultiReference, where V=1 for histograms # but VAvg is used for densities VAvg = V else: # --- for non-sphere geometries, we calculate V using x particles below V = None # --- virtual_param = hs.query_meta('VirtualParticles') if (virtual_param is not None): self.x_particle_method = virtual_param['method'] xrho = virtual_param['x_density'] # --- rdf_header = list( (hs.get_data(base.loc_solv_match + '/g_scaled')).keys()) rdf_header.remove('radii') rdf_elements = util.get_elements(rdf_header) n_solv = len(rdf_elements) hs_full = selection.get_full(hs) n_part_elements = util.get_elements( list(hs_full.get_data(base.loc_nr_particles).keys())) histo_elements = util.get_elements( list(hs_full.get_data(base.loc_histograms).keys())) # --- print '###', n_part_elements, histo_elements assert (n_part_elements == histo_elements) n_prot = len(histo_elements) if (self.debug): print(" rdf_header", rdf_header) print(" rdf_elements", rdf_elements) print(" n_solv =", n_solv) print(" n_prot=", n_prot) histo = copy.deepcopy(hs_full.get_data(base.loc_histograms)) nr = len(hs_full.get_data(base.loc_histograms + '/radii')) for key in list(histo.keys()): if (key == 'radii'): continue histo[key] *= 2.0 # --- NOTE : in the following, we're sorting out the virtual particles H, Hx = _separate_ghosts_from_histogram(histo) # --- consistency checks of the radii assert (len( hs.get_data(base.loc_solv_match + '/g_scaled/radii')) >= nr) radii_1 = hs.get_data(base.loc_solv_match + '/g_scaled/radii')[0:nr] radii_2 = hs_full.get_data(base.loc_histograms + '/radii')[0:nr] eps = 1.e-9 assert np.all(np.fabs(radii_1 - radii_2) < eps) # rdf_expanded = {} for key in list( (hs.get_data(base.loc_solv_match + '/g_scaled')).keys()): # Note: g_scaled dictionary includes the radii array rdf_expanded[key] = np.zeros(nr) (rdf_expanded[key])[0:nr] = ( hs.get_data(base.loc_solv_match + '/g_scaled/' + key))[0:nr] rdf_org = copy.deepcopy(rdf_expanded) # --- if (self.debug): hs.put_data(base.loc_delta_h + '/debug/rdf_org', rdf_org) rho = hs.get_data(base.loc_solv_match + '/rho') # --- for key in list(rdf_expanded.keys()): # zero densities as done in the reference code <deltaH.py> if (key == 'radii'): continue (rdf_expanded[key])[0] = 0.0 if (self.geometry == 'Sphere') and (self.x_particle_method is None): # print "### delta_H :: SPHERE BRANCH ###" R = geometry_param['radius'] dHs = copy.deepcopy(H) for key in list(dHs.keys()): if (key == 'radii'): continue (dHs[key])[:] = 0.0 dHp = copy.deepcopy(dHs) dH = copy.deepcopy(dHs) # --- assert hs.contains_key(base.loc_len_histograms) # --- construct h matrix x_list = hs.get_data(base.loc_len_histograms + '/radii') r_list = H['radii'] # --- implement h using a dictionary h_dict = {} for key in hs.get_keys(base.loc_len_histograms): h_dict[key] = np.zeros(len(r_list)) h_dict['radii'][:] = r_list[:] # --- pSphere = np.zeros((r_list.shape[0], 2)) pSphere[:, 0] = r_list[:] # --- for j, rv in enumerate(r_list): pSphere[j, 1] = rdf.P(rv, R) if (self.debug): hs.put_data(base.loc_delta_h + '/debug/pSphere', pSphere) # --- dx = dr # DANGER! However, these two should be the same anyway! # --- getSr = rdf.SrFast print() for j, rv in enumerate(r_list): if self.verb and (j % 1000 == 0): print(" DeltaH:bin ", j) Sr = getSr(x_list, R, rv) for key in hs.get_keys(base.loc_len_histograms, skip_keys=['radii']): (h_dict[key])[j] += ( hs.get_data(base.loc_len_histograms + '/' + key)[:] * Sr[:]).sum(axis=0) for key in hs.get_keys(base.loc_len_histograms, skip_keys=['radii']): h_dict[key] *= 2.0 * dx / V # --- patch rho[] such that it can be used in the block below if key not in rho: rho[key] = 0.0 for key in sorted(H.keys()): if (key == 'radii'): continue # --- patch rdf_expanded such that it can be used below if key not in rdf_expanded: rdf_expanded[key] = np.zeros(nr) # --- (el1, el2) = key.split(',') if (el1 == el2): fac = 1.0 else: fac = 2.0 # --- (dHs[key])[:] = fac * ((rdf_expanded[key])[:] - 2.0) \ * rho[el1] * rho[el2] * V * V * pSphere[:, 1] * dr # Hx[:,ixx] # --- if (fac == 1): (dHp[key])[:] = (H[key])[:] - V * rho[el1] * ( h_dict[el1])[:] # *Hx[:,ix1] else: (dHp[key])[:] = ( H[key])[:] - V * (rho[el2] * (h_dict[el1])[:] + rho[el1] * (h_dict[el2])[:]) # --- (dH[key])[:] = (dHp[key])[:] - (dHs[key])[:] else: # --- virtual particle method branch # print "delta_h " nx = np.mean(hs_full.get_data(base.loc_nr_particles + '/X'), dtype=np.float64) if not (self.geometry == 'Sphere' or self.geometry == 'Cuboid' or self.geometry == 'Ellipsoid'): V = old_div(nx, xrho) VAvg = V if (self.geometry == 'MultiReferenceStructure'): V = 1. # print " V =", V, "VAvg =", VAvg else: for key in Hx: if key in 'radii': continue pair = key.split(',') assert (len(pair) == 2) if (pair[0] == 'X') and (pair[1] == 'X'): Hx[key] /= (Hx[key]).sum() else: Hx[key] /= nx # --- dHs = copy.deepcopy(H) for key in list(dHs.keys()): if (key == 'radii'): continue (dHs[key])[:] = 0.0 dHp = copy.deepcopy(dHs) dH = copy.deepcopy(dHs) # --- for key in sorted(H.keys()): if (key == 'radii'): continue # --- patch rdf_expanded such that it can be used below if key not in rdf_expanded: rdf_expanded[key] = np.zeros(nr) # --- (el1, el2) = key.split(',') # --- patch rho such that it can be used below for el in [el1, el2]: if el not in rho: rho[el] = 0.0 # --- if (el1 == el2): fac = 1.0 else: fac = 2.0 # --- (dHs[key])[:] = fac * ((rdf_expanded[key])[:] - 2.0) \ * rho[el1] * rho[el2] * V * V * Hx['X,X'] # --- if (fac == 1): (dHp[key])[:] = ( H[key])[:] - V * rho[el1] * (Hx[el1 + ',X'])[:] else: (dHp[key])[:] = (H[key])[:] - V * ( rho[el2] * (Hx[el1 + ',X'])[:] + rho[el1] * (Hx[el2 + ',X'])[:]) # --- (dH[key])[:] = (dHp[key])[:] - (dHs[key])[:] # --- if (self.debug): hs.put_data(base.loc_delta_h + '/debug/rdf_expanded', rdf_expanded) hs.put_data(base.loc_delta_h + '/debug/dHs', dHs) hs.put_data(base.loc_delta_h + '/debug/dHp', dHp) hs.put_data(base.loc_delta_h + '/debug/dH', dH) hs.put_data(base.loc_delta_h + '/debug/H', H) hs.put_data(base.loc_delta_h + '/debug/rho', rho) hs.put_data(base.loc_delta_h + '/debug/h_dict', h_dict) # --- hs.put_data(base.loc_intensity + '/dH', dH) # --- calculate average particle numbers nr_part_avg = {} for key in hs_full.get_keys(base.loc_nr_particles): nr_part = hs_full.get_data(base.loc_nr_particles + '/' + key) nr_part_avg[key] = nr_part.sum(axis=0) / float( nr_part.shape[0]) # --- calculate difference nr_part_diff = {} for key in nr_part_avg: if key in rho: nr_part_diff[key] = nr_part_avg[key] - rho[key] * VAvg else: nr_part_diff[key] = nr_part_avg[key] hs.put_data(base.loc_intensity + '/dN', nr_part_diff) # --- INTENSITY CALCULATION --- # --- read atom form factors from file ff_dict = ff.readAtomSFParam(self.form_factor_file) # --- prepare 2D input array for library routine (dH_2d, dH_2d_keys) = _make_2d(dH) if (self.debug): hs.put_data(base.loc_delta_h + '/debug/dH_2d', dH_2d) # --- _pIntInter, dInter = pynt.intensitiesFFFaster( self.nq, self.dq, dH_2d, dH_2d_keys, ff_dict, 1) # # --- prepare input # nr_part_keys = sorted(nr_part_diff.keys()) # nr_part_vals = [] # for key in nr_part_keys: # nr_part_vals.append(nr_part_diff[key]) # # --- # _pIntIntra, dIntra = pynt.intensitiesFFIntraAtom(self.nq, self.dq, \ # nr_part_vals, nr_part_keys, ff_dict) # # --- # hs.put_data(base.loc_intensity+'/dI_inter', dInter) # hs.put_data(base.loc_intensity+'/dI_intra', dIntra) dI = dInter.copy() # TODO: check, the following line was commented out in <deltaH.py> # dI[:,1] += dIntra[:,1] hs.put_data(base.loc_intensity + '/dI', dI) # --- prepare 2D input array for library routine # (cannot use _make_2d() routine here) n_row = len(rdf_org['radii']) n_col = len(list(dH.keys())) rdf_org_2d = np.zeros((n_row, n_col)) rdf_org_2d[:, 0] = (rdf_org['radii'])[:] rdf_org_2d_keys = sorted(rdf_org.keys()) rdf_org_2d_keys.remove('radii') for key in rdf_org_2d_keys: if key in dH_2d_keys: idx = dH_2d_keys.index(key) + 1 rdf_org_2d[:, idx] = (rdf_org[key])[:] # --- rho_list = [] rho_keys = sorted(rho.keys()) for key in ['X', 'X1', 'X2']: if key in rho_keys: rho_keys.remove(key) for key in rho_keys: rho_list.append(rho[key]) # --- if (self.debug): hs.put_data(base.loc_delta_h + '/debug/rdf_org_2d', rdf_org_2d) # --- bulkH = pynt.getBulkIntegrand(rdf_org_2d, rho_list) bulkH_keys = dH_2d_keys # print "bulkH_keys", bulkH_keys _pIntInter, dIntensityInter = pynt.intensitiesFFFaster( self.nq, self.dq, bulkH, bulkH_keys, ff_dict, dr) _pIntIntra, dIntensityIntra = pynt.intensitiesFFIntraAtom( self.nq, self.dq, rho_list, rho_keys, ff_dict) dIntensity = dIntensityInter.copy() dIntensity[:, 1] += dIntensityIntra[:, 1] # --- hs.put_data(base.loc_intensity + '/I_solv_inter', dIntensityInter) hs.put_data(base.loc_intensity + '/I_solv_intra', dIntensityIntra) hs.put_data(base.loc_intensity + '/I_solv', dIntensity) # TODO: Think about stripping unnecessary information # (histograms, length histograms) from hs at this point. hs.put_meta(self.get_meta()) if self.verb: print("DeltaH.next() :", hs.i) yield hs else: yield None