<commit_before>
#include <string.h>

#include "boxed.h"
#include "closure.h"
#include "debug.h"
#include "function.h"
#include "gi.h"
#include "gobject.h"
#include "type.h"
#include "util.h"
#include "value.h"

using v8::Array;
using v8::External;
using v8::Function;
using v8::FunctionTemplate;
using v8::Local;
using v8::Number;
using v8::Object;
using v8::String;
using v8::Persistent;
using Nan::New;
using Nan::FunctionCallbackInfo;
using Nan::WeakCallbackType;

namespace GNodeJS {

// Our base template for all GObjects
static Nan::Persistent<FunctionTemplate> baseTemplate;

static void GObjectDestroyed(const v8::WeakCallbackInfo<GObject> &data);

static Local<FunctionTemplate> GetClassTemplateFromGI(GIBaseInfo *info);

static bool InitGParameterFromProperty(GParameter    *parameter,
                                       void          *klass,
                                       Local<String>  name,
                                       Local<Value>   value) {
    Nan::Utf8String name_utf8 (name);
    GParamSpec *pspec = g_object_class_find_property (G_OBJECT_CLASS (klass), *name_utf8);

    // Ignore additionnal keys in options, thus return true
    if (pspec == NULL)
        return true;

    GType value_type = G_PARAM_SPEC_VALUE_TYPE (pspec);
    parameter->name = pspec->name;
    g_value_init (&parameter->value, value_type);

    if (!CanConvertV8ToGValue(&parameter->value, value)) {
        char* message = g_strdup_printf("Cannot convert value for property \"%s\", expected type %s",
                *name_utf8, g_type_name(value_type));
        Nan::ThrowTypeError(message);
        free(message);
        return false;
    }

    if (!V8ToGValue (&parameter->value, value)) {
        char* message = g_strdup_printf("Couldn't convert value for property \"%s\", expected type %s",
                *name_utf8, g_type_name(value_type));
        Nan::ThrowTypeError(message);
        free(message);
        return false;
    }

    return true;
}

static bool InitGParametersFromProperty(GParameter    **parameters_p,
                                        int            *n_parameters_p,
                                        void           *klass,
                                        Local<Object>  property_hash) {
    Local<Array> properties = property_hash->GetOwnPropertyNames ();
    int n_parameters = properties->Length ();
    GParameter *parameters = g_new0 (GParameter, n_parameters);

    for (int i = 0; i < n_parameters; i++) {
        Local<String> name = properties->Get(i)->ToString();
        Local<Value> value = property_hash->Get (name);

        if (!InitGParameterFromProperty (&parameters[i], klass, name->ToString (), value))
            return false;
    }

    *parameters_p = parameters;
    *n_parameters_p = n_parameters;
    return true;
}

static void ToggleNotify(gpointer user_data, GObject *gobject, gboolean toggle_down) {
    void *data = g_object_get_qdata (gobject, GNodeJS::object_quark());

    g_assert (data != NULL);

    auto *persistent = (Persistent<Object> *) data;

    if (toggle_down) {
        /* We're dropping from 2 refs to 1 ref. We are the last holder. Make
         * sure that that our weak ref is installed. */
        persistent->SetWeak (gobject, GObjectDestroyed, v8::WeakCallbackType::kParameter);
    } else {
        /* We're going from 1 ref to 2 refs. We can't let our wrapper be
         * collected, so make sure that our reference is persistent */
        persistent->ClearWeak ();
    }
}

static void AssociateGObject(Isolate *isolate, Local<Object> object, GObject *gobject) {
    object->SetAlignedPointerInInternalField (0, gobject);

    g_object_ref_sink (gobject);
    g_object_add_toggle_ref (gobject, ToggleNotify, NULL);

    Persistent<Object> *persistent = new Persistent<Object>(isolate, object);
    g_object_set_qdata (gobject, GNodeJS::object_quark(), persistent);
}

static void GObjectConstructor(const FunctionCallbackInfo<Value> &info) {
    Isolate *isolate = info.GetIsolate ();

    /* The flow of this function is a bit twisty.

     * There's two cases for when this code is called:
     * user code doing `new Gtk.Widget({ ... })`, and
     * internal code as part of WrapperFromGObject, where
     * the constructor is called with one external. */

    if (!info.IsConstructCall ()) {
        Nan::ThrowTypeError("Not a construct call.");
        return;
    }

    Local<Object> self = info.This ();

    if (info[0]->IsExternal ()) {
        /* The External case. This is how WrapperFromGObject is called. */
        void *data = External::Cast (*info[0])->Value ();
        GObject *gobject = G_OBJECT (data);
        AssociateGObject (isolate, self, gobject);

        Nan::DefineOwnProperty(self,
                Nan::New<String>("__gtype__").ToLocalChecked(),
                Nan::New<Number>(G_OBJECT_TYPE(gobject)),
                (v8::PropertyAttribute)(v8::PropertyAttribute::ReadOnly | v8::PropertyAttribute::DontEnum)
        );
    } else {
        /* User code calling `new Gtk.Widget({ ... })` */

        GObject *gobject;
        GIBaseInfo *gi_info = (GIBaseInfo *) External::Cast (*info.Data ())->Value ();
        GType gtype = g_registered_type_info_get_g_type ((GIRegisteredTypeInfo *) gi_info);
        void *klass = g_type_class_ref (gtype);

        GParameter *parameters = NULL;
        int n_parameters = 0;

        if (info[0]->IsObject ()) {
            Local<Object> property_hash = info[0]->ToObject ();

            if (!InitGParametersFromProperty (&parameters, &n_parameters, klass, property_hash)) {
                // Error will already be thrown from InitGParametersFromProperty
                goto out;
            }
        }

        gobject = (GObject *) g_object_newv (gtype, n_parameters, parameters);
        AssociateGObject (isolate, self, gobject);

        Nan::DefineOwnProperty(self,
                UTF8("__gtype__"),
                Nan::New<Number>(g_registered_type_info_get_g_type(gi_info)),
                (v8::PropertyAttribute)(v8::PropertyAttribute::ReadOnly | v8::PropertyAttribute::DontEnum)
        );

    out:
        g_free (parameters);
        g_type_class_unref (klass);
    }
}

static void GObjectDestroyed(const v8::WeakCallbackInfo<GObject> &data) {
    GObject *gobject = data.GetParameter ();

    void *type_data = g_object_get_qdata (gobject, GNodeJS::object_quark());
    Persistent<Object> *persistent = (Persistent<Object> *) type_data;
    delete persistent;

    /* We're destroying the wrapper object, so make sure to clear out
     * the qdata that points back to us. */
    g_object_set_qdata (gobject, GNodeJS::object_quark(), NULL);

    g_object_unref (gobject);
}

static GISignalInfo* FindSignalInfo(GIObjectInfo *info, const char *signal_detail) {
    char* signal_name = Util::GetSignalName(signal_detail);

    GISignalInfo *signal_info = NULL;

    GIBaseInfo *parent = g_base_info_ref(info);

    while (parent) {
        // Find on GObject
        signal_info = g_object_info_find_signal (parent, signal_name);
        if (signal_info)
            break;

        // Find on Interfaces
        int n_interfaces = g_object_info_get_n_interfaces (info);
        for (int i = 0; i < n_interfaces; i++) {
            GIBaseInfo* interface_info = g_object_info_get_interface (info, i);
            signal_info = g_interface_info_find_signal (interface_info, signal_name);
            g_base_info_unref (interface_info);
            if (signal_info)
                goto out;
        }

        GIBaseInfo* next_parent = g_object_info_get_parent(parent);
        g_base_info_unref(parent);
        parent = next_parent;
    }

out:

    if (parent)
        g_base_info_unref(parent);

    g_free(signal_name);

    return signal_info;
}

static void ThrowSignalNotFound(GIBaseInfo *object_info, const char* signal_name) {
    char *message = g_strdup_printf("Signal \"%s\" not found for instance of %s",
            signal_name, GetInfoName(object_info));
    Nan::ThrowError(message);
    g_free(message);
}

static void SignalConnectInternal(const Nan::FunctionCallbackInfo<v8::Value> &info, bool after) {
    GObject *gobject = GObjectFromWrapper (info.This ());

    if (!gobject) {
        Nan::ThrowTypeError("Object is not a GObject");
        return;
    }

    if (!info[0]->IsString()) {
        Nan::ThrowTypeError("Signal ID invalid");
        return;
    }

    if (!info[1]->IsFunction()) {
        Nan::ThrowTypeError("Signal callback is not a function");
        return;
    }

    const char *signal_name = *Nan::Utf8String (info[0]->ToString());
    Local<Function> callback = info[1].As<Function>();
    GType gtype = (GType) Nan::Get(info.This(), UTF8("__gtype__")).ToLocalChecked()->NumberValue();

    GIBaseInfo *object_info = g_irepository_find_by_gtype (NULL, gtype);
    GISignalInfo *signal_info = FindSignalInfo (object_info, signal_name);

    if (signal_info == NULL) {
        ThrowSignalNotFound(object_info, signal_name);
    }
    else {
        GClosure *gclosure = MakeClosure (callback, signal_info);
        ulong handler_id = g_signal_connect_closure (gobject, signal_name, gclosure, after);

        info.GetReturnValue().Set((double)handler_id);
    }

    g_base_info_unref(object_info);
}

static void SignalDisconnectInternal(const Nan::FunctionCallbackInfo<v8::Value> &info) {
    GObject *gobject = GObjectFromWrapper (info.This ());

    if (!gobject) {
        Nan::ThrowTypeError("Object is not a GObject");
        return;
    }

    if (!info[0]->IsNumber()) {
        Nan::ThrowTypeError("Signal ID should be a number");
        return;
    }

    gpointer instance = static_cast<gpointer>(gobject);
    ulong handler_id = info[0]->NumberValue();
    g_signal_handler_disconnect (instance, handler_id);

    info.GetReturnValue().Set((double)handler_id);
}

NAN_METHOD(SignalConnect) {
    SignalConnectInternal(info, false);
}

NAN_METHOD(SignalDisconnect) {
    SignalDisconnectInternal(info);
}

NAN_METHOD(GObjectToString) {
    Local<Object> self = info.This();

    if (!ValueHasInternalField(self)) {
        Nan::ThrowTypeError("Object is not a GObject");
        return;
    }

    GObject* g_object = GObjectFromWrapper(self);
    GType type = G_OBJECT_TYPE (g_object);

    const char* typeName = g_type_name(type);
    char *className = *Nan::Utf8String(self->GetConstructorName());
    void *address = self->GetAlignedPointerFromInternalField(0);

    char *str = g_strdup_printf("[%s:%s %#zx]", typeName, className, (unsigned long)address);

    info.GetReturnValue().Set(UTF8(str));
    g_free(str);
}

Local<FunctionTemplate> GetBaseClassTemplate() {
    static bool isBaseClassCreated = false;

    if (!isBaseClassCreated) {
        isBaseClassCreated = true;

        Local<FunctionTemplate> tpl = Nan::New<FunctionTemplate>();
        Nan::SetPrototypeMethod(tpl, "connect", SignalConnect);
        Nan::SetPrototypeMethod(tpl, "disconnect", SignalDisconnect);
        Nan::SetPrototypeMethod(tpl, "toString", GObjectToString);
        baseTemplate.Reset(tpl);
    }

    // get FunctionTemplate from persistent object
    Local<FunctionTemplate> tpl = Nan::New(baseTemplate);
    return tpl;
}

static Local<FunctionTemplate> NewClassTemplate (GIBaseInfo *info) {
    const GType gtype = g_registered_type_info_get_g_type (info);

    g_assert(gtype != G_TYPE_NONE);

    const char *class_name = g_type_name (gtype);

    auto tpl = New<FunctionTemplate> (GObjectConstructor, New<External> (info));
    tpl->SetClassName (UTF8(class_name));
    tpl->InstanceTemplate()->SetInternalFieldCount(1);

    GIObjectInfo *parent_info = g_object_info_get_parent (info);
    if (parent_info) {
        auto parent_tpl = GetClassTemplateFromGI ((GIBaseInfo *) parent_info);
        tpl->Inherit(parent_tpl);
    } else {
        tpl->Inherit(GetBaseClassTemplate());
    }

    return tpl;
}

static Local<FunctionTemplate> GetClassTemplate(GType gtype) {
    void *data = g_type_get_qdata (gtype, GNodeJS::template_quark());

    if (data) {
        auto *persistent = (Persistent<FunctionTemplate> *) data;
        auto tpl = New<FunctionTemplate> (*persistent);
        return tpl;

    } else {
        GIBaseInfo *gi_info = g_irepository_find_by_gtype(NULL, gtype);

        auto tpl = NewClassTemplate(gi_info);
        auto *persistent = new Persistent<FunctionTemplate>(Isolate::GetCurrent(), tpl);
        persistent->SetWeak (
                g_base_info_ref (gi_info),
                GNodeJS::ClassDestroyed,
                WeakCallbackType::kParameter);

        g_type_set_qdata(gtype, GNodeJS::template_quark(), persistent);
        return tpl;
    }
}

static Local<FunctionTemplate> GetClassTemplateFromGI(GIBaseInfo *info) {
    GType gtype = g_registered_type_info_get_g_type ((GIRegisteredTypeInfo *) info);
    return GetClassTemplate(gtype);
}

Local<Function> MakeClass(GIBaseInfo *info) {
    auto tpl = GetClassTemplateFromGI (info);
    return tpl->GetFunction ();
}

Local<Value> WrapperFromGObject(GObject *gobject) {
    if (gobject == NULL)
        return Nan::Null();

    void *data = g_object_get_qdata (gobject, GNodeJS::object_quark());

    if (data) {
        /* Easy case: we already have an object. */
        auto *persistent = (Persistent<Object> *) data;
        auto obj = New<Object> (*persistent);
        return obj;

    } else {
        GType gtype = G_OBJECT_TYPE(gobject);
        g_type_ensure(gtype); //void *klass = g_type_class_ref (type);

        auto tpl = GetClassTemplate(gtype);
        Local<Function> constructor = tpl->GetFunction ();
        Local<Value> gobject_external = New<External> (gobject);
        Local<Value> args[] = { gobject_external };
        Local<Object> obj = Nan::NewInstance(constructor, 1, args).ToLocalChecked();

        return obj;
    }
}

GObject * GObjectFromWrapper(Local<Value> value) {
    if (!ValueHasInternalField(value))
        return nullptr;

    Local<Object> object = value->ToObject ();

    void    *ptr     = object->GetAlignedPointerFromInternalField (0);
    GObject *gobject = G_OBJECT (ptr);
    return gobject;
}

};
<commit_msg>gobject: reuse gtype<commit_after>
#include <string.h>

