コード例 #1
0
ファイル: Spidroin.py プロジェクト: cjforman/vesiform
    def initialiseParameters(self):
        BBG.initialiseParameters(self)

        self.numResiduesAlphaHelix = self.getParam('numResiduesAlphaHelix')
        self.lengthPerResidueAlpha = self.getParam('lengthPerResidueAlpha')
        self.lengthPerResidueBeta = self.getParam('lengthPerResidueBeta')
        self.terminiSeparation = self.getParam('terminiSeparation')
        self.numBetaSheets = self.getParam('numBetaSheets')
        self.numBetaStrands = self.getParam('numBetaStrands')
        self.betaStrandLength = self.getParam('betaStrandLength')
        self.betaSheetRx = self.getParam('betaSheetRx')
        self.betaSheetRy = self.getParam('betaSheetRy')
        self.betaSheetRz = self.getParam('betaSheetRz')
        self.alphaBetaSeparation = self.getParam('alphaBetaSeparation')
        self.alphaHelixAtomName = self.getParam('alphaHelixAtomName')
        self.betaStrandAtomName = self.getParam('betaStrandAtomName')
        self.coilAtomName = self.getParam('coilAtomName')

        self.BSG = BSG(self.paramFilename)
        self.AHG = PBG(self.paramFilename)
        self.PHG = PHG(self.paramFilename)
        self.USP = NBB(self.paramFilename)
        self.SPEBBG = SPEBBG(self.paramFilename)

        if self.noLoadErrors == False:
            print "Critical Parameters are undefined for Spidroin Object"
            sys.exit()
コード例 #2
0
 def initialiseParameters(self):
     # initialise the constrained polymer parent
     CPBBG.initialiseParameters(self)
     
     # load the backbone building object
     self.PBG = PBG(self.paramFilename)
     
     if self.noLoadErrors == False:            
         print "Critical Parameters are undefined for hairpin"
         sys.exit()        
コード例 #3
0
ファイル: betasheet2.py プロジェクト: cjforman/vesiform
    def generateBuildingBlockXYZ(self):

        # create a building block generator using the standard parameter file for this object
        strandGen = PBG(self.paramFilename)

        # construct a prototype beta strand building block
        strandBB = strandGen.generateBuildingBlock(self.strandLength)

        # generate an array of strand building blocks
        BBs = [
            strandBB.cloneBuildingBlock() for _ in range(0, self.numStrands)
        ]
        baseLine = [
            self.startPos +
            n * self.betaStrandSeparation * self.crossStrandDirectorHat
            for n in range(self.numStrands)
        ]
        directors = [self.inStrandDirectorHat for n in range(self.numStrands)]
        rotation = [0.0 for n in range(self.numStrands)]

        # modify the strands if we are anti-parallel
        if not self.parallel:
            baseLine = [
                basePoint if n % 2 == 0 else basePoint + self.offsetXYZ
                for n, basePoint in enumerate(baseLine)
            ]
            directors = [
                self.inStrandDirectorHat if n % 2 == 0 else -1 *
                self.inStrandDirectorHat for n in range(self.numStrands)
            ]
            rotation = [
                rot if n % 2 == 0 else 0 for n, rot in enumerate(rotation)
            ]

        # do the sheet construction:
        [
            BB.transformBBToLabFrame(director, pos,
                                     rot) for director, pos, rot, BB in zip(
                                         directors, baseLine, rotation, BBs)
        ]

        # if we are adding loops then construct the loops
        if self.numLoopResidues > 0:
            Loops = self.constructLoops(BBs)

        # compile the final building block
        retBB = BBs[0]
        if self.numLoopResidues > 0:
            for BB, Loop in zip(BBs[1:], Loops):
                retBB.append(Loop)
                retBB.append(BB)
        else:
            [retBB.append(BB) for BB in BBs[1:]]

        return retBB.blockXYZVals
