### This script will read data from an excel file, run the model based on that
### data and write the result data to another excel file
### The code is commented to explain the concepts.

### Besides basic python knowledge, if you feel you are helpless in generating
### code related to ABAQUS, just perform the action through the UI
### and read the JNL file generated in the working directory. ABAQUS by-default
### creates python code for each and every step performed through
### UI

# Import all the the relevant modules, based on your requirement

from part import *
from material import *
from section import *
from assembly import *
from step import *
from interaction import *
from load import *
from mesh import *
from optimization import *
from job import *
from sketch import *
from visualization import *
from connectorBehavior import *
import os

# change the abaqus working directory to one you find suitable
os.chdir('E://rahul')

### This step might require some tweaking to work.
### Openpyxl doesnt ship with the standard abaqus python installation, so the
### suggested work-around is to install the version of python that your abaqus
### version comes with, this changes with your abaqus version. Generally 2.x
### Just run "python -v" on the the python interpreter inside abaqus to find
### this version. Now install the same version python on your system, by
### downloading from https://www.python.org/downloads/
### Once you have python installed on your system, you can install openpyxl, or
### any other library that you are interested in.
### Then copy the folder openpyxl from %python_install_dir%/lib/site-packages
### to the abaqus python installation, which is usually located at
### C:\SIMULIA\Abaqus\6.12-1\tools\SMApy\Lib\site-packages
### You might also have to copy jdcal from your system's python site-packages
### folder.


# import openpyxl for excel manupulation


from openpyxl import load_workbook

# Reading an excel file - load workbook at the specified location
wb = load_workbook(filename = "D:/test_py.xlsx")

# Select the worksheet you want to read, active means first
ws = wb.active

