OpenPisco and OpenPiscoCL interfaces

The aim of this section is to provide an exhaustive description of the capabilities of the platform while using the OpenPisco Domain Specific languages (DSLs) interface.

What are OpenPisco and OpenPiscoCL?

OpenPisco and OpenPiscoCL are two applications enabling a user to interact with the platform. OpenPisco relies on a GUI while OpenPiscoCL is a command line application.

Both applications allow to build a complete topology optimization problem by combining bricks corresponding to each operation performed during the optimization process. Such a high level language make relatively easy to modify an existing study (see the tutorials for more details). Creating a new study from scratch is not especially difficult either.

How do OpenPisco and OpenPiscoCL work?

When running the OpenPiscoCL module using the command line, the user is expected to provide as an input (within the command line) a file written in a domain specific syntax (see the tutorial for actual examples). Then, OpenPiscoCL simply does:

  • Reading the file

  • Parsing the information contained within the script

  • Run each operation, mapped to the actual implementation, one by one.

One DSL supported within both applications is a xml-like idiom (denoted by xml). The language relies on tag-like entities.

At this point, we provide below some elementary rules:

  • Each elementary operation performed during a topology optimization with level set can be use with this API. That includes in particular the physical solver and the remeshing related tools.

  • It is not required to build a complete optimization problem to use this API, it is just as modular as the platform itself

  • It aims to be even more user-friendly than the python API and should be enough for a user

  • Within the script, the module tags order do not matter, meaning you can for instance start with the Zones description before even characterizing the domain

  • Within a module tag, only the Action operations order matters, as it determines the sequential intructions executed by OpenPiscoCL

  • Elementary mathematical operations (+,-,*,/) are supported within a string containing numbers

How can OpenPisco and OpenPiscoCL be used?

Let file.xml be a script written in the OpenPisco DSL, to run the script by using the command line application execute in a terminal

code-block:

OpenPiscoCL file.xml

To run the script by using the GUI execute in a terminal

code-block:

OpenPisco file.xml

Module tags

In each case, we provide a brief description of the module and the features available. For clarity and completeness, we also provide a template-like snippet in xml.

In each xml snippet provided below, a representative variable name for the argument is given followed by “:” and the type of the variable expected (similar to type hinting logic in python). Therefore

<ModuleType>
    <ModuleSubType
        id="moduleTypeId:int"
        origin="originValX:float originValY:float originValZ:float"
        path="moduleTypePath:str"/>
</ModuleType>

means that we expect

  • an integer moduleTypeId for id

  • 3 floats values for origin, respectively originValX,originValY and originValZ

  • a string moduleTypePath for path

When there are several options available, it is denoted by

<ModuleType>
    <ModuleSubType
        type="[type1|type2|type3]"
        use="*None|useId:int" />
</ModuleType>

which means:

  • you can chose either type1, type2 or type3 for type

  • you can define a useId for use, if you don’t, the default option is None

Finally, when the type is meant to be related to a specific class instance/function of the platform, it is denoted as OpenPisco*

<ModuleType>
    <ModuleSubType
        criteria="criteria:OpenPiscoCriteria"/>
</ModuleType>

In other words:

  • It is not a simple primitive (string, int, float, bool)

  • The user has to refer to the proper documentation to check which xml tags are available within a module

  • There are a limited number of choices and an exhaustive description is out of the scope of the present documentation

Plugins

Enable to import a python module “on the fly” from the module name. For instance, the following code

<Plugins>
    <Plugin name="MyAwesomeRepo.MyAwesomeModuleWithinRepo" />
</Plugins>

would be equivalent in python to

import MyAwesomeRepo.MyAwesomeModuleWithinRepo

By doing so, it is even possible to enable the use of one’s own routine without modifying the platform source code.

Mesh

There are two possibilities. You can create a 3D structured grid with the platform

