Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ SCCXMAIN = ccx_$(CCX_VERSION).c

# Append additional sources
SCCXC += nonlingeo_precice.c dyna_precice.c CCXHelpers.c PreciceInterface.c
SCCXF += getflux.f getkdeltatemp.f
SCCXF += getflux.f getkdeltatemp.f getc3d8elementgausspointcoords.f getc3d4elementgausspointcoords.f



Expand Down
19 changes: 10 additions & 9 deletions adapter/CCXHelpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,16 @@ void getSurfaceElementsAndFaces(ITG setID, ITG *ialset, ITG *istartset, ITG *ien
}
}

void getElementsIDs(ITG setID, ITG *ialset, ITG *istartset, ITG *iendset, ITG *elements)
{
ITG i, k = 0;

for (i = istartset[setID] - 1; i < iendset[setID]; i++) {
elements[k] = ialset[i];
k++;
}
}

void getNodeCoordinates(ITG *nodes, ITG numNodes, int dim, double *co, double *v, int mt, double *coordinates)
{

Expand Down Expand Up @@ -219,15 +229,6 @@ void getHexaFaceCenters(ITG *elements, ITG *faces, ITG numElements, ITG *kon, IT
}
}

/*
void getSurfaceGaussPoints(int setID, ITG * co, ITG istartset, ITG iendset, ITG * ipkon, ITG * lakon, ITG * kon, ITG * ialset, double * coords) {

int iset = setID + 1; // plus one because of fortran indices
FORTRAN(getgausspointscoords,(co,&iset,istartset,iendset,ipkon,lakon,kon,ialset, coords));

}
*/