#include "boxed.h"
#include "closure.h"
#include "debug.h"
#include "function.h"
#include "gi.h"
#include "gobject.h"
#include "type.h"
#include "util.h"
#include "value.h"

using v8::Array;
using v8::External;
using v8::Function;
using v8::FunctionTemplate;
using v8::Local;
using v8::Number;
using v8::Object;
using v8::String;
using v8::Persistent;
using Nan::New;
using Nan::FunctionCallbackInfo;
using Nan::WeakCallbackType;

namespace GNodeJS {

// Our base template for all GObjects
static Nan::Persistent<FunctionTemplate> baseTemplate;

static void GObjectDestroyed(const v8::WeakCallbackInfo<GObject> &data);

static Local<FunctionTemplate> GetClassTemplateFromGI(GIBaseInfo *info);

static bool InitGParameterFromProperty(GParameter    *parameter,
                                       void          *klass,
                                       Local<String>  name,
                                       Local<Value>   value) {
    Nan::Utf8String name_utf8 (name);
    GParamSpec *pspec = g_object_class_find_property (G_OBJECT_CLASS (klass), *name_utf8);

    // Ignore additionnal keys in options, thus return true
    if (pspec == NULL)
        return true;

    GType value_type = G_PARAM_SPEC_VALUE_TYPE (pspec);
    parameter->name = pspec->name;
    g_value_init (&parameter->value, value_type);

    if (!CanConvertV8ToGValue(&parameter->value, value)) {
        char* message = g_strdup_printf("Cannot convert value for property \"%s\", expected type %s",
                *name_utf8, g_type_name(value_type));
        Nan::ThrowTypeError(message);
        free(message);
        return false;
    }

    if (!V8ToGValue (&parameter->value, value)) {
        char* message = g_strdup_printf("Couldn't convert value for property \"%s\", expected type %s",
                *name_utf8, g_type_name(value_type));
        Nan::ThrowTypeError(message);
        free(message);
        return false;
    }

    return true;
}

static bool InitGParametersFromProperty(GParameter    **parameters_p,
                                        int            *n_parameters_p,
                                        void           *klass,
                                        Local<Object>  property_hash) {
    Local<Array> properties = property_hash->GetOwnPropertyNames ();
    int n_parameters = properties->Length ();
    GParameter *parameters = g_new0 (GParameter, n_parameters);

    for (int i = 0; i < n_parameters; i++) {
        Local<String> name = properties->Get(i)->ToString();
        Local<Value> value = property_hash->Get (name);

        if (!InitGParameterFromProperty (&parameters[i], klass, name->ToString (), value))
            return false;
    }

    *parameters_p = parameters;
    *n_parameters_p = n_parameters;
    return true;
}

static void ToggleNotify(gpointer user_data, GObject *gobject, gboolean toggle_down) {
    void *data = g_object_get_qdata (gobject, GNodeJS::object_quark());

    g_assert (data != NULL);

    auto *persistent = (Persistent<Object> *) data;

    if (toggle_down) {
        /* We're dropping from 2 refs to 1 ref. We are the last holder. Make
         * sure that that our weak ref is installed. */
        persistent->SetWeak (gobject, GObjectDestroyed, v8::WeakCallbackType::kParameter);
    } else {
        /* We're going from 1 ref to 2 refs. We can't let our wrapper be
         * collected, so make sure that our reference is persistent */
        persistent->ClearWeak ();
    }
}

static void AssociateGObject(Isolate *isolate, Local<Object> object, GObject *gobject) {
    object->SetAlignedPointerInInternalField (0, gobject);

    g_object_ref_sink (gobject);
    g_object_add_toggle_ref (gobject, ToggleNotify, NULL);

    Persistent<Object> *persistent = new Persistent<Object>(isolate, object);
    g_object_set_qdata (gobject, GNodeJS::object_quark(), persistent);
}

static void GObjectConstructor(const FunctionCallbackInfo<Value> &info) {
    Isolate *isolate = info.GetIsolate ();

    /* The flow of this function is a bit twisty.

     * There's two cases for when this code is called:
     * user code doing `new Gtk.Widget({ ... })`, and
     * internal code as part of WrapperFromGObject, where
     * the constructor is called with one external. */

    if (!info.IsConstructCall ()) {
        Nan::ThrowTypeError("Not a construct call.");
        return;
    }

    Local<Object> self = info.This ();

    if (info[0]->IsExternal ()) {
        /* The External case. This is how WrapperFromGObject is called. */
        void *data = External::Cast (*info[0])->Value ();
        GObject *gobject = G_OBJECT (data);
        AssociateGObject (isolate, self, gobject);

        Nan::DefineOwnProperty(self,
                Nan::New<String>("__gtype__").ToLocalChecked(),
                Nan::New<Number>(G_OBJECT_TYPE(gobject)),
                (v8::PropertyAttribute)(v8::PropertyAttribute::ReadOnly | v8::PropertyAttribute::DontEnum)
        );
    } else {
        /* User code calling `new Gtk.Widget({ ... })` */

        GObject *gobject;
        GIBaseInfo *gi_info = (GIBaseInfo *) External::Cast (*info.Data ())->Value ();
        GType gtype = g_registered_type_info_get_g_type ((GIRegisteredTypeInfo *) gi_info);
        void *klass = g_type_class_ref (gtype);

        GParameter *parameters = NULL;
        int n_parameters = 0;

        if (info[0]->IsObject ()) {
            Local<Object> property_hash = info[0]->ToObject ();

            if (!InitGParametersFromProperty (&parameters, &n_parameters, klass, property_hash)) {
                // Error will already be thrown from InitGParametersFromProperty
                goto out;
            }
        }

        gobject = (GObject *) g_object_newv (gtype, n_parameters, parameters);
        AssociateGObject (isolate, self, gobject);

        Nan::DefineOwnProperty(self,
                UTF8("__gtype__"),
                Nan::New<Number>(gtype),
                (v8::PropertyAttribute)(v8::PropertyAttribute::ReadOnly | v8::PropertyAttribute::DontEnum)
        );

    out:
        g_free (parameters);
        g_type_class_unref (klass);
    }
}

static void GObjectDestroyed(const v8::WeakCallbackInfo<GObject> &data) {
    GObject *gobject = data.GetParameter ();

    void *type_data = g_object_get_qdata (gobject, GNodeJS::object_quark());
    Persistent<Object> *persistent = (Persistent<Object> *) type_data;
    delete persistent;

    /* We're destroying the wrapper object, so make sure to clear out
     * the qdata that points back to us. */
    g_object_set_qdata (gobject, GNodeJS::object_quark(), NULL);

    g_object_unref (gobject);
}

static GISignalInfo* FindSignalInfo(GIObjectInfo *info, const char *signal_detail) {
    char* signal_name = Util::GetSignalName(signal_detail);

    GISignalInfo *signal_info = NULL;

    GIBaseInfo *parent = g_base_info_ref(info);

    while (parent) {
        // Find on GObject
        signal_info = g_object_info_find_signal (parent, signal_name);
        if (signal_info)
            break;

        // Find on Interfaces
        int n_interfaces = g_object_info_get_n_interfaces (info);
        for (int i = 0; i < n_interfaces; i++) {
            GIBaseInfo* interface_info = g_object_info_get_interface (info, i);
            signal_info = g_interface_info_find_signal (interface_info, signal_name);
            g_base_info_unref (interface_info);
            if (signal_info)
                goto out;
        }

        GIBaseInfo* next_parent = g_object_info_get_parent(parent);
        g_base_info_unref(parent);
        parent = next_parent;
    }

out:

    if (parent)
        g_base_info_unref(parent);

    g_free(signal_name);

    return signal_info;
}

static void ThrowSignalNotFound(GIBaseInfo *object_info, const char* signal_name) {
    char *message = g_strdup_printf("Signal \"%s\" not found for instance of %s",
            signal_name, GetInfoName(object_info));
    Nan::ThrowError(message);
    g_free(message);
}

static void SignalConnectInternal(const Nan::FunctionCallbackInfo<v8::Value> &info, bool after) {
    GObject *gobject = GObjectFromWrapper (info.This ());

    if (!gobject) {
        Nan::ThrowTypeError("Object is not a GObject");
        return;
    }

    if (!info[0]->IsString()) {
        Nan::ThrowTypeError("Signal ID invalid");
        return;
    }

    if (!info[1]->IsFunction()) {
        Nan::ThrowTypeError("Signal callback is not a function");
        return;
    }

    const char *signal_name = *Nan::Utf8String (info[0]->ToString());
    Local<Function> callback = info[1].As<Function>();
    GType gtype = (GType) Nan::Get(info.This(), UTF8("__gtype__")).ToLocalChecked()->NumberValue();

    GIBaseInfo *object_info = g_irepository_find_by_gtype (NULL, gtype);
    GISignalInfo *signal_info = FindSignalInfo (object_info, signal_name);

    if (signal_info == NULL) {
        ThrowSignalNotFound(object_info, signal_name);
    }
    else {
        GClosure *gclosure = MakeClosure (callback, signal_info);
        ulong handler_id = g_signal_connect_closure (gobject, signal_name, gclosure, after);

        info.GetReturnValue().Set((double)handler_id);
    }

    g_base_info_unref(object_info);
}

static void SignalDisconnectInternal(const Nan::FunctionCallbackInfo<v8::Value> &info) {
    GObject *gobject = GObjectFromWrapper (info.This ());

    if (!gobject) {
        Nan::ThrowTypeError("Object is not a GObject");
        return;
    }

    if (!info[0]->IsNumber()) {
        Nan::ThrowTypeError("Signal ID should be a number");
        return;
    }

    gpointer instance = static_cast<gpointer>(gobject);
    ulong handler_id = info[0]->NumberValue();
    g_signal_handler_disconnect (instance, handler_id);

    info.GetReturnValue().Set((double)handler_id);
}

NAN_METHOD(SignalConnect) {
    SignalConnectInternal(info, false);
}

NAN_METHOD(SignalDisconnect) {
    SignalDisconnectInternal(info);
}

NAN_METHOD(GObjectToString) {
    Local<Object> self = info.This();

    if (!ValueHasInternalField(self)) {
        Nan::ThrowTypeError("Object is not a GObject");
        return;
    }

    GObject* g_object = GObjectFromWrapper(self);
    GType type = G_OBJECT_TYPE (g_object);

    const char* typeName = g_type_name(type);
    char *className = *Nan::Utf8String(self->GetConstructorName());
    void *address = self->GetAlignedPointerFromInternalField(0);

    char *str = g_strdup_printf("[%s:%s %#zx]", typeName, className, (unsigned long)address);

    info.GetReturnValue().Set(UTF8(str));
    g_free(str);
}

Local<FunctionTemplate> GetBaseClassTemplate() {
    static bool isBaseClassCreated = false;

    if (!isBaseClassCreated) {
        isBaseClassCreated = true;

        Local<FunctionTemplate> tpl = Nan::New<FunctionTemplate>();
        Nan::SetPrototypeMethod(tpl, "connect", SignalConnect);
        Nan::SetPrototypeMethod(tpl, "disconnect", SignalDisconnect);
        Nan::SetPrototypeMethod(tpl, "toString", GObjectToString);
        baseTemplate.Reset(tpl);
    }

    // get FunctionTemplate from persistent object
    Local<FunctionTemplate> tpl = Nan::New(baseTemplate);
    return tpl;
}

static Local<FunctionTemplate> NewClassTemplate (GIBaseInfo *info) {
    const GType gtype = g_registered_type_info_get_g_type (info);

    g_assert(gtype != G_TYPE_NONE);

    const char *class_name = g_type_name (gtype);

    auto tpl = New<FunctionTemplate> (GObjectConstructor, New<External> (info));
    tpl->SetClassName (UTF8(class_name));
    tpl->InstanceTemplate()->SetInternalFieldCount(1);

    GIObjectInfo *parent_info = g_object_info_get_parent (info);
    if (parent_info) {
        auto parent_tpl = GetClassTemplateFromGI ((GIBaseInfo *) parent_info);
        tpl->Inherit(parent_tpl);
    } else {
        tpl->Inherit(GetBaseClassTemplate());
    }

    return tpl;
}

static Local<FunctionTemplate> GetClassTemplate(GType gtype) {
    void *data = g_type_get_qdata (gtype, GNodeJS::template_quark());

    if (data) {
        auto *persistent = (Persistent<FunctionTemplate> *) data;
        auto tpl = New<FunctionTemplate> (*persistent);
        return tpl;

    } else {
        GIBaseInfo *gi_info = g_irepository_find_by_gtype(NULL, gtype);

        auto tpl = NewClassTemplate(gi_info);
        auto *persistent = new Persistent<FunctionTemplate>(Isolate::GetCurrent(), tpl);
        persistent->SetWeak (
                g_base_info_ref (gi_info),
                GNodeJS::ClassDestroyed,
                WeakCallbackType::kParameter);

        g_type_set_qdata(gtype, GNodeJS::template_quark(), persistent);
        return tpl;
    }
}

static Local<FunctionTemplate> GetClassTemplateFromGI(GIBaseInfo *info) {
    GType gtype = g_registered_type_info_get_g_type ((GIRegisteredTypeInfo *) info);
    return GetClassTemplate(gtype);
}

Local<Function> MakeClass(GIBaseInfo *info) {
    auto tpl = GetClassTemplateFromGI (info);
    return tpl->GetFunction ();
}

Local<Value> WrapperFromGObject(GObject *gobject) {
    if (gobject == NULL)
        return Nan::Null();

    void *data = g_object_get_qdata (gobject, GNodeJS::object_quark());

    if (data) {
        /* Easy case: we already have an object. */
        auto *persistent = (Persistent<Object> *) data;
        auto obj = New<Object> (*persistent);
        return obj;

    } else {
        GType gtype = G_OBJECT_TYPE(gobject);
        g_type_ensure(gtype); //void *klass = g_type_class_ref (type);

        auto tpl = GetClassTemplate(gtype);
        Local<Function> constructor = tpl->GetFunction ();
        Local<Value> gobject_external = New<External> (gobject);
        Local<Value> args[] = { gobject_external };
        Local<Object> obj = Nan::NewInstance(constructor, 1, args).ToLocalChecked();

        return obj;
    }
}

GObject * GObjectFromWrapper(Local<Value> value) {
    if (!ValueHasInternalField(value))
        return nullptr;

    Local<Object> object = value->ToObject ();

    void    *ptr     = object->GetAlignedPointerFromInternalField (0);
    GObject *gobject = G_OBJECT (ptr);
    return gobject;
}

};
<|endoftext|>


