void* CustomNonbondedForceProxy::deserialize(const SerializationNode& node) const {
    int version = node.getIntProperty("version");
    if (version < 1 || version > 2)
        throw OpenMMException("Unsupported version number");
    CustomNonbondedForce* force = NULL;
    try {
        CustomNonbondedForce* force = new CustomNonbondedForce(node.getStringProperty("energy"));
        force->setForceGroup(node.getIntProperty("forceGroup", 0));
        force->setNonbondedMethod((CustomNonbondedForce::NonbondedMethod) node.getIntProperty("method"));
        force->setCutoffDistance(node.getDoubleProperty("cutoff"));
        force->setUseSwitchingFunction(node.getBoolProperty("useSwitchingFunction", false));
        force->setSwitchingDistance(node.getDoubleProperty("switchingDistance", -1.0));
        force->setUseLongRangeCorrection(node.getBoolProperty("useLongRangeCorrection", false));
        const SerializationNode& perParticleParams = node.getChildNode("PerParticleParameters");
        for (int i = 0; i < (int) perParticleParams.getChildren().size(); i++) {
            const SerializationNode& parameter = perParticleParams.getChildren()[i];
            force->addPerParticleParameter(parameter.getStringProperty("name"));
        }
        const SerializationNode& globalParams = node.getChildNode("GlobalParameters");
        for (int i = 0; i < (int) globalParams.getChildren().size(); i++) {
            const SerializationNode& parameter = globalParams.getChildren()[i];
            force->addGlobalParameter(parameter.getStringProperty("name"), parameter.getDoubleProperty("default"));
        }
        if (version > 1) {
            const SerializationNode& energyDerivs = node.getChildNode("EnergyParameterDerivatives");
            for (int i = 0; i < (int) energyDerivs.getChildren().size(); i++) {
                const SerializationNode& parameter = energyDerivs.getChildren()[i];
                force->addEnergyParameterDerivative(parameter.getStringProperty("name"));
            }
        }
        const SerializationNode& particles = node.getChildNode("Particles");
        vector<double> params(force->getNumPerParticleParameters());
        for (int i = 0; i < (int) particles.getChildren().size(); i++) {
            const SerializationNode& particle = particles.getChildren()[i];
            for (int j = 0; j < (int) params.size(); j++) {
                stringstream key;
                key << "param";
                key << j+1;
                params[j] = particle.getDoubleProperty(key.str());
            }
            force->addParticle(params);
        }
        const SerializationNode& exclusions = node.getChildNode("Exclusions");
        for (int i = 0; i < (int) exclusions.getChildren().size(); i++) {
            const SerializationNode& exclusion = exclusions.getChildren()[i];
            force->addExclusion(exclusion.getIntProperty("p1"), exclusion.getIntProperty("p2"));
        }
        const SerializationNode& functions = node.getChildNode("Functions");
        for (int i = 0; i < (int) functions.getChildren().size(); i++) {
            const SerializationNode& function = functions.getChildren()[i];
            if (function.hasProperty("type")) {
                force->addTabulatedFunction(function.getStringProperty("name"), function.decodeObject<TabulatedFunction>());
            }
            else {
                // This is an old file created before TabulatedFunction existed.

                const SerializationNode& valuesNode = function.getChildNode("Values");
                vector<double> values;
                for (int j = 0; j < (int) valuesNode.getChildren().size(); j++)
                    values.push_back(valuesNode.getChildren()[j].getDoubleProperty("v"));
                force->addTabulatedFunction(function.getStringProperty("name"), new Continuous1DFunction(values, function.getDoubleProperty("min"), function.getDoubleProperty("max")));
            }
        }
        bool hasInteractionGroups = false; // Older files will be missing this block.
        for (int i = 0; i < (int) node.getChildren().size(); i++) {
            if (node.getChildren()[i].getName() == "InteractionGroups")
                hasInteractionGroups = true;
        }
        if (hasInteractionGroups) {
            const SerializationNode& interactionGroups = node.getChildNode("InteractionGroups");
            for (int i = 0; i < (int) interactionGroups.getChildren().size(); i++) {
                const SerializationNode& interactionGroup = interactionGroups.getChildren()[i];
                // Get set 1.
                const SerializationNode& set1node = interactionGroup.getChildNode("Set1");
                std::set<int> set1;
                for (int j = 0; j < (int) set1node.getChildren().size(); j++)
                    set1.insert(set1node.getChildren()[j].getIntProperty("index"));
                // Get set 2.
                const SerializationNode& set2node = interactionGroup.getChildNode("Set2");
                std::set<int> set2;
                for (int j = 0; j < (int) set2node.getChildren().size(); j++)
                    set2.insert(set2node.getChildren()[j].getIntProperty("index"));
                force->addInteractionGroup(set1, set2);
            }
        }
        return force;
    }
    catch (...) {
        if (force != NULL)
            delete force;
        throw;
    }
}