<commit_before>// Copyright © 2010-2015 The CefSharp Project. All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
#pragma once

#include "Stdafx.h"

#include "CefBrowserWrapper.h"
#include "CefAppUnmanagedWrapper.h"
#include "JavascriptRootObjectWrapper.h"
#include "Serialization\V8Serialization.h"
#include "Serialization\JsObjectsSerialization.h"
#include "Async/JavascriptAsyncMethodCallback.h"
#include "..\CefSharp.Core\Internals\Messaging\Messages.h"
#include "..\CefSharp.Core\Internals\Serialization\Primitives.h"

using namespace System::Diagnostics;
using namespace System::Collections::Generic;
using namespace CefSharp::Internals::Messaging;
using namespace CefSharp::Internals::Serialization;

namespace CefSharp
{
    const CefString CefAppUnmanagedWrapper::kPromiseCreatorFunction = "cefsharp_CreatePromise";
    const CefString CefAppUnmanagedWrapper::kPromiseCreatorScript = ""
        "function cefsharp_CreatePromise() {"
        "   var object = {};"
        "   var promise = new Promise(function(resolve, reject) {"
        "       object.resolve = resolve;object.reject = reject;"
        "   });"
        "   return{ p: promise, res : object.resolve,  rej: object.reject};"
        "}";

    CefRefPtr<CefRenderProcessHandler> CefAppUnmanagedWrapper::GetRenderProcessHandler()
    {
        return this;
    };

    // CefRenderProcessHandler
    void CefAppUnmanagedWrapper::OnBrowserCreated(CefRefPtr<CefBrowser> browser)
    {
        auto wrapper = gcnew CefBrowserWrapper(browser);
        _onBrowserCreated->Invoke(wrapper);

        //Multiple CefBrowserWrappers created when opening popups
        _browserWrappers->TryAdd(browser->GetIdentifier(), wrapper);
    }

    void CefAppUnmanagedWrapper::OnBrowserDestroyed(CefRefPtr<CefBrowser> browser)
    {
        CefBrowserWrapper^ wrapper;
        if (_browserWrappers->TryRemove(browser->GetIdentifier(), wrapper))
        {
            _onBrowserDestroyed->Invoke(wrapper);
            delete wrapper;
        }
    };

    void CefAppUnmanagedWrapper::OnContextCreated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context)
    {
        auto browserWrapper = FindBrowserWrapper(browser->GetIdentifier(), true);

        if (!Object::ReferenceEquals(_javascriptRootObject, nullptr) || !Object::ReferenceEquals(_javascriptAsyncRootObject, nullptr))
        {
            auto rootObjectWrappers = browserWrapper->JavascriptRootObjectWrappers;
            auto frameId = frame->GetIdentifier();

            if (rootObjectWrappers->ContainsKey(frameId))
            {
                LOG(WARNING) << "A context has been created for the same browser / frame without context released called previously";
            }
            else
            {
                auto rootObject = gcnew JavascriptRootObjectWrapper(browser->GetIdentifier(), browserWrapper->BrowserProcess);
                rootObject->Bind(_javascriptRootObject, _javascriptAsyncRootObject, context->GetGlobal());

                rootObjectWrappers->TryAdd(frameId, rootObject);
            }
        }
    };

    void CefAppUnmanagedWrapper::OnContextReleased(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context)
    {
        auto browserWrapper = FindBrowserWrapper(browser->GetIdentifier(), true);

        auto rootObjectWrappers = browserWrapper->JavascriptRootObjectWrappers;

        JavascriptRootObjectWrapper^ wrapper;
        if (rootObjectWrappers->TryRemove(frame->GetIdentifier(), wrapper))
        {
            delete wrapper;
        }
    };

    CefBrowserWrapper^ CefAppUnmanagedWrapper::FindBrowserWrapper(int browserId, bool mustExist)
    {
        CefBrowserWrapper^ wrapper = nullptr;

        _browserWrappers->TryGetValue(browserId, wrapper);

        if (mustExist && wrapper == nullptr)
        {
            throw gcnew InvalidOperationException(String::Format("Failed to identify BrowserWrapper in OnContextCreated. : {0}", browserId));
        }

        return wrapper;
    }

    bool CefAppUnmanagedWrapper::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser, CefProcessId sourceProcessId, CefRefPtr<CefProcessMessage> message)
    {
        auto handled = false;
        auto name = message->GetName();
        auto argList = message->GetArgumentList();

        auto browserWrapper = FindBrowserWrapper(browser->GetIdentifier(), false);
        //Error handling for missing/closed browser
        if (browserWrapper == nullptr)
        {
            if (name == kJavascriptCallbackDestroyRequest ||
                name == kJavascriptRootObjectRequest ||
                name == kJavascriptAsyncMethodCallResponse)
            {
                //If we can't find the browser wrapper then we'll just
                //ignore this as it's likely already been disposed of
                return true;
            }

            CefString responseName;
            if (name == kEvaluateJavascriptRequest)
            {
                responseName = kEvaluateJavascriptResponse;
            }
            else if (name == kJavascriptCallbackRequest)
            {
                responseName = kJavascriptCallbackResponse;
            }
            else
            {
                //TODO: Should be throw an exception here? It's likely that only a CefSharp developer would see this
                // when they added a new message and havn't yet implemented the render process functionality.
                throw gcnew Exception("Unsupported message type");
            }

            auto callbackId = GetInt64(argList, 1);
            auto response = CefProcessMessage::Create(responseName);
            auto responseArgList = response->GetArgumentList();
            auto errorMessage = String::Format("Request BrowserId : {0} not found it's likely the browser is already closed", browser->GetIdentifier());

            //success: false
            responseArgList->SetBool(0, false);
            SetInt64(callbackId, responseArgList, 1);
            responseArgList->SetString(2, StringUtils::ToNative(errorMessage));
            browser->SendProcessMessage(sourceProcessId, response);

            return true;
        }

        //these messages are roughly handled the same way
        if (name == kEvaluateJavascriptRequest || name == kJavascriptCallbackRequest)
        {
            bool success;
            CefRefPtr<CefV8Value> result;
            CefString errorMessage;
            CefRefPtr<CefProcessMessage> response;
            //both messages have the frameId stored at 0 and callbackId stored at index 1
            auto frameId = GetInt64(argList, 0);
            int64 callbackId = GetInt64(argList, 1);

            JavascriptRootObjectWrapper^ rootObjectWrapper;
            browserWrapper->JavascriptRootObjectWrappers->TryGetValue(frameId, rootObjectWrapper);
            auto callbackRegistry = rootObjectWrapper == nullptr ? nullptr : rootObjectWrapper->CallbackRegistry;
            if (callbackRegistry == nullptr)
            {
                success = false;
                errorMessage = StringUtils::ToNative("Frame " + frameId + " is no longer available, most likely the Frame has been Disposed.");
            }
            else if (name == kEvaluateJavascriptRequest)
            {
                auto script = argList->GetString(2);

                response = CefProcessMessage::Create(kEvaluateJavascriptResponse);

                auto frame = browser->GetFrame(frameId);
                if (frame.get())
                {
                    auto context = frame->GetV8Context();

                    if (context.get() && context->Enter())
                    {
                        try
                        {
                            CefRefPtr<CefV8Exception> exception;
                            success = context->Eval(script, result, exception);

                            //we need to do this here to be able to store the v8context
                            if (success)
                            {
                                auto responseArgList = response->GetArgumentList();
                                SerializeV8Object(result, responseArgList, 2, callbackRegistry);
                            }
                            else
                            {
                                errorMessage = exception->GetMessage();
                            }
                        }
                        finally
                        {
                            context->Exit();
                        }
                    }
                    else
                    {
                        errorMessage = "Unable to Enter Context";
                    }
                }
                else
                {
                    errorMessage = "Unable to Get Frame matching Id";
                }
            }
            else
            {
                auto jsCallbackId = GetInt64(argList, 2);
                auto parameterList = argList->GetList(3);
                CefV8ValueList params;
                for (CefV8ValueList::size_type i = 0; i < parameterList->GetSize(); i++)
                {
                    params.push_back(DeserializeV8Object(parameterList, static_cast<int>(i)));
                }

                response = CefProcessMessage::Create(kJavascriptCallbackResponse);

                auto callbackWrapper = callbackRegistry->FindWrapper(jsCallbackId);
                auto context = callbackWrapper->GetContext();
                auto value = callbackWrapper->GetValue();

                if (context.get() && context->Enter())
                {
                    try
                    {
                        result = value->ExecuteFunction(nullptr, params);
                        success = result.get() != nullptr;

                        //we need to do this here to be able to store the v8context
                        if (success)
                        {
                            auto responseArgList = response->GetArgumentList();
                            SerializeV8Object(result, responseArgList, 2, callbackRegistry);
                        }
                        else
                        {
                            auto exception = value->GetException();
                            if (exception.get())
                            {
                                errorMessage = exception->GetMessage();
                            }
                        }
                    }
                    finally
                    {
                        context->Exit();
                    }
                }
                else
                {
                    errorMessage = "Unable to Enter Context";
                }
            }

            if (response.get())
            {
                auto responseArgList = response->GetArgumentList();
                responseArgList->SetBool(0, success);
                SetInt64(callbackId, responseArgList, 1);
                if (!success)
                {
                    responseArgList->SetString(2, errorMessage);
                }
                browser->SendProcessMessage(sourceProcessId, response);
            }

            handled = true;
        }
        else if (name == kJavascriptCallbackDestroyRequest)
        {
            auto jsCallbackId = GetInt64(argList, 0);
            auto frameId = GetInt64(argList, 1);
            JavascriptRootObjectWrapper^ rootObjectWrapper;
            browserWrapper->JavascriptRootObjectWrappers->TryGetValue(frameId, rootObjectWrapper);
            if (rootObjectWrapper != nullptr && rootObjectWrapper->CallbackRegistry != nullptr)
            {
                rootObjectWrapper->CallbackRegistry->Deregister(jsCallbackId);
            }

            handled = true;
        }
        else if (name == kJavascriptRootObjectRequest)
        {
            _javascriptAsyncRootObject = DeserializeJsRootObject(argList, 0);
            _javascriptRootObject = DeserializeJsRootObject(argList, 1);
            handled = true;
        }
        else if (name == kJavascriptAsyncMethodCallResponse)
        {
            auto frameId = GetInt64(argList, 0);
            auto callbackId = GetInt64(argList, 1);

            JavascriptRootObjectWrapper^ rootObjectWrapper;
            browserWrapper->JavascriptRootObjectWrappers->TryGetValue(frameId, rootObjectWrapper);

            if (rootObjectWrapper != nullptr)
            {
                JavascriptAsyncMethodCallback^ callback;
                if (rootObjectWrapper->TryGetAndRemoveMethodCallback(callbackId, callback))
                {
                    auto success = argList->GetBool(2);
                    if (success)
                    {
                        callback->Success(DeserializeV8Object(argList, 3));
                    }
                    else
                    {
                        callback->Fail(argList->GetString(3));
                    }
                    //dispose
                    delete callback;
                }
            }
            handled = true;
        }

        return handled;
    };

    void CefAppUnmanagedWrapper::OnRenderThreadCreated(CefRefPtr<CefListValue> extraInfo)
    {
        auto extensionList = extraInfo->GetList(0);

        for (size_t i = 0; i < extensionList->GetSize(); i++)
        {
            auto extension = extensionList->GetList(i);
            auto ext = gcnew CefExtension(StringUtils::ToClr(extension->GetString(0)), StringUtils::ToClr(extension->GetString(1)));

            _extensions->Add(ext);
        }
    }

    void CefAppUnmanagedWrapper::OnWebKitInitialized()
    {
        //we need to do this because the builtin Promise object is not accesible
        CefRegisterExtension("cefsharp/promisecreator", kPromiseCreatorScript, NULL);

        for each(CefExtension^ extension in _extensions->AsReadOnly())
        {
            //only support extensions without handlers now
            CefRegisterExtension(StringUtils::ToNative(extension->Name), StringUtils::ToNative(extension->JavascriptCode), NULL);
        }
    }

    void CefAppUnmanagedWrapper::OnRegisterCustomSchemes(CefRefPtr<CefSchemeRegistrar> registrar)
    {
        for each (CefCustomScheme^ scheme in _schemes->AsReadOnly())
        {
            registrar->AddCustomScheme(StringUtils::ToNative(scheme->SchemeName), scheme->IsStandard, scheme->IsLocal, scheme->IsDisplayIsolated);
        }
    }
}<commit_msg>create a root object even if no objects have been registered but only bind the root object if objects are available<commit_after>// Copyright © 2010-2015 The CefSharp Project. All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
#pragma once