コード例 #4
0
ファイル: peptideHairpin5.py プロジェクト: cjforman/vesiform
    def initialiseParameters(self):
        # initialise the constrained polymer parent
        CPBBG.initialiseParameters(self)

        self.distEpsilon = self.getParam("distEpsilon")
        self.maxNumConnectingMoves = self.getParam("maxNumConnectingMoves")
        self.springConstant = self.getParam("springConstant")
        self.connectingTemp = self.getParam("connectingTemp")

        # load the backbone building object
        self.PBG = PBG(self.paramFilename)

        if self.noLoadErrors == False:
            print "Critical Parameters are undefined for hairpin"
            sys.exit()
コード例 #5
0
        
        return names

    def generateBuildingBlockConnectors(self):
        # N connector first, then C Connector 
        return [ [2, 1, 0], [self.numPoints-3, self.numPoints-2, self.numPoints-1] ]
        
if __name__ == "__main__":
    
    
    # get the file name from the command line
    filename = sys.argv[1]

    # create the generator objects.
    hairPinGen = peptideHairpinGenerator(filename)
    backboneGenerator = PBG(filename)
    
    # generate 1 residue seed building block
    seedResidue = backboneGenerator.generateBuildingBlock(1)
    
    # generate starting points and move the seed to those points extracting
    # the xyzVals each time. 
    numResidues = 20
    pointA = np.array([10.0, 10.0, 10.0])
    pointB = np.array([0.0, 0.0, 0.0])
    
    print "Estimate min num residues: ", np.linalg.norm(pointA-pointB)/3.5
    
    seedResidue.placeAtom(2, pointA)
    seedResidue.setBlockRefPoint(pointA)
    seedResidue.orientToDirector(np.array([-1.0, 1.0, 0.0]))
コード例 #6
0
def decoratePolymerBackbone(brushDictList, backboneInfo): 

    # unpack input
    backboneXYZ = backboneInfo[0]
    backboneNames = backboneInfo[1]
    backboneSegmentLengths = backboneInfo[2]
    backboneTNBList = backboneInfo[3]

    # break the list of XYZ points into list of points for each segment
    backBoneXYZList = breakListToSubList(backboneXYZ, np.cumsum(np.concatenate((np.array([0]), backboneSegmentLengths), 0)))

    # set up output
    polymerXYZ = cp.copy(backboneXYZ)
    polymerNames = cp.copy(backboneNames)
    
    for brush, numBrushes, TNB, points in zip(brushDictList, backboneSegmentLengths, backboneTNBList, backBoneXYZList):
        if brush['numMonomers']>0:
            # create the brush generator. Default is polymer. Check to see if we want a peptide brush 
            if 'Peptide' in brush['mode']:
                brushBBG = PBG(brush['filename'])
                brushBB = brushBBG.generateBuildingBlock(brush['numMonomers']) # only need to create this once for peptide backbones as they are either alpha or beta.
                brushBB.blockAtomNames = brush['monomerNames']
            else:
                brushBBG = RPPBBG(brush['filename'])
        
            # Set the angle of each brush around the segment director defined relative to the Binormal in the TNB frame for that polymer.
            # The range of angles is defined in the dictionary.
            brushPhaseAngles = [ rnd.uniform(0, brush['phaseRange'] * np.pi/180.0) for _ in range(0, numBrushes) ]

            # if the word Alternate is in the mode than add 180 to every other phase        
            if "Alternate" in brush['mode']:
                for index in range(0, numBrushes):
                    if index % 2 ==0:
                        brushPhaseAngles[index] += np.pi
            
            # if the word "mirror" is in the mode then add 180 randomly to half the brush phases 
            if "Mirror" in brush['mode']:
                numFlipped = 0
                indexList = list(range(0, numBrushes))
                while numFlipped < numBrushes/2:
                    index = rnd.choice(indexList)
                    brushPhaseAngles[index] += np.pi
                    numFlipped += 1
                    indexList.remove(index)    
        
            # generate directors in direction of phase angles
            brushDirectors = [ np.cos(angle) * TNB[2] + np.sin(angle) * TNB[1] for angle in brushPhaseAngles] 
            brushDirectorsNorm = [ d/np.linalg.norm(d) for d in brushDirectors]
    
            # for each of the points in the backbone generate a brush as defined    
            for point, director in zip(points, brushDirectorsNorm):
                if "Polymer" in brush['mode'] and not "Peptide" in brush['mode']:
                    # if we're doing a polymer then generate a new polymer with the given polymer parameters for each pass.
                    polyStart = np.array([ 0.0, 0.0, brush['Z1']])
                    envelopeList = ['frustum ' + str(brush['Z1'] - brush['minDist']) + ' ' + str(brush['R1']) + ' ' + str(brush['Z2']) + ' ' + str(brush['R2'])]
                
                    brushBB = brushBBG.generateBuildingBlock( brush['numMonomers'],
                                                              polyStart,
                                                              brush['alpha1'],
                                                              brush['alpha2'],
                                                              brush['beta1'],
                                                              brush['beta2'],
                                                              brush['minDist'],
                                                              brush['bondLength'],
                                                              envelopeList=envelopeList,
                                                              visualiseEnvelope=(0, 100, brush['name'] + '_envelope.xyz'))
                    # work out the block director
                    if brush['numMonomers']>2:
                        blockDirector = coords.axisFromHelix(brushBB.blockXYZVals)
                    else:
                        if brush['numMonomers']==2:
                            blockDirector = brushBB.blockXYZVals[1] - brushBB.blockXYZVals[0]
                            blockDirector = blockDirector/np.linalg.norm(blockDirector)
                        if brush['numMonomers']==1:
                            blockDirector = np.array([0.0, 0.0, 1.0])
    
                    # rotate the brush and set it at the right place
                    brushXYZVals = coords.transformFromBlockFrameToLabFrame(director, point + brush['bondLength'] * director, 0.0, blockDirector, brushBB.blockXYZVals[0], brushBB.blockXYZVals)
            
                    # concatenate the brush positions and the brush names to the output arrays
                    polymerXYZ = np.concatenate( (polymerXYZ, brushXYZVals), 0)
                    polymerNames = np.concatenate( (polymerNames, brush['monomerNames']), 0)
        
    return polymerXYZ, polymerNames 
