Defining Functions for Connecting to a Third-Party Solver

The script main.py follows.

import os
import solver
    
def CreateValuesLoad(analysis):
    analysis.CreateLoadObject("Values")

initValues = {}
sol = None
solbystep = SerializableDictionary[int,dict]()
values = {}
steps = []
res = [0.]
dScal = [0.]
dVec = [0., 0., 0.]

def WriteInitialValues(load,filename):
    global initValues    
    propEx = load.Properties["Expression"]
    exp = propEx.Value
    if exp=="": 
        return None
    vexp = compile(exp,'','eval')
    values = []
    propGeo = load.Properties["Geometry"]
    refIds = propGeo.Value.Ids
    mesh = load.Analysis.MeshData
    for refId in refIds:
        meshRegion = mesh.MeshRegionById(refId)
        nodeIds = meshRegion.NodeIds
        for nodeId in nodeIds:
            node = mesh.NodeById(nodeId)
            x = node.X
            y = node.Y
            z = node.Z
            v = 0.
            try:
                v = eval(vexp)
                v = float(v)
            finally:
                initValues.Add(nodeId,v)

def NodeValues(load,nodeIds):
    propEx = load.Properties["Expression"]
    exp = propEx.Value
    if exp=="": 
        return None
    try:
        vexp = compile(exp,'','eval')
    except: 
        return None
    values = []
    mesh = load.Analysis.MeshData
    for id in nodeIds:
        node = mesh.NodeById(id)
        x = node.X
        y = node.Y
        z = node.Z
        v = 0.
        try:
            v = eval(vexp)
            v = float(v)
        finally:
            values.Add(v)
    return values

def Solve(s):
    global steps
    global initValues
    global sol
    global solbystep
    global values
    
    solbystep = SerializableDictionary[int,dict]()
    solbystepTmp = {}
    
    f = open("solve.out","w")
    f.write("SolverEngine version 1.0\n\n\n")
    try:
    
        maxIter = int(s.Properties["MaxIter"].Value)
        f.write("Max. iteration : %d\n" % (maxIter))
    
        mesh = s.Analysis.MeshData
        
        numEdges = 0
        geo = ExtAPI.DataModel.GeoData
        nodeIds = []
        for asm in geo.Assemblies:
            for part in asm.Parts:
                for body in part.Bodies:
                    for edge in body.Edges:
                        numEdges = numEdges + 1
                        ids = mesh.MeshRegionById(edge.Id).NodeIds
                        nodeIds.extend(ids)
        steps = []
        stepsTmp = []
        f.write("Num. edges : %d\n" % (numEdges))
        sol = solver.SolverEngine(mesh,initValues,nodeIds)
        initValues = sol.Run(maxIter,f,stepsTmp,solbystepTmp)
        nodeIds = mesh.NodeIds
        sol = solver.SolverEngine(mesh,initValues,nodeIds)
        values = sol.Run(maxIter,f,steps,solbystep)
    
        initValues = {}
    
    except StandardError, e:
        f.write("Error:\n");
        f.write(e.message+"\n");
        f.close()
        return False

    f.close()
    
    return True

def GetSteps(solver):
    global steps
    return steps


def Save(folder):
    global solbystep
    fm = System.Runtime.Serialization.Formatters.Binary.BinaryFormatter()
    try:
        stream = System.IO.StreamWriter(os.path.join(folder,"sol.res"),False)
    except:
        return
    try:
        fm.Serialize(stream.BaseStream,solbystep)
    finally:
        stream.Close()
    
def Load(folder):
    global solbystep
    if folder==None:
        return
    fm = System.Runtime.Serialization.Formatters.Binary.BinaryFormatter()
    try:
        stream = System.IO.StreamReader(os.path.join(folder,"sol.res"))
    except:
        return
    try:
        solbystep = fm.Deserialize(stream.BaseStream)
    finally:
        stream.Close()

class ExtSolver1Reader(ResultReaderBase):
    def __init__(self,infos):
        self.infos = infos
        self.step = 1

    def get_CurrentStep(self):
        return self.step

    def set_CurrentStep(self,step):
        self.step = step

    def StepValues(self):
        global steps
        return steps

    def ResultNames(self):
        return ["U","VALUES"]

    def GetResultLocation(self,resultName):
        return "node"

    def GetResultType(self,resultName):
        if resultName=="U":
            return "vector"
        return "scalar"

    def ComponentNames(self,resultName):
        if resultName=="U":
            return ["X","Y","Z"]
        else:
            return ["VALUES"]

    def ComponentUnit(self,resultName,componentName):
        if resultName=="U":
            return "Length"
        return "Temperature"

    def GetValues(self,resultName,entityId):
        global values
        global solbystep
        global dVec
        global dScal
        if resultName=="U":
            values = solbystep[self.step]
            dVec[0] = 0.
            dVec[1] = 0.
            dVec[2] = 0.
            try:
                dVec[0] = values[entityId]
            finally:
                return dVec
        else:
            values = solbystep[self.step]
            try:
                dScal[0] = values[entityId]
                return dScal
            except:
                return None

def GetReader(solver):
    return ["ExtSolver1Reader"]

The second line of the script main.py is import solver. The solver code is located in a separate script, solver.py, which is placed in the same folder as main.py. This technique of importing another script supports reuse and maintainability. The script in solver.py defines the class SolverEngine.

The function Solve is associated with the callback <onsolve>. This function creates a file solve.out, which is read interactively by the product and stored in the solution information.

By default, the product starts the resolution directly in the working directory, so it is not necessary to set the folder in which the file solve.out must be created.

The callback function must return True or False to specify if the solve has succeeded or failed.

Currently, it is not possible to return progress information.