Index: doc/userguide/userguide.xml
===================================================================
--- doc/userguide/userguide.xml	(revision 0ea063beb1f1de6945df69f74ce759aab7643539)
+++ doc/userguide/userguide.xml	(revision 9e1bfbc27ee42cdb562491c7e51fdb9da26faaf0)
@@ -955,4 +955,18 @@
           domain.</para>
         </section>
+
+        <section xml:id='atoms.mirror-atoms'>
+          <title xml:id='atoms.mirror-atoms.title'>Mirroring atoms</title>
+
+          <para>Present (and selected) atoms can be mirrored with respect to
+          a certain plane. You have to specify the normal vector of the plane
+          and the offset with respect to the origin as follows</para>
+
+          <programlisting>
+		... --mirror-atoms "1,0,0" \
+                    --plane-offset 10.1 \
+                    --periodic 0
+	  </programlisting>
+	</section>
 
         <section xml:id='atoms.change-element'>
Index: src/Actions/AtomAction/MirrorAction.cpp
===================================================================
--- src/Actions/AtomAction/MirrorAction.cpp	(revision 9e1bfbc27ee42cdb562491c7e51fdb9da26faaf0)
+++ src/Actions/AtomAction/MirrorAction.cpp	(revision 9e1bfbc27ee42cdb562491c7e51fdb9da26faaf0)
@@ -0,0 +1,117 @@
+/*
+ * Project: MoleCuilder
+ * Description: creates and alters molecular systems
+ * Copyright (C)  2014 Frederik Heber. All rights reserved.
+ * 
+ *
+ *   This file is part of MoleCuilder.
+ *
+ *    MoleCuilder 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, either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    MoleCuilder 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 MoleCuilder.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * MirrorAction.cpp
+ *
+ *  Created on: Sep 10, 2014
+ *      Author: heber
+ */
+
+// include config.h
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "CodePatterns/MemDebug.hpp"
+
+#include "CodePatterns/Log.hpp"
+#include "Atom/atom.hpp"
+#include "LinearAlgebra/Plane.hpp"
+#include "LinearAlgebra/Vector.hpp"
+#include "CodePatterns/Verbose.hpp"
+#include "World.hpp"
+
+#include <iostream>
+#include <fstream>
+#include <string>
+
+#include "Actions/AtomAction/MirrorAction.hpp"
+
+using namespace MoleCuilder;
+
+// and construct the stuff
+#include "MirrorAction.def"
+#include "Action_impl_pre.hpp"
+/** =========== define the function ====================== */
+ActionState::ptr AtomMirrorAction::performCall() {
+  Box &domain = World::getInstance().getDomain();
+  std::vector<atom *> selectedAtoms = World::getInstance().getSelectedAtoms();
+
+  Plane *MirrorPlane = NULL;
+  std::vector<atom *>::iterator iter = selectedAtoms.begin();
+  try {
+    MirrorPlane = new Plane(params.normal.get(), params.offset.get());
+    for (; iter != selectedAtoms.end(); ++iter) {
+      (*iter)->setPosition(MirrorPlane->mirrorVector((*iter)->getPosition()));
+      if (params.periodic.get())
+        (*iter)->setPosition(domain.enforceBoundaryConditions((*iter)->getPosition()));
+    }
+  } catch( LinearAlgebraException &e) {
+    // flip back
+    for (std::vector<atom *>::iterator undoiter = selectedAtoms.begin();
+        undoiter != iter; ++undoiter)
+      (*iter)->setPosition(MirrorPlane->mirrorVector((*iter)->getPosition()));
+    delete MirrorPlane;
+    return Action::failure;
+  }
+  delete MirrorPlane;
+
+  return ActionState::ptr(new AtomMirrorState(selectedAtoms, params));
+}
+
+ActionState::ptr AtomMirrorAction::performUndo(ActionState::ptr _state) {
+  AtomMirrorState *state = assert_cast<AtomMirrorState*>(_state.get());
+  Box &domain = World::getInstance().getDomain();
+
+  Plane MirrorPlane(state->params.normal.get(), state->params.offset.get());
+  for (std::vector<atom *>::iterator iter = state->selectedAtoms.begin(); iter != state->selectedAtoms.end(); ++iter) {
+    (*iter)->setPosition(MirrorPlane.mirrorVector((*iter)->getPosition()));
+    if (state->params.periodic.get())
+      (*iter)->setPosition(domain.enforceBoundaryConditions((*iter)->getPosition()));
+  }
+
+  return ActionState::ptr(_state);
+}
+
+ActionState::ptr AtomMirrorAction::performRedo(ActionState::ptr _state){
+  AtomMirrorState *state = assert_cast<AtomMirrorState*>(_state.get());
+  Box &domain = World::getInstance().getDomain();
+
+  Plane MirrorPlane(state->params.normal.get(), state->params.offset.get());
+  for (std::vector<atom *>::iterator iter = state->selectedAtoms.begin(); iter != state->selectedAtoms.end(); ++iter) {
+    (*iter)->setPosition(MirrorPlane.mirrorVector((*iter)->getPosition()));
+    if (state->params.periodic.get())
+      (*iter)->setPosition(domain.enforceBoundaryConditions((*iter)->getPosition()));
+  }
+
+  return ActionState::ptr(_state);
+}
+
+bool AtomMirrorAction::canUndo() {
+  return true;
+}
+
+bool AtomMirrorAction::shouldUndo() {
+  return true;
+}
+/** =========== end of function ====================== */
Index: src/Actions/AtomAction/MirrorAction.def
===================================================================
--- src/Actions/AtomAction/MirrorAction.def	(revision 9e1bfbc27ee42cdb562491c7e51fdb9da26faaf0)
+++ src/Actions/AtomAction/MirrorAction.def	(revision 9e1bfbc27ee42cdb562491c7e51fdb9da26faaf0)
@@ -0,0 +1,40 @@
+/*
+ * MirrorAction.def
+ *
+ *  Created on: Aug 26, 2010
+ *      Author: heber
+ */
+
+// all includes and forward declarations necessary for non-integral types below
+#include "Actions/Values.hpp"
+#include "LinearAlgebra/Vector.hpp"
+
+#include "Parameters/Validators/DummyValidator.hpp"
+
+// i.e. there is an integer with variable name Z that can be found in
+// ValueStorage by the token "Z" -> first column: int, Z, "Z"
+// "undefine" if no parameters are required, use (NOPARAM_DEFAULT) for each (undefined) default value
+#define paramtypes (Vector)(double)(bool)
+#define paramtokens ("mirror-atoms")("plane-offset")("periodic")
+#define paramdescriptions ("normal vector of mirror plane")("offset of plane with respect to origin")("system is constraint to periodic boundary conditions")
+#define paramreferences (normal)(offset)(periodic)
+#define paramdefaults (NOPARAM_DEFAULT)(NOPARAM_DEFAULT)(PARAM_DEFAULT(false))
+#define paramvalids \
+(DummyValidator< Vector >()) \
+(DummyValidator< double >()) \
+(DummyValidator< bool >())
+
+#define statetypes (std::vector<atom*>)
+#define statereferences (selectedAtoms)
+
+// some defines for all the names, you may use ACTION, STATE and PARAMS
+#define CATEGORY Atom
+#define MENUNAME "atom"
+#define MENUPOSITION 4
+#define ACTIONNAME Mirror
+#define TOKEN "mirror-atoms"
+
+
+// finally the information stored in the ActionTrait specialization
+#define DESCRIPTION "mirror all selected atoms by a plane determined by a given normal and an offset"
+#undef SHORTFORM
Index: src/Actions/AtomAction/MirrorAction.hpp
===================================================================
--- src/Actions/AtomAction/MirrorAction.hpp	(revision 9e1bfbc27ee42cdb562491c7e51fdb9da26faaf0)
+++ src/Actions/AtomAction/MirrorAction.hpp	(revision 9e1bfbc27ee42cdb562491c7e51fdb9da26faaf0)
@@ -0,0 +1,22 @@
+/*
+ * MirrorAction.hpp
+ *
+ *  Created on: Sep 10, 2014
+ *      Author: heber
+ */
+
+#ifndef MIRRORACTION_HPP
+#define MIRRORACTION_HPP
+
+// include config.h
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+#include "Actions/Action.hpp"
+
+#include "MirrorAction.def"
+#include "Action_impl_header.hpp"
+
+#endif // MIRRORACTION_HPP
Index: src/Actions/GlobalListOfActions.hpp
===================================================================
--- src/Actions/GlobalListOfActions.hpp	(revision 0ea063beb1f1de6945df69f74ce759aab7643539)
+++ src/Actions/GlobalListOfActions.hpp	(revision 9e1bfbc27ee42cdb562491c7e51fdb9da26faaf0)
@@ -31,4 +31,5 @@
   (AtomAdd) \
   (AtomChangeElement) \