コード例 #7
0
                # then throw a wobbly.
                if np.linalg.norm((zPos - pos)) <= self.minDist:
                    inBounds= False
                    if self.verbose==1: 
                        print("Packing violation")

        return inBounds
        
        
if __name__ == '__main__':
    
    # get the file name from the command line
    filename = sys.argv[1]

    # create a beta backbone generator object using static file parameters
    backboneObject = PBG(filename)

    # generate backbone realtime parameters
    numPos = 3* 8
    startPos = np.array([0.0, 0.0, 0.0])
    director = np.array([0.0, 0.0, 1.0])
    rotation = 0 * np.pi/180
    offset =  np.array([4.8, 0.0, 0.0])
    polarity = 'CN'
    
    backBoneBuildingBlock1 = backboneObject.generateBuildingBlock(numPos, polarity) 
    backBoneBuildingBlock1.transformFromBlockFrameToLabFrame(director, startPos, rotation)
    backBoneBuildingBlock1.exportBBK("backbone1")
    backBoneBuildingBlock2 = backboneObject.generateBuildingBlock(numPos, polarity) 
    backBoneBuildingBlock2.transformFromBlockFrameToLabFrame(director, startPos + offset, rotation)
    backBoneBuildingBlock2.exportBBK("backbone2")
コード例 #8
0
    def exportBBK(self, fileroot):
        fIO.saveXYZList(self.blockXYZVals, self.blockAtomNames, fileroot + '.xyz')
        line1 = "floatlist blockRefPoint " + str(self.blockRefPoint[0]) + " " + str(self.blockRefPoint[1]) + " " + str(self.blockRefPoint[2]) + "\n"
        line2 = "floatlist blockOrientation " + str(self.blockDirectorHat[0]) + " " + str(self.blockDirectorHat[1]) + " " + str(self.blockDirectorHat[2]) + "\n"
        lines = "intlist blockConnectors" 
        for connection in self.blockConnectors:
            lines += " " + str(connection[0]) + " " + str(connection[1]) + " " + str(connection[2])
        lines +='\n'
        fIO.writeTextFile([line1, line2, lines], fileroot + '.bbk')