#include "Stdafx.h"

#include "CefBrowserWrapper.h"
#include "CefAppUnmanagedWrapper.h"
#include "JavascriptRootObjectWrapper.h"
#include "Serialization\V8Serialization.h"
#include "Serialization\JsObjectsSerialization.h"
#include "Async/JavascriptAsyncMethodCallback.h"
#include "..\CefSharp.Core\Internals\Messaging\Messages.h"
#include "..\CefSharp.Core\Internals\Serialization\Primitives.h"

using namespace System::Diagnostics;
using namespace System::Collections::Generic;
using namespace CefSharp::Internals::Messaging;
using namespace CefSharp::Internals::Serialization;

namespace CefSharp
{
    const CefString CefAppUnmanagedWrapper::kPromiseCreatorFunction = "cefsharp_CreatePromise";
    const CefString CefAppUnmanagedWrapper::kPromiseCreatorScript = ""
        "function cefsharp_CreatePromise() {"
        "   var object = {};"
        "   var promise = new Promise(function(resolve, reject) {"
        "       object.resolve = resolve;object.reject = reject;"
        "   });"
        "   return{ p: promise, res : object.resolve,  rej: object.reject};"
        "}";

    CefRefPtr<CefRenderProcessHandler> CefAppUnmanagedWrapper::GetRenderProcessHandler()
    {
        return this;
    };

    // CefRenderProcessHandler
    void CefAppUnmanagedWrapper::OnBrowserCreated(CefRefPtr<CefBrowser> browser)
    {
        auto wrapper = gcnew CefBrowserWrapper(browser);
        _onBrowserCreated->Invoke(wrapper);

        //Multiple CefBrowserWrappers created when opening popups
        _browserWrappers->TryAdd(browser->GetIdentifier(), wrapper);
    }

    void CefAppUnmanagedWrapper::OnBrowserDestroyed(CefRefPtr<CefBrowser> browser)
    {
        CefBrowserWrapper^ wrapper;
        if (_browserWrappers->TryRemove(browser->GetIdentifier(), wrapper))
        {
            _onBrowserDestroyed->Invoke(wrapper);
            delete wrapper;
        }
    };

    void CefAppUnmanagedWrapper::OnContextCreated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context)
    {
        auto browserWrapper = FindBrowserWrapper(browser->GetIdentifier(), true);

        auto rootObjectWrappers = browserWrapper->JavascriptRootObjectWrappers;
        auto frameId = frame->GetIdentifier();

        if (rootObjectWrappers->ContainsKey(frameId))
        {
            LOG(WARNING) << "A context has been created for the same browser / frame without context released called previously";
        }
        else
        {
            auto rootObject = gcnew JavascriptRootObjectWrapper(browser->GetIdentifier(), browserWrapper->BrowserProcess);
            if (!Object::ReferenceEquals(_javascriptRootObject, nullptr) || !Object::ReferenceEquals(_javascriptAsyncRootObject, nullptr))
            {
                rootObject->Bind(_javascriptRootObject, _javascriptAsyncRootObject, context->GetGlobal());
            }

            rootObjectWrappers->TryAdd(frameId, rootObject);
        }
    };

    void CefAppUnmanagedWrapper::OnContextReleased(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context)
    {
        auto browserWrapper = FindBrowserWrapper(browser->GetIdentifier(), true);

        auto rootObjectWrappers = browserWrapper->JavascriptRootObjectWrappers;

        JavascriptRootObjectWrapper^ wrapper;
        if (rootObjectWrappers->TryRemove(frame->GetIdentifier(), wrapper))
        {
            delete wrapper;
        }
    };

    CefBrowserWrapper^ CefAppUnmanagedWrapper::FindBrowserWrapper(int browserId, bool mustExist)
    {
        CefBrowserWrapper^ wrapper = nullptr;

        _browserWrappers->TryGetValue(browserId, wrapper);

        if (mustExist && wrapper == nullptr)
        {
            throw gcnew InvalidOperationException(String::Format("Failed to identify BrowserWrapper in OnContextCreated. : {0}", browserId));
        }

        return wrapper;
    }

    bool CefAppUnmanagedWrapper::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser, CefProcessId sourceProcessId, CefRefPtr<CefProcessMessage> message)
    {
        auto handled = false;
        auto name = message->GetName();
        auto argList = message->GetArgumentList();

        auto browserWrapper = FindBrowserWrapper(browser->GetIdentifier(), false);
        //Error handling for missing/closed browser
        if (browserWrapper == nullptr)
        {
            if (name == kJavascriptCallbackDestroyRequest ||
                name == kJavascriptRootObjectRequest ||
                name == kJavascriptAsyncMethodCallResponse)
            {
                //If we can't find the browser wrapper then we'll just
                //ignore this as it's likely already been disposed of
                return true;
            }

            CefString responseName;
            if (name == kEvaluateJavascriptRequest)
            {
                responseName = kEvaluateJavascriptResponse;
            }
            else if (name == kJavascriptCallbackRequest)
            {
                responseName = kJavascriptCallbackResponse;
            }
            else
            {
                //TODO: Should be throw an exception here? It's likely that only a CefSharp developer would see this
                // when they added a new message and havn't yet implemented the render process functionality.
                throw gcnew Exception("Unsupported message type");
            }

            auto callbackId = GetInt64(argList, 1);
            auto response = CefProcessMessage::Create(responseName);
            auto responseArgList = response->GetArgumentList();
            auto errorMessage = String::Format("Request BrowserId : {0} not found it's likely the browser is already closed", browser->GetIdentifier());

            //success: false
            responseArgList->SetBool(0, false);
            SetInt64(callbackId, responseArgList, 1);
            responseArgList->SetString(2, StringUtils::ToNative(errorMessage));
            browser->SendProcessMessage(sourceProcessId, response);

            return true;
        }

        //these messages are roughly handled the same way
        if (name == kEvaluateJavascriptRequest || name == kJavascriptCallbackRequest)
        {
            bool success;
            CefRefPtr<CefV8Value> result;
            CefString errorMessage;
            CefRefPtr<CefProcessMessage> response;
            //both messages have the frameId stored at 0 and callbackId stored at index 1
            auto frameId = GetInt64(argList, 0);
            int64 callbackId = GetInt64(argList, 1);

            JavascriptRootObjectWrapper^ rootObjectWrapper;
            browserWrapper->JavascriptRootObjectWrappers->TryGetValue(frameId, rootObjectWrapper);
            auto callbackRegistry = rootObjectWrapper == nullptr ? nullptr : rootObjectWrapper->CallbackRegistry;
            if (callbackRegistry == nullptr)
            {
                success = false;
                errorMessage = StringUtils::ToNative("Frame " + frameId + " is no longer available, most likely the Frame has been Disposed.");
            }
            else if (name == kEvaluateJavascriptRequest)
            {
                auto script = argList->GetString(2);

                response = CefProcessMessage::Create(kEvaluateJavascriptResponse);

                auto frame = browser->GetFrame(frameId);
                if (frame.get())
                {
                    auto context = frame->GetV8Context();

                    if (context.get() && context->Enter())
                    {
                        try
                        {
                            CefRefPtr<CefV8Exception> exception;
                            success = context->Eval(script, result, exception);

                            //we need to do this here to be able to store the v8context
                            if (success)
                            {
                                auto responseArgList = response->GetArgumentList();
                                SerializeV8Object(result, responseArgList, 2, callbackRegistry);
                            }
                            else
                            {
                                errorMessage = exception->GetMessage();
                            }
                        }
                        finally
                        {
                            context->Exit();
                        }
                    }
                    else
                    {
                        errorMessage = "Unable to Enter Context";
                    }
                }
                else
                {
                    errorMessage = "Unable to Get Frame matching Id";
                }
            }
            else
            {
                auto jsCallbackId = GetInt64(argList, 2);
                auto parameterList = argList->GetList(3);
                CefV8ValueList params;
                for (CefV8ValueList::size_type i = 0; i < parameterList->GetSize(); i++)
                {
                    params.push_back(DeserializeV8Object(parameterList, static_cast<int>(i)));
                }

                response = CefProcessMessage::Create(kJavascriptCallbackResponse);

                auto callbackWrapper = callbackRegistry->FindWrapper(jsCallbackId);
                auto context = callbackWrapper->GetContext();
                auto value = callbackWrapper->GetValue();

                if (context.get() && context->Enter())
                {
                    try
                    {
                        result = value->ExecuteFunction(nullptr, params);
                        success = result.get() != nullptr;

                        //we need to do this here to be able to store the v8context
                        if (success)
                        {
                            auto responseArgList = response->GetArgumentList();
                            SerializeV8Object(result, responseArgList, 2, callbackRegistry);
                        }
                        else
                        {
                            auto exception = value->GetException();
                            if (exception.get())
                            {
                                errorMessage = exception->GetMessage();
                            }
                        }
                    }
                    finally
                    {
                        context->Exit();
                    }
                }
                else
                {
                    errorMessage = "Unable to Enter Context";
                }
            }

            if (response.get())
            {
                auto responseArgList = response->GetArgumentList();
                responseArgList->SetBool(0, success);
                SetInt64(callbackId, responseArgList, 1);
                if (!success)
                {
                    responseArgList->SetString(2, errorMessage);
                }
                browser->SendProcessMessage(sourceProcessId, response);
            }

            handled = true;
        }
        else if (name == kJavascriptCallbackDestroyRequest)
        {
            auto jsCallbackId = GetInt64(argList, 0);
            auto frameId = GetInt64(argList, 1);
            JavascriptRootObjectWrapper^ rootObjectWrapper;
            browserWrapper->JavascriptRootObjectWrappers->TryGetValue(frameId, rootObjectWrapper);
            if (rootObjectWrapper != nullptr && rootObjectWrapper->CallbackRegistry != nullptr)
            {
                rootObjectWrapper->CallbackRegistry->Deregister(jsCallbackId);
            }

            handled = true;
        }
        else if (name == kJavascriptRootObjectRequest)
        {
            _javascriptAsyncRootObject = DeserializeJsRootObject(argList, 0);
            _javascriptRootObject = DeserializeJsRootObject(argList, 1);
            handled = true;
        }
        else if (name == kJavascriptAsyncMethodCallResponse)
        {
            auto frameId = GetInt64(argList, 0);
            auto callbackId = GetInt64(argList, 1);

            JavascriptRootObjectWrapper^ rootObjectWrapper;
            browserWrapper->JavascriptRootObjectWrappers->TryGetValue(frameId, rootObjectWrapper);

            if (rootObjectWrapper != nullptr)
            {
                JavascriptAsyncMethodCallback^ callback;
                if (rootObjectWrapper->TryGetAndRemoveMethodCallback(callbackId, callback))
                {
                    auto success = argList->GetBool(2);
                    if (success)
                    {
                        callback->Success(DeserializeV8Object(argList, 3));
                    }
                    else
                    {
                        callback->Fail(argList->GetString(3));
                    }
                    //dispose
                    delete callback;
                }
            }
            handled = true;
        }

        return handled;
    };

    void CefAppUnmanagedWrapper::OnRenderThreadCreated(CefRefPtr<CefListValue> extraInfo)
    {
        auto extensionList = extraInfo->GetList(0);

        for (size_t i = 0; i < extensionList->GetSize(); i++)
        {
            auto extension = extensionList->GetList(i);
            auto ext = gcnew CefExtension(StringUtils::ToClr(extension->GetString(0)), StringUtils::ToClr(extension->GetString(1)));

            _extensions->Add(ext);
        }
    }

    void CefAppUnmanagedWrapper::OnWebKitInitialized()
    {
        //we need to do this because the builtin Promise object is not accesible
        CefRegisterExtension("cefsharp/promisecreator", kPromiseCreatorScript, NULL);

        for each(CefExtension^ extension in _extensions->AsReadOnly())
        {
            //only support extensions without handlers now
            CefRegisterExtension(StringUtils::ToNative(extension->Name), StringUtils::ToNative(extension->JavascriptCode), NULL);
        }
    }

    void CefAppUnmanagedWrapper::OnRegisterCustomSchemes(CefRefPtr<CefSchemeRegistrar> registrar)
    {
        for each (CefCustomScheme^ scheme in _schemes->AsReadOnly())
        {
            registrar->AddCustomScheme(StringUtils::ToNative(scheme->SchemeName), scheme->IsStandard, scheme->IsLocal, scheme->IsDisplayIsolated);
        }
    }
}<|endoftext|>