+  (AtomMirror) \
   (AtomRemove) \
   (AtomRotateAroundOriginByAngle) \
Index: src/Actions/Makefile.am
===================================================================
--- src/Actions/Makefile.am	(revision 0ea063beb1f1de6945df69f74ce759aab7643539)
+++ src/Actions/Makefile.am	(revision 9e1bfbc27ee42cdb562491c7e51fdb9da26faaf0)
@@ -144,4 +144,5 @@
   Actions/AtomAction/AddAction.cpp \
   Actions/AtomAction/ChangeElementAction.cpp \
+  Actions/AtomAction/MirrorAction.cpp \
   Actions/AtomAction/RemoveAction.cpp \
   Actions/AtomAction/RotateAroundOriginByAngleAction.cpp \
@@ -151,4 +152,5 @@
   Actions/AtomAction/AddAction.hpp \
   Actions/AtomAction/ChangeElementAction.hpp \
+  Actions/AtomAction/MirrorAction.hpp \
   Actions/AtomAction/RemoveAction.hpp \
   Actions/AtomAction/RotateAroundOriginByAngleAction.hpp \
@@ -158,4 +160,5 @@
   Actions/AtomAction/AddAction.def \
   Actions/AtomAction/ChangeElementAction.def \
+  Actions/AtomAction/MirrorAction.def \
   Actions/AtomAction/RemoveAction.def \
   Actions/AtomAction/RotateAroundOriginByAngleAction.def \