if __name__=="__main__":

    from Library.peptideBackbone import peptideBackboneGenerator as PBG
        
    # set up an alpha helix generator object using the alphaHelix parameters
    helixGenerator = PBG("alphaHelix.txt")
     
    # specify the desired location and orientations of two specific helices
    numResidues = 16
    refPoint1 = np.array([0.0, 0.0, 0.0])
    director1 = np.array([0.0, 0.0, 1.0])
    refPoint2 = np.array([20.0, 0.0, 0.0])
    director2 = np.array([1.0, 0.0, 1.0])
    
    # generate helix1 using the generator function 
    helix1 = helixGenerator.generateBuildingBlock(numResidues, showBlockDirector=False)
    helix1.transformBBToLabFrame(director1, refPoint1, 0)
    
    # generate helix 2 using the generator function
    helix2 = helixGenerator.generateBuildingBlock(numResidues, showBlockDirector=False)
    helix2.transformBBToLabFrame(director2, refPoint2, 0)
コード例 #9
0
ファイル: peptideVesicle.py プロジェクト: cjforman/vesiform
import numpy as np
from Library.peptideBackbone import peptideBackboneGenerator as PBG
from Library.SurfacePackSphere import SurfacePackSphereBBG as SPSBBG
from Library.VolumePackEllipsoid import VolumePackEllipsoidBBG as VPEBBG
import Utilities.fileIO as fIO
peptideBBG = PBG('betastrand.txt')
sphereBBG = SPSBBG('SurfacePackSphere.txt')
VolSphereBBG = VPEBBG('VolumePackEllipsoid.txt')

numResidues = 5
minDist = 1.0

numStrands = 100
centerPos = np.array([-0,-0, -0])
director = np.array([0, 0, 1])
rotation = 0
radius1 = 22
radius2 = 12
radius3 = 8
theta1 = -90
theta2 = 90
phi1 = -135
phi2 = 135
minDist1 = 3.0
minDist2 = 1.0
minDist3 = 1.0