<commit_before>// @(#)root/thread:$Id$
// Author: Enric Tejedor, CERN  12/09/2016

/*************************************************************************
 * Copyright (C) 1995-2016, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

/** \class ROOT::TTreeProcessorMT
    \ingroup Parallelism
    \brief A class to process the entries of a TTree in parallel.

By means of its Process method, ROOT::TTreeProcessorMT provides a way to process the
entries of a TTree in parallel. When invoking TTreeProcessor::Process, the user
passes a function whose only parameter is a TTreeReader. The function iterates
on a subrange of entries by using that TTreeReader.

The implementation of ROOT::TTreeProcessorMT parallelizes the processing of the subranges,
each corresponding to a cluster in the TTree. This is possible thanks to the use
of a ROOT::TThreadedObject, so that each thread works with its own TFile and TTree
objects.
*/

#include "TROOT.h"
#include "ROOT/TTreeProcessorMT.hxx"
#include "ROOT/TThreadExecutor.hxx"

using namespace ROOT;

namespace ROOT {
namespace Internal {
////////////////////////////////////////////////////////////////////////
/// Return a vector of cluster boundaries for the given tree and files.
ClustersAndEntries
MakeClusters(const std::string &treeName, const std::vector<std::string> &fileNames)
{
   // Note that as a side-effect of opening all files that are going to be used in the
   // analysis once, all necessary streamers will be loaded into memory.
   TDirectory::TContext c;
   std::vector<std::vector<EntryCluster>> clustersPerFile;
   std::vector<Long64_t> entriesPerFile;
   const auto nFileNames = fileNames.size();
   Long64_t offset = 0ll;
   for (auto i = 0u; i < nFileNames; ++i) {
      std::unique_ptr<TFile> f(TFile::Open(fileNames[i].c_str())); // need TFile::Open to load plugins if need be
      TTree *t = nullptr; // not a leak, t will be deleted by f
      f->GetObject(treeName.c_str(), t);
      auto clusterIter = t->GetClusterIterator(0);
      Long64_t start = 0ll, end = 0ll;
      const Long64_t entries = t->GetEntries();
      // Iterate over the clusters in the current file
      std::vector<EntryCluster> clusters;
      while ((start = clusterIter()) < entries) {
         end = clusterIter.GetNextEntry();
         // Add the current file's offset to start and end to make them (chain) global
         clusters.emplace_back(EntryCluster{start + offset, end + offset});
      }
      offset += entries;
      clustersPerFile.emplace_back(std::move(clusters));
      entriesPerFile.emplace_back(entries);
   }

   return std::make_pair(std::move(clustersPerFile), std::move(entriesPerFile));
}

////////////////////////////////////////////////////////////////////////
/// Return a vector containing the number of entries of each file of each friend TChain
std::vector<std::vector<Long64_t>> GetFriendEntries(const std::vector<std::pair<std::string, std::string>> &friendNames,
                                                    const std::vector<std::vector<std::string>> &friendFileNames)
{
   std::vector<std::vector<Long64_t>> friendEntries;
   const auto nFriends = friendNames.size();
   for (auto i = 0u; i < nFriends; ++i) {
      std::vector<Long64_t> nEntries;
      const auto &thisFriendName = friendNames[i].first;
      const auto &thisFriendFiles = friendFileNames[i];
      for (const auto &fname : thisFriendFiles) {
         std::unique_ptr<TFile> f(TFile::Open(fname.c_str()));
         TTree *t = nullptr; // owned by TFile
         f->GetObject(thisFriendName.c_str(), t);
         nEntries.emplace_back(t->GetEntries());
      }
      friendEntries.emplace_back(std::move(nEntries));
   }

   return friendEntries;
}
}
}

////////////////////////////////////////////////////////////////////////
/// Constructor based on a file name.
/// \param[in] filename Name of the file containing the tree to process.
/// \param[in] treename Name of the tree to process. If not provided,
///                     the implementation will automatically search for a
///                     tree in the file.
TTreeProcessorMT::TTreeProcessorMT(std::string_view filename, std::string_view treename) : treeView(filename, treename) {}

////////////////////////////////////////////////////////////////////////
/// Constructor based on a collection of file names.
/// \param[in] filenames Collection of the names of the files containing the tree to process.
/// \param[in] treename Name of the tree to process. If not provided,
///                     the implementation will automatically search for a
///                     tree in the collection of files.
TTreeProcessorMT::TTreeProcessorMT(const std::vector<std::string_view> &filenames, std::string_view treename) : treeView(filenames, treename) {}

////////////////////////////////////////////////////////////////////////
/// Constructor based on a TTree.
/// \param[in] tree Tree or chain of files containing the tree to process.
TTreeProcessorMT::TTreeProcessorMT(TTree &tree) : treeView(tree) {}

////////////////////////////////////////////////////////////////////////
/// Constructor based on a TTree and a TEntryList.
/// \param[in] tree Tree or chain of files containing the tree to process.
/// \param[in] entries List of entry numbers to process.
TTreeProcessorMT::TTreeProcessorMT(TTree &tree, TEntryList &entries) : treeView(tree, entries) {}