Index: src/Actions/SelectionAction/Atoms/AtomByIdAction.cpp
===================================================================
--- src/Actions/SelectionAction/Atoms/AtomByIdAction.cpp	(revision 0ea063beb1f1de6945df69f74ce759aab7643539)
+++ src/Actions/SelectionAction/Atoms/AtomByIdAction.cpp	(revision 9e1bfbc27ee42cdb562491c7e51fdb9da26faaf0)
@@ -93,5 +93,5 @@
       break;
     default:
-      ASSERT(0, "SelectionAtomByIdAction::performCall() - this must not happen.");
+      STATUS("No atoms have been selected.");
       return Action::failure;
       break;
Index: src/Actions/SelectionAction/Atoms/NotAtomByIdAction.cpp
===================================================================
--- src/Actions/SelectionAction/Atoms/NotAtomByIdAction.cpp	(revision 0ea063beb1f1de6945df69f74ce759aab7643539)
+++ src/Actions/SelectionAction/Atoms/NotAtomByIdAction.cpp	(revision 9e1bfbc27ee42cdb562491c7e51fdb9da26faaf0)
@@ -93,5 +93,5 @@
       break;
     default:
-      ASSERT(0, "SelectionAtomByIdAction::performCall() - this must not happen.");
+      STATUS("No atoms have been selected.");
       return Action::failure;
       break;
Index: tests/Python/AllActions/options.dat
===================================================================
--- tests/Python/AllActions/options.dat	(revision 0ea063beb1f1de6945df69f74ce759aab7643539)
+++ tests/Python/AllActions/options.dat	(revision 9e1bfbc27ee42cdb562491c7e51fdb9da26faaf0)
@@ -99,4 +99,5 @@
 mesh-size	"10,10,10"
 min-distance	"1."
+mirror-atoms	"1.,1.,1."
 molecule-by-id	"0"
 near-field-cells	"3"
@@ -130,4 +131,5 @@
 parser-parameters	"psi3"
 periodic	"0"
+plane-offset	"5."
 position	"0 0 0"
 position	"0 0 1"