<commit_before>// Copyright (c) 2018 ASMlover. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//  * Redistributions of source code must retain the above copyright
//    notice, this list ofconditions and the following disclaimer.
//
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in
//    the documentation and/or other materialsprovided with the
//    distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE 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.
#include "Utility.h"
#include "Container/VectorWrap.h"
#include "Container/SetWrap.h"
#include "Container/MapWrap.h"
#include "Property/Common.h"
#include "Container/Container.h"

#if defined(TULIP_DEBUG_MODE)
void tulip_debug_wrap(void) {
  tulip::VectorWrap<int>::wrap("IVec");
  tulip::SetWrap<int>::wrap("ISet");
  tulip::MapWrap<int, std::string>::wrap("ISMap");
}
#else
# define tulip_debug_wrap() (void)0
#endif

BOOST_PYTHON_MODULE(Tulip) {
  tulip_debug_wrap();

  tulip::TulipDict::wrap();
}
<commit_msg>:construction: chore(tulip): updated the test for tulip<commit_after>// Copyright (c) 2018 ASMlover. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//  * Redistributions of source code must retain the above copyright
//    notice, this list ofconditions and the following disclaimer.
//
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in
//    the documentation and/or other materialsprovided with the
//    distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE 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.
#include "Utility.h"
#include "Container/VectorWrap.h"
#include "Container/SetWrap.h"
#include "Container/MapWrap.h"
// #include "Property/Common.h" // Not implementation
#include "Container/Container.h"
#include <iostream>

#if defined(TULIP_DEBUG_MODE)
static void tulip_run_callscript(const tulip::TulipDict& d) {
  PyObject* k{};
  PyObject* v{};
  py::ssize_t pos{};
  while (PyDict_Next(d.ptr(), &pos, &k, &v)) {
    py::call_method<void>(v, "show");
  }
}

void tulip_debug_wrap(void) {
  tulip::VectorWrap<int>::wrap("IVec");
  tulip::SetWrap<int>::wrap("ISet");
  tulip::MapWrap<int, std::string>::wrap("ISMap");

  py::def("tulip_run_callscript", tulip_run_callscript);
}
#else
# define tulip_debug_wrap() (void)0
#endif

BOOST_PYTHON_MODULE(Tulip) {
  PyEval_InitThreads();
  tulip_debug_wrap();

  tulip::TulipList::wrap();
  tulip::TulipDict::wrap();
}
<|endoftext|>


<commit_before>/****************************************************************/
/*               DO NOT MODIFY THIS HEADER                      */
/* MOOSE - Multiphysics Object Oriented Simulation Environment  */
/*                                                              */
/*           (c) 2010 Battelle Energy Alliance, LLC             */
/*                   ALL RIGHTS RESERVED                        */
/*                                                              */
/*          Prepared by Battelle Energy Alliance, LLC           */
/*            Under Contract No. DE-AC07-05ID14517              */
/*            With the U. S. Department of Energy               */
/*                                                              */
/*            See COPYRIGHT for full restrictions               */
/****************************************************************/

#include "GapValueAux.h"
#include "MooseSystem.h"

#include "mesh.h"

template<>
InputParameters validParams<GapValueAux>()
{
  InputParameters params = validParams<AuxKernel>();
  params.addRequiredParam<unsigned int>("paired_boundary", "The boundary on the other side of a gap.");
  params.addRequiredCoupledVar("paired_variable", "The variable to get the value of.");
  params.set<bool>("use_displaced_mesh") = true;
  return params;
}

GapValueAux::GapValueAux(const std::string & name, InputParameters parameters)
  :AuxKernel(name, parameters),
   _penetration_locator(getPenetrationLocator(parameters.get<unsigned int>("paired_boundary"), getParam<std::vector<unsigned int> >("boundary")[0])),
   _paired_variable(coupled("paired_variable"))
{
  _moose_system.needSerializedSolution(true);
}

Real
GapValueAux::computeValue()
{
  PenetrationLocator::PenetrationInfo * pinfo = _penetration_locator._penetration_info[_current_node->id()];

  Elem * slave_side = pinfo->_side;
  std::vector<std::vector<Real> > & slave_side_phi = pinfo->_side_phi;
  std::vector<unsigned int> slave_side_dof_indices;
  _moose_system._dof_map->dof_indices(slave_side, slave_side_dof_indices ,_paired_variable);

  Real gap_temp = 0.0;

  for(unsigned int i=0; i<slave_side_dof_indices.size(); i++)
    //The zero index is because we only have point that the phis are evaluated at
    gap_temp += slave_side_phi[i][0] * _moose_system._serialized_solution(slave_side_dof_indices[i]);

  std::cout<<gap_temp<<std::endl;

  return gap_temp;
}
<commit_msg>change the way gap heat transfer is done such that the roughnesses are only considered when the gap gets below them... this provides a cutoff point while still _freezing_ the gap after it gets to a certain point<commit_after>/****************************************************************/
/*               DO NOT MODIFY THIS HEADER                      */
/* MOOSE - Multiphysics Object Oriented Simulation Environment  */
/*                                                              */
/*           (c) 2010 Battelle Energy Alliance, LLC             */
/*                   ALL RIGHTS RESERVED                        */
/*                                                              */
/*          Prepared by Battelle Energy Alliance, LLC           */
/*            Under Contract No. DE-AC07-05ID14517              */
/*            With the U. S. Department of Energy               */
/*                                                              */
/*            See COPYRIGHT for full restrictions               */
/****************************************************************/

#include "GapValueAux.h"
#include "MooseSystem.h"

#include "mesh.h"

template<>
InputParameters validParams<GapValueAux>()
{
  InputParameters params = validParams<AuxKernel>();
  params.addRequiredParam<unsigned int>("paired_boundary", "The boundary on the other side of a gap.");
  params.addRequiredCoupledVar("paired_variable", "The variable to get the value of.");
  params.set<bool>("use_displaced_mesh") = true;
  return params;
}

GapValueAux::GapValueAux(const std::string & name, InputParameters parameters)
  :AuxKernel(name, parameters),
   _penetration_locator(getPenetrationLocator(parameters.get<unsigned int>("paired_boundary"), getParam<std::vector<unsigned int> >("boundary")[0])),
   _paired_variable(coupled("paired_variable"))
{
  _moose_system.needSerializedSolution(true);
}

Real
GapValueAux::computeValue()
{
  PenetrationLocator::PenetrationInfo * pinfo = _penetration_locator._penetration_info[_current_node->id()];

  Elem * slave_side = pinfo->_side;
  std::vector<std::vector<Real> > & slave_side_phi = pinfo->_side_phi;
  std::vector<unsigned int> slave_side_dof_indices;
  _moose_system._dof_map->dof_indices(slave_side, slave_side_dof_indices ,_paired_variable);

  Real gap_temp = 0.0;

  for(unsigned int i=0; i<slave_side_dof_indices.size(); i++)
    //The zero index is because we only have point that the phis are evaluated at
    gap_temp += slave_side_phi[i][0] * _moose_system._serialized_solution(slave_side_dof_indices[i]);

  return gap_temp;
}
<|endoftext|>


<commit_before>/*
 * The StockMap class is a hash table of any number of Stock objects,
 * each with a different URI.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "hstock.hxx"
#include "stock.hxx"
#include "hashmap.hxx"
#include "pool.hxx"

#include <daemon/log.h>

#include <assert.h>

struct StockMap {
    struct pool &pool;
    const StockClass &cls;
    void *class_ctx;

    /**
     * The maximum number of items in each stock.
     */
    unsigned limit;

    /**
     * The maximum number of permanent idle items in each stock.
     */
    unsigned max_idle;

    struct hashmap &stocks;

    StockMap(struct pool &_pool, const StockClass &_cls, void *_class_ctx,
             unsigned _limit, unsigned _max_idle)
        :pool(*pool_new_linear(&_pool, "hstock", 4096)),
         cls(_cls), class_ctx(_class_ctx),
         limit(_limit), max_idle(_max_idle),
         stocks(*hashmap_new(&pool, 64)) {}

    ~StockMap() {
        hashmap_rewind(&stocks);
        const struct hashmap_pair *pair;
        while ((pair = hashmap_next(&stocks)) != nullptr) {
            Stock *stock = (Stock *)pair->value;

            stock_free(stock);
        }

        pool_unref(&pool);
    }

    void Destroy() {
        DeleteFromPool(pool, this);
    }
};