void getTetraFaceNodes(ITG *elements, ITG *faces, ITG *nodes, ITG numElements, ITG numNodes, ITG *kon, ITG *ipkon, int *tetraFaceNodes)
{
// Assume all tetra elements -- maybe implement checking later...
Expand Down
10 changes: 10 additions & 0 deletions adapter/CCXHelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,16 @@ ITG getSetID(char const *setName, char const *set, ITG nset);
*/
ITG getNumSetElements(ITG setID, ITG *istartset, ITG *iendset);

/**
* @brief Gets the element IDs given a set ID
* @param setID: input set id
* @param ialset: CalculiX variable
* @param istartset: CalculiX variable
* @param iendset: CalculiX variable
* @param elements: output element IDs
*/
void getElementsIDs(ITG setID, ITG *ialset, ITG *istartset, ITG *iendset, ITG *elements);

/**
* @brief Gets the element and face IDs given a set ID
* @param setID: input set id
Expand Down
4 changes: 4 additions & 0 deletions adapter/ConfigReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ void ConfigReader_Read(char const *configFilename, char const *participantName,
interface.facesMeshName = NULL;
}

if (config["participants"][participantName]["interfaces"][i].contains("elements-mesh")) {
interface.elementsMeshName = strdup(config["participants"][participantName]["interfaces"][i]["elements-mesh"].get_value<std::string>().c_str());
}

if (config["participants"][participantName]["interfaces"][i].contains("mesh")) {
interface.facesMeshName = strdup(config["participants"][participantName]["interfaces"][i]["mesh"].get_value<std::string>().c_str());
}
Expand Down
1 change: 1 addition & 0 deletions adapter/ConfigReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
typedef struct InterfaceConfig {
char * facesMeshName;
char * nodesMeshName;
char * elementsMeshName;
char * patchName;
int map;
int numWriteData;
Expand Down
60 changes: 58 additions & 2 deletions adapter/PreciceInterface.c
Original file line number Diff line number Diff line change
Expand Up @@ -450,8 +450,8 @@ void Precice_FreeData(SimulationData *sim)
void PreciceInterface_Create(PreciceInterface *interface, SimulationData *sim, InterfaceConfig const *config)
{
// Deduce configured dimensions
if (config->nodesMeshName == NULL && config->facesMeshName == NULL) {
printf("ERROR: You need to define either a face or a nodes mesh. Check the adapter configuration file.\n");
if (config->nodesMeshName == NULL && config->facesMeshName == NULL && config->elementsMeshName == NULL) {
printf("ERROR: You need to define either a face, nodes, or elements mesh. Check the adapter configuration file.\n");
exit(EXIT_FAILURE);
}
if (config->nodesMeshName && config->facesMeshName) {
Expand All @@ -473,6 +473,8 @@ void PreciceInterface_Create(PreciceInterface *interface, SimulationData *sim, I

// Initialize pointers as NULL
interface->elementIDs = NULL;
interface->elemIPID = NULL;
interface->elemIPCoordinates = NULL;
interface->faceIDs = NULL;
interface->faceCenterCoordinates = NULL;
interface->preciceFaceCenterIDs = NULL;
Expand Down Expand Up @@ -545,6 +547,14 @@ void PreciceInterface_Create(PreciceInterface *interface, SimulationData *sim, I
interface->couplingMeshName = interface->faceCentersMeshName;
}

// Element mesh
interface->elementsMeshName = NULL;
if (config->elementsMeshName) {
interface->elementsMeshName = strdup(config->elementsMeshName);
PreciceInterface_ConfigureElementsMesh(interface, sim);
interface->couplingMeshName = interface->elementsMeshName;
}

PreciceInterface_ConfigureCouplingData(interface, sim, config);
}

Expand All @@ -567,6 +577,48 @@ static enum ElemType findSimulationMeshType(SimulationData *sim)
return INVALID_ELEMENT;
}

void PreciceInterface_ConfigureElementsMesh(PreciceInterface *interface, SimulationData *sim)
{
char *elementSetName = interface->name;
interface->elementSetID = getSetID(elementSetName, sim->set, sim->nset);
interface->numElements = getNumSetElements(interface->elementSetID, sim->istartset, sim->iendset);

interface->elementIDs = malloc(interface->numElements * sizeof(ITG));
getElementsIDs(interface->elementSetID, sim->ialset, sim->istartset, sim->iendset, interface->elementIDs);

interface->numIPTotal = sim->mi[0] * interface->numElements; // Number of Gauss points per element * number of elements
interface->elemIPCoordinates = malloc(interface->numIPTotal * 3 * sizeof(double));

interface->elemIPID = malloc(interface->numIPTotal * sizeof(int));
for (int j = 0; j < interface->numIPTotal; j++) {
interface->elemIPID[j] = j;
}

int numElements = interface->numElements;

enum ElemType elemType = findSimulationMeshType(sim);

if (elemType == TETRAHEDRA) {
FORTRAN(getc3d4elementgausspointcoords, (&numElements,
interface->elementIDs,
sim->co,
sim->kon,
sim->ipkon,
interface->elemIPCoordinates));
} else if (elemType == HEXAHEDRA) {
FORTRAN(getc3d8elementgausspointcoords, (&numElements,
interface->elementIDs,
sim->co,
sim->kon,
sim->ipkon,
interface->elemIPCoordinates));
} else {
supportedElementError();
}

precicec_setMeshVertices(interface->elementsMeshName, interface->numIPTotal, interface->elemIPCoordinates, interface->elemIPID);
}

void PreciceInterface_ConfigureFaceCentersMesh(PreciceInterface *interface, SimulationData *sim)
{
// printf("Entering ConfigureFaceCentersMesh \n");
Expand Down Expand Up @@ -803,7 +855,10 @@ void PreciceInterface_FreeData(PreciceInterface *preciceInterface)
free(preciceInterface->readData);
free(preciceInterface->writeData);
free(preciceInterface->elementIDs);
free(preciceInterface->elemIPID);
free(preciceInterface->elemIPCoordinates);
free(preciceInterface->faceIDs);
free(preciceInterface->nodeIDs);
free(preciceInterface->preciceFaceCenterIDs);
free(preciceInterface->faceCenterCoordinates);
free(preciceInterface->nodeCoordinates);
Expand All @@ -822,6 +877,7 @@ void PreciceInterface_FreeData(PreciceInterface *preciceInterface)
// Mesh names
free(preciceInterface->faceCentersMeshName);
free(preciceInterface->nodesMeshName);
free(preciceInterface->elementsMeshName);

// Data names
free(preciceInterface->displacementDeltas);
Expand Down
14 changes: 13 additions & 1 deletion adapter/PreciceInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,15 @@ typedef struct PreciceInterface {
int nodeSetID;
int * preciceNodeIDs;
char * nodesMeshName;
char * elementsMeshName;

// Interface face elements
int numElements;
int * elementIDs;
int * elemIPID;
int elementSetID;
double *elemIPCoordinates;
int numIPTotal;

int * faceIDs;
double *faceCenterCoordinates;
int faceSetID;
Expand Down Expand Up @@ -277,6 +282,13 @@ void sendFaceCentersVertices(PreciceInterface *interface);
*/
void PreciceInterface_ConfigureNodesMesh(PreciceInterface *interface, SimulationData *sim);

/**
* @brief Configures the elements mesh and calls setMeshVertices on preCICE
* @param interface
* @param sim: Structure with CalculiX data
*/
void PreciceInterface_ConfigureElementsMesh(PreciceInterface *interface, SimulationData *sim);

/**
* @brief Terminate execution if the nodes mesh ID is not valid
* @param interface
Expand Down
29 changes: 28 additions & 1 deletion docs/adapter-calculix-configure.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,19 @@ precice-config-file: ../precice-config.xml
The adapter allows us to use several participants in one simulation (e.g., several instances of Calculix if several solid objects are taken into account). The name of the participant `Calculix` must match the specification of the participant on the command line when running the executable of `CCX` with the adapter being used (this is described later). Also, the name must be the same as the one used in the preCICE configuration file `precice-config.xml`.

One participant may have several coupling interfaces. Note that each interface specification starts with a dash.
Depending on the data you need to read and write, the interface should define either a `faces-mesh` (or `mesh` as a synonym) where the data points are centers of faces (computed by the adapter) or a mesh made of CalculiX vertices, with the keyword `nodes-mesh`. An interface made of faces should be defined in the CalculiX case using the `*SURFACE` command, whereas meshes with nodes should define these nodes using `*NSET`. Using the wrong family of mesh (e.g. reading forces on faces) throws an error. If you need both kinds of meshes, you should define more than one interface.
Depending on the data you need to read and write, the interface should define a mesh of the following types

* a `faces-mesh` (or `mesh` as a synonym) where the data points are centers of faces (computed by the adapter). An interface made of faces should be defined in the CalculiX case using the `*SURFACE` command.
* a `nodes-mesh` where the data points are the nodal vertices. An interface made of nodes should define these nodes using `*NSET`.
* a `elements-mesh` where the data points are the quadrature points of the elements of a mesh. The mesh should be defined by nodes using `*NEST`.

Using the wrong family of mesh (e.g. reading forces on faces) throws an error. If you need both kinds of meshes, you should define more than one interface.

For FSI simulations the mesh type of an interface is always `nodes-mesh`, as forces and displacement are defined on nodes. The name of this mesh, `Calculix_Mesh`, must match the mesh name given in the preCICE configuration file. In CHT simulations, `faces-meshes` are usually chosen, as they are needed to apply heat fluxes or convective heat transfer.
For defining which nodes of the CalculiX domain belong to the FSI interface, a node set needs to be defined in the CalculiX input files. The name of this node set must match the name of the patch (here: "interface").

For multiscale mechanics simulations, the mesh type is always `elements-mesh`. The stresses, strains, and the material stiffness are defined on the quadrature points.

In the current FSI example, the adapter reads forces from preCICE and feeds displacement deltas (not absolute displacements, but the change of the displacements relative to the last time step) to preCICE. This is defined with the keywords `read-data` and `write-data`, respectively. The names (here: `Forces` and `DisplacementDeltas`) again need to match the specifications in the preCICE configuration file. In the current example, the coupled fluid solver expects displacement deltas instead of displacements. However, the adapter is capable of writing either type. Just use `write-data: [Displacements]` for absolute displacements rather than relative changes being transferred in each time step. Valid `readData` keywords in CalculiX are:

On faces-mesh:
Expand All @@ -45,6 +53,18 @@ On nodes-mesh:
* Displacements (Use `*BOUNDARY`)
* Temperature (Use `*BOUNDARY`)

On elements-mesh:

* stresses1to3 (components (1,1), (2,2), (3,3) of the stress tensor)
* stresses4to6 (components (2,3), (1,3), (1,2) of the stress tensor)
* cmat1 (components (1,1), (1,2), (1,3) of the material stiffness tensor)
* cmat2 (components (1,4), (1,5), (1,6) of the material stiffness tensor)
* cmat3 (components (2,2), (2,3), (2,4) of the material stiffness tensor)
* cmat4 (components (2,5), (2,5), (3,3) of the material stiffness tensor)
* cmat5 (components (3,4), (3,5), (3,6) of the material stiffness tensor)
* cmat6 (components (4,4), (4,5), (4,6) of the material stiffness tensor)
* cmat7 (components (5,5), (5,6), (6,6) of the material stiffness tensor)
Comment on lines +56 to +66
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Open discussion in the original PR: precice/precice.github.io#530 (comment)

Current state: some cleanup is needed to focus on the feature of this PR vs the feature introduced with #135.

Let's continue the discussion here.


Have a look at the CalculiX documentation for a detailed description of each of these commands. There is an [online (but outdated) version](https://web.mit.edu/calculix_v2.7/CalculiX/ccx_2.7/doc/ccx/node1.html) and an [up-to-date PDF version](http://www.dhondt.de/ccx_2.19.pdf).

Valid `writeData` keywords are:
Expand All @@ -70,6 +90,11 @@ From CalculiX version 2.15, additional `writeData` keywords are available:
* Velocities
```

On elements-mesh:

* strains1to3 (components (1,1), (2,2), (3,3) of the strain tensor)
* strains4to6 (components (2,3), (1,3), (1,2) of the strain tensor)

Note that the square brackets imply that several read- and write-data types can be used on a single interface. This is not needed for FSI simulations (but for CHT simulations). Lastly, the `precice-config-file` needs to be identified including its location. In this example, the file is called `precice-config.xml` and is located one directory above the folder, in which the YAML configuration file lies.

## CalculiX case input file
Expand Down Expand Up @@ -144,6 +169,8 @@ The preCICE CalculiX adapter should support most elements when using `nodes-mesh

When using face meshes, only tetrahedra and hexahedra are supported.

When using `elements-mesh`, linear tetrahedral (C3D4) and hexahedral (C3D8) elements are supported.

### Coupling to 2D simulations

The adapter supports quasi 2D simulations when the z-direction is ignored. If you set the preCICE interface dimension to 2, the adapter will map data from the CalculiX 3D simulation to 2D space and vice-versa. The 3D simulation should be made of solid elements (or shells) of unit thickness.
Expand Down
2 changes: 1 addition & 1 deletion docs/adapter-calculix-overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ The latest supported CalculiX version is {{site.calculix_version}}. If you alrea

## History

The adapter was initially developed for conjugate heat transfer (CHT) simulations via preCICE by Lucia Cheung in the scope of her master’s thesis[^1], in cooperation with [SimScale](https://www.simscale.com/). For running the adapter for CHT simulations refer to this thesis. The adapter was extended to fluid-structure interaction by Alexander Rusch[^2].
The adapter was initially developed for conjugate heat transfer (CHT) simulations via preCICE by Lucia Cheung in the scope of her master’s thesis[^1], in cooperation with [SimScale](https://www.simscale.com/). For running the adapter for CHT simulations refer to this thesis. The adapter was extended to fluid-structure interaction by Alexander Rusch[^2]. The adapter was further extended for volumetric coupling of multiscale mechanics problems by Ibrahim Kaleel and Ishaan Desai.

## References

Expand Down
86 changes: 86 additions & 0 deletions getc3d4elementgausspointcoords.f
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume that these two files contain changes compared to the original CalculiX files. A comment on the modifications would be very helpful when porting to later versions.

Was the functionality provided by the deleted file never needed, or is it just substituted by the two new files?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume that these two files contain changes compared to the original CalculiX files. A comment on the modifications would be very helpful when porting to later versions.

Yes, the contents of both the new Fortran files is essentially copied from the CalculiX source code. Additionally I put some of my own code in there. I will add comments in the file.

Was the functionality provided by the deleted file never needed, or is it just substituted by the two new files?

The functionality in the deleted file was not used. I tried to use it, but the Gauss point coordinates returned by it were not correct. Hence the decision to remove the file and add two separate files for two different elements. it id worth noting that in the future, these two files can be merged.

Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
!
! CalculiX - A 3-dimensional finite element program
! Copyright (C) 1998-2015 Guido Dhondt
!
! This program is free software; you can redistribute it and/or
! modify it under the terms of the GNU General Public License as
! published by the Free Software Foundation(version 2);
!
!
! This program is distributed in the hope that it will be useful,
! but WITHOUT ANY WARRANTY; without even the implied warranty of
! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
! GNU General Public License for more details.
!
! You should have received a copy of the GNU General Public License
! along with this program; if not, write to the Free Software
! Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
!
! This function is a copy of the function for calculation and printout of the lift and drag forces
!
subroutine getc3d4elementgausspointcoords(nelem, elem_ids,
& co, kon, ipkon, elem_gp_coord)

implicit none

!Input/Output variables
integer :: nelem ! Number of elements
integer :: elem_ids(*) ! Element IDs, need to be adjusted for Fortran
real(8) :: co(3,*) ! Nodal coordinates of all nodes
integer :: kon(*)
integer :: ipkon(*)

real(8) :: elem_gp_coord(*) ! Gauss point coords

! Internal variables
integer(4) :: iel, el_id, indexe, i, j, k, l
integer(4) :: iflag, idx, konl(4), gp_id
REAL(8) :: xl(3,4), xi, et, ze, xsj, shp(4,20)

include "gauss.f"

data iflag /1/

! Initialize gauss point coordinates to zero
do l = 1, nelem*3
elem_gp_coord(l) = 0.0
end do

do iel = 1, nelem
el_id = elem_ids(iel)

indexe=ipkon(el_id)

! Local nodal coordinates
do i = 1, 4
konl(i) = kon(indexe+i)
do j = 1, 3
xl(j,i)=co(j,konl(i))
end do
end do

! One Gauss point per element
gp_id = 1

! gauss3d4: tet, 1 integration point
xi = gauss3d4(1,gp_id)
et = gauss3d4(2,gp_id)
ze = gauss3d4(3,gp_id)

! Get the shape function
call shape4tet(xi,et,ze,xl,xsj,shp,iflag)

! Calculate the Gauss point coordinates
do k = 1, 3
idx = (iel - 1) * 3 + k
do l = 1, 4
elem_gp_coord(idx)=elem_gp_coord(idx)
& +xl(k,l)*shp(4,l)
end do
end do

end do

return

end subroutine getc3d4elementgausspointcoords
Loading