<Grids>
    <Grid
        id="gridId:int"
        n="numElemX:int numElemY:int numElemZ:int"
        origin="originX:float originY:float originZ:float"
        length="lengthX:float lengthY:float lengthZ:float"/>
</Grids>

where the grid is labeled with an integer id and n denotes the number of elements in each direction. Origin and length are respectively the position of the origin in cartesian coordinates and the size of the grid in each direction.

It is also possible to simply import the mesh in any format supported by the platform (for an exhaustive list, we refer to the :py:module:`Muscat.IO.IOFactory`)

<Grids>
    <Mesh
        id="meshId:int"
        filename="filename:(str+"."+PiscoIOFormat)" />
</Grids>

where the mesh is also labeled with an integer id. In that case, the platform assumes the user provide a filename extension (for instance .mesh, .med etc…) consistent with the actual mesh format used within the meshfile.

Zones

This is where the implicit zones are defined. The format supports :py:module:`Muscat.ImplicitGeometry.ImplicitGeometryObjects` and :py:module:`Muscat.ImplicitGeometry.ImplicitGeometryOperators`

Each are endowed with an integer id, so that any of them can be used by other bricks. These operations and their respective arguments match almost exactly the ImplicitGeometry objects and operators name in the python API within Muscat

Albeit a mapping between the name of the implemented features and its actual use within the xml format is not provided here, it is not difficult to find it, should you ever need to use one not present in the tutorials. As a matter of fact; in the python implementation, all the implicit geometry objects and operators classes are followed by a call to a :py:module:`Muscat.ImplicitGeometry.ImplicitGeometryFactory.RegisterClass`. The first argument is a string that can be used in xml.

We provide below an example where we define:

  • 2 implicit geometry objects
    • Plane for Muscat.ImplicitGeometry.ImplicitGeometryObjects.ImplicitGeometryPlane

    • Cylinder for Muscat.ImplicitGeometry.ImplicitGeometryObjects.ImplicitGeometryCylinder

  • 1 operator:
    • Union for Muscat.ImplicitGeometry.ImplicitGeometryOperators.ImplicitGeometryUnion

<Zones>
    <Plane
        id="planeId:int"
        point="pointCoordX:float pointCoordY:float pointCoordZ:float"
        normal="normalX:float normalY:float normalZ:float"
        desc="planeDescription:str"/>
    <Cylinder
        id="cylinderId:int"
        center1="center1CoordX:float center1CoordY:float center1CoordZ:float"
        center2="center2CoordX:float center2CoordY:float center2CoordZ:float"
        radius="radiusVal:float"
        desc="cylinderDescription:str"/>
    <Union
        id="unionZoneId:int"
        z="zoneIdToMerge1:int zoneIdToMerge2:int"/>
</Zones>

As a common features, each implicit geometry object/operators are labeled with an id. Those ids are already explicitly used for union, to create a new implicit geometry from the implicit geometries labeled as zoneIdToMerge1 and zoneIdToMerge2. Here, in this specific case, it would be planeId and cylinderId, for instance.

Level sets

Then, we define the level sets, each endowed with:

  • Their support described by the mesh id

  • Their own id, in order to be used by other xml tags/platform bricks

<LevelSets>
    <LevelSet
        id="levelSetId:int"
        support="supportId:int"/>
</LevelSets>

Physical analysis

Next, we define the physical problems.

For the static_elastic physic, a template example is presented below

<PhysicalProblems>
    <[GeneralAster|GeneralFreefem|GeneralZset|StructuredFEA]
        id="physicalProblemId:int"
        type="static_elastic"
        p="*1|2"  >
        <Material
            eTag="*everyelement|elementsTag:str"
            E="youngModulusVal:float"
            Nu="poisonRatioVal:float"/>
        <Dirichlet
            eTag="elementsTag:str"
            dofs="[0|1|2|0 1|0 2|1 2|0 1 2]"
            value="[prescribedValue:float]"/>
        <Force
            eTag="elementsTag:str"
            value="FxVal:float FyVal:float FzVal:float"/>
        <Pressure
            eTag="elementsTag:str"
            value="pressureVal:float"/>
    <[/GeneralAster|/GeneralFreefem|/GeneralZset|/StructuredFEA]>