# generate the XYZVals in the packed spaced
SphereBB = sphereBBG.generateBuildingBlock(numStrands, radius1, theta1, theta2, phi1, phi2, minDist1)
SphereBB.transformBBToLabFrame(director, centerPos, rotation)
SphereBB.exportBBK("sphereBasePoints")
コード例 #10
0
ファイル: PolymerBrushFull.py プロジェクト: cjforman/vesiform
def GeneralPolymerBrush(brushDict, mode="RandomPolymer"):

    # unpack the brush dictionary
    
    
    
    
    
    
    filenameRandom = brushDict['filenameBlock']
    filenameBrush = brushDict['filenameBrush']
    mode = brushDict['mode']
    
    ABlock = brushDict['ABlock']
    num_A = ABlock['num'] 
    alpha1_A = ABlock['alpha1']
    alpha2_A = ABlock['alpha2'] 
    beta1_A = ABlock['beta1'] 
    beta2_A = ABlock['beta2'] 
    minDist_A = ABlock['minDist'] 
    bondLength_A = ABlock['bondLength']
    Z1_A = ABlock['Z1'] 
    R1_A = ABlock['R1'] 
    Z2_A = ABlock['Z2'] 
    R2_A = ABlock['R2'] 
    
    BBlock = brushDict['BBlock']
    num_B = BBlock['num'] 
    alpha1_B = BBlock['alpha1']
    alpha2_B = BBlock['alpha2'] 
    beta1_B = BBlock['beta1'] 
    beta2_B = BBlock['beta2'] 
    minDist_B = BBlock['minDist'] 
    bondLength_B = BBlock['bondLength']
    Z1_B = BBlock['Z1'] 
    R1_B = BBlock['R1'] 
    Z2_B = BBlock['Z2'] 
    R2_B = BBlock['R2']
    
    brushBlock = brushDict['brushBlock']
    num_brush = brushBlock['num'] 
    alpha1_brush = brushBlock['alpha1']
    alpha2_brush = brushBlock['alpha2'] 
    beta1_brush = brushBlock['beta1'] 
    beta2_brush = brushBlock['beta2'] 
    minDist_brush = brushBlock['minDist'] 
    bondLength_brush = brushBlock['bondLength']
    Z1_brush = brushBlock['Z1'] 
    R1_brush = brushBlock['R1'] 
    Z2_brush = brushBlock['Z2'] 
    R2_brush = brushBlock['R2']
    

    # Mode word must specify one of Polymer or Peptide.  Can also include modifiers Sheet or Random to specify phase of brushes around polymer backbone axis.
    # defaults to RandomPolymer.  Can supply brush polymer parameters via parameter polymer params. These are alpha1, alpha2, beta1, beta2, minDist and bond length. 
    # atom name supplied in filenameBrush.  This is a mess. I know. I don't care.  
    
    # if one of Peptide or Polymer is not in mode then add Polymer to the end of mode. Anything else is dandy. If you specify both peptide and polymer, then Peptide will override.
    if not ("Peptide" in mode or "Polymer" in mode):
        mode = mode + "Polymer"
    
    # generate the block Copolymer backbone
    (polymerXyzVals, polymerNames) = MBCP(num_A, num_B,   Z1_A, R1_A, Z2_A, R2_A, alpha1_A, alpha2_A, beta1_A, beta2_A, minDist_A, bondLength_A, 
                                                        Z1_B, R1_B, Z2_B, R2_B, alpha1_B, alpha2_B, beta1_B, beta2_B, minDist_B, bondLength_B, filenameRandom)
    
    # get axis of block A
    BlockAAxis = coords.axisFromHelix(polymerXyzVals[0:num_A])
    BlockAAxisNorm = BlockAAxis/np.linalg.norm(BlockAAxis) 
    
    # get an orthogonal vector to BlockAAxis which is random. 
    randDirXYZ = BlockAAxis
    randXYZIsAxizXYZ = True
    
    while randXYZIsAxizXYZ: 
        randVecDir = coords.pickRandomPointOnUnitSphere()
        randDirXYZ = coords.sphericalPolar2XYZ(np.array([1.0, randVecDir[0], randVecDir[1]]))
        randXYZIsAxizXYZ = not False in [ np.abs(a - b) < 1e-7 for a, b in zip(randDirXYZ, BlockAAxis) ]
        
    OrthVec = randDirXYZ - np.dot(BlockAAxisNorm, randDirXYZ) * BlockAAxisNorm
    OrthVec1Norm = OrthVec/np.linalg.norm(OrthVec) 
    OrthVec2Norm  = np.cross(OrthVec1Norm, BlockAAxisNorm)

    # now have orthonormal basis for the polymer backbone for the brush part of system 
    
    # create the brush generator. Default is polymer mode. If peptide is included in mode word then over ride to use peptide instead 
    if "Peptide" in mode:
        # create a peptide generator using supplied filename to specify parameters of peptide - filename overides polymerParams
        brushGenerator = PBG(filenameBrush)
        brushObject = brushGenerator.generateBuildingBlock(num_brush) # only need to create this once for peptides as all are the same
    else:
        brushGenerator = RPPBBG(filenameBrush)
    
    # choose the phase angles of each brush
    # initially make the phase angle a little bit random
    brushPhaseAngles = [ rnd.uniform(0, 0.2 * np.pi) for _ in range(0, num_A) ]

    # if Random is in mode then make it very random
    if "Random" in mode:
        brushPhaseAngles = [ rnd.uniform(0, 2 * np.pi) for _ in range(0, num_A) ] 
    
    # if sheet is in mode then make phase zero.
    if "Sheet" in mode:
        brushPhaseAngles = [ 0.0 for _ in range(0, num_A) ]

    # generate directors in direction of phase angles
    brushDirectors = [ np.cos(angle) * OrthVec1Norm + np.sin(angle) * OrthVec2Norm for angle in brushPhaseAngles] 
    brushDirectorsNorm = [ d/np.linalg.norm(d) for d in brushDirectors]

    # for each of the directors (defined by the length of block A) figure out the final xyz vals    
    for point, labDirector in zip(polymerXyzVals[0:num_A], brushDirectorsNorm):
        if "Polymer" in mode and not "Peptide" in mode:
            # if we're doing a polymer then generate a new polymer with the given polymer parameters for each pass.
            polyStart = np.array([ 0.0, 0.0, Z1_brush])
            envelopeList = ['frustum ' + str(Z1_brush - minDist_brush) + ' ' + str(R1_brush) + ' ' + str(Z2_brush) + ' ' + str(R2_brush)]
            
            brushObject = brushGenerator.generateBuildingBlock( num_brush,
                                                                polyStart,
                                                                alpha1_brush,
                                                                alpha2_brush,
                                                                beta1_brush,
                                                                beta2_brush,
                                                                minDist_brush,
                                                                bondLength_brush,
                                                                envelopeList = envelopeList)
        
        newBrushXYZ = coords.transformFromBlockFrameToLabFrame(labDirector, point + minDist_A * labDirector, 0.0, brushObject.blockDirectorHat, brushObject.blockXYZVals[0], brushObject.blockXYZVals)
        polymerXyzVals = np.concatenate((polymerXyzVals, newBrushXYZ), 0) 
        polymerNames = np.concatenate( (polymerNames, brushObject.blockAtomNames), 0 )


    # direction of brush is z-axis.  
    # reference point is the first of the B polymers, which is the numAth entry in the list of xyzVals
    return (np.array([0.0, 0.0, 1.0]), polymerXyzVals[num_A], polymerXyzVals, polymerNames)