# Here, iterating through rows, reading each one, one at a time
for j in range(0, len(ws.rows)):

    # Fill variables width_beam, height_beam etc. as required from the excel file
    # These are the parameters you want to change each subsequent time
    width_beam  = float(ws.rows[j][0].value)
    height_beam = float(ws.rows[j][1].value)
    length_beam = float(ws.rows[j][2].value)
    nel = float(ws.rows[j][3].value)
    if nel %2 != 0:
        print "no of element should be even"
        exit()
    else:
        mid_node_no = int((nel/2)+1)

    # This code is auto-generated by abaqus, although it can be
    # simplified and made mor readable as explained in the documentation

    mdb.models['Model-1'].ConstrainedSketch(name='__profile__', sheetSize=200.0)
    mdb.models['Model-1'].sketches['__profile__'].Line(point1=(0.0, 0.0), point2=(
        length_beam, 0.0))
    mdb.models['Model-1'].sketches['__profile__'].geometry.findAt((10.0, 0.0))
    mdb.models['Model-1'].sketches['__profile__'].HorizontalConstraint(
        addUndoState=False, entity=
        mdb.models['Model-1'].sketches['__profile__'].geometry.findAt((10.0, 0.0),
        ))
    mdb.models['Model-1'].Part(dimensionality=TWO_D_PLANAR, name='Beam', type=
        DEFORMABLE_BODY)
    mdb.models['Model-1'].parts['Beam'].BaseWire(sketch=
        mdb.models['Model-1'].sketches['__profile__'])
    del mdb.models['Model-1'].sketches['__profile__']

    # First use of our parameters, rather than a fixed numerical value,
    # width and height defined as in excel file
    mdb.models['Model-1'].RectangularProfile(a=width_beam, b=height_beam, name='Profile-1')
    mdb.models['Model-1'].Material(name='Material-1')
    mdb.models['Model-1'].materials['Material-1'].Density(table=((1.0, ), ))
    mdb.models['Model-1'].materials['Material-1'].Elastic(table=((100000000.0,
        0.25), ))
    mdb.models['Model-1'].BeamSection(consistentMassMatrix=False, integration=
        DURING_ANALYSIS, material='Material-1', name='Section-1', poissonRatio=0.0,
        profile='Profile-1', temperatureVar=LINEAR)
    mdb.models['Model-1'].parts['Beam'].SectionAssignment(offset=0.0, offsetField=
        '', offsetType=MIDDLE_SURFACE, region=Region(
        edges=mdb.models['Model-1'].parts['Beam'].edges.findAt(((5.0, 0.0, 0.0), ),
        )), sectionName='Section-1', thicknessAssignment=FROM_SECTION)
    mdb.models['Model-1'].parts['Beam'].assignBeamSectionOrientation(method=
        N1_COSINES, n1=(0.0, 0.0, -1.0), region=Region(
        edges=mdb.models['Model-1'].parts['Beam'].edges.findAt(((5.0, 0.0, 0.0), ),
        )))
    mdb.models['Model-1'].rootAssembly.DatumCsysByDefault(CARTESIAN)
    mdb.models['Model-1'].rootAssembly.Instance(dependent=ON, name='Beam-1', part=
        mdb.models['Model-1'].parts['Beam'])
    mdb.models['Model-1'].StaticStep(name='Step-1', previous='Initial')
    mdb.models['Model-1'].parts['Beam'].seedPart(deviationFactor=0.1,
        minSizeFactor=0.1, size=(length_beam/nel))
    mdb.models['Model-1'].parts['Beam'].generateMesh()
    mdb.models['Model-1'].parts['Beam'].setElementType(elemTypes=(ElemType(
        elemCode=B21, elemLibrary=STANDARD), ), regions=(
        mdb.models['Model-1'].parts['Beam'].edges.findAt(((5.0, 0.0, 0.0), )), ))
    mdb.models['Model-1'].parts['Beam'].Set(name='Set-1', nodes=
        mdb.models['Model-1'].parts['Beam'].nodes[(mid_node_no-1):mid_node_no])
    mdb.models['Model-1'].rootAssembly.regenerate()
    mdb.models['Model-1'].DisplacementBC(amplitude=UNSET, createStepName='Step-1',
        distributionType=UNIFORM, fieldName='', fixed=OFF, localCsys=None, name=
        'BC-1', region=Region(
        vertices=mdb.models['Model-1'].rootAssembly.instances['Beam-1'].vertices.findAt(
        ((0.0, 0.0, 0.0), ), )), u1=0.0, u2=0.0, ur3=UNSET)
    mdb.models['Model-1'].DisplacementBC(amplitude=UNSET, createStepName='Step-1',
        distributionType=UNIFORM, fieldName='', fixed=OFF, localCsys=None, name=
        'BC-2', region=Region(
        vertices=mdb.models['Model-1'].rootAssembly.instances['Beam-1'].vertices.findAt(
        ((length_beam, 0.0, 0.0), ), )), u1=UNSET, u2=0.0, ur3=UNSET)
    mdb.models['Model-1'].ConcentratedForce(cf2=-100.0, createStepName='Step-1',
        distributionType=UNIFORM, field='', localCsys=None, name='Load-1', region=
        mdb.models['Model-1'].rootAssembly.instances['Beam-1'].sets['Set-1'])
    mdb.Job(atTime=None, contactPrint=OFF, description='', echoPrint=OFF,
        explicitPrecision=SINGLE, getMemoryFromAnalysis=True, historyPrint=OFF,
        memory=50, memoryUnits=PERCENTAGE, model='Model-1', modelPrint=OFF,
        multiprocessingMode=DEFAULT, name='job' + str(j), nodalOutputPrecision=SINGLE,
        numCpus=1, numGPUs=0, queue=None, scratch='', type=ANALYSIS,
        userSubroutine='', waitHours=0, waitMinutes=0)

    # Job submitted for running
    mdb.jobs['job' + str(j)].submit(consistencyChecking=OFF)
    # Wait for completion, as the result file will generated only after running,
    # so code should stop here
    mdb.jobs['job' + str(j)].waitForCompletion()


    ##############################   RESULT EXTRACTION ########################

    from openpyxl import Workbook

    # define an empty workbook
    wbo = Workbook()
    # Create a worksheet at the specified location, 0 means beginning
    wso = wbo.create_sheet(0)

    # Import abaqus odb work related modules
    from odbAccess import *
    from abaqusConstants import *
    from odbMaterial import *
    from odbSection import *

    # open the odb file, paramatrically referred, as each imput row creates
    # a new odb file
    odb = openOdb(path='E://Rahul//' + 'job' + str(j) + '.odb')
    # Refer to the last frame for final results
    lastFrame = odb.steps['Step-1'].frames[-1]

    # Field output U captured in the variable displacement
    displacement = lastFrame.fieldOutputs['U']
    fieldValues1 = displacement.values

    # Field output UR3 - rotation, captured in the variable rotationalDisplacement
    rotaionalDisplacement = lastFrame.fieldOutputs['UR3']
    fieldValues2 = rotaionalDisplacement.values

    i = 1
    # Iterate over all the values of displacement
    for v in fieldValues1:
        # store the relevant value in the excel cell as you want
        wso['A'+str(i)].value=float(v.nodeLabel)
        wso['B'+str(i)].value=float(v.data[0])
        wso['C'+str(i)].value=float(v.data[1])
        i=i+1

    i = 1
    for v in fieldValues2:
        wso['D'+str(i)].value=float(v.data)
        i=i+1

    # Finally, save the workbook after writing the results.
    wbo.save("E://Rahul//output" + str(j) + ".xlsx")


