void ElectricField::initMdpTransform(IKeyValueTreeTransformRules *rules)
{
- // TODO This responsibility should be handled by the caller,
- // e.g. embedded in the rules, somehow.
- std::string prefix = "/applied-forces/";
-
- rules->addRule().from<std::string>("/E-x").to<real>(prefix + "electric-field/x/E0")
+ rules->addRule().from<std::string>("/E-x").to<real>("/electric-field/x/E0")
.transformWith(&convertStaticParameters);
- rules->addRule().from<std::string>("/E-xt").toObject(prefix + "electric-field/x")
+ rules->addRule().from<std::string>("/E-xt").toObject("/electric-field/x")
.transformWith(&convertDynamicParameters);
- rules->addRule().from<std::string>("/E-y").to<real>(prefix + "electric-field/y/E0")
+ rules->addRule().from<std::string>("/E-y").to<real>("/electric-field/y/E0")
.transformWith(&convertStaticParameters);
- rules->addRule().from<std::string>("/E-yt").toObject(prefix + "electric-field/y")
+ rules->addRule().from<std::string>("/E-yt").toObject("/electric-field/y")
.transformWith(&convertDynamicParameters);
- rules->addRule().from<std::string>("/E-z").to<real>(prefix + "electric-field/z/E0")
+ rules->addRule().from<std::string>("/E-z").to<real>("/electric-field/z/E0")
.transformWith(&convertStaticParameters);
- rules->addRule().from<std::string>("/E-zt").toObject(prefix + "electric-field/z")
+ rules->addRule().from<std::string>("/E-zt").toObject("/electric-field/z")
.transformWith(&convertDynamicParameters);
}
#include "gromacs/gmxlib/network.h"
#include "gromacs/math/vec.h"
#include "gromacs/mdlib/forcerec.h"
-#include "gromacs/mdrunutility/mdmodules.h"
#include "gromacs/mdtypes/forcerec.h"
#include "gromacs/mdtypes/iforceprovider.h"
+#include "gromacs/mdtypes/imdmodule.h"
+#include "gromacs/mdtypes/imdpoptionprovider.h"
#include "gromacs/mdtypes/inputrec.h"
#include "gromacs/mdtypes/mdatom.h"
+#include "gromacs/options/options.h"
+#include "gromacs/options/treesupport.h"
#include "gromacs/utility/arrayref.h"
#include "gromacs/utility/keyvaluetreebuilder.h"
#include "gromacs/utility/keyvaluetreetransform.h"
{
gmx::test::FloatingPointTolerance tolerance(
gmx::test::relativeToleranceAsFloatingPoint(1.0, 0.005));
- gmx::MDModules module;
+ auto module(gmx::createElectricFieldModule());
// Prepare MDP inputs
const char *dimXYZ[3] = { "x", "y", "z" };
- GMX_RELEASE_ASSERT((dim >= 0 && dim < 3), "Dimension should be 0, 1 or 2");
+ GMX_RELEASE_ASSERT(dim >= 0 && dim < DIM, "Dimension should be 0, 1 or 2");
gmx::KeyValueTreeBuilder mdpValues;
mdpValues.rootObject().addValue(gmx::formatString("E%s", dimXYZ[dim]),
gmx::KeyValueTreeTransformer transform;
transform.rules()->addRule()
.keyMatchType("/", gmx::StringCompareType::CaseAndDashInsensitive);
- module.initMdpTransform(transform.rules());
- auto result = transform.transform(mdpValues.build(), nullptr);
- module.assignOptionsToModules(result.object(), nullptr);
+ module->mdpOptionProvider()->initMdpTransform(transform.rules());
+ auto result = transform.transform(mdpValues.build(), nullptr);
+ gmx::Options moduleOptions;
+ module->mdpOptionProvider()->initMdpOptions(&moduleOptions);
+ gmx::assignOptionsFromKeyValueTree(&moduleOptions, result.object(), nullptr);
+
+ ForceProviders forceProviders;
+ module->initForceProviders(&forceProviders);
t_mdatoms md;
PaddedRVecVector f = { { 0, 0, 0 } };
md.chargeA[0] = 1;
t_commrec *cr = init_commrec();
- module.initForceProviders()->calculateForces(cr, &md, nullptr, 0, nullptr,
- gmx::EmptyArrayRef(), f);
+ forceProviders.calculateForces(cr, &md, nullptr, 0, nullptr,
+ gmx::EmptyArrayRef(), f);
done_commrec(cr);
+
EXPECT_REAL_EQ_TOL(f[0][dim], expectedValue, tolerance);
sfree(md.chargeA);
}
#include "gromacs/options/optionsection.h"
#include "gromacs/options/treesupport.h"
#include "gromacs/utility/keyvaluetree.h"
+#include "gromacs/utility/keyvaluetreetransform.h"
#include "gromacs/utility/smalloc.h"
namespace gmx
void MDModules::initMdpTransform(IKeyValueTreeTransformRules *rules)
{
- // TODO The transform rules for applied-forces modules should
- // embed the necessary prefix (and similarly for other groupings
- // of modules). For now, electric-field embeds this itself.
- impl_->field_->mdpOptionProvider()->initMdpTransform(rules);
+ auto appliedForcesScope = rules->scopedTransform("/applied-forces");
+ impl_->field_->mdpOptionProvider()->initMdpTransform(appliedForcesScope.rules());
}
void MDModules::assignOptionsToModules(const KeyValueTreeObject ¶ms,
{
if (knownNames.count(prop.key()) == 0)
{
- KeyValueTreePath path(currentPath_);
- path.append(prop.key());
- unknownPaths_.push_back(std::move(path));
+ unknownPaths_.push_back(currentPath_ + prop.key());
}
}
}
//! Adds another element to the path, making it a child of the old path.
void append(const std::string &key) { path_.push_back(key); }
+ //! Adds elements from another path to the path.
+ void append(const KeyValueTreePath &other)
+ {
+ auto elements = other.elements();
+ path_.insert(path_.end(), elements.begin(), elements.end());
+ }
//! Removes the last element in the path, making it the parent path.
void pop_back() { return path_.pop_back(); }
//! Removes and returns the last element in the path.
std::vector<std::string> path_;
};
+//! \cond libapi
+
+//! Combines two paths as with KeyValueTreePath::append().
+inline KeyValueTreePath operator+(const KeyValueTreePath &a, const KeyValueTreePath &b)
+{
+ KeyValueTreePath result(a);
+ result.append(b);
+ return result;
+}
+
+//! Combines an element to a path as with KeyValueTreePath::append().
+inline KeyValueTreePath operator+(const KeyValueTreePath &a, const std::string &b)
+{
+ KeyValueTreePath result(a);
+ result.append(b);
+ return result;
+}
+//! \endcond
+
class KeyValueTreeValue
{
public:
{
}
+/********************************************************************
+ * KeyValueTreeTransformRulesScoped::Impl
+ */
+
+class KeyValueTreeTransformRulesScoped::Impl : public IKeyValueTreeTransformRules
+{
+ public:
+ Impl(internal::KeyValueTreeTransformerImpl *impl, const KeyValueTreePath &prefix)
+ : impl_(impl), prefix_(prefix)
+ {
+ }
+
+ KeyValueTreeTransformRuleBuilder addRule() override
+ {
+ return KeyValueTreeTransformRuleBuilder(impl_, prefix_);
+ }
+
+ KeyValueTreeTransformRulesScoped
+ scopedTransform(const KeyValueTreePath &scope) override
+ {
+ return KeyValueTreeTransformRulesScoped(impl_, prefix_ + scope);
+ }
+
+ private:
+ internal::KeyValueTreeTransformerImpl *impl_;
+ KeyValueTreePath prefix_;
+};
+
+/********************************************************************
+ * KeyValueTreeTransformRulesScoped
+ */
+
+KeyValueTreeTransformRulesScoped::KeyValueTreeTransformRulesScoped(
+ internal::KeyValueTreeTransformerImpl *impl, const KeyValueTreePath &prefix)
+ : impl_(new Impl(impl, prefix))
+{
+}
+
+KeyValueTreeTransformRulesScoped::KeyValueTreeTransformRulesScoped(
+ KeyValueTreeTransformRulesScoped &&) = default;
+
+KeyValueTreeTransformRulesScoped &
+KeyValueTreeTransformRulesScoped::operator=(
+ KeyValueTreeTransformRulesScoped &&) = default;
+
+KeyValueTreeTransformRulesScoped::~KeyValueTreeTransformRulesScoped()
+{
+}
+
+IKeyValueTreeTransformRules *KeyValueTreeTransformRulesScoped::rules()
+{
+ return impl_.get();
+}
+
/********************************************************************
* IKeyValueTreeBackMapping
*/
* KeyValueTreeTransformerImpl
*/
-class KeyValueTreeTransformerImpl : public IKeyValueTreeTransformRules
+class KeyValueTreeTransformerImpl
{
public:
class Rule
KeyValueTreePath context_;
};
- virtual KeyValueTreeTransformRuleBuilder addRule()
+ KeyValueTreeTransformerImpl()
+ : rootScope_(this, KeyValueTreePath())
{
- return KeyValueTreeTransformRuleBuilder(this);
}
Rule *getOrCreateRootRule()
rootRule_.reset(new Rule(keyMatchType));
}
- std::unique_ptr<Rule> rootRule_;
+ std::unique_ptr<Rule> rootRule_;
+ KeyValueTreeTransformRulesScoped rootScope_;
};
/********************************************************************
IKeyValueTreeTransformRules *KeyValueTreeTransformer::rules()
{
- return impl_.get();
+ return impl_->rootScope_.rules();
}
std::vector<KeyValueTreePath> KeyValueTreeTransformer::mappedPaths() const
public:
typedef internal::KeyValueTreeTransformerImpl::Rule Rule;
- Data()
- : expectedType_(typeid(void)),
+ explicit Data(const KeyValueTreePath &prefix)
+ : prefixPath_(prefix), expectedType_(typeid(void)),
keyMatchType_(StringCompareType::Exact), keyMatchRule_(false)
{
}
}
}
+ const KeyValueTreePath prefixPath_;
KeyValueTreePath fromPath_;
KeyValueTreePath toPath_;
std::type_index expectedType_;
*/
KeyValueTreeTransformRuleBuilder::KeyValueTreeTransformRuleBuilder(
- internal::KeyValueTreeTransformerImpl *impl)
- : impl_(impl), data_(new Data)
+ internal::KeyValueTreeTransformerImpl *impl, const KeyValueTreePath &prefix)
+ : impl_(impl), data_(new Data(prefix))
{
}
void KeyValueTreeTransformRuleBuilder::setToPath(const KeyValueTreePath &path)
{
- data_->toPath_ = path;
+ data_->toPath_ = data_->prefixPath_ + path;
}
void KeyValueTreeTransformRuleBuilder::setKeyMatchType(StringCompareType keyMatchType)
class KeyValueTreeTransformResult;
class KeyValueTreeTransformRuleBuilder;
+class KeyValueTreeTransformRulesScoped;
namespace internal
{
* builder.
*/
virtual KeyValueTreeTransformRuleBuilder addRule() = 0;
+ /*! \brief
+ * Creates a scoped set of rules, where all rules use a target sub-tree.
+ *
+ * \param[in] scope Prefix defining the scope in the target tree
+ *
+ * Any rules added to the returned scope will have `scope` prefixed to
+ * their target paths, i.e., it is not possible to produce elements
+ * outside the specified subtree.
+ */
+ virtual KeyValueTreeTransformRulesScoped
+ scopedTransform(const KeyValueTreePath &scope) = 0;
protected:
~IKeyValueTreeTransformRules();
};
+/*! \libinternal \brief
+ * Helper object returned from IKeyValueTreeTransformRules::scopedTransform().
+ *
+ * \inlibraryapi
+ * \ingroup module_utility
+ */
+class KeyValueTreeTransformRulesScoped
+{
+ public:
+ //! Internal constructor for creating the scope.
+ KeyValueTreeTransformRulesScoped(
+ internal::KeyValueTreeTransformerImpl *impl,
+ const KeyValueTreePath &prefix);
+ //! Supports returning the object from IKeyValueTreeTransformRules::scopedTransform().
+ KeyValueTreeTransformRulesScoped(KeyValueTreeTransformRulesScoped &&other);
+ //! Supports returning the object from IKeyValueTreeTransformRules::scopedTransform().
+ KeyValueTreeTransformRulesScoped &operator=(KeyValueTreeTransformRulesScoped &&other);
+ ~KeyValueTreeTransformRulesScoped();
+
+ //! Returns the interface for adding rules to this scope.
+ IKeyValueTreeTransformRules *rules();
+
+ private:
+ class Impl;
+
+ PrivateImplPointer<Impl> impl_;
+};
+
/*! \libinternal \brief
* Provides methods to specify one transformation rule.
*
};
//! Internal constructor for creating a builder.
- explicit KeyValueTreeTransformRuleBuilder(internal::KeyValueTreeTransformerImpl *impl);
+ KeyValueTreeTransformRuleBuilder(internal::KeyValueTreeTransformerImpl *impl,
+ const KeyValueTreePath &prefix);
//! Supports returning the builder from IKeyValueTreeTransformRules::addRule().
KeyValueTreeTransformRuleBuilder(KeyValueTreeTransformRuleBuilder &&) = default;
//! Supports returning the builder from IKeyValueTreeTransformRules::addRule().
/*
* This file is part of the GROMACS molecular simulation package.
*
- * Copyright (c) 2016, by the GROMACS development team, led by
+ * Copyright (c) 2016,2017, by the GROMACS development team, led by
* Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
* and including many others, as listed in the AUTHORS file in the
* top-level source directory and at http://www.gromacs.org.
testTransform(input, transform);
}
+TEST_F(TreeValueTransformTest, ScopedTransformRules)
+{
+ gmx::KeyValueTreeBuilder builder;
+ builder.rootObject().addValue<std::string>("a", "1");
+ builder.rootObject().addValue<std::string>("b", "2");
+ gmx::KeyValueTreeObject input = builder.build();
+
+ gmx::KeyValueTreeTransformer transform;
+ auto scope = transform.rules()->scopedTransform("/foo");
+ scope.rules()->addRule()
+ .from<std::string>("/a").to<int>("/i").transformWith(&gmx::fromStdString<int>);
+ scope.rules()->addRule()
+ .from<std::string>("/b").to<int>("/j").transformWith(&gmx::fromStdString<int>);
+
+ testTransform(input, transform);
+}
+
/********************************************************************
* Tests for errors
*/
--- /dev/null
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+ <Object Name="Input">
+ <String Name="a">1</String>
+ <String Name="b">2</String>
+ </Object>
+ <Sequence Name="MappedPaths">
+ <Int Name="Length">2</Int>
+ <String>/a</String>
+ <String>/b</String>
+ </Sequence>
+ <Object Name="Tree">
+ <Object Name="foo">
+ <Int Name="i">1</Int>
+ <Int Name="j">2</Int>
+ </Object>
+ </Object>
+ <BackMapping Name="Mapping">
+ <String Name="/foo/i">/a</String>
+ <String Name="/foo/j">/b</String>
+ </BackMapping>
+</ReferenceData>