</PhysicalProblems>

Each problem includes:

  • the physical solver to use, amongst those supported by the platform

  • id, the id for the physical problem

  • type, the type of physical analysis involved (assuming the chosen physical solver can handle it, see PhysicalSolver.rst for that)

  • p, the degree of the finite element approximation (either linear with p=1 or quadratic with p=2)

  • the parameters related to the physical analysis chosen, in linear elasticity that would be the material properties denoted by the xml tag Material. The optional elementsTag is available to enable multi materials computations.

  • the boundary conditions; amongst them there are

    • Dirichlet condition: Displacement prescribed at a given value on given degrees of freedom (dof) on a zone given by an eTag

    • Neumann condition: Apply a force on a zone given by an elementsTag

    • Pressure condition: Apply a pressure on a zone given by an elementsTag

We provide below a concrete example relying on the interface with Code_Aster

<PhysicalProblems>
    <GeneralAster type="static_elastic">
            <Material  E="210000000000" Nu="0.3" />
            <Dirichlet eTag="ET1" dofs="0 1 2" value="0.0"/>
            <Dirichlet eTag="ET2" dofs="0" value="0.0"/>
            <Dirichlet eTag="ET7" dofs="2" value="0.0"/>
            <Force eTag="ET3" value="0. -10000. 0." />
    </GeneralAster>
</PhysicalProblems>

where ET1, ET2 and ET7 are elementsTag defined within the domain, prior to running the physical problem. Therefore, in this example, these elements tag have to created (see Action section below for more details) if they do not already exist in the mesh.

Optimization problems

We now define the actual optimization problems, relying on most of the already introduced existing module tags.

A generic template code would be

<OptimProblems>
    <OptimProblem
      type="[PenalizedTopoGeneric|SquaredTopoGeneric|TopoGeneric]"
      id="optimProblemId:int"
      OnZone="onZoneId:int" Dirichlet="dirichletId:int" Neumann="*None|neumannId:int"
      useLevelset="levelSetId:int"
      e2="[*MinLenghtScaleInitMesh|regularizationCoeffVal:float]"
      output="outputId:int">
        <Objective
            type="Criteria1:PiscoCriteria"
            name="criteria1Name:str"
            useProblem="*None|criteria1ProblemId:int" />
        <Constraint
            type="Criteria2:PiscoCriteria"
            name="criteria2Name:str"
            useProblem="*None|criteria2ProblemId:int"
            upperBound="upperBoundVal:float"/>
        <Constraint
            type="Criteria3:PiscoCriteria"
            name="criteri3Name:str"
            useProblem="*None|criteria3ProblemId:int"
            upperBound="upperBoundVal:float"/>
    ...
    </OptimProblem>

</OptimProblems>

For each optimization problem, we have

  • type, the type of optimization problem

  • id, the id for the optimization problem

  • OnZone, the id associated to the non optimizable zone

  • Dirichlet, the id associated to the dirichlet zone

  • Neumann, the id associated to the neumann zone (optional)

  • useLevelset, the considered level set id

  • e2, the regularization coefficient value (optional). The default value is the minimal characteristic size of the element computed on the initial mesh.

  • output, the id associated the output (see output tag section below for more details)

  • an objective, described by:
    • a criterion supported by the platform

    • its name

    • the physical problem associated (if applicable)

  • None/one/more than one constraint(s), with
    • their respective upperbounds

    • criteria supported by the platform

    • criteria name

    • the physical problems associated (if applicable)