//////////////////////////////////////////////////////////////////////////////
/// Process the entries of a TTree in parallel. The user-provided function
/// receives a TTreeReader which can be used to iterate on a subrange of
/// entries
/// ~~~{.cpp}
/// TTreeProcessorMT::Process([](TTreeReader& readerSubRange) {
///                            // Select branches to read
///                            while (readerSubRange.next()) {
///                                // Use content of current entry
///                            }
///                         });
/// ~~~
/// The user needs to be aware that each of the subranges can potentially
/// be processed in parallel. This means that the code of the user function
/// should be thread safe.
///
/// \param[in] func User-defined function that processes a subrange of entries
void TTreeProcessorMT::Process(std::function<void(TTreeReader &)> func)
{
   // Enable this IMT use case (activate its locks)
   Internal::TParTreeProcessingRAII ptpRAII;

   // If an entry list or friend trees are present, we need to generate clusters with global entry numbers,
   // so we do it here for all files.
   const bool hasFriends = !treeView->GetFriendNames().empty();
   const bool hasEntryList = treeView->GetEntryList().GetN() > 0;
   const bool shouldRetrieveAllClusters = hasFriends || hasEntryList;
   const auto clustersAndEntries = shouldRetrieveAllClusters
                                      ? ROOT::Internal::MakeClusters(treeView->GetTreeName(), treeView->GetFileNames())
                                      : ROOT::Internal::ClustersAndEntries{};
   const auto &clusters = clustersAndEntries.first;
   const auto &entries = clustersAndEntries.second;

   // Retrieve number of entries for each file for each friend tree
   const auto friendEntries =
      hasFriends ? ROOT::Internal::GetFriendEntries(treeView->GetFriendNames(), treeView->GetFriendFileNames())
                 : std::vector<std::vector<Long64_t>>{};

   TThreadExecutor pool;
   // Parent task, spawns tasks that process each of the entry clusters for each input file
   using ROOT::Internal::EntryCluster;
   auto processFile = [&](std::size_t fileIdx) {

      // If cluster information is already present, build TChains with all input files and use global entry numbers
      // Otherwise get cluster information only for the file we need to process and use local entry numbers
      const bool shouldUseGlobalEntries = hasFriends || hasEntryList;
      // theseFiles contains either all files or just the single file to process
      const auto &theseFiles = shouldUseGlobalEntries ? treeView->GetFileNames()
                                                      : std::vector<std::string>({treeView->GetFileNames()[fileIdx]});
      // Evaluate clusters (with local entry numbers) and number of entries for this file, if needed
      const auto theseClustersAndEntries = shouldUseGlobalEntries
                                              ? Internal::ClustersAndEntries{}
                                              : Internal::MakeClusters(treeView->GetTreeName(), theseFiles);

      // All clusters for the file to process, either with global or local entry numbers
      const auto &thisFileClusters = shouldUseGlobalEntries ? clusters[fileIdx] : theseClustersAndEntries.first[0];

      // Either all number of entries or just the ones for this file
      const auto &theseEntries =
         shouldUseGlobalEntries ? entries : std::vector<Long64_t>({theseClustersAndEntries.second[0]});

      auto processCluster = [&](const ROOT::Internal::EntryCluster &c) {
         // This task will operate with the tree that contains start
         treeView->PushTaskFirstEntry(c.start);

         std::unique_ptr<TTreeReader> reader;
         std::unique_ptr<TEntryList> elist;
         std::tie(reader, elist) = treeView->GetTreeReader(c.start, c.end, theseFiles, theseEntries, friendEntries);
         func(*reader);

         // In case of task interleaving, we need to load here the tree of the parent task
         treeView->PopTaskFirstEntry();
      };

      pool.Foreach(processCluster, thisFileClusters);
   };

   std::vector<std::size_t> fileIdxs(treeView->GetFileNames().size());
   std::iota(fileIdxs.begin(), fileIdxs.end(), 0u);
   pool.Foreach(processFile, fileIdxs);
}
<commit_msg>[TREEPROCMT][NFC] Use Internal:: instead of ROOT::Internal<commit_after>// @(#)root/thread:$Id$
// Author: Enric Tejedor, CERN  12/09/2016

/*************************************************************************
 * Copyright (C) 1995-2016, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

/** \class ROOT::TTreeProcessorMT
    \ingroup Parallelism
    \brief A class to process the entries of a TTree in parallel.

By means of its Process method, ROOT::TTreeProcessorMT provides a way to process the
entries of a TTree in parallel. When invoking TTreeProcessor::Process, the user
passes a function whose only parameter is a TTreeReader. The function iterates
on a subrange of entries by using that TTreeReader.

The implementation of ROOT::TTreeProcessorMT parallelizes the processing of the subranges,
each corresponding to a cluster in the TTree. This is possible thanks to the use
of a ROOT::TThreadedObject, so that each thread works with its own TFile and TTree
objects.
*/

#include "TROOT.h"
#include "ROOT/TTreeProcessorMT.hxx"
#include "ROOT/TThreadExecutor.hxx"

using namespace ROOT;

namespace ROOT {
namespace Internal {
////////////////////////////////////////////////////////////////////////
/// Return a vector of cluster boundaries for the given tree and files.
ClustersAndEntries
MakeClusters(const std::string &treeName, const std::vector<std::string> &fileNames)
{
   // Note that as a side-effect of opening all files that are going to be used in the
   // analysis once, all necessary streamers will be loaded into memory.
   TDirectory::TContext c;
   std::vector<std::vector<EntryCluster>> clustersPerFile;
   std::vector<Long64_t> entriesPerFile;
   const auto nFileNames = fileNames.size();
   Long64_t offset = 0ll;
   for (auto i = 0u; i < nFileNames; ++i) {
      std::unique_ptr<TFile> f(TFile::Open(fileNames[i].c_str())); // need TFile::Open to load plugins if need be
      TTree *t = nullptr; // not a leak, t will be deleted by f
      f->GetObject(treeName.c_str(), t);
      auto clusterIter = t->GetClusterIterator(0);
      Long64_t start = 0ll, end = 0ll;
      const Long64_t entries = t->GetEntries();
      // Iterate over the clusters in the current file
      std::vector<EntryCluster> clusters;
      while ((start = clusterIter()) < entries) {
         end = clusterIter.GetNextEntry();
         // Add the current file's offset to start and end to make them (chain) global
         clusters.emplace_back(EntryCluster{start + offset, end + offset});
      }
      offset += entries;
      clustersPerFile.emplace_back(std::move(clusters));
      entriesPerFile.emplace_back(entries);
   }

   return std::make_pair(std::move(clustersPerFile), std::move(entriesPerFile));
}

////////////////////////////////////////////////////////////////////////
/// Return a vector containing the number of entries of each file of each friend TChain
std::vector<std::vector<Long64_t>> GetFriendEntries(const std::vector<std::pair<std::string, std::string>> &friendNames,
                                                    const std::vector<std::vector<std::string>> &friendFileNames)
{
   std::vector<std::vector<Long64_t>> friendEntries;
   const auto nFriends = friendNames.size();
   for (auto i = 0u; i < nFriends; ++i) {
      std::vector<Long64_t> nEntries;
      const auto &thisFriendName = friendNames[i].first;
      const auto &thisFriendFiles = friendFileNames[i];
      for (const auto &fname : thisFriendFiles) {
         std::unique_ptr<TFile> f(TFile::Open(fname.c_str()));
         TTree *t = nullptr; // owned by TFile
         f->GetObject(thisFriendName.c_str(), t);
         nEntries.emplace_back(t->GetEntries());
      }
      friendEntries.emplace_back(std::move(nEntries));
   }

   return friendEntries;
}
}
}

////////////////////////////////////////////////////////////////////////
/// Constructor based on a file name.
/// \param[in] filename Name of the file containing the tree to process.
/// \param[in] treename Name of the tree to process. If not provided,
///                     the implementation will automatically search for a
///                     tree in the file.
TTreeProcessorMT::TTreeProcessorMT(std::string_view filename, std::string_view treename) : treeView(filename, treename) {}

////////////////////////////////////////////////////////////////////////
/// Constructor based on a collection of file names.
/// \param[in] filenames Collection of the names of the files containing the tree to process.
/// \param[in] treename Name of the tree to process. If not provided,
///                     the implementation will automatically search for a
///                     tree in the collection of files.
TTreeProcessorMT::TTreeProcessorMT(const std::vector<std::string_view> &filenames, std::string_view treename) : treeView(filenames, treename) {}

////////////////////////////////////////////////////////////////////////
/// Constructor based on a TTree.
/// \param[in] tree Tree or chain of files containing the tree to process.
TTreeProcessorMT::TTreeProcessorMT(TTree &tree) : treeView(tree) {}

////////////////////////////////////////////////////////////////////////
/// Constructor based on a TTree and a TEntryList.
/// \param[in] tree Tree or chain of files containing the tree to process.
/// \param[in] entries List of entry numbers to process.
TTreeProcessorMT::TTreeProcessorMT(TTree &tree, TEntryList &entries) : treeView(tree, entries) {}

//////////////////////////////////////////////////////////////////////////////
/// Process the entries of a TTree in parallel. The user-provided function
/// receives a TTreeReader which can be used to iterate on a subrange of
/// entries
/// ~~~{.cpp}
/// TTreeProcessorMT::Process([](TTreeReader& readerSubRange) {
///                            // Select branches to read
///                            while (readerSubRange.next()) {
///                                // Use content of current entry
///                            }
///                         });
/// ~~~
/// The user needs to be aware that each of the subranges can potentially
/// be processed in parallel. This means that the code of the user function
/// should be thread safe.
///
/// \param[in] func User-defined function that processes a subrange of entries
void TTreeProcessorMT::Process(std::function<void(TTreeReader &)> func)
{
   // Enable this IMT use case (activate its locks)
   Internal::TParTreeProcessingRAII ptpRAII;

   // If an entry list or friend trees are present, we need to generate clusters with global entry numbers,
   // so we do it here for all files.
   const bool hasFriends = !treeView->GetFriendNames().empty();
   const bool hasEntryList = treeView->GetEntryList().GetN() > 0;
   const bool shouldRetrieveAllClusters = hasFriends || hasEntryList;
   const auto clustersAndEntries = shouldRetrieveAllClusters
                                      ? Internal::MakeClusters(treeView->GetTreeName(), treeView->GetFileNames())
                                      : Internal::ClustersAndEntries{};
   const auto &clusters = clustersAndEntries.first;
   const auto &entries = clustersAndEntries.second;

   // Retrieve number of entries for each file for each friend tree
   const auto friendEntries =
      hasFriends ? Internal::GetFriendEntries(treeView->GetFriendNames(), treeView->GetFriendFileNames())
                 : std::vector<std::vector<Long64_t>>{};

   TThreadExecutor pool;
   // Parent task, spawns tasks that process each of the entry clusters for each input file
   using Internal::EntryCluster;
   auto processFile = [&](std::size_t fileIdx) {

      // If cluster information is already present, build TChains with all input files and use global entry numbers
      // Otherwise get cluster information only for the file we need to process and use local entry numbers
      const bool shouldUseGlobalEntries = hasFriends || hasEntryList;
      // theseFiles contains either all files or just the single file to process
      const auto &theseFiles = shouldUseGlobalEntries ? treeView->GetFileNames()
                                                      : std::vector<std::string>({treeView->GetFileNames()[fileIdx]});
      // Evaluate clusters (with local entry numbers) and number of entries for this file, if needed
      const auto theseClustersAndEntries = shouldUseGlobalEntries
                                              ? Internal::ClustersAndEntries{}
                                              : Internal::MakeClusters(treeView->GetTreeName(), theseFiles);

      // All clusters for the file to process, either with global or local entry numbers
      const auto &thisFileClusters = shouldUseGlobalEntries ? clusters[fileIdx] : theseClustersAndEntries.first[0];

      // Either all number of entries or just the ones for this file
      const auto &theseEntries =
         shouldUseGlobalEntries ? entries : std::vector<Long64_t>({theseClustersAndEntries.second[0]});

      auto processCluster = [&](const Internal::EntryCluster &c) {
         // This task will operate with the tree that contains start
         treeView->PushTaskFirstEntry(c.start);

         std::unique_ptr<TTreeReader> reader;
         std::unique_ptr<TEntryList> elist;
         std::tie(reader, elist) = treeView->GetTreeReader(c.start, c.end, theseFiles, theseEntries, friendEntries);
         func(*reader);

         // In case of task interleaving, we need to load here the tree of the parent task
         treeView->PopTaskFirstEntry();
      };

      pool.Foreach(processCluster, thisFileClusters);
   };

   std::vector<std::size_t> fileIdxs(treeView->GetFileNames().size());
   std::iota(fileIdxs.begin(), fileIdxs.end(), 0u);
   pool.Foreach(processFile, fileIdxs);
}
<|endoftext|>