コード例 #11
0
ファイル: betasheet.py プロジェクト: cjforman/vesiform
    def generateBuildingBlockXYZ(self):

        # create a strand and loop generator
        strandGen = PBG(self.paramFilename)
        loopGen = PHG(self.paramFilename)

        loopPoints = []
        sphereCentrePoints = []
        dummyConnector = [[2, 1, 0]]

        # construct the base line for the strand start points
        baseLine = [
            self.startPos +
            n * self.betaStrandSeparation * self.crossStrandDirectorHat
            for n in range(self.numStrands)
        ]

        # construct a prototype beta strand building Block in the defined polarity
        strandA_BB = strandGen.generateBuildingBlock(self.numPoints,
                                                     self.polarity,
                                                     dummyConnector)

        # assume loop length needs to be long enough to stretch a whole beta strand.
        loopLength = int(np.ceil(1.5 * self.strandLength))

        # In a not parallel situation construct the antiparallel strand - StrandB
        # also add the offset to every other strand starting on the first or second strand depending on the polarity
        # also compute the alternative strand building block
        if not self.parallel:
            loopLength = 2  # in a parallel situation the loop is always 2 (residues) long. I just said so.
            if self.polarity == 'NC':
                baseLine = [
                    basePoint + self.offsetXYZ if (n % 2) == 0 else basePoint
                    for n, basePoint in enumerate(baseLine)
                ]
                strandB_BB = strandGen.generateBuildingBlock(
                    self.numPoints, 'CN', dummyConnector)
            else:
                baseLine = [
                    basePoint + self.offsetXYZ if (n % 2) == 1 else basePoint
                    for n, basePoint in enumerate(baseLine)
                ]
                strandB_BB = strandGen.generateBuildingBlock(
                    self.numPoints, 'NC', dummyConnector)

        # compute the relative vector from the end of the first chain to the next atom in the hairpin.
        TNB = coords.constructTNBFrame(strandA_BB.xyzVals[-3],
                                       strandA_BB.xyzVals[-2],
                                       strandA_BB.xyzVals[-1])

        if self.polarity == 'NC':
            # if polarity is NC then the last three values are an NCC triad.
            beta = self.angleC
            alpha = self.phi
            bondLength = self.CNbondLength
        else:
            # if polarity is CN then the last three values are CCN triad.
            beta = self.angleN
            alpha = self.psi
            bondLength = self.CNbondLength

        # the vector from the end of the first strand to its hairpin is defined as the positive connectorVector.
        ConnectorVectorPos = bondLength * coords.generateTNBVecXYZ(
            TNB, beta, alpha)

        # -ve connector vector is the reciprocal of that
        ConnectorVectorNeg = -1 * ConnectorVectorPos

        # for parallel all CVs are always the Positive from end of strand to hairpin
        # and from hairpin to end of strand
        connectorVectorStrandToHairpin = ConnectorVectorPos
        connectorVectorHairpinToStrand = ConnectorVectorPos

        # for parallel strands are always the same set of xyz vals
        curStrandXYZ = strandA_BB.xyzVals

        # now the preparatory stuff is complete begin constructing the beta sheet
        # copy across the first strand to get the structure going.
        buildingBlockXYZ = [baseLine[0] + xyz for xyz in strandA_BB.xyzVals]

        innerRadiusParallel = 0.75 * self.strandLength * 3 * bondLength / 2
        outerRadiusParallel = 40 * self.strandLength * 3 * bondLength / 2
        innerRadiusAntiParallel = 0.9 * self.betaStrandSeparation / 2
        outerRadiusAntiParallel = 40 * self.betaStrandSeparation
        print "Radii: ", innerRadiusParallel, outerRadiusParallel, innerRadiusAntiParallel, outerRadiusAntiParallel
        print "Diameter: ", 2 * innerRadiusParallel, 2 * outerRadiusParallel, 2 * innerRadiusAntiParallel, 2 * outerRadiusAntiParallel

        # contruct the remaining strands following this procedure
        curStrand = 1
        while curStrand < self.numStrands:

            # if parallel, strands and connectorvectors are always the same so do nothing
            # to them.

            # if not parallel work out the connectorVectors for attaching hairpin between
            # the previous strand and the current strand.
            if not self.parallel:
                if (curStrand % 2) == 0:
                    connectorVectorStrandToHairpin = ConnectorVectorNeg
                    connectorVectorHairpinToStrand = ConnectorVectorPos
                    curStrandXYZ = strandA_BB.xyzVals
                if (curStrand % 2) == 1:
                    connectorVectorStrandToHairpin = ConnectorVectorPos
                    connectorVectorHairpinToStrand = ConnectorVectorNeg
                    curStrandXYZ = list(reversed(strandB_BB.xyzVals))

            # loop start is end of building block + connectorvector
            loopStartPoint = buildingBlockXYZ[
                -1] + connectorVectorStrandToHairpin

            loopPoints.append(loopStartPoint)

            # compute values for new strand
            newStrand = [baseLine[curStrand] + xyz for xyz in curStrandXYZ]

            # loop end point is start of next strand - connector vector.
            loopEndPoint = newStrand[0] - connectorVectorHairpinToStrand

            loopPoints.append(loopEndPoint)
            sphereCentrePoint = (loopEndPoint + loopStartPoint) / 2
            sphereCentrePoints.append(sphereCentrePoint)

            print "loopPointdist: ", np.linalg.norm(loopEndPoint -
                                                    loopStartPoint)

            # now we have the length of the loop and the start and end points
            # makes and attempt to stop the hairpin from entering
            # a sphere at the mid point of the start and end points
            if self.loopEnds:
                if self.parallel:

                    loop = loopGen.generateBuildingBlock(
                        loopLength * 3, loopStartPoint, loopEndPoint, 0, -180,
                        180, beta * 180 / np.pi - 40, beta * 180 / np.pi + 40,
                        0.9 * bondLength, bondLength, innerRadiusParallel,
                        outerRadiusParallel, sphereCentrePoint, self.polarity)
                else:
                    loop = loopGen.generateBuildingBlock(
                        loopLength * 3, loopStartPoint, loopEndPoint, 0, -180,
                        180, beta * 180 / np.pi - 40, beta * 180 / np.pi + 40,
                        0.9 * bondLength, bondLength, innerRadiusAntiParallel,
                        outerRadiusAntiParallel, sphereCentrePoint,
                        self.polarity)
                # append the loop to the array
                buildingBlockXYZ = buildingBlockXYZ + loop.xyzVals

            # append each vector to the current output array
            buildingBlockXYZ = buildingBlockXYZ + newStrand

            #next strand
            curStrand += 1

        #buildingBlockXYZ = buildingBlockXYZ + loopPoints
        #buildingBlockXYZ = buildingBlockXYZ + sphereCentrePoints

        self.numPoints = len(buildingBlockXYZ)

        return buildingBlockXYZ