Index: tests/regression/Atoms/Mirror/post/test-mirrored.xyz
===================================================================
--- tests/regression/Atoms/Mirror/post/test-mirrored.xyz	(revision 9e1bfbc27ee42cdb562491c7e51fdb9da26faaf0)
+++ tests/regression/Atoms/Mirror/post/test-mirrored.xyz	(revision 9e1bfbc27ee42cdb562491c7e51fdb9da26faaf0)
@@ -0,0 +1,5 @@
+3
+	Created for regression test mirror-atoms
+H	10	0	0
+H	7	0	0
+H	2	1	0
Index: tests/regression/Atoms/Mirror/post/test.xyz
===================================================================
--- tests/regression/Atoms/Mirror/post/test.xyz	(revision 9e1bfbc27ee42cdb562491c7e51fdb9da26faaf0)
+++ tests/regression/Atoms/Mirror/post/test.xyz	(revision 9e1bfbc27ee42cdb562491c7e51fdb9da26faaf0)
@@ -0,0 +1,5 @@
+3
+	Created for regression test mirror-atoms
+H	0	0	0
+H	3	0	0
+H	8	1	0
Index: tests/regression/Atoms/Mirror/pre/test.xyz
===================================================================
--- tests/regression/Atoms/Mirror/pre/test.xyz	(revision 9e1bfbc27ee42cdb562491c7e51fdb9da26faaf0)
+++ tests/regression/Atoms/Mirror/pre/test.xyz	(revision 9e1bfbc27ee42cdb562491c7e51fdb9da26faaf0)
@@ -0,0 +1,5 @@
+3
+	Created for regression test mirror-atoms
+H	0	0	0
+H	3	0	0
+H	8	1	0
Index: tests/regression/Atoms/Mirror/testsuite-atoms-mirror.at
===================================================================
--- tests/regression/Atoms/Mirror/testsuite-atoms-mirror.at	(revision 9e1bfbc27ee42cdb562491c7e51fdb9da26faaf0)
+++ tests/regression/Atoms/Mirror/testsuite-atoms-mirror.at	(revision 9e1bfbc27ee42cdb562491c7e51fdb9da26faaf0)
@@ -0,0 +1,53 @@
+#
+#    MoleCuilder - creates and alters molecular systems
+#    Copyright (C) 2008-2012 University of Bonn
+#
+#    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, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    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, see <http://www.gnu.org/licenses/>.
+#
+### translation
+
+AT_SETUP([Atoms - Mirror])
+AT_KEYWORDS([atoms mirror-atoms])
+
+file=test.xyz
+AT_CHECK([/bin/cp -f ${abs_top_srcdir}/tests/regression/Atoms/Mirror/pre/test.xyz $file], 0)
+AT_CHECK([chmod u+w $file], 0)
+AT_CHECK([../../molecuilder -i $file --select-all-atoms --mirror-atoms "1,0,0" --plane-offset 5.], 0, [stdout], [stderr])
+AT_CHECK([diff -I '.*Created .*' $file ${abs_top_srcdir}/tests/regression/Atoms/Mirror/post/test-mirrored.xyz], 0, [ignore], [ignore])
+
+AT_CLEANUP
+
+
+AT_SETUP([Atoms - Mirror with Undo])
+AT_KEYWORDS([atoms mirror-atoms undo])
+
+file=test.xyz
+AT_CHECK([/bin/cp -f ${abs_top_srcdir}/tests/regression/Atoms/Mirror/pre/test.xyz $file], 0)
+AT_CHECK([chmod u+w $file], 0)
+AT_CHECK([../../molecuilder -i $file --select-all-atoms --mirror-atoms "1,0,0" --plane-offset 5. --undo], 0, [stdout], [stderr])
+AT_CHECK([diff -I '.*Created .*' $file ${abs_top_srcdir}/tests/regression/Atoms/Mirror/pre/test.xyz], 0, [ignore], [ignore])
+
+AT_CLEANUP
+
+
+AT_SETUP([Atoms - Mirror with Redo])
+AT_KEYWORDS([atoms mirror-atoms redo])
+
+file=test.xyz
+AT_CHECK([/bin/cp -f ${abs_top_srcdir}/tests/regression/Atoms/Mirror/pre/test.xyz $file], 0)
+AT_CHECK([chmod u+w $file], 0)
+AT_CHECK([../../molecuilder -i $file --select-all-atoms --mirror-atoms "1,0,0" --plane-offset 5. --undo --redo], 0, [stdout], [stderr])
+AT_CHECK([diff -I '.*Created .*' $file ${abs_top_srcdir}/tests/regression/Atoms/Mirror/post/test-mirrored.xyz], 0, [ignore], [ignore])
+
+AT_CLEANUP
Index: tests/regression/Atoms/testsuite-atoms.at
===================================================================
--- tests/regression/Atoms/testsuite-atoms.at	(revision 0ea063beb1f1de6945df69f74ce759aab7643539)
+++ tests/regression/Atoms/testsuite-atoms.at	(revision 9e1bfbc27ee42cdb562491c7e51fdb9da26faaf0)
@@ -38,2 +38,5 @@
 # Undo and redo a translation
 m4_include([Atoms/Translation/testsuite-atoms-translation.at])
+
+# mirror atoms
+m4_include([Atoms/Mirror/testsuite-atoms-mirror.at])
Index: tests/regression/Makefile.am
===================================================================
--- tests/regression/Makefile.am	(revision 0ea063beb1f1de6945df69f74ce759aab7643539)
+++ tests/regression/Makefile.am	(revision 9e1bfbc27ee42cdb562491c7e51fdb9da26faaf0)
@@ -35,4 +35,5 @@
 	$(srcdir)/Atoms/Add/testsuite-atoms-add.at \
 	$(srcdir)/Atoms/ChangeElement/testsuite-atoms-change-element.at \
+	$(srcdir)/Atoms/Mirror/testsuite-atoms-mirror.at \
 	$(srcdir)/Atoms/Remove/testsuite-atoms-remove.at \
 	$(srcdir)/Atoms/RemoveCuboid/testsuite-atoms-remove-cuboid.at \