<commit_before>/*
 * Distributed under the OSI-approved Apache License, Version 2.0.  See
 * accompanying file Copyright.txt for details.
 *
 * MPIAggregator.cpp
 *
 *  Created on: Feb 20, 2018
 *      Author: William F Godoy godoywf@ornl.gov
 */

#include "MPIAggregator.h"

#include "adios2/helper/adiosFunctions.h"

namespace adios2
{
namespace aggregator
{

MPIAggregator::MPIAggregator() : m_Comm(MPI_COMM_NULL) {}

MPIAggregator::~MPIAggregator()
{
    if (m_IsActive)
    {
        helper::CheckMPIReturn(MPI_Comm_free(&m_Comm),
                               "freeing aggregators comm in MPIAggregator "
                               "destructor, not recommended");
    }
}

void MPIAggregator::Init(const size_t subStreams, MPI_Comm parentComm) {}

void MPIAggregator::SwapBuffers(const int step) noexcept {}

void MPIAggregator::ResetBuffers() noexcept {}

format::Buffer &MPIAggregator::GetConsumerBuffer(format::Buffer &buffer)
{
    return buffer;
}

void MPIAggregator::Close()
{
    if (m_IsActive)
    {
        helper::CheckMPIReturn(MPI_Comm_free(&m_Comm),
                               "freeing aggregators comm at Close\n");
        m_IsActive = false;
    }
}

// PROTECTED
void MPIAggregator::InitComm(const size_t subStreams, MPI_Comm parentComm)
{
    int parentRank;
    int parentSize;
    MPI_Comm_rank(parentComm, &parentRank);
    MPI_Comm_size(parentComm, &parentSize);

    const size_t processes = static_cast<size_t>(parentSize);
    size_t stride = processes / subStreams + 1;
    const size_t remainder = processes % subStreams;

    size_t consumer = 0;

    for (auto s = 0; s < subStreams; ++s)
    {
        if (s >= remainder)
        {
            stride = processes / subStreams;
        }

        if (static_cast<size_t>(parentRank) >= consumer &&
            static_cast<size_t>(parentRank) < consumer + stride)
        {
            helper::CheckMPIReturn(
                MPI_Comm_split(parentComm, static_cast<int>(consumer),
                               parentRank, &m_Comm),
                "creating aggregators comm with split at Open");
            m_ConsumerRank = static_cast<int>(consumer);
            m_SubStreamIndex = static_cast<size_t>(s);
        }

        consumer += stride;
    }

    MPI_Comm_rank(m_Comm, &m_Rank);
    MPI_Comm_size(m_Comm, &m_Size);

    if (m_Rank != 0)
    {
        m_IsConsumer = false;
    }

    m_IsActive = true;
    m_SubStreams = subStreams;
}

void MPIAggregator::HandshakeRank(const int rank)
{
    int message = -1;
    if (m_Rank == rank)
    {
        message = m_Rank;
    }

    helper::CheckMPIReturn(MPI_Bcast(&message, 1, MPI_INT, rank, m_Comm),
                           "handshake with aggregator rank 0 at Open");
}

} // end namespace aggregator
} // end namespace adios2
<commit_msg>aggregator: Simplify substream assignment logic<commit_after>/*
 * Distributed under the OSI-approved Apache License, Version 2.0.  See
 * accompanying file Copyright.txt for details.
 *
 * MPIAggregator.cpp
 *
 *  Created on: Feb 20, 2018
 *      Author: William F Godoy godoywf@ornl.gov
 */

#include "MPIAggregator.h"

#include "adios2/helper/adiosFunctions.h"

namespace adios2
{
namespace aggregator
{

MPIAggregator::MPIAggregator() : m_Comm(MPI_COMM_NULL) {}

MPIAggregator::~MPIAggregator()
{
    if (m_IsActive)
    {
        helper::CheckMPIReturn(MPI_Comm_free(&m_Comm),
                               "freeing aggregators comm in MPIAggregator "
                               "destructor, not recommended");
    }
}

void MPIAggregator::Init(const size_t subStreams, MPI_Comm parentComm) {}

void MPIAggregator::SwapBuffers(const int step) noexcept {}

void MPIAggregator::ResetBuffers() noexcept {}

format::Buffer &MPIAggregator::GetConsumerBuffer(format::Buffer &buffer)
{
    return buffer;
}

void MPIAggregator::Close()
{
    if (m_IsActive)
    {
        helper::CheckMPIReturn(MPI_Comm_free(&m_Comm),
                               "freeing aggregators comm at Close\n");
        m_IsActive = false;
    }
}

// PROTECTED
void MPIAggregator::InitComm(const size_t subStreams, MPI_Comm parentComm)
{
    int parentRank;
    int parentSize;
    MPI_Comm_rank(parentComm, &parentRank);
    MPI_Comm_size(parentComm, &parentSize);

    const size_t process = static_cast<size_t>(parentRank);
    const size_t processes = static_cast<size_t>(parentSize);

    // Divide the processes into S=subStreams groups.
    const size_t q = processes / subStreams;
    const size_t r = processes % subStreams;

    // Groups [0,r) have size q+1.  Groups [r,S) have size q.
    const size_t first_in_small_groups = r * (q + 1);

    // Within each group the first process becomes its consumer.
    if (process >= first_in_small_groups)
    {
        m_SubStreamIndex = r + (process - first_in_small_groups) / q;
        m_ConsumerRank = static_cast<int>(first_in_small_groups +
                                          (m_SubStreamIndex - r) * q);
    }
    else
    {
        m_SubStreamIndex = process / (q + 1);
        m_ConsumerRank = static_cast<int>(m_SubStreamIndex * (q + 1));
    }

    helper::CheckMPIReturn(
        MPI_Comm_split(parentComm, m_ConsumerRank, parentRank, &m_Comm),
        "creating aggregators comm with split at Open");

    MPI_Comm_rank(m_Comm, &m_Rank);
    MPI_Comm_size(m_Comm, &m_Size);

    if (m_Rank != 0)
    {
        m_IsConsumer = false;
    }

    m_IsActive = true;
    m_SubStreams = subStreams;
}

void MPIAggregator::HandshakeRank(const int rank)
{
    int message = -1;
    if (m_Rank == rank)
    {
        message = m_Rank;
    }

    helper::CheckMPIReturn(MPI_Bcast(&message, 1, MPI_INT, rank, m_Comm),
                           "handshake with aggregator rank 0 at Open");
}

} // end namespace aggregator
} // end namespace adios2
<|endoftext|>


<commit_before>/*
Highly Optimized Object-oriented Many-particle Dynamics -- Blue Edition
(HOOMD-blue) Open Source Software License Copyright 2008-2011 Ames Laboratory
Iowa State University and The Regents of the University of Michigan All rights
reserved.

HOOMD-blue may contain modifications ("Contributions") provided, and to which
copyright is held, by various Contributors who have granted The Regents of the
University of Michigan the right to modify and/or distribute such Contributions.

You may redistribute, use, and create derivate works of HOOMD-blue, in source
and binary forms, provided you abide by the following conditions:

* Redistributions of source code must retain the above copyright notice, this
list of conditions, and the following disclaimer both in the code and
prominently in any materials provided with the distribution.

* Redistributions in binary form must reproduce the above copyright notice, this
list of conditions, and the following disclaimer in the documentation and/or
other materials provided with the distribution.

* All publications and presentations based on HOOMD-blue, including any reports
or published results obtained, in whole or in part, with HOOMD-blue, will
acknowledge its use according to the terms posted at the time of submission on:
http://codeblue.umich.edu/hoomd-blue/citations.html

* Any electronic documents citing HOOMD-Blue will link to the HOOMD-Blue website:
http://codeblue.umich.edu/hoomd-blue/

* Apart from the above required attributions, neither the name of the copyright
holder nor the names of HOOMD-blue's contributors may be used to endorse or
promote products derived from this software without specific prior written
permission.

Disclaimer

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND/OR ANY
WARRANTIES THAT THIS SOFTWARE IS FREE OF INFRINGEMENT ARE DISCLAIMED.

IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifdef WIN32
#pragma warning( push )
#pragma warning( disable : 4103 4244 )
#endif

#include <boost/python.hpp>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/shared_ptr.hpp>

#include <iostream>
#include <fstream>

#include "PPPMForceCompute.h"
#ifdef ENABLE_CUDA
#include "PPPMForceComputeGPU.h"
#endif

#include "NeighborListBinned.h"
#include "Initializers.h"

#include <math.h>

using namespace std;
using namespace boost;
using namespace boost::python;

/*! \file pppm_force_test.cc
    \brief Implements unit tests for PPPMForceCompute and PPPMForceComputeGPU and descendants
    \ingroup unit_tests
*/

//! Name the unit test module
#define BOOST_TEST_MODULE PPPMTest
#include "boost_utf_configure.h"

//! Typedef'd PPPMForceCompute factory

typedef boost::function<shared_ptr<PPPMForceCompute> (shared_ptr<SystemDefinition> sysdef,
                                                      shared_ptr<NeighborList> nlist,
                                                      shared_ptr<ParticleGroup> group)> pppmforce_creator;