Note also that, even though they are called Dirichlet and Neumann in the API, the real purpose is to make sure there are no deconnection between these 2 zones. Otherwise, the problem would not make sense from a physical point of view. Note that for a physical criterion, whether it is the objective or a constraint, one also has to specify problem associated. That is not the case for a geometrical criterion.

Optimization algorithms

Each optimization problem can be handled by a different algorithm, if required. We provide below the xml template for the so-called Nullspace algorithm

<TopologicalOptimizations>
    <OptimAlgoNullSpace
        id="optimAlgoId:int"
        useOptimProblem="optimProblemId:int"
        numberOfDesignStepsMax="[*200|maxDesignStepsAllowed:int]"
        numberOfIterationsMax="[*20|maxTrialStepsAllowed:int]"
        stepSizeMax="[*1|stepSizeMaxVal:float]"
        stepSize="[*1|stepSizeVal:float]"
        alphaC="[*1.0|alphaCVal:float]"
        alphaJ="[*0.5|alphaJVal:float]"
        tol_merit="[*0.0005,tolMeritVal:float]"/>
</TopologicalOptimizations>

Where there are:

  • the algorithm name (here, OptimAlgoNullSpace)

  • id, an algorithm labeled with an integer id

  • useOptimProblem, the id related to the optimization problem to apply the algo on

  • numberOfDesignStepsMax, the maximal number of design steps allowed (optional)

  • numberOfIterationsMax, number of trials until the merit function decreases within a design step (optional)

  • stepSizeMax, the maximal step size allowed for the optimization (optional)

  • stepSize, the initial step size along the descent direction (optional)

  • Some considerations specific to the NullSpace algorithm, related in particular to the merit function considered to evaluate a trial
    • alphaC and alphaJ, the coefficients related to the merit function (optional)

    • tol_merit, the tolerance for acceptance step with the merit function method (optional)

Outputs

At this point, it is possible to define the desired outputs format. For an exhaustive list of the formats available, we refer to the Muscat.IO.IOFactory().

<Outputs>
   <Output id="outputId:int" name="Filename:(str+"."+PiscoIOFormat)"/>
</Outputs>

Guessing from the filename extension provided by the user in Filename, the platform tries to write results in the associated format.

Still, notes that not all format are equivalent regarding their storing capabilities. For instance, if you want to be able to save all the intermediate design steps within the optimization process, not all formats would fit your needs.

For this very reason, one format used classicaly to handle temporal data is the .xdmf format (also compatible with Paraview).

Another interesting feature is the ProxyWriter (PROXY); we provide below a concrete example to illustrate its use

<Outputs>
   <Output id="1" name="LBeamHistory.xdmf" inTempDirectory="False" />
   <Output id="2" name="LBeamHistory.csv" inTempDirectory="False" />
   <Output id="3" name="PROXY" outputs="1 2"/>
</Outputs>

In this context, it can be used for instance to write the same information in 2 different formats using a single output id.

Actions

What the action actually do is encapsulated in the Apply method of each action class within each submodule of :py:module:`OpenPisco.Actions`.

General:

  • Repeate

  • Try

  • Set

Unstructured:

  • CreateTagsFromZones

  • AddETagFromNTag

  • AddNodalTag

  • Remesh

  • CleanLonelyNodes

  • Create0DElements

Fields:

  • UpdateDistance

  • LevelSetTransfert/FieldTransfert

  • SetOriginalSupport

  • InitLevelset

  • LevelSetOffset

  • ChangePhiByZones

  • InitWith

  • LsStats

  • LsSupportLengthScale

  • LsQualityInfo

  • AddExterieursZeros

Optimization algorithm

  • RunAlgorithm

  • ResetTopoOp

Mesh Actions

  • WriteToFile

  • SaveShapeToFile

  • SetAllToInside

  • AddSkin

  • ETagFromNTag

  • AddEdges

  • SetAsRequired

  • CleanTags

  • CleanInternalFaces

  • DeleteZone

  • MirrorLevelSet