Commit bca7b615 authored by Lukas Riedel's avatar Lukas Riedel

Merge branch '123-add-input-of-boundary-segmentation' into 'master'

Resolve "Add input of boundary segmentation"

Closes #123

See merge request !119
parents c3fd7c01 b3272895
......@@ -25,6 +25,7 @@
grid functions of water content and velocity.
* Infrastructure for the input of Miller scaling fields. !110
* Add logging framework 'spdlog' as submodule !106
* Support input of boundary segmentations !119
### Changed
* `Simulation` is renamed `RichardsSimulation` and moved to
......
......@@ -45,6 +45,7 @@ dune_cmake_sphinx_doc(SPHINX_CONF ${CMAKE_CURRENT_SOURCE_DIR}/conf.py.in
man-installation.rst
man-config-file.rst
man-parameter-file.rst
man-grid.rst
MODULE_ONLY)
if(TARGET sphinx_html)
......
......@@ -76,28 +76,80 @@ adding an empty line, make text **bold** or ``monospaced``.
<values> int </values>
<suggestion> 0 </suggestion>
</parameter>
</category>
<parameter name="mappingFile">
<definition> The H5 file containing the mapping from cell to medium index.
Specify the dataset inside the file with the next key. Leave empty or
set to ``None`` for a global homogeneous medium. In this case,
``grid.globalIndex`` has to be specified.
<category name="grid.mapping">
<parameter name="file">
<definition> The H5 file containing all mapping datasets.
Leave empty or set to ``None`` for global mappings.
</definition>
<values> path </values>
<suggestion> None </suggestion>
<comment> This category is only used for 'rectangular' grids </comment>
</parameter>
<parameter name="mappingFileDataset">
<definition> The H5 dataset inside ``grid.mappingFile`` containing the
mapping from cell to medium index.
<parameter name="volume">
<definition> The H5 dataset containing the
mapping from cell to medium index. May specify a global index for the
entire volume if its value can be parsed as ``int``.
</definition>
<values> path </values>
<suggestion> 0 </suggestion>
<values> path or int </values>
</parameter>
<parameter name="globalIndex">
<definition> The medium index to use for all grid cells, if
``mappingFile`` is unset or ``None``.
<parameter name="boundaryLower">
<definition> The H5 dataset mapping the lower boundary faces to
boundary condition indices. May specify a global index for the
boundary if its value can be parsed as ``int``.
</definition>
<values> int </values>
<suggestion> 0 </suggestion>
<values> path or int </values>
</parameter>
<parameter name="boundaryUpper">
<definition> The H5 dataset mapping the upper boundary faces to
boundary condition indices. May specify a global index for the
boundary if its value can be parsed as ``int``.
</definition>
<suggestion> 1 </suggestion>
<values> path or int </values>
</parameter>
<parameter name="boundaryLeft">
<definition> The H5 dataset mapping the left boundary faces to
boundary condition indices. May specify a global index for the
boundary if its value can be parsed as ``int``.
</definition>
<suggestion> 2 </suggestion>
<values> path or int </values>
</parameter>
<parameter name="boundaryRight">
<definition> The H5 dataset mapping the right boundary faces to
boundary condition indices. May specify a global index for the
boundary if its value can be parsed as ``int``.
</definition>
<suggestion> 3 </suggestion>
<values> path or int </values>
</parameter>
<parameter name="boundaryFront">
<definition> The H5 dataset mapping the front boundary faces to
boundary condition indices (3D only). May specify a global index for
the boundary if its value can be parsed as ``int``.
</definition>
<suggestion> 4 </suggestion>
<values> path or int </values>
<comment> Only in 3D </comment>
</parameter>
<parameter name="boundaryBack">
<definition> The H5 dataset mapping the back boundary faces to
boundary condition indices (3D only). May specify a global index for
the boundary if its value can be parsed as ``int``.
</definition>
<suggestion> 5 </suggestion>
<values> path or int </values>
</parameter>
</category>
......
......@@ -48,6 +48,7 @@ Manual
man-installation
python-dorie-wrapper
man-config-file
man-grid
man-bcfile
man-cookbook
man-parameter-file
......
Grid Creation and Mapping
=========================
To guarantee numeric accuracy, :doc:`boundary conditions <man-bcfile>`
and :doc:`parameterizations <man-parameter-file>` must exactly map to grid
boundary faces and grid cells, respectively. DORiE therefore not only requires
a specification of the actual grid, but also of these mappings.
DORiE supports two types of grid input, which are controlled via the config
file parameter ``grid.gridType``:
1. Building a rectangular grid on the fly (``rectangular``).
Depending on whether grid adaptivity is enabled or not, DORiE will use
a structured or an unstructured grid manager. This does not change the input
scheme. The user has to specify the config parameters for ``[grid]``
``dimensions``, spatial ``extensions``, and grid ``cells`` in each
direction. For the mapping of boundary conditions and parameters,
:ref:`mapping datasets <man-grid_mapping-dataset>` are required.
2. Building a grid according to a GMSH grid file (``gmsh``).
This mode always uses an unstructured grid manager. The user only has to
specify the ``[grid]`` ``dimensions`` and the GMSH ``gridFile``.
The mapping is read from this file and must be considered when
:ref:`building the mesh <man-grid_gmsh>`.
.. _man-grid_mapping-dataset:
Mapping Datasets
----------------
Mappings are realized as HDF5_ datasets, where every value is mapped to a
single grid entity. Changing the grid configuration requires adapting these
datasets! All config keys of this part refer to the config section
``[grid.mapping]``. There is one dataset for the mapping of the soil
architecture (``volume``) and one dataset for each segment of the boundary
(``boundaryXYZ``). The datasets contain *integer* indices, which are then
identified with certain boundary conditions or parameterizations given by
the respective YAML input files. All mapping datasets must be stored inside
the same H5 file (``file``). Use the Python module ``h5py`` for easily
creating these data files.
The dataset layout follows the C memory layout, with the primary dimension
running fastest. The coordinate system is (right-hand) cartesian, with the
x-axis running to the right in both 2D and 3D.
All datasets follow the general layout ``array[z, y, x]``, where unused
dimensions are simply omitted. The first dimension is always the vertical axis.
The ``volume`` dataset must have the same dimension as the grid itself
(``grid.dimensions``), whereas the ``boundaryXYZ`` datasets are interpreted as
projections of the boundary in their respective normal direction, reducing the
dimension by one. The ``boundaryLower`` dataset would have the layout
``array[x]`` for a 2D grid, and ``array[y, x]`` for a 3D grid. Therefore,
``boundaryLower`` and ``boundaryUpper`` are "seen from above"
(3D-layout: ``array[y, x]``), and ``boundaryLeft`` and ``boundaryRight`` are
"seen from the right" (3D-layout: ``array[z, y]``).
The following Python code creates a volume mapping dataset ``layered`` in a
file ``mapping.h5``, where the lower half of the domain maps to medium 0,
and the upper half to medium 1. The 3D domain contains 10 cells in each
direction.
.. code-block:: python
import numpy as np
import h5py
# Create dataset. Mind the data type!
size = 10
layered = np.zeros((size, size, size), dtype=np.int_)
layered[5:, ...] = 1
# Write dataset to file in 'append' mode
with h5py.File("mapping.h5", 'a') as file:
file.create_dataset("layered", data=layered)
Homogeneous Mappings
^^^^^^^^^^^^^^^^^^^^
If the entire volume, or a complete boundary, should be mapped to a single
index, no dataset is required. Instead, you can set the value for the
respective config file parameter to the desired index. If no dataset should be
read at all, set ``file`` to ``none``.
Even with ``file`` set to a valid H5 file, DORiE will *always* try to
interpret the input values for ``grid.mapping`` as integers. If this succeeds,
the value is interpreted as "global" mapping index for the respective part
of the grid. Therefore, **do not use dataset names starting with digits!**
.. _man-grid_gmsh:
Mapping Soil Layers with GMSH
-----------------------------
GMSH_ supports mapping lines, surfaces, and volumes to *physical* entities.
These entities may combine multiple of the aforementioned *geometric*
entities. Physical entities are assigned a non-negative index upon creation.
These indices can be set by the user in any of the GMSH frontends.
Indices may not occur multiple times, even if they are assigned to different
types of physical entities.
The following ``.geo`` GMSH input file creates a rectangular domain that is
split in half. The lower part is mapped to index 1, the upper part to index 2.
Additionally, a different index for every boundary orientation is set. Notice
that the left and right boundaries consist of two *geometric* lines each.
This code can directly be transferred to a Python script using
the pygmsh_ module. It writes a ``.geo`` file while checking for a correct
syntax within your script. It is readily installed into the
:doc:`virtual environment <python-dorie-wrapper>`.
.. code-block:: default
// define geometric entities
Point(1) = {0, 0, 0, 0.1};
Point(2) = {2, 0, 0, 0.1};
Point(3) = {2, 2, 0, 0.1};
Point(4) = {0, 2, 0, 0.1};
Point(5) = {0, 1, 0, 0.1};
Point(6) = {2, 1, 0, 0.1};
Line(1) = {1, 2};
Line(2) = {2, 6};
Line(3) = {6, 3};
Line(4) = {3, 4};
Line(5) = {4, 5};
Line(6) = {5, 1};
Line(7) = {5, 6};
Line Loop(1) = {1, 2, -7, 6};
Plane Surface(1) = {1};
Line Loop(2) = {7, 3, 4, 5};
Plane Surface(2) = {2};
// define physical entities, index in round brackets
Physical Surface(1) = {1}; // lower
Physical Surface(2) = {2}; // upper
// entire set of physical entities must always be defined!
Physical Line(3) = {1}; // bottom
Physical Line(4) = {2, 3}; // right
Physical Line(5) = {4}; // top
Physical Line(6) = {5, 6}; // left
A ``.geo`` file is the basis for creating the actual mesh in GMSH. You can
load it into the GMSH GUI, or perform the meshing directly using the
`GMSH command line interface
<http://gmsh.info/doc/texinfo/gmsh.html#Non_002dinteractive-mode>`_:
gmsh <geo-file> -<dim>
Replace ``<geo-file>`` with the appropriate file, and ``dim`` with the
spatial dimension of the intended mesh.
.. _HDF5: https://www.h5py.org/
.. _GMSH: http://gmsh.info/
.. _pygmsh: https://pypi.org/project/pygmsh/
Soil Parameters and Architecture
================================
Soil Parameterization
=====================
Specifying the domain properties requires input of the soil architecture
Specifying the domain properties requires input of the
:doc:`soil architecture <man-grid>`
(in relation to the grid) and of the soil parameters. The latter incorporate
the *subscale physics*, the representation of the soil hydraulic properties
below the REV scale. DORiE requires several input files for retrieving this
......@@ -9,10 +10,8 @@ information, depending on the type of grid used for the computation.
A YAML_ parameter file is always required. It specifies a set of soil
parameterizations, along with a medium index. This index is used to reference
the medium specified in the architecture files. There are two types of these:
If you insert an unstructured grid with GMSH, you have to incorporate the
medium information. If you create a rectangular grid, you need to add a mapping
dataset, specifying the medium index for each (initial) grid cell.
the medium specified in the architecture files, or with the "global" indices
given in the config file.
Additionally, you can specify settings for the small-scale heterogeneities
of the soil. They require an input via H5 datasets that contain appropriate
......@@ -40,8 +39,8 @@ of scaling.
Every ``scaling_section`` has the same keys: The H5 filepath is given by
``file``, and the internal dataset path by ``dataset``. You can then choose an
``interpolation`` method for the dataset, which requires you to insert values
for the physical ``extensions`` of the dataset and the ``offset`` of its (front)
lower left corner from the grid origin.
for the physical ``extensions`` of the dataset and the ``offset`` of its
(front) lower left corner from the grid origin.
.. code-block:: yaml
......@@ -73,98 +72,6 @@ The parameterization ``type`` must match the static ``type`` member of one of
them. Likewise, the parameters must match the names of parameters
these objects use.
Medium Mapping Dataset
----------------------
This dataset is required when creating a rectangular grid, whether adaptive or
not. It has to be realized as dataset inside an HDF5_ file. The dataset must
have the same dimensions as the target grid, and must specify the medium index
for every cell of this grid. As all medium indices are integers, the dataset
must contain **integers, not floats**! An HDF5 file with such a dataset can
easily be created with the Python module ``h5py``.
The dataset layout follows the C memory layout, with the primary dimension
running fastest. A 3D HDF5 dataset or a 3D ``numpy`` array have the layout
``array[z][y][x]``, and 2D arrays have the layout ``array[y][x]``. The first
dimension is always the vertical axis.
The following Python code creates a dataset ``layered`` in a file
``mapping.h5``, where the lower half of the domain maps to medium 0, and the
upper half to medium 1. The 3D domain contains 10 cells in each direction.
.. code-block:: python
import numpy as np
import h5py
# Create dataset. Mind the data type!
size = 10
layered = np.zeros((size, size, size), dtype=np.int_)
layered[5:, ...] = 1
# Write dataset to file
with h5py.File("mapping.h5", 'a') as file:
f.create_dataset("layered", data=layered)
The dataset and the file containing it are specified in the
:doc:`config file <man-config-file>` via the keys ``grid.mappingFile`` and
``grid.mappingFileDataset``.
Homogeneous Media
^^^^^^^^^^^^^^^^^
In the special case of a globally homogeneous medium, you can omit the mapping
dataset. This is indicated by leaving ``grid.mappingFile`` undefined or setting
its value to ``None``. You can then define the medium index for the entire
domain with the key ``grid.globalIndex``, which is unused otherwise.
Mapping Soil Layers with GMSH
-----------------------------
GMSH_ supports mapping lines, surfaces, and volumes to *physical* entities.
These entities may combine multiple of the aforementioned *geometrical*
entities. Physical entities are assigned a non-negative index upon creation.
These indices can be set by the user in any of the GMSH frontends.
Indices may not occur multiple times, even if they are assigned to different
types of physical entities.
The following ``.geo`` GMSH input file creates a rectangular domain that is
split in half. The lower part is mapped to index 1, the upper part to index 2.
This code can directly tranferred to a Python script using the pygmsh_ module.
It writes a ``.geo`` file while checking for a correct syntax within your
script. It is readily installed into the
:doc:`virtual environment <python-dorie-wrapper>`.
.. code-block:: default
// define geometric entities
Point(1) = {0, 0, 0, 0.1};
Point(2) = {2, 0, 0, 0.1};
Point(3) = {2, 2, 0, 0.1};
Point(4) = {0, 2, 0, 0.1};
Point(5) = {0, 1, 0, 0.1};
Point(6) = {2, 1, 0, 0.1};
Line(1) = {1, 2};
Line(2) = {2, 6};
Line(3) = {6, 3};
Line(4) = {3, 4};
Line(5) = {4, 5};
Line(6) = {5, 1};
Line(7) = {5, 6};
Line Loop(1) = {1, 2, -7, 6};
Plane Surface(1) = {1};
Line Loop(2) = {7, 3, 4, 5};
Plane Surface(2) = {2};
// define physical entities, index in round brackets
Physical Surface(1) = {1}; // lower
Physical Surface(2) = {2}; // upper
// entire set of physical entities must always be defined!
Physical Line(3) = {1}; // bottom
Physical Line(4) = {2, 3}; // right
Physical Line(5) = {4}; // top
Physical Line(6) = {5, 6}; // left
Scaling Field Datasets
----------------------
One or more datasets in possibly multiple HDF5_ files are required for creating
......@@ -295,5 +202,3 @@ Their ``type`` and the names of their member parameters must match.
.. _YAML: https://gettaurus.org/docs/YAMLTutorial/
.. _HDF5: https://www.h5py.org/
.. _GMSH: http://gmsh.info/
.. _pygmsh: https://pypi.org/project/pygmsh/
This diff is collapsed.
This diff is collapsed.
......@@ -23,6 +23,8 @@ private:
using Logger = std::shared_ptr<spdlog::logger>;
//! The logger of this instance
const Logger _log;
//! The name of this file
const std::string _file_path;
//! ID of the H5 file
hid_t _file_id;
//! ID of the currently opened group
......@@ -38,6 +40,7 @@ public:
explicit H5File(const std::string& file_path,
const Logger log=get_logger(log_base)):
_log(log),
_file_path(file_path),
_file_id(-1),
_group_id(-1)
{
......@@ -69,7 +72,7 @@ public:
/// Close the H5 file when this object is destroyed
~H5File ()
{
_log->trace("Closing H5 file");
_log->trace("Closing H5 file: {}", _file_path);
// close the opened group
herr_t status = H5Gclose(_group_id);
......@@ -80,6 +83,9 @@ public:
assert(status > -1);
}
/// Return the file path of this object
std::string path () const { return _file_path; }
/// Open a group
/** \param group_path Full internal path to the group.
* Defaults to the base group.
......@@ -156,7 +162,7 @@ public:
dims.data(),
0);
assert(status > -1);
// log dataset extensions as read
_log->debug(" Dataset extensions: {}", to_string(dims));
......
// These groups should gather information strongly related portions of the code.
// These groups should gather information strongly related portions of the code.
// In them we aim to explain to other developers:
// - The rationale of the design
// - How careful someone has to be when modifying it
......@@ -31,10 +31,79 @@
beginning of any program like
auto [inifile, log, helper] = Dune::Dorie::Setup::init(argc, argv);
Notice that `helper` will be of *reference* type `Dune::MPIHelper &`.
@}
@defgroup Grid Grid Creation and Mapping Utilities
@{
@ingroup Common
@brief Classes for building grids and load-balancing mapping data
## Overview
DORiE offers a variety of grid setups which require different DUNE grid
managers and different setup routines. For structured rectangular grids,
we use `Dune::YaspGrid`, and for unstructured rectangular or simplex grids,
we use `Dune::UGGrid`.
In addition to the actual grid, DORiE also manages mappings of grid elements
(cells) and boundary segments to indices. These indices are used to refer to
medium layers in case of cells and boundary conditions in case of boundary
faces. Through the medium layer, a certain
\ref RichardsParam "hydraulic Parameterization" is applied to the
respective cell.
The Dorie::GridCreator builds a DUNE grid from the settings given in the
config file. It then internally assembles the Dorie::GridMapper which
loads the mapping data and load-balances it appropriately across all
processes if executed in parallel. The resulting local maps are retrieved
by the Dorie::GridCreator and can be queried by the user.
There are two general ways of constructing a grid:
1. Assembling an unstructured grid from a [GMSH](http://gmsh.info/)
file. This always uses `UGGrid`. GMSH has the capability of storing
grid element and boundary mappings and the `Dune::GmshReader` also loads
this information. It is then passed to the `GridMapper` and properly
load-balanced, as the `GmshReader` currently only works sequentially.
2. Building a rectangular grid with user-defined extensions and numbers
of cells in each direction. Depending on wether grid adaptivity was
enabled, this either creates a `UGGrid` or a `YaspGrid`. In both cases,
the user has to supply the mapping information separately. DORiE offers
two options here: Mapping a single ("global") index to all elements,
or reading a mapping dataset. This H5 dataset must have the same shape
as the grid. Each of its values maps to a single grid cell.
## Constructing The Grid
Initialize the grid creator with the config file settings. This will
automatically build the grid.
@code{.cc}
Dune::Dorie::GridCreator<GridType> grid_creator(config, helper);
@endcode
Retrieve a shared pointer to the grid from it. The grid will already be
properly load-balanced.
@code{.cc}
auto grid = grid_creator.grid();
@endcode
The index maps are managed by the `GridMapper`, which is created internally.
After initializing the `GridCreator`, they can be retrieved from it.
Notice that these maps only remain valid if the grid is **not load-balanced
any further** (e.g., after local grid refinement)!
@code{.cc}
auto element_index_map = grid_creator.element_index_map();
auto boundary_index_map = grid_creator.boundary_index_map();
@endcode
@}
@defgroup Logging Terminal Logging
@{
@ingroup Common
......@@ -110,11 +179,11 @@
Could not open file: filename.xyz
Parameter 'name' incompatible to setting 'value'
Bad:
name incompatible to value
Also, do not include the header `<spdlog/spdlog.h>` directly, but only the
respective logging header inside DORiE.
@}
......@@ -140,13 +209,13 @@
@{
Local operators are in many senses the heart of dorie; in them, we transform
finite element basis into a vector of residuals and a mass matrix taking into
account the specific equation and method we want to solve. These
account the specific equation and method we want to solve. These
transformations follow the structure of dune-pdelab. In particular,
some care has to be taken regarding the different frames of reference when
working with coordinates and gradients. It can get particularly messy
when working with intersections because one has to express the same
when working with intersections because one has to express the same
position/gradient with respect to the inside, outside, and face entities,
and sometimes with respect to the macro-grid (e.g. global coordinates).
and sometimes with respect to the macro-grid (e.g. global coordinates).
Therefore, in dorie we try to use the following suffixes convention :
| Convention | Meaning |
......@@ -157,9 +226,9 @@
| `<description>` + `_g` | `<description>` with respect to the **global** grid. |
| `<description>` + `_n` | `<description>` in **normal** direction. |
Notice that when working with gradients, the suffix for normal direction can
be combined with the first three suffixes (`_n_i`, `_n_o`, and `_n_f`). When
it's not specified, is understood that normal directions are referenced with
Notice that when working with gradients, the suffix for normal direction can
be combined with the first three suffixes (`_n_i`, `_n_o`, and `_n_f`). When
it's not specified, is understood that normal directions are referenced with
respect to the face (`_n` \f$\equiv\f$. `_n_f`).
@todo Update Dune::Dorie::Operator::RichardsDGSpatialOperator to the
......
#ifndef DUNE_DORIE_COMMON_UTILITY_HH
#define DUNE_DORIE_COMMON_UTILITY_HH
#include <string>
#include <algorithm>
#include <cctype>
#include <memory>
#include <dune/common/fvector.hh>
#include <dune/grid/common/gridview.hh>
namespace Dune {
namespace Dorie {
/// Retrieve the grid extensions as a position vector
/** Iterate over all vertices of the coarsest level grid view, determine the
* locally largest extensions and compute the maximum across all processes.
*
* \param grid Shared pointer to the grid
* \note This assumes the grid has rectangular shape and its origin
* is the origin of Euklidian space.
* \ingroup Grid
*/
template<typename Grid>
auto get_grid_extensions (const std::shared_ptr<Grid> grid)
-> Dune::FieldVector<typename Grid::ctype, Grid::dimension>
{
Dune::FieldVector<typename Grid::ctype, Grid::dimension> ret;
std::fill(ret.begin(), ret.end(), 0.0);
// iterate over all grid vertices
auto gv = grid->levelGridView(0);
for (auto&& vertex : vertices(gv)) {
const auto pos = vertex.geometry().center();
if (pos.two_norm() > ret.two_norm()) {
ret = pos;
}
}
// compute the maximum of all processes
auto& comm = grid->comm();
comm.max(&ret[0], ret.size());
// return the maximum vector
return ret;
}
/// Turn a string into lowercase characters
/** \param in Input string
* \return Lowercase output string
*/
inline std::string to_lower (const std::string& in)
{
std::string out = in;
std::transform(in.begin(), in.end(), out.begin(),
[](unsigned char c){ return std::tolower(c); }
);
return out;
}
/// Check if a string read as value from a file is none
/** Check if the input string is empty or its lowercase version is equal to
* `none`.
* \param in Input string to check
* \return True if the string is `none` or empty
*/
inline bool is_none (const std::string& in)
{
if (in.empty() or to_lower(in) == "none")
return true;
return false;
}
} // namespace Dorie
} // namespace Dune
#endif // DUNE_DORIE_COMMON_UTILITY_HH
......@@ -90,22 +90,21 @@ int main(int argc, char** argv)
{
if (gtype == "gmsh"){
Dune::Dorie::GridCreator<Dune::UGGrid<2>> grid_creator(inifile, helper);
auto grid_mapper = grid_creator.get_mapper();
switch(FEorder){
case 1:{
Sim<Simplex<2,1>> sim(richards_config, grid_mapper, helper);
Sim<Simplex<2,1>> sim(richards_config, grid_creator, helper);
sim.set_policy(adapt_policy);
sim.run();
break;
}
case 2:{
Sim<Simplex<2,2>> sim(richards_config, grid_mapper, helper);
Sim<Simplex<2,2>> sim(richards_config, grid_creator, helper);
sim.set_policy(adapt_policy);
sim.run();
break;
}
case 3:{
Sim<Simplex<2,3>> sim(richards_config, grid_mapper, helper);
Sim<Simplex<2,3>> sim(richards_config, grid_creator, helper);
sim.set_policy(adapt_policy);
sim.run();
break;
......@@ -117,22 +116,21 @@ int main(int argc, char** argv)
else if (gtype == "rectangular"){
if (adapt_policy != Dune::Dorie::AdaptivityPolicy::None) {
Dune::Dorie::GridCreator<Dune::UGGrid<2>> grid_creator(inifile, helper);
auto grid_mapper = grid_creator.get_mapper();
switch(FEorder){