/*
 * stock handler
 *
 */

static void
hstock_stock_empty(Stock &stock, const char *uri, void *ctx)
{
    StockMap *hstock = (StockMap *)ctx;

    daemon_log(5, "hstock(%p) remove empty stock(%p, '%s')\n",
               (const void *)hstock, (const void *)&stock, uri);
    hashmap_remove_existing(&hstock->stocks, uri, &stock);

    stock_free(&stock);
}

static constexpr StockHandler hstock_stock_handler = {
    .empty = hstock_stock_empty,
};

StockMap *
hstock_new(struct pool &pool, const StockClass &cls, void *class_ctx,
           unsigned limit, unsigned max_idle)
{
    assert(cls.item_size > sizeof(StockItem));
    assert(cls.create != nullptr);
    assert(cls.borrow != nullptr);
    assert(cls.release != nullptr);
    assert(cls.destroy != nullptr);
    assert(max_idle > 0);

    return NewFromPool<StockMap>(pool, pool, cls, class_ctx,
                                 limit, max_idle);
}

void
hstock_free(StockMap *hstock)
{
    hstock->Destroy();
}

void
hstock_fade_all(StockMap &hstock)
{
    hashmap_rewind(&hstock.stocks);

    const struct hashmap_pair *pair;
    while ((pair = hashmap_next(&hstock.stocks)) != nullptr) {
        Stock &stock = *(Stock *)pair->value;
        stock_fade_all(stock);
    }
}

void
hstock_add_stats(const StockMap &stock, StockStats &data)
{
    struct hashmap *h = &stock.stocks;
    hashmap_rewind(h);

    const struct hashmap_pair *p;
    while ((p = hashmap_next(h)) != nullptr) {
        const Stock &s = *(const Stock *)p->value;
        stock_add_stats(s, data);
    }
}

static Stock &
hstock_get_stock(StockMap &hstock, const char *uri)
{
    Stock *stock = (Stock *)hashmap_get(&hstock.stocks, uri);
    if (stock == nullptr) {
        stock = stock_new(hstock.pool, hstock.cls, hstock.class_ctx,
                          uri, hstock.limit, hstock.max_idle,
                          hstock_stock_handler, &hstock);
        hashmap_set(&hstock.stocks, stock_get_uri(*stock), stock);
    }

    return *stock;
}

void
hstock_get(StockMap &hstock, struct pool &pool,
           const char *uri, void *info,
           const StockGetHandler &handler, void *handler_ctx,
           struct async_operation_ref &async_ref)
{
    auto &stock = hstock_get_stock(hstock, uri);
    stock_get(stock, pool, info, handler, handler_ctx, async_ref);
}

StockItem *
hstock_get_now(StockMap &hstock, struct pool &pool,
               const char *uri, void *info,
               GError **error_r)
{
    Stock &stock = hstock_get_stock(hstock, uri);
    return stock_get_now(stock, pool, info, error_r);
}

void
hstock_put(gcc_unused StockMap &hstock, gcc_unused const char *uri,
           StockItem &object, bool destroy)
{
#ifndef NDEBUG
    Stock *stock = (Stock *)hashmap_get(&hstock.stocks, uri);

    assert(stock != nullptr);
    assert(stock == object.stock);
#endif

    stock_put(object, destroy);
}
<commit_msg>hstock: make attributes "const"<commit_after>/*
 * The StockMap class is a hash table of any number of Stock objects,
 * each with a different URI.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "hstock.hxx"
#include "stock.hxx"
#include "hashmap.hxx"
#include "pool.hxx"

#include <daemon/log.h>

#include <assert.h>

struct StockMap {
    struct pool &pool;
    const StockClass &cls;
    void *const class_ctx;

    /**
     * The maximum number of items in each stock.
     */
    const unsigned limit;

    /**
     * The maximum number of permanent idle items in each stock.
     */
    const unsigned max_idle;

    struct hashmap &stocks;

    StockMap(struct pool &_pool, const StockClass &_cls, void *_class_ctx,
             unsigned _limit, unsigned _max_idle)
        :pool(*pool_new_linear(&_pool, "hstock", 4096)),
         cls(_cls), class_ctx(_class_ctx),
         limit(_limit), max_idle(_max_idle),
         stocks(*hashmap_new(&pool, 64)) {}

    ~StockMap() {
        hashmap_rewind(&stocks);
        const struct hashmap_pair *pair;
        while ((pair = hashmap_next(&stocks)) != nullptr) {
            Stock *stock = (Stock *)pair->value;

            stock_free(stock);
        }

        pool_unref(&pool);
    }

    void Destroy() {
        DeleteFromPool(pool, this);
    }
};

/*
 * stock handler
 *
 */

static void
hstock_stock_empty(Stock &stock, const char *uri, void *ctx)
{
    StockMap *hstock = (StockMap *)ctx;

    daemon_log(5, "hstock(%p) remove empty stock(%p, '%s')\n",
               (const void *)hstock, (const void *)&stock, uri);
    hashmap_remove_existing(&hstock->stocks, uri, &stock);

    stock_free(&stock);
}

static constexpr StockHandler hstock_stock_handler = {
    .empty = hstock_stock_empty,
};

StockMap *
hstock_new(struct pool &pool, const StockClass &cls, void *class_ctx,
           unsigned limit, unsigned max_idle)
{
    assert(cls.item_size > sizeof(StockItem));
    assert(cls.create != nullptr);
    assert(cls.borrow != nullptr);
    assert(cls.release != nullptr);
    assert(cls.destroy != nullptr);
    assert(max_idle > 0);

    return NewFromPool<StockMap>(pool, pool, cls, class_ctx,
                                 limit, max_idle);
}

void
hstock_free(StockMap *hstock)
{
    hstock->Destroy();
}

void
hstock_fade_all(StockMap &hstock)
{
    hashmap_rewind(&hstock.stocks);

    const struct hashmap_pair *pair;
    while ((pair = hashmap_next(&hstock.stocks)) != nullptr) {
        Stock &stock = *(Stock *)pair->value;
        stock_fade_all(stock);
    }
}

void
hstock_add_stats(const StockMap &stock, StockStats &data)
{
    struct hashmap *h = &stock.stocks;
    hashmap_rewind(h);

    const struct hashmap_pair *p;
    while ((p = hashmap_next(h)) != nullptr) {
        const Stock &s = *(const Stock *)p->value;
        stock_add_stats(s, data);
    }
}

static Stock &
hstock_get_stock(StockMap &hstock, const char *uri)
{
    Stock *stock = (Stock *)hashmap_get(&hstock.stocks, uri);
    if (stock == nullptr) {
        stock = stock_new(hstock.pool, hstock.cls, hstock.class_ctx,
                          uri, hstock.limit, hstock.max_idle,
                          hstock_stock_handler, &hstock);
        hashmap_set(&hstock.stocks, stock_get_uri(*stock), stock);
    }

    return *stock;
}

void
hstock_get(StockMap &hstock, struct pool &pool,
           const char *uri, void *info,
           const StockGetHandler &handler, void *handler_ctx,
           struct async_operation_ref &async_ref)
{
    auto &stock = hstock_get_stock(hstock, uri);
    stock_get(stock, pool, info, handler, handler_ctx, async_ref);
}

StockItem *
hstock_get_now(StockMap &hstock, struct pool &pool,
               const char *uri, void *info,
               GError **error_r)
{
    Stock &stock = hstock_get_stock(hstock, uri);
    return stock_get_now(stock, pool, info, error_r);
}

void
hstock_put(gcc_unused StockMap &hstock, gcc_unused const char *uri,
           StockItem &object, bool destroy)
{
#ifndef NDEBUG
    Stock *stock = (Stock *)hashmap_get(&hstock.stocks, uri);

    assert(stock != nullptr);
    assert(stock == object.stock);
#endif

    stock_put(object, destroy);
}
<|endoftext|>


<commit_before>#include "stepper_motor.h"
#include "jenny5_types.h"
#include "utils.h"

