def __init__(self, trajectory, configurationsIndexes, cylinderAtomsIndexes, targetAtomsIndexes, axis=None, weighting="equal", histBin=1, *args, **kwargs): # set trajectory super(MeanSquareDisplacementInCylinder,self).__init__(trajectory, *args, **kwargs) # set configurations indexes self.configurationsIndexes = self.get_trajectory_indexes(configurationsIndexes) # set atoms indexes self.targetAtomsIndexes = self.get_atoms_indexes(targetAtomsIndexes) self.cylinderAtomsIndexes = self.get_atoms_indexes(cylinderAtomsIndexes) # set steps indexes self.numberOfSteps = len(self.targetAtomsIndexes) # set weighting assert is_element_property(weighting), Logger.error("weighting '%s' don't exist in database"%weighting) self.weighting = weighting # set residency time histogram bin try: self.histBin = float(histBin) except: raise Logger.error("histBin must be number convertible. %s is given."%histBin) assert self.histBin%1 == 0, logger.error("histBin must be integer. %s is given."%histBin) assert self.histBin>0, logger.error("histBin must be positive. %s is given."%histBin) assert self.histBin<len(self.configurationsIndexes), logger.error("histBin must smaller than numberOfConfigurations") # initialize variables self.__initialize_variables__(axis) # initialize results self.__initialize_results__() # get cylinder centers, matrices, radii, length Logger.info("%s --> initializing cylinder parameters along all configurations"%self.__class__.__name__) self.cylCenters, self.cylMatrices, self.cylRadii, self.cylLengths = self.__get_cylinder_properties__()
def convert(self, types=None): """ Converts to pdbparser """ # read lines lines = self.get_lines() # get number of atoms self.info["number_of_records"] = self.__get_number_of_records__(lines) # get number of types self.info["number_of_types"] = self.__get_number_of_types__(lines) # get simulation box vectors self.info["vectors"] = self.__get_box_vectors__(lines) # set types names if types is None: Logger.info( "types are not given. carbon element is considered for all types" ) self.info["types"] = [{ "name": "c%s" % idx, "element": "c" } for idx in range(self.info["number_of_types"])] else: assert len(types) == self.info[ "number_of_types"], "types must be a list of length equal to the number of types" for idx in range(self.info["number_of_types"]): if not isinstance(types[idx], dict): assert is_element( types[idx] ), "%s not found database elements" % types[idx] types[idx] = {"name": types[idx], "element": types[idx]} assert "name" in types[ idx], "every type dictionary must have 'name' and 'element' keys" assert "element" in types[ idx], "every type dictionary must have 'name' and 'element' keys" if types[idx]["element"].lower( ) not in __atoms_database__.keys(): Logger.warr("type %r is not defined in database" % types[idx]["element"]) else: types[idx]["element"] = types[idx]["element"].lower() self.info["types"] = types # get types records number self.info["records_per_type"] = [] for idx in range(self.info["number_of_types"]): self.info["records_per_type"].append( self.__get_records_per_type__(lines, idx + 1)) assert sum(self.info["records_per_type"]) == self.info[ "number_of_records"], "the sum of number of molecules in all types must be equal to number of ' molecules of all types'" # get coordinates fracCoord = self.__get_coordinates__(lines) assert fracCoord.shape == ( self.info["number_of_records"], 3 ), "stored fractional coordinates must be equal to number of ' molecules of all types'" # calculate real coordinates realCoord = self.__calculate_real_coordinates__(fracCoord) # create pdb self.__create_pdb__(realCoord) return self
def status(self, step, totalSteps, logFrequency=10): """ This method is used to log converting status.\n :Parameters: #. step (int): The current step number #. logFrequency (float): the frequency of status logging. its a percent number. """ if not step: Logger.info("%s --> converting started" % (self.__class__.__name__)) elif step == totalSteps: Logger.info("%s --> converting finished" % (self.__class__.__name__)) else: actualPercent = int(float(step) / float(totalSteps) * 100) if self.__previousStep is not None: previousPercent = int( float(self.__previousStep) / float(totalSteps) * 100) else: previousPercent = -1 if actualPercent / logFrequency != previousPercent / logFrequency: Logger.info("%s --> %s%% completed. %s left out of %s" % (self.__class__.__name__, actualPercent, totalSteps - step, totalSteps)) # update previous step self.__previousStep = step
def __init__(self, pdb, dcd, indexes=None, format="charmm"): """ Read new simulation trajectory :Parameters: #. pdb (string): NAMD pdb file used as trajectory structure file #. dcd (string): NAMD DCD output file #. indexes (list): the configuration indexes to convert. None converts all configurations #. format (string): the known formats. only charmm and dcd are supported. """ # initialize converter super(DCDConverter, self).__init__() # log some info Logger.info("Converting NAMD trajectory") Logger.info("pdb file path: %s" % pdb) Logger.info("dcd file path: %s" % dcd) # check format assert isinstance(format, str), Logger.error("format must be a string") self.format = str(format).lower() assert self.format in ( "charmm", "namd"), Logger.error("format must be either charmm or namd") # check indexes if indexes is not None: assert isinstance( indexes, (list, tuple, set, np.ndarray)), Logger.error( "indexes must be a list of 3 integers [start, end, step]") indexes = [int(idx) for idx in sorted(set(indexes))] assert indexes[0] >= 0, Logger.error( "indexes start must be positive") self.indexes = indexes # check pdb file try: fd = open(pdb, 'r') except: raise Logger.error("cannot open pdb file") else: fd.close() self.pdb = pdb # check dcd file try: fd = open(dcd, 'r') except: raise Logger.error("cannot open dcd file") else: fd.close() self.dcd = dcd # create trajectory self.trajectory = None
def status(self, step, logFrequency = 10): """ This method is used to log analysis status.\n :Parameters: #. step (int): The current step number #. logFrequency (float): the frequency of status logging. its a percent number. """ if not step: Logger.info("%s --> analysis started %s steps to go" %(self.__class__.__name__, self.numberOfSteps)) elif step == self.numberOfSteps: Logger.info("%s --> analysis steps finished" %(self.__class__.__name__)) else: actualPercent = int( float(step)/float(self.numberOfSteps)*100) previousPercent = int(float(step-1)/float(self.numberOfSteps)*100) if actualPercent/logFrequency != previousPercent/logFrequency: Logger.info("%s --> %s%% completed. %s left out of %s" %(self.__class__.__name__, actualPercent, self.numberOfSteps-step, self.numberOfSteps))
def finalize(self): """ called once all the steps has been run.\n """ # self.hbonds = [[[hIdx, shellIdx, shellTimeLimitsIdx, accIdx],[hIdx, shellIdx, shellTimeLimitsIdx,accIdx],...], ... ] # ............first bond first shell..........,............first bond second shell2.......,.... # ........................................first bond..........................................., .... second bond ... Logger.info("%s --> parsing and creating hydrogen bonds" % (self.__class__.__name__)) self.hbonds = [[]] def create_hbonds(): for bond in self.hbonds: if not len(bond): continue # check all bond time threshold if self.time[bond[-1][2][1]] - self.time[ bond[0][2][0]] < self.thresholdTime: continue if self.bondStartAtCore and bond[0][1]: continue self.results['hbonds_time'][bond[-1][2][1] - bond[0][2][0]] += 1 self.results['number_of_hbonds'][ bond[0][2][0]:bond[-1][2][1]] += 1 for shell in bond: hIdx = shell[0] shellIdx = shell[1] shellTimeIdx = shell[2] shellKey = self.shellsResultKeys[shellIdx] time = shellTimeIdx[1] - shellTimeIdx[0] # append 1 to hbonds time self.results['hbonds_%s_time' % shellKey][time] += 1 # update number of hbonds self.results['number_of_hbonds_%s' % shellKey][shellTimeIdx[0]:shellTimeIdx[1] + 1] += 1 # calculate bond lengths histogram hist, _ = np.histogram( self.bondsDistances[hIdx, shellTimeIdx[0]:shellTimeIdx[1] + 1], self.bins) self.results['hbonds_%s_distribution' % shellKey] += hist def add_hbond(hIdx, shellIdx, shellTimeIdx, thisAcceptor, breakBond=False, debugMessage=""): if not (shellTimeIdx[0] is None) and not (shellTimeIdx[1] is None): #if not (self.time[shellTimeIdx[1]]-self.time[shellTimeIdx[0]]<=self.hbondAllShellsTime[shellIdx]): # print debugMessage # print "last shell index: %s"%str(lastShellIdx) # print "this shell index: %s"%str(thisShellIdx) # print "saving shell index: %s"%str(shellIdx) # print "stayed between %s"%str(shellTimeIdx) # print "total time of %s while allowed time is %s"%(str(self.time[timeIdx]-self.time[shellTimeIdx[0]]), str(self.hbondAllShellsTime[shellIdx])) # print '\n' # first or new hbond added to the same hydrogen atom if not len(self.hbonds[-1]): self.hbonds[-1].append( [hIdx, shellIdx, shellTimeIdx, thisAcceptor]) # new hydrogen index elif self.hbonds[-1][-1][0] != hIdx: self.hbonds.append( [[hIdx, shellIdx, shellTimeIdx, thisAcceptor]]) # new acceptor elif self.hbonds[-1][-1][3] != thisAcceptor: self.hbonds.append( [[hIdx, shellIdx, shellTimeIdx, thisAcceptor]]) # not continuous shellTimeIdx elif self.hbonds[-1][-1][2][1] + 1 != shellTimeIdx[0]: self.hbonds.append( [[hIdx, shellIdx, shellTimeIdx, thisAcceptor]]) else: self.hbonds[-1].append( [hIdx, shellIdx, shellTimeIdx, thisAcceptor]) if breakBond: self.hbonds.append([]) def reset_shellTimeIdx_lowerAngleTime(thisDistance, thisAngle, thisTime): if self.bondStartAtCore and thisDistance > self.bondLength: shellTimeIdx = [None, None] lowerAngleTime = [None, None] elif self.bondStartWithinAngle and ( thisAngle < self.bondAngleLimits[0] or thisAngle > self.bondAngleLimits[1]): shellTimeIdx = [None, None] lowerAngleTime = [None, None] else: shellTimeIdx = [timeIdx, timeIdx] # update bond angle time if thisAngle < self.bondAngleLimits[ 0] or thisAngle > self.bondAngleLimits[1]: if lowerAngleTime[0] is None: lowerAngleTime = [thisTime, thisTime] else: lowerAngleTime[1] = thisTime else: lowerAngleTime = [None, None] return shellTimeIdx, lowerAngleTime # create hydrogen bonds for hIdx in range(len(self.hydrogenAtomsIndexes)): # create shellsIndexes list shellsIndexes = [] for timeIdx in range(len(self.configurationsIndexes)): thisDistance = self.bondsDistances[hIdx, timeIdx] if thisDistance == -1: shellsIndexes.append(-1) else: indexes = [ idx for idx in range(len(self.cumsumhbondAllShells)) if thisDistance <= self.cumsumhbondAllShells[idx] ] shellIdx = indexes[0] shellsIndexes.append(shellIdx) # remove hfjumps if self.smoothHfJumps and len(shellsIndexes) >= 3: for timeIdx in range(1, len(shellsIndexes) - 1): if self.bondsDistances[hIdx, timeIdx] == -1: continue if shellsIndexes[timeIdx - 1] == shellsIndexes[timeIdx + 1]: shellsIndexes[timeIdx] = shellsIndexes[timeIdx - 1] self.bondsDistances[hIdx, timeIdx] = ( self.bondsDistances[hIdx, timeIdx - 1] + self.bondsDistances[hIdx, timeIdx + 1]) / 2. if self.acceptorsIndex[hIdx, timeIdx - 1] == self.acceptorsIndex[hIdx, timeIdx + 1]: self.acceptorsIndex[ hIdx, timeIdx] = self.acceptorsIndex[hIdx, timeIdx - 1] # create hbonds shellTimeIdx = [None, None] lowerAngleTime = [None, None] for timeIdx in range(len(self.configurationsIndexes)): # get bond information thisShellIdx = shellsIndexes[timeIdx] thisAcceptor = self.acceptorsIndex[hIdx, timeIdx] thisAngle = self.bondsAngles[hIdx, timeIdx] thisTime = self.time[timeIdx] if timeIdx == 0: lastShellIdx = thisShellIdx lastAcceptor = thisAcceptor else: lastAcceptor = self.acceptorsIndex[hIdx, timeIdx - 1] lastShellIdx = shellsIndexes[timeIdx - 1] ################################################################################################# ########################################## checking bond ######################################## # check shell idx whether there is a bond or not if thisShellIdx == -1: # add all valid bonds add_hbond(hIdx, lastShellIdx, shellTimeIdx, thisAcceptor, breakBond=True, debugMessage="no bond found") # reset parameters shellTimeIdx = [None, None] lowerAngleTime = [None, None] continue # new bond or after non-bond thisShellIdx = -1 if shellTimeIdx[0] is None: shellTimeIdx, lowerAngleTime = reset_shellTimeIdx_lowerAngleTime( thisDistance, thisAngle, thisTime) continue # check acceptors and break bond if thisAcceptor != lastAcceptor: # add all valid bonds add_hbond(hIdx, lastShellIdx, shellTimeIdx, thisAcceptor, breakBond=True, debugMessage="different acceptor") # reset parameters shellTimeIdx, lowerAngleTime = reset_shellTimeIdx_lowerAngleTime( thisDistance, thisAngle, thisTime) continue # check bondAngle and break bond if thisAngle < self.bondAngleLimits[ 0] or thisAngle > self.bondAngleLimits[1]: if (lowerAngleTime[0] is not None): if (thisTime - lowerAngleTime[0] ) > self.belowAngleToleranceTime: # add all valid bonds add_hbond(hIdx, lastShellIdx, shellTimeIdx, thisAcceptor, breakBond=True, debugMessage="angle time") # reset parameters shellTimeIdx = [None, None] lowerAngleTime = [None, None] continue else: lowerAngleTime[1] = thisTime else: lowerAngleTime = [thisTime, thisTime] else: lowerAngleTime = [None, None] # Bond change shell if thisShellIdx != lastShellIdx: # add all valid bonds add_hbond(hIdx, lastShellIdx, shellTimeIdx, thisAcceptor, breakBond=False, debugMessage="jump to another shell") # reset parameters shellTimeIdx = [timeIdx, timeIdx] continue # bond stay in same shell, check tolerance time elif thisTime - self.time[shellTimeIdx[ 0]] <= self.hbondAllShellsTime[thisShellIdx]: shellTimeIdx[1] = timeIdx continue # bond break because of tolerance time in outer shell else: # add all valid bonds add_hbond(hIdx, lastShellIdx, shellTimeIdx, thisAcceptor, breakBond=True, debugMessage="tolerance time violated") # reset parameters shellTimeIdx = [None, None] lowerAngleTime = [None, None] continue # final hbonds in hIdx add_hbond(hIdx, lastShellIdx, shellTimeIdx, thisAcceptor, breakBond=False) # create all registered hbond create_hbonds() # normalize and create the total for shellIdx in range(len(self.shellsResultKeys)): shellKey = self.shellsResultKeys[shellIdx] self.results['hbonds_%s_distribution' % shellKey] /= len( self.configurationsIndexes) self.results['hbonds_distribution'] += self.results[ 'hbonds_%s_distribution' % shellKey] # Hydrogen bonds mean life time nonzero = list(np.where(self.results['hbonds_time'])[0]) nHbonds = [self.results['hbonds_time'][idx] for idx in nonzero] times = [self.results['time'][idx] for idx in nonzero] times = [times[idx] * nHbonds[idx] for idx in range(len(times))] if len(times): self.results['hBond_mean_life_time'] = np.array([np.sum(times) ]) / len(times) else: self.results['hBond_mean_life_time'] = np.array([0.0])
# create simulation sim = Simulation(pdb, logStatus = True, logExport = False, numberOfSteps = 100, outputFrequency = 1, exportInitialConfiguration = True, outputPath = tempfile.mktemp(".xyz")) # remove all bonded and non bonded interactions except dihedrals sim.bonds_indexes = [] sim.angles_indexes = [] sim.lennardJones_eps *= 0 sim.atomsCharge *= 0 # initial parameters sim.__DIHEDRAL__["c c c c"] = {1.0: {'delta': 40.0, 'n': 1.0, 'kchi': 3.6375696}} sim.set_dihedrals_parameters() Logger.info("minimizing %s steps at %s fm per step, with all terms suppressed but dihedral %s" % (sim.numberOfSteps, sim.timeStep, sim.__DIHEDRAL__["c c c c"]) ) sim.minimize_steepest_descent() sim.exportInitialConfiguration = False # initial parameters sim.__DIHEDRAL__["c c c c"] = {1.0: {'delta': 120.0, 'n': 1.0, 'kchi': 3.6375696}} sim.set_dihedrals_parameters() Logger.info("minimizing %s steps at %s fm per step, with all terms suppressed but dihedral %s" % (sim.numberOfSteps, sim.timeStep, sim.__DIHEDRAL__["c c c c"]) ) sim.minimize_steepest_descent() # sim.__DIHEDRAL__["c c c c"] = {1.0: {'delta': 0.0, 'n': 1.0, 'kchi': 3.6375696}, 2.0: {'delta': 180.0, 'n': 2.0, 'kchi': -0.328444}, 3.0: {'delta': 0.0, 'n': 3.0, 'kchi': 0.5832496}} # sim.set_dihedrals_parameters() # Logger.info("minimizing %s steps at %s fm per step, with all terms suppressed but dihedral %s" % (sim.numberOfSteps, sim.stepTime, sim.__DIHEDRAL__["c c c c"]) ) # sim.minimize_steepest_descent(200)
In this test, an SDS molecule is loaded several records manipulations, translation, rotation, orientation, ... are tested """ # standard distribution imports from __future__ import print_function import os # pdbparser imports from pdbparser.Utilities.Collection import get_path from pdbparser.log import Logger from pdbparser.pdbparser import pdbparser from pdbparser.Utilities.Geometry import * pdbRESULT = pdbparser() Logger.info("loading sds molecule ...") pdbSDS = pdbparser(os.path.join(get_path("pdbparser"), "Data", "SDS.pdb")) INDEXES = range(len(pdbSDS.records)) # get molecule axis sdsAxis = get_axis(INDEXES, pdbSDS) ## translate to positive quadrant atomToOriginIndex = get_closest_to_origin(INDEXES, pdbSDS) atom = pdbSDS.records[atomToOriginIndex] [minX, minY, minZ] = [atom['coordinates_x'], atom['coordinates_y'], atom['coordinates_z']] translate(INDEXES, pdbSDS, [-1.1 * minX, -1.1 * minY, -1.1 * minZ]) Logger.info("orient molecule along [1,0,0] ...") orient(axis=[1, 0, 0], indexes=INDEXES, pdb=pdbSDS, records_axis=sdsAxis) sdsAxis = [1, 0, 0] pdbRESULT.concatenate(pdbSDS)
# initial parameters sim.bonds_indexes = [] sim.nBondsThreshold = [[] for ids in pdb.indexes] sim.angles_indexes = [] sim.dihedrals_indexes = [] sim.atomsCharge *= 0 # minimize energy #Logger.info("minimization at %s fm per step" % (sim.timeStep) ) #sim.outputFrequency = 1 #sim.minimize_steepest_descent(99) # equilibration sim.exportInitialConfiguration = True sim.outputFrequency = 1 sim.logExport = True sim.timeStep = 0.1 Logger.info("equilibration at %s fm per step" % (sim.timeStep)) sim.simulate(100) # production sim.exportInitialConfiguration = False sim.outputFrequency = 1 sim.logExport = True sim.timeStep = 1 Logger.info("production at %s fm per step" % (sim.timeStep)) sim.simulate(3000, initializeVelocities=False) # visualize molecule sim.visualize_trajectory(sim.outputPath)
pdb1.records = [at1, at2] # create simulation sim = Simulation(pdb1, logStatus = False, logExport = False, stepTime = 0.2, numberOfSteps = 10, outputFrequency = 1, exportInitialConfiguration = True, outputPath = tempfile.mktemp(".xyz")) # remove all bonded interactions sim.bonds_indexes = [] sim.angles_indexes = [] sim.dihedrals_indexes = [] sim.nBondsThreshold = [[],[]] # setting charges to 0 sim.atomsCharge = [0,0] # initial parameters Logger.info("minimizing %s steps at %s fm per step, with atoms charge %s, VDW forces push atoms to equilibrium distance %s" % (sim.numberOfSteps, sim.timeStep, sim.atomsCharge, 2*sim.__LJ__['h']['rmin/2']) ) sim.minimize_steepest_descent() # add charges and change stepTime sim.atomsCharge = [0.15,0.15] sim.stepTime = 0.02 sim.exportInitialConfiguration = False # re-minimize parameters Logger.info("minimizing %s steps at %s fm per step, with atoms charge %s, VDW forces push atoms to equilibrium distance %s" % (sim.numberOfSteps, sim.timeStep, sim.atomsCharge, 2*sim.__LJ__['h']['rmin/2']) ) sim.minimize_steepest_descent() # add charges and change stepTime sim.atomsCharge = [-0.15,0.15] # # # re-minimize parameters
# pdbparser imports from pdbparser.Utilities.Collection import get_path from pdbparser import pdbparser from pdbparser.log import Logger from pdbparser.Utilities.Construct import AmorphousSystem, Micelle from pdbparser.Utilities.Geometry import get_satisfactory_records_indexes, translate from pdbparser.Utilities.Modify import delete_records_and_models_records from pdbparser.Utilities.Database import __WATER__ # create pdbWATER pdbWATER = pdbparser() pdbWATER.records = __WATER__ pdbWATER.set_name("water") Logger.info("Create water box") pdbWATER = AmorphousSystem(pdbWATER, density = 0.5).construct().get_pdb() pdbWATERhollow = pdbWATER.get_copy() # make sphere Logger.info("Create a water sphere of 15A radius") sphereIndexes = get_satisfactory_records_indexes(pdbWATER.indexes, pdbWATER, "np.sqrt(x**2 + y**2 + z**2) >= 15") delete_records_and_models_records(sphereIndexes, pdbWATER) # make hollow Logger.info("Remove a water sphere of 15A radius") hollowIndexes = get_satisfactory_records_indexes(pdbWATERhollow.indexes, pdbWATERhollow, "np.sqrt(x**2 + y**2 + z**2) <= 15") delete_records_and_models_records(hollowIndexes, pdbWATERhollow) # translate hollow translate(pdbWATERhollow.indexes, pdbWATERhollow, vector =[60,0,0])
""" Construct a graphene sheet in two orientations """ from __future__ import print_function from pdbparser.log import Logger from pdbparser import pdbparser from pdbparser.Utilities.Geometry import translate from pdbparser.Utilities.Construct import Sheet, Nanotube, MultipleWallNanotube Logger.info("Constructing arm-chair sheet") pdbGS_armchair = Sheet().construct().get_pdb() Logger.info("Constructing zig-zag sheet") pdbGS_zigzag = Sheet(orientation = "zigzag").construct().pdb translate(pdbGS_zigzag.indexes, pdbGS_zigzag, vector = [0,0,10]) Logger.info("Constructing carbon nanotube from scratch") pdbCNT1 = Sheet(orientation = "zigzag").construct().wrap().get_pdb() translate(pdbCNT1.indexes, pdbCNT1, vector = [0,40,30]) Logger.info("constructing nanotube using appropriate class") pdbCNT2 = Nanotube().construct().get_pdb() translate(pdbCNT2.indexes, pdbCNT2, vector = [0,10,30]) Logger.info("constructing 5 walls multi-walled nanotube") pdbMWNT = MultipleWallNanotube(wallsNumber = 5, orientation = ["armchair", "zig-zag","zig-zag","zig-zag","armchair"]).construct().get_pdb() translate(pdbMWNT.indexes, pdbMWNT, vector = [0,25,-40]) pdbALL = pdbGS_armchair pdbALL.concatenate(pdbGS_zigzag)
import os import numpy as np from pdbparser.log import Logger from pdbparser import pdbparser from pdbparser.Utilities.Collection import get_path from pdbparser.Utilities.Selection import NanotubeSelection from pdbparser.Utilities.Information import get_models_records_indexes_by_records_indexes, get_records_indexes_in_attribute_values from pdbparser.Utilities.Modify import * from pdbparser.Utilities.Geometry import get_principal_axis, translate, orient # read pdb pdbCNT = pdbparser( os.path.join(get_path("pdbparser"), "Data/nanotubeWaterNAGMA.pdb")) Logger.info("Define models") # define models define_models_by_records_attribute_value(pdbCNT.indexes, pdbCNT) Logger.info("Getting nanotube indexes") # get CNT indexes cntIndexes = get_records_indexes_in_attribute_values(pdbCNT.indexes, pdbCNT, "residue_name", "CNT") Logger.info("Create selection") # create selection sel = NanotubeSelection(pdbCNT, nanotubeIndexes=cntIndexes).select() Logger.info("Get models inside nanotube") # construct models out of residues indexes = get_models_records_indexes_by_records_indexes(