diff --git a/DDSegmentation/include/DDSegmentation/TiledLayerGridXY.h b/DDSegmentation/include/DDSegmentation/TiledLayerGridXY.h
new file mode 100644
index 0000000000000000000000000000000000000000..3f23db73f49a9ed859de59a9deb59fca3eb7b381
--- /dev/null
+++ b/DDSegmentation/include/DDSegmentation/TiledLayerGridXY.h
@@ -0,0 +1,114 @@
+/*
+ * TiledLayerGridXY.h
+ *
+ *  Created on: November 12, 2015
+ *      Author: Shaojun Lu, DESY
+ */
+
+#ifndef DDSegmentation_TILEDLAYERGRIDXY_H_
+#define DDSegmentation_TILEDLAYERGRIDXY_H_
+
+#include "DDSegmentation/CartesianGrid.h"
+
+// C/C++ includes
+#include <string>
+#include <vector>
+
+namespace DD4hep {
+namespace DDSegmentation {
+
+class TiledLayerGridXY: public CartesianGrid {
+public:
+	/// Default constructor passing the encoding string
+	TiledLayerGridXY(const std::string& cellEncoding = "");
+	/// destructor
+	virtual ~TiledLayerGridXY();
+
+	/// determine the position based on the cell ID
+	virtual Vector3D position(const CellID& cellID) const;
+	/// determine the cell ID based on the position
+	virtual CellID cellID(const Vector3D& localPosition, const Vector3D& globalPosition, const VolumeID& volumeID) const;
+	/// access the grid size in X
+	double gridSizeX() const {
+		return _gridSizeX;
+	}
+	/// access the grid size in Y
+	double gridSizeY() const {
+		return _gridSizeY;
+	}
+	/// access the coordinate offset in X
+	double offsetX() const {
+		return _offsetX;
+	}
+	/// access the coordinate offset in Y
+	double offsetY() const {
+		return _offsetY;
+	}
+	/// access the field name used for X
+	const std::string& fieldNameX() const {
+		return _xId;
+	}
+	/// access the field name used for Y
+	const std::string& fieldNameY() const {
+		return _yId;
+	}
+	/// set the grid size in X
+	void setGridSizeX(double cellSize) {
+		_gridSizeX = cellSize;
+	}
+	/// set the grid size in Y
+	void setGridSizeY(double cellSize) {
+		_gridSizeY = cellSize;
+	}
+	/// set the coordinate offset in X
+	void setOffsetX(double offset) {
+		_offsetX = offset;
+	}
+	/// set the coordinate offset in Y
+	void setOffsetY(double offset) {
+		_offsetY = offset;
+	}
+	/// set the field name used for X
+	void setFieldNameX(const std::string& fieldName) {
+		_xId = fieldName;
+	}
+	/// set the field name used for Y
+	void setFieldNameY(const std::string& fieldName) {
+		_yId = fieldName;
+	}
+	/** \brief Returns a vector<double> of the cellDimensions of the given cell ID
+	    in natural order of dimensions, e.g., dx/dy/dz, or dr/r*dPhi
+
+	    Returns a vector of the cellDimensions of the given cell ID
+	    \param cellID is ignored as all cells have the same dimension
+	    \return std::vector<double> size 2:
+	    -# size in x
+	    -# size in y
+	*/
+	virtual std::vector<double> cellDimensions(const CellID& cellID) const;
+
+protected:
+	/// the grid size in X
+	double _gridSizeX;
+	/// the coordinate offset in X
+	double _offsetX;
+	/// the grid size in Y
+	double _gridSizeY;
+	/// the coordinate offset in Y
+	double _offsetY;
+	/// the field name used for X
+	std::string _xId;
+	/// the field name used for Y
+	std::string _yId;
+	/// encoding field used for the layer
+	std::string _identifierLayer; 
+	/// list of layer x offset
+	std::vector<double> _layerOffsetX;
+	/// list of layer y offset
+	std::vector<double> _layerOffsetY;
+
+};
+
+} /* namespace DDSegmentation */
+} /* namespace DD4hep */
+#endif /* DDSegmentation_TILEDLAYERGRIDXY_H_ */
diff --git a/DDSegmentation/src/TiledLayerGridXY.cpp b/DDSegmentation/src/TiledLayerGridXY.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6070a084e5bbf076f74bac460dd937c89099c3b1
--- /dev/null
+++ b/DDSegmentation/src/TiledLayerGridXY.cpp
@@ -0,0 +1,94 @@
+/*
+ * TiledLayerGridXY.cpp
+ *
+ *  Created on: November 12, 2015
+ *      Author: Shaojun Lu, DESY
+ */
+
+#include "DDSegmentation/TiledLayerGridXY.h"
+
+// C/C++ includes
+#include <algorithm>
+#include <sstream>
+#include <stdexcept>
+
+namespace DD4hep {
+namespace DDSegmentation {
+
+/// default constructor using an encoding string
+TiledLayerGridXY::TiledLayerGridXY(const std::string& cellEncoding) :
+		CartesianGrid(cellEncoding) {
+	// define type and description
+	_type = "TiledLayerGridXY";
+	_description = "Cartesian segmentation in the local XY-plane using optimal tiling depending on the layer dimensions";
+
+	// register all necessary parameters
+	registerParameter("grid_size_x", "Cell size in X", _gridSizeX, 1., SegmentationParameter::LengthUnit);
+	registerParameter("grid_size_y", "Cell size in Y", _gridSizeY, 1., SegmentationParameter::LengthUnit);
+	registerParameter("offset_x", "Cell offset in X", _offsetX, 0., SegmentationParameter::LengthUnit, true);
+	registerParameter("offset_y", "Cell offset in Y", _offsetY, 0., SegmentationParameter::LengthUnit, true);
+	registerIdentifier("identifier_x", "Cell ID identifier for X", _xId, "x");
+	registerIdentifier("identifier_y", "Cell ID identifier for Y", _yId, "y");
+	registerParameter("identifier_layer", "Cell encoding identifier for layer", _identifierLayer, std::string("layer"),
+			SegmentationParameter::NoUnit, true);
+	registerParameter("layer_offsetX", "List of layer x offset", _layerOffsetX, std::vector<double>(),
+			SegmentationParameter::NoUnit, true);
+	registerParameter("layer_offsetY", "List of layer y offset", _layerOffsetY, std::vector<double>(),
+			SegmentationParameter::NoUnit, true);
+}
+
+/// destructor
+TiledLayerGridXY::~TiledLayerGridXY() {
+
+}
+
+/// determine the position based on the cell ID
+Vector3D TiledLayerGridXY::position(const CellID& cID) const {
+	_decoder->setValue(cID);
+	unsigned int _layerIndex;
+	Vector3D cellPosition;
+
+	// AHcal: _layerIndex is [1,48], _layerOffsetX is [0,47]
+	_layerIndex = (*_decoder)[_identifierLayer];
+
+	if ( _layerOffsetX.size() != 0 && _layerIndex <=_layerOffsetX.size() ) {
+	  cellPosition.X = binToPosition((*_decoder)[_xId].value(), _gridSizeX, _layerOffsetX[_layerIndex - 1]*_gridSizeX/2.);
+	} else {
+	  cellPosition.X = binToPosition((*_decoder)[_xId].value(), _gridSizeX, _offsetX);
+	}
+	cellPosition.Y = binToPosition((*_decoder)[_yId].value(), _gridSizeY, _offsetY);
+	return cellPosition;
+}
+
+/// determine the cell ID based on the position
+  CellID TiledLayerGridXY::cellID(const Vector3D& localPosition, const Vector3D& /* globalPosition */, const VolumeID& vID) const {
+	_decoder->setValue(vID);
+	unsigned int _layerIndex;
+
+	// AHcal: _layerIndex is [1,48], _layerOffsetX is [0,47]
+	_layerIndex = (*_decoder)[_identifierLayer];
+
+	if ( _layerOffsetX.size() != 0 && _layerIndex <=_layerOffsetX.size() ) {
+	  (*_decoder)[_xId] = positionToBin(localPosition.X, _gridSizeX, _layerOffsetX[_layerIndex - 1]*_gridSizeX/2.);
+	} else {
+	  (*_decoder)[_xId] = positionToBin(localPosition.X, _gridSizeX, _offsetX);
+	}
+	(*_decoder)[_yId] = positionToBin(localPosition.Y, _gridSizeY, _offsetY);
+	return _decoder->getValue();
+}
+
+std::vector<double> TiledLayerGridXY::cellDimensions(const CellID&) const {
+#if __cplusplus >= 201103L
+  return {_gridSizeX, _gridSizeY};
+#else
+  std::vector<double> cellDims(2,0.0);
+  cellDims[0] = _gridSizeX;
+  cellDims[1] = _gridSizeY;
+  return cellDims;
+#endif
+}
+
+REGISTER_SEGMENTATION(TiledLayerGridXY)
+
+} /* namespace DDSegmentation */
+} /* namespace DD4hep */