//-------------------------------------------------------------------------------
t_stepper_motor_controller::t_stepper_motor_controller(void)
{
//  dir_pin = 2;
//  step_pin = 3;
  enable_pin = 4;

  sensors_count = 0;
  sensors = NULL;

  motor_running = 0;
  stepper = NULL;

  going_to_position = false;
  sensor_stop_position = NULL;
}
//-------------------------------------------------------------------------------
t_stepper_motor_controller::~t_stepper_motor_controller(void)
{
  if (stepper)
    delete stepper;

  if (sensors)
    delete[] sensors;

  if (sensor_stop_position)
	  delete[] sensor_stop_position;

  sensors_count = 0;

  motor_running = 0;
}
//-------------------------------------------------------------------------------
void t_stepper_motor_controller::create_init(byte _dir, byte _step, byte _enable, float default_motor_speed, float default_motor_acceleration)
{
  enable_pin = _enable;

  if (stepper)
    delete stepper;

  if (sensors)
    delete[] sensors;

  if (sensor_stop_position)
	  delete[] sensor_stop_position;

  sensors_count = 0;

  motor_running = 0;
  going_to_position = false;

  stepper = new AccelStepper(AccelStepper::DRIVER, _step, _dir);
  stepper->setMaxSpeed(default_motor_speed);
  stepper->setSpeed(default_motor_speed);
  stepper->setAcceleration(default_motor_acceleration);

  digitalWrite(_step, LOW);
  digitalWrite(_dir, LOW);
  pinMode(enable_pin, OUTPUT);
  digitalWrite(enable_pin, HIGH); // all motors are disabled now
}
//-------------------------------------------------------------------------------
void t_stepper_motor_controller::move_motor(int num_steps)
{
  digitalWrite(enable_pin, LOW); // turn motor on
  stepper->move(num_steps); //move num_steps
  motor_running = 1;
}
//-------------------------------------------------------------------------------
void t_stepper_motor_controller::move_motor_to(int _position)
{
  digitalWrite(enable_pin, LOW); // turn motor on
  stepper->moveTo(_position); //move num_steps
  motor_running = 1;
}
//-------------------------------------------------------------------------------
void t_stepper_motor_controller::set_motor_speed(float _motor_speed)
{
  stepper->setMaxSpeed(_motor_speed);
  stepper->setSpeed(_motor_speed);
}
//-------------------------------------------------------------------------------
void t_stepper_motor_controller::set_motor_acceleration(float _motor_acceleration)
{
  stepper->setAcceleration(_motor_acceleration);
  // motor_acceleration = _motor_acceleration;
}
//-------------------------------------------------------------------------------
void t_stepper_motor_controller::set_motor_speed_and_acceleration(float _motor_speed, float _motor_acceleration)
{
  stepper->setMaxSpeed(_motor_speed);
  stepper->setSpeed(_motor_speed);
  stepper->setAcceleration(_motor_acceleration);
}
//-------------------------------------------------------------------------------
void t_stepper_motor_controller::disable_motor(void)
{
  digitalWrite(enable_pin, HIGH); // disable motor
}
//-------------------------------------------------------------------------------
void t_stepper_motor_controller::lock_motor(void)
{
  digitalWrite(enable_pin, LOW); // enable motor
}
//-------------------------------------------------------------------------------
void t_stepper_motor_controller::add_sensor(byte sensor_type, byte sensor_index, int _min_pos, int _max_pos, int _home_pos, int8_t __direction)
{
  sensors[sensors_count].type = sensor_type;
  sensors[sensors_count].index = sensor_index;

  sensors[sensors_count].min_pos = _min_pos;
  sensors[sensors_count].max_pos = _max_pos;
  sensors[sensors_count].home_pos = _home_pos;
  sensors[sensors_count]._direction = __direction;
  sensors_count++;
}
//-------------------------------------------------------------------------------
byte t_stepper_motor_controller::get_num_attached_sensors(void)
{
  return sensors_count;
}
//-------------------------------------------------------------------------------
void t_stepper_motor_controller::set_num_attached_sensors(byte num_sensors)
{
  if (sensors_count != num_sensors) {
    // clear memory if the array has a different size
    if (sensors) {
      delete[] sensors;
      sensors = NULL;
    }

	if (sensor_stop_position) {
		delete[] sensor_stop_position;
		sensor_stop_position = NULL;
	}

	if (num_sensors > 0) {
		sensors = new t_sensor_info[num_sensors]; // allocate memory for them
		sensor_stop_position = new int[num_sensors];
	}
  }
  sensors_count = 0; // actual number of sensors
}
//-------------------------------------------------------------------------------
void t_stepper_motor_controller::set_motor_running(byte is_running)
{
  motor_running = is_running;
}
//-------------------------------------------------------------------------------
byte t_stepper_motor_controller::is_motor_running(void)
{
  return motor_running;
}
//-------------------------------------------------------------------------------
void t_stepper_motor_controller::get_sensor(byte sensor_index_in_motor_list, byte *sensor_type, byte *sensor_index, int *_min_pos, int *_max_pos, int *_home_pos, int8_t *__direction)
{
  *sensor_type = sensors[sensor_index_in_motor_list].type;
  *sensor_index = sensors[sensor_index_in_motor_list].index;

  *_min_pos = sensors[sensor_index_in_motor_list].min_pos;
  *_max_pos = sensors[sensor_index_in_motor_list].max_pos;
  *_home_pos = sensors[sensor_index_in_motor_list].home_pos;
  *__direction = sensors[sensor_index_in_motor_list]._direction;
}
//-------------------------------------------------------------------------------
void t_stepper_motor_controller::get_motor_speed_and_acceleration(float *_motor_speed, float *_motor_acceleration)
{
  if (stepper) {
    *_motor_acceleration = stepper->getAcceleration();
    *_motor_speed = stepper->maxSpeed();
  }
  else {
    *_motor_speed = 0;
    *_motor_acceleration = 0;
  }
}
//-------------------------------------------------------------------------------
byte t_stepper_motor_controller::run_motor(t_potentiometers_controller *potentiometers_control, t_buttons_controller *buttons_controller, int& dist_left_to_go)
{
  // returns 1 if is still running
  // returns 2 if it does nothing
  // returns 0 if it has just stopped; in dist_to_go we have what is left to run (or 0)

  bool limit_reached = false;
  int distance_to_go = stepper->distanceToGo();

  if (distance_to_go) {
    for (byte j = 0; j < sensors_count; j++){
      byte sensor_index = sensors[j].index;
      byte type = sensors[j].type;

      if (POTENTIOMETER == type) {
          int potentiometer_direction = sensors[j]._direction;

		      int val = potentiometers_control->get_position(sensor_index);

          if (sensors[j].min_pos > val){
            if (distance_to_go * potentiometer_direction < 0) {
              limit_reached = true;
            }
          }
          if (sensors[j].max_pos < val){
            if (distance_to_go * potentiometer_direction > 0) {
              limit_reached = true;
            }
          }

		  if (going_to_position) {
			  // must stop to home
			  int pot_position = potentiometers_control->get_position(sensor_index);
			  int pot_stop_position = sensor_stop_position[j]; // sensors[j].home_pos;// potentiometers_control->get_home_position(sensor_index);
			  int8_t pot_direction = sensors[j]._direction;// potentiometers_control->get_direction(sensor_index);

			  if (pot_direction == 1) {
				  if (distance_to_go > 0) {
					  if (pot_position >= pot_stop_position)
						  limit_reached = true;
				  }
				  else { // distance to go is negative
					  if (pot_position <= pot_stop_position)
						  limit_reached = true;
				  }
			  }
			  else {// pot direction == -1
				  if (distance_to_go > 0) {
					  if (pot_position <= pot_stop_position)
						  limit_reached = true;
				  }
				  else { // distance to go is negative
					  if (pot_position >= pot_stop_position)
						  limit_reached = true;
				  }
			  }
		  }
      }
      else
		if (BUTTON == type) {
          int button_direction = sensors[j]._direction;
          int button_state = buttons_controller->get_state(sensor_index);

          if (button_state == 1) // limit reached
            if (distance_to_go * button_direction > 0)
              limit_reached = true;
        }
    }

    if (!limit_reached){
      stepper->run();
      return MOTOR_STILL_RUNNING; // still running
    }
    else {
      if (is_motor_running()) {
        int to_go = stepper->distanceToGo();
        stepper->setCurrentPosition(0);
        stepper->move(0);
        dist_left_to_go = to_go;
        going_to_position = false;
        //Serial.println("left to go  > 0");
        set_motor_running(0);
        return MOTOR_JUST_STOPPED;
      }
      else
        return MOTOR_DOES_NOTHING;
    }
  }
  else {
    // the motor has just finished the move, so we output that event
    going_to_position = false;
    if (is_motor_running()) {
      set_motor_running(0);
      dist_left_to_go = 0;
      //Serial.println("left to go == 0");
      return MOTOR_JUST_STOPPED; // distance to go
    }
    else
      return MOTOR_DOES_NOTHING;
  }
}
//-------------------------------------------------------------------------------
void t_stepper_motor_controller::go_home(t_potentiometers_controller *potentiometers_control, t_buttons_controller* buttons_controller)
{
  if (sensors_count > 0) {
    int sensor_index = sensors[0].index;
    byte sensor_type = sensors[0].type;

    if (sensor_type == POTENTIOMETER) {
      //calculate the remaining distance from the current position to home position, relative to the direction and position of the potentiometer
		  int pot_dir = sensors[0]._direction; // potentiometers_control->get_direction(sensor_index);
		  int pot_home = sensors[0].home_pos; // potentiometers_control->get_home_position(sensor_index);
      int pot_pos = potentiometers_control->get_position(sensor_index);
	    int max_steps_to_home = pot_dir * sign(pot_home - pot_pos) * 32000;
	    going_to_position = true;
      sensor_stop_position[0] = pot_home;
      move_motor(max_steps_to_home);
    }
    else if (sensor_type ==  BUTTON) {
      int b_direction = sensors[0]._direction;//buttons_controller->get_direction(sensor_index);
      int max_steps_to_home;
      if (b_direction > 0)
		    max_steps_to_home = 32000; // this depends on microstepping, gear redunction etc
      else
		    max_steps_to_home = -32000;
	    going_to_position = true;
      move_motor(max_steps_to_home);
    }
  }
}
//-------------------------------------------------------------------------------
void t_stepper_motor_controller::go_to_sensor_position(int pot_stop_position)
{
	if (sensors_count > 0) {
		byte sensor_type = sensors[0].type;

		if (sensor_type == POTENTIOMETER) {
			//calculate the remaining distance from the current position to home position, relative to the direction and position of the potentiometer
			int pot_dir = sensors[0]._direction; // potentiometers_control->get_direction(sensor_index);
			int pot_home = sensors[0].home_pos; // potentiometers_control->get_home_position(sensor_index);

			int max_steps_to_home = pot_dir * sign(-pot_home + pot_stop_position) * 32000;
				  //Serial.println(pot_dir);
				  //Serial.println(pot_home);
				  //Serial.println(pot_stop_position);
			//	  Serial.println(distance_to_home);
			going_to_position = true;
     sensor_stop_position[0] = pot_stop_position;
     //Serial.println(max_steps_to_home);
			move_motor(max_steps_to_home);
		}
		else if (sensor_type == BUTTON) {
			int b_direction = sensors[0]._direction;//buttons_controller->get_direction(sensor_index);
			int max_steps_to_home;
			if (b_direction > 0)
				max_steps_to_home = 32000; // this depends on microstepping, gear redunction etc
			else
				max_steps_to_home = -32000;
			going_to_position = true;
			move_motor(max_steps_to_home);
		}
	}
}
//-------------------------------------------------------------------------------
<commit_msg>removed button from go_to_sensor_position method<commit_after>#include "stepper_motor.h"
#include "jenny5_types.h"
#include "utils.h"