//! Test the ability of the lj force compute to actually calucate forces
void pppm_force_particle_test(pppmforce_creator pppm_creator, boost::shared_ptr<ExecutionConfiguration> exec_conf)
    {
    // this is a 2-particle of charge 1 and -1
    // due to the complexity of FFTs, the correct resutls are not analytically computed
    // but instead taken from a known working implementation of the PPPM method
    // The box lengths and grid points are different in each direction

    shared_ptr<SystemDefinition> sysdef_2(new SystemDefinition(2, BoxDim(6.0, 10.0, 14.0), 1, 0, 0, 0, 0, exec_conf));
    shared_ptr<ParticleData> pdata_2 = sysdef_2->getParticleData();
    pdata_2->setFlags(~PDataFlags(0));

    shared_ptr<NeighborList> nlist_2(new NeighborList(sysdef_2, Scalar(1.0), Scalar(1.0)));
    shared_ptr<ParticleSelector> selector_all(new ParticleSelectorTag(sysdef_2, 0, 1));
    shared_ptr<ParticleGroup> group_all(new ParticleGroup(sysdef_2, selector_all));

    {
    ArrayHandle<Scalar4> h_pos(pdata_2->getPositions(), access_location::host, access_mode::readwrite);
    ArrayHandle<Scalar> h_charge(pdata_2->getCharges(), access_location::host, access_mode::readwrite);

    h_pos.data[0].x = h_pos.data[0].y = h_pos.data[0].z = 1.0;
    h_charge.data[0] = 1.0;
    h_pos.data[1].x = h_pos.data[1].y = h_pos.data[1].z = 2.0;
    h_charge.data[1] = -1.0;

    }

    shared_ptr<PPPMForceCompute> fc_2 = pppm_creator(sysdef_2, nlist_2, group_all);

    // first test: setup a sigma of 1.0 so that all forces will be 0
    int Nx = 10;
    int Ny = 15;
    int Nz = 24;
    int order = 5;
    Scalar kappa = 1.0;
    Scalar rcut = 1.0;
    Scalar volume = 6.0*10.0*14.0;
    fc_2->setParams(Nx, Ny, Nz, order, kappa, rcut);

    // compute the forces
    fc_2->compute(0);

    ArrayHandle<Scalar4> h_force(fc_2->getForceArray(), access_location::host, access_mode::read);
    ArrayHandle<Scalar> h_virial(fc_2->getVirialArray(), access_location::host, access_mode::read);
    unsigned int pitch = fc_2->getVirialArray().getPitch();

    MY_BOOST_CHECK_CLOSE(h_force.data[0].x, 0.151335f, tol_small);
    MY_BOOST_CHECK_CLOSE(h_force.data[0].y, 0.172246f, tol_small);
    MY_BOOST_CHECK_CLOSE(h_force.data[0].z, 0.179186f, tol_small);
    MY_BOOST_CHECK_CLOSE(h_force.data[0].w, -0.576491f, tol_small);
    MY_BOOST_CHECK_CLOSE(h_virial.data[0*pitch]/volume, -0.000180413f, tol_small);
    MY_BOOST_CHECK_CLOSE(h_virial.data[1*pitch]/volume, -0.000180153f, tol_small);
    MY_BOOST_CHECK_CLOSE(h_virial.data[2*pitch]/volume, -0.000180394f, tol_small);
    MY_BOOST_CHECK_CLOSE(h_virial.data[3*pitch]/volume, -0.000211184f, tol_small);
    MY_BOOST_CHECK_CLOSE(h_virial.data[4*pitch]/volume, -0.000204873f, tol_small);
    MY_BOOST_CHECK_CLOSE(h_virial.data[5*pitch]/volume, -0.000219209f, tol_small);

    MY_BOOST_CHECK_CLOSE(h_force.data[1].x, -0.151335f, tol_small);
    MY_BOOST_CHECK_CLOSE(h_force.data[1].y, -0.172246f, tol_small);
    MY_BOOST_CHECK_CLOSE(h_force.data[1].z, -0.179186f, tol_small);
    MY_BOOST_CHECK_SMALL(h_force.data[1].w, tol_small);
    MY_BOOST_CHECK_SMALL(h_virial.data[0*pitch+1]
                        +h_virial.data[3*pitch+1]
                        +h_virial.data[5*pitch+1], tol_small);

    }

//! PPPMForceCompute creator for unit tests
shared_ptr<PPPMForceCompute> base_class_pppm_creator(shared_ptr<SystemDefinition> sysdef,
                                                     shared_ptr<NeighborList> nlist,
                                                     shared_ptr<ParticleGroup> group)
    {
    return shared_ptr<PPPMForceCompute>(new PPPMForceCompute(sysdef, nlist, group));
    }

#ifdef ENABLE_CUDA
//! PPPMForceComputeGPU creator for unit tests
shared_ptr<PPPMForceCompute> gpu_pppm_creator(shared_ptr<SystemDefinition> sysdef,
                                              shared_ptr<NeighborList> nlist,
                                              shared_ptr<ParticleGroup> group)
    {
    nlist->setStorageMode(NeighborList::full);
    return shared_ptr<PPPMForceComputeGPU> (new PPPMForceComputeGPU(sysdef, nlist, group));
    }
#endif

//! boost test case for particle test on CPU
BOOST_AUTO_TEST_CASE( PPPMForceCompute_basic )
    {
    pppmforce_creator pppm_creator = bind(base_class_pppm_creator, _1, _2, _3);
    pppm_force_particle_test(pppm_creator, boost::shared_ptr<ExecutionConfiguration>(new ExecutionConfiguration(ExecutionConfiguration::CPU)));
    }

#ifdef ENABLE_CUDA
//! boost test case for bond forces on the GPU
BOOST_AUTO_TEST_CASE( PPPMForceComputeGPU_basic )
    {
    pppmforce_creator pppm_creator = bind(gpu_pppm_creator, _1, _2, _3);
    pppm_force_particle_test(pppm_creator, boost::shared_ptr<ExecutionConfiguration>(new ExecutionConfiguration(ExecutionConfiguration::GPU)));
    }
#endif

#ifdef WIN32
#pragma warning( pop )
#endif

<commit_msg>Added unit test for charge.pppm with triclinic<commit_after>/*
Highly Optimized Object-oriented Many-particle Dynamics -- Blue Edition
(HOOMD-blue) Open Source Software License Copyright 2008-2011 Ames Laboratory
Iowa State University and The Regents of the University of Michigan All rights
reserved.

HOOMD-blue may contain modifications ("Contributions") provided, and to which
copyright is held, by various Contributors who have granted The Regents of the
University of Michigan the right to modify and/or distribute such Contributions.

You may redistribute, use, and create derivate works of HOOMD-blue, in source
and binary forms, provided you abide by the following conditions:

* Redistributions of source code must retain the above copyright notice, this
list of conditions, and the following disclaimer both in the code and
prominently in any materials provided with the distribution.

* Redistributions in binary form must reproduce the above copyright notice, this
list of conditions, and the following disclaimer in the documentation and/or
other materials provided with the distribution.

* All publications and presentations based on HOOMD-blue, including any reports
or published results obtained, in whole or in part, with HOOMD-blue, will
acknowledge its use according to the terms posted at the time of submission on:
http://codeblue.umich.edu/hoomd-blue/citations.html

* Any electronic documents citing HOOMD-Blue will link to the HOOMD-Blue website:
http://codeblue.umich.edu/hoomd-blue/

* Apart from the above required attributions, neither the name of the copyright
holder nor the names of HOOMD-blue's contributors may be used to endorse or
promote products derived from this software without specific prior written
permission.

Disclaimer

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND/OR ANY
WARRANTIES THAT THIS SOFTWARE IS FREE OF INFRINGEMENT ARE DISCLAIMED.

IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifdef WIN32
#pragma warning( push )
#pragma warning( disable : 4103 4244 )
#endif

#include <boost/python.hpp>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/shared_ptr.hpp>

#include <iostream>
#include <fstream>

#include "PPPMForceCompute.h"
#ifdef ENABLE_CUDA
#include "PPPMForceComputeGPU.h"
#endif

#include "NeighborListBinned.h"
#include "Initializers.h"

#include <math.h>

using namespace std;
using namespace boost;
using namespace boost::python;

/*! \file pppm_force_test.cc
    \brief Implements unit tests for PPPMForceCompute and PPPMForceComputeGPU and descendants
    \ingroup unit_tests
*/

//! Name the unit test module
#define BOOST_TEST_MODULE PPPMTest
#include "boost_utf_configure.h"

//! Typedef'd PPPMForceCompute factory

typedef boost::function<shared_ptr<PPPMForceCompute> (shared_ptr<SystemDefinition> sysdef,
                                                      shared_ptr<NeighborList> nlist,
                                                      shared_ptr<ParticleGroup> group)> pppmforce_creator;

//! Test the ability of the lj force compute to actually calucate forces
void pppm_force_particle_test(pppmforce_creator pppm_creator, boost::shared_ptr<ExecutionConfiguration> exec_conf)
    {
    // this is a 2-particle of charge 1 and -1
    // due to the complexity of FFTs, the correct resutls are not analytically computed
    // but instead taken from a known working implementation of the PPPM method
    // The box lengths and grid points are different in each direction

    shared_ptr<SystemDefinition> sysdef_2(new SystemDefinition(2, BoxDim(6.0, 10.0, 14.0), 1, 0, 0, 0, 0, exec_conf));
    shared_ptr<ParticleData> pdata_2 = sysdef_2->getParticleData();
    pdata_2->setFlags(~PDataFlags(0));

    shared_ptr<NeighborList> nlist_2(new NeighborList(sysdef_2, Scalar(1.0), Scalar(1.0)));
    shared_ptr<ParticleSelector> selector_all(new ParticleSelectorTag(sysdef_2, 0, 1));
    shared_ptr<ParticleGroup> group_all(new ParticleGroup(sysdef_2, selector_all));

    {
    ArrayHandle<Scalar4> h_pos(pdata_2->getPositions(), access_location::host, access_mode::readwrite);
    ArrayHandle<Scalar> h_charge(pdata_2->getCharges(), access_location::host, access_mode::readwrite);

    h_pos.data[0].x = h_pos.data[0].y = h_pos.data[0].z = 1.0;
    h_charge.data[0] = 1.0;
    h_pos.data[1].x = h_pos.data[1].y = h_pos.data[1].z = 2.0;
    h_charge.data[1] = -1.0;

    }

    shared_ptr<PPPMForceCompute> fc_2 = pppm_creator(sysdef_2, nlist_2, group_all);

    // first test: setup a sigma of 1.0 so that all forces will be 0
    int Nx = 10;
    int Ny = 15;
    int Nz = 24;
    int order = 5;
    Scalar kappa = 1.0;
    Scalar rcut = 1.0;
    Scalar volume = 6.0*10.0*14.0;
    fc_2->setParams(Nx, Ny, Nz, order, kappa, rcut);

    // compute the forces
    fc_2->compute(0);

    ArrayHandle<Scalar4> h_force(fc_2->getForceArray(), access_location::host, access_mode::read);
    ArrayHandle<Scalar> h_virial(fc_2->getVirialArray(), access_location::host, access_mode::read);
    unsigned int pitch = fc_2->getVirialArray().getPitch();

    MY_BOOST_CHECK_CLOSE(h_force.data[0].x, 0.151335f, tol_small);
    MY_BOOST_CHECK_CLOSE(h_force.data[0].y, 0.172246f, tol_small);
    MY_BOOST_CHECK_CLOSE(h_force.data[0].z, 0.179186f, tol_small);
    MY_BOOST_CHECK_CLOSE(h_force.data[0].w, -0.576491f, tol_small);
    MY_BOOST_CHECK_CLOSE(h_virial.data[0*pitch]/volume, -0.000180413f, tol_small);
    MY_BOOST_CHECK_CLOSE(h_virial.data[1*pitch]/volume, -0.000180153f, tol_small);
    MY_BOOST_CHECK_CLOSE(h_virial.data[2*pitch]/volume, -0.000180394f, tol_small);
    MY_BOOST_CHECK_CLOSE(h_virial.data[3*pitch]/volume, -0.000211184f, tol_small);
    MY_BOOST_CHECK_CLOSE(h_virial.data[4*pitch]/volume, -0.000204873f, tol_small);
    MY_BOOST_CHECK_CLOSE(h_virial.data[5*pitch]/volume, -0.000219209f, tol_small);

    MY_BOOST_CHECK_CLOSE(h_force.data[1].x, -0.151335f, tol_small);
    MY_BOOST_CHECK_CLOSE(h_force.data[1].y, -0.172246f, tol_small);
    MY_BOOST_CHECK_CLOSE(h_force.data[1].z, -0.179186f, tol_small);
    MY_BOOST_CHECK_SMALL(h_force.data[1].w, tol_small);
    MY_BOOST_CHECK_SMALL(h_virial.data[0*pitch+1]
                        +h_virial.data[3*pitch+1]
                        +h_virial.data[5*pitch+1], tol_small);

    }

