ICBC stands for Initial Conditions Boundary conditions. It is a set of generic classes for defining the right hand side, the value of the initial condition, the value and type of the boundary conditions, the exact solution (if exists), bathymetry, manning, wind, pulse, atmospheric pressure or spectral waves.
These inputs can be inquired using an ICBC file combined with a configuration file (see Configuration file for keys to fulfill) or using only the configuration file (see Using Uhaina in Operational mode section).
The advantage of using an ICBC file is that you can implement standard inputs thanks to analytic formula that suits well academic cases and so help the validation. But Uhaina has to be recompile and a new executable has to be rebuild. It can be problematic in an industrial context because all users have to use a unique executable for consistency in the results.
We advice users to use ICBC file only for academic applications when integrating and validating new fonctionalities, designing pre-defined functions for Operational mode etc. If the user wants to run realistic test cases, he should use in Uhaina in Operational mode.
For more information about ICBC you can go to the following link https://gitlab.inria.fr/aerosol/aerosol/-/wikis/Boundary-conditions/How-to-create-an-icbc-file-to-define-the-boundary-conditions (lib/include/icbc/IcbcInterface.hpp
file (
Base template file for Icbc file
/*
* MyICBC.hpp
*
* An Icbc file for test case MyICBC
*
* Author:
* Date:
*
* Description:
*/
#ifndef MYICBC__HPP
#define MYICBC__HPP
#include "icbc/IcbcInterface.hpp"
namespace ICBC {
class MyICBC : public IcbcInterface {
public:
MyICBC()
{
}
}; // class MyICBC
} // namespace ICBC
#endif // MYICBC
To create your ICBC you should replace MyICBC
by a name relative to your test case. For example we will replace MyICBC
by Bump1d
.
Into the MyICBC
class constructor - i.e. MyICBC() {}
- you have to specify your ICBC behavior. For this you have access to several methods :
void setRHSFunc(FFuncT f);
void setExactFunc(FFunc f);
void setDataVariable(const std::string& dataVarName, FFunc f); // "dataVarName" can be bathymetry, manning, initialSolution.
void setTDataVariable(const std::string& dataVarName, FFuncT f); // "dataVarName" can be pressure, wind, pulse, spectralWaves.
void setDistance(FFunc f);
void addBoundary(int color, const std::string& name, FFuncT boundTimeFunc = NULL);
void addPeriodicBoundary(int color1, int color2, Isometry iso);
You don't have to use them all, use only the ones you need.
Notice there are 2 special parameter types FFunc
and FFuncT
.
typedef void(* FFunc) (const Coord3 &pos, const Real *const params, Real *vect);
typedef void(* FFuncT) (const Coord3 &pos, const Real &time, const Real *const params, Real *vect);
More precisely, FFunc
is for stationary functions, whereas FFuncT
is for defining functions that may be unstationary. Functions defining initialization, exact solution, bathymetry, manning, distance must have a FFunc
shape. Functions defining a right hand side, the boundary solution, pressure, wind, pulse, spectralWaves must have a FFuncT
shape, even if they do not depend on the time.
It is possible to put them inside your MyICBC
class, with
class MyICBC : public IcbcInterface {
public:
MyICBC() {}
// Note static attributes
static void funcInitMyIcbc(const Coord3& c, const Real* const params, Real * solution) {}
static void funcBoundaryMyIcbc(const Coord3& c, const Real& time,const Real* const params, Real * solution) {}
}; // class MyICBC
Or you can define them outside the class like it is done in most the examples in the test case section. For example the Bump1d case becomes:
// Class declaration
class Bump1d : public IcbcInterface {
public:
// Class constructor
Bump1d()
{
setDataVariable("bathymetry", funcBathymetryBump1d);
setExactFunc( &funcExactBump1d );
setRHSFunc( NULL );
setDataVariable("initialSolution", funcInitBump1d);
addBoundary( 1 , "RII_NonReflective" , &funcBoundaryBump1d );
addBoundary( 2 , "RII_NonReflective" , &funcBoundaryBump1d );
}
// Static function
static void funcBathymetryBump1d(const Coord3& c, const Real * const params, Real * solution) {
double x = c[0];
double z = 0.;
double mu = 10.;
double sigma = 1.;
z += 0.5 / (sigma * sqrt(2. * M_PI)) * exp(-0.5 * ((x - mu) / sigma) * ((x - mu) / sigma));
solution[0] = z;
}
// Static function
static void funcInitBump1d(const Coord3& c, const Real* const params, Real * solution)
{
[...]
}
// Static function
static void funcBoundaryBump1d(const Coord3& c, const Real& time,const Real* const params, Real * solution)
{
[...]
}
}; // class Bump1d
In this example, Initial conditions and bathymetry are described by a FFunc
and boundary condition by a FFuncT
. In these function implementations, solution
values should be setted. Form of solution
is model dependent.
The other inputs as well as the initialization are defined the same way using setDataVariable
or setTDataVariable
depending if the variable is time dependent or not and by changing the variable key word. Here is an example of a more complex test cases:
public:
AuthieBay() {
setDataVariable("bathymetry", funcBathymetryAuthieBay);
setDataVariable("manning", funcManningAuthieBay);
setDataVariable("initialSolution", funcInitAuthieBay);
setTDataVariable("wind", funcWindAuthieBay );
setTDataVariable("pressure", funcPressureAuthieBay );
setExactFunc( NULL );
setRHSFunc( NULL );
addBoundary( 2 , "WHI_Reflective" , &funcBoundaryAuthieBayTide );
addBoundary( 3 , "Wall" , NULL );
addBoundary( 4 , "Discharge_NonReflective" , &funcBoundaryAuthieBayRiver );
}
~AuthieBay() { }
};
The boundary conditions in a similar way are defined using addBoundary
where the first argument of the function is the boundary color, then the boundary type (see List of boundary conditions) and the boundary static function representing the signal to imposed.
After your ICBC file has been created (icbc_NewCase.hpp for example), you have to include it into the main.cpp
.
#include "icbc_NewCase.hpp"
else if (castest == "NewCase")
icbc = new ICBC::NewCase;
The key word (castest == "NewCase")
is the test case name given in the config file and icbc = new ICBC::NewCase;
is the name of the new ICBC class constructor (MyICBC
) the user just created in the file icbc_NewCase.hpp.
Then don't forget to recompile the program, by running make; make install
from the aerosol/build
folder.
See the test cases section for more examples.