//-------------------------------------------------------------------------------
t_stepper_motor_controller::t_stepper_motor_controller(void)
{
//  dir_pin = 2;
//  step_pin = 3;
  enable_pin = 4;

  sensors_count = 0;
  sensors = NULL;

  motor_running = 0;
  stepper = NULL;

  going_to_position = false;
  sensor_stop_position = NULL;
}
//-------------------------------------------------------------------------------
t_stepper_motor_controller::~t_stepper_motor_controller(void)
{
  if (stepper)
    delete stepper;

  if (sensors)
    delete[] sensors;

  if (sensor_stop_position)
	  delete[] sensor_stop_position;

  sensors_count = 0;

  motor_running = 0;
}
//-------------------------------------------------------------------------------
void t_stepper_motor_controller::create_init(byte _dir, byte _step, byte _enable, float default_motor_speed, float default_motor_acceleration)
{
  enable_pin = _enable;

  if (stepper)
    delete stepper;

  if (sensors)
    delete[] sensors;

  if (sensor_stop_position)
	  delete[] sensor_stop_position;

  sensors_count = 0;

  motor_running = 0;
  going_to_position = false;

  stepper = new AccelStepper(AccelStepper::DRIVER, _step, _dir);
  stepper->setMaxSpeed(default_motor_speed);
  stepper->setSpeed(default_motor_speed);
  stepper->setAcceleration(default_motor_acceleration);

  digitalWrite(_step, LOW);
  digitalWrite(_dir, LOW);
  pinMode(enable_pin, OUTPUT);
  digitalWrite(enable_pin, HIGH); // all motors are disabled now
}
//-------------------------------------------------------------------------------
void t_stepper_motor_controller::move_motor(int num_steps)
{
  digitalWrite(enable_pin, LOW); // turn motor on
  stepper->move(num_steps); //move num_steps
  motor_running = 1;
}
//-------------------------------------------------------------------------------
void t_stepper_motor_controller::move_motor_to(int _position)
{
  digitalWrite(enable_pin, LOW); // turn motor on
  stepper->moveTo(_position); //move num_steps
  motor_running = 1;
}
//-------------------------------------------------------------------------------
void t_stepper_motor_controller::set_motor_speed(float _motor_speed)
{
  stepper->setMaxSpeed(_motor_speed);
  stepper->setSpeed(_motor_speed);
}
//-------------------------------------------------------------------------------
void t_stepper_motor_controller::set_motor_acceleration(float _motor_acceleration)
{
  stepper->setAcceleration(_motor_acceleration);
  // motor_acceleration = _motor_acceleration;
}
//-------------------------------------------------------------------------------
void t_stepper_motor_controller::set_motor_speed_and_acceleration(float _motor_speed, float _motor_acceleration)
{
  stepper->setMaxSpeed(_motor_speed);
  stepper->setSpeed(_motor_speed);
  stepper->setAcceleration(_motor_acceleration);
}
//-------------------------------------------------------------------------------
void t_stepper_motor_controller::disable_motor(void)
{
  digitalWrite(enable_pin, HIGH); // disable motor
}
//-------------------------------------------------------------------------------
void t_stepper_motor_controller::lock_motor(void)
{
  digitalWrite(enable_pin, LOW); // enable motor
}
//-------------------------------------------------------------------------------
void t_stepper_motor_controller::add_sensor(byte sensor_type, byte sensor_index, int _min_pos, int _max_pos, int _home_pos, int8_t __direction)
{
  sensors[sensors_count].type = sensor_type;
  sensors[sensors_count].index = sensor_index;

  sensors[sensors_count].min_pos = _min_pos;
  sensors[sensors_count].max_pos = _max_pos;
  sensors[sensors_count].home_pos = _home_pos;
  sensors[sensors_count]._direction = __direction;
  sensors_count++;
}
//-------------------------------------------------------------------------------
byte t_stepper_motor_controller::get_num_attached_sensors(void)
{
  return sensors_count;
}
//-------------------------------------------------------------------------------
void t_stepper_motor_controller::set_num_attached_sensors(byte num_sensors)
{
  if (sensors_count != num_sensors) {
    // clear memory if the array has a different size
    if (sensors) {
      delete[] sensors;
      sensors = NULL;
    }

	if (sensor_stop_position) {
		delete[] sensor_stop_position;
		sensor_stop_position = NULL;
	}

	if (num_sensors > 0) {
		sensors = new t_sensor_info[num_sensors]; // allocate memory for them
		sensor_stop_position = new int[num_sensors];
	}
  }
  sensors_count = 0; // actual number of sensors
}
//-------------------------------------------------------------------------------
void t_stepper_motor_controller::set_motor_running(byte is_running)
{
  motor_running = is_running;
}
//-------------------------------------------------------------------------------
byte t_stepper_motor_controller::is_motor_running(void)
{
  return motor_running;
}
//-------------------------------------------------------------------------------
void t_stepper_motor_controller::get_sensor(byte sensor_index_in_motor_list, byte *sensor_type, byte *sensor_index, int *_min_pos, int *_max_pos, int *_home_pos, int8_t *__direction)
{
  *sensor_type = sensors[sensor_index_in_motor_list].type;
  *sensor_index = sensors[sensor_index_in_motor_list].index;

  *_min_pos = sensors[sensor_index_in_motor_list].min_pos;
  *_max_pos = sensors[sensor_index_in_motor_list].max_pos;
  *_home_pos = sensors[sensor_index_in_motor_list].home_pos;
  *__direction = sensors[sensor_index_in_motor_list]._direction;
}
//-------------------------------------------------------------------------------
void t_stepper_motor_controller::get_motor_speed_and_acceleration(float *_motor_speed, float *_motor_acceleration)
{
  if (stepper) {
    *_motor_acceleration = stepper->getAcceleration();
    *_motor_speed = stepper->maxSpeed();
  }
  else {
    *_motor_speed = 0;
    *_motor_acceleration = 0;
  }
}
//-------------------------------------------------------------------------------
byte t_stepper_motor_controller::run_motor(t_potentiometers_controller *potentiometers_control, t_buttons_controller *buttons_controller, int& dist_left_to_go)
{
  // returns 1 if is still running
  // returns 2 if it does nothing
  // returns 0 if it has just stopped; in dist_to_go we have what is left to run (or 0)

  bool limit_reached = false;
  int distance_to_go = stepper->distanceToGo();

  if (distance_to_go) {
    for (byte j = 0; j < sensors_count; j++){
      byte sensor_index = sensors[j].index;
      byte sensor_type = sensors[j].type;

      if (sensor_type == POTENTIOMETER) {
          int potentiometer_direction = sensors[j]._direction;

		      int val = potentiometers_control->get_position(sensor_index);

          if (sensors[j].min_pos > val){
            if (distance_to_go * potentiometer_direction < 0) {
              limit_reached = true;
            }
          }
          if (sensors[j].max_pos < val){
            if (distance_to_go * potentiometer_direction > 0) {
              limit_reached = true;
            }
          }

		  if (going_to_position) {
			  // must stop to home
			  int pot_position = potentiometers_control->get_position(sensor_index);
			  int pot_stop_position = sensor_stop_position[j]; // sensors[j].home_pos;// potentiometers_control->get_home_position(sensor_index);
			  int8_t pot_direction = sensors[j]._direction;// potentiometers_control->get_direction(sensor_index);

			  if (pot_direction == 1) {
				  if (distance_to_go > 0) {
					  if (pot_position >= pot_stop_position)
						  limit_reached = true;
				  }
				  else { // distance to go is negative
					  if (pot_position <= pot_stop_position)
						  limit_reached = true;
				  }
			  }
			  else {// pot direction == -1
				  if (distance_to_go > 0) {
					  if (pot_position <= pot_stop_position)
						  limit_reached = true;
				  }
				  else { // distance to go is negative
					  if (pot_position >= pot_stop_position)
						  limit_reached = true;
				  }
			  }
		  }
      }
      else
		if (sensor_type == BUTTON) {
          int button_direction = sensors[j]._direction;
          int button_state = buttons_controller->get_state(sensor_index);

          if (button_state == 1) // limit reached
            if (distance_to_go * button_direction > 0)
              limit_reached = true;
        }
    }

    if (!limit_reached){
      stepper->run();
      return MOTOR_STILL_RUNNING; // still running
    }
    else {
      if (is_motor_running()) {
        int to_go = stepper->distanceToGo();
        stepper->setCurrentPosition(0);
        stepper->move(0);
        dist_left_to_go = to_go;
        going_to_position = false;
        //Serial.println("left to go  > 0");
        set_motor_running(0);
        return MOTOR_JUST_STOPPED;
      }
      else
        return MOTOR_DOES_NOTHING;
    }
  }
  else {
    // the motor has just finished the move, so we output that event
    going_to_position = false;
    if (is_motor_running()) {
      set_motor_running(0);
      dist_left_to_go = 0;
      //Serial.println("left to go == 0");
      return MOTOR_JUST_STOPPED; // distance to go
    }
    else
      return MOTOR_DOES_NOTHING;
  }
}
//-------------------------------------------------------------------------------
void t_stepper_motor_controller::go_home(t_potentiometers_controller *potentiometers_control, t_buttons_controller* buttons_controller)
{
  if (sensors_count > 0) {
    int sensor_index = sensors[0].index;
    byte sensor_type = sensors[0].type;

    if (sensor_type == POTENTIOMETER) {
      //calculate the remaining distance from the current position to home position, relative to the direction and position of the potentiometer
		  int pot_dir = sensors[0]._direction; // potentiometers_control->get_direction(sensor_index);
		  int pot_home = sensors[0].home_pos; // potentiometers_control->get_home_position(sensor_index);
      int pot_pos = potentiometers_control->get_position(sensor_index);
	    int max_steps_to_home = pot_dir * sign(pot_home - pot_pos) * 32000;
	    going_to_position = true;
      sensor_stop_position[0] = pot_home;
      move_motor(max_steps_to_home);
    }
    else if (sensor_type ==  BUTTON) {
      int b_direction = sensors[0]._direction;//buttons_controller->get_direction(sensor_index);
      int max_steps_to_home;
      if (b_direction > 0)
		    max_steps_to_home = 32000; // this depends on microstepping, gear redunction etc
      else
		    max_steps_to_home = -32000;
	    going_to_position = true;
      move_motor(max_steps_to_home);
    }
  }
}
//-------------------------------------------------------------------------------
void t_stepper_motor_controller::go_to_sensor_position(int pot_stop_position)
{
	if (sensors_count > 0) {
		byte sensor_type = sensors[0].type;

		if (sensor_type == POTENTIOMETER) {
			//calculate the remaining distance from the current position to home position, relative to the direction and position of the potentiometer
			int pot_dir = sensors[0]._direction; // potentiometers_control->get_direction(sensor_index);
			int pot_home = sensors[0].home_pos; // potentiometers_control->get_home_position(sensor_index);

			int max_steps_to_home = pot_dir * sign(-pot_home + pot_stop_position) * 32000;
				  //Serial.println(pot_dir);
				  //Serial.println(pot_home);
				  //Serial.println(pot_stop_position);
			//	  Serial.println(distance_to_home);
			going_to_position = true;
     sensor_stop_position[0] = pot_stop_position;
     //Serial.println(max_steps_to_home);
			move_motor(max_steps_to_home);
		}
	}
}
//-------------------------------------------------------------------------------
<|endoftext|>


<commit_before>/****************************************************************/
/*               DO NOT MODIFY THIS HEADER                      */
/* MOOSE - Multiphysics Object Oriented Simulation Environment  */
/*                                                              */
/*           (c) 2010 Battelle Energy Alliance, LLC             */
/*                   ALL RIGHTS RESERVED                        */
/*                                                              */
/*          Prepared by Battelle Energy Alliance, LLC           */
/*            Under Contract No. DE-AC07-05ID14517              */
/*            With the U. S. Department of Energy               */
/*                                                              */
/*            See COPYRIGHT for full restrictions               */
/****************************************************************/

#include "Transient.h"

//Moose includes
#include "Kernel.h"
#include "Factory.h"
#include "SubProblem.h"
#include "ProblemFactory.h"
#include "TimePeriod.h"
#include "TimeScheme.h"
//libMesh includes
#include "implicit_system.h"
#include "nonlinear_implicit_system.h"
#include "transient_system.h"
#include "numeric_vector.h"
#include "o_string_stream.h"

// C++ Includes
#include <iomanip>
#include <iostream>
#include <fstream>

template<>
InputParameters validParams<Transient>()
{
  InputParameters params = validParams<Executioner>();
  std::vector<Real> sync_times(1);
  sync_times[0] = -1;

  params.addParam<Real>("start_time",      0.0,    "The start time of the simulation");
  params.addParam<Real>("end_time",        1.0e30, "The end time of the simulation");
  params.addRequiredParam<Real>("dt", "The timestep size between solves");
  params.addParam<Real>("dtmin",           0.0,    "The minimum timestep size in an adaptive run");
  params.addParam<Real>("dtmax",           1.0e30, "The maximum timestep size in an adaptive run");
  params.addParam<Real>("num_steps",       std::numeric_limits<Real>::max(),     "The number of timesteps in a transient run");
  params.addParam<int> ("n_startup_steps", 0,      "The number of timesteps during startup");
  params.addParam<bool>("trans_ss_check",  false,  "Whether or not to check for steady state conditions");
  params.addParam<Real>("ss_check_tol",    1.0e-08,"Whenever the relative residual changes by less than this the solution will be considered to be at steady state.");
  params.addParam<Real>("ss_tmin",         0.0,    "Minimum number of timesteps to take before checking for steady state conditions.");
  params.addParam<std::vector<Real> >("sync_times", sync_times, "A list of times that will be solved for provided they are within the simulation time");
  params.addParam<std::vector<Real> >("time_t", "The values of t");
  params.addParam<std::vector<Real> >("time_dt", "The values of dt");
  params.addParam<Real>("growth_factor", 2, "Maximum ratio of new to previous timestep sizes following a step that required the time step to be cut due to a failed solve.  For use with 'time_t' and 'time_dt'.");
  params.addParam<Real>("predictor_scale",      0.0,    "The scale factor for the predictor (can range from 0 to 1)");

  params.addParam<std::vector<std::string> >("time_periods", "The names of periods");
  params.addParam<std::vector<Real> >("time_period_starts", "The start times of time periods");
  params.addParam<std::vector<Real> >("time_period_ends", "The end times of time periods");
  params.addParam<bool>("use_AB2", false, "Whether to use the Adams-Bashforth 2 predictor");
  params.addParam<bool>("use_littlef", false, "if a function evaluation should be used or time deriv's in predictors");
  params.addParam<bool>("abort_on_solve_fail", false, "abort if solve not converged rather than cut timestep");
  return params;
}

Transient::Transient(const std::string & name, InputParameters parameters) :
    Executioner(name, parameters),
    _problem(*ProblemFactory::instance()->createFEProblem(_mesh)),
    _t_step(_problem.timeStep()),
    _time(_problem.time()),
    _time_old(_problem.timeOld()),
    _input_dt(getParam<Real>("dt")),
    _dt(_problem.dt()),
    _dt_old(_problem.dtOld()),
    _prev_dt(-1),
    _reset_dt(false),
    _end_time(getParam<Real>("end_time")),
    _dtmin(getParam<Real>("dtmin")),
    _dtmax(getParam<Real>("dtmax")),
    _num_steps(getParam<Real>("num_steps")),
    _n_startup_steps(getParam<int>("n_startup_steps")),
    _trans_ss_check(getParam<bool>("trans_ss_check")),
    _ss_check_tol(getParam<Real>("ss_check_tol")),
    _ss_tmin(getParam<Real>("ss_tmin")),
    _converged(true),
    _sync_times(getParam<std::vector<Real> >("sync_times")),
    _remaining_sync_time(true),
    _time_ipol(getParam<std::vector<Real> >("time_t"),
               getParam<std::vector<Real> >("time_dt")),
    _use_time_ipol(_time_ipol.getSampleSize() > 0),
    _growth_factor(getParam<Real>("growth_factor")),
    _cutback_occurred(false),
    _abort(getParam<bool>("abort_on_solve_fail"))
{
  _t_step = 0;
  _dt = 0;
  _time = _time_old = getParam<Real>("start_time");
  _problem.transient(true);
  if (parameters.wasSeenInInput("predictor_scale"))
  {
    Real predscale(getParam<Real>("predictor_scale"));
    if (predscale >= 0.0 and predscale <= 1.0)
    {
      _problem.getNonlinearSystem().setPredictorScale(getParam<Real>("predictor_scale"));
    }
    else
    {
      mooseError("Input value for predictor_scale = "<< predscale << ", outside of permissible range (0 to 1)");
    }
    _problem.getTimeScheme()->_use_AB2 = getParam<bool>("use_AB2");
    _problem.getTimeScheme()->_use_littlef = getParam<bool>("use_littlef");
  }

  if (!_restart_file_base.empty())
    _problem.setRestartFile(_restart_file_base);
}

Transient::~Transient()
{
  // This problem was built by the Factory and needs to be released by this destructor
  delete &_problem;
}

void
Transient::execute()
{
  _problem.initialSetup();

  preExecute();

  // Start time loop...
  while(keepGoing())
  {
    takeStep();
    if (lastSolveConverged())
      endStep();
  }
  postExecute();
}

