next up previous
Next: Post-processing Up: neBEM toolkit - a Previous: Device without use of

Device using input files

Next, let us discuss an example where we create a device ab initio. Let us consider developing a device that has one rectangle, one triangle and one wire primitive. As you can see from the driver and interface source codes, there is hardly any difference from the earlier one we just finished discussing. So, we will rather concentrate on the main differences in the interfacing routines.

As expected, the variable OptDeviceFile is set to a non-zero value and the DeviceInputFile string is assigned a string constant that is, in fact, the name of the file that contains the device details. This prompts the neBEMIntitialize function to invoke a routine called (neBEMGetInputsFromFile). This routine, in this example, simply uses the supplied file to read all the necessary details as temporary variables (implied by tmp in all the variable names). The neBEM global variables necessary for setting up the solution procedure are assigned values from these temporary variables. The rest of the procedure is identical to the one discussed in the earlier sub-section.

One additional question remains. How do we generate the DeviceInputFile for a realistic device with several inter-related components? Since this step is in no way related to the neBEM toolkit, this depends entirely on the user. However, just to provide a convenient point of departure, we have provided some examples that can be used as templates. Let us consider the problem related to the Applications/ExampleDevice.c source code. This hypothetical device has one rectangular flat plate, one triangular flat plate and a wire. The reason for including these shapes is the fact that, at present, these are the primitive shapes that are directly allowed by the neBEM toolkit. In addition, since any three dimensional device can be represented by a combination of these three types of primitives, if the user knows how to set up these primitives, she / he should be able to set any device at all. So, let us concentrate on the device generation code related to Applications/ExampleDevice.c. This source code can be found in the Devices sub-directory and is named ExampleDevice.c as well.

Any device is composed of primitives of two kinds: wire (1D) and flat surface (2D). The flat surfaces can be either right triangular and rectangular. In the case of a right triangular primitive, a sequence is maintained such that the second vertex is the right corner. By definition, primitive of the first kind can be used to represent only few very special geometries. On the other hand, the second kind can represent 3D geometries of any kind.

While defining the device, it is also important to define the volumes that define any given primitive. This is so because, the boundary conditions applicable to an interface depends on the properties of the volumes on its either side. So, each primitive has two volumes associated to it. As a result, it is important to identify the volumes that we need to supply in order to completely specify the problem. In addition, please note that primitives should be defined such that they are at the interface of two volumes only.

The input files are defined in the following manner: A device input directory contains all the information for a device under study, one subdirectory for each model representation; the model subdirectories in their turn contain files that store data on each of the primitives, the volume files and the map file. In the present example, ExampleDevice is the device directory. The rest of the files are kept in a directory called Model1 while details of the device is given in the Model1.inp file. The device directory is assumed to be already existing.

/* ExampleDevice.c */
// An example that creates three primitives:
// a rectangular plane, a right triangular plane and a wire 