//! Test the ability of the lj force compute to actually calucate forces
void pppm_force_particle_test_triclinic(pppmforce_creator pppm_creator, boost::shared_ptr<ExecutionConfiguration> exec_conf)
    {
    // this is a 2-particle of charge 1 and -1
    // due to the complexity of FFTs, the correct resutls are not analytically computed
    // but instead taken from a known working implementation of the PPPM method (LAMMPS ewald/disp
    // with lj/long/coul/long at RMS error = 6.14724e-06)
    // The box lengths and grid points are different in each direction

    // set up triclinic box
    Scalar tilt(0.5);
    shared_ptr<SystemDefinition> sysdef_2(new SystemDefinition(2, BoxDim(10.0,tilt,tilt,tilt), 1, 0, 0, 0, 0, exec_conf));
    shared_ptr<ParticleData> pdata_2 = sysdef_2->getParticleData();
    pdata_2->setFlags(~PDataFlags(0));

    shared_ptr<NeighborList> nlist_2(new NeighborList(sysdef_2, Scalar(1.0), Scalar(1.0)));
    shared_ptr<ParticleSelector> selector_all(new ParticleSelectorTag(sysdef_2, 0, 1));
    shared_ptr<ParticleGroup> group_all(new ParticleGroup(sysdef_2, selector_all));

    {
    ArrayHandle<Scalar4> h_pos(pdata_2->getPositions(), access_location::host, access_mode::readwrite);
    ArrayHandle<Scalar> h_charge(pdata_2->getCharges(), access_location::host, access_mode::readwrite);

    h_pos.data[0].x = h_pos.data[0].y = h_pos.data[0].z = 0.0;
    h_charge.data[0] = 1.0;
    h_pos.data[1].x = 3.0; h_pos.data[1].y = 3.0; h_pos.data[1].z = 3.0;
    h_charge.data[1] = -1.0;

    }

    shared_ptr<PPPMForceCompute> fc_2 = pppm_creator(sysdef_2, nlist_2, group_all);

    int Nx = 128;
    int Ny = 128;
    int Nz = 128;
    int order = 3;
    Scalar kappa = 1.519768; // this value is calculated by charge.pppm
    Scalar rcut = 2.0;
    Scalar volume = 10.0*10.0*10.0;
    fc_2->setParams(Nx, Ny, Nz, order, kappa, rcut);

    // compute the forces
    fc_2->compute(0);

    ArrayHandle<Scalar4> h_force(fc_2->getForceArray(), access_location::host, access_mode::read);
    ArrayHandle<Scalar> h_virial(fc_2->getVirialArray(), access_location::host, access_mode::read);
    unsigned int pitch = fc_2->getVirialArray().getPitch();

    Scalar rough_tol = 0.02;
    Scalar rough_tol_2 = 1.0;
    MY_BOOST_CHECK_CLOSE(h_force.data[0].x, 0.00904953, rough_tol);
    MY_BOOST_CHECK_CLOSE(h_force.data[0].y, 0.0101797, rough_tol);
    MY_BOOST_CHECK_CLOSE(h_force.data[0].z, 0.0124804, rough_tol);
    MY_BOOST_CHECK_CLOSE(h_force.data[0].w, -0.2441, rough_tol);
    MY_BOOST_CHECK_CLOSE(h_virial.data[0*pitch]/volume, -5.7313404e-05, rough_tol_2);
    MY_BOOST_CHECK_CLOSE(h_virial.data[1*pitch]/volume, -4.5494677e-05, rough_tol_2);
    MY_BOOST_CHECK_CLOSE(h_virial.data[2*pitch]/volume, -3.9889249e-05, rough_tol_2);
    MY_BOOST_CHECK_CLOSE(h_virial.data[3*pitch]/volume, -7.8745142e-05, rough_tol_2);
    MY_BOOST_CHECK_CLOSE(h_virial.data[4*pitch]/volume, -4.8501155e-05, rough_tol_2);
    MY_BOOST_CHECK_CLOSE(h_virial.data[5*pitch]/volume, -0.00010732774, rough_tol_2);

    MY_BOOST_CHECK_CLOSE(h_force.data[1].x, -0.00904953, rough_tol);
    MY_BOOST_CHECK_CLOSE(h_force.data[1].y, -0.0101797, rough_tol);
    MY_BOOST_CHECK_CLOSE(h_force.data[1].z, -0.0124804, rough_tol);
    MY_BOOST_CHECK_SMALL(h_force.data[1].w, rough_tol);
    MY_BOOST_CHECK_SMALL(h_virial.data[0*pitch+1], rough_tol);
    MY_BOOST_CHECK_SMALL(h_virial.data[1*pitch+1], rough_tol);
    MY_BOOST_CHECK_SMALL(h_virial.data[2*pitch+1], rough_tol);
    MY_BOOST_CHECK_SMALL(h_virial.data[3*pitch+1], rough_tol);
    MY_BOOST_CHECK_SMALL(h_virial.data[4*pitch+1], rough_tol);
    MY_BOOST_CHECK_SMALL(h_virial.data[5*pitch+1], rough_tol);
    }

//! PPPMForceCompute creator for unit tests
shared_ptr<PPPMForceCompute> base_class_pppm_creator(shared_ptr<SystemDefinition> sysdef,
                                                     shared_ptr<NeighborList> nlist,
                                                     shared_ptr<ParticleGroup> group)
    {
    return shared_ptr<PPPMForceCompute>(new PPPMForceCompute(sysdef, nlist, group));
    }

#ifdef ENABLE_CUDA
//! PPPMForceComputeGPU creator for unit tests
shared_ptr<PPPMForceCompute> gpu_pppm_creator(shared_ptr<SystemDefinition> sysdef,
                                              shared_ptr<NeighborList> nlist,
                                              shared_ptr<ParticleGroup> group)
    {
    nlist->setStorageMode(NeighborList::full);
    return shared_ptr<PPPMForceComputeGPU> (new PPPMForceComputeGPU(sysdef, nlist, group));
    }
#endif

//! boost test case for particle test on CPU
BOOST_AUTO_TEST_CASE( PPPMForceCompute_basic )
    {
    pppmforce_creator pppm_creator = bind(base_class_pppm_creator, _1, _2, _3);
    pppm_force_particle_test(pppm_creator, boost::shared_ptr<ExecutionConfiguration>(new ExecutionConfiguration(ExecutionConfiguration::CPU)));
    }

//! boost test case for particle test on CPU
BOOST_AUTO_TEST_CASE( PPPMForceCompute_triclinic )
    {
    pppmforce_creator pppm_creator = bind(base_class_pppm_creator, _1, _2, _3);
    pppm_force_particle_test_triclinic(pppm_creator, boost::shared_ptr<ExecutionConfiguration>(new ExecutionConfiguration(ExecutionConfiguration::CPU)));
    }

#
#ifdef ENABLE_CUDA
//! boost test case for bond forces on the GPU
BOOST_AUTO_TEST_CASE( PPPMForceComputeGPU_basic )
    {
    pppmforce_creator pppm_creator = bind(gpu_pppm_creator, _1, _2, _3);
    pppm_force_particle_test(pppm_creator, boost::shared_ptr<ExecutionConfiguration>(new ExecutionConfiguration(ExecutionConfiguration::GPU)));
    }

BOOST_AUTO_TEST_CASE( PPPMForceComputeGPU_triclinic )
    {
    pppmforce_creator pppm_creator = bind(gpu_pppm_creator, _1, _2, _3);
    pppm_force_particle_test_triclinic(pppm_creator, boost::shared_ptr<ExecutionConfiguration>(new ExecutionConfiguration(ExecutionConfiguration::GPU)));
    }

#endif

#ifdef WIN32
#pragma warning( pop )
#endif

<|endoftext|>


<commit_before>//################################################
// This code file
// defines Measure class used to track properties
// (e.g. peak, min, duration) of specified state variable.
//
// Copyright (C) 2015 Thomas J. Hund.
// Updated 07/2015
// Email thomas.hund@osumc.edu
//#################################################

#include "measure_kernel.h"

//#############################################################
// Measure class constructor and destructor
//#############################################################

MeasureKernel::MeasureKernel(string varname, double percrepol)
{
    peak=-100.0;
    min=100.0;
    vartakeoff=-100.0;
    repol = -25.0;
    amp = 70.0;
    maxderiv=0.0;
    maxderiv2nd=0.0;
    cl=0.0;
    told = -10000.0;
    mint = 0.0;
    maxt = 0.0;
    varold = 100.0;
    derivold = 0.0;
    minflag = false;
    maxflag = false;
    ampflag = false;
    ddrflag = false;
    derivt2 = 0.0;
    derivt1 = 0.0;
    derivt = 0.0;
    deriv2ndt = 0.0;
    durflag = false;
    this->percrepol = percrepol;
    returnflag = 0;

    this->varname = varname;
    this->mkmap();

    };

MeasureKernel::MeasureKernel(const MeasureKernel& toCopy) {
    this->copy(toCopy);
};

MeasureKernel::MeasureKernel( MeasureKernel&& toCopy) {
    this->copy(toCopy);
};

MeasureKernel& MeasureKernel::operator=(const MeasureKernel& toCopy) {
    this->copy(toCopy);
    return *this;
};

MeasureKernel::~MeasureKernel()
{
};

set<string> MeasureKernel::getVariables() {
    set<string> toReturn;
    map<string,double*>::iterator it;
    for(it = varmap.begin(); it != varmap.end(); it++) {
        toReturn.insert(it->first);
    }
    return toReturn;
}

map<string,double> MeasureKernel::getVariablesMap() {
    map<string,double> toReturn;
    for(map<string,double*>::iterator it = varmap.begin(); it != varmap.end(); it++) {
        toReturn.insert(std::pair<string,double>(it->first, *it->second));
    }
    return toReturn;
}

