#include "Test.h"

#include "Log.h"
#include "User.h"

#include "Lock.h"
#include "Timer.h"
#include "Atom.h"
#include "Model.h"
#include "Model_kit.h"
#include "Path.h"
#include "Create.h"
#include "Force_field.h"
#include "Conventional_interactions.h"
#include "RMS_gradient.h"

#include "MinMax.h"

namespace MM
{

class Nonbonded_interactions_test_performance : public Test
{
    Conventional_interactions     *link;
    Force_field             *force_field_;
    Text                     text;

public:
    Nonbonded_interactions_test_performance (const Text & suite_name) 
        : Test (suite_name) 
    {
    }
    
    void run()
    {
        force_field_ = new Force_field ("AMBER94");

        test_I512         ();         count_tests();
        test_I4096        ();         count_tests();
        
        delete force_field_;
    }

    void test_I512 ()
    {
        text = "";
        int i, cycles = 100;
        double E, min_time, mean_time;
        double  time;
        Own <Model>     model (prototype <Model> (). clone ());
        model(). load (Path::tests() + "I512.hin");
        model().kit().set_force_field ("AMBER94");
        Conventional_interactions interactions (model());
        
        {
            Lock <Conventional_interactions> lock (interactions);

            E = 0., min_time = 1000000, mean_time = 0;
            Timer timer;
          
            for (i=0;  i<cycles;  ++i)
            {
                timer.restart ();

                E = interactions.potential ();

                time = timer.elapsed();
                mean_time += time;
                min_time = min (min_time, time);
            }
            text = Text(" E = ") + E + "     " + min_time + 
                " (" + (mean_time/cycles) +") sec   ";

            DOUBLES_EQUAL (E, 218.613681734554, 0.000000000001);
            // 0.0066 sec 0.0033

            E = 0., min_time = 1000000, mean_time = 0;
          
            for (i=0;  i<cycles;  ++i)
            {
                timer.restart ();

                interactions.add_force ();

                time = timer.elapsed();
                mean_time += time;
                min_time = min (min_time, time);
            }
        }

        double F = RMS_gradient (model()).value();
        //double F = 0;
        text += Text(" F = ") + F + "     " + min_time + 
                " (" + (mean_time/cycles) +") sec   ";

        DOUBLES_EQUAL (F, 2.666323, 0.00001);

        to_user(). status (text);
    }

    void test_I4096 ()
    {
        int i, cycles = 4;
        double E, min_time, mean_time;
        double  time;
        Own <Model>     model (prototype <Model> (). clone ());
        model(). load (Path::tests() + "I4096.hin");
        model().kit().set_force_field ("AMBER94");
        Conventional_interactions interactions (model()/*, *force_field_*/);
        
        {
            Lock <Conventional_interactions> lock (interactions);

            E = 0., min_time = 1000000, mean_time = 0;
            Timer timer;
          
            for (i=0;  i<cycles;  ++i)
            {
                timer.restart ();

                E = interactions.potential ();

                time = timer.elapsed();
                mean_time += time;
                min_time = min (min_time, time);
            }
            text += Text("    E = ") + E + "     " + min_time + 
                " (" + (mean_time/cycles) +") sec   ";

            DOUBLES_EQUAL (E, 1135.91, 0.01);
            // 0.37

            E = 0., min_time = 1000000, mean_time = 0;
          
            for (i=0;  i<cycles;  ++i)
            {
                timer.restart ();

                interactions.add_force ();

                time = timer.elapsed();
                mean_time += time;
                min_time = min (min_time, time);
            }
        }

        //double F = RMS_gradient (model()).value();

        //text += Text(" F = ") + F + "     " + min_time + 
        //        " (" + (mean_time/cycles) +") sec   ";

        //DOUBLES_EQUAL (F, 2.666323, 0.00001);

        to_user(). status (text);
    }
};

Nonbonded_interactions_test_performance 
    test_performance_nonbonded_interactions ("performance");

}//MM