int main(void)
{
char DeviceInDirName[256], DeviceInFileName[256], ModelName[256], DeviceOutDirName[256];
char *homedir;
homedir = getenv("HOME");
assert(homedir != NULL);
printf("user homedir is %s\n", homedir);
strcpy(DeviceInDirName, homedir);
strcat(DeviceInDirName, "/Inputs/ExampleDevice/");  // existing
strcpy(ModelName, "Model1");  // do NOT put an appending /
strcpy(DeviceOutDirName, homedir);
strcat(DeviceOutDirName, "/Outputs/ExampleDevice/");
strcat(DeviceOutDirName, ModelName);
strcat(DeviceOutDirName, "/");

char DeviceInDir[256], ModelSubDir[256], ModelInDir[256];
FILE *fModelInp;
strcpy(DeviceInDir, DeviceInDirName); // existing directory
strcpy(ModelSubDir, ModelName); // to be created
fModelInp = PrepareInputFiles(DeviceInDir, ModelSubDir,
                              DeviceInFileName, ModelInDir);

FILE *fData;
fData = PrepareViewingFiles(ModelInDir);

// Create volume reference data
{
void CreateVolume(char ModelInDir[], int VolRef,
                  int VolShape, int VolMaterial, int VolBoundaryType,
                  double VolEpsilon, double VolPotential, double VolCharge);
}	// Volume creation ends

// Component 1 - a rectangular plate
{
// a rectangular plate
{
CreatePolygon(fModelInp, fData, ModelInDir,
							NbPrimitives,
							nvertex, xvert, yvert, zvert,
							xnorm, ynorm, znorm,
							VolRef1, VolRef2, NbXSegs, NbYSegs,
							PeriodicInX, XPeriod, PeriodicInY, YPeriod, PeriodicInZ, ZPeriod);

}	// RectangularPlate ends
}	// Component 1 ends

// Component 2 - a triangular plate
{
// a triangular plate
{
CreatePolygon(fModelInp, fData, ModelInDir,
							NbPrimitives,
							nvertex, xvert, yvert, zvert,
							xnorm, ynorm, znorm,
							VolRef1, VolRef2, NbXSegs, NbYSegs,
							PeriodicInX, XPeriod, PeriodicInY, YPeriod, PeriodicInZ, ZPeriod);
}	// TriangularPlate ends
} Component 2 ends


Component 3 - a thin wire
{
// a thin wire
{
CreateLine(fModelInp, fData, ModelInDir,
							NbPrimitives,
							nvertex, xvert, yvert, zvert,
							radius, VolRef1, VolRef2, NbSegs,
							PeriodicInX, XPeriod, PeriodicInY, YPeriod, PeriodicInZ, ZPeriod);

}	// wire ends
} Component 3 ends


// data that goes into the Map files
{
CreateMapFile(ModelInDir,
               NbMaps, NbBlock,
               NbXMap, NbYMap, NbZMap,
               MapLX, MapLY, MapLZ,
               MapXMid, MapYMid, MapZMid,
               NbLines, NbSegments,
               XStart, YStart, ZStart, XStop, YStop, ZStop,
               NbPoints, XPoint, YPoint, ZPoint);
}	// Map creation ends


// Complete the DeviceInputFile
int NbBCondns = 1;
EndDeviceInputFile(fModelInp, NbBCondns,
										DeviceOutDirName, ModelInDir, NbPrimitives);

return 0;
}	// ExampleDevice.c main ends

The directory structure including the model name are user inputs. These can be read in from an input file or hash-defined, if desired. One point to be noted is that the ModelName should not be appended by a trailing despite the fact that this name is eventually used to form the sub-directory name in which the primitives related to this particular model is stored. Most of the other user-inputs, such as dimensions and locations of the primitives, outward normal on them can be hard-coded or, even better, for a truly elaborate device, a separate input file may be used. Another option could be to have ".def" file which is #included at the beginning of a device code, as has been done in the micromegas device codes. The convenience of using separate def or input files is to avoid scrolling too often. There can, of course, be many such files possibly representing each component of a device.

For this analysis, there are six volumes which is really quite arbitrary. The other examples have a more realistic design as far as volumes are concerned. Here it assumed that the rectangular surface is at the interface of two volumes (1 and 2) The triangular surface is at the interface of two volumes (3 and 4) The wire surface is at the interface of two volumes (5 and 6) Vacuum (VolRef: 1), Conductor 1 (VolRef: 2) Dielectric 1 (VolRef: 3), Dielectric 2 (VolRef: 4) Gas (VolRef: 5), Conductor 2 (VolRef: 6) The surfaces that define the device are interfaces between these volumes. Explanation of the different parameters of the CreateVolume function is given below:

InterfaceType Value
VolRef n-th volume, to be used as a referral number.
VolShape does not have any effect now.
VolMaterial 1-10, if conductor; 11-20, if a dielectric.
VolBoundaryType equivalent to the Interface type described above.
VolEpsilon relative dieletric.
VolPotential applied potential on this volume.
VolCharge applied charge density on the interfaces of this volume.

The generic function calls for creation of volumes and primitives have been shown here while the details are available in the source code. Please note that the second vertex is expected to be the right-corner. In most of these calls, two file handler are being passed - one for the input file and the other for creating a gnuplot-friendly datafile. The rest of the arguments are self-explanatory.

After the creation of the volumes and primitives, a map file is created that allows the user to evaluate properties on maps (2D grids), along lines and at given points. There can be as many 2D grids, lines and points as are needed. The maps are created based on their lengths along X, Y and Z and the mid-points of these maps. Points at which the properties are evaluated naturally do not need these information.

Finally, a few more important information is written into the DeviceInputFile and it is closed as the program stops execution. One of the important information here is the number of boundary conditions to be used per element. At a later stage, we plan to incorporate ability to tackle over-determined sets of problems through this integer. At present, the number of boundary conditions per element is fixed as one.

At the end of execution, all the files related to the device are created. These may be easily used by neBEMGetInputsFromFiles to carry out necessary computations.


next up previous
Next: Post-processing Up: neBEM toolkit - a Previous: Device without use of
Supratik Mukhopadhyay 2019-03-05