void MeasureKernel::copy(const MeasureKernel& toCopy) {
    std::map<string, double*>::iterator it;

    peak= toCopy.peak;
    min= toCopy.min;
    vartakeoff= toCopy.vartakeoff;
    repol = toCopy.repol;
    amp = toCopy.amp;
    maxderiv= toCopy.maxderiv;
    maxderiv2nd= toCopy.maxderiv2nd;
    cl= toCopy.cl;
    told = toCopy.told;
    mint = toCopy.mint;
    maxt = toCopy.maxt;
    varold = toCopy.varold;
    derivold = toCopy.derivold;
    minflag = toCopy.minflag;
    maxflag = toCopy.maxflag;
    ampflag = toCopy.ampflag;
    ddrflag = toCopy.ddrflag;
    derivt2 = toCopy.derivt2;
    derivt1 = toCopy.derivt1;
    derivt = toCopy.derivt;
    deriv2ndt = toCopy.deriv2ndt;
    durflag = toCopy.durflag;
    percrepol = toCopy.percrepol;
    returnflag = toCopy.returnflag;
    dur = toCopy.dur;
    varname = toCopy.varname;
    this->mkmap();
};

//################################################################
// Function to track properties (e.g. peak, min, duration) of
// specified state variable and return status flag to calling fxn.
//################################################################
bool MeasureKernel::measure(double time, double var)
{
    double deriv,deriv2nd;

    returnflag = false;  //default for return...set to 1 when props ready for output

    deriv=(var-varold)/(time-told);
    deriv2nd=(deriv-derivold)/(time-told);

    if(deriv>maxderiv){             // Track value and time of max 1st deriv
        maxderiv=deriv;
        derivt=time;
    }

    if(deriv2nd>.02&&var>(0.01*abs(min)+min)&&!ddrflag){   // Track 2nd deriv for SAN ddr
        vartakeoff=var;
        deriv2ndt=time;
        ddr=(vartakeoff-min)/(time-mint);
        ddrflag=true;
    }

    if(minflag&&var>peak){          // Track value and time of peak
        peak=var;
        maxt=time;
    }
    else if((peak-min)>0.3*abs(min))    // Assumes true max is more than 30% greater than the min.
        maxflag=true;

    if(var<min){                        // Track value and time of min
        min=var;
        mint=time;
    }
    else
        minflag=true;

    if(var>repol&&!durflag){          // t1 for dur calculation = first time var crosses repol.
        durtime1=time;            // will depend on percrepol - default is 50 but can be changed.
        durflag=true;
    }

    if(maxflag&&minflag&&!ampflag){
        amp=peak-min;
        ampflag = true;
        cl=derivt-derivt1;
        derivt2=derivt1;
        derivt1=derivt;
        repol = (1-percrepol*0.01)*amp+min;
    }

    if(durflag&&var<repol){
        dur=time-durtime1;
        durflag=false;
        returnflag = true;  // lets calling fxn know that it is time to output and reset.
    }

    told=time;
    varold=var;
    derivold=deriv;

    return (returnflag);
};

void MeasureKernel::reset()
{
	for(auto var: this->varmap) {
		this->lastMap[var.first] = *var.second;
	}
    peak=-100.0;
    min=100.0;
    maxderiv=0.0;
    maxderiv2nd=0.0;
    told = 0.0;
    minflag = 0;
    maxflag = 0;
    ampflag = 0;
    ddrflag = 0;
};
void MeasureKernel::setPercrepol(double val) {
    this->percrepol = val;
}

double MeasureKernel::getPercrepol() const {
    return this->percrepol;
}

void MeasureKernel::restoreLast() {
	for(auto var: lastMap) {
		*this->varmap[var.first] = var.second;
	}
}

void MeasureKernel::mkmap() {

    varmap["cl"]=&cl;
    varmap["peak"]=&peak;
    varmap["min"]=&min;
    varmap["amp"]=&
    varmap["ddr"]=&ddr;
    varmap["maxderiv"]=&maxderiv;
    varmap["dur"]=&dur;
    varmap["durtime1"]=&durtime1;
    varmap["vartakeoff"]=&vartakeoff;
    varmap["mint"]=&mint;
    varmap["derivt"]=&derivt;
    varmap["deriv2ndt"]=&deriv2ndt;
}
<commit_msg>peak is now the abs of value<commit_after>//################################################
// This code file
// defines Measure class used to track properties
// (e.g. peak, min, duration) of specified state variable.
//
// Copyright (C) 2015 Thomas J. Hund.
// Updated 07/2015
// Email thomas.hund@osumc.edu
//#################################################

#include "measure_kernel.h"

//#############################################################
// Measure class constructor and destructor
//#############################################################

MeasureKernel::MeasureKernel(string varname, double percrepol)
{
    peak=-100.0;
    min=100.0;
    vartakeoff=-100.0;
    repol = -25.0;
    amp = 70.0;
    maxderiv=0.0;
    maxderiv2nd=0.0;
    cl=0.0;
    told = -10000.0;
    mint = 0.0;
    maxt = 0.0;
    varold = 100.0;
    derivold = 0.0;
    minflag = false;
    maxflag = false;
    ampflag = false;
    ddrflag = false;
    derivt2 = 0.0;
    derivt1 = 0.0;
    derivt = 0.0;
    deriv2ndt = 0.0;
    durflag = false;
    this->percrepol = percrepol;
    returnflag = 0;

    this->varname = varname;
    this->mkmap();

    };

MeasureKernel::MeasureKernel(const MeasureKernel& toCopy) {
    this->copy(toCopy);
};

MeasureKernel::MeasureKernel( MeasureKernel&& toCopy) {
    this->copy(toCopy);
};

MeasureKernel& MeasureKernel::operator=(const MeasureKernel& toCopy) {
    this->copy(toCopy);
    return *this;
};

MeasureKernel::~MeasureKernel()
{
};

set<string> MeasureKernel::getVariables() {
    set<string> toReturn;
    map<string,double*>::iterator it;
    for(it = varmap.begin(); it != varmap.end(); it++) {
        toReturn.insert(it->first);
    }
    return toReturn;
}

map<string,double> MeasureKernel::getVariablesMap() {
    map<string,double> toReturn;
    for(map<string,double*>::iterator it = varmap.begin(); it != varmap.end(); it++) {
        toReturn.insert(std::pair<string,double>(it->first, *it->second));
    }
    return toReturn;
}

void MeasureKernel::copy(const MeasureKernel& toCopy) {
    std::map<string, double*>::iterator it;

    peak= toCopy.peak;
    min= toCopy.min;
    vartakeoff= toCopy.vartakeoff;
    repol = toCopy.repol;
    amp = toCopy.amp;
    maxderiv= toCopy.maxderiv;
    maxderiv2nd= toCopy.maxderiv2nd;
    cl= toCopy.cl;
    told = toCopy.told;
    mint = toCopy.mint;
    maxt = toCopy.maxt;
    varold = toCopy.varold;
    derivold = toCopy.derivold;
    minflag = toCopy.minflag;
    maxflag = toCopy.maxflag;
    ampflag = toCopy.ampflag;
    ddrflag = toCopy.ddrflag;
    derivt2 = toCopy.derivt2;
    derivt1 = toCopy.derivt1;
    derivt = toCopy.derivt;
    deriv2ndt = toCopy.deriv2ndt;
    durflag = toCopy.durflag;
    percrepol = toCopy.percrepol;
    returnflag = toCopy.returnflag;
    dur = toCopy.dur;
    varname = toCopy.varname;
    this->mkmap();
};

//################################################################
// Function to track properties (e.g. peak, min, duration) of
// specified state variable and return status flag to calling fxn.
//################################################################
bool MeasureKernel::measure(double time, double var)
{
    double deriv,deriv2nd;

    returnflag = false;  //default for return...set to 1 when props ready for output

    deriv=(var-varold)/(time-told);
    deriv2nd=(deriv-derivold)/(time-told);

    if(deriv>maxderiv){             // Track value and time of max 1st deriv
        maxderiv=deriv;
        derivt=time;
    }

    if(deriv2nd>.02&&var>(0.01*abs(min)+min)&&!ddrflag){   // Track 2nd deriv for SAN ddr
        vartakeoff=var;
        deriv2ndt=time;
        ddr=(vartakeoff-min)/(time-mint);
        ddrflag=true;
    }

    if(minflag&&abs(var)>peak){          // Track value and time of peak
        peak=var;
        maxt=time;
    }
    else if((peak-min)>0.3*abs(min))    // Assumes true max is more than 30% greater than the min.
        maxflag=true;

    if(var<min){                        // Track value and time of min
        min=var;
        mint=time;
    }
    else
        minflag=true;

    if(var>repol&&!durflag){          // t1 for dur calculation = first time var crosses repol.
        durtime1=time;            // will depend on percrepol - default is 50 but can be changed.
        durflag=true;
    }

    if(maxflag&&minflag&&!ampflag){
        amp=peak-min;
        ampflag = true;
        cl=derivt-derivt1;
        derivt2=derivt1;
        derivt1=derivt;
        repol = (1-percrepol*0.01)*amp+min;
    }

    if(durflag&&var<repol){
        dur=time-durtime1;
        durflag=false;
        returnflag = true;  // lets calling fxn know that it is time to output and reset.
    }

    told=time;
    varold=var;
    derivold=deriv;

    return (returnflag);
};

void MeasureKernel::reset()
{
	for(auto var: this->varmap) {
		this->lastMap[var.first] = *var.second;
	}
    peak=-100.0;
    min=100.0;
    maxderiv=0.0;
    maxderiv2nd=0.0;
    told = 0.0;
    minflag = 0;
    maxflag = 0;
    ampflag = 0;
    ddrflag = 0;
};
void MeasureKernel::setPercrepol(double val) {
    this->percrepol = val;
}

double MeasureKernel::getPercrepol() const {
    return this->percrepol;
}

void MeasureKernel::restoreLast() {
	for(auto var: lastMap) {
		*this->varmap[var.first] = var.second;
	}
}

void MeasureKernel::mkmap() {

    varmap["cl"]=&cl;
    varmap["peak"]=&peak;
    varmap["min"]=&min;
    varmap["amp"]=&
    varmap["ddr"]=&ddr;
    varmap["maxderiv"]=&maxderiv;
    varmap["dur"]=&dur;
    varmap["durtime1"]=&durtime1;
    varmap["vartakeoff"]=&vartakeoff;
    varmap["mint"]=&mint;
    varmap["derivt"]=&derivt;
    varmap["deriv2ndt"]=&deriv2ndt;
}
<|endoftext|>