# Source code for Parts.GeometryBuilder

    """ Module contains helper functions to build microtubules, centrosomes
    and interMT connectors"""
    from abaqus import *
    from abaqusConstants import *
    import section
    import regionToolset
    import part
    import material
    import sketch

    def create_MT_part( l, type, i, **kwargs ):
        """
        Create an Abaqus object representing a single microtubule part

        :param l: Length of the microtuble

        :type l: float

        :param type: Type of the MT: aMT or ipMT

        :type type: str

        :param i: sequential number of the MT

        :type i: str

        :param kwargs: model parameters

        :type kwargs: dict

        :return: part object, MTname

        :rtype: object, str
        """
        modelname = kwargs['modelname']
        s = mdb.models[modelname].ConstrainedSketch(
            name='__profile__',
            sheetSize=1.0)
        g, v, d, c = s.geometry, s.vertices, s.dimensions, s.constraints
        s.sketchOptions.setValues(decimalPlaces=3)
        s.setPrimaryObject(option=STANDALONE)
        # create line
        s.Line(point1=(0.0, 0.0), point2=(l, 0.0))
        # create a name for MT
        MTname = create_mt_name(l, type, i)
        # Create part
        p = mdb.models[modelname].Part(
            name=MTname,
            dimensionality=THREE_D,
            type=DEFORMABLE_BODY)
        p = mdb.models[modelname].parts[MTname]
        p.BaseWire(sketch=s)
        s.unsetPrimaryObject()
        del mdb.models[modelname].sketches['__profile__']
        return p, MTname

    def create_connector_part( connectorname, length, **kwargs ):
        """
        Create an Abaqus object that represents a single connector part

        :param connectorname: Name of the connector

        :type connectorname: str

        :param length: Length of the connector

        :type length: float

        :param kwargs: model parameters

        :type kwargs: dict

        :return: Part object

        :rtype: object
        """
        modelname = kwargs['modelname']
        s = mdb.models[modelname].ConstrainedSketch(
            name='__profile__',
            sheetSize=1)
        g, v, d, c = s.geometry, s.vertices, s.dimensions, s.constraints
        s.sketchOptions.setValues(decimalPlaces=4)
        s.setPrimaryObject(option=STANDALONE)
        # create line
        s.Line(point1=(0.0, 0.0), point2=(0.0, length))
        p = mdb.models[modelname].Part(
            name=connectorname,
            dimensionality=THREE_D,
            type=DEFORMABLE_BODY)
        p = mdb.models[modelname].parts[connectorname]
        p.BaseWire(sketch=s)
        s.unsetPrimaryObject()
        del mdb.models[modelname].sketches['__profile__']
        return p

    def create_centrosome_sketch( l, r, **kwargs ):
        """
        Create a 2D sketch of the centrosome middle cross-section

        :param l: Length of the centrosome, e.g., dimension along z axis

        :type l: float

        :param r: Radius of the centrosome, e.g., radius of the centrosome cross-section
                in x-y plane

        :type r: float

        :param kwargs: model parameters

        :type kwargs: dict

        :return: Sketch object

        :rtype: object
        """
        modelname = kwargs['modelname']
        s = mdb.models[modelname].ConstrainedSketch(
            name='__profile__', sheetSize=2.0)
        g, v, d, c = s.geometry, s.vertices, s.dimensions, s.constraints
        # Create cross-sectoion
        s.setPrimaryObject(option=STANDALONE)
        # Define an axis of revolution
        s.ConstructionLine(point1=(0.0, -1.0), point2=(0.0, 1.0))
        # Create a revolution sketch
        s.FixedConstraint(entity=g[2])
        s.Arc3Points(point1=(0.0, r), point2=(0.0, -r), point3=(l / 2, 0.0))
        s.Line(point1=(0.0, -r), point2=(0.0, r))
        s.VerticalConstraint(entity=g[4], addUndoState=False)
        return s

    def create_mt_name( l, type, i ):
        """
        Specify a unique name to each created microtubule

        :param l: Length of the MT

        :type l: float

        :param type: Type of the MT: aMT or ipMT

        :type type: str

        :param i: sequential number of the MT

        :type i: int

        :return: MTname

        :rtype: str
        """
        if type == 'ipMT':
            MTname = 'ipMT_' + str(l * 100)[:3] + '_' + str(i)
            print(MTname)
        elif type == 'aMT':
            MTname = 'aMT_' + str(i)
        else:
            raise ValueError('Only interpolar MTs (ipMT) and astral MTs (aMT) are currently supported')

        return MTname

    def create_section( sectionName, sectionProfile, sectionMaterial, **kwargs ):
        """
        Create a beam section for the microtubule

        :param sectionName: Name of the section. 'MT-section'

        :type sectionName: str

        :param sectionProfile: Type of the section profile. 'MT-profile'

        :type sectionProfile: str

        :param sectionMaterial: Name of the material assigned to the section. 'MT_material'

        :type sectionMaterial: str

        :param kwargs: model parameters

        :type kwargs: dict

        :return: Null

        :rtype: Null
        """
        modelname = kwargs['modelname']
        mdb.models[modelname].BeamSection(
            name=sectionName,
            integration=DURING_ANALYSIS,
            poissonRatio=0.0,
            profile=sectionProfile,
            material=sectionMaterial,
            temperatureVar=LINEAR,
            consistentMassMatrix=False)

    def define_material( name, E, nu, **kwargs ):
        """
        Define material parameters of microtubules, connectors and centrosomes specifying
        its module of elasticity and Poisson's ratio

        :param name: Name of the material

        :type name: str

        :param E: Module of elasticity

        :type E: float

        :param nu: Poisson's ratio

        :type nu: float

        :param kwargs: model parameters

        :type kwargs: dict

        :return: Null

        :rtype: Null
        """
        modelname = kwargs['modelname']
        mdb.models[modelname].Material(name=name)
        mdb.models[modelname].materials[name].Elastic(table=((E, nu),))

    def assign_MT_section( part, MTname, **kwargs ):
        """
        Assign a section to microtubules

        :param part: Microtubule part to which section to be assigned

        :type part: object

        :param MTname: Name of the microtubule

        :type MTname: str

        :param kwargs: model parameters

        :type kwargs: dict

        :return: Null

        :rtype: Null
        """
        modelname = kwargs['modelname']
        e = part.edges
        edges = e.getByBoundingSphere((0.0, 0.0, 0.0), (kwargs['spindleLength']), )
        region = part.Set(edges=edges, name='MT-set')
        p = mdb.models[modelname].parts[MTname]
        p.SectionAssignment(
            region=region, sectionName='MT-section', offset=0.0,
            offsetType=MIDDLE_SURFACE, offsetField='',
            thicknessAssignment=FROM_SECTION)

    def assign_MT_section_orientation( MTname, **kwargs ):
        """
        Assign MT section orientation with respect to the local coordinates of the MT

        :param MTname: Name of the microtubule

        :type MTname: str

        :param kwargs: model parameters

        :type kwargs: dict

        :return: Null

        :rtype: Null
        """
        modelname = kwargs['modelname']
        p = mdb.models[modelname].parts[MTname]
        e = p.edges
        edges = e.getSequenceFromMask(mask=('[#1 ]',), )
        region = p.Set(edges=edges, name='MT-set')
        p = mdb.models[modelname].parts[MTname]
        p.assignBeamSectionOrientation(
            region=region,
            method=N1_COSINES,
            n1=(0.0, 0.0, -1.0))

    def assign_connector_section( part, name, **kwargs ):
        """
        Assign a section to each connector

        :param part: Connector part to which section to be assigned

        :type part: object

        :param name: Name of the connector

        :type name: str

        :param kwargs: model parameters

        :type kwargs: dict

        :return: Region containing connector

        :rtype: object
        """
        e = part.edges
        edges = e.getByBoundingSphere((0.0, 0.0, 0.0), (kwargs['spindleLength']), )
        region = part.Set(edges=edges, name='connector-set')
        part.SectionAssignment(
            region=region, sectionName=name, offset=0.0,
            offsetType=MIDDLE_SURFACE, offsetField='',
            thicknessAssignment=FROM_SECTION)
        return region

    def create_centrosome_part( Centrosomesketch, name, **kwargs ):
        """
        Create an Abaqus object containing centrosome geometry part

        :param Centrosomesketch: Name of the centrosome sketch object

        :type Centrosomesketch: str

        :param name: Name of the centrosome part

        :type name: object

        :param kwargs: model parameters

        :type kwargs: str

        :return: Centrosome part

        :rtype: object
        """
        modelname = kwargs['modelname']
        p = mdb.models[modelname].Part(
            name=name,
            dimensionality=THREE_D,
            type=DEFORMABLE_BODY)
        p = mdb.models[modelname].parts[name]
        p.BaseSolidRevolve(sketch=Centrosomesketch, angle=360.0, flipRevolveDirection=OFF)
        Centrosomesketch.unsetPrimaryObject()
        p = mdb.models[modelname].parts[name]
        del mdb.models[modelname].sketches['__profile__']
        return p

    def assign_centrosome_section( part, name, sectionName, **kwargs ):
        """
        Assign section to the Centrosome part

        :param part: Centrosome part to which the section is to be assigned

        :type part: object

        :param name: Name of the centrosome

        :type name: str

        :param sectionName: Name of the section to be assigned

        :type sectionName: str

        :param kwargs: model parameters

        :type kwargs: dict

        :return: Null

        :rtype: Null
        """
        modelname = kwargs['modelname']
        c = part.cells
        cells = c.getByBoundingSphere((0.0, 0.0, 0.0), (kwargs['spindleLength']), )
        region = part.Set(cells=cells, name='centrosome-set')
        p = mdb.models[modelname].parts[name]
        p.SectionAssignment(
            region=region,
            sectionName=sectionName, offset=0.0,
            offsetType=MIDDLE_SURFACE, offsetField='',
            thicknessAssignment=FROM_SECTION)

    def model( **kwargs ):
        """
        Create Abaqus model for the mitotic spindle

        :param kwargs: model parameters

        :type kwargs: dict

        :return: Null

        :rtype: Null
        """
        modelname = kwargs['modelname']
        # Create and save model database
        mdb.Model(name=modelname, modelType=STANDARD_EXPLICIT)