void
Transient::takeStep(Real input_dt)
{
  if (_converged)
    _problem.copyOldSolutions();
  else
    _problem.restoreSolutions();

  _dt_old = _dt;
  if (input_dt == -1.0)
    _dt = computeConstrainedDT();
  else
    _dt = input_dt;

  _problem.onTimestepBegin();
  if (_converged)
  {
    // Update backward material data structures
    _problem.updateMaterials();
  }

  // Increment time
  _time = _time_old + _dt;

  std::cout<<"DT: "<<_dt<<std::endl;

  std::cout << " Solving time step ";
  {
    OStringStream out;

    OSSInt(out,2,_t_step);
    out << ", time=";
    OSSRealzeroleft(out, 9, 6, _time);
    out <<  "...";
    std::cout << out.str() << std::endl;
  }

  preSolve();

  _problem.timestepSetup();

  // Compute Pre-Aux User Objects (Timestep begin)
  _problem.computeUserObjects(EXEC_TIMESTEP_BEGIN, UserObjectWarehouse::PRE_AUX);

  // Compute TimestepBegin AuxKernels
  _problem.computeAuxiliaryKernels(EXEC_TIMESTEP_BEGIN);

  // Compute Post-Aux User Objects (Timestep begin)
  _problem.computeUserObjects(EXEC_TIMESTEP_BEGIN, UserObjectWarehouse::POST_AUX);

  _problem.solve();

  _converged = _problem.converged();

  // Compute Pre-Aux User Objects
  _problem.computeUserObjects(EXEC_TIMESTEP, UserObjectWarehouse::PRE_AUX);

  postSolve();

  _problem.onTimestepEnd();

  // We know whether or not the nonlinear solver thinks it converged, but we need to see if the executioner concurs
  bool last_solve_converged = lastSolveConverged();

  // If _reset_dt is true, the time step was synced to the user defined value and we dump the solution in an output file
  if (last_solve_converged)
  {
    _problem.computeUserObjects(EXEC_TIMESTEP, UserObjectWarehouse::POST_AUX);
  }
}

void
Transient::endStep()
{
  // Compute the Error Indicators and Markers
  _problem.computeIndicatorsAndMarkers();

  // if _reset_dt is true, force the output no matter what
  _problem.output(_reset_dt);
  _problem.outputPostprocessors(_reset_dt);

#ifdef LIBMESH_ENABLE_AMR
  if (_problem.adaptivity().isOn())
  {
    _problem.adaptMesh();
    _problem.out().meshChanged();
  }
#endif

  _time_old = _time;
  _t_step++;
}

Real
Transient::computeConstrainedDT()
{
  // If this is the first step
  if (_t_step == 0)
  {
    _t_step = 1;
    _dt = _input_dt;
  }

//  // If start up steps are needed
//  if(_t_step == 1 && _n_startup_steps > 1)
//    _dt = _input_dt/(double)(_n_startup_steps);
//  else if (_t_step == 1+_n_startup_steps && _n_startup_steps > 1)
//    _dt = _input_dt;

  Real dt_cur = _dt;
  //After startup steps, compute new dt
  if (_t_step > _n_startup_steps)
    dt_cur = computeDT();

  // Don't let the time step size exceed maximum time step size
  if (dt_cur > _dtmax)
    dt_cur = _dtmax;

  // Don't allow time step size to be smaller than minimum time step size
  if (dt_cur < _dtmin)
    dt_cur = _dtmin;

  // Don't let time go beyond simulation end time
  if (_time + dt_cur > _end_time)
    dt_cur = _end_time - _time;

  // Adjust to a sync time if supplied and skipped over
  if (_remaining_sync_time && _time + dt_cur >= *_curr_sync_time_iter)
  {
    dt_cur = *_curr_sync_time_iter - _time;
    if (++_curr_sync_time_iter == _sync_times.end())
      _remaining_sync_time = false;

    _prev_dt = _dt;

    _reset_dt = true;
  }
  else
  {
    if (_reset_dt)
    {
      if (_use_time_ipol)
        dt_cur = _time_ipol.sample(_time);
      else
        dt_cur = _prev_dt;
      _reset_dt = false;
    }
  }

  return dt_cur;

}

Real
Transient::computeDT()
{
  if (!lastSolveConverged())
  {
    _cutback_occurred = true;
    //std::cout<<"Solve failed... cutting timestep"<<std::endl;
    //return _dt / 2.0;

    // Instead of blindly cutting timestep, respect dtmin.
    if (_dt <= _dtmin)
      mooseError("Solve failed and timestep already at or below dtmin, cannot continue!");

    if (0.5 * _dt >= _dtmin)
      return 0.5 * _dt;

    else // (0.5 * _dt < _dtmin)
      return _dtmin;
  }

  Real dt = _dt;
  if (_use_time_ipol)
  {
    dt = _time_ipol.sample(_time);
    if (_cutback_occurred &&
        dt > _dt * _growth_factor)
    {
      dt = _dt * _growth_factor;
    }
  }

  _cutback_occurred = false;
  return dt;
}

bool
Transient::keepGoing()
{
  // Check for stop condition based upon steady-state check flag:
  if(_converged && _trans_ss_check == true && _time > _ss_tmin)
  {
    // Compute new time solution l2_norm
    Real new_time_solution_norm = _problem.getNonlinearSystem().currentSolution()->l2_norm();

    // Compute l2_norm relative error
    Real ss_relerr_norm = fabs(new_time_solution_norm - _old_time_solution_norm)/new_time_solution_norm;

    // Check current solution relative error norm against steady-state tolerance
    if(ss_relerr_norm < _ss_check_tol)
    {
      std::cout<<"Steady-State Solution Achieved at time: "<<_time<<std::endl;
      return false;
    }
    else // Keep going
    {
      // Update solution norm for next time step
      _old_time_solution_norm = new_time_solution_norm;
      // Print steady-state relative error norm
      std::cout<<"Steady-State Relative Differential Norm: "<<ss_relerr_norm<<std::endl;
    }
  }

  if(!_converged && _abort)
  {
    std::cout<<"Aborting as solve did not converge and input selected to abort"<<std::endl;
    return false;
  }

  // Check for stop condition based upon number of simulation steps and/or solution end time:
  if(_t_step>_num_steps)
    return false;

  if((_time>_end_time) || (fabs(_time-_end_time)<1.e-14))
    return false;

  return true;
}

bool
Transient::lastSolveConverged()
{
  return _converged;
}

void
Transient::preExecute()
{
  // process time periods
  const std::vector<TimePeriod *> _time_periods = _problem.getTimePeriods();
  for (unsigned int i = 0; i < _time_periods.size(); ++i)
    _sync_times.push_back(_time_periods[i]->start());

  const std::vector<Real> & time = getParam<std::vector<Real> >("time_t");
  if (_use_time_ipol)
    _sync_times.insert(_sync_times.end(), time.begin()+1, time.end());          // insert times as sync points except the very first one
  sort(_sync_times.begin(), _sync_times.end());
  _sync_times.erase(std::unique(_sync_times.begin(), _sync_times.end()), _sync_times.end());    // remove duplicates (needs sorted array)

  // Advance to the first sync time if one is provided in sim time range
  _curr_sync_time_iter = _sync_times.begin();
  while (_remaining_sync_time && *_curr_sync_time_iter <= _time)
    if (++_curr_sync_time_iter == _sync_times.end())
      _remaining_sync_time = false;
}
<commit_msg>Fixing uninitialized memory - refs #720<commit_after>/****************************************************************/
/*               DO NOT MODIFY THIS HEADER                      */
/* MOOSE - Multiphysics Object Oriented Simulation Environment  */
/*                                                              */
/*           (c) 2010 Battelle Energy Alliance, LLC             */
/*                   ALL RIGHTS RESERVED                        */
/*                                                              */
/*          Prepared by Battelle Energy Alliance, LLC           */
/*            Under Contract No. DE-AC07-05ID14517              */
/*            With the U. S. Department of Energy               */
/*                                                              */
/*            See COPYRIGHT for full restrictions               */
/****************************************************************/

#include "Transient.h"

//Moose includes
#include "Kernel.h"
#include "Factory.h"
#include "SubProblem.h"
#include "ProblemFactory.h"
#include "TimePeriod.h"
#include "TimeScheme.h"
//libMesh includes
#include "implicit_system.h"
#include "nonlinear_implicit_system.h"
#include "transient_system.h"
#include "numeric_vector.h"
#include "o_string_stream.h"

// C++ Includes
#include <iomanip>
#include <iostream>
#include <fstream>

template<>
InputParameters validParams<Transient>()
{
  InputParameters params = validParams<Executioner>();
  std::vector<Real> sync_times(1);
  sync_times[0] = -1;

  params.addParam<Real>("start_time",      0.0,    "The start time of the simulation");
  params.addParam<Real>("end_time",        1.0e30, "The end time of the simulation");
  params.addRequiredParam<Real>("dt", "The timestep size between solves");
  params.addParam<Real>("dtmin",           0.0,    "The minimum timestep size in an adaptive run");
  params.addParam<Real>("dtmax",           1.0e30, "The maximum timestep size in an adaptive run");
  params.addParam<Real>("num_steps",       std::numeric_limits<Real>::max(),     "The number of timesteps in a transient run");
  params.addParam<int> ("n_startup_steps", 0,      "The number of timesteps during startup");
  params.addParam<bool>("trans_ss_check",  false,  "Whether or not to check for steady state conditions");
  params.addParam<Real>("ss_check_tol",    1.0e-08,"Whenever the relative residual changes by less than this the solution will be considered to be at steady state.");
  params.addParam<Real>("ss_tmin",         0.0,    "Minimum number of timesteps to take before checking for steady state conditions.");
  params.addParam<std::vector<Real> >("sync_times", sync_times, "A list of times that will be solved for provided they are within the simulation time");
  params.addParam<std::vector<Real> >("time_t", "The values of t");
  params.addParam<std::vector<Real> >("time_dt", "The values of dt");
  params.addParam<Real>("growth_factor", 2, "Maximum ratio of new to previous timestep sizes following a step that required the time step to be cut due to a failed solve.  For use with 'time_t' and 'time_dt'.");
  params.addParam<Real>("predictor_scale",      0.0,    "The scale factor for the predictor (can range from 0 to 1)");

  params.addParam<std::vector<std::string> >("time_periods", "The names of periods");
  params.addParam<std::vector<Real> >("time_period_starts", "The start times of time periods");
  params.addParam<std::vector<Real> >("time_period_ends", "The end times of time periods");
  params.addParam<bool>("use_AB2", false, "Whether to use the Adams-Bashforth 2 predictor");
  params.addParam<bool>("use_littlef", false, "if a function evaluation should be used or time deriv's in predictors");
  params.addParam<bool>("abort_on_solve_fail", false, "abort if solve not converged rather than cut timestep");
  return params;
}

Transient::Transient(const std::string & name, InputParameters parameters) :
    Executioner(name, parameters),
    _problem(*ProblemFactory::instance()->createFEProblem(_mesh)),
    _t_step(_problem.timeStep()),
    _time(_problem.time()),
    _time_old(_problem.timeOld()),
    _input_dt(getParam<Real>("dt")),
    _dt(_problem.dt()),
    _dt_old(_problem.dtOld()),
    _prev_dt(-1),
    _reset_dt(false),
    _end_time(getParam<Real>("end_time")),
    _dtmin(getParam<Real>("dtmin")),
    _dtmax(getParam<Real>("dtmax")),
    _num_steps(getParam<Real>("num_steps")),
    _n_startup_steps(getParam<int>("n_startup_steps")),
    _trans_ss_check(getParam<bool>("trans_ss_check")),
    _ss_check_tol(getParam<Real>("ss_check_tol")),
    _ss_tmin(getParam<Real>("ss_tmin")),
    _old_time_solution_norm(0.0),
    _converged(true),
    _sync_times(getParam<std::vector<Real> >("sync_times")),
    _remaining_sync_time(true),
    _time_ipol(getParam<std::vector<Real> >("time_t"),
               getParam<std::vector<Real> >("time_dt")),
    _use_time_ipol(_time_ipol.getSampleSize() > 0),
    _growth_factor(getParam<Real>("growth_factor")),
    _cutback_occurred(false),
    _abort(getParam<bool>("abort_on_solve_fail"))
{
  _t_step = 0;
  _dt = 0;
  _time = _time_old = getParam<Real>("start_time");
  _problem.transient(true);
  if (parameters.wasSeenInInput("predictor_scale"))
  {
    Real predscale(getParam<Real>("predictor_scale"));
    if (predscale >= 0.0 and predscale <= 1.0)
    {
      _problem.getNonlinearSystem().setPredictorScale(getParam<Real>("predictor_scale"));
    }
    else
    {
      mooseError("Input value for predictor_scale = "<< predscale << ", outside of permissible range (0 to 1)");
    }
    _problem.getTimeScheme()->_use_AB2 = getParam<bool>("use_AB2");
    _problem.getTimeScheme()->_use_littlef = getParam<bool>("use_littlef");
  }

  if (!_restart_file_base.empty())
    _problem.setRestartFile(_restart_file_base);
}

Transient::~Transient()
{
  // This problem was built by the Factory and needs to be released by this destructor
  delete &_problem;
}

void
Transient::execute()
{
  _problem.initialSetup();

  preExecute();

  // Start time loop...
  while(keepGoing())
  {
    takeStep();
    if (lastSolveConverged())
      endStep();
  }
  postExecute();
}

void
Transient::takeStep(Real input_dt)
{
  if (_converged)
    _problem.copyOldSolutions();
  else
    _problem.restoreSolutions();

  _dt_old = _dt;
  if (input_dt == -1.0)
    _dt = computeConstrainedDT();
  else
    _dt = input_dt;

  _problem.onTimestepBegin();
  if (_converged)
  {
    // Update backward material data structures
    _problem.updateMaterials();
  }

  // Increment time
  _time = _time_old + _dt;

  std::cout<<"DT: "<<_dt<<std::endl;

  std::cout << " Solving time step ";
  {
    OStringStream out;

    OSSInt(out,2,_t_step);
    out << ", time=";
    OSSRealzeroleft(out, 9, 6, _time);
    out <<  "...";
    std::cout << out.str() << std::endl;
  }

  preSolve();

  _problem.timestepSetup();

  // Compute Pre-Aux User Objects (Timestep begin)
  _problem.computeUserObjects(EXEC_TIMESTEP_BEGIN, UserObjectWarehouse::PRE_AUX);

  // Compute TimestepBegin AuxKernels
  _problem.computeAuxiliaryKernels(EXEC_TIMESTEP_BEGIN);

  // Compute Post-Aux User Objects (Timestep begin)
  _problem.computeUserObjects(EXEC_TIMESTEP_BEGIN, UserObjectWarehouse::POST_AUX);

  _problem.solve();

  _converged = _problem.converged();

  // Compute Pre-Aux User Objects
  _problem.computeUserObjects(EXEC_TIMESTEP, UserObjectWarehouse::PRE_AUX);

  postSolve();

  _problem.onTimestepEnd();

  // We know whether or not the nonlinear solver thinks it converged, but we need to see if the executioner concurs
  bool last_solve_converged = lastSolveConverged();

  // If _reset_dt is true, the time step was synced to the user defined value and we dump the solution in an output file
  if (last_solve_converged)
  {
    _problem.computeUserObjects(EXEC_TIMESTEP, UserObjectWarehouse::POST_AUX);
  }
}

void
Transient::endStep()
{
  // Compute the Error Indicators and Markers
  _problem.computeIndicatorsAndMarkers();

  // if _reset_dt is true, force the output no matter what
  _problem.output(_reset_dt);
  _problem.outputPostprocessors(_reset_dt);

#ifdef LIBMESH_ENABLE_AMR
  if (_problem.adaptivity().isOn())
  {
    _problem.adaptMesh();
    _problem.out().meshChanged();
  }
#endif

  _time_old = _time;
  _t_step++;
}

Real
Transient::computeConstrainedDT()
{
  // If this is the first step
  if (_t_step == 0)
  {
    _t_step = 1;
    _dt = _input_dt;
  }

//  // If start up steps are needed
//  if(_t_step == 1 && _n_startup_steps > 1)
//    _dt = _input_dt/(double)(_n_startup_steps);
//  else if (_t_step == 1+_n_startup_steps && _n_startup_steps > 1)
//    _dt = _input_dt;

  Real dt_cur = _dt;
  //After startup steps, compute new dt
  if (_t_step > _n_startup_steps)
    dt_cur = computeDT();

  // Don't let the time step size exceed maximum time step size
  if (dt_cur > _dtmax)
    dt_cur = _dtmax;

  // Don't allow time step size to be smaller than minimum time step size
  if (dt_cur < _dtmin)
    dt_cur = _dtmin;

  // Don't let time go beyond simulation end time
  if (_time + dt_cur > _end_time)
    dt_cur = _end_time - _time;

  // Adjust to a sync time if supplied and skipped over
  if (_remaining_sync_time && _time + dt_cur >= *_curr_sync_time_iter)
  {
    dt_cur = *_curr_sync_time_iter - _time;
    if (++_curr_sync_time_iter == _sync_times.end())
      _remaining_sync_time = false;

    _prev_dt = _dt;

    _reset_dt = true;
  }
  else
  {
    if (_reset_dt)
    {
      if (_use_time_ipol)
        dt_cur = _time_ipol.sample(_time);
      else
        dt_cur = _prev_dt;
      _reset_dt = false;
    }
  }

  return dt_cur;

}

Real
Transient::computeDT()
{
  if (!lastSolveConverged())
  {
    _cutback_occurred = true;
    //std::cout<<"Solve failed... cutting timestep"<<std::endl;
    //return _dt / 2.0;

    // Instead of blindly cutting timestep, respect dtmin.
    if (_dt <= _dtmin)
      mooseError("Solve failed and timestep already at or below dtmin, cannot continue!");

    if (0.5 * _dt >= _dtmin)
      return 0.5 * _dt;

    else // (0.5 * _dt < _dtmin)
      return _dtmin;
  }

  Real dt = _dt;
  if (_use_time_ipol)
  {
    dt = _time_ipol.sample(_time);
    if (_cutback_occurred &&
        dt > _dt * _growth_factor)
    {
      dt = _dt * _growth_factor;
    }
  }

  _cutback_occurred = false;
  return dt;
}

bool
Transient::keepGoing()
{
  // Check for stop condition based upon steady-state check flag:
  if(_converged && _trans_ss_check == true && _time > _ss_tmin)
  {
    // Compute new time solution l2_norm
    Real new_time_solution_norm = _problem.getNonlinearSystem().currentSolution()->l2_norm();

    // Compute l2_norm relative error
    Real ss_relerr_norm = fabs(new_time_solution_norm - _old_time_solution_norm)/new_time_solution_norm;

    // Check current solution relative error norm against steady-state tolerance
    if(ss_relerr_norm < _ss_check_tol)
    {
      std::cout<<"Steady-State Solution Achieved at time: "<<_time<<std::endl;
      return false;
    }
    else // Keep going
    {
      // Update solution norm for next time step
      _old_time_solution_norm = new_time_solution_norm;
      // Print steady-state relative error norm
      std::cout<<"Steady-State Relative Differential Norm: "<<ss_relerr_norm<<std::endl;
    }
  }

  if(!_converged && _abort)
  {
    std::cout<<"Aborting as solve did not converge and input selected to abort"<<std::endl;
    return false;
  }

  // Check for stop condition based upon number of simulation steps and/or solution end time:
  if(_t_step>_num_steps)
    return false;

  if((_time>_end_time) || (fabs(_time-_end_time)<1.e-14))
    return false;

  return true;
}

bool
Transient::lastSolveConverged()
{
  return _converged;
}

void
Transient::preExecute()
{
  // process time periods
  const std::vector<TimePeriod *> _time_periods = _problem.getTimePeriods();
  for (unsigned int i = 0; i < _time_periods.size(); ++i)
    _sync_times.push_back(_time_periods[i]->start());

  const std::vector<Real> & time = getParam<std::vector<Real> >("time_t");
  if (_use_time_ipol)
    _sync_times.insert(_sync_times.end(), time.begin()+1, time.end());          // insert times as sync points except the very first one
  sort(_sync_times.begin(), _sync_times.end());
  _sync_times.erase(std::unique(_sync_times.begin(), _sync_times.end()), _sync_times.end());    // remove duplicates (needs sorted array)

  // Advance to the first sync time if one is provided in sim time range
  _curr_sync_time_iter = _sync_times.begin();
  while (_remaining_sync_time && *_curr_sync_time_iter <= _time)
    if (++_curr_sync_time_iter == _sync_times.end())
      _remaining_sync_time = false;
}
<|endoftext|>


<commit_before>/****************************************************************/
/*               DO NOT MODIFY THIS HEADER                      */
/* MOOSE - Multiphysics Object Oriented Simulation Environment  */
/*                                                              */
/*           (c) 2010 Battelle Energy Alliance, LLC             */
/*                   ALL RIGHTS RESERVED                        */
/*                                                              */
/*          Prepared by Battelle Energy Alliance, LLC           */
/*            Under Contract No. DE-AC07-05ID14517              */
/*            With the U. S. Department of Energy               */
/*                                                              */
/*            See COPYRIGHT for full restrictions               */
/****************************************************************/

#include "MaterialData.h"
#include "Material.h"

MaterialData::MaterialData(MaterialPropertyStorage & storage) :
    _storage(storage),
    _n_qpoints(0),
    _swapped(false)
{
}

MaterialData::~MaterialData()
{
  release();
}

void
MaterialData::release()
{
  _props.destroy();
  _props_old.destroy();
  _props_older.destroy();
}

void
MaterialData::size(unsigned int n_qpoints)
{
  _props.resizeItems(n_qpoints);
  // if there are stateful material properties in the system, also resize
  // storage for old and older material properties
  if (_storage.hasStatefulProperties())
  {
    _props_old.resizeItems(n_qpoints);

    if (_storage.hasOlderProperties())
      _props_older.resizeItems(n_qpoints);
  }
  _n_qpoints = n_qpoints;
}

unsigned int
MaterialData::nQPoints()
{
  return _n_qpoints;
}

void
MaterialData::swap(const Elem & elem, unsigned int side/* = 0*/)
{
  if (_storage.hasStatefulProperties())
  {
    _storage.swap(*this, elem, side);
    _swapped = true;
  }
}

void
MaterialData::reinit(std::vector<Material *> & mats)
{
  for (std::vector<Material *>::iterator it = mats.begin(); it != mats.end(); ++it)
    (*it)->computeProperties();
}

void
MaterialData::swapBack(const Elem & elem, unsigned int side/* = 0*/)
{
  if (_storage.hasStatefulProperties())
  {
    _storage.swapBack(*this, elem, side);
    _swapped = false;
  }
}

bool
MaterialData::isSwapped()
{
  return _swapped;
}
<commit_msg>Make MaterialData::swapBack() more robust.<commit_after>/****************************************************************/
/*               DO NOT MODIFY THIS HEADER                      */
/* MOOSE - Multiphysics Object Oriented Simulation Environment  */
/*                                                              */
/*           (c) 2010 Battelle Energy Alliance, LLC             */
/*                   ALL RIGHTS RESERVED                        */
/*                                                              */
/*          Prepared by Battelle Energy Alliance, LLC           */
/*            Under Contract No. DE-AC07-05ID14517              */
/*            With the U. S. Department of Energy               */
/*                                                              */
/*            See COPYRIGHT for full restrictions               */
/****************************************************************/

#include "MaterialData.h"
#include "Material.h"

MaterialData::MaterialData(MaterialPropertyStorage & storage) :
    _storage(storage),
    _n_qpoints(0),
    _swapped(false)
{
}

MaterialData::~MaterialData()
{
  release();
}

void
MaterialData::release()
{
  _props.destroy();
  _props_old.destroy();
  _props_older.destroy();
}

void
MaterialData::size(unsigned int n_qpoints)
{
  _props.resizeItems(n_qpoints);
  // if there are stateful material properties in the system, also resize
  // storage for old and older material properties
  if (_storage.hasStatefulProperties())
  {
    _props_old.resizeItems(n_qpoints);

    if (_storage.hasOlderProperties())
      _props_older.resizeItems(n_qpoints);
  }
  _n_qpoints = n_qpoints;
}

unsigned int
MaterialData::nQPoints()
{
  return _n_qpoints;
}

void
MaterialData::swap(const Elem & elem, unsigned int side/* = 0*/)
{
  if (_storage.hasStatefulProperties())
  {
    _storage.swap(*this, elem, side);
    _swapped = true;
  }
}

void
MaterialData::reinit(std::vector<Material *> & mats)
{
  for (std::vector<Material *>::iterator it = mats.begin(); it != mats.end(); ++it)
    (*it)->computeProperties();
}

void
MaterialData::swapBack(const Elem & elem, unsigned int side/* = 0*/)
{
  if (_swapped && _storage.hasStatefulProperties())
  {
    _storage.swapBack(*this, elem, side);
    _swapped = false;
  }
}

bool
MaterialData::isSwapped()
{
  return _swapped;
}
<|endoftext|>